* Makefile.in, configure.in, chkpwd.c, acconfig.h: support for
authorNathan Bryant <loanshark@uncensored.citadel.org>
Sat, 3 Apr 1999 19:57:06 +0000 (19:57 +0000)
committerNathan Bryant <loanshark@uncensored.citadel.org>
Sat, 3 Apr 1999 19:57:06 +0000 (19:57 +0000)
          `chkpwd', a setuid helper program for machines which use shadow
          passwords (configure --enable-chkpwd)
        * Makefile.in, configure.in, auth.c, citadel.pam, user_ops.c: support
          for PAM or shadow passwords (configure --with-pam)
        * Makefile.in: made some messages simpler
        * citadel.spec: updated for 5.53; correct name of tarball; build with
          --enable-chkpwd and --with-pam; add defattr tags so rpm's can be
          built by non-root user
        * commands.c: cosmetic cleanup
        * config.c: (security/paranoia) check permissions on citadel.config

14 files changed:
citadel/.cvsignore
citadel/ChangeLog
citadel/Makefile.in
citadel/acconfig.h
citadel/auth.c [new file with mode: 0644]
citadel/auth.h [new file with mode: 0644]
citadel/chkpwd.c [new file with mode: 0644]
citadel/citadel.pam [new file with mode: 0644]
citadel/citadel.spec
citadel/commands.c
citadel/config.c
citadel/configure.in
citadel/copyright.txt
citadel/user_ops.c

index 07dec2ba44fd42a7f508dc16211edd86242fca78..29fef717f5fba081757123190f3a9b9b80178403 100644 (file)
@@ -4,6 +4,7 @@
 Makefile
 aidepost
 base64
 Makefile
 aidepost
 base64
+chkpwd
 citadel
 citadel.config
 citadel.control
 citadel
 citadel.config
 citadel.control
@@ -11,6 +12,7 @@ citadel.log
 citmail
 citserver
 config.cache
 citmail
 citserver
 config.cache
+config.h.in
 config.log
 config.status
 configure
 config.log
 config.status
 configure
@@ -37,4 +39,3 @@ useradmin
 userlist
 weekly
 whobbs
 userlist
 weekly
 whobbs
-config.h.in
index 5d06bca63fccc18dbf864d2ab2043f64d3c41251..2d70ec3c7745f99be5d45d46ac0005955f0f610e 100644 (file)
@@ -1,3 +1,16 @@
+1999-04-03 Nathan Bryant <bryant@cs.usm.maine.edu>
+       * Makefile.in, configure.in, chkpwd.c, acconfig.h: support for
+         `chkpwd', a setuid helper program for machines which use shadow
+         passwords (configure --enable-chkpwd)
+       * Makefile.in, configure.in, auth.c, citadel.pam, user_ops.c: support
+         for PAM or shadow passwords (configure --with-pam)
+       * Makefile.in: made some messages simpler
+       * citadel.spec: updated for 5.53; correct name of tarball; build with
+         --enable-chkpwd and --with-pam; add defattr tags so rpm's can be
+         built by non-root user
+       * commands.c: cosmetic cleanup
+       * config.c: (security/paranoia) check permissions on citadel.config
+
 Sun Mar 21 14:21:47 EST 1999 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
        * messages.c: cosmetic cleanups to message reading loop
 
 Sun Mar 21 14:21:47 EST 1999 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
        * messages.c: cosmetic cleanups to message reading loop
 
index e2720353dcc0f760dbb65725f2ad5042dafce741..f6c92b34efc912e8f64eeabacc3e7e3870900440 100644 (file)
@@ -13,6 +13,7 @@
 ########################################################################
 
 TARGETS=@TARGETS@
 ########################################################################
 
 TARGETS=@TARGETS@
+CHKPWD=@CHKPWD@
 
 all: $(TARGETS)
 
 
 all: $(TARGETS)
 
@@ -22,7 +23,7 @@ SUFFIX=@SUFFIX@
 SO=@SO@
 
 CLIENT_TARGETS=citadel$(SUFFIX) whobbs$(SUFFIX)
 SO=@SO@
 
 CLIENT_TARGETS=citadel$(SUFFIX) whobbs$(SUFFIX)
-SERVER_TARGETS=citserver setup
+SERVER_TARGETS=citserver setup $(CHKPWD)
 SERV_MODULES=modules/serv_chat$(SO) \
        modules/serv_upgrade$(SO) modules/serv_expire$(SO)
 UTIL_TARGETS=aidepost netmailer netproc netsetup msgform readlog rcit \
 SERV_MODULES=modules/serv_chat$(SO) \
        modules/serv_upgrade$(SO) modules/serv_expire$(SO)
 UTIL_TARGETS=aidepost netmailer netproc netsetup msgform readlog rcit \
