This patch 'works for me' and re-uses the (i feel) applicable shadow doesn't have to be valid/existing option.

Thanks,
--
Scott Dier <[EMAIL PROTECTED]>
CS/IT Systems Staff
diff -ur pam-0.76/debian/changelog pam-0.76-new/debian/changelog
--- pam-0.76/debian/changelog   2005-08-31 16:00:35.267474000 -0500
+++ pam-0.76-new/debian/changelog       2005-08-31 15:55:45.857647000 -0500
@@ -1,3 +1,10 @@
+pam (0.76-22umn1) unstable; urgency=low
+
+  * Ported patches from newer version of Linux-PAM to support NIS
+    password changing in the pam_unix module.
+
+ -- Scott M. Dier <[EMAIL PROTECTED]>  Wed, 31 Aug 2005 15:30:08 -0500
+
 pam (0.76-22) unstable; urgency=medium
 
   * Add uploaders
diff -ur pam-0.76/Linux-PAM/modules/pam_unix/pam_unix_passwd.c 
pam-0.76-new/Linux-PAM/modules/pam_unix/pam_unix_passwd.c
--- pam-0.76/Linux-PAM/modules/pam_unix/pam_unix_passwd.c       2005-08-31 
16:00:36.677469000 -0500
+++ pam-0.76-new/Linux-PAM/modules/pam_unix/pam_unix_passwd.c   2005-08-31 
15:49:06.547875000 -0500
@@ -73,6 +73,8 @@
 #include <security/pam_appl.h>
 #endif                         /* LINUX_PAM */
 
+#include <security/_pam_modutil.h>
+
 #include "yppasswd.h"
 #include "md5.h"
 #include "support.h"
@@ -210,19 +212,161 @@
        return master;
 }
 
-static struct passwd *_unix_getpwnam(const char *name)
+static void _unix_cleanup(pam_handle_t *pamh, void *data, int error_status)
 {
-       struct passwd *ent = NULL;
-       FILE *pwfile;
+        free(data);
+}
 
-       pwfile = fopen(PW_FILE, "r");
-       if (pwfile != NULL) {
-               ent = fgetpwent(pwfile);
-               while (ent && (strcmp(ent->pw_name, name) != 0))
-                       ent = fgetpwent(pwfile);
-               fclose(pwfile);
-       }
-       return ent;
+static int _unix_getpwnam(pam_handle_t *pamh, const char *name,
+                   int files, int nis, struct passwd **ret)
+{
+        FILE *passwd;
+        char buf[16384];
+        int matched = 0, buflen;
+        char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p;
+
+        memset(buf, 0, sizeof(buf));
+
+        if (!matched && files) {
+                int userlen = strlen(name);
+                passwd = fopen("/etc/passwd", "r");
+                if (passwd != NULL) {
+                        while (fgets(buf, sizeof(buf), passwd) != NULL) {
+                                if ((buf[userlen] == ':') &&
+                                    (strncmp(name, buf, userlen) == 0)) {
+                                        p = buf + strlen(buf) - 1;
+                                        while (isspace(*p) && (p >= buf)) {
+                                                *p-- = '\0';
+                                        }
+                                        matched = 1;
+                                        break;
+                                }
+                        }
+                        fclose(passwd);
+                }
+        }
+
+        if (!matched && nis) {
+                char *userinfo = NULL, *domain = NULL;
+                int len = 0, i;
+                len = yp_get_default_domain(&domain);
+                if (len == YPERR_SUCCESS) {
+                        len = yp_bind(domain);
+                }
+                if (len == YPERR_SUCCESS) {
+                        i = yp_match(domain, "passwd.byname", name,
+                                     strlen(name), &userinfo, &len);
+                        yp_unbind(domain);
+                        if ((i == YPERR_SUCCESS) && (len < sizeof(buf))) {
+                                strncpy(buf, userinfo, sizeof(buf) - 1);
+                                buf[sizeof(buf) - 1] = '\0';
+                                matched = 1;
+                        }
+                }
+        }
+
+        if (matched && (ret != NULL)) {
+                *ret = NULL;
+
+                slogin = buf;
+
+                spasswd = strchr(slogin, ':');
+                if (spasswd == NULL) {
+                        return matched;
+                }
+                *spasswd++ = '\0';
+
+
+                suid = strchr(spasswd, ':');
+                if (suid == NULL) {
+                        return matched;
+                }
+                *suid++ = '\0';
+
+                sgid = strchr(suid, ':');
+                if (sgid == NULL) {
+                        return matched;
+                }
+                *sgid++ = '\0';
+
+                sgecos = strchr(sgid, ':');
+                if (sgecos == NULL) {
+                        return matched;
+                }
+                *sgecos++ = '\0';
+
+                shome = strchr(sgecos, ':');
+                if (shome == NULL) {
+                        return matched;
+                }
+                *shome++ = '\0';
+
+                sshell = strchr(shome, ':');
+                if (sshell == NULL) {
+                        return matched;
+                }
+                *sshell++ = '\0';
+
+                buflen = sizeof(struct passwd) +
+                         strlen(slogin) + 1 +
+                         strlen(spasswd) + 1 +
+                         strlen(suid) + 1 +
+                         strlen(sgid) + 1 +
+                         strlen(sgecos) + 1 +
+                         strlen(shome) + 1 +
+                         strlen(sshell) + 1;
+                *ret = malloc(buflen);
+                if (*ret == NULL) {
+                        return matched;
+                }
+                memset(*ret, '\0', buflen);
+
+                (*ret)->pw_uid = strtol(suid, &p, 10);
+                if ((strlen(sgid) == 0) || (*p != '\0')) {
+                        free(*ret);
+                        *ret = NULL;
+                        return matched;
+                }
+
+                (*ret)->pw_gid = strtol(sgid, &p, 10);
+                if ((strlen(sgid) == 0) || (*p != '\0')) {
+                        free(*ret);
+                        *ret = NULL;
+                        return matched;
+                }
+
+                p = ((char*)(*ret)) + sizeof(struct passwd);
+                (*ret)->pw_name = strcpy(p, slogin);
+                p += strlen(p) + 1;
+                (*ret)->pw_passwd = strcpy(p, spasswd);
+                p += strlen(p) + 1;
+                (*ret)->pw_gecos = strcpy(p, sgecos);
+                p += strlen(p) + 1;
+                (*ret)->pw_dir = strcpy(p, shome);
+                p += strlen(p) + 1;
+                (*ret)->pw_shell = strcpy(p, sshell);
+
+                snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name);
+
+                if (pam_set_data(pamh, buf,
+                                 *ret, _unix_cleanup) != PAM_SUCCESS) {
+                        free(*ret);
+                        *ret = NULL;
+                }
+        }
+
+        return matched;
+}
+
+/*
+ * _unix_comsefromsource() is a quick check to see if information about a given
+ * user comes from a particular source (just files and nis for now)
+ *
+ */
+static int _unix_comesfromsource(pam_handle_t *pamh,
+                          const char *name, int files, int nis)
+{
+        return _unix_getpwnam(pamh, name, files, nis, NULL);
 }
 
 static int check_old_password(const char *forwho, const char *newpass)
