/*
- * 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
#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
#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);
}
*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);
}
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);
}
}
* 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
/*
}
#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);
* 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;
}
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'));
/* 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 ||