libwbclient: add wbcChangeUserPassword and wbcChangeUserPasswordEx.
authorGünther Deschner <gd@samba.org>
Fri, 15 Aug 2008 00:00:46 +0000 (02:00 +0200)
committerGünther Deschner <gd@samba.org>
Fri, 29 Aug 2008 15:34:11 +0000 (17:34 +0200)
Guenther
(This used to be commit 62e7b4aa32051bce34c890cb41270e5fe31111ca)

source3/nsswitch/libwbclient/wbc_pam.c
source3/nsswitch/libwbclient/wbclient.c
source3/nsswitch/libwbclient/wbclient.h

index 293f71c34796e8640398dd9ca22e3138279338ea..20b42b6efb3a7e75baa9350ee0db3659ee6153ae 100644 (file)
@@ -236,6 +236,30 @@ done:
        return wbc_status;
 }
 
+static wbcErr wbc_create_password_policy_info(TALLOC_CTX *mem_ctx,
+                                             const struct winbindd_response *resp,
+                                             struct wbcUserPasswordPolicyInfo **_i)
+{
+       wbcErr wbc_status = WBC_ERR_SUCCESS;
+       struct wbcUserPasswordPolicyInfo *i;
+
+       i = talloc(mem_ctx, struct wbcUserPasswordPolicyInfo);
+       BAIL_ON_PTR_ERROR(i, wbc_status);
+
+       i->min_passwordage      = resp->data.auth.policy.min_passwordage;
+       i->min_length_password  = resp->data.auth.policy.min_length_password;
+       i->password_history     = resp->data.auth.policy.password_history;
+       i->password_properties  = resp->data.auth.policy.password_properties;
+       i->expire               = resp->data.auth.policy.expire;
+
+       *_i = i;
+       i = NULL;
+
+done:
+       talloc_free(i);
+       return wbc_status;
+}
+
 /** @brief Authenticate with more detailed information
  *
  * @param params       Input parameters, WBC_AUTH_USER_LEVEL_HASH
@@ -523,3 +547,250 @@ wbcErr wbcLogoffUser(const char *username,
  done:
        return wbc_status;
 }
+
+/** @brief Change a password for a user with more detailed information upon
+ *        failure
+ * @param params                Input parameters
+ * @param error                 User output details on WBC_ERR_PWD_CHANGE_FAILED
+ * @param reject_reason         New password reject reason on WBC_ERR_PWD_CHANGE_FAILED
+ * @param policy                Password policy output details on WBC_ERR_PWD_CHANGE_FAILED
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
+                              struct wbcAuthErrorInfo **error,
+                              enum wbcPasswordChangeRejectReason *reject_reason,
+                              struct wbcUserPasswordPolicyInfo **policy)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+       int cmd = 0;
+
+       /* validate input */
+
+       if (!params->account_name) {
+               wbc_status = WBC_ERR_INVALID_PARAM;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+
+       if (error) {
+               *error = NULL;
+       }
+
+       if (policy) {
+               *policy = NULL;
+       }
+
+       if (reject_reason) {
+               *reject_reason = -1;
+       }
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       switch (params->level) {
+       case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
+               cmd = WINBINDD_PAM_CHAUTHTOK;
+
+               if (!params->account_name) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               strncpy(request.data.chauthtok.user, params->account_name,
+                       sizeof(request.data.chauthtok.user) - 1);
+
+               if (params->old_password.plaintext) {
+                       strncpy(request.data.chauthtok.oldpass,
+                               params->old_password.plaintext,
+                               sizeof(request.data.chauthtok.oldpass) - 1);
+               }
+
+               if (params->new_password.plaintext) {
+                       strncpy(request.data.chauthtok.newpass,
+                               params->new_password.plaintext,
+                               sizeof(request.data.chauthtok.newpass) - 1);
+               }
+               break;
+
+       case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
+               cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
+
+               if (!params->account_name || !params->domain_name) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->old_password.response.old_lm_hash_enc_length &&
+                   !params->old_password.response.old_lm_hash_enc_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->old_password.response.old_lm_hash_enc_length == 0 &&
+                   params->old_password.response.old_lm_hash_enc_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->old_password.response.old_nt_hash_enc_length &&
+                   !params->old_password.response.old_nt_hash_enc_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->old_password.response.old_nt_hash_enc_length == 0 &&
+                   params->old_password.response.old_nt_hash_enc_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->new_password.response.lm_length &&
+                   !params->new_password.response.lm_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->new_password.response.lm_length == 0 &&
+                   params->new_password.response.lm_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->new_password.response.nt_length &&
+                   !params->new_password.response.nt_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               if (params->new_password.response.nt_length == 0 &&
+                   params->new_password.response.nt_data) {
+                       wbc_status = WBC_ERR_INVALID_PARAM;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               strncpy(request.data.chng_pswd_auth_crap.user,
+                       params->account_name,
+                       sizeof(request.data.chng_pswd_auth_crap.user) - 1);
+
+               strncpy(request.data.chng_pswd_auth_crap.domain,
+                       params->domain_name,
+                       sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
+
+               if (params->new_password.response.nt_data) {
+                       memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
+                              params->new_password.response.nt_data,
+                              request.data.chng_pswd_auth_crap.new_nt_pswd_len);
+                       request.data.chng_pswd_auth_crap.new_nt_pswd_len =
+                               params->new_password.response.nt_length;
+               }
+
+               if (params->new_password.response.lm_data) {
+                       memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
+                              params->new_password.response.lm_data,
+                              request.data.chng_pswd_auth_crap.new_lm_pswd_len);
+                       request.data.chng_pswd_auth_crap.new_lm_pswd_len =
+                               params->new_password.response.lm_length;
+               }
+
+               if (params->old_password.response.old_nt_hash_enc_data) {
+                       memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
+                              params->old_password.response.old_nt_hash_enc_data,
+                              request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
+                       request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
+                               params->old_password.response.old_nt_hash_enc_length;
+               }
+
+               if (params->old_password.response.old_lm_hash_enc_data) {
+                       memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
+                              params->old_password.response.old_lm_hash_enc_data,
+                              request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
+                       request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
+                               params->old_password.response.old_lm_hash_enc_length;
+               }
+
+               break;
+       default:
+               wbc_status = WBC_ERR_INVALID_PARAM;
+               BAIL_ON_WBC_ERROR(wbc_status);
+               break;
+       }
+
+       if (cmd == 0) {
+               wbc_status = WBC_ERR_INVALID_PARAM;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+
+       /* Send request */
+
+       wbc_status = wbcRequestResponse(cmd,
+                                       &request,
+                                       &response);
+       if (WBC_ERROR_IS_OK(wbc_status)) {
+               goto done;
+       }
+
+       /* Take the response above and return it to the caller */
+
+       if (response.data.auth.nt_status != 0) {
+               if (error) {
+                       wbc_status = wbc_create_error_info(NULL,
+                                                          &response,
+                                                          error);
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+       }
+
+       if (policy) {
+               wbc_status = wbc_create_password_policy_info(NULL,
+                                                            &response,
+                                                            policy);
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+
+       if (reject_reason) {
+               *reject_reason = response.data.auth.reject_reason;
+       }
+
+       wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
+       BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+       return wbc_status;
+}
+
+/** @brief Change a password for a user
+ *
+ * @param username             Name of user to authenticate
+ * @param old_password         Old clear text password of user
+ * @param new_password         New clear text password of user
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcChangeUserPassword(const char *username,
+                            const char *old_password,
+                            const char *new_password)
+{
+       wbcErr wbc_status = WBC_ERR_SUCCESS;
+       struct wbcChangePasswordParams params;
+
+       ZERO_STRUCT(params);
+
+       params.account_name             = username;
+       params.level                    = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
+       params.old_password.plaintext   = old_password;
+       params.new_password.plaintext   = new_password;
+
+       wbc_status = wbcChangeUserPasswordEx(&params,
+                                            NULL,
+                                            NULL,
+                                            NULL);
+       BAIL_ON_WBC_ERROR(wbc_status);
+
+done:
+       return wbc_status;
+}
index 82decc2f780e73fccd9616b27f1fe2f4b5776eba..bdde562a93f70402e5520d53dcb2860bc798e834 100644 (file)
@@ -116,6 +116,8 @@ const char *wbcErrorString(wbcErr error)
                return "WBC_ERR_UNKNOWN_GROUP";
        case WBC_ERR_AUTH_ERROR:
                return "WBC_ERR_AUTH_ERROR";
+       case WBC_ERR_PWD_CHANGE_FAILED:
+               return "WBC_ERR_PWD_CHANGE_FAILED";
        }
 
        return "unknown wbcErr value";
index 2fefe0c07292bb2a0437838c0e0005c5c1bacbaa..cae3feec5bfa5eee2079cd2021df3b09cd18103e 100644 (file)
@@ -44,7 +44,8 @@ enum _wbcErrType {
        WBC_ERR_NSS_ERROR,            /**< NSS_STATUS error **/
        WBC_ERR_AUTH_ERROR,        /**< Authentication failed **/
        WBC_ERR_UNKNOWN_USER,      /**< User account cannot be found */
-       WBC_ERR_UNKNOWN_GROUP      /**< Group account cannot be found */
+       WBC_ERR_UNKNOWN_GROUP,     /**< Group account cannot be found */
+       WBC_ERR_PWD_CHANGE_FAILED  /**< Password Change has failed */
 };
 
 typedef enum _wbcErrType wbcErr;
@@ -204,6 +205,41 @@ struct wbcAuthUserParams {
        } password;
 };
 
+/**
+ * @brief ChangePassword Parameters
+ **/
+
+struct wbcChangePasswordParams {
+       const char *account_name;
+       const char *domain_name;
+
+       uint32_t flags;
+
+       enum wbcChangePasswordLevel {
+               WBC_CHANGE_PASSWORD_LEVEL_PLAIN = 1,
+               WBC_CHANGE_PASSWORD_LEVEL_RESPONSE = 2
+       } level;
+
+       union {
+               const char *plaintext;
+               struct {
+                       uint32_t old_nt_hash_enc_length;
+                       uint8_t *old_nt_hash_enc_data;
+                       uint32_t old_lm_hash_enc_length;
+                       uint8_t *old_lm_hash_enc_data;
+               } response;
+       } old_password;
+       union {
+               const char *plaintext;
+               struct {
+                       uint32_t nt_length;
+                       uint8_t *nt_data;
+                       uint32_t lm_length;
+                       uint8_t *lm_data;
+               } response;
+       } new_password;
+};
+
 /* wbcAuthUserParams->parameter_control */
 
 #define WBC_MSV1_0_CLEARTEXT_PASSWORD_ALLOWED          0x00000002
@@ -304,6 +340,38 @@ struct wbcAuthErrorInfo {
        char *display_string;
 };
 
+/**
+ * @brief User Password Policy Information
+ **/
+
+/* wbcUserPasswordPolicyInfo->password_properties */
+
+#define WBC_DOMAIN_PASSWORD_COMPLEX            0x00000001
+#define WBC_DOMAIN_PASSWORD_NO_ANON_CHANGE     0x00000002
+#define WBC_DOMAIN_PASSWORD_NO_CLEAR_CHANGE    0x00000004
+#define WBC_DOMAIN_PASSWORD_LOCKOUT_ADMINS     0x00000008
+#define WBC_DOMAIN_PASSWORD_STORE_CLEARTEXT    0x00000010
+#define WBC_DOMAIN_REFUSE_PASSWORD_CHANGE      0x00000020
+
+struct wbcUserPasswordPolicyInfo {
+       uint32_t min_length_password;
+       uint32_t password_history;
+       uint32_t password_properties;
+       uint64_t expire;
+       uint64_t min_passwordage;
+};
+
+/**
+ * @brief Change Password Reject Reason
+ **/
+
+enum wbcPasswordChangeRejectReason {
+       WBC_PWD_CHANGE_REJECT_OTHER=0,
+       WBC_PWD_CHANGE_REJECT_TOO_SHORT=1,
+       WBC_PWD_CHANGE_REJECT_IN_HISTORY=2,
+       WBC_PWD_CHANGE_REJECT_COMPLEXITY=5
+};
+
 /*
  * DomainControllerInfo struct
  */
@@ -478,6 +546,14 @@ wbcErr wbcLogoffUser(const char *username,
                     uid_t uid,
                     const char *ccfilename);
 
+wbcErr wbcChangeUserPassword(const char *username,
+                            const char *old_password,
+                            const char *new_password);
+
+wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
+                              struct wbcAuthErrorInfo **error,
+                              enum wbcPasswordChangeRejectReason *reject_reason,
+                              struct wbcUserPasswordPolicyInfo **policy);
 
 /*
  * Resolve functions