Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / auth / pam.c
index 0ede540880dfe909dcaf1d858fc5b6c049255907..357781ab7c53d2fc1f84dee909ffd4d8ae4c19bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005, 2007-2011 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007-2013 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
@@ -21,7 +21,6 @@
 #include <config.h>
 
 #include <sys/types.h>
-#include <sys/param.h>
 #include <stdio.h>
 #ifdef STDC_HEADERS
 # include <stdlib.h>
 # endif
 #endif
 
+/* We don't want to translate the strings in the calls to dgt(). */
+#ifdef PAM_TEXT_DOMAIN
+# define dgt(d, t)     dgettext(d, t)
+#endif
+
 #include "sudoers.h"
 #include "sudo_auth.h"
 
 # define PAM_CONST
 #endif
 
-static int converse(int, PAM_CONST struct pam_message **,
-                   struct pam_response **, void *);
-static char *def_prompt = "Password:";
-static int getpass_error;
-
 #ifndef PAM_DATA_SILENT
 #define PAM_DATA_SILENT        0
 #endif
 
+static int converse(int, PAM_CONST struct pam_message **,
+                   struct pam_response **, void *);
+static char *def_prompt = "Password:";
+static bool sudo_pam_cred_established;
+static bool sudo_pam_authenticated;
+static int getpass_error;
 static pam_handle_t *pamh;
 
 int
@@ -97,7 +102,7 @@ sudo_pam_init(struct passwd *pw, sudo_auth *auth)
 #endif
        pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
     if (pam_status != PAM_SUCCESS) {
-       log_error(USE_ERRNO|NO_MAIL, _("unable to initialize PAM"));
+       log_warning(USE_ERRNO|NO_MAIL, N_("unable to initialize PAM"));
        debug_return_int(AUTH_FATAL);
     }
 
@@ -139,28 +144,31 @@ sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
            *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
            switch (*pam_status) {
                case PAM_SUCCESS:
+                   sudo_pam_authenticated = true;
                    debug_return_int(AUTH_SUCCESS);
                case PAM_AUTH_ERR:
-                   log_error(NO_MAIL, _("account validation failure, "
+                   log_warning(NO_MAIL, N_("account validation failure, "
                        "is your account locked?"));
                    debug_return_int(AUTH_FATAL);
                case PAM_NEW_AUTHTOK_REQD:
-                   log_error(NO_MAIL, _("Account or password is "
+                   log_warning(NO_MAIL, N_("Account or password is "
                        "expired, reset your password and try again"));
                    *pam_status = pam_chauthtok(pamh,
                        PAM_CHANGE_EXPIRED_AUTHTOK);
                    if (*pam_status == PAM_SUCCESS)
                        debug_return_int(AUTH_SUCCESS);
-                   if ((s = pam_strerror(pamh, *pam_status)))
-                       log_error(NO_MAIL, _("pam_chauthtok: %s"), s);
+                   if ((s = pam_strerror(pamh, *pam_status)) != NULL) {
+                       log_warning(NO_MAIL,
+                           N_("unable to change expired password: %s"), s);
+                   }
                    debug_return_int(AUTH_FAILURE);
                case PAM_AUTHTOK_EXPIRED:
-                   log_error(NO_MAIL,
-                       _("Password expired, contact your system administrator"));
+                   log_warning(NO_MAIL,
+                       N_("Password expired, contact your system administrator"));
                    debug_return_int(AUTH_FATAL);
                case PAM_ACCT_EXPIRED:
-                   log_error(NO_MAIL,
-                       _("Account expired or PAM config lacks an \"account\" "
+                   log_warning(NO_MAIL,
+                       N_("Account expired or PAM config lacks an \"account\" "
                        "section for sudo, contact your system administrator"));
                    debug_return_int(AUTH_FATAL);
            }
@@ -176,8 +184,8 @@ sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
        case PAM_PERM_DENIED:
            debug_return_int(AUTH_FAILURE);
        default:
-           if ((s = pam_strerror(pamh, *pam_status)))
-               log_error(NO_MAIL, _("pam_authenticate: %s"), s);
+           if ((s = pam_strerror(pamh, *pam_status)) != NULL)
+               log_warning(NO_MAIL, N_("PAM authentication error: %s"), s);
            debug_return_int(AUTH_FATAL);
     }
 }
@@ -230,7 +238,15 @@ sudo_pam_begin_session(struct passwd *pw, char **user_envp[], sudo_auth *auth)
      * this is not set and so pam_setcred() returns PAM_PERM_DENIED.
      * We can't call pam_acct_mgmt() with Linux-PAM for a similar reason.
      */
-    (void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
+    status = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+    if (status == PAM_SUCCESS) {
+       sudo_pam_cred_established = true;
+    } else if (sudo_pam_authenticated) {
+       const char *s = pam_strerror(pamh, status);
+       if (s != NULL)
+           log_warning(NO_MAIL, N_("unable to establish credentials: %s"), s);
+       goto done;
+    }
 
 #ifdef HAVE_PAM_GETENVLIST
     /*
@@ -252,13 +268,13 @@ sudo_pam_begin_session(struct passwd *pw, char **user_envp[], sudo_auth *auth)
     }
 #endif /* HAVE_PAM_GETENVLIST */
 
-#ifndef NO_PAM_SESSION
-    status = pam_open_session(pamh, 0);
-    if (status != PAM_SUCCESS) {
-       (void) pam_end(pamh, status | PAM_DATA_SILENT);
-       pamh = NULL;
+    if (def_pam_session) {
+       status = pam_open_session(pamh, 0);
+       if (status != PAM_SUCCESS) {
+           (void) pam_end(pamh, status | PAM_DATA_SILENT);
+           pamh = NULL;
+       }
     }
-#endif
 
 done:
     debug_return_int(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
@@ -277,10 +293,10 @@ sudo_pam_end_session(struct passwd *pw, sudo_auth *auth)
         * XXX - still needed now that session init is in parent?
         */
        (void) pam_set_item(pamh, PAM_USER, pw->pw_name);
-#ifndef NO_PAM_SESSION
-       (void) pam_close_session(pamh, PAM_SILENT);
-#endif
-       (void) pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
+       if (def_pam_session)
+           (void) pam_close_session(pamh, PAM_SILENT);
+       if (sudo_pam_cred_established)
+           (void) pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
        status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
        pamh = NULL;
     }
@@ -321,7 +337,7 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
                if (getpass_error)
                    goto done;
 
-               /* Is the sudo prompt standard? (If so, we'l just use PAM's) */
+               /* Is the sudo prompt standard? (If so, we'll just use PAM's) */
                std_prompt =  strncmp(def_prompt, "Password:", 9) == 0 &&
                    (def_prompt[9] == '\0' ||
                    (def_prompt[9] == ' ' && def_prompt[10] == '\0'));
@@ -329,8 +345,8 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
                /* Only override PAM prompt if it matches /^Password: ?/ */
 #if defined(PAM_TEXT_DOMAIN) && defined(HAVE_LIBINTL_H)
                if (!def_passprompt_override && (std_prompt ||
-                   (strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password: ")) &&
-                   strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password:")))))
+                   (strcmp(pm->msg, dgt(PAM_TEXT_DOMAIN, "Password: ")) &&
+                   strcmp(pm->msg, dgt(PAM_TEXT_DOMAIN, "Password:")))))
                    prompt = pm->msg;
 #else
                if (!def_passprompt_override && (std_prompt ||