@@ -33,6 +34,7 @@ PROXY_TARGETS=proxy
 prefix=@prefix@
 srcdir=@srcdir@
 
 prefix=@prefix@
 srcdir=@srcdir@
 
+AUTH=@AUTH@
 DEFS=@DEFS@
 CPPFLAGS=@CPPFLAGS@ -I.
 CFLAGS=@CFLAGS@
 DEFS=@DEFS@
 CPPFLAGS=@CPPFLAGS@ -I.
 CFLAGS=@CFLAGS@
@@ -42,6 +44,7 @@ LDFLAGS=@LDFLAGS@
 SERVER_LDFLAGS=@SERVER_LDFLAGS@
 PICFLAGS=@PICFLAGS@
 CURSES=@CURSES@
 SERVER_LDFLAGS=@SERVER_LDFLAGS@
 PICFLAGS=@PICFLAGS@
 CURSES=@CURSES@
+chkpwd_LIBS=@chkpwd_LIBS@
 LIBOBJS=@LIBOBJS@
 PTHREAD_DEFS=-D_REENTRANT
 INSTALL=@INSTALL@
 LIBOBJS=@LIBOBJS@
 PTHREAD_DEFS=-D_REENTRANT
 INSTALL=@INSTALL@
@@ -61,7 +64,8 @@ SOURCES=aidepost.c citadel.c citmail.c citserver.c client_chat.c commands.c \
        room_ops.c rooms.c routines.c routines2.c serv_chat.c \
        serv_info.c serv_test.c serv_upgrade.c setup.c snprintf.c stats.c \
        support.c sysdep.c tools.c user_ops.c userlist.c serv_expire.c \
        room_ops.c rooms.c routines.c routines2.c serv_chat.c \
        serv_info.c serv_test.c serv_upgrade.c setup.c snprintf.c stats.c \
        support.c sysdep.c tools.c user_ops.c userlist.c serv_expire.c \
-       whobbs.c sendcommand.c mime_parser.c base64.c qpdecode.c getutline.c
+       whobbs.c sendcommand.c mime_parser.c base64.c qpdecode.c getutline.c \
+       auth.c chkpwd.c
 
 DEP_FILES=$(SOURCES:.c=.d)
 
 
 DEP_FILES=$(SOURCES:.c=.d)
 
@@ -95,13 +99,13 @@ netpoll: netpoll.o config.o ipc_c_tcp.o tools.o $(LIBOBJS)
 citserver: citserver.ro user_ops.ro support.ro room_ops.ro file_ops.ro \
        msgbase.ro config.ro sysdep.ro locate_host.ro \
        housekeeping.ro database.ro control.ro logging.ro \
 citserver: citserver.ro user_ops.ro support.ro room_ops.ro file_ops.ro \
        msgbase.ro config.ro sysdep.ro locate_host.ro \
        housekeeping.ro database.ro control.ro logging.ro \
-       policy.ro dynloader.ro tools.ro mime_parser.ro $(LIBOBJS:.o=.ro)
+       policy.ro dynloader.ro tools.ro mime_parser.ro $(AUTH) $(LIBOBJS:.o=.ro)
        $(CC) \
                citserver.ro user_ops.ro room_ops.ro file_ops.ro support.ro \
                msgbase.ro config.ro sysdep.ro locate_host.ro \
                housekeeping.ro database.ro control.ro logging.ro \
                policy.ro dynloader.ro tools.ro mime_parser.ro \
        $(CC) \
                citserver.ro user_ops.ro room_ops.ro file_ops.ro support.ro \
                msgbase.ro config.ro sysdep.ro locate_host.ro \
                housekeeping.ro database.ro control.ro logging.ro \
                policy.ro dynloader.ro tools.ro mime_parser.ro \
-               $(LIBOBJS:.o=.ro)\
+               $(AUTH) $(LIBOBJS:.o=.ro)\
                $(LDFLAGS) $(SERVER_LDFLAGS) $(LIBS) -o citserver
 
 .c.ro:
                $(LDFLAGS) $(SERVER_LDFLAGS) $(LIBS) -o citserver
 
 .c.ro:
@@ -163,6 +167,9 @@ mailinglist: mailinglist.o config.o internetmail.o
 setup: setup.o tools.o
        $(CC) setup.o tools.o $(CURSES) $(LDFLAGS) -o setup
 
 setup: setup.o tools.o
        $(CC) setup.o tools.o $(CURSES) $(LDFLAGS) -o setup
 
+chkpwd: chkpwd.o auth.o config.o
+       $(CC) chkpwd.o auth.o config.o $(LDFLAGS) -o chkpwd $(chkpwd_LIBS)
+
 netsetup: netsetup.o config.o
        $(CC) netsetup.o config.o $(LDFLAGS) -o netsetup
 
 netsetup: netsetup.o config.o
        $(CC) netsetup.o config.o $(LDFLAGS) -o netsetup
 
