Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : PAC Glue between Samba and the KDC
5 :
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 : Copyright (C) Simo Sorce <idra@samba.org> 2010
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 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "lib/replace/replace.h"
25 : #include "lib/replace/system/kerberos.h"
26 : #include "lib/util/debug.h"
27 : #include "lib/util/samba_util.h"
28 : #include "lib/util/talloc_stack.h"
29 :
30 : #include "auth/auth_sam_reply.h"
31 : #include "auth/kerberos/kerberos.h"
32 : #include "auth/kerberos/pac_utils.h"
33 : #include "libcli/security/security.h"
34 : #include "libds/common/flags.h"
35 : #include "librpc/gen_ndr/ndr_krb5pac.h"
36 : #include "param/param.h"
37 : #include "source4/auth/auth.h"
38 : #include "source4/dsdb/common/util.h"
39 : #include "source4/dsdb/samdb/samdb.h"
40 : #include "source4/kdc/samba_kdc.h"
41 : #include "source4/kdc/pac-glue.h"
42 :
43 : #include <ldb.h>
44 :
45 : #undef DBGC_CLASS
46 : #define DBGC_CLASS DBGC_KERBEROS
47 :
48 : static
49 55161 : NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
50 : const struct auth_user_info_dc *info,
51 : DATA_BLOB *pac_data,
52 : DATA_BLOB *requester_sid_blob)
53 : {
54 : struct netr_SamInfo3 *info3;
55 : union PAC_INFO pac_info;
56 : enum ndr_err_code ndr_err;
57 : NTSTATUS nt_status;
58 :
59 55161 : ZERO_STRUCT(pac_info);
60 :
61 55161 : *pac_data = data_blob_null;
62 55161 : if (requester_sid_blob != NULL) {
63 17199 : *requester_sid_blob = data_blob_null;
64 : }
65 :
66 55161 : nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3);
67 55161 : if (!NT_STATUS_IS_OK(nt_status)) {
68 0 : DEBUG(1, ("Getting Samba info failed: %s\n",
69 : nt_errstr(nt_status)));
70 0 : return nt_status;
71 : }
72 :
73 55161 : pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO);
74 55161 : if (!pac_info.logon_info.info) {
75 0 : return NT_STATUS_NO_MEMORY;
76 : }
77 :
78 55161 : pac_info.logon_info.info->info3 = *info3;
79 :
80 55161 : ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
81 : PAC_TYPE_LOGON_INFO,
82 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
83 55161 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
85 0 : DEBUG(1, ("PAC_LOGON_INFO (presig) push failed: %s\n",
86 : nt_errstr(nt_status)));
87 0 : return nt_status;
88 : }
89 :
90 55161 : if (requester_sid_blob != NULL && info->num_sids > 0) {
91 : union PAC_INFO pac_requester_sid;
92 :
93 17199 : ZERO_STRUCT(pac_requester_sid);
94 :
95 17199 : pac_requester_sid.requester_sid.sid = info->sids[0];
96 :
97 17199 : ndr_err = ndr_push_union_blob(requester_sid_blob, mem_ctx,
98 : &pac_requester_sid,
99 : PAC_TYPE_REQUESTER_SID,
100 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
101 17199 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
102 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
103 0 : DEBUG(1, ("PAC_REQUESTER_SID (presig) push failed: %s\n",
104 : nt_errstr(nt_status)));
105 0 : return nt_status;
106 : }
107 : }
108 :
109 55161 : return NT_STATUS_OK;
110 : }
111 :
112 : static
113 19021 : NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
114 : const struct auth_user_info_dc *info,
115 : DATA_BLOB *upn_data)
116 : {
117 : union PAC_INFO pac_upn;
118 : enum ndr_err_code ndr_err;
119 : NTSTATUS nt_status;
120 : bool ok;
121 :
122 19021 : ZERO_STRUCT(pac_upn);
123 :
124 19021 : *upn_data = data_blob_null;
125 :
126 19021 : pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
127 38042 : pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(mem_ctx,
128 19021 : info->info->dns_domain_name);
129 19021 : if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
130 0 : return NT_STATUS_NO_MEMORY;
131 : }
132 19021 : if (info->info->user_principal_constructed) {
133 17934 : pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
134 : }
135 :
136 19021 : pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
137 :
138 : pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname
139 19021 : = info->info->account_name;
140 :
141 : pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid
142 19021 : = &info->sids[0];
143 :
144 19021 : ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
145 : PAC_TYPE_UPN_DNS_INFO,
146 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
147 19021 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
148 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
149 0 : DEBUG(1, ("PAC UPN_DNS_INFO (presig) push failed: %s\n",
150 : nt_errstr(nt_status)));
151 0 : return nt_status;
152 : }
153 :
154 19021 : ok = data_blob_pad(mem_ctx, upn_data, 8);
155 19021 : if (!ok) {
156 0 : return NT_STATUS_NO_MEMORY;
157 : }
158 :
159 19021 : return NT_STATUS_OK;
160 : }
161 :
162 : static
163 17157 : NTSTATUS samba_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
164 : uint64_t pac_attributes,
165 : DATA_BLOB *pac_attrs_data)
166 : {
167 : union PAC_INFO pac_attrs;
168 : enum ndr_err_code ndr_err;
169 : NTSTATUS nt_status;
170 :
171 17157 : ZERO_STRUCT(pac_attrs);
172 :
173 17157 : *pac_attrs_data = data_blob_null;
174 :
175 : /* Set the length of the flags in bits. */
176 17157 : pac_attrs.attributes_info.flags_length = 2;
177 17157 : pac_attrs.attributes_info.flags = pac_attributes;
178 :
179 17157 : ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
180 : PAC_TYPE_ATTRIBUTES_INFO,
181 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
182 17157 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
183 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
184 0 : DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
185 : nt_errstr(nt_status)));
186 0 : return nt_status;
187 : }
188 :
189 17157 : return NT_STATUS_OK;
190 : }
191 :
192 : static
193 0 : NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
194 : const struct ldb_message *msg,
195 : DATA_BLOB *cred_blob)
196 : {
197 : enum ndr_err_code ndr_err;
198 : NTSTATUS nt_status;
199 0 : struct samr_Password *lm_hash = NULL;
200 0 : struct samr_Password *nt_hash = NULL;
201 0 : struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg = {
202 : .version = 0,
203 : };
204 0 : DATA_BLOB ntlm_blob = data_blob_null;
205 0 : struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs[1] = {{
206 : .credential_size = 0,
207 : }};
208 0 : struct PAC_CREDENTIAL_DATA cred_data = {
209 : .credential_count = 0,
210 : };
211 : struct PAC_CREDENTIAL_DATA_NDR cred_ndr;
212 :
213 0 : ZERO_STRUCT(cred_ndr);
214 :
215 0 : *cred_blob = data_blob_null;
216 :
217 0 : lm_hash = samdb_result_hash(mem_ctx, msg, "dBCSPwd");
218 0 : if (lm_hash != NULL) {
219 0 : bool zero = all_zero(lm_hash->hash, 16);
220 0 : if (zero) {
221 0 : lm_hash = NULL;
222 : }
223 : }
224 0 : if (lm_hash != NULL) {
225 0 : DEBUG(5, ("Passing LM password hash through credentials set\n"));
226 0 : ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_LM_HASH;
227 0 : ntlm_secpkg.lm_password = *lm_hash;
228 0 : ZERO_STRUCTP(lm_hash);
229 0 : TALLOC_FREE(lm_hash);
230 : }
231 :
232 0 : nt_hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
233 0 : if (nt_hash != NULL) {
234 0 : bool zero = all_zero(nt_hash->hash, 16);
235 0 : if (zero) {
236 0 : nt_hash = NULL;
237 : }
238 : }
239 0 : if (nt_hash != NULL) {
240 0 : DEBUG(5, ("Passing LM password hash through credentials set\n"));
241 0 : ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_NT_HASH;
242 0 : ntlm_secpkg.nt_password = *nt_hash;
243 0 : ZERO_STRUCTP(nt_hash);
244 0 : TALLOC_FREE(nt_hash);
245 : }
246 :
247 0 : if (ntlm_secpkg.flags == 0) {
248 0 : return NT_STATUS_OK;
249 : }
250 :
251 : #ifdef DEBUG_PASSWORD
252 0 : if (DEBUGLVL(11)) {
253 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG, &ntlm_secpkg);
254 : }
255 : #endif
256 :
257 0 : ndr_err = ndr_push_struct_blob(&ntlm_blob, mem_ctx, &ntlm_secpkg,
258 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG);
259 0 : ZERO_STRUCT(ntlm_secpkg);
260 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
261 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
262 0 : DEBUG(1, ("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
263 : nt_errstr(nt_status)));
264 0 : return nt_status;
265 : }
266 :
267 0 : DEBUG(10, ("NTLM credential BLOB (len %zu) for user\n",
268 : ntlm_blob.length));
269 0 : dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
270 0 : ntlm_blob.data, ntlm_blob.length);
271 :
272 0 : secpkgs[0].package_name.string = discard_const_p(char, "NTLM");
273 0 : secpkgs[0].credential_size = ntlm_blob.length;
274 0 : secpkgs[0].credential = ntlm_blob.data;
275 :
276 0 : cred_data.credential_count = ARRAY_SIZE(secpkgs);
277 0 : cred_data.credentials = secpkgs;
278 :
279 : #ifdef DEBUG_PASSWORD
280 0 : if (DEBUGLVL(11)) {
281 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA, &cred_data);
282 : }
283 : #endif
284 :
285 0 : cred_ndr.ctr.data = &cred_data;
286 :
287 : #ifdef DEBUG_PASSWORD
288 0 : if (DEBUGLVL(11)) {
289 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR, &cred_ndr);
290 : }
291 : #endif
292 :
293 0 : ndr_err = ndr_push_struct_blob(cred_blob, mem_ctx, &cred_ndr,
294 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_DATA_NDR);
295 0 : data_blob_clear(&ntlm_blob);
296 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
297 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
298 0 : DEBUG(1, ("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
299 : nt_errstr(nt_status)));
300 0 : return nt_status;
301 : }
302 :
303 0 : DEBUG(10, ("Created credential BLOB (len %zu) for user\n",
304 : cred_blob->length));
305 0 : dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
306 0 : cred_blob->data, cred_blob->length);
307 :
308 0 : return NT_STATUS_OK;
309 : }
310 :
311 : #ifdef SAMBA4_USES_HEIMDAL
312 0 : krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
313 : const krb5_keyblock *pkreplykey,
314 : const DATA_BLOB *cred_ndr_blob,
315 : TALLOC_CTX *mem_ctx,
316 : DATA_BLOB *cred_info_blob)
317 : {
318 : krb5_crypto cred_crypto;
319 : krb5_enctype cred_enctype;
320 : krb5_data cred_ndr_crypt;
321 0 : struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
322 : krb5_error_code ret;
323 : const char *krb5err;
324 : enum ndr_err_code ndr_err;
325 : NTSTATUS nt_status;
326 :
327 0 : *cred_info_blob = data_blob_null;
328 :
329 0 : ret = krb5_crypto_init(context, pkreplykey, ETYPE_NULL,
330 : &cred_crypto);
331 0 : if (ret != 0) {
332 0 : krb5err = krb5_get_error_message(context, ret);
333 0 : DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
334 0 : krb5_free_error_message(context, krb5err);
335 0 : return ret;
336 : }
337 :
338 0 : ret = krb5_crypto_getenctype(context, cred_crypto, &cred_enctype);
339 0 : if (ret != 0) {
340 0 : DEBUG(1, ("Failed getting crypto type for key\n"));
341 0 : krb5_crypto_destroy(context, cred_crypto);
342 0 : return ret;
343 : }
344 :
345 0 : DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
346 : cred_ndr_blob->length));
347 0 : dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
348 0 : cred_ndr_blob->data, cred_ndr_blob->length);
349 :
350 0 : ret = krb5_encrypt(context, cred_crypto,
351 : KRB5_KU_OTHER_ENCRYPTED,
352 0 : cred_ndr_blob->data, cred_ndr_blob->length,
353 : &cred_ndr_crypt);
354 0 : krb5_crypto_destroy(context, cred_crypto);
355 0 : if (ret != 0) {
356 0 : krb5err = krb5_get_error_message(context, ret);
357 0 : DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
358 0 : krb5_free_error_message(context, krb5err);
359 0 : return ret;
360 : }
361 :
362 0 : pac_cred_info.encryption_type = cred_enctype;
363 0 : pac_cred_info.encrypted_data.length = cred_ndr_crypt.length;
364 0 : pac_cred_info.encrypted_data.data = (uint8_t *)cred_ndr_crypt.data;
365 :
366 0 : if (DEBUGLVL(10)) {
367 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
368 : }
369 :
370 0 : ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
371 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
372 0 : krb5_data_free(&cred_ndr_crypt);
373 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
375 0 : DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
376 : nt_errstr(nt_status)));
377 0 : return KRB5KDC_ERR_SVC_UNAVAILABLE;
378 : }
379 :
380 0 : DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
381 : cred_info_blob->length, (int)pac_cred_info.encryption_type));
382 0 : dump_data_pw("PAC_CREDENTIAL_INFO",
383 0 : cred_info_blob->data, cred_info_blob->length);
384 :
385 0 : return 0;
386 : }
387 : #else /* SAMBA4_USES_HEIMDAL */
388 0 : krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
389 : const krb5_keyblock *pkreplykey,
390 : const DATA_BLOB *cred_ndr_blob,
391 : TALLOC_CTX *mem_ctx,
392 : DATA_BLOB *cred_info_blob)
393 : {
394 : krb5_key cred_key;
395 : krb5_enctype cred_enctype;
396 0 : struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
397 : krb5_error_code code;
398 : const char *krb5err;
399 : enum ndr_err_code ndr_err;
400 : NTSTATUS nt_status;
401 : krb5_data cred_ndr_data;
402 : krb5_enc_data cred_ndr_crypt;
403 0 : size_t enc_len = 0;
404 :
405 0 : *cred_info_blob = data_blob_null;
406 :
407 0 : code = krb5_k_create_key(context,
408 : pkreplykey,
409 : &cred_key);
410 0 : if (code != 0) {
411 0 : krb5err = krb5_get_error_message(context, code);
412 0 : DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
413 0 : krb5_free_error_message(context, krb5err);
414 0 : return code;
415 : }
416 :
417 0 : cred_enctype = krb5_k_key_enctype(context, cred_key);
418 :
419 0 : DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
420 : cred_ndr_blob->length));
421 0 : dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
422 0 : cred_ndr_blob->data, cred_ndr_blob->length);
423 :
424 0 : pac_cred_info.encryption_type = cred_enctype;
425 :
426 0 : cred_ndr_data.magic = 0;
427 0 : cred_ndr_data.data = (char *)cred_ndr_blob->data;
428 0 : cred_ndr_data.length = cred_ndr_blob->length;
429 :
430 0 : code = krb5_c_encrypt_length(context,
431 : cred_enctype,
432 0 : cred_ndr_data.length,
433 : &enc_len);
434 0 : if (code != 0) {
435 0 : krb5err = krb5_get_error_message(context, code);
436 0 : DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
437 0 : krb5_free_error_message(context, krb5err);
438 0 : return code;
439 : }
440 :
441 0 : pac_cred_info.encrypted_data = data_blob_talloc_zero(mem_ctx, enc_len);
442 0 : if (pac_cred_info.encrypted_data.data == NULL) {
443 0 : DBG_ERR("Out of memory\n");
444 0 : return ENOMEM;
445 : }
446 :
447 0 : cred_ndr_crypt.ciphertext.length = enc_len;
448 0 : cred_ndr_crypt.ciphertext.data = (char *)pac_cred_info.encrypted_data.data;
449 :
450 0 : code = krb5_k_encrypt(context,
451 : cred_key,
452 : KRB5_KU_OTHER_ENCRYPTED,
453 : NULL,
454 : &cred_ndr_data,
455 : &cred_ndr_crypt);
456 0 : krb5_k_free_key(context, cred_key);
457 0 : if (code != 0) {
458 0 : krb5err = krb5_get_error_message(context, code);
459 0 : DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
460 0 : krb5_free_error_message(context, krb5err);
461 0 : return code;
462 : }
463 :
464 0 : if (DEBUGLVL(10)) {
465 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
466 : }
467 :
468 0 : ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
469 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
470 0 : TALLOC_FREE(pac_cred_info.encrypted_data.data);
471 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
472 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
473 0 : DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
474 : nt_errstr(nt_status)));
475 0 : return KRB5KDC_ERR_SVC_UNAVAILABLE;
476 : }
477 :
478 0 : DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
479 : cred_info_blob->length, (int)pac_cred_info.encryption_type));
480 0 : dump_data_pw("PAC_CREDENTIAL_INFO",
481 0 : cred_info_blob->data, cred_info_blob->length);
482 :
483 0 : return 0;
484 : }
485 : #endif /* SAMBA4_USES_HEIMDAL */
486 :
487 :
488 : /**
489 : * @brief Create a PAC with the given blobs (logon, credentials, upn and
490 : * delegation).
491 : *
492 : * @param[in] context The KRB5 context to use.
493 : *
494 : * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
495 : * use NULL to ignore it.
496 : *
497 : * @param[in] cred_blob Fill the credentials info PAC buffer with the given
498 : * blob, use NULL to ignore it.
499 : *
500 : * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
501 : * NULL to ignore it.
502 : *
503 : * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
504 : * blob, use NULL to ignore it.
505 : *
506 : * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
507 : * given blob, use NULL to ignore it.
508 : *
509 : * @param[in] device_info_blob Fill the device info PAC buffer with the given
510 : * blob, use NULL to ignore it.
511 : *
512 : * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
513 : * blob, use NULL to ignore it.
514 : *
515 : * @param[in] pac The pac buffer to fill. This should be allocated with
516 : * krb5_pac_init() already.
517 : *
518 : * @returns 0 on success or a corresponding KRB5 error.
519 : */
520 18979 : krb5_error_code samba_make_krb5_pac(krb5_context context,
521 : const DATA_BLOB *logon_blob,
522 : const DATA_BLOB *cred_blob,
523 : const DATA_BLOB *upn_blob,
524 : const DATA_BLOB *pac_attrs_blob,
525 : const DATA_BLOB *requester_sid_blob,
526 : const DATA_BLOB *deleg_blob,
527 : const DATA_BLOB *client_claims_blob,
528 : const DATA_BLOB *device_info_blob,
529 : const DATA_BLOB *device_claims_blob,
530 : krb5_pac pac)
531 : {
532 : krb5_data logon_data;
533 : krb5_error_code ret;
534 : #ifdef SAMBA4_USES_HEIMDAL
535 18979 : char null_byte = '\0';
536 18979 : krb5_data null_data = smb_krb5_make_data(&null_byte, 0);
537 : #endif
538 :
539 : /* The user account may be set not to want the PAC */
540 18979 : if (logon_blob == NULL) {
541 0 : return 0;
542 : }
543 :
544 18979 : logon_data = smb_krb5_data_from_blob(*logon_blob);
545 18979 : ret = krb5_pac_add_buffer(context, pac, PAC_TYPE_LOGON_INFO, &logon_data);
546 18979 : if (ret != 0) {
547 0 : return ret;
548 : }
549 :
550 18979 : if (device_info_blob != NULL) {
551 0 : krb5_data device_info_data = smb_krb5_data_from_blob(*device_info_blob);
552 0 : ret = krb5_pac_add_buffer(context, pac,
553 : PAC_TYPE_DEVICE_INFO,
554 : &device_info_data);
555 0 : if (ret != 0) {
556 0 : return ret;
557 : }
558 : }
559 :
560 18979 : if (client_claims_blob != NULL) {
561 0 : krb5_data client_claims_data = smb_krb5_data_from_blob(*client_claims_blob);
562 0 : ret = krb5_pac_add_buffer(context, pac,
563 : PAC_TYPE_CLIENT_CLAIMS_INFO,
564 : &client_claims_data);
565 0 : if (ret != 0) {
566 0 : return ret;
567 : }
568 : }
569 :
570 18979 : if (device_claims_blob != NULL) {
571 0 : krb5_data device_claims_data = smb_krb5_data_from_blob(*device_claims_blob);
572 0 : ret = krb5_pac_add_buffer(context, pac,
573 : PAC_TYPE_DEVICE_CLAIMS_INFO,
574 : &device_claims_data);
575 0 : if (ret != 0) {
576 0 : return ret;
577 : }
578 : }
579 :
580 18979 : if (cred_blob != NULL) {
581 0 : krb5_data cred_data = smb_krb5_data_from_blob(*cred_blob);
582 0 : ret = krb5_pac_add_buffer(context, pac,
583 : PAC_TYPE_CREDENTIAL_INFO,
584 : &cred_data);
585 0 : if (ret != 0) {
586 0 : return ret;
587 : }
588 : }
589 :
590 : #ifdef SAMBA4_USES_HEIMDAL
591 : /*
592 : * null_data will be filled by the generic KDC code in the caller
593 : * here we just add it in order to have it before
594 : * PAC_TYPE_UPN_DNS_INFO
595 : *
596 : * Not needed with MIT Kerberos - asn
597 : */
598 18979 : ret = krb5_pac_add_buffer(context, pac,
599 : PAC_TYPE_LOGON_NAME,
600 : &null_data);
601 18979 : if (ret != 0) {
602 0 : return ret;
603 : }
604 : #endif
605 :
606 18979 : if (upn_blob != NULL) {
607 18979 : krb5_data upn_data = smb_krb5_data_from_blob(*upn_blob);
608 18979 : ret = krb5_pac_add_buffer(context, pac,
609 : PAC_TYPE_UPN_DNS_INFO,
610 : &upn_data);
611 18979 : if (ret != 0) {
612 0 : return ret;
613 : }
614 : }
615 :
616 18979 : if (pac_attrs_blob != NULL) {
617 17157 : krb5_data pac_attrs_data = smb_krb5_data_from_blob(*pac_attrs_blob);
618 17157 : ret = krb5_pac_add_buffer(context, pac,
619 : PAC_TYPE_ATTRIBUTES_INFO,
620 : &pac_attrs_data);
621 17157 : if (ret != 0) {
622 0 : return ret;
623 : }
624 : }
625 :
626 18979 : if (requester_sid_blob != NULL) {
627 17157 : krb5_data requester_sid_data = smb_krb5_data_from_blob(*requester_sid_blob);
628 17157 : ret = krb5_pac_add_buffer(context, pac,
629 : PAC_TYPE_REQUESTER_SID,
630 : &requester_sid_data);
631 17157 : if (ret != 0) {
632 0 : return ret;
633 : }
634 : }
635 :
636 18979 : if (deleg_blob != NULL) {
637 0 : krb5_data deleg_data = smb_krb5_data_from_blob(*deleg_blob);
638 0 : ret = krb5_pac_add_buffer(context, pac,
639 : PAC_TYPE_CONSTRAINED_DELEGATION,
640 : &deleg_data);
641 0 : if (ret != 0) {
642 0 : return ret;
643 : }
644 : }
645 :
646 18979 : return ret;
647 : }
648 :
649 36182 : bool samba_princ_needs_pac(struct samba_kdc_entry *skdc_entry)
650 : {
651 :
652 : uint32_t userAccountControl;
653 :
654 : /* The service account may be set not to want the PAC */
655 36182 : userAccountControl = ldb_msg_find_attr_as_uint(skdc_entry->msg, "userAccountControl", 0);
656 36182 : if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
657 9 : return false;
658 : }
659 :
660 36173 : return true;
661 : }
662 :
663 14773 : int samba_client_requested_pac(krb5_context context,
664 : const krb5_pac *pac,
665 : TALLOC_CTX *mem_ctx,
666 : bool *requested_pac)
667 : {
668 : enum ndr_err_code ndr_err;
669 : krb5_data k5pac_attrs_in;
670 : DATA_BLOB pac_attrs_in;
671 : union PAC_INFO pac_attrs;
672 : int ret;
673 :
674 14773 : *requested_pac = true;
675 :
676 14773 : ret = krb5_pac_get_buffer(context, *pac, PAC_TYPE_ATTRIBUTES_INFO,
677 : &k5pac_attrs_in);
678 14773 : if (ret != 0) {
679 51 : return ret == ENOENT ? 0 : ret;
680 : }
681 :
682 14722 : pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
683 0 : k5pac_attrs_in.length);
684 :
685 14722 : ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
686 : PAC_TYPE_ATTRIBUTES_INFO,
687 : (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
688 14722 : smb_krb5_free_data_contents(context, &k5pac_attrs_in);
689 14722 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
690 0 : NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
691 0 : DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status)));
692 0 : return EINVAL;
693 : }
694 :
695 14722 : if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
696 : | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
697 14722 : *requested_pac = true;
698 : } else {
699 0 : *requested_pac = false;
700 : }
701 :
702 14722 : return 0;
703 : }
704 :
705 : /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
706 36207 : int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
707 : bool *is_in_db,
708 : bool *is_untrusted)
709 : {
710 : NTSTATUS status;
711 : int rodc_krbtgt_number, trust_direction;
712 : uint32_t rid;
713 :
714 36207 : TALLOC_CTX *mem_ctx = talloc_new(NULL);
715 36207 : if (!mem_ctx) {
716 0 : return ENOMEM;
717 : }
718 :
719 36207 : trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
720 :
721 36207 : if (trust_direction != 0) {
722 : /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
723 :
724 : This is exactly where we should flag for SID
725 : validation when we do inter-foreest trusts
726 : */
727 48 : talloc_free(mem_ctx);
728 48 : *is_untrusted = false;
729 48 : *is_in_db = false;
730 48 : return 0;
731 : }
732 :
733 : /* The lack of password controls etc applies to krbtgt by
734 : * virtue of being that particular RID */
735 36159 : status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"), NULL, &rid);
736 :
737 36159 : if (!NT_STATUS_IS_OK(status)) {
738 0 : talloc_free(mem_ctx);
739 0 : return EINVAL;
740 : }
741 :
742 36159 : rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
743 :
744 36159 : if (p->kdc_db_ctx->my_krbtgt_number == 0) {
745 33766 : if (rid == DOMAIN_RID_KRBTGT) {
746 33724 : *is_untrusted = false;
747 33724 : *is_in_db = true;
748 33724 : talloc_free(mem_ctx);
749 33724 : return 0;
750 42 : } else if (rodc_krbtgt_number != -1) {
751 42 : *is_in_db = true;
752 42 : *is_untrusted = true;
753 42 : talloc_free(mem_ctx);
754 42 : return 0;
755 : }
756 2393 : } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
757 2393 : talloc_free(mem_ctx);
758 2393 : *is_untrusted = false;
759 2393 : *is_in_db = true;
760 2393 : return 0;
761 0 : } else if (rid == DOMAIN_RID_KRBTGT) {
762 : /* krbtgt viewed from an RODC */
763 0 : talloc_free(mem_ctx);
764 0 : *is_untrusted = false;
765 0 : *is_in_db = false;
766 0 : return 0;
767 : }
768 :
769 : /* Another RODC */
770 0 : talloc_free(mem_ctx);
771 0 : *is_untrusted = true;
772 0 : *is_in_db = false;
773 0 : return 0;
774 : }
775 :
776 : /*
777 : * Because the KDC does not limit protocol transition, two new well-known SIDs
778 : * were introduced to give this control to the resource administrator. These
779 : * SIDs identify whether protocol transition has occurred, and can be used with
780 : * standard access control lists to grant or limit access as needed.
781 : *
782 : * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
783 : */
784 19021 : static NTSTATUS samba_add_asserted_identity(TALLOC_CTX *mem_ctx,
785 : enum samba_asserted_identity ai,
786 : struct auth_user_info_dc *user_info_dc)
787 : {
788 : struct dom_sid ai_sid;
789 19021 : const char *sid_str = NULL;
790 :
791 19021 : switch (ai) {
792 636 : case SAMBA_ASSERTED_IDENTITY_SERVICE:
793 636 : sid_str = SID_SERVICE_ASSERTED_IDENTITY;
794 19021 : break;
795 18385 : case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY:
796 18385 : sid_str = SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY;
797 18385 : break;
798 0 : case SAMBA_ASSERTED_IDENTITY_IGNORE:
799 0 : return NT_STATUS_OK;
800 : }
801 :
802 19021 : dom_sid_parse(sid_str, &ai_sid);
803 :
804 19021 : return add_sid_to_array_unique(user_info_dc,
805 : &ai_sid,
806 : &user_info_dc->sids,
807 : &user_info_dc->num_sids);
808 : }
809 :
810 : /*
811 : * Look up the user's info in the database and create a auth_user_info_dc
812 : * structure. If the resulting structure is not talloc_free()d, it will be
813 : * reused on future calls to this function.
814 : */
815 50819 : NTSTATUS samba_kdc_get_user_info_from_db(struct samba_kdc_entry *skdc_entry,
816 : struct ldb_message *msg,
817 : struct auth_user_info_dc **user_info_dc)
818 : {
819 50819 : if (skdc_entry->user_info_dc == NULL) {
820 : NTSTATUS nt_status;
821 32434 : struct loadparm_context *lp_ctx = skdc_entry->kdc_db_ctx->lp_ctx;
822 :
823 32434 : nt_status = authsam_make_user_info_dc(skdc_entry,
824 32434 : skdc_entry->kdc_db_ctx->samdb,
825 : lpcfg_netbios_name(lp_ctx),
826 : lpcfg_sam_name(lp_ctx),
827 : lpcfg_sam_dnsname(lp_ctx),
828 : skdc_entry->realm_dn,
829 : msg,
830 : data_blob_null,
831 : data_blob_null,
832 : &skdc_entry->user_info_dc);
833 32434 : if (!NT_STATUS_IS_OK(nt_status)) {
834 0 : return nt_status;
835 : }
836 : }
837 :
838 50819 : *user_info_dc = skdc_entry->user_info_dc;
839 50819 : return NT_STATUS_OK;
840 : }
841 :
842 19021 : NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
843 : struct samba_kdc_entry *p,
844 : enum samba_asserted_identity asserted_identity,
845 : DATA_BLOB **_logon_info_blob,
846 : DATA_BLOB **_cred_ndr_blob,
847 : DATA_BLOB **_upn_info_blob,
848 : DATA_BLOB **_pac_attrs_blob,
849 : uint64_t pac_attributes,
850 : DATA_BLOB **_requester_sid_blob,
851 : DATA_BLOB **_client_claims_blob)
852 : {
853 19021 : struct auth_user_info_dc *user_info_dc = NULL;
854 19021 : DATA_BLOB *logon_blob = NULL;
855 19021 : DATA_BLOB *cred_blob = NULL;
856 19021 : DATA_BLOB *upn_blob = NULL;
857 19021 : DATA_BLOB *pac_attrs_blob = NULL;
858 19021 : DATA_BLOB *requester_sid_blob = NULL;
859 19021 : DATA_BLOB *client_claims_blob = NULL;
860 : NTSTATUS nt_status;
861 :
862 19021 : *_logon_info_blob = NULL;
863 19021 : if (_cred_ndr_blob != NULL) {
864 0 : *_cred_ndr_blob = NULL;
865 : }
866 19021 : *_upn_info_blob = NULL;
867 19021 : if (_pac_attrs_blob != NULL) {
868 17157 : *_pac_attrs_blob = NULL;
869 : }
870 19021 : if (_requester_sid_blob != NULL) {
871 17199 : *_requester_sid_blob = NULL;
872 : }
873 19021 : if (_client_claims_blob != NULL) {
874 85 : *_client_claims_blob = NULL;
875 : }
876 :
877 19021 : logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
878 19021 : if (logon_blob == NULL) {
879 0 : return NT_STATUS_NO_MEMORY;
880 : }
881 :
882 19021 : if (_cred_ndr_blob != NULL) {
883 0 : cred_blob = talloc_zero(mem_ctx, DATA_BLOB);
884 0 : if (cred_blob == NULL) {
885 0 : return NT_STATUS_NO_MEMORY;
886 : }
887 : }
888 :
889 19021 : upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
890 19021 : if (upn_blob == NULL) {
891 0 : return NT_STATUS_NO_MEMORY;
892 : }
893 :
894 19021 : if (_pac_attrs_blob != NULL) {
895 17157 : pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
896 17157 : if (pac_attrs_blob == NULL) {
897 0 : return NT_STATUS_NO_MEMORY;
898 : }
899 : }
900 :
901 19021 : if (_requester_sid_blob != NULL) {
902 17199 : requester_sid_blob = talloc_zero(mem_ctx, DATA_BLOB);
903 17199 : if (requester_sid_blob == NULL) {
904 0 : return NT_STATUS_NO_MEMORY;
905 : }
906 : }
907 :
908 19021 : if (_client_claims_blob != NULL) {
909 : /*
910 : * Until we support claims we just
911 : * return an empty blob,
912 : * that matches what Windows is doing
913 : * without defined claims
914 : */
915 85 : client_claims_blob = talloc_zero(mem_ctx, DATA_BLOB);
916 85 : if (client_claims_blob == NULL) {
917 0 : return NT_STATUS_NO_MEMORY;
918 : }
919 : }
920 :
921 19021 : nt_status = samba_kdc_get_user_info_from_db(p,
922 : p->msg,
923 : &user_info_dc);
924 19021 : if (!NT_STATUS_IS_OK(nt_status)) {
925 0 : DEBUG(0, ("Getting user info for PAC failed: %s\n",
926 : nt_errstr(nt_status)));
927 0 : return nt_status;
928 : }
929 :
930 19021 : nt_status = samba_add_asserted_identity(mem_ctx,
931 : asserted_identity,
932 : user_info_dc);
933 19021 : if (!NT_STATUS_IS_OK(nt_status)) {
934 0 : DBG_ERR("Failed to add assertied identity!\n");
935 0 : return nt_status;
936 : }
937 :
938 19021 : nt_status = samba_get_logon_info_pac_blob(logon_blob,
939 : user_info_dc,
940 : logon_blob,
941 : requester_sid_blob);
942 19021 : if (!NT_STATUS_IS_OK(nt_status)) {
943 0 : DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
944 : nt_errstr(nt_status)));
945 0 : return nt_status;
946 : }
947 :
948 19021 : if (cred_blob != NULL) {
949 0 : nt_status = samba_get_cred_info_ndr_blob(cred_blob,
950 0 : p->msg,
951 : cred_blob);
952 0 : if (!NT_STATUS_IS_OK(nt_status)) {
953 0 : DEBUG(0, ("Building PAC CRED INFO failed: %s\n",
954 : nt_errstr(nt_status)));
955 0 : return nt_status;
956 : }
957 : }
958 :
959 19021 : nt_status = samba_get_upn_info_pac_blob(upn_blob,
960 : user_info_dc,
961 : upn_blob);
962 19021 : if (!NT_STATUS_IS_OK(nt_status)) {
963 0 : DEBUG(0, ("Building PAC UPN INFO failed: %s\n",
964 : nt_errstr(nt_status)));
965 0 : return nt_status;
966 : }
967 :
968 19021 : if (pac_attrs_blob != NULL) {
969 17157 : nt_status = samba_get_pac_attrs_blob(pac_attrs_blob,
970 : pac_attributes,
971 : pac_attrs_blob);
972 :
973 17157 : if (!NT_STATUS_IS_OK(nt_status)) {
974 0 : DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
975 : nt_errstr(nt_status)));
976 0 : return nt_status;
977 : }
978 : }
979 :
980 19021 : *_logon_info_blob = logon_blob;
981 19021 : if (_cred_ndr_blob != NULL) {
982 0 : *_cred_ndr_blob = cred_blob;
983 : }
984 19021 : *_upn_info_blob = upn_blob;
985 19021 : if (_pac_attrs_blob != NULL) {
986 17157 : *_pac_attrs_blob = pac_attrs_blob;
987 : }
988 19021 : if (_requester_sid_blob != NULL) {
989 17199 : *_requester_sid_blob = requester_sid_blob;
990 : }
991 19021 : if (_client_claims_blob != NULL) {
992 85 : *_client_claims_blob = client_claims_blob;
993 : }
994 19021 : return NT_STATUS_OK;
995 : }
996 :
997 36140 : NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
998 : krb5_context context,
999 : struct ldb_context *samdb,
1000 : const krb5_pac pac, DATA_BLOB *pac_blob,
1001 : struct PAC_SIGNATURE_DATA *pac_srv_sig,
1002 : struct PAC_SIGNATURE_DATA *pac_kdc_sig)
1003 : {
1004 : struct auth_user_info_dc *user_info_dc;
1005 : krb5_error_code ret;
1006 : NTSTATUS nt_status;
1007 :
1008 36140 : ret = kerberos_pac_to_user_info_dc(mem_ctx, pac,
1009 : context, &user_info_dc, pac_srv_sig, pac_kdc_sig);
1010 36140 : if (ret) {
1011 0 : return NT_STATUS_UNSUCCESSFUL;
1012 : }
1013 :
1014 : /*
1015 : * We need to expand group memberships within our local domain,
1016 : * as the token might be generated by a trusted domain.
1017 : */
1018 36140 : nt_status = authsam_update_user_info_dc(mem_ctx,
1019 : samdb,
1020 : user_info_dc);
1021 36140 : if (!NT_STATUS_IS_OK(nt_status)) {
1022 0 : return nt_status;
1023 : }
1024 :
1025 36140 : nt_status = samba_get_logon_info_pac_blob(mem_ctx,
1026 : user_info_dc, pac_blob, NULL);
1027 :
1028 36140 : return nt_status;
1029 : }
1030 :
1031 51 : NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
1032 : krb5_context context,
1033 : const krb5_pac pac,
1034 : const krb5_principal server_principal,
1035 : const krb5_principal proxy_principal,
1036 : DATA_BLOB *new_blob)
1037 : {
1038 : krb5_data old_data;
1039 : DATA_BLOB old_blob;
1040 : krb5_error_code ret;
1041 : NTSTATUS nt_status;
1042 : enum ndr_err_code ndr_err;
1043 : union PAC_INFO info;
1044 : struct PAC_CONSTRAINED_DELEGATION _d;
1045 51 : struct PAC_CONSTRAINED_DELEGATION *d = NULL;
1046 51 : char *server = NULL;
1047 51 : char *proxy = NULL;
1048 : uint32_t i;
1049 51 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1050 :
1051 51 : if (tmp_ctx == NULL) {
1052 0 : return NT_STATUS_NO_MEMORY;
1053 : }
1054 :
1055 51 : ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
1056 51 : if (ret == ENOENT) {
1057 49 : ZERO_STRUCT(old_data);
1058 2 : } else if (ret) {
1059 0 : talloc_free(tmp_ctx);
1060 0 : return NT_STATUS_UNSUCCESSFUL;
1061 : }
1062 :
1063 51 : old_blob.length = old_data.length;
1064 51 : old_blob.data = (uint8_t *)old_data.data;
1065 :
1066 51 : ZERO_STRUCT(info);
1067 51 : if (old_blob.length > 0) {
1068 2 : ndr_err = ndr_pull_union_blob(&old_blob, mem_ctx,
1069 : &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1070 : (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1071 2 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1072 0 : smb_krb5_free_data_contents(context, &old_data);
1073 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1074 0 : DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1075 0 : talloc_free(tmp_ctx);
1076 0 : return nt_status;
1077 : }
1078 : } else {
1079 49 : ZERO_STRUCT(_d);
1080 49 : info.constrained_delegation.info = &_d;
1081 : }
1082 51 : smb_krb5_free_data_contents(context, &old_data);
1083 :
1084 51 : ret = krb5_unparse_name_flags(context, server_principal,
1085 : KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server);
1086 51 : if (ret) {
1087 0 : talloc_free(tmp_ctx);
1088 0 : return NT_STATUS_INTERNAL_ERROR;
1089 : }
1090 :
1091 51 : ret = krb5_unparse_name(context, proxy_principal, &proxy);
1092 51 : if (ret) {
1093 0 : SAFE_FREE(server);
1094 0 : talloc_free(tmp_ctx);
1095 0 : return NT_STATUS_INTERNAL_ERROR;
1096 : }
1097 :
1098 51 : d = info.constrained_delegation.info;
1099 51 : i = d->num_transited_services;
1100 51 : d->proxy_target.string = server;
1101 51 : d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
1102 : struct lsa_String, i + 1);
1103 51 : d->transited_services[i].string = proxy;
1104 51 : d->num_transited_services = i + 1;
1105 :
1106 51 : ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
1107 : &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1108 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1109 51 : SAFE_FREE(server);
1110 51 : SAFE_FREE(proxy);
1111 51 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1112 0 : smb_krb5_free_data_contents(context, &old_data);
1113 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1114 0 : DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1115 0 : talloc_free(tmp_ctx);
1116 0 : return nt_status;
1117 : }
1118 :
1119 51 : talloc_free(tmp_ctx);
1120 51 : return NT_STATUS_OK;
1121 : }
1122 :
1123 : /* function to map policy errors */
1124 4 : krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
1125 : {
1126 : krb5_error_code ret;
1127 :
1128 4 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
1129 4 : ret = KRB5KDC_ERR_KEY_EXP;
1130 0 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
1131 0 : ret = KRB5KDC_ERR_KEY_EXP;
1132 0 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
1133 0 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1134 0 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
1135 0 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1136 0 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
1137 0 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1138 0 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
1139 0 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1140 0 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
1141 0 : ret = KRB5KDC_ERR_POLICY;
1142 : else
1143 0 : ret = KRB5KDC_ERR_POLICY;
1144 :
1145 4 : return ret;
1146 : }
1147 :
1148 : /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1149 : * for consistency */
1150 18429 : NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
1151 : const char *client_name,
1152 : const char *workstation,
1153 : bool password_change)
1154 : {
1155 : TALLOC_CTX *tmp_ctx;
1156 : NTSTATUS nt_status;
1157 :
1158 18429 : tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
1159 18429 : if (!tmp_ctx) {
1160 0 : return NT_STATUS_NO_MEMORY;
1161 : }
1162 :
1163 : /* we allow all kinds of trusts here */
1164 18429 : nt_status = authsam_account_ok(tmp_ctx,
1165 18429 : kdc_entry->kdc_db_ctx->samdb,
1166 : MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
1167 : MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
1168 : kdc_entry->realm_dn, kdc_entry->msg,
1169 : workstation, client_name,
1170 : true, password_change);
1171 :
1172 18429 : kdc_entry->reject_status = nt_status;
1173 18429 : talloc_free(tmp_ctx);
1174 18429 : return nt_status;
1175 : }
1176 :
1177 36133 : static krb5_error_code samba_get_requester_sid(TALLOC_CTX *mem_ctx,
1178 : krb5_const_pac pac,
1179 : krb5_context context,
1180 : struct dom_sid *sid)
1181 : {
1182 : NTSTATUS nt_status;
1183 : enum ndr_err_code ndr_err;
1184 : krb5_error_code ret;
1185 :
1186 : DATA_BLOB pac_requester_sid_in;
1187 : krb5_data k5pac_requester_sid_in;
1188 :
1189 : union PAC_INFO info;
1190 :
1191 36133 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1192 36133 : if (tmp_ctx == NULL) {
1193 0 : return ENOMEM;
1194 : }
1195 :
1196 36133 : ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
1197 : &k5pac_requester_sid_in);
1198 36133 : if (ret != 0) {
1199 50 : talloc_free(tmp_ctx);
1200 50 : return ret;
1201 : }
1202 :
1203 36083 : pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
1204 0 : k5pac_requester_sid_in.length);
1205 :
1206 36083 : ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
1207 : PAC_TYPE_REQUESTER_SID,
1208 : (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1209 36083 : smb_krb5_free_data_contents(context, &k5pac_requester_sid_in);
1210 36083 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1211 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1212 0 : DEBUG(0,("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status)));
1213 0 : talloc_free(tmp_ctx);
1214 0 : return EINVAL;
1215 : }
1216 :
1217 36083 : *sid = info.requester_sid.sid;
1218 :
1219 36083 : talloc_free(tmp_ctx);
1220 36083 : return 0;
1221 : }
1222 :
1223 : /* Does a parse and SID check, but no crypto. */
1224 36133 : krb5_error_code samba_kdc_validate_pac_blob(
1225 : krb5_context context,
1226 : const struct samba_kdc_entry *client_skdc_entry,
1227 : const krb5_const_pac pac)
1228 : {
1229 36133 : TALLOC_CTX *frame = talloc_stackframe();
1230 36133 : struct auth_user_info_dc *pac_user_info = NULL;
1231 36133 : struct dom_sid *client_sid = NULL;
1232 : struct dom_sid pac_sid;
1233 : krb5_error_code code;
1234 : bool ok;
1235 :
1236 : /*
1237 : * First, try to get the SID from the requester SID buffer in the PAC.
1238 : */
1239 36133 : code = samba_get_requester_sid(frame, pac, context, &pac_sid);
1240 :
1241 36133 : if (code == ENOENT) {
1242 : /*
1243 : * If the requester SID buffer isn't present, fall back to the
1244 : * SID in the LOGON_INFO PAC buffer.
1245 : */
1246 50 : code = kerberos_pac_to_user_info_dc(frame,
1247 : pac,
1248 : context,
1249 : &pac_user_info,
1250 : NULL,
1251 : NULL);
1252 50 : if (code != 0) {
1253 0 : goto out;
1254 : }
1255 :
1256 50 : if (pac_user_info->num_sids == 0) {
1257 0 : code = EINVAL;
1258 0 : goto out;
1259 : }
1260 :
1261 50 : pac_sid = pac_user_info->sids[0];
1262 36083 : } else if (code != 0) {
1263 0 : goto out;
1264 : }
1265 :
1266 36133 : client_sid = samdb_result_dom_sid(frame,
1267 36133 : client_skdc_entry->msg,
1268 : "objectSid");
1269 :
1270 36133 : ok = dom_sid_equal(&pac_sid, client_sid);
1271 36133 : if (!ok) {
1272 : struct dom_sid_buf buf1;
1273 : struct dom_sid_buf buf2;
1274 :
1275 0 : DBG_ERR("SID mismatch between PAC and looked up client: "
1276 : "PAC[%s] != CLI[%s]\n",
1277 : dom_sid_str_buf(&pac_sid, &buf1),
1278 : dom_sid_str_buf(client_sid, &buf2));
1279 0 : code = KRB5KDC_ERR_TGT_REVOKED;
1280 0 : goto out;
1281 : }
1282 :
1283 36133 : code = 0;
1284 36133 : out:
1285 36133 : TALLOC_FREE(frame);
1286 36133 : return code;
1287 : }
1288 :
1289 :
1290 : /*
1291 : * In the RODC case, to confirm that the returned user is permitted to
1292 : * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1293 : */
1294 42 : WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
1295 : struct dom_sid *object_sids,
1296 : struct samba_kdc_entry *rodc,
1297 : struct samba_kdc_entry *object)
1298 : {
1299 : int ret;
1300 : WERROR werr;
1301 42 : TALLOC_CTX *frame = talloc_stackframe();
1302 42 : const char *rodc_attrs[] = { "msDS-KrbTgtLink",
1303 : "msDS-NeverRevealGroup",
1304 : "msDS-RevealOnDemandGroup",
1305 : "userAccountControl",
1306 : "objectSid",
1307 : NULL };
1308 42 : struct ldb_result *rodc_machine_account = NULL;
1309 42 : struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
1310 : frame,
1311 42 : rodc->msg,
1312 : "msDS-KrbTgtLinkBL",
1313 : NULL);
1314 42 : const struct dom_sid *rodc_machine_account_sid = NULL;
1315 :
1316 42 : if (rodc_machine_account_dn == NULL) {
1317 0 : DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1318 : ldb_dn_get_linearized(rodc->msg->dn));
1319 0 : TALLOC_FREE(frame);
1320 0 : return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1321 : }
1322 :
1323 : /*
1324 : * Follow the link and get the RODC account (the krbtgt
1325 : * account is the krbtgt_XXX account, but the
1326 : * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1327 : * the RODC$ account)
1328 : *
1329 : * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1330 : * out of the extended DNs
1331 : */
1332 :
1333 42 : ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
1334 : frame,
1335 : &rodc_machine_account,
1336 : rodc_machine_account_dn,
1337 : rodc_attrs,
1338 : DSDB_SEARCH_SHOW_EXTENDED_DN);
1339 42 : if (ret != LDB_SUCCESS) {
1340 0 : DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1341 : ldb_dn_get_linearized(rodc_machine_account_dn),
1342 : ldb_dn_get_linearized(rodc->msg->dn),
1343 : ldb_errstring(rodc->kdc_db_ctx->samdb));
1344 0 : TALLOC_FREE(frame);
1345 0 : return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1346 : }
1347 :
1348 42 : if (rodc_machine_account->count != 1) {
1349 0 : DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1350 : ldb_dn_get_linearized(rodc_machine_account_dn),
1351 : ldb_dn_get_linearized(rodc->msg->dn),
1352 : rodc_machine_account->count);
1353 0 : TALLOC_FREE(frame);
1354 0 : return WERR_DS_DRA_BAD_DN;
1355 : }
1356 :
1357 : /* if the object SID is equal to the user_sid, allow */
1358 42 : rodc_machine_account_sid = samdb_result_dom_sid(frame,
1359 42 : rodc_machine_account->msgs[0],
1360 : "objectSid");
1361 42 : if (rodc_machine_account_sid == NULL) {
1362 0 : return WERR_DS_DRA_BAD_DN;
1363 : }
1364 :
1365 42 : werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
1366 : rodc_machine_account_sid,
1367 42 : rodc_machine_account->msgs[0],
1368 : object->msg,
1369 : num_object_sids,
1370 : object_sids);
1371 :
1372 42 : TALLOC_FREE(frame);
1373 42 : return werr;
1374 : }
1375 :
1376 : /**
1377 : * @brief Update a PAC
1378 : *
1379 : * @param mem_ctx A talloc memory context
1380 : *
1381 : * @param context A krb5 context
1382 : *
1383 : * @param samdb An open samdb connection.
1384 : *
1385 : * @param flags Bitwise OR'ed flags
1386 : *
1387 : * @param client The client samba kdc entry.
1388 :
1389 : * @param server_principal The server principal
1390 :
1391 : * @param server The server samba kdc entry.
1392 :
1393 : * @param krbtgt The krbtgt samba kdc entry.
1394 : *
1395 : * @param delegated_proxy_principal The delegated proxy principal used for
1396 : * updating the constrained delegation PAC
1397 : * buffer.
1398 :
1399 : * @param old_pac The old PAC
1400 :
1401 : * @param new_pac The new already allocated PAC
1402 :
1403 : * @return A Kerberos error code. If no PAC should be returned, the code will be
1404 : * ENODATA!
1405 : */
1406 36182 : krb5_error_code samba_kdc_update_pac(TALLOC_CTX *mem_ctx,
1407 : krb5_context context,
1408 : struct ldb_context *samdb,
1409 : uint32_t flags,
1410 : struct samba_kdc_entry *client,
1411 : const krb5_principal server_principal,
1412 : struct samba_kdc_entry *server,
1413 : struct samba_kdc_entry *krbtgt,
1414 : const krb5_principal delegated_proxy_principal,
1415 : const krb5_pac old_pac,
1416 : krb5_pac new_pac)
1417 : {
1418 36182 : krb5_error_code code = EINVAL;
1419 : NTSTATUS nt_status;
1420 36182 : DATA_BLOB *pac_blob = NULL;
1421 36182 : DATA_BLOB *upn_blob = NULL;
1422 36182 : DATA_BLOB *deleg_blob = NULL;
1423 36182 : DATA_BLOB *requester_sid_blob = NULL;
1424 36182 : DATA_BLOB *client_claims_blob = NULL;
1425 36182 : bool is_untrusted = flags & SAMBA_KDC_FLAG_KRBTGT_IS_UNTRUSTED;
1426 36182 : int is_tgs = false;
1427 36182 : size_t num_types = 0;
1428 36182 : uint32_t *types = NULL;
1429 : /*
1430 : * FIXME: Do we really still need forced_next_type? With MIT Kerberos
1431 : * the PAC buffers do not get ordered and it works just fine. We are
1432 : * not aware of any issues in this regard. This might be just ancient
1433 : * code.
1434 : */
1435 36182 : uint32_t forced_next_type = 0;
1436 36182 : size_t i = 0;
1437 36182 : ssize_t logon_info_idx = -1;
1438 36182 : ssize_t delegation_idx = -1;
1439 36182 : ssize_t logon_name_idx = -1;
1440 36182 : ssize_t upn_dns_info_idx = -1;
1441 36182 : ssize_t srv_checksum_idx = -1;
1442 36182 : ssize_t kdc_checksum_idx = -1;
1443 36182 : ssize_t tkt_checksum_idx = -1;
1444 36182 : ssize_t attrs_info_idx = -1;
1445 36182 : ssize_t requester_sid_idx = -1;
1446 36182 : ssize_t full_checksum_idx = -1;
1447 :
1448 36182 : if (client != NULL) {
1449 : /*
1450 : * Check the objectSID of the client and pac data are the same.
1451 : * Does a parse and SID check, but no crypto.
1452 : */
1453 36133 : code = samba_kdc_validate_pac_blob(context,
1454 : client,
1455 : old_pac);
1456 36133 : if (code != 0) {
1457 0 : goto done;
1458 : }
1459 : }
1460 :
1461 36182 : if (delegated_proxy_principal != NULL) {
1462 51 : deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
1463 51 : if (deleg_blob == NULL) {
1464 0 : code = ENOMEM;
1465 0 : goto done;
1466 : }
1467 :
1468 51 : nt_status = samba_kdc_update_delegation_info_blob(
1469 : mem_ctx,
1470 : context,
1471 : old_pac,
1472 : server_principal,
1473 : delegated_proxy_principal,
1474 : deleg_blob);
1475 51 : if (!NT_STATUS_IS_OK(nt_status)) {
1476 0 : DBG_ERR("update delegation info blob failed: %s\n",
1477 : nt_errstr(nt_status));
1478 0 : code = EINVAL;
1479 0 : goto done;
1480 : }
1481 : }
1482 :
1483 36182 : if (is_untrusted) {
1484 42 : struct auth_user_info_dc *user_info_dc = NULL;
1485 : WERROR werr;
1486 : /*
1487 : * In this case the RWDC discards the PAC an RODC generated.
1488 : * Windows adds the asserted_identity in this case too.
1489 : *
1490 : * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1491 : * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1492 : * So we can always use
1493 : * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1494 : * here.
1495 : */
1496 42 : enum samba_asserted_identity asserted_identity =
1497 : SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
1498 :
1499 42 : if (client == NULL) {
1500 0 : code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1501 0 : goto done;
1502 : }
1503 :
1504 42 : nt_status = samba_kdc_get_pac_blobs(mem_ctx,
1505 : client,
1506 : asserted_identity,
1507 : &pac_blob,
1508 : NULL,
1509 : &upn_blob,
1510 : NULL,
1511 : PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
1512 : &requester_sid_blob,
1513 : &client_claims_blob);
1514 42 : if (!NT_STATUS_IS_OK(nt_status)) {
1515 0 : DBG_ERR("samba_kdc_get_pac_blobs failed: %s\n",
1516 : nt_errstr(nt_status));
1517 0 : code = KRB5KDC_ERR_TGT_REVOKED;
1518 0 : goto done;
1519 : }
1520 :
1521 42 : nt_status = samba_kdc_get_user_info_from_db(client,
1522 : client->msg,
1523 : &user_info_dc);
1524 42 : if (!NT_STATUS_IS_OK(nt_status)) {
1525 0 : DBG_ERR("samba_kdc_get_user_info_from_db failed: %s\n",
1526 : nt_errstr(nt_status));
1527 0 : code = KRB5KDC_ERR_TGT_REVOKED;
1528 0 : goto done;
1529 : }
1530 :
1531 : /*
1532 : * Check if the SID list in the user_info_dc intersects
1533 : * correctly with the RODC allow/deny lists.
1534 : */
1535 42 : werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
1536 42 : user_info_dc->sids,
1537 : krbtgt,
1538 : client);
1539 42 : TALLOC_FREE(user_info_dc);
1540 42 : if (!W_ERROR_IS_OK(werr)) {
1541 0 : code = KRB5KDC_ERR_TGT_REVOKED;
1542 0 : if (W_ERROR_EQUAL(werr,
1543 : WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
1544 0 : code = KRB5KDC_ERR_POLICY;
1545 : }
1546 0 : goto done;
1547 : }
1548 :
1549 : /*
1550 : * The RODC PAC data isn't trusted for authorization as it may
1551 : * be stale. The only thing meaningful we can do with an RODC
1552 : * account on a full DC is exchange the RODC TGT for a 'real'
1553 : * TGT.
1554 : *
1555 : * So we match Windows (at least server 2022) and
1556 : * don't allow S4U2Self.
1557 : *
1558 : * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
1559 : */
1560 42 : if (flags & SAMBA_KDC_FLAG_PROTOCOL_TRANSITION) {
1561 0 : code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1562 0 : goto done;
1563 : }
1564 : } else {
1565 36140 : pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
1566 36140 : if (pac_blob == NULL) {
1567 0 : code = ENOMEM;
1568 0 : goto done;
1569 : }
1570 :
1571 36140 : nt_status = samba_kdc_update_pac_blob(mem_ctx,
1572 : context,
1573 : samdb,
1574 : old_pac,
1575 : pac_blob,
1576 : NULL,
1577 : NULL);
1578 36140 : if (!NT_STATUS_IS_OK(nt_status)) {
1579 0 : DBG_ERR("samba_kdc_update_pac_blob failed: %s\n",
1580 : nt_errstr(nt_status));
1581 0 : code = EINVAL;
1582 0 : goto done;
1583 : }
1584 : }
1585 :
1586 : /* Check the types of the given PAC */
1587 36182 : code = krb5_pac_get_types(context, old_pac, &num_types, &types);
1588 36182 : if (code != 0) {
1589 0 : DBG_ERR("krb5_pac_get_types failed\n");
1590 0 : goto done;
1591 : }
1592 :
1593 289474 : for (i = 0; i < num_types; i++) {
1594 253292 : switch (types[i]) {
1595 36182 : case PAC_TYPE_LOGON_INFO:
1596 36182 : if (logon_info_idx != -1) {
1597 0 : DBG_WARNING("logon info type[%u] twice [%zd] "
1598 : "and [%zu]: \n",
1599 : types[i],
1600 : logon_info_idx,
1601 : i);
1602 0 : code = EINVAL;
1603 0 : goto done;
1604 : }
1605 36182 : logon_info_idx = i;
1606 36182 : break;
1607 2 : case PAC_TYPE_CONSTRAINED_DELEGATION:
1608 2 : if (delegation_idx != -1) {
1609 0 : DBG_WARNING("constrained delegation type[%u] "
1610 : "twice [%zd] and [%zu]: \n",
1611 : types[i],
1612 : delegation_idx,
1613 : i);
1614 0 : code = EINVAL;
1615 0 : goto done;
1616 : }
1617 2 : delegation_idx = i;
1618 2 : break;
1619 36182 : case PAC_TYPE_LOGON_NAME:
1620 36182 : if (logon_name_idx != -1) {
1621 0 : DBG_WARNING("logon name type[%u] twice [%zd] "
1622 : "and [%zu]: \n",
1623 : types[i],
1624 : logon_name_idx,
1625 : i);
1626 0 : code = EINVAL;
1627 0 : goto done;
1628 : }
1629 36182 : logon_name_idx = i;
1630 36182 : break;
1631 36182 : case PAC_TYPE_UPN_DNS_INFO:
1632 36182 : if (upn_dns_info_idx != -1) {
1633 0 : DBG_WARNING("upn dns info type[%u] twice [%zd] "
1634 : "and [%zu]: \n",
1635 : types[i],
1636 : upn_dns_info_idx,
1637 : i);
1638 0 : code = EINVAL;
1639 0 : goto done;
1640 : }
1641 36182 : upn_dns_info_idx = i;
1642 36182 : break;
1643 36182 : case PAC_TYPE_SRV_CHECKSUM:
1644 36182 : if (srv_checksum_idx != -1) {
1645 0 : DBG_WARNING("srv checksum type[%u] twice [%zd] "
1646 : "and [%zu]: \n",
1647 : types[i],
1648 : srv_checksum_idx,
1649 : i);
1650 0 : code = EINVAL;
1651 0 : goto done;
1652 : }
1653 36182 : srv_checksum_idx = i;
1654 36182 : break;
1655 36182 : case PAC_TYPE_KDC_CHECKSUM:
1656 36182 : if (kdc_checksum_idx != -1) {
1657 0 : DBG_WARNING("kdc checksum type[%u] twice [%zd] "
1658 : "and [%zu]: \n",
1659 : types[i],
1660 : kdc_checksum_idx,
1661 : i);
1662 0 : code = EINVAL;
1663 0 : goto done;
1664 : }
1665 36182 : kdc_checksum_idx = i;
1666 36182 : break;
1667 59 : case PAC_TYPE_TICKET_CHECKSUM:
1668 59 : if (tkt_checksum_idx != -1) {
1669 0 : DBG_WARNING("ticket checksum type[%u] twice "
1670 : "[%zd] and [%zu]: \n",
1671 : types[i],
1672 : tkt_checksum_idx,
1673 : i);
1674 0 : code = EINVAL;
1675 0 : goto done;
1676 : }
1677 59 : tkt_checksum_idx = i;
1678 59 : break;
1679 36131 : case PAC_TYPE_ATTRIBUTES_INFO:
1680 36131 : if (attrs_info_idx != -1) {
1681 0 : DBG_WARNING("attributes info type[%u] twice "
1682 : "[%zd] and [%zu]: \n",
1683 : types[i],
1684 : attrs_info_idx,
1685 : i);
1686 0 : code = EINVAL;
1687 0 : goto done;
1688 : }
1689 36131 : attrs_info_idx = i;
1690 36131 : break;
1691 36131 : case PAC_TYPE_REQUESTER_SID:
1692 36131 : if (requester_sid_idx != -1) {
1693 0 : DBG_WARNING("requester sid type[%u] twice"
1694 : "[%zd] and [%zu]: \n",
1695 : types[i],
1696 : requester_sid_idx,
1697 : i);
1698 0 : code = EINVAL;
1699 0 : goto done;
1700 : }
1701 36131 : requester_sid_idx = i;
1702 36131 : break;
1703 59 : case PAC_TYPE_FULL_CHECKSUM:
1704 59 : if (full_checksum_idx != -1) {
1705 0 : DBG_WARNING("full checksum type[%u] twice "
1706 : "[%zd] and [%zu]: \n",
1707 : types[i],
1708 : full_checksum_idx,
1709 : i);
1710 0 : code = EINVAL;
1711 0 : goto done;
1712 : }
1713 59 : full_checksum_idx = i;
1714 59 : break;
1715 0 : default:
1716 0 : continue;
1717 : }
1718 : }
1719 :
1720 36182 : if (logon_info_idx == -1) {
1721 0 : DBG_WARNING("PAC_TYPE_LOGON_INFO missing\n");
1722 0 : code = EINVAL;
1723 0 : goto done;
1724 : }
1725 36182 : if (logon_name_idx == -1) {
1726 0 : DBG_WARNING("PAC_TYPE_LOGON_NAME missing\n");
1727 0 : code = EINVAL;
1728 0 : goto done;
1729 : }
1730 36182 : if (srv_checksum_idx == -1) {
1731 0 : DBG_WARNING("PAC_TYPE_SRV_CHECKSUM missing\n");
1732 0 : code = EINVAL;
1733 0 : goto done;
1734 : }
1735 36182 : if (kdc_checksum_idx == -1) {
1736 0 : DBG_WARNING("PAC_TYPE_KDC_CHECKSUM missing\n");
1737 0 : code = EINVAL;
1738 0 : goto done;
1739 : }
1740 36182 : if (!(flags & SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION) &&
1741 : requester_sid_idx == -1) {
1742 0 : DBG_WARNING("PAC_TYPE_REQUESTER_SID missing\n");
1743 0 : code = KRB5KDC_ERR_TGT_REVOKED;
1744 0 : goto done;
1745 : }
1746 :
1747 : /*
1748 : * The server account may be set not to want the PAC.
1749 : *
1750 : * While this is wasteful if the above cacluations were done
1751 : * and now thrown away, this is cleaner as we do any ticket
1752 : * signature checking etc always.
1753 : *
1754 : * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
1755 : * time (eg not accepting a ticket from the RODC) we do not
1756 : * need to re-generate anything anyway.
1757 : */
1758 36182 : if (!samba_princ_needs_pac(server)) {
1759 9 : code = ENODATA;
1760 9 : goto done;
1761 : }
1762 :
1763 36173 : is_tgs = smb_krb5_principal_is_tgs(context, server_principal);
1764 36173 : if (is_tgs == -1) {
1765 0 : code = ENOMEM;
1766 0 : goto done;
1767 : }
1768 :
1769 36173 : if (!is_untrusted && !is_tgs) {
1770 : /*
1771 : * The client may have requested no PAC when obtaining the
1772 : * TGT.
1773 : */
1774 14773 : bool requested_pac = false;
1775 :
1776 14773 : code = samba_client_requested_pac(context,
1777 : &old_pac,
1778 : mem_ctx,
1779 : &requested_pac);
1780 14773 : if (code != 0 || !requested_pac) {
1781 0 : if (!requested_pac) {
1782 0 : code = ENODATA;
1783 : }
1784 0 : goto done;
1785 : }
1786 : }
1787 :
1788 : #define MAX_PAC_BUFFERS 128 /* Avoid infinite loops */
1789 :
1790 289451 : for (i = 0; i < MAX_PAC_BUFFERS;) {
1791 289451 : const uint8_t zero_byte = 0;
1792 : krb5_data type_data;
1793 289451 : DATA_BLOB type_blob = data_blob_null;
1794 : uint32_t type;
1795 :
1796 : static char null_byte = '\0';
1797 289451 : const krb5_data null_data = smb_krb5_make_data(&null_byte, 0);
1798 :
1799 289451 : if (forced_next_type != 0) {
1800 : /*
1801 : * We need to inject possible missing types
1802 : */
1803 49 : type = forced_next_type;
1804 49 : forced_next_type = 0;
1805 289402 : } else if (i < num_types) {
1806 253229 : type = types[i];
1807 253229 : i++;
1808 : } else {
1809 36173 : break;
1810 : }
1811 :
1812 253278 : switch (type) {
1813 36173 : case PAC_TYPE_LOGON_INFO:
1814 36173 : type_blob = *pac_blob;
1815 :
1816 36173 : if (delegation_idx == -1 && deleg_blob != NULL) {
1817 : /* inject CONSTRAINED_DELEGATION behind */
1818 49 : forced_next_type =
1819 : PAC_TYPE_CONSTRAINED_DELEGATION;
1820 : }
1821 36173 : break;
1822 51 : case PAC_TYPE_CONSTRAINED_DELEGATION:
1823 : /*
1824 : * This is generated in the main KDC code
1825 : */
1826 51 : if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1827 29528 : continue;
1828 : }
1829 :
1830 51 : if (deleg_blob != NULL) {
1831 51 : type_blob = *deleg_blob;
1832 : }
1833 51 : break;
1834 0 : case PAC_TYPE_CREDENTIAL_INFO:
1835 : /*
1836 : * Note that we copy the credential blob,
1837 : * as it's only usable with the PKINIT based
1838 : * AS-REP reply key, it's only available on the
1839 : * host which did the AS-REQ/AS-REP exchange.
1840 : *
1841 : * This matches Windows 2008R2...
1842 : */
1843 0 : break;
1844 36173 : case PAC_TYPE_LOGON_NAME:
1845 : /*
1846 : * This is generated in the main KDC code
1847 : */
1848 36173 : if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1849 0 : continue;
1850 : }
1851 :
1852 36173 : type_blob = data_blob_const(&zero_byte, 1);
1853 :
1854 36173 : if (upn_dns_info_idx == -1 && upn_blob != NULL) {
1855 : /* inject UPN_DNS_INFO behind */
1856 0 : forced_next_type = PAC_TYPE_UPN_DNS_INFO;
1857 : }
1858 36173 : break;
1859 36173 : case PAC_TYPE_UPN_DNS_INFO:
1860 : /*
1861 : * Replace in the RODC case, otherwise
1862 : * upn_blob is NULL and we just copy.
1863 : */
1864 36173 : if (upn_blob != NULL) {
1865 42 : type_blob = *upn_blob;
1866 : }
1867 36173 : break;
1868 36173 : case PAC_TYPE_SRV_CHECKSUM:
1869 : /*
1870 : * This is generated in the main KDC code
1871 : */
1872 36173 : if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1873 0 : continue;
1874 : }
1875 :
1876 36173 : type_blob = data_blob_const(&zero_byte, 1);
1877 :
1878 36173 : if (requester_sid_idx == -1 && requester_sid_blob != NULL) {
1879 : /* inject REQUESTER_SID behind */
1880 0 : forced_next_type = PAC_TYPE_REQUESTER_SID;
1881 : }
1882 36173 : break;
1883 36173 : case PAC_TYPE_KDC_CHECKSUM:
1884 : /*
1885 : * This is generated in the main KDC code
1886 : */
1887 36173 : if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1888 0 : continue;
1889 : }
1890 :
1891 36173 : type_blob = data_blob_const(&zero_byte, 1);
1892 :
1893 36173 : break;
1894 59 : case PAC_TYPE_TICKET_CHECKSUM:
1895 : /*
1896 : * This is generated in the main KDC code
1897 : */
1898 59 : if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1899 0 : continue;
1900 : }
1901 :
1902 59 : type_blob = data_blob_const(&zero_byte, 1);
1903 :
1904 59 : break;
1905 36122 : case PAC_TYPE_ATTRIBUTES_INFO:
1906 36122 : if (!is_untrusted && is_tgs) {
1907 : /* just copy... */
1908 21358 : break;
1909 : }
1910 :
1911 14764 : continue;
1912 36122 : case PAC_TYPE_REQUESTER_SID:
1913 36122 : if (!is_tgs) {
1914 14764 : continue;
1915 : }
1916 :
1917 : /*
1918 : * Replace in the RODC case, otherwise
1919 : * requester_sid_blob is NULL and we just copy.
1920 : */
1921 21358 : if (requester_sid_blob != NULL) {
1922 0 : type_blob = *requester_sid_blob;
1923 : }
1924 21358 : break;
1925 59 : case PAC_TYPE_FULL_CHECKSUM:
1926 : /*
1927 : * This is generated in the main KDC code
1928 : */
1929 59 : if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1930 0 : continue;
1931 : }
1932 :
1933 59 : type_blob = data_blob_const(&zero_byte, 1);
1934 :
1935 59 : break;
1936 0 : default:
1937 : /* just copy... */
1938 0 : break;
1939 : }
1940 :
1941 223750 : if (type_blob.length != 0) {
1942 144903 : type_data = smb_krb5_data_from_blob(type_blob);
1943 144903 : code = krb5_pac_add_buffer(context, new_pac,
1944 : type, &type_data);
1945 : } else {
1946 78847 : code = krb5_pac_get_buffer(context,
1947 : old_pac,
1948 : type,
1949 : &type_data);
1950 78847 : if (code != 0) {
1951 0 : goto done;
1952 : }
1953 : /*
1954 : * Passing a NULL pointer into krb5_pac_add_buffer() is
1955 : * not allowed, so pass null_data instead if needed.
1956 : */
1957 78847 : code = krb5_pac_add_buffer(context,
1958 : new_pac,
1959 : type,
1960 78847 : (type_data.data != NULL) ? &type_data : &null_data);
1961 78847 : smb_krb5_free_data_contents(context, &type_data);
1962 : }
1963 :
1964 223750 : if (code != 0) {
1965 0 : goto done;
1966 : }
1967 : }
1968 :
1969 36173 : code = 0;
1970 36182 : done:
1971 36182 : TALLOC_FREE(pac_blob);
1972 36182 : TALLOC_FREE(upn_blob);
1973 36182 : TALLOC_FREE(deleg_blob);
1974 36182 : SAFE_FREE(types);
1975 36182 : return code;
1976 : }
|