From 31e051fe34b06c9d21043ae9220342b20f7b3e15 Mon Sep 17 00:00:00 2001 From: Nathan Bryant Date: Sat, 3 Apr 1999 19:57:06 +0000 Subject: [PATCH] * 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 --- citadel/.cvsignore | 3 +- citadel/ChangeLog | 13 +++++ citadel/Makefile.in | 55 ++++++++++++------ citadel/acconfig.h | 3 + citadel/auth.c | 127 ++++++++++++++++++++++++++++++++++++++++++ citadel/auth.h | 2 + citadel/chkpwd.c | 53 ++++++++++++++++++ citadel/citadel.pam | 10 ++++ citadel/citadel.spec | 11 ++-- citadel/commands.c | 2 +- citadel/config.c | 15 ++++- citadel/configure.in | 54 +++++++++++++----- citadel/copyright.txt | 4 +- citadel/user_ops.c | 91 +++++++++++++++++++++++------- 14 files changed, 379 insertions(+), 64 deletions(-) create mode 100644 citadel/auth.c create mode 100644 citadel/auth.h create mode 100644 citadel/chkpwd.c create mode 100644 citadel/citadel.pam diff --git a/citadel/.cvsignore b/citadel/.cvsignore index 07dec2ba4..29fef717f 100644 --- a/citadel/.cvsignore +++ b/citadel/.cvsignore @@ -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 diff --git a/citadel/ChangeLog b/citadel/ChangeLog index 5d06bca63..2d70ec3c7 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -1,3 +1,16 @@ +1999-04-03 Nathan Bryant + * 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 * messages.c: cosmetic cleanups to message reading loop diff --git a/citadel/Makefile.in b/citadel/Makefile.in index e2720353d..f6c92b34e 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -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 diff --git a/citadel/acconfig.h b/citadel/acconfig.h index ae2811ffb..20447a49f 100644 --- a/citadel/acconfig.h +++ b/citadel/acconfig.h @@ -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 index 000000000..927c6ddb9 --- /dev/null +++ b/citadel/auth.c @@ -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 +#include +#include +#include +#include + +#include "auth.h" +#include "sysdep.h" + +#ifdef HAVE_GETSPNAM +#include +#endif + +#ifdef HAVE_PAM_START +#include + +/* + * 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 index 000000000..ea5fc5905 --- /dev/null +++ b/citadel/auth.h @@ -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 index 000000000..3dd3264f2 --- /dev/null +++ b/citadel/chkpwd.c @@ -0,0 +1,53 @@ +/* + * chkpwd.c: a setuid helper program for machines which use shadow passwords + * by Nathan Bryant, March 1999 + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..02afd5e5b --- /dev/null +++ b/citadel/citadel.pam @@ -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 diff --git a/citadel/citadel.spec b/citadel/citadel.spec index 6b89b758d..c38b23676 100644 --- a/citadel/citadel.spec +++ b/citadel/citadel.spec @@ -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) diff --git a/citadel/commands.c b/citadel/commands.c index 2a5bd73d4..89f7fd993 100644 --- a/citadel/commands.c +++ b/citadel/commands.c @@ -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; diff --git a/citadel/config.c b/citadel/config.c index 4e2e5a271..e738ff57d 100644 --- a/citadel/config.c +++ b/citadel/config.c @@ -7,6 +7,7 @@ #include "sysdep.h" #include +#include #include #include #include @@ -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. "); diff --git a/citadel/configure.in b/citadel/configure.in index 258bd3150..4c11a186e 100644 --- a/citadel/configure.in +++ b/citadel/configure.in @@ -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) diff --git a/citadel/copyright.txt b/citadel/copyright.txt index fc7cf3a6a..cb40a3ac1 100644 --- a/citadel/copyright.txt +++ b/citadel/copyright.txt @@ -1,9 +1,9 @@ - Citadel/UX release 5.52 + Citadel/UX release 5.53 Copyright (c) 1987-1999 by: Art Cancro -Portions (c) 1998 by: +Portions (c) 1998-1999 by: Brian Costello Nathan Bryant diff --git a/citadel/user_ops.c b/citadel/user_ops.c index 2a7f24d27..0848a5298 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -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 #include @@ -17,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +16,9 @@ #ifdef HAVE_PTHREAD_H #include #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; -- 2.30.2