@@ -261,7 +405,8 @@
        return retval;
 }
 
-static int save_old_password(const char *forwho, const char *oldpass,
+static int save_old_password(pam_handle_t *pamh,
+                             const char *forwho, const char *oldpass,
                             int howmany)
 {
     static char buf[16384];
@@ -333,7 +478,7 @@
     fclose(opwfile);
 
     if (!found) {
-       pwd = _unix_getpwnam(forwho);
+       pwd = _pammodutil_getpwnam(pamh, forwho);
        if (pwd == NULL) {
            err = 1;
        } else {
@@ -423,7 +568,7 @@
     }
 }
 
-static int _update_shadow(const char *forwho, char *towhat)
+static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat)
 {
     struct spwd *spwdent = NULL, *stmpent = NULL;
     FILE *pwfile, *opwfile;
@@ -479,6 +624,7 @@
 
     if (!err) {
        rename(SH_TMPFILE, "/etc/shadow");
+       _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
        return PAM_SUCCESS;
     } else {
        unlink(SH_TMPFILE);
@@ -498,7 +644,7 @@
        if (pwd == NULL)
                return PAM_AUTHTOK_ERR;
 
-       if (on(UNIX_NIS, ctrl)) {
+       if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
                struct timeval timeout;
                struct yppasswd yppwd;
                CLIENT *clnt;
@@ -518,7 +664,7 @@
                yppwd.newpw.pw_gecos = pwd->pw_gecos;
                yppwd.newpw.pw_dir = pwd->pw_dir;
                yppwd.newpw.pw_shell = pwd->pw_shell;
-               yppwd.oldpass = fromwhat ? fromwhat : "";
+               yppwd.oldpass = fromwhat ? strdup (fromwhat) : strdup ("");
                yppwd.newpw.pw_passwd = towhat;
 
                D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho));
@@ -563,7 +709,7 @@
                return retval;
        }
        /* first, save old password */
-       if (save_old_password(forwho, fromwhat, remember)) {
+       if (save_old_password(pamh, forwho, fromwhat, remember)) {
                return PAM_AUTHTOK_ERR;
        }
 
@@ -583,15 +729,20 @@
            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)
-                       retval = _update_passwd(pamh, forwho, "x");
-       } else {
-               retval = _update_passwd(pamh, forwho, towhat);
-       }
 
