Hello, > - The patch needs to be updated to apply against the current package in > unstable.
Done. I have attached a patch for unix_auth.c > and, importantly: > > - we need some some code review/feedback/ignoff from the Debian folks > maintaining PAM and other related components. I am *NOT* going to be > the guy who uploads a new setuid binary without adequate review. Will you contact them? > > unix2_chkpwd.c is available for example in the file > > pam-modules-10.3-47.src.rpm of OpenSuSE 10.3. Installing that file on a > > Debian system (with rpm -i) unpacks unix2_chkpwd.c > > into /usr/src/rpm/SOURCES/. > > This is interesting new information. You're saying "unix2_chkpwd.c" has > an upstream somewhere (separate from pam_unix2)? Well, not completely separate, because pam-unix2 is also part of pam-modules-10.3-47.src.rpm > > Is there somewhere where one can download the current "unix2_chkpwd" > source, on its own and not as part of the SuSE PAM source RPM? Though I searched for a while, I could not find it elsewhere. Regards Christoph
diff -Naurp libpam-unix2-2.1.orig/src/unix_auth.c libpam-unix2-2.1/src/unix_auth.c --- libpam-unix2-2.1.orig/src/unix_auth.c 2006-11-06 14:57:01.000000000 +0100 +++ libpam-unix2-2.1/src/unix_auth.c 2008-05-13 10:05:44.361127527 +0200 @@ -57,6 +57,7 @@ #define PAM_SM_AUTH #include <security/pam_modules.h> +#include <security/_pam_macros.h> #if defined (HAVE_SECURITY_PAM_EXT_H) #include <security/pam_ext.h> #endif @@ -69,6 +70,7 @@ #include "public.h" +#define CHKPWD_HELPER "/sbin/unix2_chkpwd" /* This module actually performs UNIX/shadow authentication. */ @@ -121,6 +123,76 @@ need_password (pam_handle_t *pamh, const return 0; } +static int _unix2_run_helper_binary(pam_handle_t *pamh, const char *passwd, + const char *user, const options_t *options) +{ + int retval, child, fds[2]; + sigset_t sigset; + char *service; + + pam_get_item (pamh, PAM_SERVICE, (void *) &service); + + if (options->debug) + pam_syslog (pamh, LOG_DEBUG, "_unix2_run_helper_binary called."); + /* create a pipe for the password */ + if (pipe(fds) != 0) { + if (options->debug) + pam_syslog (pamh, LOG_DEBUG, "could not make pipe"); + return PAM_AUTH_ERR; + } + + /* Block SIGCHLD */ + sigemptyset(&sigset); + sigaddset(&sigset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigset, 0); + + /* fork */ + child = fork(); + if (child == 0) { + char *args[] = { NULL, NULL, NULL, NULL }; + static char *envp[] = { NULL }; + + /* XXX - should really tidy up PAM here too */ + + /* reopen stdin as pipe */ + close(fds[1]); + dup2(fds[0], STDIN_FILENO); + + /* exec binary helper */ + args[0] = x_strdup(CHKPWD_HELPER); + args[1] = x_strdup(service); + args[2] = x_strdup(user); + + execve(CHKPWD_HELPER, args, envp); + + /* should not get here: exit with error */ + if (options->debug) + pam_syslog (pamh, LOG_DEBUG, "helper binary is not available"); + exit(PAM_AUTHINFO_UNAVAIL); + } else if (child > 0) { + if (passwd != NULL) { /* send the password to the child */ + write(fds[1], passwd, strlen(passwd)+1); + passwd = NULL; + } else { + write(fds[1], "", 1); /* blank password */ + } + close(fds[0]); /* close here to avoid possible SIGPIPE above */ + close(fds[1]); + (void) waitpid(child, &retval, 0); /* wait for helper to complete */ + retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR; + } else { + if (options->debug) + pam_syslog (pamh, LOG_DEBUG, "fork failed"); + retval = PAM_AUTH_ERR; + } + + /* Unblock SIGCHLD */ + sigprocmask(SIG_BLOCK, &sigset, 0); + + if (options->debug) + pam_syslog (pamh, LOG_DEBUG, "returning %d", retval); + return retval; +} int pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, @@ -303,7 +375,7 @@ pam_sm_authenticate (pam_handle_t *pamh, salt = strdupa (sp->sp_pwdp); else { - if (strcmp (pw->pw_passwd, "x") == 0) + if ((strcmp (pw->pw_passwd, "x") == 0) && ((geteuid() == 0))) __write_message (pamh, flags, PAM_TEXT_INFO, _("Permissions on the password database may be too restrictive.")); salt = strdupa (pw->pw_passwd); @@ -325,10 +397,21 @@ pam_sm_authenticate (pam_handle_t *pamh, if (strcmp (crypt_r (password, salt, &output), salt) != 0) { + if (geteuid()) + { + /* we are not root, perhaps this is the reason? Run helper */ + if (options.debug) + pam_syslog (pamh, LOG_DEBUG, "running helper binary"); + + retval = _unix2_run_helper_binary(pamh, password, name, &options); + return retval; + } + if (options.debug) pam_syslog (pamh, LOG_DEBUG, "wrong password, return PAM_AUTH_ERR"); return PAM_AUTH_ERR; } + if (options.debug) pam_syslog (pamh, LOG_DEBUG, "pam_sm_authenticate: PAM_SUCCESS"); return PAM_SUCCESS; @@ -424,3 +507,18 @@ pam_sm_setcred (pam_handle_t *pamh, int pam_syslog (pamh, LOG_DEBUG, "pam_sm_setcred: PAM_SUCCESS"); return PAM_SUCCESS; } + + + + + + + + + + + + + + +