Boredom struck at work, so I finally got round to tidying up pamckpasswd. It now calls pam_acct_mgmt() and so goes through the account stack of modules too (doing useful things like ensuring the account hasn't expired). It's available from: http://www.mathie.cx/~graeme/software/pamckpasswd.tar.gz As a bonus, I've attached a diff against inn-CURRENT (well the 20011219 snapshot anyway) which integrates PAM support into the default ckpasswd if autoconf finds it. -- graeme+sig@mathie.cx http://www.mathie.cx/~graeme/ -- Attached file included as plaintext by Ecartis -- Index: Makefile.global.in =================================================================== RCS file: /disk/devel/cvs-imports/isc/inn/Makefile.global.in,v retrieving revision 1.1.1.166 retrieving revision 1.2 diff -u -r1.1.1.166 -r1.2 --- Makefile.global.in 19 Dec 2001 10:01:17 -0000 1.1.1.166 +++ Makefile.global.in 20 Dec 2001 17:17:27 -0000 1.2 @@ -106,6 +106,7 @@ EXTSTORAGELIBS = @BERKELEY_DB_LIB@ DBMLIB = @DBM_LIB@ +PAMLIB = @PAM_LIB@ ## Embedding support. Additional flags and libraries used when compiling ## or linking portions of INN that support embedded interpretors, set by Index: configure.in =================================================================== RCS file: /disk/devel/cvs-imports/isc/inn/configure.in,v retrieving revision 1.1.1.7 retrieving revision 1.2 diff -u -r1.1.1.7 -r1.2 --- configure.in 2 Sep 2001 09:00:03 -0000 1.1.1.7 +++ configure.in 20 Dec 2001 17:17:27 -0000 1.2 @@ -685,6 +685,15 @@ LIBS=$inn_save_LIBS AC_SUBST(DBM_LIB) +dnl Look for PAM +inn_save_LIBS=$LIBS +LIBS= +AC_SEARCH_LIBS(pam_start, pam, + [PAM_LIB=$LIBS + AC_DEFINE(HAVE_PAM, 1, [Define if you have PAM.])]) +LIBS=$inn_save_LIBS +AC_SUBST(PAM_LIB) + dnl Libraries and flags for embedded Perl. Some distributions of Linux have dnl Perl linked with gdbm but don't normally have gdbm installed, so on that dnl platform only strip -lgdbm out of the Perl libraries. Leave it in on Index: authprogs/Makefile =================================================================== RCS file: /disk/devel/cvs-imports/isc/inn/authprogs/Makefile,v retrieving revision 1.1.1.3 retrieving revision 1.3 diff -u -r1.1.1.3 -r1.3 --- authprogs/Makefile 17 Aug 2001 09:00:04 -0000 1.1.1.3 +++ authprogs/Makefile 20 Dec 2001 17:17:27 -0000 1.3 @@ -41,7 +41,7 @@ AUTHLIBS = $(LIBAUTH) $(LIBS) AUTH_INN = $(LIBINN) $(LIBAUTH) -CK_LIBS = $(DBMLIB) $(AUTHLIBS) +CK_LIBS = $(PAMLIB) $(DBMLIB) $(AUTHLIBS) RAD_LIBS = $(AUTH_INN) $(LIBS) auth_smb: auth_smb.o $(LIBSMB) ; $(LINK) auth_smb.o $(LIBSMB) $(LIBS) Index: authprogs/README.pamckpasswd =================================================================== RCS file: authprogs/README.pamckpasswd diff -N authprogs/README.pamckpasswd --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ authprogs/README.pamckpasswd 21 Aug 2001 10:02:35 -0000 1.1 @@ -0,0 +1,37 @@ +This is a hacked-together PAM version of ckpasswd for doing NNRP +authentication. It works for me. YMMV. You'll need to have +libpam.a kicking around somewhere to build it. I've included a +sample pam configuration, called 'nnrpd' which you'll want to copy +into /etc/pam.d (or wherever your pam configuration lives). It +has the added bonus that it'll prevent a list of users from connecting +(much like ftpusers). I've included the list of users I prevent from +connecting. + +You'll want to copy the binary into /usr/lib/news/bin/auth/passwd modified +for wherever your copy of INN lives. And it'll need to be suid root so +that it can access shadow passwords. And this is what my readers.conf +looks like: + +--cut here-- +# Allow only access from the local machine (remote users must use +# the SSL-wrapped version), and users must authenticate themselves +auth "localhost" { + hosts: "localhost, 127.0.0.1, stdin, *.mathie.cx, 62.189.57.194" + auth: "ckpasswd -f /etc/news/readers.passwd" + auth: "pamckpasswd" +} + +access "fail" { + newsgroups: !* +} + +access "full" { + users: * + newsgroups: * +} +--cut here-- + +That's about it. Let me know if this is actually of any use to you and +I might tidy it up a little. + + -- Graeme Mathieson Index: authprogs/ckpasswd.c =================================================================== RCS file: /disk/devel/cvs-imports/isc/inn/authprogs/ckpasswd.c,v retrieving revision 1.1.1.3 retrieving revision 1.2 diff -u -r1.1.1.3 -r1.2 --- authprogs/ckpasswd.c 11 Jul 2001 09:00:05 -0000 1.1.1.3 +++ authprogs/ckpasswd.c 20 Dec 2001 17:17:28 -0000 1.2 @@ -23,6 +23,48 @@ # include #endif +#if HAVE_PAM +# include +#endif + +#if HAVE_PAM +/* + * PAM conversation function. Since we can't very well ask the user for + * a password interactively, this function returns the password to every + * question PAM asks. There appears to be no generic way to determine + * whether the message in question is indeed asking for the password which + * is less than ideal... + * + * NOTE: This function allocates an array of 'struct pam_response' which + * needs to be free()'d later on. For this program though, it's not exactly + * an issue because it will get called once and the program will exit... + * + * appdata_ptr contains the password we were given. + */ +static int pass_conv (int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + int i; + + *response = (struct pam_response *)malloc (num_msg * + sizeof(struct pam_response)); + if (*response == NULL) + return PAM_CONV_ERR; + + for (i = 0; i < num_msg; i++) { + /* Construct the response */ + (*response)[i].resp = strdup((char *)appdata_ptr); + (*response)[i].resp_retcode = 0; + } + return PAM_SUCCESS; +} + +static struct pam_conv conv = { + pass_conv, + NULL +}; +#endif /* HAVE_PAM */ + #if HAVE_GETSPNAM char * GetShadowPass(char *user) @@ -173,7 +215,43 @@ rpass = GetDBPass(uname, fname); else #endif +#if HAVE_PAM + { + pam_handle_t *pamh; + int res; + + conv.appdata_ptr = (void *)pass; + if ((res = pam_start ("nnrpd", uname, &conv, &pamh)) != PAM_SUCCESS) { + fprintf (stderr, "Failed: pam_start(): %s\n", + pam_strerror(pamh, res)); + exit (1); + } + + if ((res = pam_authenticate (pamh, 0)) != PAM_SUCCESS) { + fprintf (stderr, "Failed: pam_authenticate(): %s\n", + pam_strerror(pamh, res)); + exit (1); + } + + if ((res = pam_acct_mgmt (pamh, 0)) != PAM_SUCCESS) { + fprintf (stderr, "Failed: pam_acct_mgmt(): %s\n", + pam_strerror (pamh, res)); + exit (1); + } + + if ((res = pam_end (pamh, res) != PAM_SUCCESS)) { + fprintf (stderr, "Failed: pam_end(): %s\n", + pam_strerror (pamh, res)); + exit (1); + } + + /* If it gets this far, the user has been successfully authenticated. */ + fprintf (stdout, "User:%s\n", uname); + exit (0); + } +#else /* HAVE_PAM */ rpass = GetPass(uname); +#endif /* HAVE_PAM */ if (!rpass) { fprintf(stderr, "ckpasswd: user %s does not exist.\n", uname); Index: authprogs/pam.conf.example =================================================================== RCS file: authprogs/pam.conf.example diff -N authprogs/pam.conf.example --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ authprogs/pam.conf.example 20 Dec 2001 17:17:28 -0000 1.2 @@ -0,0 +1,18 @@ +# +# Sample entries for pam.conf for the nnrpd service +# + +# Disallows other than root logins when /etc/nologin exists +# (Replaces the `NOLOGINS_FILE' option from login.defs) +nnrpd auth requisite pam_nologin.so + +# Ensure that system users cannot login -- this is probably a bit +# hacky, but it'll do for now. +nnrpd auth required pam_listfile.so \ + onerr=succeed item=user sense=deny file=/etc/news/readers.deny + +# Standard Un*x authentication. The "nullok" line allows passwordless +# accounts. +nnrpd auth required pam_unix.so + +nnrpd account required pam_unix.so