Imported Upstream version 1.7.6p1
[debian/sudo] / auth / pam.c
index b03a1f75b1272dee331fed2a94a1e97e9a36540a..265de36e3ca47838f0e8270fea716eb6ae2cb01d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005, 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007-2010 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 # endif
 #endif /* STDC_HEADERS */
 #ifdef HAVE_STRING_H
-# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
-#  include <memory.h>
-# endif
 # include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
 #endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include "sudo_auth.h"
 
 /* Only OpenPAM and Linux PAM use const qualifiers. */
-#if defined(_OPENPAM) || defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__)
+#if defined(_OPENPAM) || defined(OPENPAM_VERSION) || \
+    defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__)
 # define PAM_CONST     const
 #else
 # define PAM_CONST
 #endif
 
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: pam.c,v 1.69 2009/08/07 14:21:51 millert Exp $";
-#endif /* lint */
-
 static int sudo_conv __P((int, PAM_CONST struct pam_message **,
                          struct pam_response **, void *));
 static char *def_prompt = "Password:";
@@ -100,10 +93,16 @@ pam_init(pw, promptp, auth)
     if (auth != NULL)
        auth->data = (void *) &pam_status;
     pam_conv.conv = sudo_conv;
-    pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
+#ifdef HAVE_PAM_LOGIN
+    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
+       pam_status = pam_start("sudo-i", pw->pw_name, &pam_conv, &pamh);
+    else
+#endif
+       pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
+
     if (pam_status != PAM_SUCCESS) {
        log_error(USE_ERRNO|NO_EXIT|NO_MAIL, "unable to initialize PAM");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     /*
@@ -111,7 +110,9 @@ pam_init(pw, promptp, auth)
      * We set PAM_RHOST to avoid a bug in Solaris 7 and below.
      */
     (void) pam_set_item(pamh, PAM_RUSER, user_name);
+#ifdef __sun__
     (void) pam_set_item(pamh, PAM_RHOST, user_host);
+#endif
 
     /*
      * Some versions of pam_lastlog have a bug that
@@ -123,7 +124,7 @@ pam_init(pw, promptp, auth)
     else
        (void) pam_set_item(pamh, PAM_TTY, user_ttypath);
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 int
@@ -144,11 +145,11 @@ pam_verify(pw, prompt, auth)
            *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
            switch (*pam_status) {
                case PAM_SUCCESS:
-                   return(AUTH_SUCCESS);
+                   return AUTH_SUCCESS;
                case PAM_AUTH_ERR:
-                   log_error(NO_EXIT|NO_MAIL, "pam_acct_mgmt: %d",
-                       *pam_status);
-                   return(AUTH_FAILURE);
+                   log_error(NO_EXIT|NO_MAIL,
+                       "account validation failure, is your account locked?");
+                   return AUTH_FATAL;
                case PAM_NEW_AUTHTOK_REQD:
                    log_error(NO_EXIT|NO_MAIL, "%s, %s",
                        "Account or password is expired",
@@ -156,33 +157,33 @@ pam_verify(pw, prompt, auth)
                    *pam_status = pam_chauthtok(pamh,
                        PAM_CHANGE_EXPIRED_AUTHTOK);
                    if (*pam_status == PAM_SUCCESS)
-                       return(AUTH_SUCCESS);
+                       return AUTH_SUCCESS;
                    if ((s = pam_strerror(pamh, *pam_status)))
                        log_error(NO_EXIT|NO_MAIL, "pam_chauthtok: %s", s);
-                   return(AUTH_FAILURE);
+                   return AUTH_FAILURE;
                case PAM_AUTHTOK_EXPIRED:
                    log_error(NO_EXIT|NO_MAIL,
                        "Password expired, contact your system administrator");
-                   return(AUTH_FATAL);
+                   return AUTH_FATAL;
                case PAM_ACCT_EXPIRED:
                    log_error(NO_EXIT|NO_MAIL, "%s %s",
                        "Account expired or PAM config lacks an \"account\"",
                        "section for sudo, contact your system administrator");
-                   return(AUTH_FATAL);
+                   return AUTH_FATAL;
            }
            /* FALLTHROUGH */
        case PAM_AUTH_ERR:
            if (gotintr) {
                /* error or ^C from tgetpass() */
-               return(AUTH_INTR);
+               return AUTH_INTR;
            }
        case PAM_MAXTRIES:
        case PAM_PERM_DENIED:
-           return(AUTH_FAILURE);
+           return AUTH_FAILURE;
        default:
            if ((s = pam_strerror(pamh, *pam_status)))
                log_error(NO_EXIT|NO_MAIL, "pam_authenticate: %s", s);
-           return(AUTH_FATAL);
+           return AUTH_FATAL;
     }
 }
 
@@ -195,18 +196,19 @@ pam_cleanup(pw, auth)
 
     /* If successful, we can't close the session until pam_prep_user() */
     if (auth->status == AUTH_SUCCESS)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
 
     *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT);
-    return(*pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
+    return *pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
 }
 
 int
-pam_prep_user(pw)
+pam_begin_session(pw)
     struct passwd *pw;
 {
-    int eval;
+    int status =  PAM_SUCCESS;
 
+    /* If the user did not have to authenticate there is no pam handle yet. */
     if (pamh == NULL)
        pam_init(pw, NULL, NULL);
 
@@ -227,23 +229,27 @@ pam_prep_user(pw)
     (void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
 
 #ifndef NO_PAM_SESSION
-    /*
-     * To fully utilize PAM sessions we would need to keep a
-     * sudo process around until the command exits.  However, we
-     * can at least cause pam_limits to be run by opening and then
-     * immediately closing the session.
-     */
-    if ((eval = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
-       (void) pam_end(pamh, eval | PAM_DATA_SILENT);
-       return(AUTH_FAILURE);
+    status = pam_open_session(pamh, 0);
+     if (status != PAM_SUCCESS) {
+       (void) pam_end(pamh, status | PAM_DATA_SILENT);
+       pamh = NULL;
     }
-    (void) pam_close_session(pamh, 0);
 #endif
+    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
+}
 
-    if (pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT) == PAM_SUCCESS)
-       return(AUTH_SUCCESS);
-    else
-       return(AUTH_FAILURE);
+int
+pam_end_session()
+{
+    int status = PAM_SUCCESS;
+
+    if (pamh != NULL) {
+#ifndef NO_PAM_SESSION
+       (void) pam_close_session(pamh, 0);
+#endif
+       status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
+    }
+    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
 }
 
 /*
@@ -264,7 +270,7 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
     int n, flags, std_prompt;
 
     if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
-       return(PAM_SYSTEM_ERR);
+       return PAM_SYSTEM_ERR;
     zero_bytes(*response, num_msg * sizeof(struct pam_response));
 
     for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
@@ -275,6 +281,10 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
            case PAM_PROMPT_ECHO_OFF:
                prompt = def_prompt;
 
+               /* Error out if the last password read was interrupted. */
+               if (gotintr)
+                   goto err;
+
                /* Is the sudo prompt standard? (If so, we'l just use PAM's) */
                std_prompt =  strncmp(def_prompt, "Password:", 9) == 0 &&
                    (def_prompt[9] == '\0' ||
@@ -322,7 +332,7 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
        }
     }
 
-    return(PAM_SUCCESS);
+    return PAM_SUCCESS;
 
 err:
     /* Zero and free allocated memory and return an error. */
@@ -336,5 +346,5 @@ err:
     zero_bytes(*response, num_msg * sizeof(struct pam_response));
     free(*response);
     *response = NULL;
-    return(gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR);
+    return gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR;
 }