2 Unix SMB/CIFS implementation.
4 samr server password set/change handling
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "librpc/gen_ndr/ndr_samr.h"
25 #include "rpc_server/dcerpc_server.h"
26 #include "rpc_server/common/common.h"
27 #include "rpc_server/samr/dcesrv_samr.h"
28 #include "system/time.h"
29 #include "lib/crypto/crypto.h"
30 #include "lib/ldb/include/ldb.h"
34 samr_ChangePasswordUser
36 NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
37 struct samr_ChangePasswordUser *r)
39 struct dcesrv_handle *h;
40 struct samr_account_state *a_state;
41 struct ldb_message **res, *msg;
43 struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
44 struct samr_Password *lm_pwd, *nt_pwd;
45 NTSTATUS status = NT_STATUS_OK;
46 const char * const attrs[] = { "lmPwdHash", "ntPwdHash" , "unicodePwd", NULL };
48 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
52 /* fetch the old hashes */
53 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
54 a_state->account_dn, &res, attrs);
56 return NT_STATUS_INTERNAL_DB_CORRUPTION;
60 /* basic sanity checking on parameters */
61 if (!r->in.lm_present || !r->in.nt_present ||
62 !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
63 !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
64 /* we should really handle a change with lm not
66 return NT_STATUS_INVALID_PARAMETER_MIX;
68 if (!r->in.cross1_present || !r->in.nt_cross) {
69 return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED;
71 if (!r->in.cross2_present || !r->in.lm_cross) {
72 return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED;
75 status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
76 if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
77 return NT_STATUS_WRONG_PASSWORD;
80 /* decrypt and check the new lm hash */
81 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
82 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
83 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
84 return NT_STATUS_WRONG_PASSWORD;
87 /* decrypt and check the new nt hash */
88 D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
89 D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
90 if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
91 return NT_STATUS_WRONG_PASSWORD;
94 /* check the nt cross hash */
95 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
96 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
97 return NT_STATUS_WRONG_PASSWORD;
100 /* check the lm cross hash */
101 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
102 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
103 return NT_STATUS_WRONG_PASSWORD;
106 msg = ldb_msg_new(mem_ctx);
108 return NT_STATUS_NO_MEMORY;
111 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
113 return NT_STATUS_NO_MEMORY;
116 status = samdb_set_password(a_state->sam_ctx, mem_ctx,
117 a_state->account_dn, a_state->domain_state->domain_dn,
118 msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
119 True, /* this is a user password change */
120 True, /* run restriction tests */
122 if (!NT_STATUS_IS_OK(status)) {
126 /* modify the samdb record */
127 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
129 return NT_STATUS_UNSUCCESSFUL;
136 samr_OemChangePasswordUser2
138 NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
139 struct samr_OemChangePasswordUser2 *r)
143 uint32_t new_pass_len;
144 struct samr_CryptPassword *pwbuf = r->in.password;
146 const struct ldb_dn *user_dn, *domain_dn;
148 struct ldb_message **res, *mod;
149 const char * const attrs[] = { "objectSid", "lmPwdHash", "unicodePwd", NULL };
150 struct samr_Password *lm_pwd;
151 DATA_BLOB lm_pwd_blob;
152 uint8_t new_lm_hash[16];
153 struct samr_Password lm_verifier;
154 struct dom_sid *domain_sid;
157 return NT_STATUS_WRONG_PASSWORD;
160 /* this call doesn't take a policy handle, so we need to open
161 the sam db from scratch */
162 sam_ctx = samdb_connect(mem_ctx);
163 if (sam_ctx == NULL) {
164 return NT_STATUS_INVALID_SYSTEM_SERVICE;
167 /* we need the users dn and the domain dn (derived from the
168 user SID). We also need the current lm password hash in
169 order to decrypt the incoming password */
170 ret = gendb_search(sam_ctx,
171 mem_ctx, NULL, &res, attrs,
172 "(&(sAMAccountName=%s)(objectclass=user))",
173 r->in.account->string);
175 return NT_STATUS_NO_SUCH_USER;
178 user_dn = res[0]->dn;
180 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
181 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
182 return NT_STATUS_WRONG_PASSWORD;
185 /* decrypt the password we have been given */
186 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
187 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
188 data_blob_free(&lm_pwd_blob);
190 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
191 &new_pass_len, STR_ASCII)) {
192 DEBUG(3,("samr: failed to decode password buffer\n"));
193 return NT_STATUS_WRONG_PASSWORD;
196 /* check LM verifier */
197 if (lm_pwd == NULL || r->in.hash == NULL) {
198 return NT_STATUS_WRONG_PASSWORD;
201 E_deshash(new_pass, new_lm_hash);
202 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
203 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
204 return NT_STATUS_WRONG_PASSWORD;
207 /* work out the domain dn */
208 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
209 if (domain_sid == NULL) {
210 return NT_STATUS_NO_SUCH_USER;
213 domain_dn = ldb_dn_explode(mem_ctx,
214 samdb_search_string(sam_ctx, mem_ctx, NULL, "dn",
216 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)));
218 return NT_STATUS_INTERNAL_DB_CORRUPTION;
221 mod = ldb_msg_new(mem_ctx);
223 return NT_STATUS_NO_MEMORY;
226 mod->dn = ldb_dn_copy(mod, user_dn);
228 return NT_STATUS_NO_MEMORY;
231 /* set the password - samdb needs to know both the domain and user DNs,
232 so the domain password policy can be used */
233 status = samdb_set_password(sam_ctx, mem_ctx,
237 True, /* this is a user password change */
238 True, /* run restriction tests */
240 if (!NT_STATUS_IS_OK(status)) {
244 /* modify the samdb record */
245 ret = samdb_replace(sam_ctx, mem_ctx, mod);
247 return NT_STATUS_UNSUCCESSFUL;
255 samr_ChangePasswordUser3
257 NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
259 struct samr_ChangePasswordUser3 *r)
263 uint32_t new_pass_len;
264 void *sam_ctx = NULL;
265 const struct ldb_dn *user_dn, *domain_dn = NULL;
267 struct ldb_message **res, *mod;
268 const char * const attrs[] = { "objectSid", "ntPwdHash", "lmPwdHash", "unicodePwd", NULL };
269 const char * const dom_attrs[] = { "minPwdLength", "pwdHistoryLength",
270 "pwdProperties", "minPwdAge", "maxPwdAge",
272 struct dom_sid *domain_sid;
273 struct samr_Password *nt_pwd, *lm_pwd;
274 DATA_BLOB nt_pwd_blob;
275 struct samr_DomInfo1 *dominfo;
276 struct samr_ChangeReject *reject;
278 uint8_t new_nt_hash[16], new_lm_hash[16];
279 struct samr_Password nt_verifier, lm_verifier;
283 if (r->in.nt_password == NULL ||
284 r->in.nt_verifier == NULL) {
285 status = NT_STATUS_INVALID_PARAMETER;
289 /* this call doesn't take a policy handle, so we need to open
290 the sam db from scratch */
291 sam_ctx = samdb_connect(mem_ctx);
292 if (sam_ctx == NULL) {
293 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
297 /* we need the users dn and the domain dn (derived from the
298 user SID). We also need the current lm and nt password hashes
299 in order to decrypt the incoming passwords */
300 ret = gendb_search(sam_ctx,
301 mem_ctx, NULL, &res, attrs,
302 "(&(sAMAccountName=%s)(objectclass=user))",
303 r->in.account->string);
305 status = NT_STATUS_NO_SUCH_USER;
309 user_dn = res[0]->dn;
311 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
312 if (!NT_STATUS_IS_OK(status) ) {
317 status = NT_STATUS_WRONG_PASSWORD;
321 /* decrypt the password we have been given */
322 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
323 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
324 data_blob_free(&nt_pwd_blob);
326 if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
327 &new_pass_len, STR_UNICODE)) {
328 DEBUG(3,("samr: failed to decode password buffer\n"));
329 status = NT_STATUS_WRONG_PASSWORD;
333 if (r->in.nt_verifier == NULL) {
334 status = NT_STATUS_WRONG_PASSWORD;
338 /* check NT verifier */
339 E_md4hash(new_pass, new_nt_hash);
340 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
341 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
342 status = NT_STATUS_WRONG_PASSWORD;
346 /* check LM verifier */
347 if (lm_pwd && r->in.lm_verifier != NULL) {
348 E_deshash(new_pass, new_lm_hash);
349 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
350 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
351 status = NT_STATUS_WRONG_PASSWORD;
357 /* work out the domain dn */
358 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
359 if (domain_sid == NULL) {
360 status = NT_STATUS_NO_SUCH_DOMAIN;
364 domain_dn = ldb_dn_explode(mem_ctx,
365 samdb_search_string(sam_ctx, mem_ctx, NULL, "dn",
367 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)));
369 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
373 mod = ldb_msg_new(mem_ctx);
375 return NT_STATUS_NO_MEMORY;
378 mod->dn = ldb_dn_copy(mod, user_dn);
380 status = NT_STATUS_NO_MEMORY;
384 /* set the password - samdb needs to know both the domain and user DNs,
385 so the domain password policy can be used */
386 status = samdb_set_password(sam_ctx, mem_ctx,
390 True, /* this is a user password change */
391 True, /* run restriction tests */
393 if (!NT_STATUS_IS_OK(status)) {
397 /* modify the samdb record */
398 ret = samdb_replace(sam_ctx, mem_ctx, mod);
400 status = NT_STATUS_UNSUCCESSFUL;
408 ret = gendb_search_dn(sam_ctx, mem_ctx,
409 domain_dn, &res, dom_attrs);
416 /* on failure we need to fill in the reject reasons */
417 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
418 if (dominfo == NULL) {
421 reject = talloc(mem_ctx, struct samr_ChangeReject);
422 if (reject == NULL) {
426 ZERO_STRUCTP(dominfo);
427 ZERO_STRUCTP(reject);
429 reject->reason = reason;
431 r->out.dominfo = dominfo;
432 r->out.reject = reject;
438 dominfo->min_password_length = samdb_result_uint (res[0], "minPwdLength", 0);
439 dominfo->password_properties = samdb_result_uint (res[0], "pwdProperties", 0);
440 dominfo->password_history_length = samdb_result_uint (res[0], "pwdHistoryLength", 0);
441 dominfo->max_password_age = samdb_result_int64(res[0], "maxPwdAge", 0);
442 dominfo->min_password_age = samdb_result_int64(res[0], "minPwdAge", 0);
449 samr_ChangePasswordUser2
451 easy - just a subset of samr_ChangePasswordUser3
453 NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
454 struct samr_ChangePasswordUser2 *r)
456 struct samr_ChangePasswordUser3 r2;
458 r2.in.server = r->in.server;
459 r2.in.account = r->in.account;
460 r2.in.nt_password = r->in.nt_password;
461 r2.in.nt_verifier = r->in.nt_verifier;
462 r2.in.lm_change = r->in.lm_change;
463 r2.in.lm_password = r->in.lm_password;
464 r2.in.lm_verifier = r->in.lm_verifier;
465 r2.in.password3 = NULL;
467 return samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
472 check that a password is sufficiently complex
474 static BOOL samdb_password_complexity_ok(const char *pass)
476 return check_password_quality(pass);
480 set the user password using plaintext, obeying any user or domain
481 password restrictions
483 note that this function doesn't actually store the result in the
484 database, it just fills in the "mod" structure with ldb modify
485 elements to setup the correct change when samdb_replace() is
486 called. This allows the caller to combine the change with other
487 changes (as is needed by some of the set user info levels)
489 NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
490 const struct ldb_dn *user_dn,
491 const struct ldb_dn *domain_dn,
492 struct ldb_message *mod,
493 const char *new_pass,
494 struct samr_Password *lmNewHash,
495 struct samr_Password *ntNewHash,
498 uint32_t *reject_reason)
500 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
501 "ntPwdHistory", "unicodePwd",
502 "lmPwdHash", "ntPwdHash", "badPwdCount",
504 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
505 "maxPwdAge", "minPwdAge",
506 "minPwdLength", "pwdLastSet", NULL };
507 const char *unicodePwd;
510 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
511 uint_t userAccountControl, badPwdCount;
512 struct samr_Password *lmPwdHistory, *ntPwdHistory, lmPwdHash, ntPwdHash;
513 struct samr_Password *new_lmPwdHistory, *new_ntPwdHistory;
514 struct samr_Password local_lmNewHash, local_ntNewHash;
515 int lmPwdHistory_len, ntPwdHistory_len;
517 struct ldb_message **res;
519 time_t now = time(NULL);
523 /* we need to know the time to compute password age */
524 unix_to_nt_time(&now_nt, now);
526 /* pull all the user parameters */
527 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
529 return NT_STATUS_INTERNAL_DB_CORRUPTION;
531 unicodePwd = samdb_result_string(res[0], "unicodePwd", NULL);
532 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
533 badPwdCount = samdb_result_uint(res[0], "badPwdCount", 0);
534 lmPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
535 "lmPwdHistory", &lmPwdHistory);
536 ntPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
537 "ntPwdHistory", &ntPwdHistory);
538 lmPwdHash = samdb_result_hash(res[0], "lmPwdHash");
539 ntPwdHash = samdb_result_hash(res[0], "ntPwdHash");
540 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
541 kvno = samdb_result_uint(res[0], "msDS-KeyVersionNumber", 0);
543 /* pull the domain parameters */
544 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
546 return NT_STATUS_INTERNAL_DB_CORRUPTION;
548 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
549 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
550 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
551 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
554 /* check the various password restrictions */
555 if (restrictions && minPwdLength > strlen_m(new_pass)) {
557 *reject_reason = SAMR_REJECT_TOO_SHORT;
559 return NT_STATUS_PASSWORD_RESTRICTION;
562 /* possibly check password complexity */
563 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
564 !samdb_password_complexity_ok(new_pass)) {
566 *reject_reason = SAMR_REJECT_COMPLEXITY;
568 return NT_STATUS_PASSWORD_RESTRICTION;
571 /* compute the new nt and lm hashes */
572 if (E_deshash(new_pass, local_lmNewHash.hash)) {
573 lmNewHash = &local_lmNewHash;
575 E_md4hash(new_pass, local_ntNewHash.hash);
576 ntNewHash = &local_ntNewHash;
579 if (restrictions && user_change) {
580 /* are all password changes disallowed? */
581 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
583 *reject_reason = SAMR_REJECT_OTHER;
585 return NT_STATUS_PASSWORD_RESTRICTION;
588 /* can this user change password? */
589 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
591 *reject_reason = SAMR_REJECT_OTHER;
593 return NT_STATUS_PASSWORD_RESTRICTION;
596 /* yes, this is a minus. The ages are in negative 100nsec units! */
597 if (pwdLastSet - minPwdAge > now_nt) {
599 *reject_reason = SAMR_REJECT_OTHER;
601 return NT_STATUS_PASSWORD_RESTRICTION;
604 /* check the immediately past password */
605 if (pwdHistoryLength > 0) {
606 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
608 *reject_reason = SAMR_REJECT_COMPLEXITY;
610 return NT_STATUS_PASSWORD_RESTRICTION;
612 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
614 *reject_reason = SAMR_REJECT_COMPLEXITY;
616 return NT_STATUS_PASSWORD_RESTRICTION;
620 /* check the password history */
621 lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength);
622 ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength);
624 if (pwdHistoryLength > 0) {
625 if (unicodePwd && new_pass && strcmp(unicodePwd, new_pass) == 0) {
627 *reject_reason = SAMR_REJECT_COMPLEXITY;
629 return NT_STATUS_PASSWORD_RESTRICTION;
631 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
633 *reject_reason = SAMR_REJECT_COMPLEXITY;
635 return NT_STATUS_PASSWORD_RESTRICTION;
637 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
639 *reject_reason = SAMR_REJECT_COMPLEXITY;
641 return NT_STATUS_PASSWORD_RESTRICTION;
645 for (i=0; lmNewHash && i<lmPwdHistory_len;i++) {
646 if (memcmp(lmNewHash->hash, lmPwdHistory[i].hash, 16) == 0) {
648 *reject_reason = SAMR_REJECT_COMPLEXITY;
650 return NT_STATUS_PASSWORD_RESTRICTION;
653 for (i=0; ntNewHash && i<ntPwdHistory_len;i++) {
654 if (memcmp(ntNewHash->hash, ntPwdHistory[i].hash, 16) == 0) {
656 *reject_reason = SAMR_REJECT_COMPLEXITY;
658 return NT_STATUS_PASSWORD_RESTRICTION;
663 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
665 /* the password is acceptable. Start forming the new fields */
667 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
669 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
673 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
675 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
678 if (new_pass && (pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT) &&
679 (userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
680 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
681 "unicodePwd", new_pass));
683 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
686 CHECK_RET(samdb_msg_add_uint64(ctx, mem_ctx, mod, "pwdLastSet", now_nt));
688 CHECK_RET(samdb_msg_add_uint(ctx, mem_ctx, mod, "msDS-KeyVersionNumber", kvno + 1));
690 if (pwdHistoryLength == 0) {
691 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHistory"));
692 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHistory"));
696 /* store the password history */
697 new_lmPwdHistory = talloc_array(mem_ctx, struct samr_Password,
699 if (!new_lmPwdHistory) {
700 return NT_STATUS_NO_MEMORY;
702 new_ntPwdHistory = talloc_array(mem_ctx, struct samr_Password,
704 if (!new_ntPwdHistory) {
705 return NT_STATUS_NO_MEMORY;
707 for (i=0;i<MIN(pwdHistoryLength-1, lmPwdHistory_len);i++) {
708 new_lmPwdHistory[i+1] = lmPwdHistory[i];
710 for (i=0;i<MIN(pwdHistoryLength-1, ntPwdHistory_len);i++) {
711 new_ntPwdHistory[i+1] = ntPwdHistory[i];
714 /* Don't store 'long' passwords in the LM history,
715 but make sure to 'expire' one password off the other end */
717 new_lmPwdHistory[0] = *lmNewHash;
719 ZERO_STRUCT(new_lmPwdHistory[0]);
721 lmPwdHistory_len = MIN(lmPwdHistory_len + 1, pwdHistoryLength);
724 new_ntPwdHistory[0] = *ntNewHash;
726 ZERO_STRUCT(new_ntPwdHistory[0]);
728 ntPwdHistory_len = MIN(ntPwdHistory_len + 1, pwdHistoryLength);
730 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
735 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
743 set password via a samr_CryptPassword buffer
744 this will in the 'msg' with modify operations that will update the user
745 password when applied
747 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
749 const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
751 struct ldb_message *msg,
752 struct samr_CryptPassword *pwbuf)
756 uint32_t new_pass_len;
757 DATA_BLOB session_key = data_blob(NULL, 0);
759 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
760 if (!NT_STATUS_IS_OK(nt_status)) {
764 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
766 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
767 &new_pass_len, STR_UNICODE)) {
768 DEBUG(3,("samr: failed to decode password buffer\n"));
769 return NT_STATUS_WRONG_PASSWORD;
772 /* set the password - samdb needs to know both the domain and user DNs,
773 so the domain password policy can be used */
774 return samdb_set_password(sam_ctx, mem_ctx,
775 account_dn, domain_dn,
778 False, /* This is a password set, not change */
779 True, /* run restriction tests */
785 set password via a samr_CryptPasswordEx buffer
786 this will in the 'msg' with modify operations that will update the user
787 password when applied
789 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
791 const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
793 struct ldb_message *msg,
794 struct samr_CryptPasswordEx *pwbuf)
798 uint32_t new_pass_len;
799 DATA_BLOB co_session_key;
800 DATA_BLOB session_key = data_blob(NULL, 0);
801 struct MD5Context ctx;
803 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
804 if (!NT_STATUS_IS_OK(nt_status)) {
808 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
809 if (!co_session_key.data) {
810 return NT_STATUS_NO_MEMORY;
814 MD5Update(&ctx, &pwbuf->data[516], 16);
815 MD5Update(&ctx, session_key.data, session_key.length);
816 MD5Final(co_session_key.data, &ctx);
818 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
820 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
821 &new_pass_len, STR_UNICODE)) {
822 DEBUG(3,("samr: failed to decode password buffer\n"));
823 return NT_STATUS_WRONG_PASSWORD;
826 /* set the password - samdb needs to know both the domain and user DNs,
827 so the domain password policy can be used */
828 return samdb_set_password(sam_ctx, mem_ctx,
829 account_dn, domain_dn,
832 False, /* This is a password set, not change */
833 True, /* run restriction tests */