/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- dcesrv_samr_ChangePasswordUser
- dcesrv_samr_OemChangePasswordUser2
- dcesrv_samr_ChangePasswordUser3
- dcesrv_samr_ChangePasswordUser2
- samr_set_password
- samr_set_password_ex
1 /*
2 Unix SMB/CIFS implementation.
3
4 samr server password set/change handling
5
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/common/common.h"
26 #include "rpc_server/samr/dcesrv_samr.h"
27 #include "system/time.h"
28 #include "../lib/crypto/crypto.h"
29 #include "dsdb/common/flags.h"
30 #include "libcli/ldap/ldap.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "auth/auth.h"
33 #include "rpc_server/samr/proto.h"
34 #include "libcli/auth/libcli_auth.h"
35 #include "../lib/util/util_ldb.h"
36 #include "param/param.h"
37
38 /*
39 samr_ChangePasswordUser
40 */
41 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
/* [<][>][^][v][top][bottom][index][help] */
42 TALLOC_CTX *mem_ctx,
43 struct samr_ChangePasswordUser *r)
44 {
45 struct dcesrv_handle *h;
46 struct samr_account_state *a_state;
47 struct ldb_context *sam_ctx;
48 struct ldb_message **res, *msg;
49 int ret;
50 struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
51 struct samr_Password *lm_pwd, *nt_pwd;
52 NTSTATUS status = NT_STATUS_OK;
53 const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };
54
55 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
56
57 a_state = h->data;
58
59 /* basic sanity checking on parameters. Do this before any database ops */
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
64 present */
65 return NT_STATUS_INVALID_PARAMETER_MIX;
66 }
67
68 /* To change a password we need to open as system */
69 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
70 if (sam_ctx == NULL) {
71 return NT_STATUS_INVALID_SYSTEM_SERVICE;
72 }
73
74 ret = ldb_transaction_start(sam_ctx);
75 if (ret) {
76 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
77 return NT_STATUS_TRANSACTION_ABORTED;
78 }
79
80 /* fetch the old hashes */
81 ret = gendb_search_dn(sam_ctx, mem_ctx,
82 a_state->account_dn, &res, attrs);
83 if (ret != 1) {
84 ldb_transaction_cancel(sam_ctx);
85 return NT_STATUS_WRONG_PASSWORD;
86 }
87 msg = res[0];
88
89 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
90 msg, &lm_pwd, &nt_pwd);
91 if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
92 ldb_transaction_cancel(sam_ctx);
93 return NT_STATUS_WRONG_PASSWORD;
94 }
95
96 /* decrypt and check the new lm hash */
97 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
98 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
99 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
100 ldb_transaction_cancel(sam_ctx);
101 return NT_STATUS_WRONG_PASSWORD;
102 }
103
104 /* decrypt and check the new nt hash */
105 D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
106 D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
107 if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
108 ldb_transaction_cancel(sam_ctx);
109 return NT_STATUS_WRONG_PASSWORD;
110 }
111
112 /* The NT Cross is not required by Win2k3 R2, but if present
113 check the nt cross hash */
114 if (r->in.cross1_present && r->in.nt_cross) {
115 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
116 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
117 ldb_transaction_cancel(sam_ctx);
118 return NT_STATUS_WRONG_PASSWORD;
119 }
120 }
121
122 /* The LM Cross is not required by Win2k3 R2, but if present
123 check the lm cross hash */
124 if (r->in.cross2_present && r->in.lm_cross) {
125 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
126 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
127 ldb_transaction_cancel(sam_ctx);
128 return NT_STATUS_WRONG_PASSWORD;
129 }
130 }
131
132 msg = ldb_msg_new(mem_ctx);
133 if (msg == NULL) {
134 ldb_transaction_cancel(sam_ctx);
135 return NT_STATUS_NO_MEMORY;
136 }
137
138 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
139 if (!msg->dn) {
140 ldb_transaction_cancel(sam_ctx);
141 return NT_STATUS_NO_MEMORY;
142 }
143
144 /* setup password modify mods on the user DN specified. This may fail
145 * due to password policies. */
146 status = samdb_set_password(sam_ctx, mem_ctx,
147 a_state->account_dn, a_state->domain_state->domain_dn,
148 msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
149 true, /* this is a user password change */
150 NULL,
151 NULL);
152 if (!NT_STATUS_IS_OK(status)) {
153 ldb_transaction_cancel(sam_ctx);
154 return status;
155 }
156
157 /* The above call only setup the modifications, this actually
158 * makes the write to the database. */
159 ret = samdb_replace(sam_ctx, mem_ctx, msg);
160 if (ret != 0) {
161 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
162 ldb_dn_get_linearized(a_state->account_dn),
163 ldb_errstring(sam_ctx)));
164 ldb_transaction_cancel(sam_ctx);
165 return NT_STATUS_INTERNAL_DB_CORRUPTION;
166 }
167
168 /* And this confirms it in a transaction commit */
169 ret = ldb_transaction_commit(sam_ctx);
170 if (ret != 0) {
171 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
172 ldb_dn_get_linearized(a_state->account_dn),
173 ldb_errstring(sam_ctx)));
174 return NT_STATUS_TRANSACTION_ABORTED;
175 }
176
177 return NT_STATUS_OK;
178 }
179
180 /*
181 samr_OemChangePasswordUser2
182 */
183 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
184 struct samr_OemChangePasswordUser2 *r)
185 {
186 NTSTATUS status;
187 DATA_BLOB new_password, new_unicode_password;
188 char *new_pass;
189 struct samr_CryptPassword *pwbuf = r->in.password;
190 struct ldb_context *sam_ctx;
191 struct ldb_dn *user_dn;
192 int ret;
193 struct ldb_message **res, *mod;
194 const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
195 struct samr_Password *lm_pwd;
196 DATA_BLOB lm_pwd_blob;
197 uint8_t new_lm_hash[16];
198 struct samr_Password lm_verifier;
199 size_t unicode_pw_len;
200
201 if (pwbuf == NULL) {
202 return NT_STATUS_INVALID_PARAMETER;
203 }
204
205 if (r->in.hash == NULL) {
206 return NT_STATUS_INVALID_PARAMETER;
207 }
208
209 /* To change a password we need to open as system */
210 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
211 if (sam_ctx == NULL) {
212 return NT_STATUS_INVALID_SYSTEM_SERVICE;
213 }
214
215 ret = ldb_transaction_start(sam_ctx);
216 if (ret) {
217 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
218 return NT_STATUS_TRANSACTION_ABORTED;
219 }
220
221 /* we need the users dn and the domain dn (derived from the
222 user SID). We also need the current lm password hash in
223 order to decrypt the incoming password */
224 ret = gendb_search(sam_ctx,
225 mem_ctx, NULL, &res, attrs,
226 "(&(sAMAccountName=%s)(objectclass=user))",
227 r->in.account->string);
228 if (ret != 1) {
229 ldb_transaction_cancel(sam_ctx);
230 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
231 return NT_STATUS_WRONG_PASSWORD;
232 }
233
234 user_dn = res[0]->dn;
235
236 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
237 res[0], &lm_pwd, NULL);
238 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
239 ldb_transaction_cancel(sam_ctx);
240 return NT_STATUS_WRONG_PASSWORD;
241 }
242
243 /* decrypt the password we have been given */
244 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
245 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
246 data_blob_free(&lm_pwd_blob);
247
248 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
249 ldb_transaction_cancel(sam_ctx);
250 DEBUG(3,("samr: failed to decode password buffer\n"));
251 return NT_STATUS_WRONG_PASSWORD;
252 }
253
254 if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
255 CH_DOS, CH_UNIX,
256 (const char *)new_password.data,
257 new_password.length,
258 (void **)&new_pass, NULL, false)) {
259 DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
260 ldb_transaction_cancel(sam_ctx);
261 return NT_STATUS_WRONG_PASSWORD;
262 }
263
264 if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
265 CH_DOS, CH_UTF16,
266 (const char *)new_password.data,
267 new_password.length,
268 (void **)&new_unicode_password.data, &unicode_pw_len, false)) {
269 DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
270 ldb_transaction_cancel(sam_ctx);
271 return NT_STATUS_WRONG_PASSWORD;
272 }
273 new_unicode_password.length = unicode_pw_len;
274
275 E_deshash(new_pass, new_lm_hash);
276 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
277 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
278 ldb_transaction_cancel(sam_ctx);
279 return NT_STATUS_WRONG_PASSWORD;
280 }
281
282 mod = ldb_msg_new(mem_ctx);
283 if (mod == NULL) {
284 ldb_transaction_cancel(sam_ctx);
285 return NT_STATUS_NO_MEMORY;
286 }
287
288 mod->dn = ldb_dn_copy(mod, user_dn);
289 if (!mod->dn) {
290 ldb_transaction_cancel(sam_ctx);
291 return NT_STATUS_NO_MEMORY;
292 }
293
294 /* set the password on the user DN specified. This may fail
295 * due to password policies */
296 status = samdb_set_password(sam_ctx, mem_ctx,
297 user_dn, NULL,
298 mod, &new_unicode_password,
299 NULL, NULL,
300 true, /* this is a user password change */
301 NULL,
302 NULL);
303 if (!NT_STATUS_IS_OK(status)) {
304 ldb_transaction_cancel(sam_ctx);
305 return status;
306 }
307
308 /* The above call only setup the modifications, this actually
309 * makes the write to the database. */
310 ret = samdb_replace(sam_ctx, mem_ctx, mod);
311 if (ret != 0) {
312 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
313 ldb_dn_get_linearized(user_dn),
314 ldb_errstring(sam_ctx)));
315 ldb_transaction_cancel(sam_ctx);
316 return NT_STATUS_INTERNAL_DB_CORRUPTION;
317 }
318
319 /* And this confirms it in a transaction commit */
320 ret = ldb_transaction_commit(sam_ctx);
321 if (ret != 0) {
322 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
323 ldb_dn_get_linearized(user_dn),
324 ldb_errstring(sam_ctx)));
325 return NT_STATUS_TRANSACTION_ABORTED;
326 }
327
328 return NT_STATUS_OK;
329 }
330
331
332 /*
333 samr_ChangePasswordUser3
334 */
335 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
/* [<][>][^][v][top][bottom][index][help] */
336 TALLOC_CTX *mem_ctx,
337 struct samr_ChangePasswordUser3 *r)
338 {
339 NTSTATUS status;
340 DATA_BLOB new_password;
341 struct ldb_context *sam_ctx = NULL;
342 struct ldb_dn *user_dn;
343 int ret;
344 struct ldb_message **res, *mod;
345 const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
346 struct samr_Password *nt_pwd, *lm_pwd;
347 DATA_BLOB nt_pwd_blob;
348 struct samr_DomInfo1 *dominfo = NULL;
349 struct samr_ChangeReject *reject = NULL;
350 enum samr_RejectReason reason = SAMR_REJECT_OTHER;
351 uint8_t new_nt_hash[16], new_lm_hash[16];
352 struct samr_Password nt_verifier, lm_verifier;
353
354 *r->out.dominfo = NULL;
355 *r->out.reject = NULL;
356
357 if (r->in.nt_password == NULL ||
358 r->in.nt_verifier == NULL) {
359 return NT_STATUS_INVALID_PARAMETER;
360 }
361
362 /* To change a password we need to open as system */
363 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
364 if (sam_ctx == NULL) {
365 return NT_STATUS_INVALID_SYSTEM_SERVICE;
366 }
367
368 ret = ldb_transaction_start(sam_ctx);
369 if (ret) {
370 talloc_free(sam_ctx);
371 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
372 return NT_STATUS_TRANSACTION_ABORTED;
373 }
374
375 /* we need the users dn and the domain dn (derived from the
376 user SID). We also need the current lm and nt password hashes
377 in order to decrypt the incoming passwords */
378 ret = gendb_search(sam_ctx,
379 mem_ctx, NULL, &res, attrs,
380 "(&(sAMAccountName=%s)(objectclass=user))",
381 r->in.account->string);
382 if (ret != 1) {
383 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
384 status = NT_STATUS_WRONG_PASSWORD;
385 goto failed;
386 }
387
388 user_dn = res[0]->dn;
389
390 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
391 res[0], &lm_pwd, &nt_pwd);
392 if (!NT_STATUS_IS_OK(status) ) {
393 goto failed;
394 }
395
396 if (!nt_pwd) {
397 status = NT_STATUS_WRONG_PASSWORD;
398 goto failed;
399 }
400
401 /* decrypt the password we have been given */
402 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
403 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
404 data_blob_free(&nt_pwd_blob);
405
406 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
407 ldb_transaction_cancel(sam_ctx);
408 DEBUG(3,("samr: failed to decode password buffer\n"));
409 return NT_STATUS_WRONG_PASSWORD;
410 }
411
412 if (r->in.nt_verifier == NULL) {
413 status = NT_STATUS_WRONG_PASSWORD;
414 goto failed;
415 }
416
417 /* check NT verifier */
418 mdfour(new_nt_hash, new_password.data, new_password.length);
419
420 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
421 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
422 status = NT_STATUS_WRONG_PASSWORD;
423 goto failed;
424 }
425
426 /* check LM verifier (really not needed as we just checked the
427 * much stronger NT hash, but the RPC-SAMR test checks for
428 * this) */
429 if (lm_pwd && r->in.lm_verifier != NULL) {
430 char *new_pass;
431 if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
432 CH_UTF16, CH_UNIX,
433 (const char *)new_password.data,
434 new_password.length,
435 (void **)&new_pass, NULL, false)) {
436 E_deshash(new_pass, new_lm_hash);
437 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
438 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
439 status = NT_STATUS_WRONG_PASSWORD;
440 goto failed;
441 }
442 }
443 }
444
445 mod = ldb_msg_new(mem_ctx);
446 if (mod == NULL) {
447 status = NT_STATUS_NO_MEMORY;
448 goto failed;
449 }
450
451 mod->dn = ldb_dn_copy(mod, user_dn);
452 if (!mod->dn) {
453 status = NT_STATUS_NO_MEMORY;
454 goto failed;
455 }
456
457 /* set the password on the user DN specified. This may fail
458 * due to password policies */
459 status = samdb_set_password(sam_ctx, mem_ctx,
460 user_dn, NULL,
461 mod, &new_password,
462 NULL, NULL,
463 true, /* this is a user password change */
464 &reason,
465 &dominfo);
466 if (!NT_STATUS_IS_OK(status)) {
467 goto failed;
468 }
469
470 /* The above call only setup the modifications, this actually
471 * makes the write to the database. */
472 ret = samdb_replace(sam_ctx, mem_ctx, mod);
473 if (ret != 0) {
474 DEBUG(2,("samdb_replace failed to change password for %s: %s\n",
475 ldb_dn_get_linearized(user_dn),
476 ldb_errstring(sam_ctx)));
477 status = NT_STATUS_UNSUCCESSFUL;
478 goto failed;
479 }
480
481 /* And this confirms it in a transaction commit */
482 ret = ldb_transaction_commit(sam_ctx);
483 if (ret != 0) {
484 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
485 ldb_dn_get_linearized(user_dn),
486 ldb_errstring(sam_ctx)));
487 status = NT_STATUS_TRANSACTION_ABORTED;
488 goto failed;
489 }
490
491 return NT_STATUS_OK;
492
493 failed:
494 ldb_transaction_cancel(sam_ctx);
495 talloc_free(sam_ctx);
496
497 reject = talloc(mem_ctx, struct samr_ChangeReject);
498 *r->out.dominfo = dominfo;
499 *r->out.reject = reject;
500
501 if (reject == NULL) {
502 return status;
503 }
504 ZERO_STRUCTP(reject);
505
506 reject->reason = reason;
507
508 return status;
509 }
510
511
512 /*
513 samr_ChangePasswordUser2
514
515 easy - just a subset of samr_ChangePasswordUser3
516 */
517 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
518 struct samr_ChangePasswordUser2 *r)
519 {
520 struct samr_ChangePasswordUser3 r2;
521 struct samr_DomInfo1 *dominfo = NULL;
522 struct samr_ChangeReject *reject = NULL;
523
524 r2.in.server = r->in.server;
525 r2.in.account = r->in.account;
526 r2.in.nt_password = r->in.nt_password;
527 r2.in.nt_verifier = r->in.nt_verifier;
528 r2.in.lm_change = r->in.lm_change;
529 r2.in.lm_password = r->in.lm_password;
530 r2.in.lm_verifier = r->in.lm_verifier;
531 r2.in.password3 = NULL;
532 r2.out.dominfo = &dominfo;
533 r2.out.reject = &reject;
534
535 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
536 }
537
538
539 /*
540 set password via a samr_CryptPassword buffer
541 this will in the 'msg' with modify operations that will update the user
542 password when applied
543 */
544 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
/* [<][>][^][v][top][bottom][index][help] */
545 void *sam_ctx,
546 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
547 TALLOC_CTX *mem_ctx,
548 struct ldb_message *msg,
549 struct samr_CryptPassword *pwbuf)
550 {
551 NTSTATUS nt_status;
552 DATA_BLOB new_password;
553 DATA_BLOB session_key = data_blob(NULL, 0);
554
555 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
556 if (!NT_STATUS_IS_OK(nt_status)) {
557 return nt_status;
558 }
559
560 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
561
562 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
563 DEBUG(3,("samr: failed to decode password buffer\n"));
564 return NT_STATUS_WRONG_PASSWORD;
565 }
566
567 /* set the password - samdb needs to know both the domain and user DNs,
568 so the domain password policy can be used */
569 return samdb_set_password(sam_ctx, mem_ctx,
570 account_dn, domain_dn,
571 msg, &new_password,
572 NULL, NULL,
573 false, /* This is a password set, not change */
574 NULL, NULL);
575 }
576
577
578 /*
579 set password via a samr_CryptPasswordEx buffer
580 this will in the 'msg' with modify operations that will update the user
581 password when applied
582 */
583 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
/* [<][>][^][v][top][bottom][index][help] */
584 struct ldb_context *sam_ctx,
585 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
586 TALLOC_CTX *mem_ctx,
587 struct ldb_message *msg,
588 struct samr_CryptPasswordEx *pwbuf)
589 {
590 NTSTATUS nt_status;
591 DATA_BLOB new_password;
592 DATA_BLOB co_session_key;
593 DATA_BLOB session_key = data_blob(NULL, 0);
594 struct MD5Context ctx;
595
596 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
597 if (!NT_STATUS_IS_OK(nt_status)) {
598 return nt_status;
599 }
600
601 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
602 if (!co_session_key.data) {
603 return NT_STATUS_NO_MEMORY;
604 }
605
606 MD5Init(&ctx);
607 MD5Update(&ctx, &pwbuf->data[516], 16);
608 MD5Update(&ctx, session_key.data, session_key.length);
609 MD5Final(co_session_key.data, &ctx);
610
611 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
612
613 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
614 DEBUG(3,("samr: failed to decode password buffer\n"));
615 return NT_STATUS_WRONG_PASSWORD;
616 }
617
618 /* set the password - samdb needs to know both the domain and user DNs,
619 so the domain password policy can be used */
620 return samdb_set_password(sam_ctx, mem_ctx,
621 account_dn, domain_dn,
622 msg, &new_password,
623 NULL, NULL,
624 false, /* This is a password set, not change */
625 NULL, NULL);
626 }
627
628