]> granicus.if.org Git - linux-pam/blobdiff - modules/pam_unix/pam_unix_passwd.c
Relevant BUGIDs:
[linux-pam] / modules / pam_unix / pam_unix_passwd.c
index 9c7cb07cf1d56bb77278e4f56fbff503c9cbba24..099888166fafab74e7314cb7c66e3a5098e93bbd 100644 (file)
@@ -35,7 +35,7 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <security/_pam_aconf.h>
+#include "config.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -78,12 +78,8 @@ static security_context_t prev_context=NULL;
 #define PAM_SM_PASSWORD
 
 #include <security/pam_modules.h>
-
-#ifndef LINUX_PAM
-#include <security/pam_appl.h>
-#endif                         /* LINUX_PAM */
-
-#include <security/_pam_modutil.h>
+#include <security/pam_ext.h>
+#include <security/pam_modutil.h>
 
 #include "yppasswd.h"
 #include "md5.h"
@@ -99,7 +95,7 @@ extern int getrpcport(const char *host, unsigned long prognum,
  * password changing module.
  */
 
-#ifdef NEED_LCKPWDF
+#if defined(USE_LCKPWDF) && !defined(HAVE_LCKPWDF)
 # include "./lckpwdf.-c"
 #endif
 
@@ -127,7 +123,7 @@ extern char *bigcrypt(const char *key, const char *salt);
 #define PW_TMPFILE             "/etc/npasswd"
 #define SH_TMPFILE             "/etc/nshadow"
 #ifndef CRACKLIB_DICTS
-#define CRACKLIB_DICTS         "/usr/share/dict/cracklib_dict"
+#define CRACKLIB_DICTS         NULL
 #endif
 #define OPW_TMPFILE            "/etc/security/nopasswd"
 #define OLD_PASSWORDS_FILE     "/etc/security/opasswd"
@@ -197,24 +193,24 @@ static char *getNISserver(pam_handle_t *pamh)
        int port, err;
 
        if ((err = yp_get_default_domain(&domainname)) != 0) {
-               _log_err(LOG_WARNING, pamh, "can't get local yp domain: %s\n",
+               pam_syslog(pamh, LOG_WARNING, "can't get local yp domain: %s",
                         yperr_string(err));
                return NULL;
        }
        if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) {
-               _log_err(LOG_WARNING, pamh, "can't find the master ypserver: %s\n",
+               pam_syslog(pamh, LOG_WARNING, "can't find the master ypserver: %s",
                         yperr_string(err));
                return NULL;
        }
        port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP);
        if (port == 0) {
-               _log_err(LOG_WARNING, pamh,
-                        "yppasswdd not running on NIS master host\n");
+               pam_syslog(pamh, LOG_WARNING,
+                        "yppasswdd not running on NIS master host");
                return NULL;
        }
        if (port >= IPPORT_RESERVED) {
-               _log_err(LOG_WARNING, pamh,
-                        "yppasswd daemon running on illegal port.\n");
+               pam_syslog(pamh, LOG_WARNING,
+                        "yppasswd daemon running on illegal port");
                return NULL;
        }
        return master;
@@ -249,7 +245,7 @@ static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const
     /* fork */
     child = fork();
     if (child == 0) {
-        int i=0;
+        size_t i=0;
         struct rlimit rlim;
        static char *envp[] = { NULL };
        char *args[] = { NULL, NULL, NULL, NULL };
@@ -263,10 +259,17 @@ static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const
 
        if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
          for (i=2; i < rlim.rlim_max; i++) {
-               if (fds[0] != i)
+           if ((unsigned int)fds[0] != i)
                   close(i);
          }
        }
+
+        if (SELINUX_ENABLED && geteuid() == 0) {
+          /* must set the real uid to 0 so the helper will not error
+             out if pam is called from setuid binary (su, sudo...) */
+          setuid(0);
+        }
+
        /* exec binary helper */
        args[0] = x_strdup(CHKPWD_HELPER);
        args[1] = x_strdup(user);
@@ -282,20 +285,20 @@ static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const
        /* if the stored password is NULL */
         int rc=0;
        if (fromwhat)
-         _pammodutil_write(fds[1], fromwhat, strlen(fromwhat)+1);
+         pam_modutil_write(fds[1], fromwhat, strlen(fromwhat)+1);
        else
-         _pammodutil_write(fds[1], "", 1);
+         pam_modutil_write(fds[1], "", 1);
        if (towhat) {
-         _pammodutil_write(fds[1], towhat, strlen(towhat)+1);
+         pam_modutil_write(fds[1], towhat, strlen(towhat)+1);
        }
        else
-         _pammodutil_write(fds[1], "", 1);
+         pam_modutil_write(fds[1], "", 1);
 
        close(fds[0]);       /* close here to avoid possible SIGPIPE above */
        close(fds[1]);
        rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
        if (rc<0) {
-         _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
+         pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc);
          retval = PAM_AUTH_ERR;
        } else {
          retval = WEXITSTATUS(retval);
@@ -463,7 +466,7 @@ static int save_old_password(pam_handle_t *pamh,
     fclose(opwfile);
 
     if (!found) {
-       pwd = _pammodutil_getpwnam(pamh, forwho);
+       pwd = pam_modutil_getpwnam(pamh, forwho);
        if (pwd == NULL) {
            err = 1;
        } else {
@@ -598,7 +601,7 @@ static int _update_passwd(pam_handle_t *pamh,
 done:
     if (!err) {
        if (!rename(PW_TMPFILE, "/etc/passwd"))
-           _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
+           pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho);
        else
            err = 1;
     }
@@ -714,7 +717,7 @@ static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat)
  done:
     if (!err) {
        if (!rename(SH_TMPFILE, "/etc/shadow"))
-           _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
+           pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho);
        else
            err = 1;
     }
@@ -738,7 +741,8 @@ static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat)
     }
 }
 