@@ -208,30 +215,43 @@ stats: stats.o ipc_c_tcp.o tools.o config.o $(LIBOBJS)
 install: install-exec install-data install-doc
 
 install-data:
 install: install-exec install-data install-doc
 
 install-data:
-       for i in help messages network/spoolin network/spoolout \
+       @for i in help messages network/spoolin network/spoolout \
                 network/systems; do \
                 network/systems; do \
-               ./mkinstalldirs $(prefix)/$$i; \
+               ./mkinstalldirs $(root)$(prefix)/$$i; \
        done
        done
-       for i in citadel.rc public_clients \
+       @for i in citadel.rc public_clients \
                 `find help messages network -type f | grep -v CVS`; do \
                 `find help messages network -type f | grep -v CVS`; do \
-               $(INSTALL_DATA) $$i $(prefix)/$$i; \
+               $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
+               echo $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
        done
        done
+       @if test -d $(root)/etc/pam.d; then \
+               $(INSTALL_DATA) citadel.pam $(root)/etc/pam.d/citadel; \
+               echo $(INSTALL_DATA) citadel.pam $(root)/etc/pam.d/citadel; \
+       fi
 
 install-doc:
 
 install-doc:
-       ./mkinstalldirs $(prefix)/techdoc
-       for i in *.txt `find techdoc -type f | grep -v CVS`; do \
-               $(INSTALL_DATA) $$i $(prefix)/$$i; \
+       @./mkinstalldirs $(root)$(prefix)/techdoc
+       @for i in *.txt `find techdoc -type f | grep -v CVS`; do \
+               $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
+               echo $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
        done
 
 install-exec: all weekly
        done
 
 install-exec: all weekly
-       for i in bio bitbucket files images info modules userpics; do \
-               ./mkinstalldirs $(prefix)/$$i; \
+       @for i in bio bitbucket files images info modules userpics; do \
+               ./mkinstalldirs $(root)$(prefix)/$$i; \
        done
        done
-       for i in $(CLIENT_TARGETS) $(SERVER_TARGETS) $(UTIL_TARGETS) \
+       @for i in $(CLIENT_TARGETS) $(SERVER_TARGETS) $(UTIL_TARGETS) \
                 $(PROXY_TARGETS) $(SERV_MODULES) utilsmenu weekly \
                 dnetsetup; do \
                 $(PROXY_TARGETS) $(SERV_MODULES) utilsmenu weekly \
                 dnetsetup; do \
-               test -f $$i && $(INSTALL) $$i $(prefix)/$$i; \
+               if test -f $$i; then \
+                       $(INSTALL) $$i $(root)$(prefix)/$$i; \
+                       echo $(INSTALL) $$i $(root)$(prefix)/$$i; \
+               fi \
        done
        done
+       @if test -f $(root)$(prefix)/chkpwd; then \
+               chmod u+s $(root)$(prefix)/chkpwd; \
+               echo chmod +s $(root)$(prefix)/chkpwd; \
+       fi
 
 clean:
        rm -f *.o *.ro *.mo
 
 clean:
        rm -f *.o *.ro *.mo
@@ -244,8 +264,9 @@ distclean: cleaner
        rm -f Makefile sysdep.h config.cache config.log config.status *.d weekly
 
 .c.d:
        rm -f Makefile sysdep.h config.cache config.log config.status *.d weekly
 
 .c.d:
-       $(CC) -M $(CPPFLAGS) $< | sed -e 's!$*.o!$*.o $*.ro $*.mo $@!' > $@
-       test -s $@ || rm -f $@
+       @echo Checking dependencies for $<
+       @$(CC) -M $(CPPFLAGS) $< | sed -e 's!$*.o!$*.o $*.ro $*.mo $@!' > $@
+       @test -s $@ || rm -f $@
 
 Makefile: $(srcdir)/Makefile.in config.status
        CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status
 
 Makefile: $(srcdir)/Makefile.in config.status
        CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status
index ae2811ffbc4395651c3f7a9fc934d0a06a851c4f..20447a49fea4f624d625fb3745a95c13307d3bff 100644 (file)
@@ -4,6 +4,9 @@
 /* define this to enable the autologin feature */
 #undef ENABLE_AUTOLOGIN
 
 /* define this to enable the autologin feature */
 #undef ENABLE_AUTOLOGIN
 
+/* define this to enable use of the chkpwd program (for shadow passwords) */
+#undef ENABLE_CHKPWD
+
 /* define this if struct utmp has an ut_type member */
 #undef HAVE_UT_TYPE
 
 /* define this if struct utmp has an ut_type member */
 #undef HAVE_UT_TYPE
 
