]> granicus.if.org Git - linux-pam/blobdiff - modules/pam_unix/pam_unix_passwd.c
Add missing ')'
[linux-pam] / modules / pam_unix / pam_unix_passwd.c
index b8da991388c8d68d091e50f928ccaed538c163b3..9aae3b03de3531c5542fc3acaff620819b8ee400 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
  * Copyright (C) 1996.
- * Copyright (c) Jan Rêkorajski, 1999.
+ * Copyright (c) Jan Rêkorajski, 1999.
  * Copyright (c) Red Hat, Inc., 2007, 2008.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <ctype.h>
 #include <sys/time.h>
 #include <sys/stat.h>
-#include <rpc/rpc.h>
-#include <rpcsvc/yp_prot.h>
-#include <rpcsvc/ypclnt.h>
 
 #include <signal.h>
 #include <errno.h>
 #include <sys/wait.h>
-#ifdef WITH_SELINUX
-static int selinux_enabled=-1;
-#include <selinux/selinux.h>
-#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0))
-#endif
+#include <sys/resource.h>
 
 #include <security/_pam_macros.h>
 
 /* indicate the following groups are defined */
 
-#define PAM_SM_PASSWORD
+#ifdef PAM_STATIC
+# include "pam_unix_static.h"
+#else
+# define PAM_SM_PASSWORD
+#endif
 
 #include <security/pam_modules.h>
 #include <security/pam_ext.h>
 #include <security/pam_modutil.h>
 
-#include "yppasswd.h"
 #include "md5.h"
 #include "support.h"
 #include "passverify.h"
 #include "bigcrypt.h"
 
-#if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
+#if (HAVE_YP_GET_DEFAULT_DOMAIN || HAVE_GETDOMAINNAME) && HAVE_YP_MASTER
+# define HAVE_NIS
+#endif
+
+#ifdef HAVE_NIS
+# include <rpc/rpc.h>
+
+# if HAVE_RPCSVC_YP_PROT_H
+#  include <rpcsvc/yp_prot.h>
+# endif
+
+# if HAVE_RPCSVC_YPCLNT_H
+#  include <rpcsvc/ypclnt.h>
+# endif
+
+# include "yppasswd.h"
+
+# if !HAVE_DECL_GETRPCPORT
 extern int getrpcport(const char *host, unsigned long prognum,
                      unsigned long versnum, unsigned int proto);
-#endif                         /* GNU libc 2.1 */
+# endif                                /* GNU libc 2.1 */
+#endif
 
 /*
    How it works:
@@ -103,17 +117,34 @@ extern int getrpcport(const char *host, unsigned long prognum,
 
 #define MAX_PASSWD_TRIES       3
 
-static char *getNISserver(pam_handle_t *pamh)
+#ifdef HAVE_NIS
+static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl)
 {
        char *master;
        char *domainname;
        int port, err;
 
+#ifdef HAVE_YP_GET_DEFAULT_DOMAIN
        if ((err = yp_get_default_domain(&domainname)) != 0) {
                pam_syslog(pamh, LOG_WARNING, "can't get local yp domain: %s",
                         yperr_string(err));
                return NULL;
        }
+#elif defined(HAVE_GETDOMAINNAME)
+       char domainname_res[256];
+
+       if (getdomainname (domainname_res, sizeof (domainname_res)) == 0)
+         {
+           if (strcmp (domainname_res, "(none)") == 0)
+             {
+               /* If domainname is not set, some systems will return "(none)" */
+               domainname_res[0] = '\0';
+             }
+           domainname = domainname_res;
+         }
+       else domainname = NULL;
+#endif
+
        if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) {
                pam_syslog(pamh, LOG_WARNING, "can't find the master ypserver: %s",
                         yperr_string(err));
@@ -130,8 +161,13 @@ static char *getNISserver(pam_handle_t *pamh)
                         "yppasswd daemon running on illegal port");
                return NULL;
        }
+       if (on(UNIX_DEBUG, ctrl)) {
+         pam_syslog(pamh, LOG_DEBUG, "Use NIS server on %s with port %d",
+                    master, port);
+       }
        return master;
 }
+#endif
 
 #ifdef WITH_SELINUX
 
@@ -139,7 +175,7 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const
     const char *fromwhat, const char *towhat, int remember)
 {
     int retval, child, fds[2];
-    void (*sighandler)(int) = NULL;
+    struct sigaction newsa, oldsa;
 
     D(("called."));
     /* create a pipe for the password */
@@ -157,7 +193,9 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const
         * The "noreap" module argument is provided so that the admin can
         * override this behavior.
         */
-       sighandler = signal(SIGCHLD, SIG_DFL);
+        memset(&newsa, '\0', sizeof(newsa));
+        newsa.sa_handler = SIG_DFL;
+        sigaction(SIGCHLD, &newsa, &oldsa);
     }
 
     /* fork */