-static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
+static int _do_setpass(pam_handle_t* pamh, const char *forwho,
+                      const char *fromwhat,
                       char *towhat, unsigned int ctrl, int remember)
 {
        struct passwd *pwd = NULL;
@@ -754,7 +758,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
                retval = PAM_AUTHTOK_ERR;
                goto done;
        }
-       
+
        if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
            if ((master=getNISserver(pamh)) != NULL) {
                struct timeval timeout;
@@ -777,7 +781,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
                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));
@@ -797,6 +801,8 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
                                (xdrproc_t) xdr_int, (char *) &status,
                                timeout);
 
+               free (yppwd.oldpass);
+
                if (err) {
                        _make_remark(pamh, ctrl, PAM_TEXT_INFO,
                                clnt_sperrno(err));
@@ -805,14 +811,14 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
                }
                D(("The password has%s been changed on %s.",
                   (err || status) ? " not" : "", master));
-               _log_err(LOG_NOTICE, pamh, "password%s changed for %s on %s",
+               pam_syslog(pamh, LOG_NOTICE, "password%s changed for %s on %s",
                         (err || status) ? " not" : "", pwd->pw_name, master);
 
                auth_destroy(clnt->cl_auth);
                clnt_destroy(clnt);
                if (err || status) {
                        _make_remark(pamh, ctrl, PAM_TEXT_INFO,
-                               "NIS password could not be changed.");
+                               _("NIS password could not be changed."));
                        retval = PAM_TRY_AGAIN;
                }
 #ifdef DEBUG
@@ -862,7 +868,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
        }
 
 
-done:  
+done:
 #ifdef USE_LCKPWDF
        ulckpwdf();
 #endif
