Hello, while converting a PureFTPd installation to vsftpd, we needed pam_userdb to authenticate against crypt(3)'d passwords stored in its password database. The following patch against pam_userdb in Linux-PAM-0.77 implements this. After this patch is installed, the default behavior is to use plaintext passwords, the same as the current version of pam_userdb. But if 'crypt=crypt' is included in the PAM service configuration file, pam_userdb will expect to find crypted passwords in its database. Comments welcome. - Paul diff -ru Linux-PAM-0.77-old/modules/pam_userdb/Makefile Linux-PAM-0.77/modules/pam_userdb/Makefile --- Linux-PAM-0.77-old/modules/pam_userdb/Makefile 2001-05-08 01:03:55.000000000 -0500 +++ Linux-PAM-0.77/modules/pam_userdb/Makefile 2004-08-19 20:51:52.000000000 -0500 @@ -24,6 +24,11 @@ endif endif +ifeq ($(HAVE_LIBCRYPT),yes) + MODULE_SIMPLE_EXTRALIBS += -lcrypt +endif + + ifeq ($(WHICH_DB),none) include ../dont_makefile diff -ru Linux-PAM-0.77-old/modules/pam_userdb/pam_userdb.c Linux-PAM-0.77/modules/pam_userdb/pam_userdb.c --- Linux-PAM-0.77-old/modules/pam_userdb/pam_userdb.c 2001-11-25 21:27:40.000000000 -0600 +++ Linux-PAM-0.77/modules/pam_userdb/pam_userdb.c 2004-08-19 20:51:52.000000000 -0500 @@ -57,6 +57,7 @@ } char * database = NULL; +char * cryptmode = NULL; static int ctrl = 0; static int _pam_parse(int argc, const char **argv) @@ -77,6 +78,11 @@ if (database == NULL) _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"", *argv); + } else if (!strncasecmp(*argv,"crypt=", 6)) { + cryptmode = strdup((*argv) + 6); + if (cryptmode == NULL) + _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"", + *argv); } else { _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); } @@ -138,15 +144,58 @@ if (data.dptr != NULL) { int compare = 0; - - if (strlen(pass) != data.dsize) { + + if (strncasecmp(cryptmode, "crypt", 5) == 0) { + + /* crypt(3) password storage */ + + char *cryptpw; + char salt[2]; + + if (data.dsize != 13) { + compare = -2; + } else if (ctrl & PAM_ICASE_ARG) { + compare = -2; + } else { + salt[0] = *data.dptr; + salt[1] = *(data.dptr + 1); + + cryptpw = crypt (pass, salt); + + if (cryptpw) { + compare = strncasecmp (data.dptr, cryptpw, data.dsize); + } else { + compare = -2; + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_INFO, "crypt() returned NULL"); + } + }; + + }; + + } else { + + /* Unknown password encryption method - + * default to plaintext password storage + */ + + if (strlen(pass) != data.dsize) { compare = 1; - } else if (ctrl & PAM_ICASE_ARG) { + } else if (ctrl & PAM_ICASE_ARG) { compare = strncasecmp(data.dptr, pass, data.dsize); - } else { + } else { compare = strncmp(data.dptr, pass, data.dsize); + } + + if (strncasecmp(cryptmode, "none", 4) && ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_INFO, "invalid value for crypt parameter: %s", + cryptmode); + _pam_log(LOG_INFO, "defaulting to plaintext password mode"); + } + } - dbm_close(dbm); + + dbm_close(dbm); if (compare == 0) return 0; /* match */ else diff -ru Linux-PAM-0.77-old/modules/pam_userdb/README Linux-PAM-0.77/modules/pam_userdb/README --- Linux-PAM-0.77-old/modules/pam_userdb/README 2000-06-20 17:12:09.000000000 -0500 +++ Linux-PAM-0.77/modules/pam_userdb/README 2004-08-19 20:51:52.000000000 -0500 @@ -9,9 +9,17 @@ db=[path] use the [path] database for performing lookup. There is no default; the module will return PAM_IGNORE if no database is provided. - + + crypt=[mode] indicates whether encrypted or plaintext passwords + are stored in the database. If [mode] is "crypt", + passwords should be stored in the database in + crypt(3) form. If [mode] is "none" or any other + value, passwords should be stored in the database in + plaintext. + icase make the password verification to be case insensitive (ie when working with registration numbers and such) + only works with plaintext password storage. dump dump all the entries in the database to the log (eek, don't do this by default!) _______________________________________________ Pam-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/pam-list