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