diff --git a/citadel/auth.c b/citadel/auth.c
new file mode 100644 (file)
index 0000000..927c6dd
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * auth.c -- system-level password checking for autologin
+ * by Nathan Bryant, March 1999
+ *
+ * $Id$
+ */
+
+#ifdef linux
+#define _XOPEN_SOURCE          /* needed for crypt() */
+#define _XOPEN_SOURCE_EXTENDED /* needed for strdup() */
+#endif
+
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "auth.h"
+#include "sysdep.h"
+
+#ifdef HAVE_GETSPNAM
+#include <shadow.h>
+#endif
+
+#ifdef HAVE_PAM_START
+#include <security/pam_appl.h>
+
+/*
+ * struct appdata: passed to the conversation function
+ */
+
+struct appdata
+{
+  const char *name;
+  const char *pw;
+};
+
+/*
+ * conv(): the PAM conversation function. this assumes that a
+ * PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is
+ * asking for a password. esoteric authentication modules will fail with this
+ * code, but we can't really support them with the existing client protocol
+ * anyway. the failure mode should be to deny access, in any case.
+ */
+
+static int conv(int num_msg, const struct pam_message **msg,
+               struct pam_response **resp, void *appdata_ptr)
+{
+  struct pam_response *temp_resp;
+  struct appdata *data = appdata_ptr;
+
+  if ((temp_resp = malloc(sizeof(struct pam_response[num_msg]))) == NULL)
+    return PAM_CONV_ERR;
+
+  while (num_msg--)
+    {
+      switch ((*msg)[num_msg].msg_style)
+       {
+       case PAM_PROMPT_ECHO_ON:
+         temp_resp[num_msg].resp = strdup(data->name);
+         break;
+       case PAM_PROMPT_ECHO_OFF:
+         temp_resp[num_msg].resp = strdup(data->pw);
+         break;
+       default:
+         temp_resp[num_msg].resp = NULL;
+       }
+      temp_resp[num_msg].resp_retcode = 0;
+    }
+
+  *resp = temp_resp;
+  return PAM_SUCCESS;
+}
+#endif /* HAVE_PAM_START */
+
+/*
+ * validpw(): check that `pass' is the correct password for `uid'
+ *            returns zero if no, nonzero if yes
+ */
+
+int validpw(uid_t uid, const char *pass)
+{
+#ifdef HAVE_PAM_START
+  struct pam_conv pc;
+  struct appdata data;
+  pam_handle_t *ph;
+  int i;
+#else
+  char *crypted_pwd;
+#ifdef HAVE_GETSPNAM
+  struct spwd *sp;
+#endif
+#endif
+  struct passwd *pw;
+  int retval = 0;
+
+  if ((pw = getpwuid(uid)) == NULL)
+    return retval;
+
+#ifdef HAVE_PAM_START
+  pc.conv = conv;
+  pc.appdata_ptr = &data;
+  data.name = pw->pw_name;
+  data.pw = pass;
+  if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS)
+    return retval;
+
+  if ((i = pam_authenticate(ph, PAM_SILENT)) == PAM_SUCCESS)
+    if ((i = pam_acct_mgmt(ph, PAM_SILENT)) == PAM_SUCCESS)
+      retval = -1;
+
+  pam_end(ph, i | PAM_DATA_SILENT);
+#else
+  crypted_pwd = pw->pw_passwd;
+
+#ifdef HAVE_GETSPNAM
+  if ((sp = getspnam(pw->pw_name)) != NULL)
+    crypted_pwd = sp->sp_pwdp;
+#endif
+
+  if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd))
+    retval = -1;
+#endif /* HAVE_PAM_START */
+
+  return retval;
+}
diff --git a/citadel/auth.h b/citadel/auth.h
new file mode 100644 (file)
index 0000000..ea5fc59
--- /dev/null
@@ -0,0 +1,2 @@
+/* $Id$ */
+int validpw(uid_t uid, const char *pass);
diff --git a/citadel/chkpwd.c b/citadel/chkpwd.c
new file mode 100644 (file)
index 0000000..3dd3264
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * chkpwd.c: a setuid helper program for machines which use shadow passwords
+ * by Nathan Bryant, March 1999
+ *
+ * $Id$
+ */
+
+#include <pwd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "auth.h"
+#include "config.h"
+#include "citadel.h"
+
+int main(void)
+{
+  uid_t uid;
+  struct passwd *pw;
+  char buf[256];
+
+  get_config();
+
+  if ((uid = getuid()) != BBSUID)
+    {
+      pw = getpwuid(uid);
+      openlog("chkpwd", LOG_CONS, LOG_AUTH);
+      syslog(LOG_WARNING, "invoked by %s (uid %u); possible breakin/probe "
+            "attempt", pw != NULL ? pw->pw_name : "?", uid);
+      return 1;
+    }
+
+  if (fgets(buf, sizeof buf, stdin) == NULL)
+    return 1;
+
+  strtok(buf, "\n");
+  uid = atoi(buf);
+
+  if (fgets(buf, sizeof buf, stdin) == NULL)
+    return 1;
+
+  strtok(buf, "\n");
+
+  if (validpw(uid, buf))
+    return 0;
+
+  return 1;
+}
diff --git a/citadel/citadel.pam b/citadel/citadel.pam
new file mode 100644 (file)
index 0000000..02afd5e
--- /dev/null
@@ -0,0 +1,10 @@
+#%PAM-1.0
+#
+# /etc/pam.d/citadel: PAM configuration file for Linux-PAM.
+#
+# $Id$
+#
+auth       required    /lib/security/pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
+auth       required    /lib/security/pam_pwdb.so shadow
+auth       required    /lib/security/pam_shells.so
+account    required    /lib/security/pam_pwdb.so
index 6b89b758db227e1bd7b55607fead6a6310fa4bc9..c38b23676ffa69d80418b95ef8bf78f10c67de79 100644 (file)
@@ -1,11 +1,11 @@
 # $Id$
 Summary: Citadel/UX
 Name: citadel
 # $Id$
 Summary: Citadel/UX
 Name: citadel
