Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 153253 Details for
Bug 236316
LSPP: Unable to change expired password on ssh login
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Proposed patch
pam-0.99.6.2-unix-update-helper.patch (text/plain), 65.93 KB, created by
Tomas Mraz
on 2007-04-22 13:17:22 UTC
(
hide
)
Description:
Proposed patch
Filename:
MIME Type:
Creator:
Tomas Mraz
Created:
2007-04-22 13:17:22 UTC
Size:
65.93 KB
patch
obsolete
>--- Linux-PAM-0.99.6.2/modules/pam_unix/passupdate.c.update-helper 2007-04-22 14:57:37.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/passupdate.c 2007-04-22 13:56:10.000000000 +0200 >@@ -0,0 +1,560 @@ >+/* >+ * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. >+ * Copyright (C) 1996. >+ * Copyright (c) Jan Rêkorajski, 1999. >+ * Copyright (c) Red Hat, Inc., 2007 >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, and the entire permission notice in its entirety, >+ * including the disclaimer of warranties. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * 3. The name of the author may not be used to endorse or promote >+ * products derived from this software without specific prior >+ * written permission. >+ * >+ * ALTERNATIVELY, this product may be distributed under the terms of >+ * the GNU Public License, in which case the provisions of the GPL are >+ * required INSTEAD OF the above restrictions. (This clause is >+ * necessary due to a potential bad interaction between the GPL and >+ * the restrictions contained in a BSD-style copyright.) >+ * >+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED >+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, >+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED >+ * OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+/* this will be included from module and update helper */ >+ >+#if defined(USE_LCKPWDF) && !defined(HAVE_LCKPWDF) >+# include "./lckpwdf.-c" >+#endif >+ >+/* passwd/salt conversion macros */ >+ >+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') >+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') >+ >+#define PW_TMPFILE "/etc/npasswd" >+#define SH_TMPFILE "/etc/nshadow" >+#define OPW_TMPFILE "/etc/security/nopasswd" >+#define OLD_PASSWORDS_FILE "/etc/security/opasswd" >+ >+/* >+ * i64c - convert an integer to a radix 64 character >+ */ >+static int i64c(int i) >+{ >+ if (i < 0) >+ return ('.'); >+ else if (i > 63) >+ return ('z'); >+ if (i == 0) >+ return ('.'); >+ if (i == 1) >+ return ('/'); >+ if (i >= 2 && i <= 11) >+ return ('0' - 2 + i); >+ if (i >= 12 && i <= 37) >+ return ('A' - 12 + i); >+ if (i >= 38 && i <= 63) >+ return ('a' - 38 + i); >+ return ('\0'); >+} >+ >+static char *crypt_md5_wrapper(const char *pass_new) >+{ >+ /* >+ * Code lifted from Marek Michalkiewicz's shadow suite. (CG) >+ * removed use of static variables (AGM) >+ */ >+ >+ struct timeval tv; >+ MD5_CTX ctx; >+ unsigned char result[16]; >+ char *cp = (char *) result; >+ unsigned char tmp[16]; >+ int i; >+ char *x = NULL; >+ >+ GoodMD5Init(&ctx); >+ gettimeofday(&tv, (struct timezone *) 0); >+ GoodMD5Update(&ctx, (void *) &tv, sizeof tv); >+ i = getpid(); >+ GoodMD5Update(&ctx, (void *) &i, sizeof i); >+ i = clock(); >+ GoodMD5Update(&ctx, (void *) &i, sizeof i); >+ GoodMD5Update(&ctx, result, sizeof result); >+ GoodMD5Final(tmp, &ctx); >+ strcpy(cp, "$1$"); /* magic for the MD5 */ >+ cp += strlen(cp); >+ for (i = 0; i < 8; i++) >+ *cp++ = i64c(tmp[i] & 077); >+ *cp = '\0'; >+ >+ /* no longer need cleartext */ >+ x = Goodcrypt_md5(pass_new, (const char *) result); >+ >+ return x; >+} >+ >+#ifdef USE_LCKPWDF >+static int lock_pwdf(void) >+{ >+ int i; >+ int retval; >+ >+#ifndef HELPER_COMPILE >+ if (selinux_confined()) { >+ return PAM_SUCCESS; >+ } >+#endif >+ /* 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. */ >+ i=0; >+ while((retval = lckpwdf()) != 0 && i < 100) { >+ usleep(1000); >+ i++; >+ } >+ if(retval != 0) { >+ return PAM_AUTHTOK_LOCK_BUSY; >+ } >+ return PAM_SUCCESS; >+} >+ >+static void unlock_pwdf(void) >+{ >+#ifndef HELPER_COMPILE >+ if (selinux_confined()) { >+ return; >+ } >+#endif >+ ulckpwdf(); >+} >+#endif >+ >+static int >+save_old_password(const char *forwho, const char *oldpass, >+ int howmany) >+{ >+ static char buf[16384]; >+ static char nbuf[16384]; >+ char *s_luser, *s_uid, *s_npas, *s_pas, *pass; >+ int npas; >+ FILE *pwfile, *opwfile; >+ int err = 0; >+ int oldmask; >+ int found = 0; >+ struct passwd *pwd = NULL; >+ struct stat st; >+ >+ if (howmany < 0) { >+ return PAM_SUCCESS; >+ } >+ >+ if (oldpass == NULL) { >+ return PAM_SUCCESS; >+ } >+ >+ oldmask = umask(077); >+ >+#ifdef WITH_SELINUX >+ if (SELINUX_ENABLED) { >+ security_context_t passwd_context=NULL; >+ if (getfilecon("/etc/passwd",&passwd_context)<0) { >+ return PAM_AUTHTOK_ERR; >+ }; >+ if (getfscreatecon(&prev_context)<0) { >+ freecon(passwd_context); >+ return PAM_AUTHTOK_ERR; >+ } >+ if (setfscreatecon(passwd_context)) { >+ freecon(passwd_context); >+ freecon(prev_context); >+ return PAM_AUTHTOK_ERR; >+ } >+ freecon(passwd_context); >+ } >+#endif >+ pwfile = fopen(OPW_TMPFILE, "w"); >+ umask(oldmask); >+ if (pwfile == NULL) { >+ err = 1; >+ goto done; >+ } >+ >+ opwfile = fopen(OLD_PASSWORDS_FILE, "r"); >+ if (opwfile == NULL) { >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ if (fstat(fileno(opwfile), &st) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ if (fchmod(fileno(pwfile), st.st_mode) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ while (fgets(buf, 16380, opwfile)) { >+ if (!strncmp(buf, forwho, strlen(forwho))) { >+ char *sptr = NULL; >+ found = 1; >+ if (howmany == 0) >+ continue; >+ buf[strlen(buf) - 1] = '\0'; >+ s_luser = strtok_r(buf, ":", &sptr); >+ s_uid = strtok_r(NULL, ":", &sptr); >+ s_npas = strtok_r(NULL, ":", &sptr); >+ s_pas = strtok_r(NULL, ":", &sptr); >+ npas = strtol(s_npas, NULL, 10) + 1; >+ while (npas > howmany) { >+ s_pas = strpbrk(s_pas, ","); >+ if (s_pas != NULL) >+ s_pas++; >+ npas--; >+ } >+ pass = crypt_md5_wrapper(oldpass); >+ if (s_pas == NULL) >+ snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n", >+ s_luser, s_uid, npas, pass); >+ else >+ snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n", >+ s_luser, s_uid, npas, s_pas, pass); >+ _pam_delete(pass); >+ if (fputs(nbuf, pwfile) < 0) { >+ err = 1; >+ break; >+ } >+ } else if (fputs(buf, pwfile) < 0) { >+ err = 1; >+ break; >+ } >+ } >+ fclose(opwfile); >+ >+ if (!found) { >+ pwd = getpwnam(forwho); >+ if (pwd == NULL) { >+ err = 1; >+ } else { >+ pass = crypt_md5_wrapper(oldpass); >+ snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n", >+ forwho, (unsigned long)pwd->pw_uid, pass); >+ _pam_delete(pass); >+ if (fputs(nbuf, pwfile) < 0) { >+ err = 1; >+ } >+ } >+ } >+ >+ if (fclose(pwfile)) { >+ D(("error writing entries to old passwords file: %m")); >+ err = 1; >+ } >+ >+done: >+ if (!err) { >+ if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) >+ err = 1; >+ } >+#ifdef WITH_SELINUX >+ if (SELINUX_ENABLED) { >+ if (setfscreatecon(prev_context)) { >+ err = 1; >+ } >+ if (prev_context) >+ freecon(prev_context); >+ prev_context=NULL; >+ } >+#endif >+ if (!err) { >+ return PAM_SUCCESS; >+ } else { >+ unlink(OPW_TMPFILE); >+ return PAM_AUTHTOK_ERR; >+ } >+} >+ >+#ifdef HELPER_COMPILE >+static int >+_update_passwd(const char *forwho, const char *towhat) >+#else >+static int >+_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat) >+#endif >+{ >+ struct passwd *tmpent = NULL; >+ struct stat st; >+ FILE *pwfile, *opwfile; >+ int err = 1; >+ int oldmask; >+ >+ oldmask = umask(077); >+#ifdef WITH_SELINUX >+ if (SELINUX_ENABLED) { >+ security_context_t passwd_context=NULL; >+ if (getfilecon("/etc/passwd",&passwd_context)<0) { >+ return PAM_AUTHTOK_ERR; >+ }; >+ if (getfscreatecon(&prev_context)<0) { >+ freecon(passwd_context); >+ return PAM_AUTHTOK_ERR; >+ } >+ if (setfscreatecon(passwd_context)) { >+ freecon(passwd_context); >+ freecon(prev_context); >+ return PAM_AUTHTOK_ERR; >+ } >+ freecon(passwd_context); >+ } >+#endif >+ pwfile = fopen(PW_TMPFILE, "w"); >+ umask(oldmask); >+ if (pwfile == NULL) { >+ err = 1; >+ goto done; >+ } >+ >+ opwfile = fopen("/etc/passwd", "r"); >+ if (opwfile == NULL) { >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ if (fstat(fileno(opwfile), &st) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ if (fchmod(fileno(pwfile), st.st_mode) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ tmpent = fgetpwent(opwfile); >+ while (tmpent) { >+ if (!strcmp(tmpent->pw_name, forwho)) { >+ /* To shut gcc up */ >+ union { >+ const char *const_charp; >+ char *charp; >+ } assigned_passwd; >+ assigned_passwd.const_charp = towhat; >+ >+ tmpent->pw_passwd = assigned_passwd.charp; >+ err = 0; >+ } >+ if (putpwent(tmpent, pwfile)) { >+ D(("error writing entry to password file: %m")); >+ err = 1; >+ break; >+ } >+ tmpent = fgetpwent(opwfile); >+ } >+ fclose(opwfile); >+ >+ if (fclose(pwfile)) { >+ D(("error writing entries to password file: %m")); >+ err = 1; >+ } >+ >+done: >+ if (!err) { >+ if (!rename(PW_TMPFILE, "/etc/passwd")) >+#ifdef HELPER_COMPILE >+ _log_err( >+#else >+ pam_syslog(pamh, >+#endif >+ LOG_NOTICE, "password changed for %s", forwho); >+ else >+ err = 1; >+ } >+#ifdef WITH_SELINUX >+ if (SELINUX_ENABLED) { >+ if (setfscreatecon(prev_context)) { >+ err = 1; >+ } >+ if (prev_context) >+ freecon(prev_context); >+ prev_context=NULL; >+ } >+#endif >+ if (!err) { >+ return PAM_SUCCESS; >+ } else { >+ unlink(PW_TMPFILE); >+ return PAM_AUTHTOK_ERR; >+ } >+} >+ >+#ifdef HELPER_COMPILE >+static int >+_update_shadow(const char *forwho, char *towhat) >+#else >+static int >+_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) >+#endif >+{ >+ struct spwd *spwdent = NULL, *stmpent = NULL; >+ struct stat st; >+ FILE *pwfile, *opwfile; >+ int err = 1; >+ int oldmask; >+ >+ spwdent = getspnam(forwho); >+ if (spwdent == NULL) { >+ return PAM_USER_UNKNOWN; >+ } >+ oldmask = umask(077); >+ >+#ifdef WITH_SELINUX >+ if (SELINUX_ENABLED) { >+ security_context_t shadow_context=NULL; >+ if (getfilecon("/etc/shadow",&shadow_context)<0) { >+ return PAM_AUTHTOK_ERR; >+ }; >+ if (getfscreatecon(&prev_context)<0) { >+ freecon(shadow_context); >+ return PAM_AUTHTOK_ERR; >+ } >+ if (setfscreatecon(shadow_context)) { >+ freecon(shadow_context); >+ freecon(prev_context); >+ return PAM_AUTHTOK_ERR; >+ } >+ freecon(shadow_context); >+ } >+#endif >+ pwfile = fopen(SH_TMPFILE, "w"); >+ umask(oldmask); >+ if (pwfile == NULL) { >+ err = 1; >+ goto done; >+ } >+ >+ opwfile = fopen("/etc/shadow", "r"); >+ if (opwfile == NULL) { >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ if (fstat(fileno(opwfile), &st) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ if (fchmod(fileno(pwfile), st.st_mode) == -1) { >+ fclose(opwfile); >+ fclose(pwfile); >+ err = 1; >+ goto done; >+ } >+ >+ stmpent = fgetspent(opwfile); >+ while (stmpent) { >+ >+ if (!strcmp(stmpent->sp_namp, forwho)) { >+ stmpent->sp_pwdp = towhat; >+ stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24); >+ err = 0; >+ D(("Set password %s for %s", stmpent->sp_pwdp, forwho)); >+ } >+ >+ if (putspent(stmpent, pwfile)) { >+ D(("error writing entry to shadow file: %m")); >+ err = 1; >+ break; >+ } >+ >+ stmpent = fgetspent(opwfile); >+ } >+ fclose(opwfile); >+ >+ if (fclose(pwfile)) { >+ D(("error writing entries to shadow file: %m")); >+ err = 1; >+ } >+ >+ done: >+ if (!err) { >+ if (!rename(SH_TMPFILE, "/etc/shadow")) >+#ifdef HELPER_COMPILE >+ _log_err( >+#else >+ pam_syslog(pamh, >+#endif >+ LOG_NOTICE, "password changed for %s", forwho); >+ else >+ err = 1; >+ } >+ >+#ifdef WITH_SELINUX >+ if (SELINUX_ENABLED) { >+ if (setfscreatecon(prev_context)) { >+ err = 1; >+ } >+ if (prev_context) >+ freecon(prev_context); >+ prev_context=NULL; >+ } >+#endif >+ >+ if (!err) { >+ return PAM_SUCCESS; >+ } else { >+ unlink(SH_TMPFILE); >+ return PAM_AUTHTOK_ERR; >+ } >+} >--- Linux-PAM-0.99.6.2/modules/pam_unix/pam_unix_acct.c.update-helper 2006-06-27 10:38:14.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/pam_unix_acct.c 2007-04-22 14:49:36.000000000 +0200 >@@ -124,11 +124,11 @@ > } > > /* exec binary helper */ >- args[0] = x_strdup(CHKPWD_HELPER); >+ args[0] = x_strdup(UPDATE_HELPER); > args[1] = x_strdup(user); > args[2] = x_strdup("verify"); > >- execve(CHKPWD_HELPER, args, envp); >+ execve(UPDATE_HELPER, args, envp); > > pam_syslog(pamh, LOG_ERR, "helper binary execve failed: %m"); > /* should not get here: exit with error */ >@@ -142,11 +142,11 @@ > int rc=0; > rc=waitpid(child, &retval, 0); /* wait for helper to complete */ > if (rc<0) { >- pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc); >+ pam_syslog(pamh, LOG_ERR, "unix_update waitpid failed: %m"); > retval = PAM_AUTH_ERR; > } else { > retval = WEXITSTATUS(retval); >- if (retval != PAM_AUTHINFO_UNAVAIL) { >+ if (retval == PAM_SUCCESS) { > rc = pam_modutil_read(fds[0], buf, sizeof(buf) - 1); > if(rc > 0) { > buf[rc] = '\0'; >@@ -157,15 +157,15 @@ > &spwd.sp_warn, /* days warning for expiration */ > &spwd.sp_inact, /* days before account inactive */ > &spwd.sp_expire) /* date when account expires */ != 6 ) retval = PAM_AUTH_ERR; >- } >- else { >- pam_syslog(pamh, LOG_ERR, " ERROR %d: %m", rc); retval = PAM_AUTH_ERR; >+ } else { >+ pam_syslog(pamh, LOG_ERR, "read failed: %m"); retval = PAM_AUTH_ERR; > } >+ } else { >+ pam_syslog(pamh, LOG_ERR, "unix_update returned error %d", retval); > } > } > } else { >- pam_syslog(pamh, LOG_ERR, "Fork failed: %m"); >- D(("fork failed")); >+ pam_syslog(pamh, LOG_ERR, "fork failed: %m"); > retval = PAM_AUTH_ERR; > } > close(fds[0]); >@@ -247,6 +247,8 @@ > setreuid( -1, save_euid ); > } > >+ } else if (geteuid() != 0) { /* cannot read shadow when non root */ >+ return PAM_IGNORE; > } else if (_unix_shadowed (pwent)) > spent = pam_modutil_getspnam (pamh, uname); > else >--- Linux-PAM-0.99.6.2/modules/pam_unix/pam_unix_passwd.c.update-helper 2007-04-03 17:51:29.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/pam_unix_passwd.c 2007-04-22 15:07:42.000000000 +0200 >@@ -2,6 +2,7 @@ > * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. > * Copyright (C) 1996. > * Copyright (c) Jan Rêkorajski, 1999. >+ * Copyright (c) Red Hat, Inc., 2007. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -92,15 +93,6 @@ > #endif /* GNU libc 2.1 */ > > /* >- * PAM framework looks for these entry-points to pass control to the >- * password changing module. >- */ >- >-#if defined(USE_LCKPWDF) && !defined(HAVE_LCKPWDF) >-# include "./lckpwdf.-c" >-#endif >- >-/* > How it works: > Gets in username (has to be done) from the calling program > Does authentication of user (only if we are not running as root) >@@ -108,82 +100,15 @@ > Sets it. > */ > >-/* passwd/salt conversion macros */ >- >-#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') >-#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') >- > /* data tokens */ > > #define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS" > #define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS" > > #define MAX_PASSWD_TRIES 3 >-#define PW_TMPFILE "/etc/npasswd" >-#define SH_TMPFILE "/etc/nshadow" > #ifndef CRACKLIB_DICTS > #define CRACKLIB_DICTS NULL > #endif >-#define OPW_TMPFILE "/etc/security/nopasswd" >-#define OLD_PASSWORDS_FILE "/etc/security/opasswd" >- >-/* >- * i64c - convert an integer to a radix 64 character >- */ >-static int i64c(int i) >-{ >- if (i < 0) >- return ('.'); >- else if (i > 63) >- return ('z'); >- if (i == 0) >- return ('.'); >- if (i == 1) >- return ('/'); >- if (i >= 2 && i <= 11) >- return ('0' - 2 + i); >- if (i >= 12 && i <= 37) >- return ('A' - 12 + i); >- if (i >= 38 && i <= 63) >- return ('a' - 38 + i); >- return ('\0'); >-} >- >-static char *crypt_md5_wrapper(const char *pass_new) >-{ >- /* >- * Code lifted from Marek Michalkiewicz's shadow suite. (CG) >- * removed use of static variables (AGM) >- */ >- >- struct timeval tv; >- MD5_CTX ctx; >- unsigned char result[16]; >- char *cp = (char *) result; >- unsigned char tmp[16]; >- int i; >- char *x = NULL; >- >- GoodMD5Init(&ctx); >- gettimeofday(&tv, (struct timezone *) 0); >- GoodMD5Update(&ctx, (void *) &tv, sizeof tv); >- i = getpid(); >- GoodMD5Update(&ctx, (void *) &i, sizeof i); >- i = clock(); >- GoodMD5Update(&ctx, (void *) &i, sizeof i); >- GoodMD5Update(&ctx, result, sizeof result); >- GoodMD5Final(tmp, &ctx); >- strcpy(cp, "$1$"); /* magic for the MD5 */ >- cp += strlen(cp); >- for (i = 0; i < 8; i++) >- *cp++ = i64c(tmp[i] & 077); >- *cp = '\0'; >- >- /* no longer need cleartext */ >- x = Goodcrypt_md5(pass_new, (const char *) result); >- >- return x; >-} > > static char *getNISserver(pam_handle_t *pamh) > { >@@ -217,7 +142,8 @@ > > #ifdef WITH_SELINUX > >-static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user, const char *fromwhat, const char *towhat) >+static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user, >+ const char *fromwhat, const char *towhat, int remember) > { > int retval, child, fds[2]; > void (*sighandler)(int) = NULL; >@@ -247,7 +173,8 @@ > size_t i=0; > struct rlimit rlim; > static char *envp[] = { NULL }; >- char *args[] = { NULL, NULL, NULL, NULL }; >+ char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL }; >+ char buffer[16]; > > /* XXX - should really tidy up PAM here too */ > >@@ -270,11 +197,18 @@ > } > > /* exec binary helper */ >- args[0] = x_strdup(CHKPWD_HELPER); >+ args[0] = x_strdup(UPDATE_HELPER); > args[1] = x_strdup(user); >- args[2] = x_strdup("shadow"); >+ args[2] = x_strdup("update"); >+ if (on(UNIX_SHADOW, ctrl)) >+ args[3] = x_strdup("1"); >+ else >+ args[3] = x_strdup("0"); > >- execve(CHKPWD_HELPER, args, envp); >+ snprintf(buffer, sizeof(buffer), "%d", remember); >+ args[4] = x_strdup(buffer); >+ >+ execve(UPDATE_HELPER, args, envp); > > /* should not get here: exit with error */ > D(("helper binary is not available")); >@@ -297,7 +231,7 @@ > close(fds[1]); > rc=waitpid(child, &retval, 0); /* wait for helper to complete */ > if (rc<0) { >- pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc); >+ pam_syslog(pamh, LOG_ERR, "unix_update waitpid failed: %m"); > retval = PAM_AUTH_ERR; > } else { > retval = WEXITSTATUS(retval); >@@ -315,8 +249,52 @@ > > return retval; > } >+ >+static int selinux_confined(void) >+{ >+ static int confined = -1; >+ int fd; >+ char tempfile[]="/etc/.pwdXXXXXX"; >+ >+ if (confined != -1) >+ return confined; >+ >+ /* cannot be confined without SELinux enabled */ >+ if (!SELINUX_ENABLED){ >+ confined = 0; >+ return confined; >+ } >+ >+ /* let's try opening shadow read only */ >+ if ((fd=open("/etc/shadow", O_RDONLY)) != -1 || errno != EACCES) { >+ if (fd != -1) >+ close(fd); >+ confined = 0; >+ return confined; >+ } >+ >+ /* shadow opening failed because of other reasons let's try >+ creating a file in /etc */ >+ if ((fd=mkstemp(tempfile)) != -1) { >+ unlink(tempfile); >+ close(fd); >+ confined = 0; >+ return confined; >+ } >+ >+ confined = 1; >+ return confined; >+} >+ >+#else >+static int selinux_confined(void) >+{ >+ return 0; >+} > #endif > >+#include "passupdate.c" >+ > static int check_old_password(const char *forwho, const char *newpass) > { > static char buf[16384]; >@@ -353,392 +331,6 @@ > return retval; > } > >-static int save_old_password(pam_handle_t *pamh, >- const char *forwho, const char *oldpass, >- int howmany) >-{ >- static char buf[16384]; >- static char nbuf[16384]; >- char *s_luser, *s_uid, *s_npas, *s_pas, *pass; >- int npas; >- FILE *pwfile, *opwfile; >- int err = 0; >- int oldmask; >- int found = 0; >- struct passwd *pwd = NULL; >- struct stat st; >- >- if (howmany < 0) { >- return PAM_SUCCESS; >- } >- >- if (oldpass == NULL) { >- return PAM_SUCCESS; >- } >- >- oldmask = umask(077); >- >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- security_context_t passwd_context=NULL; >- if (getfilecon("/etc/passwd",&passwd_context)<0) { >- return PAM_AUTHTOK_ERR; >- }; >- if (getfscreatecon(&prev_context)<0) { >- freecon(passwd_context); >- return PAM_AUTHTOK_ERR; >- } >- if (setfscreatecon(passwd_context)) { >- freecon(passwd_context); >- freecon(prev_context); >- return PAM_AUTHTOK_ERR; >- } >- freecon(passwd_context); >- } >-#endif >- pwfile = fopen(OPW_TMPFILE, "w"); >- umask(oldmask); >- if (pwfile == NULL) { >- err = 1; >- goto done; >- } >- >- opwfile = fopen(OLD_PASSWORDS_FILE, "r"); >- if (opwfile == NULL) { >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fstat(fileno(opwfile), &st) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- if (fchmod(fileno(pwfile), st.st_mode) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- while (fgets(buf, 16380, opwfile)) { >- if (!strncmp(buf, forwho, strlen(forwho))) { >- buf[strlen(buf) - 1] = '\0'; >- s_luser = strtok(buf, ":"); >- s_uid = strtok(NULL, ":"); >- s_npas = strtok(NULL, ":"); >- s_pas = strtok(NULL, ":"); >- npas = strtol(s_npas, NULL, 10) + 1; >- while (npas > howmany) { >- s_pas = strpbrk(s_pas, ","); >- if (s_pas != NULL) >- s_pas++; >- npas--; >- } >- pass = crypt_md5_wrapper(oldpass); >- if (s_pas == NULL) >- snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n", >- s_luser, s_uid, npas, pass); >- else >- snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n", >- s_luser, s_uid, npas, s_pas, pass); >- _pam_delete(pass); >- if (fputs(nbuf, pwfile) < 0) { >- err = 1; >- break; >- } >- found = 1; >- } else if (fputs(buf, pwfile) < 0) { >- err = 1; >- break; >- } >- } >- fclose(opwfile); >- >- if (!found) { >- pwd = pam_modutil_getpwnam(pamh, forwho); >- if (pwd == NULL) { >- err = 1; >- } else { >- pass = crypt_md5_wrapper(oldpass); >- snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n", >- forwho, (unsigned long)pwd->pw_uid, pass); >- _pam_delete(pass); >- if (fputs(nbuf, pwfile) < 0) { >- err = 1; >- } >- } >- } >- >- if (fclose(pwfile)) { >- D(("error writing entries to old passwords file: %m")); >- err = 1; >- } >- >-done: >- if (!err) { >- if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) >- err = 1; >- } >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- if (setfscreatecon(prev_context)) { >- err = 1; >- } >- if (prev_context) >- freecon(prev_context); >- prev_context=NULL; >- } >-#endif >- if (!err) { >- return PAM_SUCCESS; >- } else { >- unlink(OPW_TMPFILE); >- return PAM_AUTHTOK_ERR; >- } >-} >- >-static int _update_passwd(pam_handle_t *pamh, >- const char *forwho, const char *towhat) >-{ >- struct passwd *tmpent = NULL; >- struct stat st; >- FILE *pwfile, *opwfile; >- int err = 1; >- int oldmask; >- >- oldmask = umask(077); >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- security_context_t passwd_context=NULL; >- if (getfilecon("/etc/passwd",&passwd_context)<0) { >- return PAM_AUTHTOK_ERR; >- }; >- if (getfscreatecon(&prev_context)<0) { >- freecon(passwd_context); >- return PAM_AUTHTOK_ERR; >- } >- if (setfscreatecon(passwd_context)) { >- freecon(passwd_context); >- freecon(prev_context); >- return PAM_AUTHTOK_ERR; >- } >- freecon(passwd_context); >- } >-#endif >- pwfile = fopen(PW_TMPFILE, "w"); >- umask(oldmask); >- if (pwfile == NULL) { >- err = 1; >- goto done; >- } >- >- opwfile = fopen("/etc/passwd", "r"); >- if (opwfile == NULL) { >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fstat(fileno(opwfile), &st) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- if (fchmod(fileno(pwfile), st.st_mode) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- tmpent = fgetpwent(opwfile); >- while (tmpent) { >- if (!strcmp(tmpent->pw_name, forwho)) { >- /* To shut gcc up */ >- union { >- const char *const_charp; >- char *charp; >- } assigned_passwd; >- assigned_passwd.const_charp = towhat; >- >- tmpent->pw_passwd = assigned_passwd.charp; >- err = 0; >- } >- if (putpwent(tmpent, pwfile)) { >- D(("error writing entry to password file: %m")); >- err = 1; >- break; >- } >- tmpent = fgetpwent(opwfile); >- } >- fclose(opwfile); >- >- if (fclose(pwfile)) { >- D(("error writing entries to password file: %m")); >- err = 1; >- } >- >-done: >- if (!err) { >- if (!rename(PW_TMPFILE, "/etc/passwd")) >- pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho); >- else >- err = 1; >- } >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- if (setfscreatecon(prev_context)) { >- err = 1; >- } >- if (prev_context) >- freecon(prev_context); >- prev_context=NULL; >- } >-#endif >- if (!err) { >- return PAM_SUCCESS; >- } else { >- unlink(PW_TMPFILE); >- return PAM_AUTHTOK_ERR; >- } >-} >- >-static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) >-{ >- struct spwd *spwdent = NULL, *stmpent = NULL; >- struct stat st; >- FILE *pwfile, *opwfile; >- int err = 1; >- int oldmask; >- >- spwdent = getspnam(forwho); >- if (spwdent == NULL) { >- return PAM_USER_UNKNOWN; >- } >- oldmask = umask(077); >- >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- security_context_t shadow_context=NULL; >- if (getfilecon("/etc/shadow",&shadow_context)<0) { >- return PAM_AUTHTOK_ERR; >- }; >- if (getfscreatecon(&prev_context)<0) { >- freecon(shadow_context); >- return PAM_AUTHTOK_ERR; >- } >- if (setfscreatecon(shadow_context)) { >- freecon(shadow_context); >- freecon(prev_context); >- return PAM_AUTHTOK_ERR; >- } >- freecon(shadow_context); >- } >-#endif >- pwfile = fopen(SH_TMPFILE, "w"); >- umask(oldmask); >- if (pwfile == NULL) { >- err = 1; >- goto done; >- } >- >- opwfile = fopen("/etc/shadow", "r"); >- if (opwfile == NULL) { >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fstat(fileno(opwfile), &st) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- if (fchmod(fileno(pwfile), st.st_mode) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- stmpent = fgetspent(opwfile); >- while (stmpent) { >- >- if (!strcmp(stmpent->sp_namp, forwho)) { >- stmpent->sp_pwdp = towhat; >- stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24); >- err = 0; >- D(("Set password %s for %s", stmpent->sp_pwdp, forwho)); >- } >- >- if (putspent(stmpent, pwfile)) { >- D(("error writing entry to shadow file: %m")); >- err = 1; >- break; >- } >- >- stmpent = fgetspent(opwfile); >- } >- fclose(opwfile); >- >- if (fclose(pwfile)) { >- D(("error writing entries to shadow file: %m")); >- err = 1; >- } >- >- done: >- if (!err) { >- if (!rename(SH_TMPFILE, "/etc/shadow")) >- pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho); >- else >- err = 1; >- } >- >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- if (setfscreatecon(prev_context)) { >- err = 1; >- } >- if (prev_context) >- freecon(prev_context); >- prev_context=NULL; >- } >-#endif >- >- if (!err) { >- return PAM_SUCCESS; >- } else { >- unlink(SH_TMPFILE); >- return PAM_AUTHTOK_ERR; >- } >-} >- > static int _do_setpass(pam_handle_t* pamh, const char *forwho, > const char *fromwhat, > char *towhat, unsigned int ctrl, int remember) >@@ -767,7 +359,7 @@ > > /* Unlock passwd file to avoid deadlock */ > #ifdef USE_LCKPWDF >- ulckpwdf(); >+ unlock_pwdf(); > #endif > unlocked = 1; > >@@ -830,33 +422,22 @@ > if (_unix_comesfromsource(pamh, forwho, 1, 0)) { > #ifdef USE_LCKPWDF > if(unlocked) { >- int i = 0; >- /* 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. */ >- while((retval = lckpwdf()) != 0 && i < 100) { >- usleep(1000); >- i++; >- } >- if(retval != 0) { >+ if (lock_pwdf() != PAM_SUCCESS) { > return PAM_AUTHTOK_LOCK_BUSY; > } > } > #endif >+#ifdef WITH_SELINUX >+ if (selinux_confined()) >+ return _unix_run_update_binary(pamh, ctrl, forwho, fromwhat, towhat, remember); >+#endif > /* first, save old password */ >- if (save_old_password(pamh, forwho, fromwhat, remember)) { >+ if (save_old_password(forwho, fromwhat, remember)) { > retval = PAM_AUTHTOK_ERR; > goto done; > } > if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { > retval = _update_shadow(pamh, forwho, towhat); >-#ifdef WITH_SELINUX >- if (retval != PAM_SUCCESS && SELINUX_ENABLED) >- retval = _unix_run_shadow_binary(pamh, ctrl, forwho, fromwhat, towhat); >-#endif > if (retval == PAM_SUCCESS) > if (!_unix_shadowed(pwd)) > retval = _update_passwd(pamh, forwho, "x"); >@@ -868,7 +449,7 @@ > > done: > #ifdef USE_LCKPWDF >- ulckpwdf(); >+ unlock_pwdf(); > #endif > > return retval; >@@ -889,13 +470,17 @@ > if (_unix_shadowed(pwd)) { > /* ...and shadow password file entry for this user, if shadowing > is enabled */ >- setspent(); >- spwdent = getspnam(user); >- endspent(); >- > #ifdef WITH_SELINUX >- if (spwdent == NULL && SELINUX_ENABLED ) >- spwdent = _unix_run_verify_binary(pamh, ctrl, user); >+ if (selinux_confined()) >+ spwdent = _unix_run_verify_binary(pamh, ctrl, user); >+ else >+ { >+#endif >+ setspent(); >+ spwdent = getspnam(user); >+ endspent(); >+#ifdef WITH_SELINUX >+ } > #endif > if (spwdent == NULL) > return PAM_AUTHINFO_UNAVAIL; >@@ -1018,7 +603,7 @@ > int argc, const char **argv) > { > unsigned int ctrl, lctrl; >- int retval, i; >+ int retval; > int remember = -1; > > /* <DO NOT free() THESE> */ >@@ -1252,49 +837,40 @@ > return retval; > } > #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. */ >- i=0; >- while((retval = lckpwdf()) != 0 && i < 100) { >- usleep(1000); >- i++; >- } >- if(retval != 0) { >+ if (lock_pwdf() != PAM_SUCCESS) { > return PAM_AUTHTOK_LOCK_BUSY; > } > #endif > >- if (pass_old) { >+ if (!selinux_confined() && pass_old) { > retval = _unix_verify_password(pamh, user, pass_old, ctrl); > if (retval != PAM_SUCCESS) { > pam_syslog(pamh, LOG_NOTICE, "user password changed by another process"); > #ifdef USE_LCKPWDF >- ulckpwdf(); >+ unlock_pwdf(); > #endif > return retval; > } > } > >- retval = _unix_verify_shadow(pamh, user, ctrl); >- if (retval != PAM_SUCCESS) { >+ >+ if (!selinux_confined() && >+ (retval=_unix_verify_shadow(pamh, user, ctrl)) != PAM_SUCCESS) { > pam_syslog(pamh, LOG_NOTICE, "user not authenticated 2"); > #ifdef USE_LCKPWDF >- ulckpwdf(); >+ unlock_pwdf(); > #endif > return retval; > } > >- retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); >- if (retval != PAM_SUCCESS) { >+ >+ if (!selinux_confined() && >+ (retval=_pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new)) != PAM_SUCCESS) { > pam_syslog(pamh, LOG_NOTICE, > "new password not acceptable 2"); > pass_new = pass_old = NULL; /* tidy up */ > #ifdef USE_LCKPWDF >- ulckpwdf(); >+ unlock_pwdf(); > #endif > return retval; > } >@@ -1338,7 +914,7 @@ > "out of memory for password"); > pass_new = pass_old = NULL; /* tidy up */ > #ifdef USE_LCKPWDF >- ulckpwdf(); >+ unlock_pwdf(); > #endif > return PAM_BUF_ERR; > } >@@ -1361,7 +937,7 @@ > > retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, > remember); >- /* _do_setpass has called ulckpwdf for us */ >+ /* _do_setpass has called unlock_pwdf for us */ > > _pam_delete(tpass); > pass_old = pass_new = NULL; >--- Linux-PAM-0.99.6.2/modules/pam_unix/passverify.h.update-helper 2007-04-22 14:57:37.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/passverify.h 2007-04-22 13:22:45.000000000 +0200 >@@ -0,0 +1,60 @@ >+/* >+ * This program is designed to run setuid(root) or with sufficient >+ * privilege to read all of the unix password databases. It is designed >+ * to provide a mechanism for the current user (defined by this >+ * process' uid) to verify their own password. >+ * >+ * The password is read from the standard input. The exit status of >+ * this program indicates whether the user is authenticated or not. >+ * >+ * Copyright information is located at the end of the file. >+ * >+ */ >+ >+#define MAXPASS 200 /* the maximum length of a password */ >+ >+void _log_err(int err, const char *format,...); >+ >+void setup_signals(void); >+ >+int read_passwords(int fd, int npass, char **passwords); >+ >+int _unix_verify_password(const char *name, const char *p, int nullok); >+ >+char *getuidname(uid_t uid); >+ >+/* >+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved >+ * Copyright (c) Red Hat, Inc. 2007. All rights reserved >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, and the entire permission notice in its entirety, >+ * including the disclaimer of warranties. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * 3. The name of the author may not be used to endorse or promote >+ * products derived from this software without specific prior >+ * written permission. >+ * >+ * ALTERNATIVELY, this product may be distributed under the terms of >+ * the GNU Public License, in which case the provisions of the GPL are >+ * required INSTEAD OF the above restrictions. (This clause is >+ * necessary due to a potential bad interaction between the GPL and >+ * the restrictions contained in a BSD-style copyright.) >+ * >+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED >+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, >+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED >+ * OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >--- Linux-PAM-0.99.6.2/modules/pam_unix/unix_chkpwd.c.update-helper 2007-04-03 17:51:28.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/unix_chkpwd.c 2007-04-22 15:00:28.000000000 +0200 >@@ -40,395 +40,8 @@ > #include <security/_pam_macros.h> > > #include "md5.h" >- >-extern char *crypt(const char *key, const char *salt); >-extern char *bigcrypt(const char *key, const char *salt); >- >-/* syslogging function for errors and other information */ >- >-static void _log_err(int err, const char *format,...) >-{ >- va_list args; >- >- va_start(args, format); >- openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTHPRIV); >- vsyslog(err, format, args); >- va_end(args); >- closelog(); >-} >- >-static int _unix_shadowed(const struct passwd *pwd) >-{ >- char hashpass[1024]; >- if (pwd != NULL) { >- if (strcmp(pwd->pw_passwd, "x") == 0) { >- return 1; >- } >- if (strlen(pwd->pw_name) < sizeof(hashpass) - 2) { >- strcpy(hashpass, "##"); >- strcpy(hashpass + 2, pwd->pw_name); >- if (strcmp(pwd->pw_passwd, hashpass) == 0) { >- return 1; >- } >- } >- } >- return 0; >-} >- >-static void su_sighandler(int sig) >-{ >-#ifndef SA_RESETHAND >- /* emulate the behaviour of the SA_RESETHAND flag */ >- if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) >- signal(sig, SIG_DFL); >-#endif >- if (sig > 0) { >- _log_err(LOG_NOTICE, "caught signal %d.", sig); >- exit(sig); >- } >-} >- >-static void setup_signals(void) >-{ >- struct sigaction action; /* posix signal structure */ >- >- /* >- * Setup signal handlers >- */ >- (void) memset((void *) &action, 0, sizeof(action)); >- action.sa_handler = su_sighandler; >-#ifdef SA_RESETHAND >- action.sa_flags = SA_RESETHAND; >-#endif >- (void) sigaction(SIGILL, &action, NULL); >- (void) sigaction(SIGTRAP, &action, NULL); >- (void) sigaction(SIGBUS, &action, NULL); >- (void) sigaction(SIGSEGV, &action, NULL); >- action.sa_handler = SIG_IGN; >- action.sa_flags = 0; >- (void) sigaction(SIGTERM, &action, NULL); >- (void) sigaction(SIGHUP, &action, NULL); >- (void) sigaction(SIGINT, &action, NULL); >- (void) sigaction(SIGQUIT, &action, NULL); >-} >- >-static int _verify_account(const char * const uname) >-{ >- struct spwd *spent; >- struct passwd *pwent; >- >- pwent = getpwnam(uname); >- if (!pwent) { >- _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname); >- return PAM_USER_UNKNOWN; >- } >- >- spent = getspnam( uname ); >- if (!spent) { >- _log_err(LOG_ALERT, "could not get username from shadow (%s))", uname); >- return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ >- } >- printf("%ld:%ld:%ld:%ld:%ld:%ld", >- spent->sp_lstchg, /* last password change */ >- spent->sp_min, /* days until change allowed. */ >- spent->sp_max, /* days before change required */ >- spent->sp_warn, /* days warning for expiration */ >- spent->sp_inact, /* days before account inactive */ >- spent->sp_expire); /* date when account expires */ >- >- return PAM_SUCCESS; >-} >- >-static void strip_hpux_aging(char *p) >-{ >- const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" >- "abcdefghijklmnopqrstuvwxyz" >- "0123456789./"; >- if ((*p != '$') && (strlen(p) > 13)) { >- for (p += 13; *p != '\0'; p++) { >- if (strchr(valid, *p) == NULL) { >- *p = '\0'; >- break; >- } >- } >- } >-} >- >-static int _unix_verify_password(const char *name, const char *p, int nullok) >-{ >- struct passwd *pwd = NULL; >- struct spwd *spwdent = NULL; >- char *salt = NULL; >- char *pp = NULL; >- int retval = PAM_AUTH_ERR; >- int salt_len; >- >- /* UNIX passwords area */ >- setpwent(); >- pwd = getpwnam(name); /* Get password file entry... */ >- endpwent(); >- if (pwd != NULL) { >- if (_unix_shadowed(pwd)) { >- /* >- * ...and shadow password file entry for this user, >- * if shadowing is enabled >- */ >- setspent(); >- spwdent = getspnam(name); >- endspent(); >- if (spwdent != NULL) >- salt = x_strdup(spwdent->sp_pwdp); >- else >- pwd = NULL; >- } else { >- if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */ >- uid_t save_uid; >- >- save_uid = geteuid(); >- seteuid(pwd->pw_uid); >- spwdent = getspnam(name); >- seteuid(save_uid); >- >- salt = x_strdup(spwdent->sp_pwdp); >- } else { >- salt = x_strdup(pwd->pw_passwd); >- } >- } >- } >- if (pwd == NULL || salt == NULL) { >- _log_err(LOG_ALERT, "check pass; user unknown"); >- p = NULL; >- return PAM_USER_UNKNOWN; >- } >- >- strip_hpux_aging(salt); >- salt_len = strlen(salt); >- if (salt_len == 0) { >- return (nullok == 0) ? PAM_AUTH_ERR : PAM_SUCCESS; >- } >- if (p == NULL || strlen(p) == 0) { >- return PAM_AUTHTOK_ERR; >- } >- >- /* the moment of truth -- do we agree with the password? */ >- retval = PAM_AUTH_ERR; >- if (!strncmp(salt, "$1$", 3)) { >- pp = Goodcrypt_md5(p, salt); >- if (strcmp(pp, salt) == 0) { >- retval = PAM_SUCCESS; >- } else { >- pp = Brokencrypt_md5(p, salt); >- if (strcmp(pp, salt) == 0) >- retval = PAM_SUCCESS; >- } >- } else if ((*salt == '*') || (salt_len < 13)) { >- retval = PAM_AUTH_ERR; >- } else { >- pp = bigcrypt(p, salt); >- /* >- * Note, we are comparing the bigcrypt of the password with >- * the contents of the password field. If the latter was >- * encrypted with regular crypt (and not bigcrypt) it will >- * have been truncated for storage relative to the output >- * of bigcrypt here. As such we need to compare only the >- * stored string with the subset of bigcrypt's result. >- * Bug 521314: the strncmp comparison is for legacy support. >- */ >- if (strncmp(pp, salt, salt_len) == 0) { >- retval = PAM_SUCCESS; >- } >- } >- p = NULL; /* no longer needed here */ >- >- /* clean up */ >- { >- char *tp = pp; >- if (pp != NULL) { >- while (tp && *tp) >- *tp++ = '\0'; >- free(pp); >- } >- pp = tp = NULL; >- } >- >- return retval; >-} >- >-static char *getuidname(uid_t uid) >-{ >- struct passwd *pw; >- static char username[32]; >- >- pw = getpwuid(uid); >- if (pw == NULL) >- return NULL; >- >- strncpy(username, pw->pw_name, sizeof(username)); >- username[sizeof(username) - 1] = '\0'; >- >- return username; >-} >- >-#define SH_TMPFILE "/etc/nshadow" >-static int _update_shadow(const char *forwho) >-{ >- struct spwd *spwdent = NULL, *stmpent = NULL; >- FILE *pwfile, *opwfile; >- int err = 1; >- int oldmask; >- struct stat st; >- char pass[MAXPASS + 1]; >- char towhat[MAXPASS + 1]; >- int npass=0; >- >- /* read the password from stdin (a pipe from the pam_unix module) */ >- >- npass = read(STDIN_FILENO, pass, MAXPASS); >- >- if (npass < 0) { /* is it a valid password? */ >- >- _log_err(LOG_DEBUG, "no password supplied"); >- return PAM_AUTHTOK_ERR; >- >- } else if (npass >= MAXPASS) { >- >- _log_err(LOG_DEBUG, "password too long"); >- return PAM_AUTHTOK_ERR; >- >- } else { >- /* does pass agree with the official one? */ >- int retval=0; >- pass[npass] = '\0'; /* NUL terminate */ >- retval = _unix_verify_password(forwho, pass, 0); >- if (retval != PAM_SUCCESS) { >- return retval; >- } >- } >- >- /* read the password from stdin (a pipe from the pam_unix module) */ >- >- npass = read(STDIN_FILENO, towhat, MAXPASS); >- >- if (npass < 0) { /* is it a valid password? */ >- >- _log_err(LOG_DEBUG, "no new password supplied"); >- return PAM_AUTHTOK_ERR; >- >- } else if (npass >= MAXPASS) { >- >- _log_err(LOG_DEBUG, "new password too long"); >- return PAM_AUTHTOK_ERR; >- >- } >- >- towhat[npass] = '\0'; /* NUL terminate */ >- spwdent = getspnam(forwho); >- if (spwdent == NULL) { >- return PAM_USER_UNKNOWN; >- } >- oldmask = umask(077); >- >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- security_context_t shadow_context=NULL; >- if (getfilecon("/etc/shadow",&shadow_context)<0) { >- return PAM_AUTHTOK_ERR; >- }; >- if (getfscreatecon(&prev_context)<0) { >- freecon(shadow_context); >- return PAM_AUTHTOK_ERR; >- } >- if (setfscreatecon(shadow_context)) { >- freecon(shadow_context); >- freecon(prev_context); >- return PAM_AUTHTOK_ERR; >- } >- freecon(shadow_context); >- } >-#endif >- pwfile = fopen(SH_TMPFILE, "w"); >- umask(oldmask); >- if (pwfile == NULL) { >- err = 1; >- goto done; >- } >- >- opwfile = fopen("/etc/shadow", "r"); >- if (opwfile == NULL) { >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fstat(fileno(opwfile), &st) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- if (fchmod(fileno(pwfile), st.st_mode) == -1) { >- fclose(opwfile); >- fclose(pwfile); >- err = 1; >- goto done; >- } >- >- stmpent = fgetspent(opwfile); >- while (stmpent) { >- >- if (!strcmp(stmpent->sp_namp, forwho)) { >- stmpent->sp_pwdp = towhat; >- stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24); >- err = 0; >- D(("Set password %s for %s", stmpent->sp_pwdp, forwho)); >- } >- >- if (putspent(stmpent, pwfile)) { >- D(("error writing entry to shadow file: %m")); >- err = 1; >- break; >- } >- >- stmpent = fgetspent(opwfile); >- } >- fclose(opwfile); >- >- if (fclose(pwfile)) { >- D(("error writing entries to shadow file: %m")); >- err = 1; >- } >- >- done: >- if (!err) { >- if (rename(SH_TMPFILE, "/etc/shadow")) >- err = 1; >- } >- >-#ifdef WITH_SELINUX >- if (SELINUX_ENABLED) { >- if (setfscreatecon(prev_context)) { >- err = 1; >- } >- if (prev_context) >- freecon(prev_context); >- prev_context=NULL; >- } >-#endif >- >- if (!err) { >- return PAM_SUCCESS; >- } else { >- unlink(SH_TMPFILE); >- return PAM_AUTHTOK_ERR; >- } >-} >+#include "bigcrypt.h" >+#include "passverify.h" > > int main(int argc, char *argv[]) > { >@@ -438,6 +51,7 @@ > int force_failure = 0; > int retval = PAM_AUTH_ERR; > char *user; >+ char *passwords[] = { pass }; > > /* > * Catch or ignore as many signal as possible. >@@ -484,49 +98,24 @@ > > option=argv[2]; > >- if (strncmp(argv[2], "verify", 8) == 0) { >- /* Get the account information from the shadow file */ >- return _verify_account(argv[1]); >- } >- >- if (strncmp(option, "shadow", 8) == 0) { >- /* Attempting to change the password */ >- return _update_shadow(argv[1]); >- } >- > /* read the nullok/nonull option */ > if (strncmp(option, "nullok", 8) == 0) > nullok = 1; >- else >+ else if (strncmp(option, "nonull", 8) == 0) > nullok = 0; >+ else >+ return PAM_SYSTEM_ERR; > > /* read the password from stdin (a pipe from the pam_unix module) */ > >- npass = read(STDIN_FILENO, pass, MAXPASS); >- >- if (npass < 0) { /* is it a valid password? */ >+ npass = read_passwords(STDIN_FILENO, 1, passwords); > >- _log_err(LOG_DEBUG, "no password supplied"); >- >- } else if (npass >= MAXPASS) { >- >- _log_err(LOG_DEBUG, "password too long"); >- >- } else { >- if (npass == 0) { >- /* the password is NULL */ >- >- retval = _unix_verify_password(user, NULL, nullok); >- >- } else { >- /* does pass agree with the official one? */ >- >- pass[npass] = '\0'; /* NUL terminate */ >- retval = _unix_verify_password(user, pass, nullok); >- >- } >+ if (npass != 1) { /* is it a valid password? */ >+ _log_err(LOG_DEBUG, "no valid password supplied"); > } > >+ retval = _unix_verify_password(user, pass, nullok); >+ > memset(pass, '\0', MAXPASS); /* clear memory of the password */ > > /* return pass or fail */ >@@ -541,6 +130,7 @@ > > /* > * Copyright (c) Andrew G. Morgan, 1996. All rights reserved >+ * Copyright (c) Red Hat, Inc., 2007. All rights reserved > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >--- Linux-PAM-0.99.6.2/modules/pam_unix/unix_update.c.update-helper 2007-04-22 14:58:46.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/unix_update.c 2007-04-22 13:56:32.000000000 +0200 >@@ -0,0 +1,262 @@ >+/* >+ * This program is designed to run setuid(root) or with sufficient >+ * privilege to read all of the unix password databases. It is designed >+ * to provide a mechanism for the current user (defined by this >+ * process' uid) to verify their own password. >+ * >+ * The password is read from the standard input. The exit status of >+ * this program indicates whether the user is authenticated or not. >+ * >+ * Copyright information is located at the end of the file. >+ * >+ */ >+ >+#include "config.h" >+ >+#include <stdarg.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <string.h> >+#include <syslog.h> >+#include <unistd.h> >+#include <sys/types.h> >+#include <sys/stat.h> >+#include <pwd.h> >+#include <shadow.h> >+#include <signal.h> >+#include <time.h> >+#include <sys/time.h> >+#ifdef WITH_SELINUX >+#include <selinux/selinux.h> >+#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0)) >+static security_context_t prev_context=NULL; >+static int selinux_enabled=-1; >+#else >+#define SELINUX_ENABLED 0 >+#endif >+ >+#define MAXPASS 200 /* the maximum length of a password */ >+ >+#include <security/_pam_types.h> >+#include <security/_pam_macros.h> >+ >+#include "md5.h" >+#include "bigcrypt.h" >+#include "passverify.h" >+ >+#define _pam_delete(xx) \ >+{ \ >+ _pam_overwrite(xx); \ >+ _pam_drop(xx); \ >+} >+ >+static int >+_unix_shadowed(const struct passwd *pwd) >+{ >+ if (pwd != NULL) { >+ if (strcmp(pwd->pw_passwd, "x") == 0) { >+ return 1; >+ } >+ if ((pwd->pw_passwd[0] == '#') && >+ (pwd->pw_passwd[1] == '#') && >+ (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) { >+ return 1; >+ } >+ } >+ return 0; >+} >+ >+#define HELPER_COMPILE >+#include "passupdate.c" >+ >+static int >+verify_account(const char * const uname) >+{ >+ struct spwd *spent; >+ struct passwd *pwent; >+ >+ pwent = getpwnam(uname); >+ if (!pwent) { >+ _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname); >+ return PAM_USER_UNKNOWN; >+ } >+ >+ spent = getspnam( uname ); >+ if (!spent) { >+ _log_err(LOG_ALERT, "could not get username from shadow (%s))", uname); >+ return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ >+ } >+ printf("%ld:%ld:%ld:%ld:%ld:%ld", >+ spent->sp_lstchg, /* last password change */ >+ spent->sp_min, /* days until change allowed. */ >+ spent->sp_max, /* days before change required */ >+ spent->sp_warn, /* days warning for expiration */ >+ spent->sp_inact, /* days before account inactive */ >+ spent->sp_expire); /* date when account expires */ >+ >+ return PAM_SUCCESS; >+} >+ >+static int >+set_password(const char *forwho, const char *shadow, const char *remember) >+{ >+ struct passwd *pwd = NULL; >+ int retval; >+ char pass[MAXPASS + 1]; >+ char towhat[MAXPASS + 1]; >+ int npass = 0; >+ /* we don't care about number format errors because the helper >+ should be called internally only */ >+ int doshadow = atoi(shadow); >+ int nremember = atoi(remember); >+ char *passwords[] = { pass, towhat }; >+ >+ /* read the password from stdin (a pipe from the pam_unix module) */ >+ >+ npass = read_passwords(STDIN_FILENO, 2, passwords); >+ >+ if (npass != 2) { /* is it a valid password? */ >+ if (npass == 1) { >+ _log_err(LOG_DEBUG, "no new password supplied"); >+ memset(pass, '\0', MAXPASS); >+ } else { >+ _log_err(LOG_DEBUG, "no valid passwords supplied"); >+ } >+ return PAM_AUTHTOK_ERR; >+ } >+ >+#ifdef USE_LCKPWDF >+ if (lock_pwdf() != PAM_SUCCESS) >+ return PAM_AUTHTOK_LOCK_BUSY; >+#endif >+ >+ pwd = getpwnam(forwho); >+ >+ if (pwd == NULL) { >+ retval = PAM_USER_UNKNOWN; >+ goto done; >+ } >+ >+ /* does pass agree with the official one? >+ we always allow change from null pass */ >+ retval = _unix_verify_password(forwho, pass, 1); >+ if (retval != PAM_SUCCESS) { >+ goto done; >+ } >+ >+ /* first, save old password */ >+ if (save_old_password(forwho, pass, nremember)) { >+ retval = PAM_AUTHTOK_ERR; >+ goto done; >+ } >+ >+ if (doshadow || _unix_shadowed(pwd)) { >+ retval = _update_shadow(forwho, towhat); >+ if (retval == PAM_SUCCESS) >+ if (!_unix_shadowed(pwd)) >+ retval = _update_passwd(forwho, "x"); >+ } else { >+ retval = _update_passwd(forwho, towhat); >+ } >+ >+done: >+ memset(pass, '\0', MAXPASS); >+ memset(towhat, '\0', MAXPASS); >+ >+#ifdef USE_LCKPWDF >+ unlock_pwdf(); >+#endif >+ >+ if (retval == PAM_SUCCESS) { >+ return PAM_SUCCESS; >+ } else { >+ return PAM_AUTHTOK_ERR; >+ } >+} >+ >+int main(int argc, char *argv[]) >+{ >+ char *option; >+ >+ /* >+ * Catch or ignore as many signal as possible. >+ */ >+ setup_signals(); >+ >+ /* >+ * we establish that this program is running with non-tty stdin. >+ * this is to discourage casual use. It does *NOT* prevent an >+ * intruder from repeatadly running this program to determine the >+ * password of the current user (brute force attack, but one for >+ * which the attacker must already have gained access to the user's >+ * account). >+ */ >+ >+ if (isatty(STDIN_FILENO) || argc < 3 ) { >+ _log_err(LOG_NOTICE >+ ,"inappropriate use of Unix helper binary [UID=%d]" >+ ,getuid()); >+ fprintf(stderr >+ ,"This binary is not designed for running in this way\n" >+ "-- the system administrator has been informed\n"); >+ sleep(10); /* this should discourage/annoy the user */ >+ return PAM_SYSTEM_ERR; >+ } >+ >+ /* We must be root to read/update shadow. >+ */ >+ if (geteuid() != 0) { >+ return PAM_AUTH_ERR; >+ } >+ >+ option = argv[2]; >+ >+ if (strncmp(option, "verify", 8) == 0) { >+ /* Get the account information from the shadow file */ >+ return verify_account(argv[1]); >+ } >+ >+ if (strncmp(option, "update", 8) == 0) { >+ if (argc == 5) >+ /* Attempting to change the password */ >+ return set_password(argv[1], argv[3], argv[4]); >+ } >+ >+ return PAM_SYSTEM_ERR; >+} >+ >+/* >+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved >+ * Copyright (c) Red Hat, Inc., 2007. All rights reserved >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, and the entire permission notice in its entirety, >+ * including the disclaimer of warranties. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * 3. The name of the author may not be used to endorse or promote >+ * products derived from this software without specific prior >+ * written permission. >+ * >+ * ALTERNATIVELY, this product may be distributed under the terms of >+ * the GNU Public License, in which case the provisions of the GPL are >+ * required INSTEAD OF the above restrictions. (This clause is >+ * necessary due to a potential bad interaction between the GPL and >+ * the restrictions contained in a BSD-style copyright.) >+ * >+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED >+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, >+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED >+ * OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >--- Linux-PAM-0.99.6.2/modules/pam_unix/passverify.c.update-helper 2007-04-22 14:57:37.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/passverify.c 2007-04-22 13:25:09.000000000 +0200 >@@ -0,0 +1,308 @@ >+/* >+ * This program is designed to run setuid(root) or with sufficient >+ * privilege to read all of the unix password databases. It is designed >+ * to provide a mechanism for the current user (defined by this >+ * process' uid) to verify their own password. >+ * >+ * The password is read from the standard input. The exit status of >+ * this program indicates whether the user is authenticated or not. >+ * >+ * Copyright information is located at the end of the file. >+ * >+ */ >+ >+#include "config.h" >+ >+#include <stdarg.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <string.h> >+#include <syslog.h> >+#include <unistd.h> >+#include <sys/types.h> >+#include <sys/stat.h> >+#include <pwd.h> >+#include <shadow.h> >+#include <signal.h> >+#include <time.h> >+#include <errno.h> >+ >+#include <security/_pam_types.h> >+#include <security/_pam_macros.h> >+ >+#include "md5.h" >+#include "bigcrypt.h" >+ >+#include "passverify.h" >+ >+/* syslogging function for errors and other information */ >+ >+void >+_log_err(int err, const char *format,...) >+{ >+ va_list args; >+ >+ va_start(args, format); >+ openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTHPRIV); >+ vsyslog(err, format, args); >+ va_end(args); >+ closelog(); >+} >+ >+static int >+_unix_shadowed(const struct passwd *pwd) >+{ >+ char hashpass[1024]; >+ if (pwd != NULL) { >+ if (strcmp(pwd->pw_passwd, "x") == 0) { >+ return 1; >+ } >+ if (strlen(pwd->pw_name) < sizeof(hashpass) - 2) { >+ strcpy(hashpass, "##"); >+ strcpy(hashpass + 2, pwd->pw_name); >+ if (strcmp(pwd->pw_passwd, hashpass) == 0) { >+ return 1; >+ } >+ } >+ } >+ return 0; >+} >+ >+static void >+su_sighandler(int sig) >+{ >+#ifndef SA_RESETHAND >+ /* emulate the behaviour of the SA_RESETHAND flag */ >+ if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) >+ signal(sig, SIG_DFL); >+#endif >+ if (sig > 0) { >+ _exit(sig); >+ } >+} >+ >+void >+setup_signals(void) >+{ >+ struct sigaction action; /* posix signal structure */ >+ >+ /* >+ * Setup signal handlers >+ */ >+ (void) memset((void *) &action, 0, sizeof(action)); >+ action.sa_handler = su_sighandler; >+#ifdef SA_RESETHAND >+ action.sa_flags = SA_RESETHAND; >+#endif >+ (void) sigaction(SIGILL, &action, NULL); >+ (void) sigaction(SIGTRAP, &action, NULL); >+ (void) sigaction(SIGBUS, &action, NULL); >+ (void) sigaction(SIGSEGV, &action, NULL); >+ action.sa_handler = SIG_IGN; >+ action.sa_flags = 0; >+ (void) sigaction(SIGTERM, &action, NULL); >+ (void) sigaction(SIGHUP, &action, NULL); >+ (void) sigaction(SIGINT, &action, NULL); >+ (void) sigaction(SIGQUIT, &action, NULL); >+} >+ >+int >+read_passwords(int fd, int npass, char **passwords) >+{ >+ int rbytes = 0; >+ int offset = 0; >+ int i = 0; >+ char *pptr; >+ while (npass > 0) { >+ rbytes = read(fd, passwords[i] + offset, MAXPASS-offset); >+ >+ if (rbytes < 0) { >+ if (errno == EINTR) continue; >+ break; >+ } >+ if (rbytes == 0) >+ break; >+ >+ while ((pptr=memchr(passwords[i] + offset, '\0', rbytes)) >+ != NULL) { >+ rbytes -= pptr - (passwords[i] + offset) + 1; >+ i++; >+ offset = 0; >+ npass--; >+ if (rbytes > 0) { >+ if (npass > 0) >+ memcpy(passwords[i], pptr+1, rbytes); >+ memset(pptr+1, '\0', rbytes); >+ } >+ } >+ offset += rbytes; >+ } >+ >+ /* clear up */ >+ if (offset > 0 && npass > 0) { >+ memset(passwords[i], '\0', offset); >+ } >+ >+ return i; >+} >+ >+int >+_unix_verify_password(const char *name, const char *p, int nullok) >+{ >+ struct passwd *pwd = NULL; >+ struct spwd *spwdent = NULL; >+ char *salt = NULL; >+ char *pp = NULL; >+ int retval = PAM_AUTH_ERR; >+ size_t salt_len; >+ >+ /* UNIX passwords area */ >+ setpwent(); >+ pwd = getpwnam(name); /* Get password file entry... */ >+ endpwent(); >+ if (pwd != NULL) { >+ if (_unix_shadowed(pwd)) { >+ /* >+ * ...and shadow password file entry for this user, >+ * if shadowing is enabled >+ */ >+ setspent(); >+ spwdent = getspnam(name); >+ endspent(); >+ if (spwdent != NULL) >+ salt = x_strdup(spwdent->sp_pwdp); >+ else >+ pwd = NULL; >+ } else { >+ if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */ >+ uid_t save_uid; >+ >+ save_uid = geteuid(); >+ seteuid(pwd->pw_uid); >+ spwdent = getspnam(name); >+ seteuid(save_uid); >+ >+ salt = x_strdup(spwdent->sp_pwdp); >+ } else { >+ salt = x_strdup(pwd->pw_passwd); >+ } >+ } >+ } >+ if (pwd == NULL || salt == NULL) { >+ _log_err(LOG_ALERT, "check pass; user unknown"); >+ p = NULL; >+ return PAM_USER_UNKNOWN; >+ } >+ >+ salt_len = strlen(salt); >+ if (salt_len == 0) { >+ return (nullok == 0) ? PAM_AUTH_ERR : PAM_SUCCESS; >+ } >+ if (p == NULL || strlen(p) == 0) { >+ _pam_overwrite(salt); >+ _pam_drop(salt); >+ return PAM_AUTHTOK_ERR; >+ } >+ >+ /* the moment of truth -- do we agree with the password? */ >+ retval = PAM_AUTH_ERR; >+ if (!strncmp(salt, "$1$", 3)) { >+ pp = Goodcrypt_md5(p, salt); >+ if (pp && strcmp(pp, salt) == 0) { >+ retval = PAM_SUCCESS; >+ } else { >+ _pam_overwrite(pp); >+ _pam_drop(pp); >+ pp = Brokencrypt_md5(p, salt); >+ if (pp && strcmp(pp, salt) == 0) >+ retval = PAM_SUCCESS; >+ } >+ } else if (*salt == '$') { >+ /* >+ * Ok, we don't know the crypt algorithm, but maybe >+ * libcrypt nows about it? We should try it. >+ */ >+ pp = x_strdup (crypt(p, salt)); >+ if (pp && strcmp(pp, salt) == 0) { >+ retval = PAM_SUCCESS; >+ } >+ } else if (*salt == '*' || *salt == '!' || salt_len < 13) { >+ retval = PAM_AUTH_ERR; >+ } else { >+ pp = bigcrypt(p, salt); >+ /* >+ * Note, we are comparing the bigcrypt of the password with >+ * the contents of the password field. If the latter was >+ * encrypted with regular crypt (and not bigcrypt) it will >+ * have been truncated for storage relative to the output >+ * of bigcrypt here. As such we need to compare only the >+ * stored string with the subset of bigcrypt's result. >+ * Bug 521314. >+ */ >+ if (pp && salt_len == 13 && strlen(pp) > salt_len) { >+ _pam_overwrite(pp+salt_len); >+ } >+ >+ if (pp && strcmp(pp, salt) == 0) { >+ retval = PAM_SUCCESS; >+ } >+ } >+ p = NULL; /* no longer needed here */ >+ >+ /* clean up */ >+ _pam_overwrite(pp); >+ _pam_drop(pp); >+ >+ return retval; >+} >+ >+char * >+getuidname(uid_t uid) >+{ >+ struct passwd *pw; >+ static char username[256]; >+ >+ pw = getpwuid(uid); >+ if (pw == NULL) >+ return NULL; >+ >+ strncpy(username, pw->pw_name, sizeof(username)); >+ username[sizeof(username) - 1] = '\0'; >+ >+ return username; >+} >+/* >+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved >+ * Copyright (c) Red Hat, Inc. 2007. All rights reserved >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, and the entire permission notice in its entirety, >+ * including the disclaimer of warranties. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * 3. The name of the author may not be used to endorse or promote >+ * products derived from this software without specific prior >+ * written permission. >+ * >+ * ALTERNATIVELY, this product may be distributed under the terms of >+ * the GNU Public License, in which case the provisions of the GPL are >+ * required INSTEAD OF the above restrictions. (This clause is >+ * necessary due to a potential bad interaction between the GPL and >+ * the restrictions contained in a BSD-style copyright.) >+ * >+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED >+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, >+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED >+ * OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >--- Linux-PAM-0.99.6.2/modules/pam_unix/Makefile.am.update-helper 2006-06-16 07:49:11.000000000 +0200 >+++ Linux-PAM-0.99.6.2/modules/pam_unix/Makefile.am 2007-04-22 14:48:31.000000000 +0200 >@@ -15,9 +15,8 @@ > secureconfdir = $(SCONFIGDIR) > > AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ >- -DCHKPWD_HELPER=\"$(sbindir)/unix_chkpwd\" >- >-AM_LDFLAGS = -L$(top_builddir)/libpam -lpam @LIBCRYPT@ @LIBSELINUX@ >+ -DCHKPWD_HELPER=\"$(sbindir)/unix_chkpwd\" \ >+ -DUPDATE_HELPER=\"$(sbindir)/unix_update\" > > if HAVE_LIBSELINUX > AM_CFLAGS += -D"WITH_SELINUX" >@@ -27,16 +26,17 @@ > endif > > pam_unix_la_LDFLAGS = -no-undefined -avoid-version -module \ >- @LIBCRACK@ @LIBNSL@ >+ @LIBCRACK@ @LIBNSL@ -L$(top_builddir)/libpam -lpam \ >+ @LIBCRYPT@ @LIBSELINUX@ > if HAVE_VERSIONING > pam_unix_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map > endif > > securelib_LTLIBRARIES = pam_unix.la > >-noinst_HEADERS = md5.h support.h yppasswd.h bigcrypt.h >+noinst_HEADERS = md5.h support.h yppasswd.h bigcrypt.h passverify.h > >-sbin_PROGRAMS = unix_chkpwd >+sbin_PROGRAMS = unix_chkpwd unix_update > > noinst_PROGRAMS = bigcrypt > >@@ -46,7 +46,14 @@ > > bigcrypt_SOURCES = bigcrypt.c bigcrypt_main.c > bigcrypt_CFLAGS = $(AM_CFLAGS) >+bigcrypt_LDFLAGS = @LIBCRYPT@ > >-unix_chkpwd_SOURCES = unix_chkpwd.c md5_good.c md5_broken.c bigcrypt.c >+unix_chkpwd_SOURCES = unix_chkpwd.c passverify.c md5_good.c md5_broken.c bigcrypt.c > unix_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ >-unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@ >+unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@ -L$(top_builddir)/libpam -lpam \ >+ @LIBCRYPT@ @LIBSELINUX@ >+ >+unix_update_SOURCES = unix_update.c passverify.c md5_good.c md5_broken.c bigcrypt.c >+unix_update_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ >+unix_update_LDFLAGS = @PIE_LDFLAGS@ -L$(top_builddir)/libpam -lpam \ >+ @LIBCRYPT@ @LIBSELINUX@
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 236316
:
152572
| 153253