Submitted By: Jim Gifford (jim at linuxfromscratch dot org) Date: 2004-06-09 Initial Package Version: 0.77 Origin: PAM CVS Upstream Status: Already Applied Description: Two bug fixes in one: don't trust getlogin() and sanely lower the time the password databases are locked in pam_unix. Go to the url below for more details http://www.securiteam.com/unixfocus/5UP0J1PAAQ.html diff -Naur Linux-PAM-0.77.orig/modules/pam_unix/Makefile Linux-PAM-0.77/modules/pam_unix/Makefile --- Linux-PAM-0.77.orig/modules/pam_unix/Makefile 2001-02-11 06:33:53.000000000 +0000 +++ Linux-PAM-0.77/modules/pam_unix/Makefile 2004-06-09 18:28:23.922188125 +0000 @@ -41,8 +41,10 @@ ######################################################################## -CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) -LDLIBS = $(EXTRALS) +CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) \ + -I../pammodutil/include + +LDLIBS = $(EXTRALS) -L../pammodutil -lpammodutil ifdef USE_CRACKLIB CRACKLIB = -lcrack diff -Naur Linux-PAM-0.77.orig/modules/pam_unix/pam_unix_passwd.c Linux-PAM-0.77/modules/pam_unix/pam_unix_passwd.c --- Linux-PAM-0.77.orig/modules/pam_unix/pam_unix_passwd.c 2002-07-09 04:44:18.000000000 +0000 +++ Linux-PAM-0.77/modules/pam_unix/pam_unix_passwd.c 2004-06-09 18:28:24.058164102 +0000 @@ -88,7 +88,7 @@ */ #ifdef NEED_LCKPWDF -#include "./lckpwdf.-c" +# include "./lckpwdf.-c" #endif extern char *bigcrypt(const char *key, const char *salt); @@ -471,10 +471,7 @@ D(("called")); - setpwent(); pwd = getpwnam(forwho); - endpwent(); - if (pwd == NULL) return PAM_AUTHTOK_ERR; @@ -544,6 +541,24 @@ if (save_old_password(forwho, fromwhat, remember)) { return PAM_AUTHTOK_ERR; } + +#ifdef USE_LCKPWDF + /* + * These values for the number of attempts and the sleep time + * are, of course, completely arbitrary. + * + * My reading of the PAM docs is that, once pam_chauthtok() + * has been called with PAM_UPDATE_AUTHTOK, we are obliged to + * take any reasonable steps to make sure the token is + * updated; so retrying for 1/10 sec. isn't overdoing it. + */ + + retval = lckpwdf(); + if (retval != 0) { + return PAM_AUTHTOK_LOCK_BUSY; + } +#endif /* def USE_LCKPWDF */ + if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) { retval = _update_shadow(forwho, towhat); if (retval == PAM_SUCCESS) @@ -552,6 +567,10 @@ retval = _update_passwd(pamh, forwho, towhat); } +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif /* def USE_LCKPWDF */ + return retval; } @@ -563,9 +582,7 @@ int retval = PAM_SUCCESS; /* UNIX passwords area */ - setpwent(); pwd = getpwnam(user); /* Get password file entry... */ - endpwent(); if (pwd == NULL) return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */ @@ -679,7 +696,7 @@ int argc, const char **argv) { unsigned int ctrl, lctrl; - int retval, i; + int retval; int remember = -1; /* */ @@ -689,33 +706,12 @@ D(("called.")); -#ifdef USE_LCKPWDF - /* our current locking system requires that we lock the - entire password database. This avoids both livelock - and deadlock. */ - /* These values for the number of attempts and the sleep time - are, of course, completely arbitrary. - My reading of the PAM docs is that, once pam_chauthtok() has been - called with PAM_UPDATE_AUTHTOK, we are obliged to take any - reasonable steps to make sure the token is updated; so retrying - for 1/10 sec. isn't overdoing it. - The other possibility is to call lckpwdf() on the first - pam_chauthtok() pass, and hold the lock until released in the - second pass--but is this guaranteed to work? -SRL */ - i=0; - while((retval = lckpwdf()) != 0 && i < 100) { - usleep(1000); - } - if(retval != 0) { - return PAM_AUTHTOK_LOCK_BUSY; - } -#endif ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); /* * First get the name of a user */ - retval = pam_get_user(pamh, &user, "Username: "); + retval = pam_get_user(pamh, &user, NULL); if (retval == PAM_SUCCESS) { /* * Various libraries at various times have had bugs related to @@ -725,9 +721,6 @@ */ if (user == NULL || !isalnum(*user)) { _log_err(LOG_ERR, pamh, "bad username [%s]", user); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) @@ -737,9 +730,6 @@ if (on(UNIX_DEBUG, ctrl)) _log_err(LOG_DEBUG, pamh, "password - could not identify user"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } @@ -761,9 +751,6 @@ D(("prelim check")); if (_unix_blankpasswd(ctrl, user)) { -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_SUCCESS; } else if (off(UNIX__IAMROOT, ctrl)) { @@ -773,9 +760,6 @@ if (Announce == NULL) { _log_err(LOG_CRIT, pamh, "password - out of memory"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_BUF_ERR; } (void) strcpy(Announce, greeting); @@ -795,9 +779,6 @@ if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh ,"password - (old) token not obtained"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } /* verify that this is the password for this user */ @@ -812,9 +793,6 @@ if (retval != PAM_SUCCESS) { D(("Authentication failed")); pass_old = NULL; -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); @@ -867,17 +845,11 @@ if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } retval = _unix_verify_shadow(user, ctrl); if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } D(("get new password now")); @@ -908,9 +880,6 @@ ,"password - new password not obtained"); } pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } D(("returned to _unix_chauthtok")); @@ -931,9 +900,6 @@ _log_err(LOG_NOTICE, pamh, "new password not acceptable"); pass_new = pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } /* @@ -974,9 +940,6 @@ _log_err(LOG_CRIT, pamh, "out of memory for password"); pass_new = pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_BUF_ERR; } /* copy first 8 bytes of password */ @@ -998,6 +961,7 @@ retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, remember); + _pam_delete(tpass); pass_old = pass_new = NULL; } else { /* something has broken with the module */ @@ -1008,9 +972,6 @@ D(("retval was %d", retval)); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } diff -Naur Linux-PAM-0.77.orig/modules/pam_unix/pam_unix_sess.c Linux-PAM-0.77/modules/pam_unix/pam_unix_sess.c --- Linux-PAM-0.77.orig/modules/pam_unix/pam_unix_sess.c 2000-12-20 05:15:05.000000000 +0000 +++ Linux-PAM-0.77/modules/pam_unix/pam_unix_sess.c 2004-06-09 18:28:24.064163042 +0000 @@ -53,6 +53,7 @@ #include #include +#include #ifndef LINUX_PAM #include @@ -71,6 +72,7 @@ char *user_name, *service; unsigned int ctrl; int retval; + const char *login_name; D(("called.")); @@ -89,9 +91,12 @@ "open_session - error recovering service"); return PAM_SESSION_ERR; } - _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)" - ,user_name - ,PAM_getlogin() == NULL ? "" : PAM_getlogin(), getuid()); + login_name = _pammodutil_getlogin(pamh); + if (login_name == NULL) { + login_name = ""; + } + _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)", + user_name, login_name, getuid()); return PAM_SUCCESS; } diff -Naur Linux-PAM-0.77.orig/modules/pam_unix/support.c Linux-PAM-0.77/modules/pam_unix/support.c --- Linux-PAM-0.77.orig/modules/pam_unix/support.c 2002-09-23 17:33:22.000000000 +0000 +++ Linux-PAM-0.77/modules/pam_unix/support.c 2004-06-09 18:28:24.096157389 +0000 @@ -20,6 +20,7 @@ #include #include +#include #include "md5.h" #include "support.h" @@ -107,36 +108,6 @@ return retval; } - /* - * Beacause getlogin() is braindead and sometimes it just - * doesn't work, we reimplement it here. - */ -char *PAM_getlogin(void) -{ - struct utmp *ut, line; - char *curr_tty, *retval; - static char curr_user[sizeof(ut->ut_user) + 4]; - - retval = NULL; - - curr_tty = ttyname(0); - if (curr_tty != NULL) { - D(("PAM_getlogin ttyname: %s", curr_tty)); - curr_tty += 5; - setutent(); - strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); - if ((ut = getutline(&line)) != NULL) { - strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); - curr_user[sizeof(curr_user) - 1] = '\0'; - retval = curr_user; - } - endutent(); - } - D(("PAM_getlogin retval: %s", retval)); - - return retval; -} - /* * set the control flags for the UNIX module. */ @@ -668,10 +639,17 @@ if (new != NULL) { - new->user = x_strdup(name ? name : ""); + const char *login_name; + + login_name = _pammodutil_getlogin(pamh); + if (login_name == NULL) { + login_name = ""; + } + + new->user = x_strdup(name ? name : ""); new->uid = getuid(); new->euid = geteuid(); - new->name = x_strdup(PAM_getlogin()? PAM_getlogin() : ""); + new->name = x_strdup(login_name); /* any previous failures for this user ? */ pam_get_data(pamh, data_name, (const void **) &old); diff -Naur Linux-PAM-0.77.orig/modules/pam_unix/support.h Linux-PAM-0.77/modules/pam_unix/support.h --- Linux-PAM-0.77.orig/modules/pam_unix/support.h 2002-07-11 05:43:51.000000000 +0000 +++ Linux-PAM-0.77/modules/pam_unix/support.h 2004-06-09 18:28:24.101156506 +0000 @@ -125,7 +125,6 @@ _pam_drop(xx); \ } -extern char *PAM_getlogin(void); extern void _log_err(int err, pam_handle_t *pamh, const char *format,...); extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl ,int type, const char *text); diff -Naur Linux-PAM-0.77.orig/modules/pam_wheel/pam_wheel.c Linux-PAM-0.77/modules/pam_wheel/pam_wheel.c --- Linux-PAM-0.77.orig/modules/pam_wheel/pam_wheel.c 2002-07-13 05:48:19.000000000 +0000 +++ Linux-PAM-0.77/modules/pam_wheel/pam_wheel.c 2004-06-09 18:28:24.105155800 +0000 @@ -43,6 +43,7 @@ #define PAM_SM_ACCOUNT #include +#include /* some syslogging */ @@ -110,7 +111,7 @@ const char *use_group) { const char *username = NULL; - char *fromsu; + const char *fromsu; struct passwd *pwd, *tpwd; struct group *grp; int retval = PAM_AUTH_ERR; @@ -142,7 +143,7 @@ } fromsu = tpwd->pw_name; } else { - fromsu = getlogin(); + fromsu = _pammodutil_getlogin(pamh); if (fromsu) { tpwd = getpwnam(fromsu); } diff -Naur Linux-PAM-0.77.orig/modules/pammodutil/Makefile Linux-PAM-0.77/modules/pammodutil/Makefile --- Linux-PAM-0.77.orig/modules/pammodutil/Makefile 2001-12-09 22:15:12.000000000 +0000 +++ Linux-PAM-0.77/modules/pammodutil/Makefile 2004-06-09 18:28:24.107155446 +0000 @@ -18,7 +18,8 @@ -DLIBPAM_VERSION_MINOR=$(MINOR_REL) # all the object files we care about -LIBOBJECTS = modutil_cleanup.o modutil_getpwnam.o modutil_getpwuid.o +LIBOBJECTS = modutil_cleanup.o modutil_getpwnam.o modutil_getpwuid.o \ + modutil_getlogin.o # static library name LIBSTATIC = $(LIBNAME).a diff -Naur Linux-PAM-0.77.orig/modules/pammodutil/include/security/_pam_modutil.h Linux-PAM-0.77/modules/pammodutil/include/security/_pam_modutil.h --- Linux-PAM-0.77.orig/modules/pammodutil/include/security/_pam_modutil.h 2001-12-09 22:15:12.000000000 +0000 +++ Linux-PAM-0.77/modules/pammodutil/include/security/_pam_modutil.h 2004-06-09 18:28:24.110154916 +0000 @@ -15,7 +15,7 @@ * On systems that simply can't support thread safe programming, these * functions don't support it either - sorry. * - * Copyright (c) 2001 Andrew Morgan + * Copyright (c) 2001-2002 Andrew Morgan */ #include @@ -30,4 +30,6 @@ extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data, int error_status); +extern const char *_pammodutil_getlogin(pam_handle_t *pamh); + #endif /* _PAM_MODUTIL_H */ diff -Naur Linux-PAM-0.77.orig/modules/pammodutil/modutil_getlogin.c Linux-PAM-0.77/modules/pammodutil/modutil_getlogin.c --- Linux-PAM-0.77.orig/modules/pammodutil/modutil_getlogin.c 1970-01-01 00:00:00.000000000 +0000 +++ Linux-PAM-0.77/modules/pammodutil/modutil_getlogin.c 2004-06-09 18:32:32.659204375 +0000 @@ -0,0 +1,71 @@ +/* + * $Id: Linux-PAM-0.77-security-4.patch,v 1.1 2004/06/11 05:39:22 jim Exp $ + * + * A central point for invoking getlogin(). Hopefully, this is a + * little harder to spoof than all the other versions that are out + * there. + */ + +#include +#include +#include + +#include "pammodutil.h" + +#define _PAMMODUTIL_GETLOGIN "_pammodutil_getlogin" + +const char *_pammodutil_getlogin(pam_handle_t *pamh) +{ + int status; + const char *logname, *curr_tty; + char *curr_user; + struct utmp *ut, line; + + status = pam_get_data(pamh, _PAMMODUTIL_GETLOGIN, + (const void **) &logname); + if (status == PAM_SUCCESS) { + return logname; + } + + status = pam_get_item(pamh, PAM_TTY, (const void **) &curr_tty); + if ((status != PAM_SUCCESS) || (curr_tty == NULL)) { + curr_tty = ttyname(0); + } + + if ((curr_tty == NULL) || memcmp(curr_tty, "/dev/", 5)) { + return NULL; + } + + curr_tty += 5; /* strlen("/dev/") */ + logname = NULL; + + setutent(); + strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); + + if ((ut = getutline(&line)) == NULL) { + goto clean_up_and_go_home; + } + + curr_user = calloc(sizeof(line.ut_user)+1, 1); + if (curr_user == NULL) { + goto clean_up_and_go_home; + } + + strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); + curr_user[sizeof(line.ut_user)] = '\0'; + + status = pam_set_data(pamh, _PAMMODUTIL_GETLOGIN, logname, + _pammodutil_cleanup); + if (status != PAM_SUCCESS) { + free(curr_user); + goto clean_up_and_go_home; + } + + logname = curr_user; + +clean_up_and_go_home: + + endutent(); + + return logname; +}