-Version: 5.52
+Version: 5.53
 Release: 1
 Copyright: GPL
 Group: Applications/Communications
 Release: 1
 Copyright: GPL
 Group: Applications/Communications
-Source0: citadel.tar.gz
+Source0: citadel-ux-%{PACKAGE_VERSION}.tar.gz
 Buildroot: /var/tmp/citadel-%{PACKAGE_VERSION}-root
 Autoprov: false
 
 Buildroot: /var/tmp/citadel-%{PACKAGE_VERSION}-root
 Autoprov: false
 
@@ -17,13 +17,13 @@ driven, and accessible via a growing selection of front ends.
 %setup -n citadel
 
 %build
 %setup -n citadel
 
 %build
-CFLAGS="$RPM_OPT_FLAGS" ./configure
+CFLAGS="$RPM_OPT_FLAGS" ./configure --enable-chkpwd --with-pam
 make
 
 %install
 rm -rf $RPM_BUILD_ROOT
 make
 
 %install
 rm -rf $RPM_BUILD_ROOT
-mkdir -p $RPM_BUILD_ROOT/usr/local/citadel
-make prefix=$RPM_BUILD_ROOT/usr/local/citadel install
+mkdir -p $RPM_BUILD_ROOT/etc/pam.d
+make root=$RPM_BUILD_ROOT install
 find $RPM_BUILD_ROOT/usr/local/citadel -type d | sed "s|$RPM_BUILD_ROOT|%dir |" > filelist
 find $RPM_BUILD_ROOT -type f | egrep -v '(citadel\.rc|public_clients|/help/|/messages/|/network/)' | sed "s|$RPM_BUILD_ROOT||" >> filelist
 find $RPM_BUILD_ROOT -type f | egrep '(citadel\.rc|public_clients|/help/|/messages/|/network/)' | sed "s|$RPM_BUILD_ROOT|%config |" >> filelist
 find $RPM_BUILD_ROOT/usr/local/citadel -type d | sed "s|$RPM_BUILD_ROOT|%dir |" > filelist
 find $RPM_BUILD_ROOT -type f | egrep -v '(citadel\.rc|public_clients|/help/|/messages/|/network/)' | sed "s|$RPM_BUILD_ROOT||" >> filelist
 find $RPM_BUILD_ROOT -type f | egrep '(citadel\.rc|public_clients|/help/|/messages/|/network/)' | sed "s|$RPM_BUILD_ROOT|%config |" >> filelist
@@ -33,3 +33,4 @@ rm -rf "$RPM_BUILD_ROOT"
 rm -f filelist
 
 %files -f filelist
 rm -f filelist
 
 %files -f filelist
