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, *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;
105 msg = ldb_msg_new(mem_ctx);
107 return NT_STATUS_NO_MEMORY;
110 msg->dn = talloc_strdup(msg, a_state->account_dn);
112 return NT_STATUS_NO_MEMORY;
115 status = samdb_set_password(a_state->sam_ctx, mem_ctx,
116 a_state->account_dn, a_state->domain_state->domain_dn,
117 msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
119 if (!NT_STATUS_IS_OK(status)) {
123 /* modify the samdb record */
124 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
126 return NT_STATUS_UNSUCCESSFUL;
133 samr_OemChangePasswordUser2
135 NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
136 struct samr_OemChangePasswordUser2 *r)
140 uint32_t new_pass_len;
141 struct samr_CryptPassword *pwbuf = r->in.password;
143 const char *user_dn, *domain_dn;
145 struct ldb_message **res, *mod;
146 const char * const attrs[] = { "objectSid", "lmPwdHash", "unicodePwd", NULL };
147 const char *domain_sid;
148 struct samr_Password *lm_pwd;
149 DATA_BLOB lm_pwd_blob;
150 uint8_t new_lm_hash[16];
151 struct samr_Password lm_verifier;
154 return NT_STATUS_WRONG_PASSWORD;
157 /* this call doesn't take a policy handle, so we need to open
158 the sam db from scratch */
159 sam_ctx = samdb_connect(mem_ctx);
160 if (sam_ctx == NULL) {
161 return NT_STATUS_INVALID_SYSTEM_SERVICE;
164 /* we need the users dn and the domain dn (derived from the
165 user SID). We also need the current lm password hash in
166 order to decrypt the incoming password */
167 ret = samdb_search(sam_ctx,
168 mem_ctx, NULL, &res, attrs,
169 "(&(sAMAccountName=%s)(objectclass=user))",
170 r->in.account->string);
172 return NT_STATUS_NO_SUCH_USER;
175 user_dn = res[0]->dn;
177 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
178 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
179 return NT_STATUS_WRONG_PASSWORD;
182 /* decrypt the password we have been given */
183 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
184 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
185 data_blob_free(&lm_pwd_blob);
187 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
188 &new_pass_len, STR_ASCII)) {
189 DEBUG(3,("samr: failed to decode password buffer\n"));
190 return NT_STATUS_WRONG_PASSWORD;
193 /* check LM verifier */
194 if (lm_pwd == NULL || r->in.hash == NULL) {
195 return NT_STATUS_WRONG_PASSWORD;
198 E_deshash(new_pass, new_lm_hash);
199 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
200 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
201 return NT_STATUS_WRONG_PASSWORD;
204 /* work out the domain dn */
205 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
206 if (domain_sid == NULL) {
207 return NT_STATUS_NO_SUCH_USER;
210 domain_dn = samdb_search_string(sam_ctx, mem_ctx, NULL, "dn",
211 "(objectSid=%s)", domain_sid);
213 return NT_STATUS_INTERNAL_DB_CORRUPTION;
216 mod = ldb_msg_new(mem_ctx);
218 return NT_STATUS_NO_MEMORY;
221 mod->dn = talloc_strdup(mod, user_dn);
223 return NT_STATUS_NO_MEMORY;
226 /* set the password - samdb needs to know both the domain and user DNs,
227 so the domain password policy can be used */
228 status = samdb_set_password(sam_ctx, mem_ctx,
233 if (!NT_STATUS_IS_OK(status)) {
237 /* modify the samdb record */
238 ret = samdb_replace(sam_ctx, mem_ctx, mod);
240 return NT_STATUS_UNSUCCESSFUL;
248 samr_ChangePasswordUser3
250 NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
252 struct samr_ChangePasswordUser3 *r)
256 uint32_t new_pass_len;
257 void *sam_ctx = NULL;
258 const char *user_dn, *domain_dn = NULL;
260 struct ldb_message **res, *mod;
261 const char * const attrs[] = { "objectSid", "ntPwdHash", "lmPwdHash", "unicodePwd", NULL };
262 const char * const dom_attrs[] = { "minPwdLength", "pwdHistoryLength",
263 "pwdProperties", "minPwdAge", "maxPwdAge",
265 const char *domain_sid;
266 struct samr_Password *nt_pwd, *lm_pwd;
267 DATA_BLOB nt_pwd_blob;
268 struct samr_DomInfo1 *dominfo;
269 struct samr_ChangeReject *reject;
271 uint8_t new_nt_hash[16], new_lm_hash[16];
272 struct samr_Password nt_verifier, lm_verifier;
276 if (r->in.nt_password == NULL ||
277 r->in.nt_verifier == NULL) {
278 status = NT_STATUS_INVALID_PARAMETER;
282 /* this call doesn't take a policy handle, so we need to open
283 the sam db from scratch */
284 sam_ctx = samdb_connect(mem_ctx);
285 if (sam_ctx == NULL) {
286 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
290 /* we need the users dn and the domain dn (derived from the
291 user SID). We also need the current lm and nt password hashes
292 in order to decrypt the incoming passwords */
293 ret = samdb_search(sam_ctx,
294 mem_ctx, NULL, &res, attrs,
295 "(&(sAMAccountName=%s)(objectclass=user))",
296 r->in.account->string);
298 status = NT_STATUS_NO_SUCH_USER;
302 user_dn = res[0]->dn;
304 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
305 if (!NT_STATUS_IS_OK(status) ) {
310 status = NT_STATUS_WRONG_PASSWORD;
314 /* decrypt the password we have been given */
315 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
316 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
317 data_blob_free(&nt_pwd_blob);
319 if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
320 &new_pass_len, STR_UNICODE)) {
321 DEBUG(3,("samr: failed to decode password buffer\n"));
322 status = NT_STATUS_WRONG_PASSWORD;
326 if (r->in.nt_verifier == NULL) {
327 status = NT_STATUS_WRONG_PASSWORD;
331 /* check NT verifier */
332 E_md4hash(new_pass, new_nt_hash);
333 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
334 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
335 status = NT_STATUS_WRONG_PASSWORD;
339 /* check LM verifier */
340 if (lm_pwd && r->in.lm_verifier != NULL) {
341 E_deshash(new_pass, new_lm_hash);
342 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
343 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
344 status = NT_STATUS_WRONG_PASSWORD;
350 /* work out the domain dn */
351 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
352 if (domain_sid == NULL) {
353 status = NT_STATUS_NO_SUCH_DOMAIN;
357 domain_dn = samdb_search_string(sam_ctx, mem_ctx, NULL, "dn",
358 "(objectSid=%s)", domain_sid);
360 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
364 mod = ldb_msg_new(mem_ctx);
366 return NT_STATUS_NO_MEMORY;
369 mod->dn = talloc_strdup(mod, user_dn);
371 status = NT_STATUS_NO_MEMORY;
375 /* set the password - samdb needs to know both the domain and user DNs,
376 so the domain password policy can be used */
377 status = samdb_set_password(sam_ctx, mem_ctx,
382 if (!NT_STATUS_IS_OK(status)) {
386 /* modify the samdb record */
387 ret = samdb_replace(sam_ctx, mem_ctx, mod);
389 status = NT_STATUS_UNSUCCESSFUL;
396 ret = samdb_search(sam_ctx,
397 mem_ctx, NULL, &res, dom_attrs,
404 /* on failure we need to fill in the reject reasons */
405 dominfo = talloc_p(mem_ctx, struct samr_DomInfo1);
406 if (dominfo == NULL) {
409 reject = talloc_p(mem_ctx, struct samr_ChangeReject);
410 if (reject == NULL) {
414 ZERO_STRUCTP(dominfo);
415 ZERO_STRUCTP(reject);
417 reject->reason = reason;
419 r->out.dominfo = dominfo;
420 r->out.reject = reject;
426 dominfo->min_password_length = samdb_result_uint (res[0], "minPwdLength", 0);
427 dominfo->password_properties = samdb_result_uint (res[0], "pwdProperties", 0);
428 dominfo->password_history_length = samdb_result_uint (res[0], "pwdHistoryLength", 0);
429 dominfo->max_password_age = samdb_result_int64(res[0], "maxPwdAge", 0);
430 dominfo->min_password_age = samdb_result_int64(res[0], "minPwdAge", 0);
437 samr_ChangePasswordUser2
439 easy - just a subset of samr_ChangePasswordUser3
441 NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
442 struct samr_ChangePasswordUser2 *r)
444 struct samr_ChangePasswordUser3 r2;
446 r2.in.server = r->in.server;
447 r2.in.account = r->in.account;
448 r2.in.nt_password = r->in.nt_password;
449 r2.in.nt_verifier = r->in.nt_verifier;
450 r2.in.lm_change = r->in.lm_change;
451 r2.in.lm_password = r->in.lm_password;
452 r2.in.lm_verifier = r->in.lm_verifier;
453 r2.in.password3 = NULL;
455 return samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
460 check that a password is sufficiently complex
462 static BOOL samdb_password_complexity_ok(const char *pass)
464 return check_password_quality(pass);
468 set the user password using plaintext, obeying any user or domain
469 password restrictions
471 note that this function doesn't actually store the result in the
472 database, it just fills in the "mod" structure with ldb modify
473 elements to setup the correct change when samdb_replace() is
474 called. This allows the caller to combine the change with other
475 changes (as is needed by some of the set user info levels)
477 NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
478 const char *user_dn, const char *domain_dn,
479 struct ldb_message *mod,
480 const char *new_pass,
481 struct samr_Password *lmNewHash,
482 struct samr_Password *ntNewHash,
484 uint32_t *reject_reason)
486 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
487 "ntPwdHistory", "unicodePwd",
488 "lmPwdHash", "ntPwdHash", "badPwdCount",
490 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
491 "maxPwdAge", "minPwdAge",
492 "minPwdLength", "pwdLastSet", NULL };
493 const char *unicodePwd;
496 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
497 uint_t userAccountControl, badPwdCount;
498 struct samr_Password *lmPwdHistory, *ntPwdHistory, lmPwdHash, ntPwdHash;
499 struct samr_Password *new_lmPwdHistory, *new_ntPwdHistory;
500 struct samr_Password local_lmNewHash, local_ntNewHash;
501 int lmPwdHistory_len, ntPwdHistory_len;
502 struct ldb_message **res;
504 time_t now = time(NULL);
508 /* we need to know the time to compute password age */
509 unix_to_nt_time(&now_nt, now);
511 /* pull all the user parameters */
512 count = samdb_search(ctx, mem_ctx, NULL, &res, user_attrs, "dn=%s", user_dn);
514 return NT_STATUS_INTERNAL_DB_CORRUPTION;
516 unicodePwd = samdb_result_string(res[0], "unicodePwd", NULL);
517 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
518 badPwdCount = samdb_result_uint(res[0], "badPwdCount", 0);
519 lmPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
520 "lmPwdHistory", &lmPwdHistory);
521 ntPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
522 "ntPwdHistory", &ntPwdHistory);
523 lmPwdHash = samdb_result_hash(res[0], "lmPwdHash");
524 ntPwdHash = samdb_result_hash(res[0], "ntPwdHash");
525 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
527 /* pull the domain parameters */
528 count = samdb_search(ctx, mem_ctx, NULL, &res, domain_attrs, "dn=%s", domain_dn);
530 return NT_STATUS_INTERNAL_DB_CORRUPTION;
532 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
533 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
534 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
535 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
538 /* check the various password restrictions */
539 if (minPwdLength > strlen_m(new_pass)) {
541 *reject_reason = SAMR_REJECT_TOO_SHORT;
543 return NT_STATUS_PASSWORD_RESTRICTION;
546 /* possibly check password complexity */
547 if (pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
548 !samdb_password_complexity_ok(new_pass)) {
550 *reject_reason = SAMR_REJECT_COMPLEXITY;
552 return NT_STATUS_PASSWORD_RESTRICTION;
555 /* compute the new nt and lm hashes */
556 if (E_deshash(new_pass, local_lmNewHash.hash)) {
557 lmNewHash = &local_lmNewHash;
559 E_md4hash(new_pass, local_ntNewHash.hash);
560 ntNewHash = &local_ntNewHash;
564 /* are all password changes disallowed? */
565 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
567 *reject_reason = SAMR_REJECT_OTHER;
569 return NT_STATUS_PASSWORD_RESTRICTION;
572 /* can this user change password? */
573 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
575 *reject_reason = SAMR_REJECT_OTHER;
577 return NT_STATUS_PASSWORD_RESTRICTION;
580 /* yes, this is a minus. The ages are in negative 100nsec units! */
581 if (pwdLastSet - minPwdAge > now_nt) {
583 *reject_reason = SAMR_REJECT_OTHER;
585 return NT_STATUS_PASSWORD_RESTRICTION;
588 /* check the immediately past password */
589 if (pwdHistoryLength > 0) {
590 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
592 *reject_reason = SAMR_REJECT_COMPLEXITY;
594 return NT_STATUS_PASSWORD_RESTRICTION;
596 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
598 *reject_reason = SAMR_REJECT_COMPLEXITY;
600 return NT_STATUS_PASSWORD_RESTRICTION;
604 /* check the password history */
605 lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength);
606 ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength);
608 if (pwdHistoryLength > 0) {
609 if (unicodePwd && new_pass && strcmp(unicodePwd, new_pass) == 0) {
611 *reject_reason = SAMR_REJECT_COMPLEXITY;
613 return NT_STATUS_PASSWORD_RESTRICTION;
615 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
617 *reject_reason = SAMR_REJECT_COMPLEXITY;
619 return NT_STATUS_PASSWORD_RESTRICTION;
621 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
623 *reject_reason = SAMR_REJECT_COMPLEXITY;
625 return NT_STATUS_PASSWORD_RESTRICTION;
629 for (i=0; lmNewHash && i<lmPwdHistory_len;i++) {
630 if (memcmp(lmNewHash->hash, lmPwdHistory[i].hash, 16) == 0) {
632 *reject_reason = SAMR_REJECT_COMPLEXITY;
634 return NT_STATUS_PASSWORD_RESTRICTION;
637 for (i=0; ntNewHash && i<ntPwdHistory_len;i++) {
638 if (memcmp(ntNewHash->hash, ntPwdHistory[i].hash, 16) == 0) {
640 *reject_reason = SAMR_REJECT_COMPLEXITY;
642 return NT_STATUS_PASSWORD_RESTRICTION;
647 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
649 /* the password is acceptable. Start forming the new fields */
651 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", *lmNewHash));
653 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
657 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", *ntNewHash));
659 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
662 if (new_pass && (pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT) &&
663 (userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
664 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
665 "unicodePwd", new_pass));
667 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
670 CHECK_RET(samdb_msg_add_uint64(ctx, mem_ctx, mod, "pwdLastSet", now_nt));
672 if (pwdHistoryLength == 0) {
673 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHistory"));
674 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHistory"));
678 /* store the password history */
679 new_lmPwdHistory = talloc_array_p(mem_ctx, struct samr_Password,
681 if (!new_lmPwdHistory) {
682 return NT_STATUS_NO_MEMORY;
684 new_ntPwdHistory = talloc_array_p(mem_ctx, struct samr_Password,
686 if (!new_ntPwdHistory) {
687 return NT_STATUS_NO_MEMORY;
689 for (i=0;i<MIN(pwdHistoryLength-1, lmPwdHistory_len);i++) {
690 new_lmPwdHistory[i+1] = lmPwdHistory[i];
692 for (i=0;i<MIN(pwdHistoryLength-1, ntPwdHistory_len);i++) {
693 new_ntPwdHistory[i+1] = ntPwdHistory[i];
696 /* Don't store 'long' passwords in the LM history,
697 but make sure to 'expire' one password off the other end */
699 new_lmPwdHistory[0] = *lmNewHash;
701 ZERO_STRUCT(new_lmPwdHistory[0]);
703 lmPwdHistory_len = MIN(lmPwdHistory_len + 1, pwdHistoryLength);
706 new_ntPwdHistory[0] = *ntNewHash;
708 ZERO_STRUCT(new_ntPwdHistory[0]);
710 ntPwdHistory_len = MIN(ntPwdHistory_len + 1, pwdHistoryLength);
712 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
717 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
725 set password via a samr_CryptPassword buffer
726 this will in the 'msg' with modify operations that will update the user
727 password when applied
729 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
731 const char *account_dn, const char *domain_dn,
733 struct ldb_message *msg,
734 struct samr_CryptPassword *pwbuf)
738 uint32_t new_pass_len;
739 DATA_BLOB session_key = data_blob(NULL, 0);
741 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
742 if (!NT_STATUS_IS_OK(nt_status)) {
746 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
748 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
749 &new_pass_len, STR_UNICODE)) {
750 DEBUG(3,("samr: failed to decode password buffer\n"));
751 return NT_STATUS_WRONG_PASSWORD;
754 /* set the password - samdb needs to know both the domain and user DNs,
755 so the domain password policy can be used */
756 return samdb_set_password(sam_ctx, mem_ctx,
757 account_dn, domain_dn,
760 False /* This is a password set, not change */,
766 set password via a samr_CryptPasswordEx buffer
767 this will in the 'msg' with modify operations that will update the user
768 password when applied
770 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
772 const char *account_dn, const char *domain_dn,
774 struct ldb_message *msg,
775 struct samr_CryptPasswordEx *pwbuf)
779 uint32_t new_pass_len;
780 DATA_BLOB co_session_key;
781 DATA_BLOB session_key = data_blob(NULL, 0);
782 struct MD5Context ctx;
784 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
785 if (!NT_STATUS_IS_OK(nt_status)) {
789 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
790 if (!co_session_key.data) {
791 return NT_STATUS_NO_MEMORY;
795 MD5Update(&ctx, &pwbuf->data[516], 16);
796 MD5Update(&ctx, session_key.data, session_key.length);
797 MD5Final(co_session_key.data, &ctx);
799 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
801 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
802 &new_pass_len, STR_UNICODE)) {
803 DEBUG(3,("samr: failed to decode password buffer\n"));
804 return NT_STATUS_WRONG_PASSWORD;
807 /* set the password - samdb needs to know both the domain and user DNs,
808 so the domain password policy can be used */
809 return samdb_set_password(sam_ctx, mem_ctx,
810 account_dn, domain_dn,