1 /*
2    MIT-Samba4 library
3 
4    Copyright (c) 2010, Simo Sorce <idra@samba.org>
5    Copyright (c) 2014-2015 Guenther Deschner <gd@samba.org>
6    Copyright (c) 2014-2016 Andreas Schneider <asn@samba.org>
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #define TEVENT_DEPRECATED 1
23 
24 #include "includes.h"
25 #include "param/param.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "system/kerberos.h"
28 #include <kdb.h>
29 #include <kadm5/kadm_err.h>
30 #include "kdc/sdb.h"
31 #include "kdc/sdb_kdb.h"
32 #include "auth/kerberos/kerberos.h"
33 #include "auth/kerberos/pac_utils.h"
34 #include "kdc/samba_kdc.h"
35 #include "kdc/pac-glue.h"
36 #include "kdc/db-glue.h"
37 #include "auth/auth.h"
38 #include "kdc/kpasswd_glue.h"
39 #include "auth/auth_sam.h"
40 
41 #include "mit_samba.h"
42 
mit_samba_context_free(struct mit_samba_context * ctx)43 void mit_samba_context_free(struct mit_samba_context *ctx)
44 {
45 	/* free heimdal's krb5_context */
46 	if (ctx->context) {
47 		krb5_free_context(ctx->context);
48 	}
49 
50 	/* then free everything else */
51 	talloc_free(ctx);
52 }
53 
mit_samba_context_init(struct mit_samba_context ** _ctx)54 int mit_samba_context_init(struct mit_samba_context **_ctx)
55 {
56 	NTSTATUS status;
57 	struct mit_samba_context *ctx;
58 	const char *s4_conf_file;
59 	int ret;
60 	struct samba_kdc_base_context base_ctx;
61 
62 	ctx = talloc_zero(NULL, struct mit_samba_context);
63 	if (!ctx) {
64 		ret = ENOMEM;
65 		goto done;
66 	}
67 
68 	base_ctx.ev_ctx = tevent_context_init(ctx);
69 	if (!base_ctx.ev_ctx) {
70 		ret = ENOMEM;
71 		goto done;
72 	}
73 	tevent_loop_allow_nesting(base_ctx.ev_ctx);
74 	base_ctx.lp_ctx = loadparm_init_global(false);
75 	if (!base_ctx.lp_ctx) {
76 		ret = ENOMEM;
77 		goto done;
78 	}
79 
80 	setup_logging("mitkdc", DEBUG_DEFAULT_STDOUT);
81 
82 	/* init s4 configuration */
83 	s4_conf_file = lpcfg_configfile(base_ctx.lp_ctx);
84 	if (s4_conf_file) {
85 		lpcfg_load(base_ctx.lp_ctx, s4_conf_file);
86 	} else {
87 		lpcfg_load_default(base_ctx.lp_ctx);
88 	}
89 
90 	status = samba_kdc_setup_db_ctx(ctx, &base_ctx, &ctx->db_ctx);
91 	if (!NT_STATUS_IS_OK(status)) {
92 		ret = EINVAL;
93 		goto done;
94 	}
95 
96 	/* init heimdal's krb_context and log facilities */
97 	ret = smb_krb5_init_context_basic(ctx,
98 					  ctx->db_ctx->lp_ctx,
99 					  &ctx->context);
100 	if (ret) {
101 		goto done;
102 	}
103 
104 	ret = 0;
105 
106 done:
107 	if (ret) {
108 		mit_samba_context_free(ctx);
109 	} else {
110 		*_ctx = ctx;
111 	}
112 	return ret;
113 }
114 
ks_is_tgs_principal(struct mit_samba_context * ctx,krb5_const_principal principal)115 static krb5_error_code ks_is_tgs_principal(struct mit_samba_context *ctx,
116 					   krb5_const_principal principal)
117 {
118 	char *p;
119 	int eq = -1;
120 
121 	p = smb_krb5_principal_get_comp_string(ctx, ctx->context, principal, 0);
122 
123 	eq = krb5_princ_size(ctx->context, principal) == 2 &&
124 	     (strcmp(p, KRB5_TGS_NAME) == 0);
125 
126 	talloc_free(p);
127 
128 	return eq;
129 }
130 
mit_samba_generate_salt(krb5_data * salt)131 int mit_samba_generate_salt(krb5_data *salt)
132 {
133 	if (salt == NULL) {
134 		return EINVAL;
135 	}
136 
137 	salt->length = 16;
138 	salt->data = malloc(salt->length);
139 	if (salt->data == NULL) {
140 		return ENOMEM;
141 	}
142 
143 	generate_random_buffer((uint8_t *)salt->data, salt->length);
144 
145 	return 0;
146 }
147 
mit_samba_generate_random_password(krb5_data * pwd)148 int mit_samba_generate_random_password(krb5_data *pwd)
149 {
150 	TALLOC_CTX *tmp_ctx;
151 	char *password;
152 
153 	if (pwd == NULL) {
154 		return EINVAL;
155 	}
156 	pwd->length = 24;
157 
158 	tmp_ctx = talloc_named(NULL,
159 			       0,
160 			       "mit_samba_create_principal_password context");
161 	if (tmp_ctx == NULL) {
162 		return ENOMEM;
163 	}
164 
165 	password = generate_random_password(tmp_ctx, pwd->length, pwd->length);
166 	if (password == NULL) {
167 		talloc_free(tmp_ctx);
168 		return ENOMEM;
169 	}
170 
171 	pwd->data = strdup(password);
172 	talloc_free(tmp_ctx);
173 	if (pwd->data == NULL) {
174 		return ENOMEM;
175 	}
176 
177 	return 0;
178 }
179 
mit_samba_get_principal(struct mit_samba_context * ctx,krb5_const_principal principal,unsigned int kflags,krb5_db_entry ** _kentry)180 int mit_samba_get_principal(struct mit_samba_context *ctx,
181 			    krb5_const_principal principal,
182 			    unsigned int kflags,
183 			    krb5_db_entry **_kentry)
184 {
185 	struct sdb_entry_ex sentry = {
186 		.free_entry = NULL,
187 	};
188 	krb5_db_entry *kentry;
189 	int ret;
190 	int sflags = 0;
191 	krb5_principal referral_principal = NULL;
192 
193 	kentry = calloc(1, sizeof(krb5_db_entry));
194 	if (kentry == NULL) {
195 		return ENOMEM;
196 	}
197 
198 	if (kflags & KRB5_KDB_FLAG_CANONICALIZE) {
199 		sflags |= SDB_F_CANON;
200 	}
201 	if (kflags & (KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY |
202 		      KRB5_KDB_FLAG_INCLUDE_PAC)) {
203 		/*
204 		 * KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY is equal to
205 		 * SDB_F_FOR_AS_REQ
206 		 *
207 		 * We use ANY to also allow AS_REQ for service principal names
208 		 * This is supported by Windows.
209 		 */
210 		sflags |= SDB_F_GET_ANY|SDB_F_FOR_AS_REQ;
211 	} else if (ks_is_tgs_principal(ctx, principal)) {
212 		sflags |= SDB_F_GET_KRBTGT;
213 	} else {
214 		sflags |= SDB_F_GET_SERVER|SDB_F_FOR_TGS_REQ;
215 	}
216 
217 	/* always set this or the created_by data will not be populated by samba's
218 	 * backend and we will fail to parse the entry later */
219 	sflags |= SDB_F_ADMIN_DATA;
220 
221 
222 fetch_referral_principal:
223 	ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
224 			      principal, sflags, 0, &sentry);
225 	switch (ret) {
226 	case 0:
227 		break;
228 	case SDB_ERR_NOENTRY:
229 		ret = KRB5_KDB_NOENTRY;
230 		goto done;
231 	case SDB_ERR_WRONG_REALM: {
232 		char *dest_realm = NULL;
233 		const char *our_realm = lpcfg_realm(ctx->db_ctx->lp_ctx);
234 
235 		if (sflags & SDB_F_FOR_AS_REQ) {
236 			/*
237 			 * If this is a request for a TGT, we are done. The KDC
238 			 * will return the correct error to the client.
239 			 */
240 			ret = 0;
241 			break;
242 		}
243 
244 		if (referral_principal != NULL) {
245 			sdb_free_entry(&sentry);
246 			ret = KRB5_KDB_NOENTRY;
247 			goto done;
248 		}
249 
250 		/*
251 		 * We get a TGS request
252 		 *
253 		 *     cifs/dc7.SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
254 		 *
255 		 * to our DC for the realm
256 		 *
257 		 *     ADDOM.SAMBA.EXAMPLE.COM
258 		 *
259 		 * We look up if we have and entry in the database and get an
260 		 * entry with the pricipal:
261 		 *
262 		 *     cifs/dc7.SAMBA2008R2.EXAMPLE.COM@SAMBA2008R2.EXAMPLE.COM
263 		 *
264 		 * and the error: SDB_ERR_WRONG_REALM.
265 		 *
266 		 * In the case of a TGS-REQ we need to return a referral ticket
267 		 * fo the next trust hop to the client. This ticket will have
268 		 * the following principal:
269 		 *
270 		 *     krbtgt/SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
271 		 *
272 		 * We just redo the lookup in the database with the referral
273 		 * principal and return success.
274 		 */
275 		dest_realm = smb_krb5_principal_get_realm(
276 			ctx, ctx->context, sentry.entry.principal);
277 		sdb_free_entry(&sentry);
278 		if (dest_realm == NULL) {
279 			ret = KRB5_KDB_NOENTRY;
280 			goto done;
281 		}
282 
283 		ret = smb_krb5_make_principal(ctx->context,
284 					      &referral_principal,
285 					      our_realm,
286 					      KRB5_TGS_NAME,
287 					      dest_realm,
288 					      NULL);
289 		TALLOC_FREE(dest_realm);
290 		if (ret != 0) {
291 			goto done;
292 		}
293 
294 		principal = referral_principal;
295 		goto fetch_referral_principal;
296 	}
297 	case SDB_ERR_NOT_FOUND_HERE:
298 		/* FIXME: RODC support */
299 	default:
300 		goto done;
301 	}
302 
303 	ret = sdb_entry_ex_to_kdb_entry_ex(ctx->context, &sentry, kentry);
304 
305 	sdb_free_entry(&sentry);
306 
307 	if ((kflags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) == 0) {
308 		kentry->attributes &= ~KRB5_KDB_DISALLOW_FORWARDABLE;
309 		kentry->attributes &= ~KRB5_KDB_DISALLOW_PROXIABLE;
310 	}
311 
312 done:
313 	krb5_free_principal(ctx->context, referral_principal);
314 	referral_principal = NULL;
315 
316 	if (ret) {
317 		free(kentry);
318 	} else {
319 		*_kentry = kentry;
320 	}
321 	return ret;
322 }
323 
mit_samba_get_firstkey(struct mit_samba_context * ctx,krb5_db_entry ** _kentry)324 int mit_samba_get_firstkey(struct mit_samba_context *ctx,
325 			   krb5_db_entry **_kentry)
326 {
327 	struct sdb_entry_ex sentry = {
328 		.free_entry = NULL,
329 	};
330 	krb5_db_entry *kentry;
331 	int ret;
332 
333 	kentry = malloc(sizeof(krb5_db_entry));
334 	if (kentry == NULL) {
335 		return ENOMEM;
336 	}
337 
338 	ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, &sentry);
339 	switch (ret) {
340 	case 0:
341 		break;
342 	case SDB_ERR_NOENTRY:
343 		free(kentry);
344 		return KRB5_KDB_NOENTRY;
345 	case SDB_ERR_NOT_FOUND_HERE:
346 		/* FIXME: RODC support */
347 	default:
348 		free(kentry);
349 		return ret;
350 	}
351 
352 	ret = sdb_entry_ex_to_kdb_entry_ex(ctx->context, &sentry, kentry);
353 
354 	sdb_free_entry(&sentry);
355 
356 	if (ret) {
357 		free(kentry);
358 	} else {
359 		*_kentry = kentry;
360 	}
361 	return ret;
362 }
363 
mit_samba_get_nextkey(struct mit_samba_context * ctx,krb5_db_entry ** _kentry)364 int mit_samba_get_nextkey(struct mit_samba_context *ctx,
365 			  krb5_db_entry **_kentry)
366 {
367 	struct sdb_entry_ex sentry = {
368 		.free_entry = NULL,
369 	};
370 	krb5_db_entry *kentry;
371 	int ret;
372 
373 	kentry = malloc(sizeof(krb5_db_entry));
374 	if (kentry == NULL) {
375 		return ENOMEM;
376 	}
377 
378 	ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, &sentry);
379 	switch (ret) {
380 	case 0:
381 		break;
382 	case SDB_ERR_NOENTRY:
383 		free(kentry);
384 		return KRB5_KDB_NOENTRY;
385 	case SDB_ERR_NOT_FOUND_HERE:
386 		/* FIXME: RODC support */
387 	default:
388 		free(kentry);
389 		return ret;
390 	}
391 
392 	ret = sdb_entry_ex_to_kdb_entry_ex(ctx->context, &sentry, kentry);
393 
394 	sdb_free_entry(&sentry);
395 
396 	if (ret) {
397 		free(kentry);
398 	} else {
399 		*_kentry = kentry;
400 	}
401 	return ret;
402 }
403 
mit_samba_get_pac(struct mit_samba_context * smb_ctx,krb5_context context,krb5_db_entry * client,krb5_keyblock * client_key,krb5_pac * pac)404 int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
405 		      krb5_context context,
406 		      krb5_db_entry *client,
407 		      krb5_keyblock *client_key,
408 		      krb5_pac *pac)
409 {
410 	TALLOC_CTX *tmp_ctx;
411 	DATA_BLOB *logon_info_blob = NULL;
412 	DATA_BLOB *upn_dns_info_blob = NULL;
413 	DATA_BLOB *cred_ndr = NULL;
414 	DATA_BLOB **cred_ndr_ptr = NULL;
415 	DATA_BLOB cred_blob = data_blob_null;
416 	DATA_BLOB *pcred_blob = NULL;
417 	NTSTATUS nt_status;
418 	krb5_error_code code;
419 	struct samba_kdc_entry *skdc_entry;
420 
421 	skdc_entry = talloc_get_type_abort(client->e_data,
422 					   struct samba_kdc_entry);
423 
424 	tmp_ctx = talloc_named(smb_ctx,
425 			       0,
426 			       "mit_samba_get_pac_data_blobs context");
427 	if (tmp_ctx == NULL) {
428 		return ENOMEM;
429 	}
430 
431 #if 0 /* TODO Find out if this is a pkinit_reply key */
432 	/* Check if we have a PREAUTH key */
433 	if (client_key != NULL) {
434 		cred_ndr_ptr = &cred_ndr;
435 	}
436 #endif
437 
438 	nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
439 					    skdc_entry,
440 					    &logon_info_blob,
441 					    cred_ndr_ptr,
442 					    &upn_dns_info_blob);
443 	if (!NT_STATUS_IS_OK(nt_status)) {
444 		talloc_free(tmp_ctx);
445 		return EINVAL;
446 	}
447 
448 	if (cred_ndr != NULL) {
449 		code = samba_kdc_encrypt_pac_credentials(context,
450 							 client_key,
451 							 cred_ndr,
452 							 tmp_ctx,
453 							 &cred_blob);
454 		if (code != 0) {
455 			talloc_free(tmp_ctx);
456 			return code;
457 		}
458 		pcred_blob = &cred_blob;
459 	}
460 
461 	code = samba_make_krb5_pac(context,
462 				   logon_info_blob,
463 				   pcred_blob,
464 				   upn_dns_info_blob,
465 				   NULL,
466 				   pac);
467 
468 	talloc_free(tmp_ctx);
469 	return code;
470 }
471 
mit_samba_reget_pac(struct mit_samba_context * ctx,krb5_context context,int flags,krb5_const_principal client_principal,krb5_db_entry * client,krb5_db_entry * server,krb5_db_entry * krbtgt,krb5_keyblock * krbtgt_keyblock,krb5_pac * pac)472 krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
473 				    krb5_context context,
474 				    int flags,
475 				    krb5_const_principal client_principal,
476 				    krb5_db_entry *client,
477 				    krb5_db_entry *server,
478 				    krb5_db_entry *krbtgt,
479 				    krb5_keyblock *krbtgt_keyblock,
480 				    krb5_pac *pac)
481 {
482 	TALLOC_CTX *tmp_ctx;
483 	krb5_error_code code;
484 	NTSTATUS nt_status;
485 	DATA_BLOB *pac_blob = NULL;
486 	DATA_BLOB *upn_blob = NULL;
487 	DATA_BLOB *deleg_blob = NULL;
488 	struct samba_kdc_entry *client_skdc_entry = NULL;
489 	struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
490 	struct samba_kdc_entry *server_skdc_entry = NULL;
491 	bool is_in_db = false;
492 	bool is_untrusted = false;
493 	size_t num_types = 0;
494 	uint32_t *types = NULL;
495 	uint32_t forced_next_type = 0;
496 	size_t i = 0;
497 	ssize_t logon_info_idx = -1;
498 	ssize_t delegation_idx = -1;
499 	ssize_t logon_name_idx = -1;
500 	ssize_t upn_dns_info_idx = -1;
501 	ssize_t srv_checksum_idx = -1;
502 	ssize_t kdc_checksum_idx = -1;
503 	krb5_pac new_pac = NULL;
504 	bool ok;
505 
506 	if (client != NULL) {
507 		client_skdc_entry =
508 			talloc_get_type_abort(client->e_data,
509 					      struct samba_kdc_entry);
510 
511 		/* The user account may be set not to want the PAC */
512 		ok = samba_princ_needs_pac(client_skdc_entry);
513 		if (!ok) {
514 			return EINVAL;
515 		}
516 	}
517 
518 	if (server == NULL) {
519 		return EINVAL;
520 	}
521 	server_skdc_entry =
522 		talloc_get_type_abort(server->e_data,
523 				      struct samba_kdc_entry);
524 
525 	if (krbtgt == NULL) {
526 		return EINVAL;
527 	}
528 	krbtgt_skdc_entry =
529 		talloc_get_type_abort(krbtgt->e_data,
530 				      struct samba_kdc_entry);
531 
532 	tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
533 	if (tmp_ctx == NULL) {
534 		return ENOMEM;
535 	}
536 
537 	code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
538 				     &is_in_db,
539 				     &is_untrusted);
540 	if (code != 0) {
541 		goto done;
542 	}
543 
544 	if (is_untrusted) {
545 		if (client == NULL) {
546 			code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
547 			goto done;
548 		}
549 
550 		nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
551 						    client_skdc_entry,
552 						    &pac_blob,
553 						    NULL,
554 						    &upn_blob);
555 		if (!NT_STATUS_IS_OK(nt_status)) {
556 			code = EINVAL;
557 			goto done;
558 		}
559 	} else {
560 		struct PAC_SIGNATURE_DATA *pac_srv_sig;
561 		struct PAC_SIGNATURE_DATA *pac_kdc_sig;
562 
563 		pac_blob = talloc_zero(tmp_ctx, DATA_BLOB);
564 		if (pac_blob == NULL) {
565 			code = ENOMEM;
566 			goto done;
567 		}
568 
569 		pac_srv_sig = talloc_zero(tmp_ctx, struct PAC_SIGNATURE_DATA);
570 		if (pac_srv_sig == NULL) {
571 			code = ENOMEM;
572 			goto done;
573 		}
574 
575 		pac_kdc_sig = talloc_zero(tmp_ctx, struct PAC_SIGNATURE_DATA);
576 		if (pac_kdc_sig == NULL) {
577 			code = ENOMEM;
578 			goto done;
579 		}
580 
581 		nt_status = samba_kdc_update_pac_blob(tmp_ctx,
582 						      context,
583 						      krbtgt_skdc_entry,
584 						      server_skdc_entry,
585 						      *pac,
586 						      pac_blob,
587 						      pac_srv_sig,
588 						      pac_kdc_sig);
589 		if (!NT_STATUS_IS_OK(nt_status)) {
590 			DEBUG(0, ("Update PAC blob failed: %s\n",
591 				  nt_errstr(nt_status)));
592 			code = EINVAL;
593 			goto done;
594 		}
595 
596 		if (is_in_db) {
597 			/*
598 			 * Now check the KDC signature, fetching the correct
599 			 * key based on the enc type.
600 			 */
601 			code = check_pac_checksum(pac_srv_sig->signature,
602 						  pac_kdc_sig,
603 						  context,
604 						  krbtgt_keyblock);
605 			if (code != 0) {
606 				DBG_INFO("PAC KDC signature failed to verify\n");
607 				goto done;
608 			}
609 		}
610 	}
611 
612 	if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
613 		deleg_blob = talloc_zero(tmp_ctx, DATA_BLOB);
614 		if (deleg_blob == NULL) {
615 			code = ENOMEM;
616 			goto done;
617 		}
618 
619 		nt_status = samba_kdc_update_delegation_info_blob(tmp_ctx,
620 								  context,
621 								  *pac,
622 								  server->princ,
623 								  discard_const(client_principal),
624 								  deleg_blob);
625 		if (!NT_STATUS_IS_OK(nt_status)) {
626 			DEBUG(0, ("Update delegation info failed: %s\n",
627 				  nt_errstr(nt_status)));
628 			code = EINVAL;
629 			goto done;
630 		}
631 	}
632 
633 	/* Check the types of the given PAC */
634 	code = krb5_pac_get_types(context, *pac, &num_types, &types);
635 	if (code != 0) {
636 		goto done;
637 	}
638 
639 	for (i = 0; i < num_types; i++) {
640 		switch (types[i]) {
641 		case PAC_TYPE_LOGON_INFO:
642 			if (logon_info_idx != -1) {
643 				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
644 					    types[i],
645 					    logon_info_idx,
646 					    i);
647 				SAFE_FREE(types);
648 				code = EINVAL;
649 				goto done;
650 			}
651 			logon_info_idx = i;
652 			break;
653 		case PAC_TYPE_CONSTRAINED_DELEGATION:
654 			if (delegation_idx != -1) {
655 				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
656 					    types[i],
657 					    delegation_idx,
658 					    i);
659 				SAFE_FREE(types);
660 				code = EINVAL;
661 				goto done;
662 			}
663 			delegation_idx = i;
664 			break;
665 		case PAC_TYPE_LOGON_NAME:
666 			if (logon_name_idx != -1) {
667 				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
668 					    types[i],
669 					    logon_name_idx,
670 					    i);
671 				SAFE_FREE(types);
672 				code = EINVAL;
673 				goto done;
674 			}
675 			logon_name_idx = i;
676 			break;
677 		case PAC_TYPE_UPN_DNS_INFO:
678 			if (upn_dns_info_idx != -1) {
679 				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
680 					    types[i],
681 					    upn_dns_info_idx,
682 					    i);
683 				SAFE_FREE(types);
684 				code = EINVAL;
685 				goto done;
686 			}
687 			upn_dns_info_idx = i;
688 			break;
689 		case PAC_TYPE_SRV_CHECKSUM:
690 			if (srv_checksum_idx != -1) {
691 				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
692 					    types[i],
693 					    srv_checksum_idx,
694 					    i);
695 				SAFE_FREE(types);
696 				code = EINVAL;
697 				goto done;
698 			}
699 			srv_checksum_idx = i;
700 			break;
701 		case PAC_TYPE_KDC_CHECKSUM:
702 			if (kdc_checksum_idx != -1) {
703 				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
704 					    types[i],
705 					    kdc_checksum_idx,
706 					    i);
707 				SAFE_FREE(types);
708 				code = EINVAL;
709 				goto done;
710 			}
711 			kdc_checksum_idx = i;
712 			break;
713 		default:
714 			continue;
715 		}
716 	}
717 
718 	if (logon_info_idx == -1) {
719 		DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n"));
720 		SAFE_FREE(types);
721 		code = EINVAL;
722 		goto done;
723 	}
724 	if (logon_name_idx == -1) {
725 		DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n"));
726 		SAFE_FREE(types);
727 		code = EINVAL;
728 		goto done;
729 	}
730 	if (srv_checksum_idx == -1) {
731 		DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n"));
732 		SAFE_FREE(types);
733 		code = EINVAL;
734 		goto done;
735 	}
736 	if (kdc_checksum_idx == -1) {
737 		DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n"));
738 		SAFE_FREE(types);
739 		code = EINVAL;
740 		goto done;
741 	}
742 
743 	/* Build an updated PAC */
744 	code = krb5_pac_init(context, &new_pac);
745 	if (code != 0) {
746 		SAFE_FREE(types);
747 		goto done;
748 	}
749 
750 	for (i = 0;;) {
751 		krb5_data type_data;
752 		DATA_BLOB type_blob = data_blob_null;
753 		uint32_t type;
754 
755 		if (forced_next_type != 0) {
756 			/*
757 			 * We need to inject possible missing types
758 			 */
759 			type = forced_next_type;
760 			forced_next_type = 0;
761 		} else if (i < num_types) {
762 			type = types[i];
763 			i++;
764 		} else {
765 			break;
766 		}
767 
768 		switch (type) {
769 		case PAC_TYPE_LOGON_INFO:
770 			type_blob = *pac_blob;
771 
772 			if (delegation_idx == -1 && deleg_blob != NULL) {
773 				/* inject CONSTRAINED_DELEGATION behind */
774 				forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION;
775 			}
776 			break;
777 		case PAC_TYPE_CONSTRAINED_DELEGATION:
778 			if (deleg_blob != NULL) {
779 				type_blob = *deleg_blob;
780 			}
781 			break;
782 		case PAC_TYPE_CREDENTIAL_INFO:
783 			/*
784 			 * Note that we copy the credential blob,
785 			 * as it's only usable with the PKINIT based
786 			 * AS-REP reply key, it's only available on the
787 			 * host which did the AS-REQ/AS-REP exchange.
788 			 *
789 			 * This matches Windows 2008R2...
790 			 */
791 			break;
792 		case PAC_TYPE_LOGON_NAME:
793 			/*
794 			 * This is generated in the main KDC code
795 			 */
796 			continue;
797 		case PAC_TYPE_UPN_DNS_INFO:
798 			/*
799 			 * Replace in the RODC case, otherwise
800 			 * upn_blob is NULL and we just copy.
801 			 */
802 			if (upn_blob != NULL) {
803 				type_blob = *upn_blob;
804 			}
805 			break;
806 		case PAC_TYPE_SRV_CHECKSUM:
807 			/*
808 			 * This is generated in the main KDC code
809 			 */
810 			continue;
811 		case PAC_TYPE_KDC_CHECKSUM:
812 			/*
813 			 * This is generated in the main KDC code
814 			 */
815 			continue;
816 		default:
817 			/* just copy... */
818 			break;
819 		}
820 
821 		if (type_blob.length != 0) {
822 			code = smb_krb5_copy_data_contents(&type_data,
823 							   type_blob.data,
824 							   type_blob.length);
825 			if (code != 0) {
826 				SAFE_FREE(types);
827 				krb5_pac_free(context, new_pac);
828 				goto done;
829 			}
830 		} else {
831 			code = krb5_pac_get_buffer(context,
832 						   *pac,
833 						   type,
834 						   &type_data);
835 			if (code != 0) {
836 				SAFE_FREE(types);
837 				krb5_pac_free(context, new_pac);
838 				goto done;
839 			}
840 		}
841 
842 		code = krb5_pac_add_buffer(context,
843 					   new_pac,
844 					   type,
845 					   &type_data);
846 		smb_krb5_free_data_contents(context, &type_data);
847 		if (code != 0) {
848 			SAFE_FREE(types);
849 			krb5_pac_free(context, new_pac);
850 			goto done;
851 		}
852 	}
853 
854 	SAFE_FREE(types);
855 
856 	/* We now replace the pac */
857 	krb5_pac_free(context, *pac);
858 	*pac = new_pac;
859 done:
860 	talloc_free(tmp_ctx);
861 	return code;
862 }
863 
864 /* provide header, function is exported but there are no public headers */
865 
866 krb5_error_code encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);
867 
868 /* this function allocates 'data' using malloc.
869  * The caller is responsible for freeing it */
samba_kdc_build_edata_reply(NTSTATUS nt_status,DATA_BLOB * e_data)870 static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
871 {
872 	krb5_error_code ret = 0;
873 	krb5_pa_data pa, *ppa[2];
874 	krb5_data *d = NULL;
875 
876 	if (!e_data)
877 		return;
878 
879 	e_data->data   = NULL;
880 	e_data->length = 0;
881 
882 	pa.magic		= KV5M_PA_DATA;
883 	pa.pa_type		= KRB5_PADATA_PW_SALT;
884 	pa.length		= 12;
885 	pa.contents		= malloc(pa.length);
886 	if (!pa.contents) {
887 		return;
888 	}
889 
890 	SIVAL(pa.contents, 0, NT_STATUS_V(nt_status));
891 	SIVAL(pa.contents, 4, 0);
892 	SIVAL(pa.contents, 8, 1);
893 
894 	ppa[0] = &pa;
895 	ppa[1] = NULL;
896 
897 	ret = encode_krb5_padata_sequence(ppa, &d);
898 	free(pa.contents);
899 	if (ret) {
900 		return;
901 	}
902 
903 	e_data->data   = (uint8_t *)d->data;
904 	e_data->length = d->length;
905 
906 	/* free d, not d->data - gd */
907 	free(d);
908 
909 	return;
910 }
911 
mit_samba_check_client_access(struct mit_samba_context * ctx,krb5_db_entry * client,const char * client_name,krb5_db_entry * server,const char * server_name,const char * netbios_name,bool password_change,DATA_BLOB * e_data)912 int mit_samba_check_client_access(struct mit_samba_context *ctx,
913 				  krb5_db_entry *client,
914 				  const char *client_name,
915 				  krb5_db_entry *server,
916 				  const char *server_name,
917 				  const char *netbios_name,
918 				  bool password_change,
919 				  DATA_BLOB *e_data)
920 {
921 	struct samba_kdc_entry *skdc_entry;
922 	NTSTATUS nt_status;
923 
924 	skdc_entry = talloc_get_type(client->e_data, struct samba_kdc_entry);
925 
926 	nt_status = samba_kdc_check_client_access(skdc_entry,
927 						  client_name,
928 						  netbios_name,
929 						  password_change);
930 
931 	if (!NT_STATUS_IS_OK(nt_status)) {
932 		if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
933 			return ENOMEM;
934 		}
935 
936 		samba_kdc_build_edata_reply(nt_status, e_data);
937 
938 		return samba_kdc_map_policy_err(nt_status);
939 	}
940 
941 	return 0;
942 }
943 
mit_samba_check_s4u2proxy(struct mit_samba_context * ctx,krb5_db_entry * kentry,const char * target_name,bool is_nt_enterprise_name)944 int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
945 			      krb5_db_entry *kentry,
946 			      const char *target_name,
947 			      bool is_nt_enterprise_name)
948 {
949 #if 1
950 	/*
951 	 * This is disabled because mit_samba_update_pac_data() does not handle
952 	 * S4U_DELEGATION_INFO
953 	 */
954 
955 	return KRB5KDC_ERR_BADOPTION;
956 #else
957 	krb5_principal target_principal;
958 	int flags = 0;
959 	int ret;
960 
961 	if (is_nt_enterprise_name) {
962 		flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
963 	}
964 
965 	ret = krb5_parse_name_flags(ctx->context, target_name,
966 				    flags, &target_principal);
967 	if (ret) {
968 		return ret;
969 	}
970 
971 	ret = samba_kdc_check_s4u2proxy(ctx->context,
972 					ctx->db_ctx,
973 					skdc_entry,
974 					target_principal);
975 
976 	krb5_free_principal(ctx->context, target_principal);
977 
978 	return ret;
979 #endif
980 }
981 
mit_samba_change_pwd_error(krb5_context context,NTSTATUS result,enum samPwdChangeReason reject_reason,struct samr_DomInfo1 * dominfo)982 static krb5_error_code mit_samba_change_pwd_error(krb5_context context,
983 						  NTSTATUS result,
984 						  enum samPwdChangeReason reject_reason,
985 						  struct samr_DomInfo1 *dominfo)
986 {
987 	krb5_error_code code = KADM5_PASS_Q_GENERIC;
988 
989 	if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
990 		code = KADM5_BAD_PRINCIPAL;
991 		krb5_set_error_message(context,
992 				       code,
993 				       "No such user when changing password");
994 	}
995 	if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
996 		code = KADM5_PASS_Q_GENERIC;
997 		krb5_set_error_message(context,
998 				       code,
999 				       "Not permitted to change password");
1000 	}
1001 	if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) &&
1002 	    dominfo != NULL) {
1003 		switch (reject_reason) {
1004 		case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
1005 			code = KADM5_PASS_Q_TOOSHORT;
1006 			krb5_set_error_message(context,
1007 					       code,
1008 					       "Password too short, password "
1009 					       "must be at least %d characters "
1010 					       "long.",
1011 					       dominfo->min_password_length);
1012 			break;
1013 		case SAM_PWD_CHANGE_NOT_COMPLEX:
1014 			code = KADM5_PASS_Q_DICT;
1015 			krb5_set_error_message(context,
1016 					       code,
1017 					       "Password does not meet "
1018 					       "complexity requirements");
1019 			break;
1020 		case SAM_PWD_CHANGE_PWD_IN_HISTORY:
1021 			code = KADM5_PASS_TOOSOON;
1022 			krb5_set_error_message(context,
1023 					       code,
1024 					       "Password is already in password "
1025 					       "history. New password must not "
1026 					       "match any of your %d previous "
1027 					       "passwords.",
1028 					       dominfo->password_history_length);
1029 			break;
1030 		default:
1031 			code = KADM5_PASS_Q_GENERIC;
1032 			krb5_set_error_message(context,
1033 					       code,
1034 					       "Password change rejected, "
1035 					       "password changes may not be "
1036 					       "permitted on this account, or "
1037 					       "the minimum password age may "
1038 					       "not have elapsed.");
1039 			break;
1040 		}
1041 	}
1042 
1043 	return code;
1044 }
1045 
mit_samba_kpasswd_change_password(struct mit_samba_context * ctx,char * pwd,krb5_db_entry * db_entry)1046 int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
1047 				      char *pwd,
1048 				      krb5_db_entry *db_entry)
1049 {
1050 	NTSTATUS status;
1051 	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1052 	TALLOC_CTX *tmp_ctx;
1053 	DATA_BLOB password;
1054 	enum samPwdChangeReason reject_reason;
1055 	struct samr_DomInfo1 *dominfo;
1056 	const char *error_string = NULL;
1057 	struct auth_user_info_dc *user_info_dc;
1058 	struct samba_kdc_entry *p;
1059 	krb5_error_code code = 0;
1060 
1061 #ifdef DEBUG_PASSWORD
1062 	DEBUG(1,("mit_samba_kpasswd_change_password called with: %s\n", pwd));
1063 #endif
1064 
1065 	tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
1066 	if (tmp_ctx == NULL) {
1067 		return ENOMEM;
1068 	}
1069 
1070 	p = (struct samba_kdc_entry *)db_entry->e_data;
1071 
1072 	status = authsam_make_user_info_dc(tmp_ctx,
1073 					   ctx->db_ctx->samdb,
1074 					   lpcfg_netbios_name(ctx->db_ctx->lp_ctx),
1075 					   lpcfg_sam_name(ctx->db_ctx->lp_ctx),
1076 					   lpcfg_sam_dnsname(ctx->db_ctx->lp_ctx),
1077 					   p->realm_dn,
1078 					   p->msg,
1079 					   data_blob(NULL, 0),
1080 					   data_blob(NULL, 0),
1081 					   &user_info_dc);
1082 	if (!NT_STATUS_IS_OK(status)) {
1083 		DEBUG(1,("authsam_make_user_info_dc failed: %s\n",
1084 			nt_errstr(status)));
1085 		talloc_free(tmp_ctx);
1086 		return EINVAL;
1087 	}
1088 
1089 	status = auth_generate_session_info(tmp_ctx,
1090 					    ctx->db_ctx->lp_ctx,
1091 					    ctx->db_ctx->samdb,
1092 					    user_info_dc,
1093 					    0, /* session_info_flags */
1094 					    &ctx->session_info);
1095 
1096 	if (!NT_STATUS_IS_OK(status)) {
1097 		DEBUG(1,("auth_generate_session_info failed: %s\n",
1098 			nt_errstr(status)));
1099 		talloc_free(tmp_ctx);
1100 		return EINVAL;
1101 	}
1102 
1103 	/* password is expected as UTF16 */
1104 
1105 	if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
1106 				   pwd, strlen(pwd),
1107 				   &password.data, &password.length)) {
1108 		DEBUG(1,("convert_string_talloc failed\n"));
1109 		talloc_free(tmp_ctx);
1110 		return EINVAL;
1111 	}
1112 
1113 	status = samdb_kpasswd_change_password(tmp_ctx,
1114 					       ctx->db_ctx->lp_ctx,
1115 					       ctx->db_ctx->ev_ctx,
1116 					       ctx->db_ctx->samdb,
1117 					       ctx->session_info,
1118 					       &password,
1119 					       &reject_reason,
1120 					       &dominfo,
1121 					       &error_string,
1122 					       &result);
1123 	if (!NT_STATUS_IS_OK(status)) {
1124 		DEBUG(1,("samdb_kpasswd_change_password failed: %s\n",
1125 			nt_errstr(status)));
1126 		code = KADM5_PASS_Q_GENERIC;
1127 		krb5_set_error_message(ctx->context, code, "%s", error_string);
1128 		goto out;
1129 	}
1130 
1131 	if (!NT_STATUS_IS_OK(result)) {
1132 		code = mit_samba_change_pwd_error(ctx->context,
1133 						  result,
1134 						  reject_reason,
1135 						  dominfo);
1136 	}
1137 
1138 out:
1139 	talloc_free(tmp_ctx);
1140 
1141 	return code;
1142 }
1143 
mit_samba_zero_bad_password_count(krb5_db_entry * db_entry)1144 void mit_samba_zero_bad_password_count(krb5_db_entry *db_entry)
1145 {
1146 	struct netr_SendToSamBase *send_to_sam = NULL;
1147 	struct samba_kdc_entry *p;
1148 	struct ldb_dn *domain_dn;
1149 
1150 	p = (struct samba_kdc_entry *)db_entry->e_data;
1151 
1152 	domain_dn = ldb_get_default_basedn(p->kdc_db_ctx->samdb);
1153 
1154 	authsam_logon_success_accounting(p->kdc_db_ctx->samdb,
1155 					 p->msg,
1156 					 domain_dn,
1157 					 true,
1158 					 &send_to_sam);
1159 	/* TODO: RODC support */
1160 }
1161 
1162 
mit_samba_update_bad_password_count(krb5_db_entry * db_entry)1163 void mit_samba_update_bad_password_count(krb5_db_entry *db_entry)
1164 {
1165 	struct samba_kdc_entry *p;
1166 
1167 	p = (struct samba_kdc_entry *)db_entry->e_data;
1168 
1169 	authsam_update_bad_pwd_count(p->kdc_db_ctx->samdb,
1170 				     p->msg,
1171 				     ldb_get_default_basedn(p->kdc_db_ctx->samdb));
1172 }
1173