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_context *sam_ctx;
42 struct ldb_message **res, *msg;
44 struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
45 struct samr_Password *lm_pwd, *nt_pwd;
46 NTSTATUS status = NT_STATUS_OK;
47 const char * const attrs[] = { "lmPwdHash", "ntPwdHash" , "unicodePwd", NULL };
49 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
53 /* To change a password we need to open as system */
54 sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
55 if (sam_ctx == NULL) {
56 return NT_STATUS_INVALID_SYSTEM_SERVICE;
59 /* fetch the old hashes */
60 ret = gendb_search_dn(sam_ctx, mem_ctx,
61 a_state->account_dn, &res, attrs);
63 return NT_STATUS_INTERNAL_DB_CORRUPTION;
67 /* basic sanity checking on parameters */
68 if (!r->in.lm_present || !r->in.nt_present ||
69 !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
70 !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
71 /* we should really handle a change with lm not
73 return NT_STATUS_INVALID_PARAMETER_MIX;
75 if (!r->in.cross1_present || !r->in.nt_cross) {
76 return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED;
78 if (!r->in.cross2_present || !r->in.lm_cross) {
79 return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED;
82 status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
83 if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
84 return NT_STATUS_WRONG_PASSWORD;
87 /* decrypt and check the new lm hash */
88 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
89 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
90 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
91 return NT_STATUS_WRONG_PASSWORD;
94 /* decrypt and check the new nt hash */
95 D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
96 D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
97 if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
98 return NT_STATUS_WRONG_PASSWORD;
101 /* check the nt cross hash */
102 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
103 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
104 return NT_STATUS_WRONG_PASSWORD;
107 /* check the lm cross hash */
108 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
109 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
110 return NT_STATUS_WRONG_PASSWORD;
113 msg = ldb_msg_new(mem_ctx);
115 return NT_STATUS_NO_MEMORY;
118 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
120 return NT_STATUS_NO_MEMORY;
123 status = samdb_set_password(sam_ctx, mem_ctx,
124 a_state->account_dn, a_state->domain_state->domain_dn,
125 msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
126 True, /* this is a user password change */
127 True, /* run restriction tests */
129 if (!NT_STATUS_IS_OK(status)) {
133 /* modify the samdb record */
134 ret = samdb_replace(sam_ctx, mem_ctx, msg);
136 return NT_STATUS_UNSUCCESSFUL;
143 samr_OemChangePasswordUser2
145 NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
146 struct samr_OemChangePasswordUser2 *r)
150 uint32_t new_pass_len;
151 struct samr_CryptPassword *pwbuf = r->in.password;
152 struct ldb_context *sam_ctx;
153 const struct ldb_dn *user_dn, *domain_dn;
155 struct ldb_message **res, *mod;
156 const char * const attrs[] = { "objectSid", "lmPwdHash", "unicodePwd", NULL };
157 struct samr_Password *lm_pwd;
158 DATA_BLOB lm_pwd_blob;
159 uint8_t new_lm_hash[16];
160 struct samr_Password lm_verifier;
161 struct dom_sid *domain_sid;
164 return NT_STATUS_WRONG_PASSWORD;
167 /* To change a password we need to open as system */
168 sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
169 if (sam_ctx == NULL) {
170 return NT_STATUS_INVALID_SYSTEM_SERVICE;
173 /* we need the users dn and the domain dn (derived from the
174 user SID). We also need the current lm password hash in
175 order to decrypt the incoming password */
176 ret = gendb_search(sam_ctx,
177 mem_ctx, NULL, &res, attrs,
178 "(&(sAMAccountName=%s)(objectclass=user))",
179 r->in.account->string);
181 return NT_STATUS_NO_SUCH_USER;
184 user_dn = res[0]->dn;
186 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
187 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
188 return NT_STATUS_WRONG_PASSWORD;
191 /* decrypt the password we have been given */
192 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
193 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
194 data_blob_free(&lm_pwd_blob);
196 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
197 &new_pass_len, STR_ASCII)) {
198 DEBUG(3,("samr: failed to decode password buffer\n"));
199 return NT_STATUS_WRONG_PASSWORD;
202 /* check LM verifier */
203 if (lm_pwd == NULL || r->in.hash == NULL) {
204 return NT_STATUS_WRONG_PASSWORD;
207 E_deshash(new_pass, new_lm_hash);
208 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
209 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
210 return NT_STATUS_WRONG_PASSWORD;
213 /* work out the domain dn */
214 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
215 if (domain_sid == NULL) {
216 return NT_STATUS_NO_SUCH_USER;
219 domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
221 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
223 return NT_STATUS_INTERNAL_DB_CORRUPTION;
226 mod = ldb_msg_new(mem_ctx);
228 return NT_STATUS_NO_MEMORY;
231 mod->dn = ldb_dn_copy(mod, user_dn);
233 return NT_STATUS_NO_MEMORY;
236 /* set the password - samdb needs to know both the domain and user DNs,
237 so the domain password policy can be used */
238 status = samdb_set_password(sam_ctx, mem_ctx,
242 True, /* this is a user password change */
243 True, /* run restriction tests */
245 if (!NT_STATUS_IS_OK(status)) {
249 /* modify the samdb record */
250 ret = samdb_replace(sam_ctx, mem_ctx, mod);
252 return NT_STATUS_UNSUCCESSFUL;
260 samr_ChangePasswordUser3
262 NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
264 struct samr_ChangePasswordUser3 *r)
268 uint32_t new_pass_len;
269 struct ldb_context *sam_ctx;
270 const struct ldb_dn *user_dn, *domain_dn = NULL;
272 struct ldb_message **res, *mod;
273 const char * const attrs[] = { "objectSid", "ntPwdHash", "lmPwdHash", "unicodePwd", NULL };
274 const char * const dom_attrs[] = { "minPwdLength", "pwdHistoryLength",
275 "pwdProperties", "minPwdAge", "maxPwdAge",
277 struct dom_sid *domain_sid;
278 struct samr_Password *nt_pwd, *lm_pwd;
279 DATA_BLOB nt_pwd_blob;
280 struct samr_DomInfo1 *dominfo;
281 struct samr_ChangeReject *reject;
283 uint8_t new_nt_hash[16], new_lm_hash[16];
284 struct samr_Password nt_verifier, lm_verifier;
288 if (r->in.nt_password == NULL ||
289 r->in.nt_verifier == NULL) {
290 status = NT_STATUS_INVALID_PARAMETER;
294 /* To change a password we need to open as system */
295 sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
296 if (sam_ctx == NULL) {
297 return NT_STATUS_INVALID_SYSTEM_SERVICE;
301 /* we need the users dn and the domain dn (derived from the
302 user SID). We also need the current lm and nt password hashes
303 in order to decrypt the incoming passwords */
304 ret = gendb_search(sam_ctx,
305 mem_ctx, NULL, &res, attrs,
306 "(&(sAMAccountName=%s)(objectclass=user))",
307 r->in.account->string);
309 status = NT_STATUS_NO_SUCH_USER;
313 user_dn = res[0]->dn;
315 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
316 if (!NT_STATUS_IS_OK(status) ) {
321 status = NT_STATUS_WRONG_PASSWORD;
325 /* decrypt the password we have been given */
326 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
327 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
328 data_blob_free(&nt_pwd_blob);
330 if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
331 &new_pass_len, STR_UNICODE)) {
332 DEBUG(3,("samr: failed to decode password buffer\n"));
333 status = NT_STATUS_WRONG_PASSWORD;
337 if (r->in.nt_verifier == NULL) {
338 status = NT_STATUS_WRONG_PASSWORD;
342 /* check NT verifier */
343 E_md4hash(new_pass, new_nt_hash);
344 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
345 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
346 status = NT_STATUS_WRONG_PASSWORD;
350 /* check LM verifier */
351 if (lm_pwd && r->in.lm_verifier != NULL) {
352 E_deshash(new_pass, new_lm_hash);
353 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
354 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
355 status = NT_STATUS_WRONG_PASSWORD;
361 /* work out the domain dn */
362 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
363 if (domain_sid == NULL) {
364 status = NT_STATUS_NO_SUCH_DOMAIN;
368 domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
370 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
372 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
376 mod = ldb_msg_new(mem_ctx);
378 return NT_STATUS_NO_MEMORY;
381 mod->dn = ldb_dn_copy(mod, user_dn);
383 status = NT_STATUS_NO_MEMORY;
387 /* set the password - samdb needs to know both the domain and user DNs,
388 so the domain password policy can be used */
389 status = samdb_set_password(sam_ctx, mem_ctx,
393 True, /* this is a user password change */
394 True, /* run restriction tests */
396 if (!NT_STATUS_IS_OK(status)) {
400 /* modify the samdb record */
401 ret = samdb_replace(sam_ctx, mem_ctx, mod);
403 status = NT_STATUS_UNSUCCESSFUL;
411 ret = gendb_search_dn(sam_ctx, mem_ctx,
412 domain_dn, &res, dom_attrs);
419 /* on failure we need to fill in the reject reasons */
420 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
421 if (dominfo == NULL) {
424 reject = talloc(mem_ctx, struct samr_ChangeReject);
425 if (reject == NULL) {
429 ZERO_STRUCTP(dominfo);
430 ZERO_STRUCTP(reject);
432 reject->reason = reason;
434 r->out.dominfo = dominfo;
435 r->out.reject = reject;
441 dominfo->min_password_length = samdb_result_uint (res[0], "minPwdLength", 0);
442 dominfo->password_properties = samdb_result_uint (res[0], "pwdProperties", 0);
443 dominfo->password_history_length = samdb_result_uint (res[0], "pwdHistoryLength", 0);
444 dominfo->max_password_age = samdb_result_int64(res[0], "maxPwdAge", 0);
445 dominfo->min_password_age = samdb_result_int64(res[0], "minPwdAge", 0);
452 samr_ChangePasswordUser2
454 easy - just a subset of samr_ChangePasswordUser3
456 NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
457 struct samr_ChangePasswordUser2 *r)
459 struct samr_ChangePasswordUser3 r2;
461 r2.in.server = r->in.server;
462 r2.in.account = r->in.account;
463 r2.in.nt_password = r->in.nt_password;
464 r2.in.nt_verifier = r->in.nt_verifier;
465 r2.in.lm_change = r->in.lm_change;
466 r2.in.lm_password = r->in.lm_password;
467 r2.in.lm_verifier = r->in.lm_verifier;
468 r2.in.password3 = NULL;
470 return samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
475 check that a password is sufficiently complex
477 static BOOL samdb_password_complexity_ok(const char *pass)
479 return check_password_quality(pass);
483 set the user password using plaintext, obeying any user or domain
484 password restrictions
486 note that this function doesn't actually store the result in the
487 database, it just fills in the "mod" structure with ldb modify
488 elements to setup the correct change when samdb_replace() is
489 called. This allows the caller to combine the change with other
490 changes (as is needed by some of the set user info levels)
492 NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
493 const struct ldb_dn *user_dn,
494 const struct ldb_dn *domain_dn,
495 struct ldb_message *mod,
496 const char *new_pass,
497 struct samr_Password *lmNewHash,
498 struct samr_Password *ntNewHash,
501 uint32_t *reject_reason)
503 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
504 "ntPwdHistory", "unicodePwd",
505 "lmPwdHash", "ntPwdHash", "badPwdCount",
507 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
508 "maxPwdAge", "minPwdAge",
509 "minPwdLength", "pwdLastSet", NULL };
510 const char *unicodePwd;
513 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
514 uint_t userAccountControl, badPwdCount;
515 struct samr_Password *lmPwdHistory, *ntPwdHistory, lmPwdHash, ntPwdHash;
516 struct samr_Password *new_lmPwdHistory, *new_ntPwdHistory;
517 struct samr_Password local_lmNewHash, local_ntNewHash;
518 int lmPwdHistory_len, ntPwdHistory_len;
520 struct ldb_message **res;
522 time_t now = time(NULL);
526 /* we need to know the time to compute password age */
527 unix_to_nt_time(&now_nt, now);
529 /* pull all the user parameters */
530 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
532 return NT_STATUS_INTERNAL_DB_CORRUPTION;
534 unicodePwd = samdb_result_string(res[0], "unicodePwd", NULL);
535 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
536 badPwdCount = samdb_result_uint(res[0], "badPwdCount", 0);
537 lmPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
538 "lmPwdHistory", &lmPwdHistory);
539 ntPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
540 "ntPwdHistory", &ntPwdHistory);
541 lmPwdHash = samdb_result_hash(res[0], "lmPwdHash");
542 ntPwdHash = samdb_result_hash(res[0], "ntPwdHash");
543 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
544 kvno = samdb_result_uint(res[0], "msDS-KeyVersionNumber", 0);
546 /* pull the domain parameters */
547 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
549 return NT_STATUS_INTERNAL_DB_CORRUPTION;
551 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
552 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
553 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
554 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
557 /* check the various password restrictions */
558 if (restrictions && minPwdLength > strlen_m(new_pass)) {
560 *reject_reason = SAMR_REJECT_TOO_SHORT;
562 return NT_STATUS_PASSWORD_RESTRICTION;
565 /* possibly check password complexity */
566 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
567 !samdb_password_complexity_ok(new_pass)) {
569 *reject_reason = SAMR_REJECT_COMPLEXITY;
571 return NT_STATUS_PASSWORD_RESTRICTION;
574 /* compute the new nt and lm hashes */
575 if (E_deshash(new_pass, local_lmNewHash.hash)) {
576 lmNewHash = &local_lmNewHash;
578 E_md4hash(new_pass, local_ntNewHash.hash);
579 ntNewHash = &local_ntNewHash;
582 if (restrictions && user_change) {
583 /* are all password changes disallowed? */
584 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
586 *reject_reason = SAMR_REJECT_OTHER;
588 return NT_STATUS_PASSWORD_RESTRICTION;
591 /* can this user change password? */
592 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
594 *reject_reason = SAMR_REJECT_OTHER;
596 return NT_STATUS_PASSWORD_RESTRICTION;
599 /* yes, this is a minus. The ages are in negative 100nsec units! */
600 if (pwdLastSet - minPwdAge > now_nt) {
602 *reject_reason = SAMR_REJECT_OTHER;
604 return NT_STATUS_PASSWORD_RESTRICTION;
607 /* check the immediately past password */
608 if (pwdHistoryLength > 0) {
609 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
611 *reject_reason = SAMR_REJECT_COMPLEXITY;
613 return NT_STATUS_PASSWORD_RESTRICTION;
615 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
617 *reject_reason = SAMR_REJECT_COMPLEXITY;
619 return NT_STATUS_PASSWORD_RESTRICTION;
623 /* check the password history */
624 lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength);
625 ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength);
627 if (pwdHistoryLength > 0) {
628 if (unicodePwd && new_pass && strcmp(unicodePwd, new_pass) == 0) {
630 *reject_reason = SAMR_REJECT_COMPLEXITY;
632 return NT_STATUS_PASSWORD_RESTRICTION;
634 if (lmNewHash && memcmp(lmNewHash->hash, lmPwdHash.hash, 16) == 0) {
636 *reject_reason = SAMR_REJECT_COMPLEXITY;
638 return NT_STATUS_PASSWORD_RESTRICTION;
640 if (ntNewHash && memcmp(ntNewHash->hash, ntPwdHash.hash, 16) == 0) {
642 *reject_reason = SAMR_REJECT_COMPLEXITY;
644 return NT_STATUS_PASSWORD_RESTRICTION;
648 for (i=0; lmNewHash && i<lmPwdHistory_len;i++) {
649 if (memcmp(lmNewHash->hash, lmPwdHistory[i].hash, 16) == 0) {
651 *reject_reason = SAMR_REJECT_COMPLEXITY;
653 return NT_STATUS_PASSWORD_RESTRICTION;
656 for (i=0; ntNewHash && i<ntPwdHistory_len;i++) {
657 if (memcmp(ntNewHash->hash, ntPwdHistory[i].hash, 16) == 0) {
659 *reject_reason = SAMR_REJECT_COMPLEXITY;
661 return NT_STATUS_PASSWORD_RESTRICTION;
666 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
668 /* the password is acceptable. Start forming the new fields */
670 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
672 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
676 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
678 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
681 if (new_pass && (pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT) &&
682 (userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
683 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
684 "unicodePwd", new_pass));
686 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
689 CHECK_RET(samdb_msg_add_uint64(ctx, mem_ctx, mod, "pwdLastSet", now_nt));
691 CHECK_RET(samdb_msg_add_uint(ctx, mem_ctx, mod, "msDS-KeyVersionNumber", kvno + 1));
693 if (pwdHistoryLength == 0) {
694 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHistory"));
695 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHistory"));
699 /* store the password history */
700 new_lmPwdHistory = talloc_array(mem_ctx, struct samr_Password,
702 if (!new_lmPwdHistory) {
703 return NT_STATUS_NO_MEMORY;
705 new_ntPwdHistory = talloc_array(mem_ctx, struct samr_Password,
707 if (!new_ntPwdHistory) {
708 return NT_STATUS_NO_MEMORY;
710 for (i=0;i<MIN(pwdHistoryLength-1, lmPwdHistory_len);i++) {
711 new_lmPwdHistory[i+1] = lmPwdHistory[i];
713 for (i=0;i<MIN(pwdHistoryLength-1, ntPwdHistory_len);i++) {
714 new_ntPwdHistory[i+1] = ntPwdHistory[i];
717 /* Don't store 'long' passwords in the LM history,
718 but make sure to 'expire' one password off the other end */
720 new_lmPwdHistory[0] = *lmNewHash;
722 ZERO_STRUCT(new_lmPwdHistory[0]);
724 lmPwdHistory_len = MIN(lmPwdHistory_len + 1, pwdHistoryLength);
727 new_ntPwdHistory[0] = *ntNewHash;
729 ZERO_STRUCT(new_ntPwdHistory[0]);
731 ntPwdHistory_len = MIN(ntPwdHistory_len + 1, pwdHistoryLength);
733 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
738 CHECK_RET(samdb_msg_add_hashes(ctx, mem_ctx, mod,
746 set password via a samr_CryptPassword buffer
747 this will in the 'msg' with modify operations that will update the user
748 password when applied
750 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
752 const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
754 struct ldb_message *msg,
755 struct samr_CryptPassword *pwbuf)
759 uint32_t new_pass_len;
760 DATA_BLOB session_key = data_blob(NULL, 0);
762 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
763 if (!NT_STATUS_IS_OK(nt_status)) {
767 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
769 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
770 &new_pass_len, STR_UNICODE)) {
771 DEBUG(3,("samr: failed to decode password buffer\n"));
772 return NT_STATUS_WRONG_PASSWORD;
775 /* set the password - samdb needs to know both the domain and user DNs,
776 so the domain password policy can be used */
777 return samdb_set_password(sam_ctx, mem_ctx,
778 account_dn, domain_dn,
781 False, /* This is a password set, not change */
782 True, /* run restriction tests */
788 set password via a samr_CryptPasswordEx buffer
789 this will in the 'msg' with modify operations that will update the user
790 password when applied
792 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
794 const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
796 struct ldb_message *msg,
797 struct samr_CryptPasswordEx *pwbuf)
801 uint32_t new_pass_len;
802 DATA_BLOB co_session_key;
803 DATA_BLOB session_key = data_blob(NULL, 0);
804 struct MD5Context ctx;
806 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
807 if (!NT_STATUS_IS_OK(nt_status)) {
811 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
812 if (!co_session_key.data) {
813 return NT_STATUS_NO_MEMORY;
817 MD5Update(&ctx, &pwbuf->data[516], 16);
818 MD5Update(&ctx, session_key.data, session_key.length);
819 MD5Final(co_session_key.data, &ctx);
821 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
823 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
824 &new_pass_len, STR_UNICODE)) {
825 DEBUG(3,("samr: failed to decode password buffer\n"));
826 return NT_STATUS_WRONG_PASSWORD;
829 /* set the password - samdb needs to know both the domain and user DNs,
830 so the domain password policy can be used */
831 return samdb_set_password(sam_ctx, mem_ctx,
832 account_dn, domain_dn,
835 False, /* This is a password set, not change */
836 True, /* run restriction tests */