+       if (_unix_comesfromsource (pamh, forwho, 1, 0))
+         {
+           if (on(UNIX_SHADOW, ctrl) || _unix_shadowed (pwd))
+             {
+               retval = _update_shadow (pamh, forwho, towhat);
+                if (retval == PAM_SUCCESS)
+                 if (!_unix_shadowed (pwd))
+                   retval = _update_passwd (pamh, forwho, "x");
+             }
+           else
+             retval = _update_passwd (pamh, forwho, towhat);
+         }
+       
        if (retval == PAM_SUCCESS)
            _log_err(LOG_NOTICE, pamh, "Password for %s was changed", forwho);
 
@@ -610,11 +761,11 @@
        int retval = PAM_SUCCESS;
 
        /* UNIX passwords area */
-       pwd = _unix_getpwnam(user);     /* Get password *file* entry... */
+       pwd = getpwnam(user);   /* Get password *file* entry... */
        if (pwd == NULL)
                return PAM_AUTHINFO_UNAVAIL;    /* We don't need to do the 
rest... */
 
-       if (strcmp(pwd->pw_passwd, "x") == 0) {
+       if (_unix_shadowed(pwd)) {
                /* ...and shadow password file entry for this user, if shadowing
                   is enabled */
                setspent();
@@ -767,6 +918,30 @@
        D(("Got username of %s", user));
 
        /*
+        * Before we do anything else, check to make sure that the user's
+        * info is in one of the databases we can modify from this module,
+        * which currently is 'files' and 'nis'.  We have to do this because
+        * getpwnam() doesn't tell you *where* the information it gives you
+        * came from, nor should it.  That's our job.
+        */
+       if (_unix_comesfromsource(pamh, user, 1, 1) == 0) {
+               _log_err(LOG_DEBUG, pamh,
+                        "user \"%s\" does not exist in /etc/passwd or NIS",
+                        user);
+               return PAM_USER_UNKNOWN;
+       } else {
+               struct passwd *pwd;
+               _unix_getpwnam(pamh, user, 1, 1, &pwd);
+               if (!_unix_shadowed(pwd) &&
+                   (strchr(pwd->pw_passwd, '*') != NULL)) {
+                       _log_err(LOG_DEBUG, pamh,
+                               "user \"%s\" does not have modifiable password",
+                               user);
+                       return PAM_USER_UNKNOWN;
+               }
+       }
+
+       /*
         * This is not an AUTH module!
         */
        if (on(UNIX__NONULL, ctrl))
@@ -806,7 +981,7 @@
                                               : "(current) UNIX password: ")
                                                     ,NULL
                                                     ,_UNIX_OLD_AUTHTOK
-                                            ,(const char **) &pass_old);
+                                            ,&pass_old);
                        free(Announce);
 
                        if (retval != PAM_SUCCESS) {
diff -ur pam-0.76/Linux-PAM/modules/pam_unix/support.c 
pam-0.76-new/Linux-PAM/modules/pam_unix/support.c
--- pam-0.76/Linux-PAM/modules/pam_unix/support.c       2005-08-31 
16:00:36.797475000 -0500
+++ pam-0.76-new/Linux-PAM/modules/pam_unix/support.c   2005-08-31 
15:48:54.957884000 -0500
@@ -791,7 +791,7 @@
         */
 
        if (on(UNIX_TRY_FIRST_PASS, ctrl) || on(UNIX_USE_FIRST_PASS, ctrl)) {
-               retval = pam_get_item(pamh, authtok_flag, (const void **) pass);
+               retval = pam_get_item(pamh, authtok_flag, pass);
                if (retval != PAM_SUCCESS) {
                        /* very strange. */
                        _log_err(LOG_ALERT, pamh
@@ -926,6 +926,21 @@
        return PAM_SUCCESS;
 }
 
+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;
+}
+
 /* ****************************************************************** *
  * Copyright (c) Jan Rêkorajski 1999.
  * Copyright (c) Andrew G. Morgan 1996-8.
diff -ur pam-0.76/Linux-PAM/modules/pam_unix/support.h 
pam-0.76-new/Linux-PAM/modules/pam_unix/support.h
--- pam-0.76/Linux-PAM/modules/pam_unix/support.h       2005-08-31 
16:00:36.837467000 -0500
+++ pam-0.76-new/Linux-PAM/modules/pam_unix/support.h   2005-08-31 
15:48:54.967880000 -0500
@@ -149,6 +149,7 @@
                        ,const char *prompt2
                        ,const char *data_name
                        ,const char **pass);
+extern int _unix_shadowed(const struct passwd *pwd);
 
 extern unsigned int pass_min_len;
 extern unsigned int pass_max_len;

Reply via email to