@@ -179,16 +217,10 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const
            rlim.rlim_max = MAX_FD_NO;
          for (i=0; i < (int)rlim.rlim_max; i++) {
            if (i != STDIN_FILENO)
-                  close(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(UPDATE_HELPER);
        args[1] = x_strdup(user);
@@ -200,12 +232,12 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const
 
         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"));
-       exit(PAM_AUTHINFO_UNAVAIL);
+       _exit(PAM_AUTHINFO_UNAVAIL);
     } else if (child > 0) {
        /* wait for child */
        /* if the stored password is NULL */
@@ -222,22 +254,26 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const
 
        close(fds[0]);       /* close here to avoid possible SIGPIPE above */
        close(fds[1]);
-       rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
+       /* wait for helper to complete: */
+       while ((rc=waitpid(child, &retval, 0)) < 0 && errno == EINTR);
        if (rc<0) {
          pam_syslog(pamh, LOG_ERR, "unix_update waitpid failed: %m");
-         retval = PAM_AUTH_ERR;
-       } else {
+         retval = PAM_AUTHTOK_ERR;
+       } else if (!WIFEXITED(retval)) {
+          pam_syslog(pamh, LOG_ERR, "unix_update abnormal exit: %d", retval);
+          retval = PAM_AUTHTOK_ERR;
+        } else {
          retval = WEXITSTATUS(retval);
        }
     } else {
        D(("fork failed"));
        close(fds[0]);
-       close(fds[1]);
+       close(fds[1]);
        retval = PAM_AUTH_ERR;
     }
 
-    if (sighandler != SIG_ERR) {
-        (void) signal(SIGCHLD, sighandler);   /* restore old signal handler */
+    if (off(UNIX_NOREAP, ctrl)) {
+        sigaction(SIGCHLD, &oldsa, NULL);   /* restore old signal handler */
     }
 
     return retval;
@@ -250,13 +286,15 @@ static int check_old_password(const char *forwho, const char *newpass)
        char *s_luser, *s_uid, *s_npas, *s_pas;
        int retval = PAM_SUCCESS;
        FILE *opwfile;
+       size_t len = strlen(forwho);
 
        opwfile = fopen(OLD_PASSWORDS_FILE, "r");
        if (opwfile == NULL)
                return PAM_ABORT;
 
        while (fgets(buf, 16380, opwfile)) {
-               if (!strncmp(buf, forwho, strlen(forwho))) {
+               if (!strncmp(buf, forwho, len) && (buf[len] == ':' ||
+                       buf[len] == ',')) {
                        char *sptr;
                        buf[strlen(buf) - 1] = '\0';
                        s_luser = strtok_r(buf, ":,", &sptr);
@@ -300,7 +338,8 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho,
        }
 
        if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
-           if ((master=getNISserver(pamh)) != NULL) {
+#ifdef HAVE_NIS
+         if ((master=getNISserver(pamh, ctrl)) != NULL) {
                struct timeval timeout;
                struct yppasswd yppwd;
                CLIENT *clnt;
@@ -359,12 +398,19 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho,
                                _("NIS password could not be changed."));
                        retval = PAM_TRY_AGAIN;
                }
-#ifdef DEBUG
+#ifdef PAM_DEBUG
                sleep(5);
 #endif
            } else {
                    retval = PAM_TRY_AGAIN;
            }
+#else
+          if (on(UNIX_DEBUG, ctrl)) {
+            pam_syslog(pamh, LOG_DEBUG, "No NIS support available");
+          }
+
+          retval = PAM_TRY_AGAIN;
+#endif
        }
 
        if (_unix_comesfromsource(pamh, forwho, 1, 0)) {
@@ -431,7 +477,8 @@ static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned in
 static int _pam_unix_approve_pass(pam_handle_t * pamh
                                  ,unsigned int ctrl
                                  ,const char *pass_old
-                                 ,const char *pass_new)
+                                 ,const char *pass_new,
+                                  int pass_min_len)
 {
        const void *user;
        const char *remark = NULL;
@@ -462,7 +509,7 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh
                }
        }
        if (off(UNIX__IAMROOT, ctrl)) {
-               if (strlen(pass_new) < 6)
+               if (strlen(pass_new) < pass_min_len)
                  remark = _("You must choose a longer password");
                D(("length check [%s]", remark));
                if (on(UNIX_REMEMBER_PASSWD, ctrl)) {
@@ -482,14 +529,14 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh
        return retval;
 }
 
-
-PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
-                               int argc, const char **argv)
+int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
 {
        unsigned int ctrl, lctrl;
        int retval;
        int remember = -1;
        int rounds = -1;
+       int pass_min_len = 0;
 
        /* <DO NOT free() THESE> */
        const char *user;
@@ -498,7 +545,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
        D(("called."));
 
-       ctrl = _set_ctrl(pamh, flags, &remember, &rounds, argc, argv);
+       ctrl = _set_ctrl(pamh, flags, &remember, &rounds, &pass_min_len,
+                        argc, argv);
 
        /*
         * First get the name of a user
@@ -698,8 +746,9 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                        if (*(const char *)pass_new == '\0') {  /* "\0" password = NULL */
                                pass_new = NULL;
                        }
-                       retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
-                       
+                       retval = _pam_unix_approve_pass(pamh, ctrl, pass_old,
+                                                       pass_new, pass_min_len);
+
                        if (retval != PAM_SUCCESS && off(UNIX_NOT_SET_PASS, ctrl)) {
                                pam_set_item(pamh, PAM_AUTHTOK, NULL);
                        }
@@ -731,7 +780,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                        return retval;
                }
 
-               retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
+               retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new,
+                                               pass_min_len);
                if (retval != PAM_SUCCESS) {
                        pam_syslog(pamh, LOG_NOTICE,
                                 "new password not acceptable 2");
@@ -752,7 +802,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                tpass = create_password_hash(pamh, pass_new, ctrl, rounds);
                if (tpass == NULL) {
                        pam_syslog(pamh, LOG_CRIT,
-                               "out of memory for password");
+                               "crypt() failure or out of memory for password");
                        pass_new = pass_old = NULL;     /* tidy up */
                        unlock_pwdf();
                        return PAM_BUF_ERR;
@@ -778,17 +828,3 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
        return retval;
 }
-
-
-/* static module data */
-#ifdef PAM_STATIC
-struct pam_module _pam_unix_passwd_modstruct = {
-    "pam_unix_passwd",
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    pam_sm_chauthtok,
-};
-#endif