]> granicus.if.org Git - linux-pam/blobdiff - modules/pam_unix/passverify.c
Relevant BUGIDs:
[linux-pam] / modules / pam_unix / passverify.c
index 6d588e63c24397d845af83eefa1d13fb9a34418e..8cf95c3331afef93f0bd90814f1034cafb92880d 100644 (file)
@@ -19,7 +19,9 @@
 #include <sys/time.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#ifdef HAVE_CRYPT_H
+#ifdef HAVE_LIBXCRYPT
+#include <xcrypt.h>
+#elif defined(HAVE_CRYPT_H)
 #include <crypt.h>
 #endif
 
@@ -117,7 +119,7 @@ verify_pwd_hash(const char *p, char *hash, unsigned int nullok)
                p = NULL;               /* no longer needed here */
 
                /* the moment of truth -- do we agree with the password? */
-               D(("comparing state of pp[%s] and salt[%s]", pp, salt));
+               D(("comparing state of pp[%s] and hash[%s]", pp, hash));
 
                if (pp && strcmp(pp, hash) == 0) {
                        retval = PAM_SUCCESS;
@@ -149,15 +151,8 @@ is_pwd_shadowed(const struct passwd *pwd)
        return 0;
 }
 
-#ifdef HELPER_COMPILE
-int
-get_account_info(const char *name,
-       struct passwd **pwd, struct spwd **spwdent)
-#else
-int
-get_account_info(pam_handle_t *pamh, const char *name,
-       struct passwd **pwd,  struct spwd **spwdent)
-#endif
+PAMH_ARG_DECL(int get_account_info,
+       const char *name, struct passwd **pwd, struct spwd **spwdent)
 {
        /* UNIX passwords area */
        *pwd = pam_modutil_getpwnam(pamh, name);        /* Get password file entry... */
@@ -217,24 +212,13 @@ get_account_info(pam_handle_t *pamh, const char *name,
        return PAM_SUCCESS;
 }
 
-#ifdef HELPER_COMPILE
-int
-get_pwd_hash(const char *name,
-       struct passwd **pwd, char **hash)
-#else
-int
-get_pwd_hash(pam_handle_t *pamh, const char *name,
-       struct passwd **pwd, char **hash)
-#endif
+PAMH_ARG_DECL(int get_pwd_hash,
+       const char *name, struct passwd **pwd, char **hash)
 {
        int retval;
        struct spwd *spwdent = NULL;
 
-#ifdef HELPER_COMPILE
-       retval = get_account_info(name, pwd, &spwdent);
-#else
-       retval = get_account_info(pamh, name, pwd, &spwdent);
-#endif
+       retval = get_account_info(PAMH_ARG(name, pwd, &spwdent));
        if (retval != PAM_SUCCESS) {
                return retval;
        }
@@ -249,13 +233,8 @@ get_pwd_hash(pam_handle_t *pamh, const char *name,
        return PAM_SUCCESS;
 }
 
-#ifdef HELPER_COMPILE
-int
-check_shadow_expiry(struct spwd *spent, int *daysleft)
-#else
-int
-check_shadow_expiry(pam_handle_t *pamh, struct spwd *spent, int *daysleft)
-#endif
+PAMH_ARG_DECL(int check_shadow_expiry,
+       struct spwd *spent, int *daysleft)
 {
        long int curdays;
        *daysleft = -1;
@@ -293,8 +272,16 @@ check_shadow_expiry(pam_handle_t *pamh, struct spwd *spent, int *daysleft)
                *daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays);
                D(("warn before expiry"));
        }
+       if ((curdays - spent->sp_lstchg < spent->sp_min)
+           && (spent->sp_min != -1)) {
+               /* 
+                * The last password change was too recent. This error will be ignored
+                * if no password change is attempted.
+                */
+               D(("password change too recent"));
+               return PAM_AUTHTOK_ERR;
+       }
        return PAM_SUCCESS;
-
 }
 
 /* passwd/salt conversion macros */
@@ -384,17 +371,19 @@ crypt_md5_wrapper(const char *pass_new)
         return cp;
 }
 