@@ -917,10 +923,22 @@ static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned in
                if (off(UNIX__IAMROOT, ctrl)) {
                        /* Get the current number of days since 1970 */
                        curdays = time(NULL) / (60 * 60 * 24);
-                       if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min))
-                           && (spwdent->sp_min != -1))
+                       if (curdays < spwdent->sp_lstchg) {
+                               pam_syslog(pamh, LOG_DEBUG,
+                                       "account %s has password changed in future",
+                                       user);
+                               curdays = spwdent->sp_lstchg;
+                       }
+                       if ((curdays - spwdent->sp_lstchg < spwdent->sp_min)
+                                && (spwdent->sp_min != -1))
+                               /*
+                                * The last password change was too recent.
+                                */
                                retval = PAM_AUTHTOK_ERR;
-                       else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact))
+                       else if ((curdays - spwdent->sp_lstchg > spwdent->sp_max)
+                                && (curdays - spwdent->sp_lstchg > spwdent->sp_inact)
+                                && (curdays - spwdent->sp_lstchg >
+                                    spwdent->sp_max + spwdent->sp_inact)
                                 && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1)
                                 && (spwdent->sp_lstchg != 0))
                                /*
@@ -943,7 +961,7 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh
                                  ,const char *pass_old
                                  ,const char *pass_new)
 {
-       const char *user;
+       const void *user;
        const char *remark = NULL;
        int retval = PAM_SUCCESS;
 
@@ -953,10 +971,10 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh
 
        if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) {
                if (on(UNIX_DEBUG, ctrl)) {
-                       _log_err(LOG_DEBUG, pamh, "bad authentication token");
+                       pam_syslog(pamh, LOG_DEBUG, "bad authentication token");
                }
                _make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
-                         "No password supplied" : "Password unchanged");
+                       _("No password supplied") : _("Password unchanged"));
                return PAM_AUTHTOK_ERR;
        }
        /*
@@ -964,27 +982,27 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh
         * checking this would be the place - AGM
         */
 
-       retval = pam_get_item(pamh, PAM_USER, (const void **) &user);
+       retval = pam_get_item(pamh, PAM_USER, &user);
        if (retval != PAM_SUCCESS) {
                if (on(UNIX_DEBUG, ctrl)) {
-                       _log_err(LOG_ERR, pamh, "Can not get username");
+                       pam_syslog(pamh, LOG_ERR, "Can not get username");
                        return PAM_AUTHTOK_ERR;
                }
        }
        if (off(UNIX__IAMROOT, ctrl)) {
 #ifdef USE_CRACKLIB
-               remark = FascistCheck(pass_new, CRACKLIB_DICTS);
+               remark = FascistCheck (pass_new, CRACKLIB_DICTS);
                D(("called cracklib [%s]", remark));
 #else
                if (strlen(pass_new) < 6)
-                       remark = "You must choose a longer password";
+                 remark = _("You must choose a longer password");
                D(("length check [%s]", remark));
 #endif
                if (on(UNIX_REMEMBER_PASSWD, ctrl)) {
                        if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR)
-                               remark = "Password has been already used. Choose another.";
+                         remark = _("Password has been already used. Choose another.");
                        if (retval == PAM_ABORT) {
-                               _log_err(LOG_ERR, pamh, "can't open %s file to check old passwords",
+                               pam_syslog(pamh, LOG_ERR, "can't open %s file to check old passwords",
                                        OLD_PASSWORDS_FILE);
                                return retval;
                        }
@@ -1007,7 +1025,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
        /* <DO NOT free() THESE> */
        const char *user;
-       char *pass_old, *pass_new;
+       const void *pass_old, *pass_new;
        /* </DO NOT free() THESE> */
 
        D(("called."));
@@ -1026,15 +1044,15 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                 * alphanumeric character.
                 */
                if (user == NULL || !isalnum(*user)) {
-                       _log_err(LOG_ERR, pamh, "bad username [%s]", user);
+                       pam_syslog(pamh, LOG_ERR, "bad username [%s]", user);
                        return PAM_USER_UNKNOWN;
                }
                if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl))
