* 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
+chkpwd
 citadel
 citadel.config
 citadel.control
@@ -11,6 +12,7 @@ citadel.log
 citmail
 citserver
 config.cache
+config.h.in
 config.log
 config.status
 configure
@@ -37,4 +39,3 @@ useradmin
 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
 
index e2720353dcc0f760dbb65725f2ad5042dafce741..f6c92b34efc912e8f64eeabacc3e7e3870900440 100644 (file)
@@ -13,6 +13,7 @@
 ########################################################################
 
 TARGETS=@TARGETS@
+CHKPWD=@CHKPWD@
 
 all: $(TARGETS)
 
@@ -22,7 +23,7 @@ SUFFIX=@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 \
@@ -33,6 +34,7 @@ PROXY_TARGETS=proxy
 prefix=@prefix@
 srcdir=@srcdir@
 
+AUTH=@AUTH@
 DEFS=@DEFS@
 CPPFLAGS=@CPPFLAGS@ -I.
 CFLAGS=@CFLAGS@
@@ -42,6 +44,7 @@ LDFLAGS=@LDFLAGS@
 SERVER_LDFLAGS=@SERVER_LDFLAGS@
 PICFLAGS=@PICFLAGS@
 CURSES=@CURSES@
+chkpwd_LIBS=@chkpwd_LIBS@
 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 \
-       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)
 
@@ -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 \
-       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 \
-               $(LIBOBJS:.o=.ro)\
+               $(AUTH) $(LIBOBJS:.o=.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
 
+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
 
@@ -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:
-       for i in help messages network/spoolin network/spoolout \
+       @for i in help messages network/spoolin network/spoolout \
                 network/systems; do \
-               ./mkinstalldirs $(prefix)/$$i; \
+               ./mkinstalldirs $(root)$(prefix)/$$i; \
        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 \
-               $(INSTALL_DATA) $$i $(prefix)/$$i; \
+               $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
+               echo $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
        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:
-       ./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
-       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
-       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 \
-               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
+       @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
@@ -244,8 +264,9 @@ distclean: cleaner
        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
index ae2811ffbc4395651c3f7a9fc934d0a06a851c4f..20447a49fea4f624d625fb3745a95c13307d3bff 100644 (file)
@@ -4,6 +4,9 @@
 /* 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
 
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
-Version: 5.52
+Version: 5.53
 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
 
@@ -17,13 +17,13 @@ driven, and accessible via a growing selection of front ends.
 %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
-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
@@ -33,3 +33,4 @@ rm -rf "$RPM_BUILD_ROOT"
 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];
 
+       fflush(stdout);
        time(&start_time);
        
        do {
@@ -168,7 +169,6 @@ int inkey(void) {           /* get a character from the keyboard, with   */
                 */
                do {
                        do_keepalive();
-                       fflush(stdout);
                        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 <sys/stat.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <errno.h>
@@ -21,12 +22,13 @@ int home_specified = 0;
 
 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));
-               exit(errno);
+               exit(1);
                }
        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));
-               exit(errno);
+               exit(1);
                }
        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.  ");
index 258bd3150fc705fa07e3430c229a8466ad8ce5c1..4c11a186ee31c88f6312e21939a75f63f13e2edc 100644 (file)
@@ -10,6 +10,8 @@ else
 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.
@@ -26,8 +28,8 @@ case "$host" in
                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
@@ -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 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
 
-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)
@@ -127,13 +148,16 @@ AC_FUNC_GETPGRP
 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_SUBST(AUTH)
 AC_SUBST(SO)
+AC_SUBST(CHKPWD)
 AC_SUBST(CURSES)
+AC_SUBST(chkpwd_LIBS)
 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>
 
-Portions (c) 1998 by:
+Portions (c) 1998-1999 by:
        Brian Costello <btx@calyx.net>
        Nathan Bryant <bryant@cs.usm.maine.edu>
  
index 2a7f24d2765f795c85bc104253fabadecd31ff88..0848a52982d994cebe00f75bd449a4bf1e685278 100644 (file)
@@ -1,14 +1,5 @@
 /* $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>
@@ -17,6 +8,7 @@
 #include <signal.h>
 #include <pwd.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/time.h>
 #include <string.h>
 #include <syslog.h>
@@ -24,6 +16,9 @@
 #ifdef HAVE_PTHREAD_H
 #include <pthread.h>
 #endif
+#ifndef ENABLE_CHKPWD
+#include "auth.h"
+#endif
 #include "citadel.h"
 #include "server.h"
 #include "database.h"
@@ -348,12 +343,69 @@ void logout(struct CitContext *who)
        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;
-       struct passwd *p;
 
        extract(password,buf,0);
 
@@ -376,20 +428,17 @@ void cmd_pass(char *buf)
                strproc(CC->usersupp.password);
                code = strcasecmp(CC->usersupp.password,password);
                }
-       else {
-               p = (struct passwd *)getpwuid(CC->usersupp.USuid);
 #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;