-char *
-create_password_hash(const char *password, unsigned int ctrl, int rounds)
+PAMH_ARG_DECL(char * create_password_hash,
+       const char *password, unsigned int ctrl, int rounds)
 {
        const char *algoid;
        char salt[64]; /* contains rounds number + max 16 bytes of salt + algo id */
        char *sp;
 
        if (on(UNIX_MD5_PASS, ctrl)) {
+               /* algoid = "$1" */
                return crypt_md5_wrapper(password);
-       }
-       if (on(UNIX_SHA256_PASS, ctrl)) {
+       } else if (on(UNIX_BLOWFISH_PASS, ctrl)) {
+               algoid = "$2a$";
+       } else if (on(UNIX_SHA256_PASS, ctrl)) {
                algoid = "$5$";
        } else if (on(UNIX_SHA512_PASS, ctrl)) {
                algoid = "$6$";
@@ -414,17 +403,35 @@ create_password_hash(const char *password, unsigned int ctrl, int rounds)
                return crypted;
        }
 
-       sp = stpcpy(salt, algoid);
-       if (on(UNIX_ALGO_ROUNDS, ctrl)) {
-               sp += snprintf(sp, sizeof(salt) - 3, "rounds=%u$", rounds);
+#ifdef HAVE_CRYPT_GENSALT_RN
+       if (on(UNIX_BLOWFISH_PASS, ctrl)) {
+               char entropy[17];
+               crypt_make_salt(entropy, sizeof(entropy) - 1);
+               sp = crypt_gensalt_rn(algoid, rounds,
+                                     entropy, sizeof(entropy),
+                                     salt, sizeof(salt));
+       } else {
+#endif
+               sp = stpcpy(salt, algoid);
+               if (on(UNIX_ALGO_ROUNDS, ctrl)) {
+                       sp += snprintf(sp, sizeof(salt) - 3, "rounds=%u$", rounds);
+               }
+               crypt_make_salt(sp, 8);
+               /* For now be conservative so the resulting hashes
+                * are not too long. 8 bytes of salt prevents dictionary
+                * attacks well enough. */
+#ifdef HAVE_CRYPT_GENSALT_RN
        }
-       crypt_make_salt(sp, 8);
-       /* For now be conservative so the resulting hashes
-        * are not too long. 8 bytes of salt prevents dictionary
-        * attacks well enough. */
+#endif
        sp = crypt(password, salt);
        if (strncmp(algoid, sp, strlen(algoid)) != 0) {
-       /* libc doesn't know the algorithm, use MD5 */
+               /* libxcrypt/libc doesn't know the algorithm, use MD5 */
+               pam_syslog(pamh, LOG_ERR,
+                          "Algo %s not supported by the crypto backend, "
+                          "falling back to MD5\n",
+                          on(UNIX_BLOWFISH_PASS, ctrl) ? "blowfish" :
+                          on(UNIX_SHA256_PASS, ctrl) ? "sha256" :
+                          on(UNIX_SHA512_PASS, ctrl) ? "sha512" : algoid);
                memset(sp, '\0', strlen(sp));
                return crypt_md5_wrapper(password);
        }
@@ -535,9 +542,15 @@ unlock_pwdf(void)
 }
 #endif
 
+#ifdef HELPER_COMPILE
 int
 save_old_password(const char *forwho, const char *oldpass,
                  int howmany)
+#else
+int
+save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass,
+                 int howmany)
+#endif
 {
     static char buf[16384];
     static char nbuf[16384];
@@ -653,7 +666,7 @@ save_old_password(const char *forwho, const char *oldpass,
     fclose(opwfile);
 
     if (!found) {
-       pwd = getpwnam(forwho);
+       pwd = pam_modutil_getpwnam(pamh, forwho);
        if (pwd == NULL) {
            err = 1;
        } else {
@@ -667,8 +680,13 @@ save_old_password(const char *forwho, const char *oldpass,
        }
     }
 
+    if (fflush(pwfile) || fsync(fileno(pwfile))) {
+       D(("fflush or fsync error writing entries to old passwords file: %m"));
+       err = 1;
+    }
+    
     if (fclose(pwfile)) {
-       D(("error writing entries to old passwords file: %m"));
+       D(("fclose error writing entries to old passwords file: %m"));
        err = 1;
     }
 
@@ -695,13 +713,8 @@ done:
     }
 }
 
-#ifdef HELPER_COMPILE
-int
-unix_update_passwd(const char *forwho, const char *towhat)
-#else
-int
-unix_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat)
-#endif
+PAMH_ARG_DECL(int unix_update_passwd,
+       const char *forwho, const char *towhat)
 {
     struct passwd *tmpent = NULL;
     struct stat st;
@@ -787,19 +800,20 @@ unix_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat)
     }
     fclose(opwfile);
 
+    if (fflush(pwfile) || fsync(fileno(pwfile))) {
+       D(("fflush or fsync error writing entries to password file: %m"));
+       err = 1;
+    }
+    
     if (fclose(pwfile)) {
-       D(("error writing entries to password file: %m"));
+       D(("fclose error writing entries to password file: %m"));
        err = 1;
     }
 
 done:
     if (!err) {
        if (!rename(PW_TMPFILE, "/etc/passwd"))
-#ifdef HELPER_COMPILE
-           helper_log_err(
-#else
            pam_syslog(pamh,
-#endif
                LOG_NOTICE, "password changed for %s", forwho);
        else
            err = 1;
@@ -822,13 +836,8 @@ done:
     }
 }
 
-#ifdef HELPER_COMPILE
-int
-unix_update_shadow(const char *forwho, char *towhat)
-#else
-int
-unix_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat)
-#endif
+PAMH_ARG_DECL(int unix_update_shadow,
+       const char *forwho, char *towhat)
 {
     struct spwd *spwdent = NULL, *stmpent = NULL;
     struct stat st;
@@ -917,19 +926,20 @@ unix_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat)
     }
     fclose(opwfile);
 
+    if (fflush(pwfile) || fsync(fileno(pwfile))) {
+       D(("fflush or fsync error writing entries to shadow file: %m"));
+       err = 1;
+    }
+    
     if (fclose(pwfile)) {
-       D(("error writing entries to shadow file: %m"));
+       D(("fclose error writing entries to shadow file: %m"));
        err = 1;
     }
 
  done:
     if (!err) {
        if (!rename(SH_TMPFILE, "/etc/shadow"))
-#ifdef HELPER_COMPILE
-           helper_log_err(
-#else
            pam_syslog(pamh,
-#endif
                LOG_NOTICE, "password changed for %s", forwho);
        else
            err = 1;
@@ -999,8 +1009,12 @@ 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);
+        if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) {
+               struct sigaction sa;
+               memset(&sa, '\0', sizeof(sa));
+               sa.sa_handler = SIG_DFL;
+                sigaction(sig, &sa, NULL);
+       }
 #endif
         if (sig > 0) {
                 _exit(sig);