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