+%defattr(-,root,root)
index 2a5bd73d4ec291b64b0a2d974f391300c0ef2c8f..89f7fd99395d9d2a4a386212112ac4730b6b4df3 100644 (file)
@@ -158,6 +158,7 @@ int inkey(void) {           /* get a character from the keyboard, with   */
        time_t start_time, now;
        char inbuf[2];
 
        time_t start_time, now;
        char inbuf[2];
 
+       fflush(stdout);
        time(&start_time);
        
        do {
        time(&start_time);
        
        do {
@@ -168,7 +169,6 @@ int inkey(void) {           /* get a character from the keyboard, with   */
                 */
                do {
                        do_keepalive();
                 */
                do {
                        do_keepalive();
-                       fflush(stdout);
                        FD_ZERO(&rfds);
                        FD_SET(0,&rfds);
                        tv.tv_sec = S_KEEPALIVE;
                        FD_ZERO(&rfds);
                        FD_SET(0,&rfds);
                        tv.tv_sec = S_KEEPALIVE;
index 4e2e5a271f8915fbe4113dba2770678978466f04..e738ff57dcebec0802b9b3c8d3da3edfdf396f7a 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "sysdep.h"
 #include <stdlib.h>
 
 #include "sysdep.h"
 #include <stdlib.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <errno.h>
@@ -21,12 +22,13 @@ int home_specified = 0;
 
 void get_config(void) {
        FILE *cfp;
 
 void get_config(void) {
        FILE *cfp;
+       struct stat st;
 
        if (chdir( home_specified ? bbs_home_directory : BBSDIR ) != 0) {
                fprintf(stderr, "Cannot start.\nThere is no Citadel installation in %s\n%s\n",
                        (home_specified ? bbs_home_directory : BBSDIR),
                        strerror(errno));
 
        if (chdir( home_specified ? bbs_home_directory : BBSDIR ) != 0) {
                fprintf(stderr, "Cannot start.\nThere is no Citadel installation in %s\n%s\n",
                        (home_specified ? bbs_home_directory : BBSDIR),
                        strerror(errno));
-               exit(errno);
+               exit(1);
                }
        cfp=fopen("citadel.config","rb");
        if (cfp==NULL) {
                }
        cfp=fopen("citadel.config","rb");
        if (cfp==NULL) {
@@ -34,9 +36,18 @@ void get_config(void) {
                fprintf(stderr, "There is no citadel.config in %s\n%s\n",
                        (home_specified ? bbs_home_directory : BBSDIR),
                        strerror(errno));
                fprintf(stderr, "There is no citadel.config in %s\n%s\n",
                        (home_specified ? bbs_home_directory : BBSDIR),
                        strerror(errno));
-               exit(errno);
+               exit(1);
                }
        fread((char *)&config,sizeof(struct config),1,cfp);
                }
        fread((char *)&config,sizeof(struct config),1,cfp);
+       if (fstat(fileno(cfp), &st)) {
+               perror("citadel.config");
+               exit(1);
+               }
+       if (st.st_uid != BBSUID || st.st_mode != (S_IFREG | S_IRUSR | S_IWUSR))
+               {
+               fprintf(stderr, "check the permissions on citadel.config\n");
+               exit(1);
+               }
        fclose(cfp);
        if ( (config.c_setup_level / 10) != (REV_LEVEL/10) ) {
                fprintf(stderr, "config: Your data files are out of date.  ");
        fclose(cfp);
        if ( (config.c_setup_level / 10) != (REV_LEVEL/10) ) {
                fprintf(stderr, "config: Your data files are out of date.  ");
index 258bd3150fc705fa07e3430c229a8466ad8ce5c1..4c11a186ee31c88f6312e21939a75f63f13e2edc 100644 (file)
@@ -10,6 +10,8 @@ else
 fi
 
 AC_ARG_ENABLE(autologin, [  --disable-autologin     disable autologin (default is enabled if possible)])
 fi
 
 AC_ARG_ENABLE(autologin, [  --disable-autologin     disable autologin (default is enabled if possible)])
+AC_ARG_ENABLE(chkpwd, [  --enable-chkpwd         build 'chkpwd' (use this if you have shadow passwords)])
+AC_ARG_WITH(pam, [  --with-pam              use PAM if present])
 
 dnl By default, we only build the client (citadel and whobbs) unless we can
 dnl figure out how to build with POSIX threads.
 
 dnl By default, we only build the client (citadel and whobbs) unless we can
 dnl figure out how to build with POSIX threads.
@@ -26,8 +28,8 @@ case "$host" in
                SO=.mo
                AC_DEFINE(HAVE_NONREENTRANT_NETDB)
        ;;
                SO=.mo
                AC_DEFINE(HAVE_NONREENTRANT_NETDB)
        ;;
-       dnl Digital Unix has an odd way to build pthreads, and we can't build
-       dnl pthreads programs with gcc due to header problems.
+       dnl Digital Unix has an odd way to build for pthreads, and we can't
+       dnl build pthreads programs with gcc due to header problems.
        alpha*-dec-osf*)
                test -z "$CC" && CC=cc
                SERVER_LDFLAGS=-pthread
        alpha*-dec-osf*)
                test -z "$CC" && CC=cc
                SERVER_LDFLAGS=-pthread
@@ -71,20 +73,39 @@ dnl We want to test for crypt() and dlopen() in libc before checking for
 dnl -lcrypt and -ldl, because some systems (like Irix) have both.
 AC_CHECK_FUNCS(crypt dlopen)
 
 dnl -lcrypt and -ldl, because some systems (like Irix) have both.
 AC_CHECK_FUNCS(crypt dlopen)
 
-dnl We only need crypt() if we're using autologin. FIXME: implement shadow
-dnl passwords and/or PAM...
-if test "$enable_autologin" != no -a "$ac_cv_func_crypt" = no; then
-       AC_CHECK_LIB(crypt, crypt)
-fi
-
-dnl Enable autologin if the feature is requested (which is the default) and
-dnl a crypt() functin is available.
-if test "$enable_autologin" != no -a \( "$ac_cv_func_crypt" = yes -o "$ac_cv_lib_crypt_crypt" = yes \); then
-       AC_DEFINE(ENABLE_AUTOLOGIN)
+if test "$ac_cv_func_dlopen" = no; then
+        AC_CHECK_LIB(dl, dlopen, [LIBS="-ldl $LIBS"
+               chkpwd_LIBS=-ldl])
 fi
 
 fi
 
-if test "$ac_cv_func_dlopen" = no; then
-       AC_CHECK_LIB(dl, dlopen)
+dnl Determine the system's authentication capabilities, if autologin is
+dnl requested. We currently support PAM, standard getpwnam(), and getspnam()
+dnl (Linux shadow passwords)
+if test "$enable_autologin" != no; then
+       if test "$with_pam" = yes; then
+               save_LIBS=$LIBS
+               AC_CHECK_LIB(pam, pam_start, [chkpwd_LIBS="-lpam $chkpwd_LIBS"
+                       LIBS="-lpam $LIBS"])
+               AC_CHECK_FUNCS(pam_start)
+               test "$enable_chkpwd" = yes && LIBS=$save_LIBS
+       fi
+       if test "$ac_cv_func_pam_start" = no -o "$with_pam" != yes; then
+               AC_CHECK_LIB(shadow, getspnam)
+               if test "$ac_cv_func_crypt" = no; then
+                       AC_CHECK_LIB(crypt, crypt, [chkpwd_LIBS=-lcrypt
+                               test "$enable_chkpwd" != yes && \
+                                       LIBS="-lcrypt $LIBS"])
+               fi
+       fi
+       if test "$ac_cv_func_crypt" = yes -o "$ac_cv_lib_crypt_crypt" = yes -o "$ac_cv_func_pam_start" = yes; then
+               AC_DEFINE(ENABLE_AUTOLOGIN)
+               if test "$enable_chkpwd" = yes; then
+                       AC_DEFINE(ENABLE_CHKPWD)
+                       CHKPWD=chkpwd
+               else
+                       AUTH=auth.ro
+               fi
+       fi
 fi
 
 AC_CHECK_LIB(gdbm, gdbm_open)
 fi
 
 AC_CHECK_LIB(gdbm, gdbm_open)
@@ -127,13 +148,16 @@ AC_FUNC_GETPGRP
 AC_PROG_GCC_TRADITIONAL
 AC_TYPE_SIGNAL
 AC_FUNC_VPRINTF
 AC_PROG_GCC_TRADITIONAL
 AC_TYPE_SIGNAL
 AC_FUNC_VPRINTF
-AC_CHECK_FUNCS(mkdir mkfifo mktime pthread_cancel rmdir select socket strerror)
+AC_CHECK_FUNCS(getspnam mkdir mkfifo mktime pthread_cancel rmdir select socket strerror)
 AC_CHECK_FUNC(pthread_create, TARGETS="client server utils serv_modules")
 AC_REPLACE_FUNCS(snprintf getutline)
 
 dnl Done! Now write the Makefile and sysdep.h
 AC_CHECK_FUNC(pthread_create, TARGETS="client server utils serv_modules")
 AC_REPLACE_FUNCS(snprintf getutline)
 
 dnl Done! Now write the Makefile and sysdep.h
+AC_SUBST(AUTH)
 AC_SUBST(SO)
 AC_SUBST(SO)
+AC_SUBST(CHKPWD)
 AC_SUBST(CURSES)
 AC_SUBST(CURSES)
+AC_SUBST(chkpwd_LIBS)
 AC_SUBST(TARGETS)
 AC_SUBST(SERVER_LDFLAGS)
 AC_SUBST(PICFLAGS)
 AC_SUBST(TARGETS)
 AC_SUBST(SERVER_LDFLAGS)
 AC_SUBST(PICFLAGS)
index fc7cf3a6ad3a63e857e3daa8cbcb88873857e284..cb40a3ac139ec8d2e7829e4e04973c88dce521d1 100644 (file)
@@ -1,9 +1,9 @@
-                         Citadel/UX release 5.52
+                         Citadel/UX release 5.53
 
 Copyright (c) 1987-1999 by:
         Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
 
 
 Copyright (c) 1987-1999 by:
         Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
 
-Portions (c) 1998 by:
+Portions (c) 1998-1999 by:
        Brian Costello <btx@calyx.net>
        Nathan Bryant <bryant@cs.usm.maine.edu>
  
        Brian Costello <btx@calyx.net>
        Nathan Bryant <bryant@cs.usm.maine.edu>
  
index 2a7f24d2765f795c85bc104253fabadecd31ff88..0848a52982d994cebe00f75bd449a4bf1e685278 100644 (file)
@@ -1,14 +1,5 @@
 /* $Id$ */
 
 /* $Id$ */
 
-#ifndef _SGI_SOURCE
-/* needed to properly enable crypt() stuff on some systems */
-#define _XOPEN_SOURCE
-/* needed for str[n]casecmp() on some systems if the above is defined */
-#define _XOPEN_SOURCE_EXTENDED
-/* needed to enable threads on some systems if the above are defined */
-#define _POSIX_C_SOURCE 199506L
-#endif
-
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
@@ -17,6 +8,7 @@
 #include <signal.h>
 #include <pwd.h>
 #include <sys/types.h>
 #include <signal.h>
 #include <pwd.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/time.h>
 #include <string.h>
 #include <syslog.h>
 #include <sys/time.h>
 #include <string.h>
 #include <syslog.h>
@@ -24,6 +16,9 @@
 #ifdef HAVE_PTHREAD_H
 #include <pthread.h>
 #endif
 #ifdef HAVE_PTHREAD_H
 #include <pthread.h>
 #endif
+#ifndef ENABLE_CHKPWD
+#include "auth.h"
+#endif
 #include "citadel.h"
 #include "server.h"
 #include "database.h"
 #include "citadel.h"
 #include "server.h"
 #include "database.h"
@@ -348,12 +343,69 @@ void logout(struct CitContext *who)
        PerformSessionHooks(EVT_LOGOUT);
        }
 
        PerformSessionHooks(EVT_LOGOUT);
        }
 
+#ifdef ENABLE_CHKPWD
+/*
+ * an alternate version of validpw() which executes `chkpwd' instead of
+ * verifying the password directly
+ */
+static int validpw(uid_t uid, const char *pass)
+{
+       pid_t pid;
+       int status, pipev[2];
+       char buf[24];
+
+       if (pipe(pipev)) {
+               lprintf(1, "pipe failed (%s): denying autologin access for "
+                          "uid %u\n", strerror(errno), uid);
+               return 0;
+               }
+
+       switch (pid = fork()) {
+           case -1:
+               lprintf(1, "fork failed (%s): denying autologin access for "
+                          "uid %u\n", strerror(errno), uid);
+               close(pipev[0]);
+               close(pipev[1]);
+               return 0;
+
+           case 0:
+               close(pipev[1]);
+               if (dup2(pipev[0], 0) == -1) {
+                       perror("dup2");
+                       exit(1);
+                       }
+               close(pipev[0]);
+
+               execl(BBSDIR "/chkpwd", BBSDIR "/chkpwd", NULL);
+               perror(BBSDIR "/chkpwd");
+               exit(1);
+               }
+
+       close(pipev[0]);
+       write(pipev[1], buf, sprintf(buf, "%u\n", uid));
+       write(pipev[1], pass, strlen(pass));
+       write(pipev[1], "\n", 1);
+       close(pipev[1]);
+
+       while (waitpid(pid, &status, 0) == -1)
+               if (errno != EINTR) {
+                       lprintf(1, "waitpid failed (%s): denying autologin "
+                                  "access for uid %u\n",
+                               strerror(errno), uid);
+                       return 0;
+                       }
+
+       if (WIFEXITED(status) && !WEXITSTATUS(status))
+               return 1;
+
+       return 0;
+       }
+#endif
 
 void cmd_pass(char *buf)
 {
        char password[256];
        int code;
 
 void cmd_pass(char *buf)
 {
        char password[256];
        int code;
-       struct passwd *p;
 
        extract(password,buf,0);
 
 
        extract(password,buf,0);
 
@@ -376,20 +428,17 @@ void cmd_pass(char *buf)
                strproc(CC->usersupp.password);
                code = strcasecmp(CC->usersupp.password,password);
                }
                strproc(CC->usersupp.password);
                code = strcasecmp(CC->usersupp.password,password);
                }
-       else {
-               p = (struct passwd *)getpwuid(CC->usersupp.USuid);
 #ifdef ENABLE_AUTOLOGIN
 #ifdef ENABLE_AUTOLOGIN
-               if (p!=NULL) {
-                       if (!strcmp(p->pw_passwd,
-                          (char *)crypt(password,p->pw_passwd))) {
-                               code = 0;
-                               lgetuser(&CC->usersupp, CC->curr_user);
-                               strcpy(CC->usersupp.password, password);
-                               lputuser(&CC->usersupp, CC->curr_user);
-                               }
+       else {
+               if (validpw(CC->usersupp.USuid, password)) {
+                       code = 0;
+                       lgetuser(&CC->usersupp, CC->curr_user);
+                       safestrncpy(CC->usersupp.password, password,
+                                   sizeof CC->usersupp.password);
+                       lputuser(&CC->usersupp, CC->curr_user);
                        }
                        }
-#endif
                }
                }
+#endif
 
        if (!code) {
                (CC->logged_in) = 1;
 
        if (!code) {
                (CC->logged_in) = 1;