pam_winbind: no longer use wbcUserPasswordPolicyInfo when authenticating
[kai/samba-autobuild/.git] / nsswitch / pam_winbind.c
index a2d9f3bde9e9e0ad482df6b8f22c314f1919b27a..4ae646442f8af15b368a4ea1857d778036cda09e 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "pam_winbind.h"
 
-enum pam_winbind_request_type 
+enum pam_winbind_request_type
 {
        PAM_WINBIND_AUTHENTICATE,
        PAM_WINBIND_SETCRED,
@@ -191,17 +191,17 @@ static void _pam_log_int(const pam_handle_t *pamh,
 {
        char *format2 = NULL;
        const char *service;
+       int ret;
 
        pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
 
-       format2 = (char *)malloc(strlen(MODULE_NAME)+strlen(format)+strlen(service)+5);
-       if (format2 == NULL) {
+       ret = asprintf(&format2, "%s(%s): %s", MODULE_NAME, service, format);
+       if (ret == -1) {
                /* what else todo ? */
                vsyslog(err, format, args);
                return;
        }
 
-       sprintf(format2, "%s(%s): %s", MODULE_NAME, service, format);
        vsyslog(err, format2, args);
        SAFE_FREE(format2);
 }
@@ -490,12 +490,12 @@ config_from_pam:
                else if (!strcasecmp(*v, "unknown_ok"))
                        ctrl |= WINBIND_UNKNOWN_OK_ARG;
                else if ((type == PAM_WINBIND_AUTHENTICATE
-                         || type == PAM_WINBIND_SETCRED) 
+                         || type == PAM_WINBIND_SETCRED)
                         && !strncasecmp(*v, "require_membership_of",
                                         strlen("require_membership_of")))
                        ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
-               else if ((type == PAM_WINBIND_AUTHENTICATE 
-                         || type == PAM_WINBIND_SETCRED) 
+               else if ((type == PAM_WINBIND_AUTHENTICATE
+                         || type == PAM_WINBIND_SETCRED)
                         && !strncasecmp(*v, "require-membership-of",
                                         strlen("require-membership-of")))
                        ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
@@ -540,6 +540,8 @@ static int _pam_winbind_free_context(struct pwb_context *ctx)
                tiniparser_freedict(ctx->dict);
        }
 
+       wbcCtxFree(ctx->wbc_ctx);
+
        return 0;
 }
 
@@ -551,6 +553,7 @@ static int _pam_winbind_init_context(pam_handle_t *pamh,
                                     struct pwb_context **ctx_p)
 {
        struct pwb_context *r = NULL;
+       int ctrl_code;
 
 #ifdef HAVE_GETTEXT
        textdomain_init();
@@ -567,8 +570,15 @@ static int _pam_winbind_init_context(pam_handle_t *pamh,
        r->flags = flags;
        r->argc = argc;
        r->argv = argv;
-       r->ctrl = _pam_parse(pamh, flags, argc, argv, type, &r->dict);
-       if (r->ctrl == -1) {
+       ctrl_code = _pam_parse(pamh, flags, argc, argv, type, &r->dict);
+       if (ctrl_code == -1) {
+               TALLOC_FREE(r);
+               return PAM_SYSTEM_ERR;
+       }
+       r->ctrl = ctrl_code;
+
+       r->wbc_ctx = wbcCtxCreate();
+       if (r->wbc_ctx == NULL) {
                TALLOC_FREE(r);
                return PAM_SYSTEM_ERR;
        }
@@ -600,7 +610,7 @@ static const struct ntstatus_errors {
        {"NT_STATUS_OK",
                N_("Success")},
        {"NT_STATUS_BACKUP_CONTROLLER",
-               N_("No primary Domain Controler available")},
+               N_("No primary Domain Controller available")},
        {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
                N_("No domain controllers found")},
        {"NT_STATUS_NO_LOGON_SERVERS",
@@ -657,7 +667,7 @@ static const char *_get_ntstatus_error_string(const char *nt_status_string)
 
 static int converse(const pam_handle_t *pamh,
                    int nargs,
-                   struct pam_message **message,
+                   const struct pam_message **message,
                    struct pam_response **response)
 {
        int retval;
@@ -680,7 +690,8 @@ static int _make_remark(struct pwb_context *ctx,
 {
        int retval = PAM_SUCCESS;
 
-       struct pam_message *pmsg[1], msg[1];
+       const struct pam_message *pmsg[1];
+       struct pam_message msg[1];
        struct pam_response *resp;
 
        if (ctx->flags & WINBIND_SILENT) {
@@ -765,6 +776,11 @@ static int pam_winbind_request_log(struct pwb_context *ctx,
                        return PAM_IGNORE;
                }
                return retval;
+       case PAM_AUTHTOK_ERR:
+               /* Authentication token manipulation error */
+               _pam_log(ctx, LOG_WARNING, "user `%s' authentication token change failed "
+                       "(pwd complexity/history/min_age not met?)", user);
+               return retval;
        case PAM_SUCCESS:
                /* Otherwise, the authentication looked good */
                if (strcmp(fn, "wbcLogonUser") == 0) {
@@ -828,7 +844,8 @@ static int wbc_auth_error_to_pam_error(struct pwb_context *ctx,
 #if defined(HAVE_PAM_RADIO_TYPE)
 static bool _pam_winbind_change_pwd(struct pwb_context *ctx)
 {
-       struct pam_message msg, *pmsg;
+       struct pam_message msg;
+       const struct pam_message *pmsg;
        struct pam_response *resp = NULL;
        int ret;
        bool retval = false;
@@ -987,7 +1004,6 @@ static bool _pam_send_password_expiry_message(struct pwb_context *ctx,
 
 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 *change_pwd)
@@ -995,7 +1011,7 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx,
        time_t now = time(NULL);
        time_t next_change = 0;
 
-       if (!info || !policy) {
+       if (info == NULL) {
                return;
        }
 
@@ -1027,23 +1043,6 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx,
                return;
        }
 
-       /* now check for the global password policy */
-       /* good catch from Ralf Haferkamp: an expiry of "never" is translated
-        * to -1 */
-       if ((policy->expire == (int64_t)-1) ||
-           (policy->expire == 0)) {
-               return;
-       }
-
-       next_change = info->pass_last_set_time + policy->expire;
-
-       if (_pam_send_password_expiry_message(ctx, next_change, now,
-                                             warn_pwd_expire,
-                                             already_expired,
-                                             change_pwd)) {
-               return;
-       }
-
        /* no warning sent */
 }
 
@@ -1100,7 +1099,11 @@ static bool winbind_name_to_sid_string(struct pwb_context *ctx,
                _pam_log_debug(ctx, LOG_DEBUG,
                               "no sid given, looking up: %s\n", name);
 
-               wbc_status = wbcLookupName("", name, &sid, &type);
+               wbc_status = wbcCtxLookupName(ctx->wbc_ctx,
+                                             "",
+                                             name,
+                                             &sid,
+                                             &type);
                if (!WBC_ERROR_IS_OK(wbc_status)) {
                        _pam_log(ctx, LOG_INFO,
                                 "could not lookup name: %s\n", name);
@@ -1262,7 +1265,7 @@ static void _pam_setup_krb5_env(struct pwb_context *ctx,
        }
 
        ret = pam_putenv(ctx->pamh, var);
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                _pam_log(ctx, LOG_ERR,
                         "failed to set KRB5CCNAME to %s: %s",
                         var, pam_strerror(ctx->pamh, ret));
@@ -1328,7 +1331,7 @@ static void _pam_set_data_string(struct pwb_context *ctx,
 
        ret = pam_set_data(ctx->pamh, data_name, talloc_strdup(NULL, value),
                           _pam_winbind_cleanup_func);
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                _pam_log_debug(ctx, LOG_DEBUG,
                               "Could not set data %s: %s\n",
                               data_name, pam_strerror(ctx->pamh, ret));
@@ -1656,7 +1659,7 @@ static int _pam_mkhomedir(struct pwb_context *ctx)
                }
 
                ret = _pam_create_homedir(ctx, create_dir, mode);
-               if (ret) {
+               if (ret != PAM_SUCCESS) {
                        return ret;
                }
        }
@@ -1675,23 +1678,17 @@ static int winbind_auth_request(struct pwb_context *ctx,
                                const int warn_pwd_expire,
                                struct wbcAuthErrorInfo **p_error,
                                struct wbcLogonUserInfo **p_info,
-                               struct wbcUserPasswordPolicyInfo **p_policy,
                                time_t *pwd_last_set,
                                char **user_ret)
 {
        wbcErr wbc_status;
-
        struct wbcLogonUserParams logon;
        char membership_of[1024];
        uid_t user_uid = -1;
-       uint32_t flags = WBFLAG_PAM_INFO3_TEXT |
-                        WBFLAG_PAM_GET_PWD_POLICY;
-
+       uint32_t flags = WBFLAG_PAM_INFO3_TEXT;
        struct wbcLogonUserInfo *info = NULL;
        struct wbcAuthUserInfo *user_info = NULL;
        struct wbcAuthErrorInfo *error = NULL;
-       struct wbcUserPasswordPolicyInfo *policy = NULL;
-
        int ret = PAM_AUTH_ERR;
        int i;
        const char *codes[] = {
@@ -1820,7 +1817,11 @@ static int winbind_auth_request(struct pwb_context *ctx,
                }
        }
 
-       wbc_status = wbcLogonUser(&logon, &info, &error, &policy);
+       wbc_status = wbcCtxLogonUser(ctx->wbc_ctx,
+                                    &logon,
+                                    &info,
+                                    &error,
+                                    NULL);
        ret = wbc_auth_error_to_pam_error(ctx, error, wbc_status,
                                          user, "wbcLogonUser");
        wbcFreeMemory(logon.blobs);
@@ -1838,10 +1839,6 @@ static int winbind_auth_request(struct pwb_context *ctx,
                *p_info = info;
        }
 
-       if (p_policy && policy) {
-               *p_policy = policy;
-       }
-
        if (p_error && error) {
                /* We want to process the error in the caller. */
                *p_error = error;
@@ -1856,13 +1853,13 @@ static int winbind_auth_request(struct pwb_context *ctx,
                }
        }
 
-       if ((ret == PAM_SUCCESS) && user_info && policy && info) {
+       if ((ret == PAM_SUCCESS) && user_info && 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,
+               _pam_warn_password_expiry(ctx, user_info,
                                          warn_pwd_expire,
                                          &already_expired,
                                          &change_pwd);
@@ -1870,15 +1867,15 @@ static int winbind_auth_request(struct pwb_context *ctx,
                if (already_expired == true) {
 
                        SMB_TIME_T last_set = user_info->pass_last_set_time;
+                       SMB_TIME_T must_set = user_info->pass_must_change_time;
 
                        _pam_log_debug(ctx, LOG_DEBUG,
                                       "Password has expired "
                                       "(Password was last set: %lld, "
-                                      "the policy says it should expire here "
+                                      "it must be changed here "
                                       "%lld (now it's: %ld))\n",
                                       (long long int)last_set,
-                                      (long long int)last_set +
-                                      policy->expire,
+                                      (long long int)must_set,
                                       (long)time(NULL));
 
                        return PAM_AUTHTOK_EXPIRED;
@@ -1917,9 +1914,6 @@ static int winbind_auth_request(struct pwb_context *ctx,
        if (info && !p_info) {
                wbcFreeMemory(info);
        }
-       if (policy && !p_policy) {
-               wbcFreeMemory(policy);
-       }
 
        return ret;
 }
@@ -1967,7 +1961,11 @@ static int winbind_chauthtok_request(struct pwb_context *ctx,
        params.new_password.plaintext   = newpass;
        params.flags                    = flags;
 
-       wbc_status = wbcChangeUserPasswordEx(&params, &error, &reject_reason, &policy);
+       wbc_status = wbcCtxChangeUserPasswordEx(ctx->wbc_ctx,
+                                               &params,
+                                               &error,
+                                               &reject_reason,
+                                               &policy);
        ret = wbc_auth_error_to_pam_error(ctx, error, wbc_status,
                                          user, "wbcChangeUserPasswordEx");
 
@@ -2071,7 +2069,7 @@ static int valid_user(struct pwb_context *ctx,
                return 1;
        }
 
-       wbc_status = wbcGetpwnam(user, &wb_pwd);
+       wbc_status = wbcCtxGetpwnam(ctx->wbc_ctx, user, &wb_pwd);
        wbcFreeMemory(wb_pwd);
        if (!WBC_ERROR_IS_OK(wbc_status)) {
                _pam_log(ctx, LOG_DEBUG, "valid_user: wbcGetpwnam gave %s\n",
@@ -2167,7 +2165,8 @@ static int _winbind_read_password(struct pwb_context *ctx,
         */
 
        {
-               struct pam_message msg[3], *pmsg[3];
+               struct pam_message msg[3];
+               const struct pam_message *pmsg[3];
                struct pam_response *resp;
                int i, replies;
 
@@ -2369,7 +2368,7 @@ static const char *get_member_from_config(struct pwb_context *ctx)
        const char *ret = NULL;
        ret = get_conf_item_string(ctx, "require_membership_of",
                                   WINBIND_REQUIRED_MEMBERSHIP);
-       if (ret) {
+       if (ret != NULL) {
                return ret;
        }
        return get_conf_item_string(ctx, "require-membership-of",
@@ -2401,7 +2400,7 @@ static char winbind_get_separator(struct pwb_context *ctx)
        wbcErr wbc_status;
        static struct wbcInterfaceDetails *details = NULL;
 
-       wbc_status = wbcInterfaceDetails(&details);
+       wbc_status = wbcCtxInterfaceDetails(ctx->wbc_ctx, &details);
        if (!WBC_ERROR_IS_OK(wbc_status)) {
                _pam_log(ctx, LOG_ERR,
                         "Could not retrieve winbind interface details: %s",
@@ -2449,21 +2448,25 @@ static char* winbind_upn_to_username(struct pwb_context *ctx,
        if (!name) {
                return NULL;
        }
-       if ((p = strchr(name, '@')) != NULL) {
-               *p = 0;
-               domain = p + 1;
+
+       p = strchr(name, '@');
+       if (p == NULL) {
+               TALLOC_FREE(name);
+               return NULL;
        }
+       *p = '\0';
+       domain = p + 1;
 
        /* Convert the UPN to a SID */
 
-       wbc_status = wbcLookupName(domain, name, &sid, &type);
+       wbc_status = wbcCtxLookupName(ctx->wbc_ctx, domain, name, &sid, &type);
        if (!WBC_ERROR_IS_OK(wbc_status)) {
                return NULL;
        }
 
        /* Convert the the SID back to the sAMAccountName */
 
-       wbc_status = wbcLookupSid(&sid, &domain, &name, &type);
+       wbc_status = wbcCtxLookupSid(ctx->wbc_ctx, &sid, &domain, &name, &type);
        if (!WBC_ERROR_IS_OK(wbc_status)) {
                return NULL;
        }
@@ -2475,7 +2478,7 @@ static char* winbind_upn_to_username(struct pwb_context *ctx,
 }
 
 static int _pam_delete_cred(pam_handle_t *pamh, int flags,
-                           int argc, enum pam_winbind_request_type type, 
+                           int argc, enum pam_winbind_request_type type,
                            const char **argv)
 {
        int retval = PAM_SUCCESS;
@@ -2488,7 +2491,7 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags,
        ZERO_STRUCT(logoff);
 
        retval = _pam_winbind_init_context(pamh, flags, argc, argv, type, &ctx);
-       if (retval) {
+       if (retval != PAM_SUCCESS) {
                return retval;
        }
 
@@ -2503,7 +2506,7 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags,
                struct passwd *pwd = NULL;
 
                retval = pam_get_user(pamh, &user, _("Username: "));
-               if (retval) {
+               if (retval != PAM_SUCCESS) {
                        _pam_log(ctx, LOG_ERR,
                                 "could not identify user");
                        goto out;
@@ -2568,7 +2571,7 @@ static int _pam_delete_cred(pam_handle_t *pamh, int flags,
                        goto out;
                }
 
-               wbc_status = wbcLogoffUserEx(&logoff, &error);
+               wbc_status = wbcCtxLogoffUserEx(ctx->wbc_ctx, &logoff, &error);
                retval = wbc_auth_error_to_pam_error(ctx, error, wbc_status,
                                                     user, "wbcLogoffUser");
                wbcFreeMemory(error);
@@ -2624,7 +2627,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
 
        retval = _pam_winbind_init_context(pamh, flags, argc, argv,
                                           PAM_WINBIND_AUTHENTICATE, &ctx);
-       if (retval) {
+       if (retval != PAM_SUCCESS) {
                return retval;
        }
 
@@ -2707,8 +2710,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
        /* Now use the username to look up password */
        retval = winbind_auth_request(ctx, real_username, password,
                                      member, cctype, warn_pwd_expire,
-                                     NULL, NULL, NULL,
-                                     NULL, &username_ret);
+                                     NULL, NULL, NULL, &username_ret);
 
        if (retval == PAM_NEW_AUTHTOK_REQD ||
            retval == PAM_AUTHTOK_EXPIRED) {
@@ -2776,7 +2778,7 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags,
 
        ret = _pam_winbind_init_context(pamh, flags, argc, argv,
                                        PAM_WINBIND_SETCRED, &ctx);
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                return ret;
        }
 
@@ -2830,7 +2832,7 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
 
        ret = _pam_winbind_init_context(pamh, flags, argc, argv,
                                        PAM_WINBIND_ACCT_MGMT, &ctx);
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                return ret;
        }
 
@@ -2926,7 +2928,7 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags,
 
        ret = _pam_winbind_init_context(pamh, flags, argc, argv,
                                        PAM_WINBIND_OPEN_SESSION, &ctx);
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                return ret;
        }
 
@@ -2953,7 +2955,7 @@ int pam_sm_close_session(pam_handle_t *pamh, int flags,
 
        ret = _pam_winbind_init_context(pamh, flags, argc, argv,
                                        PAM_WINBIND_CLOSE_SESSION, &ctx);
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                return ret;
        }
 
@@ -3039,7 +3041,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
        ret = _pam_winbind_init_context(pamh, flags, argc, argv,
                                        PAM_WINBIND_CHAUTHTOK, &ctx);
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                return ret;
        }
 
@@ -3054,7 +3056,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
         * First get the name of a user
         */
        ret = pam_get_user(pamh, &user, _("Username: "));
-       if (ret) {
+       if (ret != PAM_SUCCESS) {
                _pam_log(ctx, LOG_ERR,
                         "password - could not identify user");
                goto out;
@@ -3118,7 +3120,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                ret = winbind_auth_request(ctx, user, pass_old,
                                           NULL, NULL, 0,
-                                          &error, NULL, NULL,
+                                          &error, NULL,
                                           &pwdlastset_prelim, NULL);
 
                if (ret != PAM_ACCT_EXPIRED &&
@@ -3215,7 +3217,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                ret = winbind_chauthtok_request(ctx, user, pass_old,
                                                pass_new, pwdlastset_update);
-               if (ret) {
+               if (ret != PAM_SUCCESS) {
                        pass_old = pass_new = NULL;
                        goto out;
                }
@@ -3226,7 +3228,6 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                        const char *cctype = NULL;
                        int warn_pwd_expire;
                        struct wbcLogonUserInfo *info = NULL;
-                       struct wbcUserPasswordPolicyInfo *policy = NULL;
 
                        member = get_member_from_config(ctx);
                        cctype = get_krb5_cc_type_from_config(ctx);
@@ -3242,7 +3243,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                        ret = winbind_auth_request(ctx, user, pass_new,
                                                   member, cctype, 0,
-                                                  &error, &info, &policy,
+                                                  &error, &info,
                                                   NULL, &username_ret);
                        pass_old = pass_new = NULL;
 
@@ -3256,7 +3257,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
                                /* warn a user if the password is about to
                                 * expire soon */
-                               _pam_warn_password_expiry(ctx, user_info, policy,
+                               _pam_warn_password_expiry(ctx, user_info,
                                                          warn_pwd_expire,
                                                          NULL, NULL);
 
@@ -3282,7 +3283,6 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                                wbcFreeMemory(info->blobs);
                        }
                        wbcFreeMemory(info);
-                       wbcFreeMemory(policy);
 
                        goto out;
                }