X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=nsswitch%2Fpam_winbind.c;h=e59a6d8ea1600fbc2dee3732eb28293d951b35d7;hb=4031ff121d7f9a6b1dab8bd8ed54b47195f03955;hp=d049bdb1e7d538bce21ac1628be6282c0502f337;hpb=1b3a084d60cc0004f84bc56dedbe1d87cda2a8b3;p=nivanova%2Fsamba-autobuild%2F.git diff --git a/nsswitch/pam_winbind.c b/nsswitch/pam_winbind.c index d049bdb1e7d..e59a6d8ea16 100644 --- a/nsswitch/pam_winbind.c +++ b/nsswitch/pam_winbind.c @@ -154,7 +154,7 @@ static inline void textdomain_init(void); static inline void textdomain_init(void) { if (!initialized) { - bindtextdomain(MODULE_NAME, dyn_LOCALEDIR); + bindtextdomain(MODULE_NAME, LOCALEDIR); initialized = 1; } return; @@ -410,49 +410,51 @@ static int _pam_parse(const pam_handle_t *pamh, config_file = PAM_WINBIND_CONFIG_FILE; } - d = iniparser_load(config_file); + d = iniparser_load(discard_const_p(char, config_file)); if (d == NULL) { goto config_from_pam; } - if (iniparser_getboolean(d, "global:debug", false)) { + if (iniparser_getboolean(d, discard_const_p(char, "global:debug"), false)) { ctrl |= WINBIND_DEBUG_ARG; } - if (iniparser_getboolean(d, "global:debug_state", false)) { + if (iniparser_getboolean(d, discard_const_p(char, "global:debug_state"), false)) { ctrl |= WINBIND_DEBUG_STATE; } - if (iniparser_getboolean(d, "global:cached_login", false)) { + if (iniparser_getboolean(d, discard_const_p(char, "global:cached_login"), false)) { ctrl |= WINBIND_CACHED_LOGIN; } - if (iniparser_getboolean(d, "global:krb5_auth", false)) { + if (iniparser_getboolean(d, discard_const_p(char, "global:krb5_auth"), false)) { ctrl |= WINBIND_KRB5_AUTH; } - if (iniparser_getboolean(d, "global:silent", false)) { + if (iniparser_getboolean(d, discard_const_p(char, "global:silent"), false)) { ctrl |= WINBIND_SILENT; } - if (iniparser_getstr(d, "global:krb5_ccache_type") != NULL) { + if (iniparser_getstr(d, discard_const_p(char, "global:krb5_ccache_type")) != NULL) { ctrl |= WINBIND_KRB5_CCACHE_TYPE; } - if ((iniparser_getstr(d, "global:require-membership-of") != NULL) || - (iniparser_getstr(d, "global:require_membership_of") != NULL)) { + if ((iniparser_getstr(d, discard_const_p(char, "global:require-membership-of")) + != NULL) || + (iniparser_getstr(d, discard_const_p(char, "global:require_membership_of")) + != NULL)) { ctrl |= WINBIND_REQUIRED_MEMBERSHIP; } - if (iniparser_getboolean(d, "global:try_first_pass", false)) { + if (iniparser_getboolean(d, discard_const_p(char, "global:try_first_pass"), false)) { ctrl |= WINBIND_TRY_FIRST_PASS_ARG; } - if (iniparser_getint(d, "global:warn_pwd_expire", 0)) { + if (iniparser_getint(d, discard_const_p(char, "global:warn_pwd_expire"), 0)) { ctrl |= WINBIND_WARN_PWD_EXPIRE; } - if (iniparser_getboolean(d, "global:mkhomedir", false)) { + if (iniparser_getboolean(d, discard_const_p(char, "global:mkhomedir"), false)) { ctrl |= WINBIND_MKHOMEDIR; } @@ -534,7 +536,7 @@ static int _pam_winbind_init_context(pam_handle_t *pamh, textdomain_init(); #endif - r = TALLOC_ZERO_P(NULL, struct pwb_context); + r = talloc_zero(NULL, struct pwb_context); if (!r) { return PAM_BUF_ERR; } @@ -803,6 +805,43 @@ static int wbc_auth_error_to_pam_error(struct pwb_context *ctx, return pam_winbind_request_log(ctx, ret, username, fn); } +#if defined(HAVE_PAM_RADIO_TYPE) +static bool _pam_winbind_change_pwd(struct pwb_context *ctx) +{ + struct pam_message msg, *pmsg; + struct pam_response *resp = NULL; + const char *prompt; + int ret; + bool retval = false; + prompt = _("Do you want to change your password now?"); + pmsg = &msg; + msg.msg_style = PAM_RADIO_TYPE; + msg.msg = prompt; + ret = converse(ctx->pamh, 1, &pmsg, &resp); + if (resp == NULL) { + if (ret == PAM_SUCCESS) { + _pam_log(ctx, LOG_CRIT, "pam_winbind: system error!\n"); + return false; + } + } + if (ret != PAM_SUCCESS) { + return false; + } + _pam_log(ctx, LOG_CRIT, "Received [%s] reply from application.\n", resp->resp); + + if (strcasecmp(resp->resp, "yes") == 0) { + retval = true; + } + + _pam_drop_reply(resp, 1); + return retval; +} +#else +static bool _pam_winbind_change_pwd(struct pwb_context *ctx) +{ + return false; +} +#endif /** * send a password expiry message if required @@ -819,15 +858,22 @@ static bool _pam_send_password_expiry_message(struct pwb_context *ctx, time_t next_change, time_t now, int warn_pwd_expire, - bool *already_expired) + bool *already_expired, + bool *change_pwd) { int days = 0; struct tm tm_now, tm_next_change; + bool retval = false; + int ret; if (already_expired) { *already_expired = false; } + if (change_pwd) { + *change_pwd = false; + } + if (next_change <= now) { PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PASSWORD_EXPIRED"); if (already_expired) { @@ -850,15 +896,61 @@ static bool _pam_send_password_expiry_message(struct pwb_context *ctx, (tm_now.tm_yday+tm_now.tm_year*365); if (days == 0) { - _make_remark(ctx, PAM_TEXT_INFO, - _("Your password expires today")); + ret = _make_remark(ctx, PAM_TEXT_INFO, + _("Your password expires today.\n")); + + /* + * If change_pwd and already_expired is null. + * We are just sending a notification message. + * We don't expect any response in this case. + */ + + if (!change_pwd && !already_expired) { + return true; + } + + /* + * successfully sent the warning message. + * Give the user a chance to change pwd. + */ + if (ret == PAM_SUCCESS) { + if (change_pwd) { + retval = _pam_winbind_change_pwd(ctx); + if (retval) { + *change_pwd = true; + } + } + } return true; } if (days > 0 && days < warn_pwd_expire) { - _make_remark_format(ctx, PAM_TEXT_INFO, - _("Your password will expire in %d %s"), - days, (days > 1) ? _("days"):_("day")); + + ret = _make_remark_format(ctx, PAM_TEXT_INFO, + _("Your password will expire in %d %s.\n"), + days, (days > 1) ? _("days"):_("day")); + /* + * If change_pwd and already_expired is null. + * We are just sending a notification message. + * We don't expect any response in this case. + */ + + if (!change_pwd && !already_expired) { + return true; + } + + /* + * successfully sent the warning message. + * Give the user a chance to change pwd. + */ + if (ret == PAM_SUCCESS) { + if (change_pwd) { + retval = _pam_winbind_change_pwd(ctx); + if (retval) { + *change_pwd = true; + } + } + } return true; } @@ -879,7 +971,8 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, const struct wbcAuthUserInfo *info, const struct wbcUserPasswordPolicyInfo *policy, int warn_pwd_expire, - bool *already_expired) + bool *already_expired, + bool *change_pwd) { time_t now = time(NULL); time_t next_change = 0; @@ -892,6 +985,10 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, *already_expired = false; } + if (change_pwd) { + *change_pwd = false; + } + /* accounts with WBC_ACB_PWNOEXP set never receive a warning */ if (info->acct_flags & WBC_ACB_PWNOEXP) { return; @@ -907,14 +1004,16 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, if (_pam_send_password_expiry_message(ctx, next_change, now, warn_pwd_expire, - already_expired)) { + already_expired, + change_pwd)) { return; } /* now check for the global password policy */ /* good catch from Ralf Haferkamp: an expiry of "never" is translated * to -1 */ - if (policy->expire <= 0) { + if ((policy->expire == (int64_t)-1) || + (policy->expire == 0)) { return; } @@ -922,7 +1021,8 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, if (_pam_send_password_expiry_message(ctx, next_change, now, warn_pwd_expire, - already_expired)) { + already_expired, + change_pwd)) { return; } @@ -975,16 +1075,15 @@ static bool winbind_name_to_sid_string(struct pwb_context *ctx, char *sid_list_buffer, int sid_list_buffer_size) { - const char* sid_string; + char sid_string[WBC_SID_STRING_BUFLEN]; /* lookup name? */ if (IS_SID_STRING(name)) { - sid_string = name; + strlcpy(sid_string, name, sizeof(sid_string)); } else { wbcErr wbc_status; struct wbcDomainSid sid; enum wbcSidType type; - char *sid_str; _pam_log_debug(ctx, LOG_DEBUG, "no sid given, looking up: %s\n", name); @@ -996,20 +1095,13 @@ static bool winbind_name_to_sid_string(struct pwb_context *ctx, return false; } - wbc_status = wbcSidToString(&sid, &sid_str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - return false; - } - - wbcFreeMemory(sid_str); - sid_string = sid_str; + wbcSidToStringBuf(&sid, sid_string, sizeof(sid_string)); } if (!safe_append_string(sid_list_buffer, sid_string, sid_list_buffer_size)) { return false; } - return true; } @@ -1034,13 +1126,14 @@ static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx, char *current_name = NULL; const char *search_location; const char *comma; + int len; if (sid_list_buffer_size > 0) { sid_list_buffer[0] = 0; } search_location = name_list; - while ((comma = strstr(search_location, ",")) != NULL) { + while ((comma = strchr(search_location, ',')) != NULL) { current_name = strndup(search_location, comma - search_location); if (NULL == current_name) { @@ -1051,7 +1144,23 @@ static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx, current_name, sid_list_buffer, sid_list_buffer_size)) { - goto out; + /* + * If one group name failed, we must not fail + * the authentication totally, continue with + * the following group names. If user belongs to + * one of the valid groups, we must allow it + * login. -- BoYang + */ + + _pam_log(ctx, LOG_INFO, "cannot convert group %s to sid, " + "check if group %s is valid group.", current_name, + current_name); + _make_remark_format(ctx, PAM_TEXT_INFO, _("Cannot convert group %s " + "to sid, please contact your administrator to see " + "if group %s is valid."), current_name, current_name); + SAFE_FREE(current_name); + search_location = comma + 1; + continue; } SAFE_FREE(current_name); @@ -1067,7 +1176,21 @@ static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx, if (!winbind_name_to_sid_string(ctx, user, search_location, sid_list_buffer, sid_list_buffer_size)) { - goto out; + _pam_log(ctx, LOG_INFO, "cannot convert group %s to sid, " + "check if group %s is valid group.", search_location, + search_location); + _make_remark_format(ctx, PAM_TEXT_INFO, _("Cannot convert group %s " + "to sid, please contact your administrator to see " + "if group %s is valid."), search_location, search_location); + /* + * The lookup of the last name failed.. + * It results in require_member_of_sid ends with ',' + * It is malformated parameter here, overwrite the last ','. + */ + len = strlen(sid_list_buffer); + if ((len != 0) && (sid_list_buffer[len - 1] == ',')) { + sid_list_buffer[len - 1] = '\0'; + } } result = true; @@ -1089,7 +1212,7 @@ out: static void _pam_setup_krb5_env(struct pwb_context *ctx, struct wbcLogonUserInfo *info) { - char var[PATH_MAX]; + char *var = NULL; int ret; uint32_t i; const char *krb5ccname = NULL; @@ -1116,7 +1239,7 @@ static void _pam_setup_krb5_env(struct pwb_context *ctx, _pam_log_debug(ctx, LOG_DEBUG, "request returned KRB5CCNAME: %s", krb5ccname); - if (snprintf(var, sizeof(var), "KRB5CCNAME=%s", krb5ccname) == -1) { + if (asprintf(&var, "KRB5CCNAME=%s", krb5ccname) == -1) { return; } @@ -1126,6 +1249,7 @@ static void _pam_setup_krb5_env(struct pwb_context *ctx, "failed to set KRB5CCNAME to %s: %s", var, pam_strerror(ctx->pamh, ret)); } + free(var); } /** @@ -1298,12 +1422,12 @@ static void _pam_warn_krb5_failure(struct pwb_context *ctx, static bool _pam_check_remark_auth_err(struct pwb_context *ctx, const struct wbcAuthErrorInfo *e, const char *nt_status_string, - int *pam_error) + int *pam_err) { const char *ntstatus = NULL; const char *error_string = NULL; - if (!e || !pam_error) { + if (!e || !pam_err) { return false; } @@ -1317,18 +1441,18 @@ static bool _pam_check_remark_auth_err(struct pwb_context *ctx, error_string = _get_ntstatus_error_string(nt_status_string); if (error_string) { _make_remark(ctx, PAM_ERROR_MSG, error_string); - *pam_error = e->pam_error; + *pam_err = e->pam_error; return true; } if (e->display_string) { - _make_remark(ctx, PAM_ERROR_MSG, e->display_string); - *pam_error = e->pam_error; + _make_remark(ctx, PAM_ERROR_MSG, _(e->display_string)); + *pam_err = e->pam_error; return true; } _make_remark(ctx, PAM_ERROR_MSG, nt_status_string); - *pam_error = e->pam_error; + *pam_err = e->pam_error; return true; } @@ -1639,7 +1763,7 @@ static int winbind_auth_request(struct pwb_context *ctx, &logon.blobs, "krb5_cc_type", 0, - (uint8_t *)cctype, + discard_const_p(uint8_t, cctype), strlen(cctype)+1); if (!WBC_ERROR_IS_OK(wbc_status)) { goto done; @@ -1717,11 +1841,13 @@ static int winbind_auth_request(struct pwb_context *ctx, if ((ret == PAM_SUCCESS) && user_info && policy && info) { bool already_expired = false; + bool change_pwd = false; /* warn a user if the password is about to expire soon */ _pam_warn_password_expiry(ctx, user_info, policy, warn_pwd_expire, - &already_expired); + &already_expired, + &change_pwd); if (already_expired == true) { @@ -1731,15 +1857,20 @@ static int winbind_auth_request(struct pwb_context *ctx, "Password has expired " "(Password was last set: %lld, " "the policy says it should expire here " - "%lld (now it's: %lu))\n", + "%lld (now it's: %ld))\n", (long long int)last_set, (long long int)last_set + policy->expire, - time(NULL)); + (long)time(NULL)); return PAM_AUTHTOK_EXPIRED; } + if (change_pwd) { + ret = PAM_NEW_AUTHTOK_REQD; + goto done; + } + /* inform about logon type */ _pam_warn_logon_type(ctx, user, user_info->user_flags); @@ -1758,10 +1889,8 @@ static int winbind_auth_request(struct pwb_context *ctx, } done: - if (logon.blobs) { - wbcFreeMemory(logon.blobs); - } - if (info && info->blobs) { + wbcFreeMemory(logon.blobs); + if (info && info->blobs && !p_info) { wbcFreeMemory(info->blobs); } if (error && !p_error) { @@ -1857,22 +1986,22 @@ static int winbind_chauthtok_request(struct pwb_context *ctx, switch (reject_reason) { case -1: break; - case WBC_PWD_CHANGE_REJECT_OTHER: + case WBC_PWD_CHANGE_NO_ERROR: if ((min_pwd_age > 0) && (pwd_last_set + min_pwd_age > time(NULL))) { PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PWD_TOO_RECENT"); } break; - case WBC_PWD_CHANGE_REJECT_TOO_SHORT: + case WBC_PWD_CHANGE_PASSWORD_TOO_SHORT: PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PWD_TOO_SHORT"); break; - case WBC_PWD_CHANGE_REJECT_IN_HISTORY: + case WBC_PWD_CHANGE_PWD_IN_HISTORY: PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PWD_HISTORY_CONFLICT"); break; - case WBC_PWD_CHANGE_REJECT_COMPLEXITY: + case WBC_PWD_CHANGE_NOT_COMPLEX: _make_remark(ctx, PAM_ERROR_MSG, _("Password does not meet " "complexity requirements")); @@ -2281,8 +2410,9 @@ static char* winbind_upn_to_username(struct pwb_context *ctx, wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcDomainSid sid; enum wbcSidType type; - char *domain; + char *domain = NULL; char *name; + char *p; /* This cannot work when the winbind separator = @ */ @@ -2291,9 +2421,18 @@ static char* winbind_upn_to_username(struct pwb_context *ctx, return NULL; } + name = talloc_strdup(ctx, upn); + if (!name) { + return NULL; + } + if ((p = strchr(name, '@')) != NULL) { + *p = 0; + domain = p + 1; + } + /* Convert the UPN to a SID */ - wbc_status = wbcLookupName("", upn, &sid, &type); + wbc_status = wbcLookupName(domain, name, &sid, &type); if (!WBC_ERROR_IS_OK(wbc_status)) { return NULL; } @@ -2318,6 +2457,8 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags, const char *user; wbcErr wbc_status = WBC_ERR_SUCCESS; + ZERO_STRUCT(logoff); + retval = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx); if (retval) { goto out; @@ -2365,8 +2506,6 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags, wbc_flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CONTACT_TRUSTDOM; - ZERO_STRUCT(logoff); - logoff.username = user; if (ccname) { @@ -2374,7 +2513,7 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags, &logoff.blobs, "ccfilename", 0, - (uint8_t *)ccname, + discard_const_p(uint8_t, ccname), strlen(ccname)+1); if (!WBC_ERROR_IS_OK(wbc_status)) { goto out; @@ -2406,6 +2545,7 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags, user, "wbcLogoffUser"); wbcFreeMemory(error); wbcFreeMemory(logoff.blobs); + logoff.blobs = NULL; if (!WBC_ERROR_IS_OK(wbc_status)) { _pam_log(ctx, LOG_INFO, @@ -2428,7 +2568,7 @@ out: * Delete the krb5 ccname variable from the PAM environment * if it was set by winbind. */ - if (ctx->ctrl & WINBIND_KRB5_AUTH) { + if ((ctx->ctrl & WINBIND_KRB5_AUTH) && pam_getenv(pamh, "KRB5CCNAME")) { pam_putenv(pamh, "KRB5CCNAME"); } @@ -3043,8 +3183,6 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, ret = winbind_chauthtok_request(ctx, user, pass_old, pass_new, pwdlastset_update); if (ret) { - _pam_overwrite(pass_new); - _pam_overwrite(pass_old); pass_old = pass_new = NULL; goto out; } @@ -3073,8 +3211,6 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, member, cctype, 0, &error, &info, &policy, NULL, &username_ret); - _pam_overwrite(pass_new); - _pam_overwrite(pass_old); pass_old = pass_new = NULL; if (ret == PAM_SUCCESS) { @@ -3089,7 +3225,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * expire soon */ _pam_warn_password_expiry(ctx, user_info, policy, warn_pwd_expire, - NULL); + NULL, NULL); /* set some info3 info for other modules in the * stack */ @@ -3107,10 +3243,14 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, free(username_ret); } - wbcFreeMemory(info); - wbcFreeMemory(policy); } + if (info && info->blobs) { + wbcFreeMemory(info->blobs); + } + wbcFreeMemory(info); + wbcFreeMemory(policy); + goto out; } } else {