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