summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2006-02-10 23:09:00 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:10:03 -0500
commite83c7d0141c0726a74c7be48914e94bac7167ab1 (patch)
treeed3cab005159222c95c191d2fadd8eb3979beef7
parente493d329122e16a70f9f858aaa9ba51d20eba3c7 (diff)
downloadsamba-e83c7d0141c0726a74c7be48914e94bac7167ab1.tar.gz
samba-e83c7d0141c0726a74c7be48914e94bac7167ab1.tar.bz2
samba-e83c7d0141c0726a74c7be48914e94bac7167ab1.zip
r13442: Implement samr_chgpasswd_user3 server-side.
Guenther (This used to be commit f60eddc0a4dfe623e5f115533a62c03810fd5f38)
-rw-r--r--source3/include/rpc_samr.h16
-rw-r--r--source3/nsswitch/winbindd_pam.c16
-rw-r--r--source3/rpc_client/cli_samr.c39
-rw-r--r--source3/rpc_parse/parse_samr.c70
-rw-r--r--source3/rpc_server/srv_samr.c32
-rw-r--r--source3/rpc_server/srv_samr_nt.c105
-rw-r--r--source3/rpcclient/cmd_samr.c77
-rw-r--r--source3/smbd/chgpasswd.c16
8 files changed, 295 insertions, 76 deletions
diff --git a/source3/include/rpc_samr.h b/source3/include/rpc_samr.h
index e0b179224d..3af7d5c720 100644
--- a/source3/include/rpc_samr.h
+++ b/source3/include/rpc_samr.h
@@ -143,7 +143,7 @@ SamrTestPrivateFunctionsUser
#define SAMR_CONNECT 0x39
#define SAMR_SET_USERINFO 0x3A
#define SAMR_CONNECT4 0x3E
-#define SAMR_CHGPASSWD3 0x3F
+#define SAMR_CHGPASSWD_USER3 0x3F
#define SAMR_CONNECT5 0x40
typedef struct logon_hours_info
@@ -1826,7 +1826,7 @@ typedef struct r_samr_chgpasswd_user_info
} SAMR_R_CHGPASSWD_USER;
/* SAMR_Q_CHGPASSWD3 */
-typedef struct q_samr_chgpasswd3
+typedef struct q_samr_chgpasswd_user3
{
uint32 ptr_0;
@@ -1846,7 +1846,7 @@ typedef struct q_samr_chgpasswd3
SAMR_ENC_PASSWD password3;
-} SAMR_Q_CHGPASSWD3;
+} SAMR_Q_CHGPASSWD_USER3;
#define REJECT_REASON_TOO_SHORT 0x00000001
#define REJECT_REASON_IN_HISTORY 0x00000002
@@ -1862,13 +1862,15 @@ typedef struct samr_change_reject
} SAMR_CHANGE_REJECT;
/* SAMR_R_CHGPASSWD3 */
-typedef struct r_samr_chgpasswd3
+typedef struct r_samr_chgpasswd_user3
{
- SAM_UNK_INFO_1 info;
- SAMR_CHANGE_REJECT reject;
+ uint32 ptr_info;
+ uint32 ptr_reject;
+ SAM_UNK_INFO_1 *info;
+ SAMR_CHANGE_REJECT *reject;
NTSTATUS status; /* 0 == OK, C000006A (NT_STATUS_WRONG_PASSWORD) */
-} SAMR_R_CHGPASSWD3;
+} SAMR_R_CHGPASSWD_USER3;
diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c
index 499f225d2c..5f84d138e6 100644
--- a/source3/nsswitch/winbindd_pam.c
+++ b/source3/nsswitch/winbindd_pam.c
@@ -1557,8 +1557,8 @@ void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
struct winbindd_domain *contact_domain;
struct rpc_pipe_client *cli;
BOOL got_info = False;
- SAM_UNK_INFO_1 *info;
- SAMR_CHANGE_REJECT *reject;
+ SAM_UNK_INFO_1 info;
+ SAMR_CHANGE_REJECT reject;
DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
state->request.data.chauthtok.user));
@@ -1594,18 +1594,18 @@ void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) {
state->response.data.auth.policy.min_length_password =
- info->min_length_password;
+ info.min_length_password;
state->response.data.auth.policy.password_history =
- info->password_history;
+ info.password_history;
state->response.data.auth.policy.password_properties =
- info->password_properties;
+ info.password_properties;
state->response.data.auth.policy.expire =
- nt_time_to_unix_abs(&info->expire);
+ nt_time_to_unix_abs(&info.expire);
state->response.data.auth.policy.min_passwordage =
- nt_time_to_unix_abs(&info->min_passwordage);
+ nt_time_to_unix_abs(&info.min_passwordage);
state->response.data.auth.reject_reason =
- reject->reject_reason;
+ reject.reject_reason;
got_info = True;
diff --git a/source3/rpc_client/cli_samr.c b/source3/rpc_client/cli_samr.c
index 79f27fe2bb..1910e3a25f 100644
--- a/source3/rpc_client/cli_samr.c
+++ b/source3/rpc_client/cli_samr.c
@@ -1253,12 +1253,12 @@ NTSTATUS rpccli_samr_chgpasswd3(struct rpc_pipe_client *cli,
const char *username,
const char *newpassword,
const char *oldpassword,
- SAM_UNK_INFO_1 **info,
- SAMR_CHANGE_REJECT **reject)
+ SAM_UNK_INFO_1 *info,
+ SAMR_CHANGE_REJECT *reject)
{
prs_struct qbuf, rbuf;
- SAMR_Q_CHGPASSWD3 q;
- SAMR_R_CHGPASSWD3 r;
+ SAMR_Q_CHGPASSWD_USER3 q;
+ SAMR_R_CHGPASSWD_USER3 r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
uchar new_nt_password[516];
@@ -1273,14 +1273,11 @@ NTSTATUS rpccli_samr_chgpasswd3(struct rpc_pipe_client *cli,
char *srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", cli->cli->desthost);
- DEBUG(10,("rpccli_samr_chgpasswd3\n"));
+ DEBUG(10,("rpccli_samr_chgpasswd_user3\n"));
ZERO_STRUCT(q);
ZERO_STRUCT(r);
- *info = NULL;
- *reject = NULL;
-
/* Calculate the MD4 hash (NT compatible) of the password */
E_md4hash(oldpassword, old_nt_hash);
E_md4hash(newpassword, new_nt_hash);
@@ -1309,27 +1306,25 @@ NTSTATUS rpccli_samr_chgpasswd3(struct rpc_pipe_client *cli,
/* Marshall data and send request */
- init_samr_q_chgpasswd3(&q, srv_name_slash, username,
- new_nt_password,
- old_nt_hash_enc,
- new_lm_password,
- old_lanman_hash_enc);
+ init_samr_q_chgpasswd_user3(&q, srv_name_slash, username,
+ new_nt_password,
+ old_nt_hash_enc,
+ new_lm_password,
+ old_lanman_hash_enc);
+ r.info = info;
+ r.reject = reject;
- CLI_DO_RPC(cli, mem_ctx, PI_SAMR, SAMR_CHGPASSWD3,
+ CLI_DO_RPC(cli, mem_ctx, PI_SAMR, SAMR_CHGPASSWD_USER3,
q, r,
qbuf, rbuf,
- samr_io_q_chgpasswd3,
- samr_io_r_chgpasswd3,
+ samr_io_q_chgpasswd_user3,
+ samr_io_r_chgpasswd_user3,
NT_STATUS_UNSUCCESSFUL);
/* Return output parameters */
- if (!NT_STATUS_IS_OK(result = r.status)) {
- *info = &r.info;
- *reject = &r.reject;
- goto done;
- }
-
+ result = r.status;
+
done:
return result;
diff --git a/source3/rpc_parse/parse_samr.c b/source3/rpc_parse/parse_samr.c
index a0108d9eb7..b419fbebc4 100644
--- a/source3/rpc_parse/parse_samr.c
+++ b/source3/rpc_parse/parse_samr.c
@@ -7299,7 +7299,7 @@ inits a SAMR_R_CHGPASSWD_USER structure.
void init_samr_r_chgpasswd_user(SAMR_R_CHGPASSWD_USER * r_u, NTSTATUS status)
{
- DEBUG(5, ("init_r_chgpasswd_user\n"));
+ DEBUG(5, ("init_samr_r_chgpasswd_user\n"));
r_u->status = status;
}
@@ -7330,14 +7330,14 @@ BOOL samr_io_r_chgpasswd_user(const char *desc, SAMR_R_CHGPASSWD_USER * r_u,
inits a SAMR_Q_CHGPASSWD3 structure.
********************************************************************/
-void init_samr_q_chgpasswd3(SAMR_Q_CHGPASSWD3 * q_u,
- const char *dest_host, const char *user_name,
- const uchar nt_newpass[516],
- const uchar nt_oldhash[16],
- const uchar lm_newpass[516],
- const uchar lm_oldhash[16])
+void init_samr_q_chgpasswd_user3(SAMR_Q_CHGPASSWD_USER3 * q_u,
+ const char *dest_host, const char *user_name,
+ const uchar nt_newpass[516],
+ const uchar nt_oldhash[16],
+ const uchar lm_newpass[516],
+ const uchar lm_oldhash[16])
{
- DEBUG(5, ("init_samr_q_chgpasswd3\n"));
+ DEBUG(5, ("init_samr_q_chgpasswd_user3\n"));
q_u->ptr_0 = 1;
init_unistr2(&q_u->uni_dest_host, dest_host, UNI_FLAGS_NONE);
@@ -7361,13 +7361,13 @@ void init_samr_q_chgpasswd3(SAMR_Q_CHGPASSWD3 * q_u,
reads or writes a structure.
********************************************************************/
-BOOL samr_io_q_chgpasswd3(const char *desc, SAMR_Q_CHGPASSWD3 * q_u,
- prs_struct *ps, int depth)
+BOOL samr_io_q_chgpasswd_user3(const char *desc, SAMR_Q_CHGPASSWD_USER3 * q_u,
+ prs_struct *ps, int depth)
{
if (q_u == NULL)
return False;
- prs_debug(ps, depth, desc, "samr_io_q_chgpasswd3");
+ prs_debug(ps, depth, desc, "samr_io_q_chgpasswd_user3");
depth++;
if(!prs_align(ps))
@@ -7408,14 +7408,30 @@ BOOL samr_io_q_chgpasswd3(const char *desc, SAMR_Q_CHGPASSWD3 * q_u,
}
/*******************************************************************
-inits a SAMR_R_CHGPASSWD3 structure.
+inits a SAMR_R_CHGPASSWD_USER3 structure.
********************************************************************/
-void init_samr_r_chgpasswd3(SAMR_R_CHGPASSWD3 * r_u, NTSTATUS status)
+void init_samr_r_chgpasswd_user3(SAMR_R_CHGPASSWD_USER3 *r_u, NTSTATUS status,
+ SAMR_CHANGE_REJECT *reject, SAM_UNK_INFO_1 *info)
{
- DEBUG(5, ("init_r_chgpasswd3\n"));
+ DEBUG(5, ("init_samr_r_chgpasswd_user3\n"));
r_u->status = status;
+ r_u->info = 0;
+ r_u->ptr_info = 0;
+ r_u->reject = 0;
+ r_u->ptr_reject = 0;
+
+ if (NT_STATUS_EQUAL(r_u->status, NT_STATUS_PASSWORD_RESTRICTION)) {
+ if (info) {
+ r_u->info = info;
+ r_u->ptr_info = 1;
+ }
+ if (reject) {
+ r_u->reject = reject;
+ r_u->ptr_reject = 1;
+ }
+ }
}
/*******************************************************************
@@ -7452,41 +7468,37 @@ BOOL samr_io_change_reject(const char *desc, SAMR_CHANGE_REJECT *reject, prs_str
reads or writes a structure.
********************************************************************/
-BOOL samr_io_r_chgpasswd3(const char *desc, SAMR_R_CHGPASSWD3 * r_u,
- prs_struct *ps, int depth)
+BOOL samr_io_r_chgpasswd_user3(const char *desc, SAMR_R_CHGPASSWD_USER3 *r_u,
+ prs_struct *ps, int depth)
{
- uint32 ptr_info, ptr_reject;
-
if (r_u == NULL)
return False;
- prs_debug(ps, depth, desc, "samr_io_r_chgpasswd3");
+ prs_debug(ps, depth, desc, "samr_io_r_chgpasswd_user3");
depth++;
- if(!prs_align(ps))
+ if (!prs_align(ps))
return False;
- if(!prs_uint32("ptr_info", ps, depth, &ptr_info))
+ if (!prs_uint32("ptr_info", ps, depth, &r_u->ptr_info))
return False;
- if (ptr_info) {
-
+ if (r_u->ptr_info && r_u->info != NULL) {
/* SAM_UNK_INFO_1 */
- if(!sam_io_unk_info1("info", &r_u->info, ps, depth))
+ if (!sam_io_unk_info1("info", r_u->info, ps, depth))
return False;
}
- if(!prs_uint32("ptr_reject", ps, depth, &ptr_reject))
+ if (!prs_uint32("ptr_reject", ps, depth, &r_u->ptr_reject))
return False;
- if (ptr_reject) {
-
+ if (r_u->ptr_reject && r_u->reject != NULL) {
/* SAMR_CHANGE_REJECT */
- if(!samr_io_change_reject("reject", &r_u->reject, ps, depth))
+ if (!samr_io_change_reject("reject", r_u->reject, ps, depth))
return False;
}
- if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ if (!prs_ntstatus("status", ps, depth, &r_u->status))
return False;
return True;
diff --git a/source3/rpc_server/srv_samr.c b/source3/rpc_server/srv_samr.c
index e8fd86ba46..015ed6c5ea 100644
--- a/source3/rpc_server/srv_samr.c
+++ b/source3/rpc_server/srv_samr.c
@@ -680,6 +680,37 @@ static BOOL api_samr_connect4(pipes_struct *p)
}
/*******************************************************************
+ api_samr_chgpasswd_user3
+ ********************************************************************/
+
+static BOOL api_samr_chgpasswd_user3(pipes_struct *p)
+{
+ SAMR_Q_CHGPASSWD_USER3 q_u;
+ SAMR_R_CHGPASSWD_USER3 r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* change password request */
+ if (!samr_io_q_chgpasswd_user3("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_chgpasswd_user3: Failed to unmarshall SAMR_Q_CHGPASSWD_USER3.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_chgpasswd_user3(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_chgpasswd_user3("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_chgpasswd_user3: Failed to marshall SAMR_R_CHGPASSWD_USER3.\n" ));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
api_samr_connect5
********************************************************************/
@@ -1524,6 +1555,7 @@ static struct api_struct api_samr_cmds [] =
{"SAMR_QUERY_DOMAIN_INFO2", SAMR_QUERY_DOMAIN_INFO2, api_samr_query_domain_info2},
{"SAMR_SET_DOMAIN_INFO" , SAMR_SET_DOMAIN_INFO , api_samr_set_dom_info },
{"SAMR_CONNECT4" , SAMR_CONNECT4 , api_samr_connect4 },
+ {"SAMR_CHGPASSWD_USER3" , SAMR_CHGPASSWD_USER3 , api_samr_chgpasswd_user3 },
{"SAMR_CONNECT5" , SAMR_CONNECT5 , api_samr_connect5 }
};
diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c
index bf0e2ba070..75a72fa028 100644
--- a/source3/rpc_server/srv_samr_nt.c
+++ b/source3/rpc_server/srv_samr_nt.c
@@ -1462,7 +1462,7 @@ NTSTATUS _samr_chgpasswd_user(pipes_struct *p, SAMR_Q_CHGPASSWD_USER *q_u, SAMR_
*/
r_u->status = pass_oem_change(user_name, q_u->lm_newpass.pass, q_u->lm_oldhash.hash,
- q_u->nt_newpass.pass, q_u->nt_oldhash.hash);
+ q_u->nt_newpass.pass, q_u->nt_oldhash.hash, NULL);
init_samr_r_chgpasswd_user(r_u, r_u->status);
@@ -1472,6 +1472,97 @@ NTSTATUS _samr_chgpasswd_user(pipes_struct *p, SAMR_Q_CHGPASSWD_USER *q_u, SAMR_
}
/*******************************************************************
+ _samr_chgpasswd_user3
+ ********************************************************************/
+
+NTSTATUS _samr_chgpasswd_user3(pipes_struct *p, SAMR_Q_CHGPASSWD_USER3 *q_u, SAMR_R_CHGPASSWD_USER3 *r_u)
+{
+ fstring user_name;
+ fstring wks;
+ uint32 reject_reason;
+ SAM_UNK_INFO_1 *info = NULL;
+ SAMR_CHANGE_REJECT *reject = NULL;
+
+ DEBUG(5,("_samr_chgpasswd_user3: %d\n", __LINE__));
+
+ rpcstr_pull(user_name, q_u->uni_user_name.buffer, sizeof(user_name), q_u->uni_user_name.uni_str_len*2, 0);
+ rpcstr_pull(wks, q_u->uni_dest_host.buffer, sizeof(wks), q_u->uni_dest_host.uni_str_len*2,0);
+
+ DEBUG(5,("_samr_chgpasswd_user3: user: %s wks: %s\n", user_name, wks));
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user_name);
+
+ /*
+ * UNIX username case mangling not required, pass_oem_change
+ * is case insensitive.
+ */
+
+ r_u->status = pass_oem_change(user_name, q_u->lm_newpass.pass, q_u->lm_oldhash.hash,
+ q_u->nt_newpass.pass, q_u->nt_oldhash.hash, &reject_reason);
+
+ if (NT_STATUS_EQUAL(r_u->status, NT_STATUS_PASSWORD_RESTRICTION)) {
+
+ uint32 min_pass_len,pass_hist,password_properties;
+ time_t u_expire, u_min_age;
+ NTTIME nt_expire, nt_min_age;
+ uint32 account_policy_temp;
+
+ if ((info = TALLOC_ZERO_P(p->mem_ctx, SAM_UNK_INFO_1)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ((reject = TALLOC_ZERO_P(p->mem_ctx, SAMR_CHANGE_REJECT)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(info);
+ ZERO_STRUCTP(reject);
+
+ become_root();
+
+ /* AS ROOT !!! */
+
+ pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp);
+ min_pass_len = account_policy_temp;
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp);
+ pass_hist = account_policy_temp;
+
+ pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
+ password_properties = account_policy_temp;
+
+ pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
+ u_expire = account_policy_temp;
+
+ pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp);
+ u_min_age = account_policy_temp;
+
+ /* !AS ROOT */
+
+ unbecome_root();
+
+ unix_to_nt_time_abs(&nt_expire, u_expire);
+ unix_to_nt_time_abs(&nt_min_age, u_min_age);
+
+ init_unk_info1(info, (uint16)min_pass_len, (uint16)pass_hist,
+ password_properties, nt_expire, nt_min_age);
+
+ reject->reject_reason = reject_reason;
+ }
+
+ init_samr_r_chgpasswd_user3(r_u, r_u->status, reject, info);
+
+ DEBUG(5,("_samr_chgpasswd_user3: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
makes a SAMR_R_LOOKUP_RIDS structure.
********************************************************************/
@@ -2090,7 +2181,7 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
{
struct samr_info *info = NULL;
SAM_UNK_CTR *ctr;
- uint32 min_pass_len,pass_hist,flag;
+ uint32 min_pass_len,pass_hist,password_properties;
time_t u_expire, u_min_age;
NTTIME nt_expire, nt_min_age;
@@ -2136,7 +2227,7 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
pass_hist = account_policy_temp;
pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
- flag = account_policy_temp;
+ password_properties = account_policy_temp;
pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
u_expire = account_policy_temp;
@@ -2152,7 +2243,7 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
unix_to_nt_time_abs(&nt_min_age, u_min_age);
init_unk_info1(&ctr->info.inf1, (uint16)min_pass_len, (uint16)pass_hist,
- flag, nt_expire, nt_min_age);
+ password_properties, nt_expire, nt_min_age);
break;
case 0x02:
@@ -4815,7 +4906,7 @@ NTSTATUS _samr_query_domain_info2(pipes_struct *p,
{
struct samr_info *info = NULL;
SAM_UNK_CTR *ctr;
- uint32 min_pass_len,pass_hist,flag;
+ uint32 min_pass_len,pass_hist,password_properties;
time_t u_expire, u_min_age;
NTTIME nt_expire, nt_min_age;
@@ -4855,7 +4946,7 @@ NTSTATUS _samr_query_domain_info2(pipes_struct *p,
pass_hist = account_policy_temp;
pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
- flag = account_policy_temp;
+ password_properties = account_policy_temp;
pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
u_expire = account_policy_temp;
@@ -4867,7 +4958,7 @@ NTSTATUS _samr_query_domain_info2(pipes_struct *p,
unix_to_nt_time_abs(&nt_min_age, u_min_age);
init_unk_info1(&ctr->info.inf1, (uint16)min_pass_len, (uint16)pass_hist,
- flag, nt_expire, nt_min_age);
+ password_properties, nt_expire, nt_min_age);
break;
case 0x02:
become_root();
diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c
index 93a3e39036..ff9674b9fe 100644
--- a/source3/rpcclient/cmd_samr.c
+++ b/source3/rpcclient/cmd_samr.c
@@ -1915,6 +1915,82 @@ done:
return result;
}
+/* Change user password */
+
+static NTSTATUS cmd_samr_chgpasswd3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *user, *oldpass, *newpass;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ SAM_UNK_INFO_1 info;
+ SAMR_CHANGE_REJECT reject;
+
+ if (argc < 3) {
+ printf("Usage: %s username oldpass newpass\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ user = argv[1];
+ oldpass = argv[2];
+ newpass = argv[3];
+
+ /* Get sam policy handle */
+
+ result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ access_mask,
+ &domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Change user password */
+ result = rpccli_samr_chgpasswd3(cli, mem_ctx, user, newpass, oldpass, &info, &reject);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) {
+
+ display_sam_unk_info_1(&info);
+
+ switch (reject.reject_reason) {
+ case REJECT_REASON_TOO_SHORT:
+ d_printf("REJECT_REASON_TOO_SHORT\n");
+ break;
+ case REJECT_REASON_IN_HISTORY:
+ d_printf("REJECT_REASON_IN_HISTORY\n");
+ break;
+ case REJECT_REASON_NOT_COMPLEX:
+ d_printf("REJECT_REASON_NOT_COMPLEX\n");
+ break;
+ case 0:
+ break;
+ default:
+ d_printf("unknown reject reason: %d\n", reject.reject_reason);
+ break;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_close(cli, mem_ctx, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_close(cli, mem_ctx, &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+ return result;
+}
/* List of commands exported by this module */
@@ -1945,5 +2021,6 @@ struct cmd_set samr_commands[] = {
{ "getdompwinfo", RPC_RTYPE_NTSTATUS, cmd_samr_get_dom_pwinfo, NULL, PI_SAMR, NULL, "Retrieve domain password info", "" },
{ "lookupdomain", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_domain, NULL, PI_SAMR, NULL, "Lookup Domain Name", "" },
+ { "chgpasswd3", RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd, NULL, PI_SAMR, NULL, "Change user password", "" },
{ NULL }
};
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index 0798541cb5..501aba3336 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/smbd/chgpasswd.c
@@ -703,7 +703,8 @@ NTSTATUS pass_oem_change(char *user,
uchar password_encrypted_with_lm_hash[516],
const uchar old_lm_hash_encrypted[16],
uchar password_encrypted_with_nt_hash[516],
- const uchar old_nt_hash_encrypted[16])
+ const uchar old_nt_hash_encrypted[16],
+ uint32 *reject_reason)
{
pstring new_passwd;
SAM_ACCOUNT *sampass = NULL;
@@ -718,7 +719,7 @@ NTSTATUS pass_oem_change(char *user,
/* We've already checked the old password here.... */
become_root();
- nt_status = change_oem_password(sampass, NULL, new_passwd, True);
+ nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason);
unbecome_root();
memset(new_passwd, 0, sizeof(new_passwd));
@@ -1007,7 +1008,7 @@ static BOOL check_passwd_history(SAM_ACCOUNT *sampass, const char *plaintext)
is correct before calling. JRA.
************************************************************/
-NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root)
+NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root, uint32 *samr_reject_reason)
{
uint32 min_len, min_age;
struct passwd *pass = NULL;
@@ -1040,11 +1041,17 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw
DEBUG(1, ("user %s cannot change password - password too short\n",
username));
DEBUGADD(1, (" account policy min password len = %d\n", min_len));
+ if (samr_reject_reason) {
+ *samr_reject_reason = REJECT_REASON_TOO_SHORT;
+ }
return NT_STATUS_PASSWORD_RESTRICTION;
/* return NT_STATUS_PWD_TOO_SHORT; */
}
if (check_passwd_history(hnd,new_passwd)) {
+ if (samr_reject_reason) {
+ *samr_reject_reason = REJECT_REASON_IN_HISTORY;
+ }
return NT_STATUS_PASSWORD_RESTRICTION;
}
@@ -1063,6 +1070,9 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw
if (check_ret != 0) {
DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
+ if (samr_reject_reason) {
+ *samr_reject_reason = REJECT_REASON_NOT_COMPLEX;
+ }
return NT_STATUS_PASSWORD_RESTRICTION;
}
}