summaryrefslogtreecommitdiff
path: root/source3/nsswitch
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nsswitch')
-rw-r--r--source3/nsswitch/libwbclient/wbc_pam.c271
-rw-r--r--source3/nsswitch/libwbclient/wbclient.c2
-rw-r--r--source3/nsswitch/libwbclient/wbclient.h78
-rw-r--r--source3/nsswitch/wbinfo.c34
4 files changed, 383 insertions, 2 deletions
diff --git a/source3/nsswitch/libwbclient/wbc_pam.c b/source3/nsswitch/libwbclient/wbc_pam.c
index 293f71c347..20b42b6efb 100644
--- a/source3/nsswitch/libwbclient/wbc_pam.c
+++ b/source3/nsswitch/libwbclient/wbc_pam.c
@@ -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;
+}
diff --git a/source3/nsswitch/libwbclient/wbclient.c b/source3/nsswitch/libwbclient/wbclient.c
index 82decc2f78..bdde562a93 100644
--- a/source3/nsswitch/libwbclient/wbclient.c
+++ b/source3/nsswitch/libwbclient/wbclient.c
@@ -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";
diff --git a/source3/nsswitch/libwbclient/wbclient.h b/source3/nsswitch/libwbclient/wbclient.h
index 2fefe0c072..cae3feec5b 100644
--- a/source3/nsswitch/libwbclient/wbclient.h
+++ b/source3/nsswitch/libwbclient/wbclient.h
@@ -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
diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c
index 463d9233d0..60524d1d1b 100644
--- a/source3/nsswitch/wbinfo.c
+++ b/source3/nsswitch/wbinfo.c
@@ -1341,6 +1341,28 @@ static bool wbinfo_ping(void)
return WBC_ERROR_IS_OK(wbc_status);
}
+static bool wbinfo_change_user_password(const char *username)
+{
+ wbcErr wbc_status;
+ char *old_password = NULL;
+ char *new_password = NULL;
+
+ old_password = wbinfo_prompt_pass("old", username);
+ new_password = wbinfo_prompt_pass("new", username);
+
+ wbc_status = wbcChangeUserPassword(username, old_password, new_password);
+
+ /* Display response */
+
+ d_printf("Password change for user %s %s\n", username,
+ WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
+
+ SAFE_FREE(old_password);
+ SAFE_FREE(new_password);
+
+ return WBC_ERROR_IS_OK(wbc_status);
+}
+
/* Main program */
enum {
@@ -1360,7 +1382,8 @@ enum {
OPT_UID_INFO,
OPT_GROUP_INFO,
OPT_VERBOSE,
- OPT_ONLINESTATUS
+ OPT_ONLINESTATUS,
+ OPT_CHANGE_USER_PASSWORD
};
int main(int argc, char **argv, char **envp)
@@ -1427,6 +1450,7 @@ int main(int argc, char **argv, char **envp)
#endif
{ "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL },
{ "verbose", 0, POPT_ARG_NONE, 0, OPT_VERBOSE, "Print additional information per command", NULL },
+ { "change-user-password", 0, POPT_ARG_STRING, &string_arg, OPT_CHANGE_USER_PASSWORD, "Change the password for a user", NULL },
POPT_COMMON_CONFIGFILE
POPT_COMMON_VERSION
POPT_TABLEEND
@@ -1707,6 +1731,14 @@ int main(int argc, char **argv, char **envp)
goto done;
}
break;
+ case OPT_CHANGE_USER_PASSWORD:
+ if (!wbinfo_change_user_password(string_arg)) {
+ d_fprintf(stderr, "Could not change user password "
+ "for user %s\n", string_arg);
+ goto done;
+ }
+ break;
+
/* generic configuration options */
case OPT_DOMAIN_NAME:
break;