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"
33 samr_ChangePasswordUser
35 NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
36 struct samr_ChangePasswordUser *r)
38 struct dcesrv_handle *h;
39 struct samr_account_state *a_state;
40 struct ldb_message **res, mod, *msg;
42 struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
43 struct samr_Password *lm_pwd, *nt_pwd;
44 NTSTATUS status = NT_STATUS_OK;
45 const char * const attrs[] = { "lmPwdHash", "ntPwdHash" , "unicodePwd", NULL };
47 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
51 /* fetch the old hashes */
52 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
53 "dn=%s", a_state->account_dn);
55 return NT_STATUS_INTERNAL_DB_CORRUPTION;
59 /* basic sanity checking on parameters */
60 if (!r->in.lm_present || !r->in.nt_present ||
61 !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
62 !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
63 /* we should really handle a change with lm not
65 return NT_STATUS_INVALID_PARAMETER_MIX;
67 if (!r->in.cross1_present || !r->in.nt_cross) {
68 return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED;
70 if (!r->in.cross2_present || !r->in.lm_cross) {
71 return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED;
74 status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
75 if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
76 return NT_STATUS_WRONG_PASSWORD;
79 /* decrypt and check the new lm hash */
80 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
81 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
82 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
83 return NT_STATUS_WRONG_PASSWORD;
86 /* decrypt and check the new nt hash */
87 D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
88 D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
89 if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
90 return NT_STATUS_WRONG_PASSWORD;
93 /* check the nt cross hash */
94 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
95 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
96 return NT_STATUS_WRONG_PASSWORD;
99 /* check the lm cross hash */
100 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
101 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
102 return NT_STATUS_WRONG_PASSWORD;
106 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
108 return NT_STATUS_NO_MEMORY;
111 status = samdb_set_password(a_state->sam_ctx, mem_ctx,
112 a_state->account_dn, a_state->domain_state->domain_dn,
113 &mod, NULL, &new_lmPwdHash, &new_ntPwdHash,
115 if (!NT_STATUS_IS_OK(status)) {
119 /* modify the samdb record */
120 ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
122 return NT_STATUS_UNSUCCESSFUL;
129 samr_OemChangePasswordUser2
131 NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
132 struct samr_OemChangePasswordUser2 *r)
136 uint32_t new_pass_len;
137 struct samr_CryptPassword *pwbuf = r->in.password;
139 const char *user_dn, *domain_dn;
141 struct ldb_message **res, mod;
142 const char * const attrs[] = { "objectSid", "lmPwdHash", "unicodePwd", NULL };
143 const char *domain_sid;
144 struct samr_Password *lm_pwd;
145 DATA_BLOB lm_pwd_blob;
146 uint8_t new_lm_hash[16];
147 struct samr_Password lm_verifier;
150 return NT_STATUS_WRONG_PASSWORD;
153 /* this call doesn't take a policy handle, so we need to open
154 the sam db from scratch */
155 sam_ctx = samdb_connect(mem_ctx);
156 if (sam_ctx == NULL) {
157 return NT_STATUS_INVALID_SYSTEM_SERVICE;
160 /* we need the users dn and the domain dn (derived from the
161 user SID). We also need the current lm password hash in
162 order to decrypt the incoming password */
163 ret = samdb_search(sam_ctx,
164 mem_ctx, NULL, &res, attrs,
165 "(&(sAMAccountName=%s)(objectclass=user))",
166 r->in.account->string);
168 return NT_STATUS_NO_SUCH_USER;
171 user_dn = res[0]->dn;
173 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
174 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
175 return NT_STATUS_WRONG_PASSWORD;
178 /* decrypt the password we have been given */
179 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
180 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
181 data_blob_free(&lm_pwd_blob);
183 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
184 &new_pass_len, STR_ASCII)) {
185 DEBUG(3,("samr: failed to decode password buffer\n"));
186 return NT_STATUS_WRONG_PASSWORD;
189 /* check LM verifier */
190 if (lm_pwd == NULL || r->in.hash == NULL) {
191 return NT_STATUS_WRONG_PASSWORD;
194 E_deshash(new_pass, new_lm_hash);
195 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
196 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
197 return NT_STATUS_WRONG_PASSWORD;
200 /* work out the domain dn */
201 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
202 if (domain_sid == NULL) {
203 return NT_STATUS_NO_SUCH_USER;
206 domain_dn = samdb_search_string(sam_ctx, mem_ctx, NULL, "dn",
207 "(objectSid=%s)", domain_sid);
209 return NT_STATUS_INTERNAL_DB_CORRUPTION;
214 mod.dn = talloc_strdup(mem_ctx, user_dn);
216 return NT_STATUS_NO_MEMORY;
219 /* set the password - samdb needs to know both the domain and user DNs,
220 so the domain password policy can be used */
221 status = samdb_set_password(sam_ctx, mem_ctx,
226 if (!NT_STATUS_IS_OK(status)) {
230 /* modify the samdb record */
231 ret = samdb_replace(sam_ctx, mem_ctx, &mod);
233 return NT_STATUS_UNSUCCESSFUL;
241 samr_ChangePasswordUser3
243 NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
245 struct samr_ChangePasswordUser3 *r)
249 uint32_t new_pass_len;
250 void *sam_ctx = NULL;
251 const char *user_dn, *domain_dn = NULL;
253 struct ldb_message **res, mod;
254 const char * const attrs[] = { "objectSid", "ntPwdHash", "lmPwdHash", "unicodePwd", NULL };
255 const char * const dom_attrs[] = { "minPwdLength", "pwdHistoryLength",
256 "pwdProperties", "minPwdAge", "maxPwdAge",
258 const char *domain_sid;
259 struct samr_Password *nt_pwd, *lm_pwd;
260 DATA_BLOB nt_pwd_blob;
261 struct samr_DomInfo1 *dominfo;
262 struct samr_ChangeReject *reject;
264 uint8_t new_nt_hash[16], new_lm_hash[16];
265 struct samr_Password nt_verifier, lm_verifier;
269 if (r->in.nt_password == NULL ||
270 r->in.nt_verifier == NULL) {
271 status = NT_STATUS_INVALID_PARAMETER;
275 /* this call doesn't take a policy handle, so we need to open
276 the sam db from scratch */
277 sam_ctx = samdb_connect(mem_ctx);
278 if (sam_ctx == NULL) {
279 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
283 /* we need the users dn and the domain dn (derived from the
284 user SID). We also need the current lm and nt password hashes
285 in order to decrypt the incoming passwords */
286 ret = samdb_search(sam_ctx,
287 mem_ctx, NULL, &res, attrs,
288 "(&(sAMAccountName=%s)(objectclass=user))",
289 r->in.account->string);
291 status = NT_STATUS_NO_SUCH_USER;
295 user_dn = res[0]->dn;
297 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
298 if (!NT_STATUS_IS_OK(status) ) {
303 status = NT_STATUS_WRONG_PASSWORD;
307 /* decrypt the password we have been given */
308 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
309 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
310 data_blob_free(&nt_pwd_blob);
312 if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
313 &new_pass_len, STR_UNICODE)) {
314 DEBUG(3,("samr: failed to decode password buffer\n"));
315 status = NT_STATUS_WRONG_PASSWORD;
319 if (r->in.nt_verifier == NULL) {
320 status = NT_STATUS_WRONG_PASSWORD;
324 /* check NT verifier */
325 E_md4hash(new_pass, new_nt_hash);
326 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
327 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
328 status = NT_STATUS_WRONG_PASSWORD;
332 /* check LM verifier */
333 if (lm_pwd && r->in.lm_verifier != NULL) {
334 E_deshash(new_pass, new_lm_hash);
335 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
336 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
337 status = NT_STATUS_WRONG_PASSWORD;
343 /* work out the domain dn */
344 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
345 if (domain_sid == NULL) {
346 status = NT_STATUS_NO_SUCH_DOMAIN;
350 domain_dn = samdb_search_string(sam_ctx, mem_ctx, NULL, "dn",
351 "(objectSid=%s)", domain_sid);
353 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
359 mod.dn = talloc_strdup(mem_ctx, user_dn);
361 status = NT_STATUS_NO_MEMORY;
365 /* set the password - samdb needs to know both the domain and user DNs,
366 so the domain password policy can be used */
367 status = samdb_set_password(sam_ctx, mem_ctx,
372 if (!NT_STATUS_IS_OK(status)) {
376 /* modify the samdb record */
377 ret = samdb_replace(sam_ctx, mem_ctx, &mod);
379 status = NT_STATUS_UNSUCCESSFUL;
386 ret = samdb_search(sam_ctx,
387 mem_ctx, NULL, &res, dom_attrs,
394 /* on failure we need to fill in the reject reasons */
395 dominfo = talloc_p(mem_ctx, struct samr_DomInfo1);
396 if (dominfo == NULL) {
399 reject = talloc_p(mem_ctx, struct samr_ChangeReject);
400 if (reject == NULL) {
404 ZERO_STRUCTP(dominfo);
405 ZERO_STRUCTP(reject);
407 reject->reason = reason;
409 r->out.dominfo = dominfo;
410 r->out.reject = reject;
416 dominfo->min_password_length = samdb_result_uint (res[0], "minPwdLength", 0);
417 dominfo->password_properties = samdb_result_uint (res[0], "pwdProperties", 0);
418 dominfo->password_history_length = samdb_result_uint (res[0], "pwdHistoryLength", 0);
419 dominfo->max_password_age = samdb_result_int64(res[0], "maxPwdAge", 0);
420 dominfo->min_password_age = samdb_result_int64(res[0], "minPwdAge", 0);
427 samr_ChangePasswordUser2
429 easy - just a subset of samr_ChangePasswordUser3
431 NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
432 struct samr_ChangePasswordUser2 *r)
434 struct samr_ChangePasswordUser3 r2;
436 r2.in.server = r->in.server;
437 r2.in.account = r->in.account;
438 r2.in.nt_password = r->in.nt_password;
439 r2.in.nt_verifier = r->in.nt_verifier;
440 r2.in.lm_change = r->in.lm_change;
441 r2.in.lm_password = r->in.lm_password;
442 r2.in.lm_verifier = r->in.lm_verifier;
443 r2.in.password3 = NULL;
445 return samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
450 check that a password is sufficiently complex
452 static BOOL samdb_password_complexity_ok(const char *pass)
454 return check_password_quality(pass);
458 set the user password using plaintext, obeying any user or domain
459 password restrictions
461 note that this function doesn't actually store the result in the
462 database, it just fills in the "mod" structure with ldb modify
463 elements to setup the correct change when samdb_replace() is
464 called. This allows the caller to combine the change with other
465 changes (as is needed by some of the set user info levels)
467 NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
468 const char *user_dn, const char *domain_dn,
469 struct ldb_message *mod,
470 const char *new_pass,
471 struct samr_Password *lmNewHash,
472 struct samr_Password *ntNewHash,
474 uint32_t *reject_reason)
476 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
477 "ntPwdHistory", "unicodePwd",
478 "lmPwdHash", "ntPwdHash", "badPwdCount",
480 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
481 "maxPwdAge", "minPwdAge",
482 "minPwdLength", "pwdLastSet", NULL };
483 const char *unicodePwd;
486 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
487 uint_t userAccountControl, badPwdCount;
488 struct samr_Password *lmPwdHistory, *ntPwdHistory, lmPwdHash, ntPwdHash;
489 struct samr_Password *new_lmPwdHistory, *new_ntPwdHistory;
490 struct samr_Password local_lmNewHash, local_ntNewHash;
491 int lmPwdHistory_len, ntPwdHistory_len;
492 struct ldb_message **res;
494 time_t now = time(NULL);
498 /* we need to know the time to compute password age */
499 unix_to_nt_time(&now_nt, now);
501 /* pull all the user parameters */
502 count = samdb_search(ctx, mem_ctx, NULL, &res, user_attrs, "dn=%s", user_dn);
504 return NT_STATUS_INTERNAL_DB_CORRUPTION;
506 unicodePwd = samdb_result_string(res[0], "unicodePwd", NULL);
507 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
508 badPwdCount = samdb_result_uint(res[0], "badPwdCount", 0);
509 lmPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
510 "lmPwdHistory", &lmPwdHistory);
511 ntPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
512 "ntPwdHistory", &ntPwdHistory);
513 lmPwdHash = samdb_result_hash(res[0], "lmPwdHash");
514 ntPwdHash = samdb_result_hash(res[0], "ntPwdHash");
515 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
517 /* pull the domain parameters */
518 count = samdb_search(ctx, mem_ctx, NULL, &res, domain_attrs, "dn=%s", domain_dn);
520 return NT_STATUS_INTERNAL_DB_CORRUPTION;
522 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
523 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
524 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
525 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
528 /* check the various password restrictions */
529 if (minPwdLength > strlen_m(new_pass)) {
531 *reject_reason = SAMR_REJECT_TOO_SHORT;
533 return NT_STATUS_PASSWORD_RESTRICTION;
536 /* possibly check password complexity */
537 if (pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
538 !samdb_password_complexity_ok(new_pass)) {
540 *reject_reason = SAMR_REJECT_COMPLEXITY;
542 return NT_STATUS_PASSWORD_RESTRICTION;
545 /* compute the new nt and lm hashes */
546 if (E_deshash(new_pass, local_lmNewHash.hash)) {
547 lmNewHash = &local_lmNewHash;
549 E_md4hash(new_pass, local_ntNewHash.hash);
550 ntNewHash = &local_ntNewHash;
554 /* are all password changes disallowed? */
555 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
557 *reject_reason = SAMR_REJECT_OTHER;
559 return NT_STATUS_PASSWORD_RESTRICTION;
562 /* can this user change password? */
563 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
565 *reject_reason = SAMR_REJECT_OTHER;
567 return NT_STATUS_PASSWORD_RESTRICTION;
570 /* yes, this is a minus. The ages are in negative 100nsec units! */
571 if (pwdLastSet - minPwdAge > now_nt) {
573 *reject_reason = SAMR_REJECT_OTHER;
575 return NT_STATUS_PASSWORD_RESTRICTION;
578 /* check the immediately past password */
579 if (pwdHistoryLength > 0) {
580 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
582 *reject_reason = SAMR_REJECT_COMPLEXITY;
584 return NT_STATUS_PASSWORD_RESTRICTION;
586 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
588 *reject_reason = SAMR_REJECT_COMPLEXITY;
590 return NT_STATUS_PASSWORD_RESTRICTION;
594 /* check the password history */
595 lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength);
596 ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength);
598 if (pwdHistoryLength > 0) {
599 if (unicodePwd && new_pass && strcmp(unicodePwd, new_pass) == 0) {
601 *reject_reason = SAMR_REJECT_COMPLEXITY;
603 return NT_STATUS_PASSWORD_RESTRICTION;
605 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
607 *reject_reason = SAMR_REJECT_COMPLEXITY;
609 return NT_STATUS_PASSWORD_RESTRICTION;
611 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
613 *reject_reason = SAMR_REJECT_COMPLEXITY;
615 return NT_STATUS_PASSWORD_RESTRICTION;
619 for (i=0; lmNewHash && i<lmPwdHistory_len;i++) {
620 if (memcmp(lmNewHash->hash, lmPwdHistory[i].hash, 16) == 0) {
622 *reject_reason = SAMR_REJECT_COMPLEXITY;
624 return NT_STATUS_PASSWORD_RESTRICTION;
627 for (i=0; ntNewHash && i<ntPwdHistory_len;i++) {
628 if (memcmp(ntNewHash->hash, ntPwdHistory[i].hash, 16) == 0) {
630 *reject_reason = SAMR_REJECT_COMPLEXITY;
632 return NT_STATUS_PASSWORD_RESTRICTION;
637 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
639 /* the password is acceptable. Start forming the new fields */
641 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", *lmNewHash));
643 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
647 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", *ntNewHash));
649 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
652 if (new_pass && (pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT) &&
653 (userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
654 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
655 "unicodePwd", new_pass));
657 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
660 CHECK_RET(samdb_msg_add_uint64(ctx, mem_ctx, mod, "pwdLastSet", now_nt));
662 if (pwdHistoryLength == 0) {
663 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHistory"));
664 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHistory"));
668 /* store the password history */
669 new_lmPwdHistory = talloc_array_p(mem_ctx, struct samr_Password,
671 if (!new_lmPwdHistory) {
672 return NT_STATUS_NO_MEMORY;
674 new_ntPwdHistory = talloc_array_p(mem_ctx, struct samr_Password,
676 if (!new_ntPwdHistory) {
677 return NT_STATUS_NO_MEMORY;
679 for (i=0;i<MIN(pwdHistoryLength-1, lmPwdHistory_len);i++) {
680 new_lmPwdHistory[i+1] = lmPwdHistory[i];
682 for (i=0;i<MIN(pwdHistoryLength-1, ntPwdHistory_len);i++) {
683 new_ntPwdHistory[i+1] = ntPwdHistory[i];
686 /* Don't store 'long' passwords in the LM history,
687 but make sure to 'expire' one password off the other end */
689 new_lmPwdHistory[0] = *lmNewHash;
691 ZERO_STRUCT(new_lmPwdHistory[0]);
693 lmPwdHistory_len = MIN(lmPwdHistory_len + 1, pwdHistoryLength);
696 new_ntPwdHistory[0] = *ntNewHash;
698 ZERO_STRUCT(new_ntPwdHistory[0]);
700 ntPwdHistory_len = MIN(ntPwdHistory_len + 1, pwdHistoryLength);
702 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
707 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
715 set password via a samr_CryptPassword buffer
716 this will in the 'msg' with modify operations that will update the user
717 password when applied
719 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
721 const char *account_dn, const char *domain_dn,
723 struct ldb_message *msg,
724 struct samr_CryptPassword *pwbuf)
728 uint32_t new_pass_len;
729 DATA_BLOB session_key = data_blob(NULL, 0);
731 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
732 if (!NT_STATUS_IS_OK(nt_status)) {
736 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
738 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
739 &new_pass_len, STR_UNICODE)) {
740 DEBUG(3,("samr: failed to decode password buffer\n"));
741 return NT_STATUS_WRONG_PASSWORD;
744 /* set the password - samdb needs to know both the domain and user DNs,
745 so the domain password policy can be used */
746 return samdb_set_password(sam_ctx, mem_ctx,
747 account_dn, domain_dn,
750 False /* This is a password set, not change */,
756 set password via a samr_CryptPasswordEx buffer
757 this will in the 'msg' with modify operations that will update the user
758 password when applied
760 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
762 const char *account_dn, const char *domain_dn,
764 struct ldb_message *msg,
765 struct samr_CryptPasswordEx *pwbuf)
769 uint32_t new_pass_len;
770 DATA_BLOB co_session_key;
771 DATA_BLOB session_key = data_blob(NULL, 0);
772 struct MD5Context ctx;
774 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
775 if (!NT_STATUS_IS_OK(nt_status)) {
779 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
780 if (!co_session_key.data) {
781 return NT_STATUS_NO_MEMORY;
785 MD5Update(&ctx, &pwbuf->data[516], 16);
786 MD5Update(&ctx, session_key.data, session_key.length);
787 MD5Final(co_session_key.data, &ctx);
789 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
791 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
792 &new_pass_len, STR_UNICODE)) {
793 DEBUG(3,("samr: failed to decode password buffer\n"));
794 return NT_STATUS_WRONG_PASSWORD;
797 /* set the password - samdb needs to know both the domain and user DNs,
798 so the domain password policy can be used */
799 return samdb_set_password(sam_ctx, mem_ctx,
800 account_dn, domain_dn,