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