-                       _log_err(LOG_DEBUG, pamh, "username [%s] obtained",
+                       pam_syslog(pamh, LOG_DEBUG, "username [%s] obtained",
                                 user);
        } else {
                if (on(UNIX_DEBUG, ctrl))
-                       _log_err(LOG_DEBUG, pamh,
+                       pam_syslog(pamh, LOG_DEBUG,
                                 "password - could not identify user");
                return retval;
        }
@@ -1048,23 +1066,23 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
         * 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);
+       if (_unix_comesfromsource(pamh, user, 1, on(UNIX_NIS, ctrl)) == 0) {
+               pam_syslog(pamh, LOG_DEBUG,
+                        "user \"%s\" does not exist in /etc/passwd%s",
+                        user, on(UNIX_NIS, ctrl) ? " or NIS" : "");
                return PAM_USER_UNKNOWN;
        } else {
                struct passwd *pwd;
                _unix_getpwnam(pamh, user, 1, 1, &pwd);
                if (pwd == NULL) {
-                       _log_err(LOG_DEBUG, pamh,
+                       pam_syslog(pamh, LOG_DEBUG,
                                "user \"%s\" has corrupted passwd entry",
                                user);
                        return PAM_USER_UNKNOWN;
                }
                if (!_unix_shadowed(pwd) &&
                    (strchr(pwd->pw_passwd, '*') != NULL)) {
-                       _log_err(LOG_DEBUG, pamh,
+                       pam_syslog(pamh, LOG_DEBUG,
                                "user \"%s\" does not have modifiable password",
                                user);
                        return PAM_USER_UNKNOWN;
@@ -1094,7 +1112,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 #define greeting "Changing password for "
                        Announce = (char *) malloc(sizeof(greeting) + strlen(user));
                        if (Announce == NULL) {
-                               _log_err(LOG_CRIT, pamh,
+                               pam_syslog(pamh, LOG_CRIT,
                                         "password - out of memory");
                                return PAM_BUF_ERR;
                        }
@@ -1106,15 +1124,15 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                        set(UNIX__OLD_PASSWD, lctrl);
                        retval = _unix_read_password(pamh, lctrl
                                                     ,Announce
-                                            ,"(current) UNIX password: "
+                                            ,_("(current) UNIX password: ")
                                                     ,NULL
                                                     ,_UNIX_OLD_AUTHTOK
-                                            ,(const char **) &pass_old);
+                                            ,&pass_old);
                        free(Announce);
 
                        if (retval != PAM_SUCCESS) {
-                               _log_err(LOG_NOTICE, pamh
-                                ,"password - (old) token not obtained");
+                               pam_syslog(pamh, LOG_NOTICE,
+                                   "password - (old) token not obtained");
                                return retval;
                        }
                        /* verify that this is the password for this user */
@@ -1134,14 +1152,14 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
                pass_old = NULL;
                if (retval != PAM_SUCCESS) {
-                       _log_err(LOG_CRIT, pamh,
+                       pam_syslog(pamh, LOG_CRIT,
                                 "failed to set PAM_OLDAUTHTOK");
                }
                retval = _unix_verify_shadow(pamh,user, ctrl);
                if (retval == PAM_AUTHTOK_ERR) {
                        if (off(UNIX__IAMROOT, ctrl))
                                _make_remark(pamh, ctrl, PAM_ERROR_MSG,
-                                           "You must wait longer to change your password");
+                                            _("You must wait longer to change your password"));
                        else
                                retval = PAM_SUCCESS;
                }
@@ -1168,10 +1186,10 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                if (off(UNIX_NOT_SET_PASS, ctrl)) {
                        retval = pam_get_item(pamh, PAM_OLDAUTHTOK
-                                             ,(const void **) &pass_old);
+                                             ,&pass_old);
                } else {
                        retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK
-                                             ,(const void **) &pass_old);
+                                             ,&pass_old);
                        if (retval == PAM_NO_MODULE_DATA) {
                                retval = PAM_SUCCESS;
                                pass_old = NULL;
@@ -1180,7 +1198,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                D(("pass_old [%s]", pass_old));
 
                if (retval != PAM_SUCCESS) {
-                       _log_err(LOG_NOTICE, pamh, "user not authenticated");
+                       pam_syslog(pamh, LOG_NOTICE, "user not authenticated");
                        return retval;
                }
 
@@ -1201,15 +1219,15 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                        retval = _unix_read_password(pamh, lctrl
                                                     ,NULL
-                                            ,"Enter new UNIX password: "
-                                           ,"Retype new UNIX password: "
+                                            ,_("Enter new UNIX password: ")
+                                           ,_("Retype new UNIX password: ")
                                                     ,_UNIX_NEW_AUTHTOK
-                                            ,(const char **) &pass_new);
+                                            ,&pass_new);
 
                        if (retval != PAM_SUCCESS) {
                                if (on(UNIX_DEBUG, ctrl)) {
-                                       _log_err(LOG_ALERT, pamh
-                                                ,"password - new password not obtained");
+                                       pam_syslog(pamh, LOG_ALERT,
+                                                "password - new password not obtained");
                                }
                                pass_old = NULL;        /* tidy up */
                                return retval;
@@ -1222,14 +1240,14 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                         * password is acceptable.
                         */
 
-                       if (pass_new[0] == '\0') {      /* "\0" password = NULL */
+                       if (*(const char *)pass_new == '\0') {  /* "\0" password = NULL */
                                pass_new = NULL;
                        }
                        retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
                }
 
                if (retval != PAM_SUCCESS) {
-                       _log_err(LOG_NOTICE, pamh,
+                       pam_syslog(pamh, LOG_NOTICE,
                                 "new password not acceptable");
                        pass_new = pass_old = NULL;     /* tidy up */
                        return retval;
@@ -1254,7 +1272,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                if (pass_old) {
                        retval = _unix_verify_password(pamh, user, pass_old, ctrl);
                        if (retval != PAM_SUCCESS) {
-                               _log_err(LOG_NOTICE, pamh, "user password changed by another process");
+                               pam_syslog(pamh, LOG_NOTICE, "user password changed by another process");
 #ifdef USE_LCKPWDF
                                ulckpwdf();
 #endif
@@ -1264,7 +1282,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                retval = _unix_verify_shadow(pamh, user, ctrl);
                if (retval != PAM_SUCCESS) {
-                       _log_err(LOG_NOTICE, pamh, "user not authenticated 2");
+                       pam_syslog(pamh, LOG_NOTICE, "user not authenticated 2");
 #ifdef USE_LCKPWDF
                        ulckpwdf();
 #endif
@@ -1273,7 +1291,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
                if (retval != PAM_SUCCESS) {
-                       _log_err(LOG_NOTICE, pamh,
+                       pam_syslog(pamh, LOG_NOTICE,
                                 "new password not acceptable 2");
                        pass_new = pass_old = NULL;     /* tidy up */
 #ifdef USE_LCKPWDF
@@ -1317,7 +1335,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                                char *temp = malloc(9);
 
                                if (temp == NULL) {
-                                       _log_err(LOG_CRIT, pamh,
+                                       pam_syslog(pamh, LOG_CRIT,
                                                 "out of memory for password");
                                        pass_new = pass_old = NULL;     /* tidy up */
 #ifdef USE_LCKPWDF
@@ -1349,7 +1367,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                _pam_delete(tpass);
                pass_old = pass_new = NULL;
        } else {                /* something has broken with the module */
-               _log_err(LOG_ALERT, pamh,
+               pam_syslog(pamh, LOG_ALERT,
                         "password received unknown request");
                retval = PAM_ABORT;
        }