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/samr/dcesrv_samr.h"
26 #include "system/time.h"
27 #include "lib/crypto/md4.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "auth/auth.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "../lib/util/util_ldb.h"
32 #include "rpc_server/samr/proto.h"
33 #include "auth/auth_sam.h"
34
35 #include "lib/crypto/gnutls_helpers.h"
36 #include <gnutls/gnutls.h>
37 #include <gnutls/crypto.h>
38
log_password_change_event(struct imessaging_context * msg_ctx,struct loadparm_context * lp_ctx,const struct tsocket_address * remote_client_address,const struct tsocket_address * local_server_address,const char * auth_description,const char * password_type,const char * original_client_name,const char * account_name_from_db,NTSTATUS status,struct dom_sid * sid)39 static void log_password_change_event(struct imessaging_context *msg_ctx,
40 struct loadparm_context *lp_ctx,
41 const struct tsocket_address *remote_client_address,
42 const struct tsocket_address *local_server_address,
43 const char *auth_description,
44 const char *password_type,
45 const char *original_client_name,
46 const char *account_name_from_db,
47 NTSTATUS status,
48 struct dom_sid *sid)
49 {
50 /*
51 * Forcing this via the NTLM auth structure is not ideal, but
52 * it is the most practical option right now, and ensures the
53 * logs are consistent, even if some elements are always NULL.
54 */
55 struct auth_usersupplied_info ui = {
56 .mapped_state = true,
57 .was_mapped = true,
58 .client = {
59 .account_name = original_client_name,
60 .domain_name = lpcfg_sam_name(lp_ctx),
61 },
62 .mapped = {
63 .account_name = account_name_from_db,
64 .domain_name = lpcfg_sam_name(lp_ctx),
65 },
66 .remote_host = remote_client_address,
67 .local_host = local_server_address,
68 .service_description = "SAMR Password Change",
69 .auth_description = auth_description,
70 .password_type = password_type,
71 };
72
73 log_authentication_event(msg_ctx,
74 lp_ctx,
75 NULL,
76 &ui,
77 status,
78 ui.mapped.domain_name,
79 ui.mapped.account_name,
80 sid);
81 }
82 /*
83 samr_ChangePasswordUser
84
85 So old it is just not worth implementing
86 because it does not supply a plaintext and so we can't do password
87 complexity checking and cannot update all the other password hashes.
88
89 */
dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_ChangePasswordUser * r)90 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
91 TALLOC_CTX *mem_ctx,
92 struct samr_ChangePasswordUser *r)
93 {
94 return NT_STATUS_NOT_IMPLEMENTED;
95 }
96
97 /*
98 samr_OemChangePasswordUser2
99 */
dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_OemChangePasswordUser2 * r)100 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
101 TALLOC_CTX *mem_ctx,
102 struct samr_OemChangePasswordUser2 *r)
103 {
104 struct auth_session_info *session_info =
105 dcesrv_call_session_info(dce_call);
106 struct imessaging_context *imsg_ctx =
107 dcesrv_imessaging_context(dce_call->conn);
108 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
109 DATA_BLOB new_password, new_unicode_password;
110 char *new_pass;
111 struct samr_CryptPassword *pwbuf = r->in.password;
112 struct ldb_context *sam_ctx;
113 struct ldb_dn *user_dn;
114 int ret;
115 struct ldb_message **res;
116 const char * const attrs[] = { "objectSid", "dBCSPwd",
117 "userAccountControl",
118 "msDS-ResultantPSO",
119 "msDS-User-Account-Control-Computed",
120 "badPwdCount", "badPasswordTime",
121 "samAccountName",
122 NULL };
123 struct samr_Password *lm_pwd;
124 uint8_t new_lm_hash[16];
125 struct samr_Password lm_verifier;
126 size_t unicode_pw_len;
127 size_t converted_size = 0;
128 const char *user_samAccountName = NULL;
129 struct dom_sid *user_objectSid = NULL;
130 gnutls_cipher_hd_t cipher_hnd = NULL;
131 gnutls_datum_t lm_session_key;
132 int rc;
133
134 if (pwbuf == NULL) {
135 return NT_STATUS_INVALID_PARAMETER;
136 }
137
138 if (r->in.hash == NULL) {
139 return NT_STATUS_INVALID_PARAMETER;
140 }
141
142 /* this call can only work with lanman auth */
143 if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) {
144 return NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER;
145 }
146
147 /* Connect to a SAMDB with system privileges for fetching the old pw
148 * hashes. */
149 sam_ctx = samdb_connect(mem_ctx,
150 dce_call->event_ctx,
151 dce_call->conn->dce_ctx->lp_ctx,
152 system_session(dce_call->conn->dce_ctx->lp_ctx),
153 dce_call->conn->remote_address,
154 0);
155 if (sam_ctx == NULL) {
156 return NT_STATUS_INVALID_SYSTEM_SERVICE;
157 }
158
159 /* we need the users dn and the domain dn (derived from the
160 user SID). We also need the current lm password hash in
161 order to decrypt the incoming password */
162 ret = gendb_search(sam_ctx,
163 mem_ctx, NULL, &res, attrs,
164 "(&(sAMAccountName=%s)(objectclass=user))",
165 ldb_binary_encode_string(mem_ctx, r->in.account->string));
166 if (ret != 1) {
167 status = NT_STATUS_NO_SUCH_USER; /* Converted to WRONG_PASSWORD below */
168 goto failed;
169 }
170
171 user_dn = res[0]->dn;
172
173 user_samAccountName = ldb_msg_find_attr_as_string(res[0], "samAccountName", NULL);
174 user_objectSid = samdb_result_dom_sid(res, res[0], "objectSid");
175
176 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
177 res[0], &lm_pwd, NULL);
178 if (!NT_STATUS_IS_OK(status)) {
179 goto failed;
180 } else if (!lm_pwd) {
181 status = NT_STATUS_WRONG_PASSWORD;
182 goto failed;
183 }
184
185 /* decrypt the password we have been given */
186 lm_session_key = (gnutls_datum_t) {
187 .data = lm_pwd->hash,
188 .size = sizeof(lm_pwd->hash),
189 };
190
191 rc = gnutls_cipher_init(&cipher_hnd,
192 GNUTLS_CIPHER_ARCFOUR_128,
193 &lm_session_key,
194 NULL);
195 if (rc < 0) {
196 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
197 goto failed;
198 }
199
200 rc = gnutls_cipher_decrypt(cipher_hnd,
201 pwbuf->data,
202 516);
203 gnutls_cipher_deinit(cipher_hnd);
204 if (rc < 0) {
205 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
206 goto failed;
207 }
208
209 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
210 DEBUG(3,("samr: failed to decode password buffer\n"));
211 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
212 status = NT_STATUS_WRONG_PASSWORD;
213 goto failed;
214 }
215
216 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
217 CH_DOS, CH_UNIX,
218 (const char *)new_password.data,
219 new_password.length,
220 (void **)&new_pass, &converted_size)) {
221 DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
222 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
223 status = NT_STATUS_WRONG_PASSWORD;
224 goto failed;
225 }
226
227 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
228 CH_DOS, CH_UTF16,
229 (const char *)new_password.data,
230 new_password.length,
231 (void **)&new_unicode_password.data, &unicode_pw_len)) {
232 DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
233 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
234 status = NT_STATUS_WRONG_PASSWORD;
235 goto failed;
236 }
237 new_unicode_password.length = unicode_pw_len;
238
239 E_deshash(new_pass, new_lm_hash);
240 rc = E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
241 if (rc != 0) {
242 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
243 goto failed;
244 }
245 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
246 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
247 status = NT_STATUS_WRONG_PASSWORD;
248 goto failed;
249 }
250
251 /* Connect to a SAMDB with user privileges for the password change */
252 sam_ctx = samdb_connect(mem_ctx,
253 dce_call->event_ctx,
254 dce_call->conn->dce_ctx->lp_ctx,
255 session_info,
256 dce_call->conn->remote_address,
257 0);
258 if (sam_ctx == NULL) {
259 return NT_STATUS_INVALID_SYSTEM_SERVICE;
260 }
261
262 /* Start transaction */
263 ret = ldb_transaction_start(sam_ctx);
264 if (ret != LDB_SUCCESS) {
265 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
266 return NT_STATUS_TRANSACTION_ABORTED;
267 }
268
269 /* Performs the password modification. We pass the old hashes read out
270 * from the database since they were already checked against the user-
271 * provided ones. */
272 status = samdb_set_password(sam_ctx, mem_ctx,
273 user_dn, NULL,
274 &new_unicode_password,
275 NULL, NULL,
276 lm_pwd, NULL, /* this is a user password change */
277 NULL,
278 NULL);
279 if (!NT_STATUS_IS_OK(status)) {
280 ldb_transaction_cancel(sam_ctx);
281 goto failed;
282 }
283
284 /* And this confirms it in a transaction commit */
285 ret = ldb_transaction_commit(sam_ctx);
286 if (ret != LDB_SUCCESS) {
287 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
288 ldb_dn_get_linearized(user_dn),
289 ldb_errstring(sam_ctx)));
290 status = NT_STATUS_TRANSACTION_ABORTED;
291 goto failed;
292 }
293
294 status = NT_STATUS_OK;
295
296 failed:
297
298 log_password_change_event(imsg_ctx,
299 dce_call->conn->dce_ctx->lp_ctx,
300 dce_call->conn->remote_address,
301 dce_call->conn->local_address,
302 "OemChangePasswordUser2",
303 "RC4/DES using LanMan-hash",
304 r->in.account->string,
305 user_samAccountName,
306 status,
307 user_objectSid);
308 if (NT_STATUS_IS_OK(status)) {
309 return NT_STATUS_OK;
310 }
311 /* Only update the badPwdCount if we found the user */
312 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
313 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
314 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
315 /* Don't give the game away: (don't allow anonymous users to prove the existence of usernames) */
316 status = NT_STATUS_WRONG_PASSWORD;
317 }
318
319 return status;
320 }
321
322
323 /*
324 samr_ChangePasswordUser3
325 */
dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_ChangePasswordUser3 * r)326 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
327 TALLOC_CTX *mem_ctx,
328 struct samr_ChangePasswordUser3 *r)
329 {
330 struct auth_session_info *session_info =
331 dcesrv_call_session_info(dce_call);
332 struct imessaging_context *imsg_ctx =
333 dcesrv_imessaging_context(dce_call->conn);
334 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
335 DATA_BLOB new_password;
336 struct ldb_context *sam_ctx = NULL;
337 struct ldb_dn *user_dn = NULL;
338 int ret;
339 struct ldb_message **res;
340 const char * const attrs[] = { "unicodePwd", "dBCSPwd",
341 "userAccountControl",
342 "msDS-ResultantPSO",
343 "msDS-User-Account-Control-Computed",
344 "badPwdCount", "badPasswordTime",
345 "objectSid", NULL };
346 struct samr_Password *nt_pwd, *lm_pwd;
347 struct samr_DomInfo1 *dominfo = NULL;
348 struct userPwdChangeFailureInformation *reject = NULL;
349 enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
350 uint8_t new_nt_hash[16], new_lm_hash[16];
351 struct samr_Password nt_verifier, lm_verifier;
352 const char *user_samAccountName = NULL;
353 struct dom_sid *user_objectSid = NULL;
354 enum ntlm_auth_level ntlm_auth_level
355 = lpcfg_ntlm_auth(dce_call->conn->dce_ctx->lp_ctx);
356 gnutls_cipher_hd_t cipher_hnd = NULL;
357 gnutls_datum_t nt_session_key;
358 int rc;
359
360 *r->out.dominfo = NULL;
361 *r->out.reject = NULL;
362
363 /* this call should be disabled without NTLM auth */
364 if (ntlm_auth_level == NTLM_AUTH_DISABLED) {
365 DBG_WARNING("NTLM password changes not"
366 "permitted by configuration.\n");
367 return NT_STATUS_NTLM_BLOCKED;
368 }
369
370 if (r->in.nt_password == NULL ||
371 r->in.nt_verifier == NULL) {
372 return NT_STATUS_INVALID_PARAMETER;
373 }
374
375 /* Connect to a SAMDB with system privileges for fetching the old pw
376 * hashes. */
377 sam_ctx = samdb_connect(mem_ctx,
378 dce_call->event_ctx,
379 dce_call->conn->dce_ctx->lp_ctx,
380 system_session(dce_call->conn->dce_ctx->lp_ctx),
381 dce_call->conn->remote_address,
382 0);
383 if (sam_ctx == NULL) {
384 return NT_STATUS_INVALID_SYSTEM_SERVICE;
385 }
386
387 /* we need the users dn and the domain dn (derived from the
388 user SID). We also need the current lm and nt password hashes
389 in order to decrypt the incoming passwords */
390 ret = gendb_search(sam_ctx,
391 mem_ctx, NULL, &res, attrs,
392 "(&(sAMAccountName=%s)(objectclass=user))",
393 ldb_binary_encode_string(mem_ctx, r->in.account->string));
394 if (ret != 1) {
395 status = NT_STATUS_NO_SUCH_USER; /* Converted to WRONG_PASSWORD below */
396 goto failed;
397 }
398
399 user_dn = res[0]->dn;
400 user_samAccountName = ldb_msg_find_attr_as_string(res[0], "samAccountName", NULL);
401 user_objectSid = samdb_result_dom_sid(res, res[0], "objectSid");
402
403 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
404 res[0], &lm_pwd, &nt_pwd);
405 if (!NT_STATUS_IS_OK(status) ) {
406 goto failed;
407 }
408
409 if (!nt_pwd) {
410 status = NT_STATUS_WRONG_PASSWORD;
411 goto failed;
412 }
413
414 /* decrypt the password we have been given */
415 nt_session_key = (gnutls_datum_t) {
416 .data = nt_pwd->hash,
417 .size = sizeof(nt_pwd->hash),
418 };
419
420 rc = gnutls_cipher_init(&cipher_hnd,
421 GNUTLS_CIPHER_ARCFOUR_128,
422 &nt_session_key,
423 NULL);
424 if (rc < 0) {
425 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
426 goto failed;
427 }
428
429 rc = gnutls_cipher_decrypt(cipher_hnd,
430 r->in.nt_password->data,
431 516);
432 gnutls_cipher_deinit(cipher_hnd);
433 if (rc < 0) {
434 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
435 goto failed;
436 }
437
438 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
439 DEBUG(3,("samr: failed to decode password buffer\n"));
440 status = NT_STATUS_WRONG_PASSWORD;
441 goto failed;
442 }
443
444 if (r->in.nt_verifier == NULL) {
445 status = NT_STATUS_WRONG_PASSWORD;
446 goto failed;
447 }
448
449 /* check NT verifier */
450 mdfour(new_nt_hash, new_password.data, new_password.length);
451
452 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
453 if (rc != 0) {
454 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
455 goto failed;
456 }
457 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
458 status = NT_STATUS_WRONG_PASSWORD;
459 goto failed;
460 }
461
462 /* check LM verifier (really not needed as we just checked the
463 * much stronger NT hash, but the RPC-SAMR test checks for
464 * this) */
465 if (lm_pwd && r->in.lm_verifier != NULL) {
466 char *new_pass;
467 size_t converted_size = 0;
468
469 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
470 CH_UTF16, CH_UNIX,
471 (const char *)new_password.data,
472 new_password.length,
473 (void **)&new_pass, &converted_size)) {
474 E_deshash(new_pass, new_lm_hash);
475 rc = E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
476 if (rc != 0) {
477 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
478 goto failed;
479 }
480 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
481 status = NT_STATUS_WRONG_PASSWORD;
482 goto failed;
483 }
484 }
485 }
486
487 /* Connect to a SAMDB with user privileges for the password change */
488 sam_ctx = samdb_connect(mem_ctx,
489 dce_call->event_ctx,
490 dce_call->conn->dce_ctx->lp_ctx,
491 session_info,
492 dce_call->conn->remote_address,
493 0);
494 if (sam_ctx == NULL) {
495 return NT_STATUS_INVALID_SYSTEM_SERVICE;
496 }
497
498 ret = ldb_transaction_start(sam_ctx);
499 if (ret != LDB_SUCCESS) {
500 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
501 return NT_STATUS_TRANSACTION_ABORTED;
502 }
503
504 /* Performs the password modification. We pass the old hashes read out
505 * from the database since they were already checked against the user-
506 * provided ones. */
507 status = samdb_set_password(sam_ctx, mem_ctx,
508 user_dn, NULL,
509 &new_password,
510 NULL, NULL,
511 lm_pwd, nt_pwd, /* this is a user password change */
512 &reason,
513 &dominfo);
514
515 if (!NT_STATUS_IS_OK(status)) {
516 ldb_transaction_cancel(sam_ctx);
517 goto failed;
518 }
519
520 /* And this confirms it in a transaction commit */
521 ret = ldb_transaction_commit(sam_ctx);
522 if (ret != LDB_SUCCESS) {
523 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
524 ldb_dn_get_linearized(user_dn),
525 ldb_errstring(sam_ctx)));
526 status = NT_STATUS_TRANSACTION_ABORTED;
527 goto failed;
528 }
529
530 status = NT_STATUS_OK;
531
532 failed:
533
534 log_password_change_event(imsg_ctx,
535 dce_call->conn->dce_ctx->lp_ctx,
536 dce_call->conn->remote_address,
537 dce_call->conn->local_address,
538 "samr_ChangePasswordUser3",
539 "RC4/DES using NTLM-hash",
540 r->in.account->string,
541 user_samAccountName,
542 status,
543 user_objectSid);
544 if (NT_STATUS_IS_OK(status)) {
545 return NT_STATUS_OK;
546 }
547
548 /* Only update the badPwdCount if we found the user */
549 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
550 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
551 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
552 /* Don't give the game away: (don't allow anonymous users to prove the existence of usernames) */
553 status = NT_STATUS_WRONG_PASSWORD;
554 }
555
556 reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
557 if (reject != NULL) {
558 reject->extendedFailureReason = reason;
559
560 *r->out.reject = reject;
561 }
562
563 *r->out.dominfo = dominfo;
564
565 return status;
566 }
567
568 /*
569 samr_ChangePasswordUser2
570
571 easy - just a subset of samr_ChangePasswordUser3
572 */
dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_ChangePasswordUser2 * r)573 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
574 TALLOC_CTX *mem_ctx,
575 struct samr_ChangePasswordUser2 *r)
576 {
577 struct samr_ChangePasswordUser3 r2;
578 struct samr_DomInfo1 *dominfo = NULL;
579 struct userPwdChangeFailureInformation *reject = NULL;
580
581 r2.in.server = r->in.server;
582 r2.in.account = r->in.account;
583 r2.in.nt_password = r->in.nt_password;
584 r2.in.nt_verifier = r->in.nt_verifier;
585 r2.in.lm_change = r->in.lm_change;
586 r2.in.lm_password = r->in.lm_password;
587 r2.in.lm_verifier = r->in.lm_verifier;
588 r2.in.password3 = NULL;
589 r2.out.dominfo = &dominfo;
590 r2.out.reject = &reject;
591
592 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
593 }
594
595
596 /*
597 set password via a samr_CryptPassword buffer
598 */
samr_set_password(struct dcesrv_call_state * dce_call,struct ldb_context * sam_ctx,struct ldb_dn * account_dn,struct ldb_dn * domain_dn,TALLOC_CTX * mem_ctx,struct samr_CryptPassword * pwbuf)599 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
600 struct ldb_context *sam_ctx,
601 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
602 TALLOC_CTX *mem_ctx,
603 struct samr_CryptPassword *pwbuf)
604 {
605 NTSTATUS nt_status;
606 DATA_BLOB new_password;
607 DATA_BLOB session_key = data_blob(NULL, 0);
608 gnutls_cipher_hd_t cipher_hnd = NULL;
609 gnutls_datum_t _session_key;
610 int rc;
611
612 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
613 if (!NT_STATUS_IS_OK(nt_status)) {
614 DBG_NOTICE("samr: failed to get session key: %s\n",
615 nt_errstr(nt_status));
616 return nt_status;
617 }
618
619 _session_key = (gnutls_datum_t) {
620 .data = session_key.data,
621 .size = session_key.length,
622 };
623
624 rc = gnutls_cipher_init(&cipher_hnd,
625 GNUTLS_CIPHER_ARCFOUR_128,
626 &_session_key,
627 NULL);
628 if (rc < 0) {
629 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
630 goto out;
631 }
632
633 rc = gnutls_cipher_decrypt(cipher_hnd,
634 pwbuf->data,
635 516);
636 gnutls_cipher_deinit(cipher_hnd);
637 if (rc < 0) {
638 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
639 goto out;
640 }
641
642 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
643 DEBUG(3,("samr: failed to decode password buffer\n"));
644 return NT_STATUS_WRONG_PASSWORD;
645 }
646
647 /* set the password - samdb needs to know both the domain and user DNs,
648 so the domain password policy can be used */
649 nt_status = samdb_set_password(sam_ctx,
650 mem_ctx,
651 account_dn,
652 domain_dn,
653 &new_password,
654 NULL,
655 NULL,
656 NULL,
657 NULL, /* This is a password set, not change */
658 NULL,
659 NULL);
660 out:
661 return nt_status;
662 }
663
664
665 /*
666 set password via a samr_CryptPasswordEx buffer
667 */
samr_set_password_ex(struct dcesrv_call_state * dce_call,struct ldb_context * sam_ctx,struct ldb_dn * account_dn,struct ldb_dn * domain_dn,TALLOC_CTX * mem_ctx,struct samr_CryptPasswordEx * pwbuf)668 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
669 struct ldb_context *sam_ctx,
670 struct ldb_dn *account_dn,
671 struct ldb_dn *domain_dn,
672 TALLOC_CTX *mem_ctx,
673 struct samr_CryptPasswordEx *pwbuf)
674 {
675 NTSTATUS nt_status;
676 DATA_BLOB new_password;
677
678 /* The confounder is in the last 16 bytes of the buffer */
679 DATA_BLOB confounder = data_blob_const(&pwbuf->data[516], 16);
680 DATA_BLOB pw_data = data_blob_const(pwbuf->data, 516);
681 DATA_BLOB session_key = data_blob(NULL, 0);
682 int rc;
683
684 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
685 if (!NT_STATUS_IS_OK(nt_status)) {
686 DEBUG(3,("samr: failed to get session key: %s "
687 "=> NT_STATUS_WRONG_PASSWORD\n",
688 nt_errstr(nt_status)));
689 return NT_STATUS_WRONG_PASSWORD;
690 }
691
692 rc = samba_gnutls_arcfour_confounded_md5(&confounder,
693 &session_key,
694 &pw_data,
695 SAMBA_GNUTLS_DECRYPT);
696 if (rc < 0) {
697 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
698 goto out;
699 }
700
701 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
702 DEBUG(3,("samr: failed to decode password buffer\n"));
703 nt_status = NT_STATUS_WRONG_PASSWORD;
704 goto out;
705 }
706
707 /* set the password - samdb needs to know both the domain and user DNs,
708 so the domain password policy can be used */
709 nt_status = samdb_set_password(sam_ctx,
710 mem_ctx,
711 account_dn,
712 domain_dn,
713 &new_password,
714 NULL,
715 NULL,
716 NULL,
717 NULL, /* This is a password set, not change */
718 NULL,
719 NULL);
720 ZERO_ARRAY_LEN(new_password.data,
721 new_password.length);
722
723 out:
724 return nt_status;
725 }
726
727 /*
728 set password via encrypted NT and LM hash buffers
729 */
samr_set_password_buffers(struct dcesrv_call_state * dce_call,struct ldb_context * sam_ctx,struct ldb_dn * account_dn,struct ldb_dn * domain_dn,TALLOC_CTX * mem_ctx,const uint8_t * lm_pwd_hash,const uint8_t * nt_pwd_hash)730 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
731 struct ldb_context *sam_ctx,
732 struct ldb_dn *account_dn,
733 struct ldb_dn *domain_dn,
734 TALLOC_CTX *mem_ctx,
735 const uint8_t *lm_pwd_hash,
736 const uint8_t *nt_pwd_hash)
737 {
738 struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
739 uint8_t random_session_key[16] = { 0, };
740 DATA_BLOB session_key = data_blob(NULL, 0);
741 DATA_BLOB in, out;
742 NTSTATUS nt_status = NT_STATUS_OK;
743 int rc;
744
745 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
746 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
747 DEBUG(3,("samr: failed to get session key: %s "
748 "=> use a random session key\n",
749 nt_errstr(nt_status)));
750
751 /*
752 * Windows just uses a random key
753 */
754 generate_random_buffer(random_session_key,
755 sizeof(random_session_key));
756 session_key = data_blob_const(random_session_key,
757 sizeof(random_session_key));
758 nt_status = NT_STATUS_OK;
759 }
760 if (!NT_STATUS_IS_OK(nt_status)) {
761 return nt_status;
762 }
763
764 if (lm_pwd_hash != NULL) {
765 in = data_blob_const(lm_pwd_hash, 16);
766 out = data_blob_talloc_zero(mem_ctx, 16);
767
768 rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_DECRYPT);
769 if (rc != 0) {
770 return gnutls_error_to_ntstatus(rc,
771 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
772 }
773
774 d_lm_pwd_hash = (struct samr_Password *) out.data;
775 }
776 if (nt_pwd_hash != NULL) {
777 in = data_blob_const(nt_pwd_hash, 16);
778 out = data_blob_talloc_zero(mem_ctx, 16);
779
780 rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_DECRYPT);
781 if (rc != 0) {
782 return gnutls_error_to_ntstatus(rc,
783 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
784 }
785
786 d_nt_pwd_hash = (struct samr_Password *) out.data;
787 }
788
789 if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
790 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
791 domain_dn, NULL,
792 d_lm_pwd_hash, d_nt_pwd_hash,
793 NULL, NULL, /* this is a password set */
794 NULL, NULL);
795 }
796
797 return nt_status;
798 }
799