return on(ctrl, WINBIND_SILENT);
}
+static void _pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
static void _pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
{
va_list args;
return _pam_log_is_debug_enabled(ctrl);
}
+static void _pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
static void _pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
{
va_list args;
_PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_LOGONSERVER);
_PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_PROFILEPATH);
_PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD); /* Use atoi to get PAM result code */
+ _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH);
_PAM_LOG_STATE_DATA_POINTER(pamh, ctrl, PAM_WINBIND_PWD_LAST_SET);
}
ctrl |= WINBIND_DEBUG_ARG;
else if (!strcasecmp(*v, "debug_state"))
ctrl |= WINBIND_DEBUG_STATE;
+ else if (!strcasecmp(*v, "silent"))
+ ctrl |= WINBIND_SILENT;
else if (!strcasecmp(*v, "use_authtok"))
ctrl |= WINBIND_USE_AUTHTOK_ARG;
else if (!strcasecmp(*v, "use_first_pass"))
return ret;
}
+static int _make_remark_format(pam_handle_t * pamh, int flags, int type, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
static int _make_remark_format(pam_handle_t * pamh, int flags, int type, const char *format, ...)
{
int ret;
/* Fill in request and send down pipe */
init_request(request, req_type);
- if (write_sock(request, sizeof(*request), 0) == -1) {
+ if (write_sock(request, sizeof(*request), 0, 0) == -1) {
_pam_log(pamh, ctrl, LOG_ERR, "pam_winbind_request: write to socket failed!");
close_sock();
return PAM_SERVICE_ERR;
case WINBINDD_GETPWNAM:
case WINBINDD_LOOKUPNAME:
- _pam_log(pamh, ctrl, LOG_ERR, "request failed: %s, NT error was %s",
+ if (strlen(response->data.auth.nt_status_string) > 0) {
+ _pam_log(pamh, ctrl, LOG_ERR, "request failed, NT error was %s",
response->data.auth.nt_status_string);
+ } else {
+ _pam_log(pamh, ctrl, LOG_ERR, "request failed");
+ }
return PAM_USER_UNKNOWN;
default:
break;
}
return retval;
case PAM_SUCCESS:
- if (req_type == WINBINDD_PAM_AUTH) {
- /* Otherwise, the authentication looked good */
- _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' granted access", user);
- } else if (req_type == WINBINDD_PAM_CHAUTHTOK) {
- /* Otherwise, the authentication looked good */
- _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' password changed", user);
- } else {
- /* Otherwise, the authentication looked good */
- _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' OK", user);
+ /* Otherwise, the authentication looked good */
+ switch (req_type) {
+ case WINBINDD_INFO:
+ break;
+ case WINBINDD_PAM_AUTH:
+ _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' granted access", user);
+ break;
+ case WINBINDD_PAM_CHAUTHTOK:
+ _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' password changed", user);
+ break;
+ default:
+ _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' OK", user);
+ break;
}
return retval;
}
}
-static BOOL _pam_send_password_expiry_message(pam_handle_t *pamh, int ctrl, time_t next_change, time_t now)
+/**
+ * send a password expiry message if required
+ *
+ * @param pamh PAM handle
+ * @param ctrl PAM winbind options.
+ * @param next_change expected (calculated) next expiry date.
+ * @param already_expired pointer to a boolean to indicate if the password is
+ * already expired.
+ *
+ * @return boolean Returns True if message has been sent, False if not.
+ */
+
+static BOOL _pam_send_password_expiry_message(pam_handle_t *pamh,
+ int ctrl,
+ time_t next_change,
+ time_t now,
+ int warn_pwd_expire,
+ BOOL *already_expired)
{
int days = 0;
struct tm tm_now, tm_next_change;
+ if (already_expired) {
+ *already_expired = False;
+ }
+
+ if (next_change <= now) {
+ PAM_WB_REMARK_DIRECT(pamh, ctrl, "NT_STATUS_PASSWORD_EXPIRED");
+ if (already_expired) {
+ *already_expired = True;
+ }
+ return True;
+ }
+
if ((next_change < 0) ||
- (next_change < now) ||
- (next_change > now + DAYS_TO_WARN_BEFORE_PWD_EXPIRES * SECONDS_PER_DAY)) {
+ (next_change > now + warn_pwd_expire * SECONDS_PER_DAY)) {
return False;
}
return True;
}
- if (days > 0 && days < DAYS_TO_WARN_BEFORE_PWD_EXPIRES) {
+ if (days > 0 && days < warn_pwd_expire) {
_make_remark_format(pamh, ctrl, PAM_TEXT_INFO, "Your password will expire in %d %s",
days, (days > 1) ? "days":"day");
return True;
return False;
}
-static void _pam_warn_password_expires_in_future(pam_handle_t *pamh, int ctrl, struct winbindd_response *response)
+/**
+ * Send a warning if the password expires in the near future
+ *
+ * @param pamh PAM handle
+ * @param ctrl PAM winbind options.
+ * @param response The full authentication response structure.
+ * @param already_expired boolean, is the pwd already expired?
+ *
+ * @return void.
+ */
+
+static void _pam_warn_password_expiry(pam_handle_t *pamh,
+ int flags,
+ const struct winbindd_response *response,
+ int warn_pwd_expire,
+ BOOL *already_expired)
{
time_t now = time(NULL);
time_t next_change = 0;
+ if (already_expired) {
+ *already_expired = False;
+ }
+
/* accounts with ACB_PWNOEXP set never receive a warning */
if (response->data.auth.info3.acct_flags & ACB_PWNOEXP) {
return;
/* check if the info3 must change timestamp has been set */
next_change = response->data.auth.info3.pass_must_change_time;
- if (_pam_send_password_expiry_message(pamh, ctrl, next_change, now)) {
+ if (_pam_send_password_expiry_message(pamh, flags, next_change, now,
+ warn_pwd_expire,
+ already_expired)) {
return;
}
/* now check for the global password policy */
+ /* good catch from Ralf Haferkamp: an expiry of "never" is translated
+ * to -1 */
if (response->data.auth.policy.expire <= 0) {
return;
}
next_change = response->data.auth.info3.pass_last_set_time +
response->data.auth.policy.expire;
- if (_pam_send_password_expiry_message(pamh, ctrl, next_change, now)) {
+ if (_pam_send_password_expiry_message(pamh, flags, next_change, now,
+ warn_pwd_expire,
+ already_expired)) {
return;
}
return result;
}
+/**
+ * put krb5ccname variable into environment
+ *
+ * @param pamh PAM handle
+ * @param ctrl PAM winbind options.
+ * @param krb5ccname env variable retrieved from winbindd.
+ *
+ * @return void.
+ */
+
+static void _pam_setup_krb5_env(pam_handle_t *pamh, int ctrl, const char *krb5ccname)
+{
+ char var[PATH_MAX];
+ int ret;
+
+ if (off(ctrl, WINBIND_KRB5_AUTH)) {
+ return;
+ }
+
+ if (!krb5ccname || (strlen(krb5ccname) == 0)) {
+ return;
+ }
+
+ _pam_log_debug(pamh, ctrl, LOG_DEBUG, "request returned KRB5CCNAME: %s", krb5ccname);
+
+ if (snprintf(var, sizeof(var), "KRB5CCNAME=%s", krb5ccname) == -1) {
+ return;
+ }
+
+ ret = pam_putenv(pamh, var);
+ if (ret) {
+ _pam_log(pamh, ctrl, LOG_ERR, "failed to set KRB5CCNAME to %s: %s",
+ var, pam_strerror(pamh, ret));
+ }
+}
+
/**
* Set string into the PAM stack.
*
pam_set_data(pamh, PAM_WINBIND_PROFILEPATH, NULL, NULL);
}
+/**
+ * Send PAM_ERROR_MSG for cached or grace logons.
+ *
+ * @param pamh PAM handle
+ * @param ctrl PAM winbind options.
+ * @param username User in PAM request.
+ * @param info3_user_flgs Info3 flags containing logon type bits.
+ *
+ * @return void.
+ */
+
+static void _pam_warn_logon_type(pam_handle_t *pamh, int ctrl, const char *username, uint32 info3_user_flgs)
+{
+ /* inform about logon type */
+ if (PAM_WB_GRACE_LOGON(info3_user_flgs)) {
+
+ _make_remark(pamh, ctrl, PAM_ERROR_MSG,
+ "Grace login. Please change your password as soon you're online again");
+ _pam_log_debug(pamh, ctrl, LOG_DEBUG,
+ "User %s logged on using grace logon\n", username);
+
+ } else if (PAM_WB_CACHED_LOGON(info3_user_flgs)) {
+
+ _make_remark(pamh, ctrl, PAM_ERROR_MSG,
+ "Domain Controller unreachable, using cached credentials instead. Network resources may be unavailable");
+ _pam_log_debug(pamh, ctrl, LOG_DEBUG,
+ "User %s logged on using cached credentials\n", username);
+ }
+}
+
+/**
+ * Send PAM_ERROR_MSG for krb5 errors.
+ *
+ * @param pamh PAM handle
+ * @param ctrl PAM winbind options.
+ * @param username User in PAM request.
+ * @param info3_user_flgs Info3 flags containing logon type bits.
+ *
+ * @return void.
+ */
+
+static void _pam_warn_krb5_failure(pam_handle_t *pamh, int ctrl, const char *username, uint32 info3_user_flgs)
+{
+ if (PAM_WB_KRB5_CLOCK_SKEW(info3_user_flgs)) {
+ _make_remark(pamh, ctrl, PAM_ERROR_MSG,
+ "Failed to establish your Kerberos Ticket cache "
+ "due time differences\n"
+ "with the domain controller. "
+ "Please verify the system time.\n");
+ _pam_log_debug(pamh, ctrl, LOG_DEBUG,
+ "User %s: Clock skew when getting Krb5 TGT\n", username);
+ }
+}
+
/**
* Compose Password Restriction String for a PAM_ERROR_MSG conversation.
*
const char *pass,
const char *member,
const char *cctype,
+ const int warn_pwd_expire,
struct winbindd_response *p_response,
time_t *pwd_last_set,
char **user_ret)
struct winbindd_request request;
struct winbindd_response response;
int ret;
+ BOOL already_expired = False;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
request.flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_CONTACT_TRUSTDOM;
- if (ctrl & WINBIND_KRB5_AUTH) {
-
+ if (ctrl & (WINBIND_KRB5_AUTH|WINBIND_CACHED_LOGIN)) {
struct passwd *pwd = NULL;
- _pam_log_debug(pamh, ctrl, LOG_DEBUG, "enabling krb5 login flag\n");
-
- request.flags |= WBFLAG_PAM_KRB5 | WBFLAG_PAM_FALLBACK_AFTER_KRB5;
-
pwd = getpwnam(user);
if (pwd == NULL) {
return PAM_USER_UNKNOWN;
request.data.auth.uid = pwd->pw_uid;
}
+ if (ctrl & WINBIND_KRB5_AUTH) {
+
+ _pam_log_debug(pamh, ctrl, LOG_DEBUG, "enabling krb5 login flag\n");
+
+ request.flags |= WBFLAG_PAM_KRB5 | WBFLAG_PAM_FALLBACK_AFTER_KRB5;
+ }
+
if (ctrl & WINBIND_CACHED_LOGIN) {
_pam_log_debug(pamh, ctrl, LOG_DEBUG, "enabling cached login flag\n");
request.flags |= WBFLAG_PAM_CACHED_LOGIN;
*pwd_last_set = response.data.auth.info3.pass_last_set_time;
}
- if ((ctrl & WINBIND_KRB5_AUTH) &&
- response.data.auth.krb5ccname[0] != '\0') {
-
- char var[PATH_MAX];
-
- _pam_log_debug(pamh, ctrl, LOG_DEBUG, "request returned KRB5CCNAME: %s",
- response.data.auth.krb5ccname);
-
- snprintf(var, sizeof(var), "KRB5CCNAME=%s", response.data.auth.krb5ccname);
-
- ret = pam_putenv(pamh, var);
- if (ret != PAM_SUCCESS) {
- _pam_log(pamh, ctrl, LOG_ERR, "failed to set KRB5CCNAME to %s", var);
- return ret;
- }
- }
-
if (p_response) {
/* We want to process the response in the caller. */
*p_response = response;
PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT");
PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_NO_LOGON_SERVERS");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_WRONG_PASSWORD");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_ACCESS_DENIED");
}
- /* handle the case where the auth was ok, but the password must expire right now */
- /* good catch from Ralf Haferkamp: an expiry of "never" is translated to -1 */
- if ( ! (response.data.auth.info3.acct_flags & ACB_PWNOEXP) &&
- ! (PAM_WB_GRACE_LOGON(response.data.auth.info3.user_flgs)) &&
- (response.data.auth.policy.expire > 0) &&
- (response.data.auth.info3.pass_last_set_time + response.data.auth.policy.expire < time(NULL))) {
-
- ret = PAM_AUTHTOK_EXPIRED;
-
- _pam_log_debug(pamh, ctrl, LOG_DEBUG,"Password has expired (Password was last set: %d, "
- "the policy says it should expire here %d (now it's: %d)\n",
- response.data.auth.info3.pass_last_set_time,
- response.data.auth.info3.pass_last_set_time + response.data.auth.policy.expire,
- time(NULL));
-
- PAM_WB_REMARK_DIRECT_RET(pamh, ctrl, "NT_STATUS_PASSWORD_EXPIRED");
-
- }
-
- /* warn a user if the password is about to expire soon */
- _pam_warn_password_expires_in_future(pamh, ctrl, &response);
+ if (ret == PAM_SUCCESS) {
- /* inform about logon type */
- if (PAM_WB_GRACE_LOGON(response.data.auth.info3.user_flgs)) {
+ /* warn a user if the password is about to expire soon */
+ _pam_warn_password_expiry(pamh, ctrl, &response,
+ warn_pwd_expire,
+ &already_expired);
+
+ if (already_expired == True) {
+ _pam_log_debug(pamh, ctrl, LOG_DEBUG, "Password has expired "
+ "(Password was last set: %lld, the policy says "
+ "it should expire here %lld (now it's: %lu))\n",
+ response.data.auth.info3.pass_last_set_time,
+ response.data.auth.info3.pass_last_set_time +
+ response.data.auth.policy.expire,
+ time(NULL));
+
+ return PAM_AUTHTOK_EXPIRED;
+ }
- _make_remark(pamh, ctrl, PAM_ERROR_MSG,
- "Grace login. Please change your password as soon you're online again");
- _pam_log_debug(pamh, ctrl, LOG_DEBUG,
- "User %s logged on using grace logon\n", user);
+ /* inform about logon type */
+ _pam_warn_logon_type(pamh, ctrl, user, response.data.auth.info3.user_flgs);
- } else if (PAM_WB_CACHED_LOGON(response.data.auth.info3.user_flgs)) {
+ /* inform about krb5 failures */
+ _pam_warn_krb5_failure(pamh, ctrl, user, response.data.auth.info3.user_flgs);
- _make_remark(pamh, ctrl, PAM_ERROR_MSG,
- "Logging on using cached account. Network resources can be unavailable");
- _pam_log_debug(pamh, ctrl, LOG_DEBUG,
- "User %s logged on using cached account\n", user);
- }
+ /* set some info3 info for other modules in the stack */
+ _pam_set_data_info3(pamh, ctrl, &response);
- /* set some info3 info for other modules in the stack */
- _pam_set_data_info3(pamh, ctrl, &response);
+ /* put krb5ccname into env */
+ _pam_setup_krb5_env(pamh, ctrl, response.data.auth.krb5ccname);
- /* If winbindd returned a username, return the pointer to it here. */
- if (user_ret && response.extra_data.data) {
- /* We have to trust it's a null terminated string. */
- *user_ret = (char *)response.extra_data.data;
+ /* If winbindd returned a username, return the pointer to it here. */
+ if (user_ret && response.extra_data.data) {
+ /* We have to trust it's a null terminated string. */
+ *user_ret = (char *)response.extra_data.data;
+ }
}
return ret;
return parm_opt;
}
+int get_config_item_int(const pam_handle_t *pamh,
+ int argc,
+ const char **argv,
+ int ctrl,
+ dictionary *d,
+ const char *item)
+{
+ int parm_opt = -1, i = 0;
+ char *key = NULL;
+
+ /* let the pam opt take precedence over the pam_winbind.conf option */
+ for (i = 0; i < argc; i++) {
+
+ if ((strncmp(argv[i], item, strlen(item)) == 0)) {
+ char *p;
+
+ if ( (p = strchr( argv[i], '=' )) == NULL) {
+ _pam_log(pamh, ctrl, LOG_INFO,
+ "no \"=\" delimiter for \"%s\" found\n",
+ item);
+ goto out;
+ }
+ parm_opt = atoi(p + 1);
+ _pam_log_debug(pamh, ctrl, LOG_INFO,
+ "PAM config: %s '%d'\n",
+ item, parm_opt);
+ return parm_opt;
+ }
+ }
+
+ if (d != NULL) {
+ if (!asprintf(&key, "global:%s", item)) {
+ goto out;
+ }
+
+ parm_opt = iniparser_getint(d, key, -1);
+ SAFE_FREE(key);
+
+ _pam_log_debug(pamh, ctrl, LOG_INFO,
+ "CONFIG file: %s '%d'\n",
+ item, parm_opt);
+ }
+out:
+ return parm_opt;
+}
+
const char *get_krb5_cc_type_from_config(const pam_handle_t *pamh, int argc, const char **argv, int ctrl, dictionary *d)
{
return get_conf_item_string(pamh, argc, argv, ctrl, d, "krb5_ccache_type", WINBIND_KRB5_CCACHE_TYPE);
return get_conf_item_string(pamh, argc, argv, ctrl, d, "require-membership-of", WINBIND_REQUIRED_MEMBERSHIP);
}
+int get_warn_pwd_expire_from_config(const pam_handle_t *pamh,
+ int argc,
+ const char **argv,
+ int ctrl,
+ dictionary *d)
+{
+ int ret;
+ ret = get_config_item_int(pamh, argc, argv, ctrl, d,
+ "warn_pwd_expire");
+ /* no or broken setting */
+ if (ret <= 0) {
+ return DEFAULT_DAYS_TO_WARN_BEFORE_PWD_EXPIRES;
+ }
+ return ret;
+}
+
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
int argc, const char **argv)
const char *password;
const char *member = NULL;
const char *cctype = NULL;
+ int warn_pwd_expire;
int retval = PAM_AUTH_ERR;
dictionary *d = NULL;
char *username_ret = NULL;
char *new_authtok_required = NULL;
+ char *real_username = NULL;
/* parse arguments */
int ctrl = _pam_parse(pamh, flags, argc, argv, &d);
goto out;
}
+#if defined(AIX)
+ /* Decode the user name since AIX does not support logn user
+ names by default. The name is encoded as _#uid. */
+
+ if ( username[0] == '_' ) {
+ uid_t id = atoi( &username[1] );
+ struct passwd *pw = NULL;
+
+ if ( (id!=0) && ((pw = getpwuid( id )) != NULL) ) {
+ real_username = strdup( pw->pw_name );
+ }
+ }
+#endif
+
+ if ( !real_username ) {
+ /* Just making a copy of the username we got from PAM */
+ if ( (real_username = strdup( username )) == NULL ) {
+ _pam_log_debug(pamh, ctrl, LOG_DEBUG,
+ "memory allocation failure when copying username");
+ retval = PAM_SERVICE_ERR;
+ goto out;
+ }
+ }
+
retval = _winbind_read_password(pamh, ctrl, NULL,
"Password: ", NULL,
&password);
#ifdef DEBUG_PASSWORD
_pam_log_debug(pamh, ctrl, LOG_INFO, "Verify user '%s' with password '%s'",
- username, password);
+ real_username, password);
#else
- _pam_log_debug(pamh, ctrl, LOG_INFO, "Verify user '%s'", username);
+ _pam_log_debug(pamh, ctrl, LOG_INFO, "Verify user '%s'", real_username);
#endif
member = get_member_from_config(pamh, argc, argv, ctrl, d);
cctype = get_krb5_cc_type_from_config(pamh, argc, argv, ctrl, d);
+ warn_pwd_expire = get_warn_pwd_expire_from_config(pamh, argc, argv,
+ ctrl, d);
+
/* Now use the username to look up password */
retval = winbind_auth_request(pamh, ctrl, username, password, member,
- cctype, NULL, NULL, &username_ret);
+ cctype, warn_pwd_expire, NULL, NULL,
+ &username_ret);
if (retval == PAM_NEW_AUTHTOK_REQD ||
retval == PAM_AUTHTOK_EXPIRED) {
+ char *new_authtok_required_during_auth = NULL;
+
if (!asprintf(&new_authtok_required, "%d", retval)) {
retval = PAM_BUF_ERR;
goto out;
pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, new_authtok_required, _pam_winbind_cleanup_func);
retval = PAM_SUCCESS;
+
+ if (!asprintf(&new_authtok_required_during_auth, "%d", True)) {
+ retval = PAM_BUF_ERR;
+ goto out;
+ }
+
+ pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
+ new_authtok_required_during_auth, _pam_winbind_cleanup_func);
+
goto out;
}
free(username_ret);
}
+ if ( real_username ) {
+ free( real_username );
+ }
+
if (d) {
iniparser_freedict(d);
}
return retval;
}
+/**
+ * evaluate whether we need to re-authenticate with kerberos after a password change
+ *
+ * @param pamh PAM handle
+ * @param ctrl PAM winbind options.
+ * @param user The username
+ *
+ * @return boolean Returns True if required, False if not.
+ */
+
+static BOOL _pam_require_krb5_auth_after_chauthtok(pam_handle_t *pamh, int ctrl, const char *user)
+{
+
+ /* Make sure that we only do this if
+ * a) the chauthtok got initiated during a logon attempt (authenticate->acct_mgmt->chauthtok)
+ * b) any later password change via the "passwd" command if done by the user itself
+ */
+
+ char *new_authtok_reqd_during_auth = NULL;
+ struct passwd *pwd = NULL;
+
+ if (!(ctrl & WINBIND_KRB5_AUTH)) {
+ return False;
+ }
+
+ _pam_get_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, &new_authtok_reqd_during_auth);
+ pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, NULL, NULL);
+
+ if (new_authtok_reqd_during_auth) {
+ return True;
+ }
+
+ pwd = getpwnam(user);
+ if (!pwd) {
+ return False;
+ }
+
+ if (getuid() == pwd->pw_uid) {
+ return True;
+ }
+
+ return False;
+}
PAM_EXTERN
int retry = 0;
dictionary *d = NULL;
+ char *username_ret = NULL;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(response);
ctrl = _pam_parse(pamh, flags, argc, argv, &d);
if (ctrl == -1) {
*/
if (flags & PAM_PRELIM_CHECK) {
- struct winbindd_response response;
time_t pwdlastset_prelim = 0;
/* instruct user what is happening */
goto out;
}
- /* We don't need krb5 env set for password change test. */
- ctrl &= ~WINBIND_KRB5_AUTH;
-
/* verify that this is the password for this user */
ret = winbind_auth_request(pamh, ctrl, user, pass_old,
- NULL, NULL, &response, &pwdlastset_prelim, NULL);
+ NULL, NULL, 0, &response,
+ &pwdlastset_prelim, NULL);
if (ret != PAM_ACCT_EXPIRED &&
ret != PAM_AUTHTOK_EXPIRED &&
ret != PAM_NEW_AUTHTOK_REQD &&
ret != PAM_SUCCESS) {
pass_old = NULL;
- if (d) {
- iniparser_freedict(d);
- }
- /* Deal with offline errors. */
- PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl,
- response,
- "NT_STATUS_NO_LOGON_SERVERS");
- PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl,
- response,
- "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
- PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl,
- response,
- "NT_STATUS_ACCESS_DENIED");
- return ret;
+ goto out;
}
pam_set_data(pamh, PAM_WINBIND_PWD_LAST_SET, (void *)pwdlastset_prelim, NULL);
goto out;
}
- /* just in case we need krb5 creds after a password change over msrpc */
-
- if (ctrl & WINBIND_KRB5_AUTH) {
- struct winbindd_response response;
+ if (_pam_require_krb5_auth_after_chauthtok(pamh, ctrl, user)) {
const char *member = get_member_from_config(pamh, argc, argv, ctrl, d);
const char *cctype = get_krb5_cc_type_from_config(pamh, argc, argv, ctrl, d);
+ const int warn_pwd_expire =
+ get_warn_pwd_expire_from_config(pamh, argc, argv, ctrl,
+ d);
ret = winbind_auth_request(pamh, ctrl, user, pass_new,
- member, cctype, &response, NULL, NULL);
+ member, cctype, 0, &response,
+ NULL, &username_ret);
_pam_overwrite(pass_new);
_pam_overwrite(pass_old);
pass_old = pass_new = NULL;
- if (d) {
- iniparser_freedict(d);
+
+ if (ret == PAM_SUCCESS) {
+
+ /* warn a user if the password is about to expire soon */
+ _pam_warn_password_expiry(pamh, ctrl, &response,
+ warn_pwd_expire , NULL);
+
+ /* set some info3 info for other modules in the stack */
+ _pam_set_data_info3(pamh, ctrl, &response);
+
+ /* put krb5ccname into env */
+ _pam_setup_krb5_env(pamh, ctrl, response.data.auth.krb5ccname);
+
+ if (username_ret) {
+ pam_set_item (pamh, PAM_USER, username_ret);
+ _pam_log_debug(pamh, ctrl, LOG_INFO, "Returned user was '%s'", username_ret);
+ free(username_ret);
+ }
}
- /* Deal with offline errors. */
- PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl,
- response,
- "NT_STATUS_NO_LOGON_SERVERS");
- PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl,
- response,
- "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
- PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl,
- response,
- "NT_STATUS_ACCESS_DENIED");
- return ret;
+
+ goto out;
}
} else {
ret = PAM_SERVICE_ERR;
iniparser_freedict(d);
}
+ /* Deal with offline errors. */
+ PAM_WB_REMARK_CHECK_RESPONSE(pamh, ctrl, response, "NT_STATUS_NO_LOGON_SERVERS");
+ PAM_WB_REMARK_CHECK_RESPONSE(pamh, ctrl, response, "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
+ PAM_WB_REMARK_CHECK_RESPONSE(pamh, ctrl, response, "NT_STATUS_ACCESS_DENIED");
+
_PAM_LOG_FUNCTION_LEAVE("pam_sm_chauthtok", pamh, ctrl, ret);
return ret;