s4:kdc: Make some parameters const
[Samba.git] / source4 / kdc / pac-glue.c
blobcb36408bc811ab5da4972034abe40211c4085644
1 /*
2 Unix SMB/CIFS implementation.
4 PAC Glue between Samba and the KDC
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 Copyright (C) Simo Sorce <idra@samba.org> 2010
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.
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.
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/>.
24 #include "lib/replace/replace.h"
25 #include "lib/replace/system/kerberos.h"
26 #include "lib/replace/system/filesys.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/samba_util.h"
29 #include "lib/util/talloc_stack.h"
31 #include "auth/auth_sam_reply.h"
32 #include "auth/kerberos/kerberos.h"
33 #include "auth/kerberos/pac_utils.h"
34 #include "libcli/security/security.h"
35 #include "libds/common/flags.h"
36 #include "librpc/gen_ndr/ndr_krb5pac.h"
37 #include "param/param.h"
38 #include "source4/auth/auth.h"
39 #include "source4/dsdb/common/util.h"
40 #include "source4/dsdb/samdb/samdb.h"
41 #include "source4/kdc/samba_kdc.h"
42 #include "source4/kdc/pac-glue.h"
44 #include <ldb.h>
46 #undef DBGC_CLASS
47 #define DBGC_CLASS DBGC_KERBEROS
49 static
50 NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
51 const struct auth_user_info_dc *info,
52 const struct PAC_DOMAIN_GROUP_MEMBERSHIP *override_resource_groups,
53 const enum auth_group_inclusion group_inclusion,
54 DATA_BLOB *pac_data,
55 DATA_BLOB *requester_sid_blob)
57 struct netr_SamInfo3 *info3 = NULL;
58 struct PAC_DOMAIN_GROUP_MEMBERSHIP *_resource_groups = NULL;
59 struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups = NULL;
60 union PAC_INFO pac_info;
61 enum ndr_err_code ndr_err;
62 NTSTATUS nt_status;
64 ZERO_STRUCT(pac_info);
66 *pac_data = data_blob_null;
67 if (requester_sid_blob != NULL) {
68 *requester_sid_blob = data_blob_null;
71 if (override_resource_groups == NULL) {
72 resource_groups = &_resource_groups;
73 } else if (group_inclusion != AUTH_EXCLUDE_RESOURCE_GROUPS) {
75 * It doesn't make sense to override resource groups if we claim
76 * to want resource groups from user_info_dc.
78 DBG_ERR("supplied resource groups with invalid group inclusion parameter: %u\n",
79 group_inclusion);
80 return NT_STATUS_INVALID_PARAMETER;
83 nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info,
84 group_inclusion,
85 &info3,
86 resource_groups);
87 if (!NT_STATUS_IS_OK(nt_status)) {
88 DEBUG(1, ("Getting Samba info failed: %s\n",
89 nt_errstr(nt_status)));
90 return nt_status;
93 pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO);
94 if (!pac_info.logon_info.info) {
95 return NT_STATUS_NO_MEMORY;
98 pac_info.logon_info.info->info3 = *info3;
99 if (_resource_groups != NULL) {
100 pac_info.logon_info.info->resource_groups = *_resource_groups;
103 if (override_resource_groups != NULL) {
104 pac_info.logon_info.info->resource_groups = *override_resource_groups;
107 if (group_inclusion != AUTH_EXCLUDE_RESOURCE_GROUPS) {
109 * Set the resource groups flag based on whether any groups are
110 * present. Otherwise, the flag is propagated from the
111 * originating PAC.
113 if (pac_info.logon_info.info->resource_groups.groups.count > 0) {
114 pac_info.logon_info.info->info3.base.user_flags |= NETLOGON_RESOURCE_GROUPS;
115 } else {
116 pac_info.logon_info.info->info3.base.user_flags &= ~NETLOGON_RESOURCE_GROUPS;
120 ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
121 PAC_TYPE_LOGON_INFO,
122 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
123 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
124 nt_status = ndr_map_error2ntstatus(ndr_err);
125 DEBUG(1, ("PAC_LOGON_INFO (presig) push failed: %s\n",
126 nt_errstr(nt_status)));
127 return nt_status;
130 if (requester_sid_blob != NULL && info->num_sids > 0) {
131 union PAC_INFO pac_requester_sid;
133 ZERO_STRUCT(pac_requester_sid);
135 pac_requester_sid.requester_sid.sid = info->sids[PRIMARY_USER_SID_INDEX].sid;
137 ndr_err = ndr_push_union_blob(requester_sid_blob, mem_ctx,
138 &pac_requester_sid,
139 PAC_TYPE_REQUESTER_SID,
140 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
141 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
142 nt_status = ndr_map_error2ntstatus(ndr_err);
143 DEBUG(1, ("PAC_REQUESTER_SID (presig) push failed: %s\n",
144 nt_errstr(nt_status)));
145 return nt_status;
149 return NT_STATUS_OK;
152 static
153 NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
154 const struct auth_user_info_dc *info,
155 DATA_BLOB *upn_data)
157 union PAC_INFO pac_upn;
158 enum ndr_err_code ndr_err;
159 NTSTATUS nt_status;
160 bool ok;
162 ZERO_STRUCT(pac_upn);
164 *upn_data = data_blob_null;
166 pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
167 pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(mem_ctx,
168 info->info->dns_domain_name);
169 if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
170 return NT_STATUS_NO_MEMORY;
172 if (info->info->user_principal_constructed) {
173 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
176 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
178 pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname
179 = info->info->account_name;
181 pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid
182 = &info->sids[PRIMARY_USER_SID_INDEX].sid;
184 ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
185 PAC_TYPE_UPN_DNS_INFO,
186 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
188 nt_status = ndr_map_error2ntstatus(ndr_err);
189 DEBUG(1, ("PAC UPN_DNS_INFO (presig) push failed: %s\n",
190 nt_errstr(nt_status)));
191 return nt_status;
194 ok = data_blob_pad(mem_ctx, upn_data, 8);
195 if (!ok) {
196 return NT_STATUS_NO_MEMORY;
199 return NT_STATUS_OK;
202 static
203 NTSTATUS samba_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
204 uint64_t pac_attributes,
205 DATA_BLOB *pac_attrs_data)
207 union PAC_INFO pac_attrs;
208 enum ndr_err_code ndr_err;
209 NTSTATUS nt_status;
211 ZERO_STRUCT(pac_attrs);
213 *pac_attrs_data = data_blob_null;
215 /* Set the length of the flags in bits. */
216 pac_attrs.attributes_info.flags_length = 2;
217 pac_attrs.attributes_info.flags = pac_attributes;
219 ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
220 PAC_TYPE_ATTRIBUTES_INFO,
221 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
222 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
223 nt_status = ndr_map_error2ntstatus(ndr_err);
224 DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
225 nt_errstr(nt_status)));
226 return nt_status;
229 return NT_STATUS_OK;
232 static
233 NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
234 const struct ldb_message *msg,
235 DATA_BLOB *cred_blob)
237 enum ndr_err_code ndr_err;
238 NTSTATUS nt_status;
239 struct samr_Password *lm_hash = NULL;
240 struct samr_Password *nt_hash = NULL;
241 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg = {
242 .version = 0,
244 DATA_BLOB ntlm_blob = data_blob_null;
245 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs[1] = {{
246 .credential_size = 0,
248 struct PAC_CREDENTIAL_DATA cred_data = {
249 .credential_count = 0,
251 struct PAC_CREDENTIAL_DATA_NDR cred_ndr;
253 ZERO_STRUCT(cred_ndr);
255 *cred_blob = data_blob_null;
257 lm_hash = samdb_result_hash(mem_ctx, msg, "dBCSPwd");
258 if (lm_hash != NULL) {
259 bool zero = all_zero(lm_hash->hash, 16);
260 if (zero) {
261 lm_hash = NULL;
264 if (lm_hash != NULL) {
265 DEBUG(5, ("Passing LM password hash through credentials set\n"));
266 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_LM_HASH;
267 ntlm_secpkg.lm_password = *lm_hash;
268 ZERO_STRUCTP(lm_hash);
269 TALLOC_FREE(lm_hash);
272 nt_hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
273 if (nt_hash != NULL) {
274 bool zero = all_zero(nt_hash->hash, 16);
275 if (zero) {
276 nt_hash = NULL;
279 if (nt_hash != NULL) {
280 DEBUG(5, ("Passing LM password hash through credentials set\n"));
281 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_NT_HASH;
282 ntlm_secpkg.nt_password = *nt_hash;
283 ZERO_STRUCTP(nt_hash);
284 TALLOC_FREE(nt_hash);
287 if (ntlm_secpkg.flags == 0) {
288 return NT_STATUS_OK;
291 #ifdef DEBUG_PASSWORD
292 if (DEBUGLVL(11)) {
293 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG, &ntlm_secpkg);
295 #endif
297 ndr_err = ndr_push_struct_blob(&ntlm_blob, mem_ctx, &ntlm_secpkg,
298 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG);
299 ZERO_STRUCT(ntlm_secpkg);
300 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
301 nt_status = ndr_map_error2ntstatus(ndr_err);
302 DEBUG(1, ("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
303 nt_errstr(nt_status)));
304 return nt_status;
307 DEBUG(10, ("NTLM credential BLOB (len %zu) for user\n",
308 ntlm_blob.length));
309 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
310 ntlm_blob.data, ntlm_blob.length);
312 secpkgs[0].package_name.string = discard_const_p(char, "NTLM");
313 secpkgs[0].credential_size = ntlm_blob.length;
314 secpkgs[0].credential = ntlm_blob.data;
316 cred_data.credential_count = ARRAY_SIZE(secpkgs);
317 cred_data.credentials = secpkgs;
319 #ifdef DEBUG_PASSWORD
320 if (DEBUGLVL(11)) {
321 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA, &cred_data);
323 #endif
325 cred_ndr.ctr.data = &cred_data;
327 #ifdef DEBUG_PASSWORD
328 if (DEBUGLVL(11)) {
329 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR, &cred_ndr);
331 #endif
333 ndr_err = ndr_push_struct_blob(cred_blob, mem_ctx, &cred_ndr,
334 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_DATA_NDR);
335 data_blob_clear(&ntlm_blob);
336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
337 nt_status = ndr_map_error2ntstatus(ndr_err);
338 DEBUG(1, ("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
339 nt_errstr(nt_status)));
340 return nt_status;
343 DEBUG(10, ("Created credential BLOB (len %zu) for user\n",
344 cred_blob->length));
345 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
346 cred_blob->data, cred_blob->length);
348 return NT_STATUS_OK;
351 #ifdef SAMBA4_USES_HEIMDAL
352 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
353 const krb5_keyblock *pkreplykey,
354 const DATA_BLOB *cred_ndr_blob,
355 TALLOC_CTX *mem_ctx,
356 DATA_BLOB *cred_info_blob)
358 krb5_crypto cred_crypto;
359 krb5_enctype cred_enctype;
360 krb5_data cred_ndr_crypt;
361 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
362 krb5_error_code ret;
363 const char *krb5err;
364 enum ndr_err_code ndr_err;
365 NTSTATUS nt_status;
367 *cred_info_blob = data_blob_null;
369 ret = krb5_crypto_init(context, pkreplykey, ETYPE_NULL,
370 &cred_crypto);
371 if (ret != 0) {
372 krb5err = krb5_get_error_message(context, ret);
373 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
374 krb5_free_error_message(context, krb5err);
375 return ret;
378 ret = krb5_crypto_getenctype(context, cred_crypto, &cred_enctype);
379 if (ret != 0) {
380 DEBUG(1, ("Failed getting crypto type for key\n"));
381 krb5_crypto_destroy(context, cred_crypto);
382 return ret;
385 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
386 cred_ndr_blob->length));
387 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
388 cred_ndr_blob->data, cred_ndr_blob->length);
390 ret = krb5_encrypt(context, cred_crypto,
391 KRB5_KU_OTHER_ENCRYPTED,
392 cred_ndr_blob->data, cred_ndr_blob->length,
393 &cred_ndr_crypt);
394 krb5_crypto_destroy(context, cred_crypto);
395 if (ret != 0) {
396 krb5err = krb5_get_error_message(context, ret);
397 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
398 krb5_free_error_message(context, krb5err);
399 return ret;
402 pac_cred_info.encryption_type = cred_enctype;
403 pac_cred_info.encrypted_data.length = cred_ndr_crypt.length;
404 pac_cred_info.encrypted_data.data = (uint8_t *)cred_ndr_crypt.data;
406 if (DEBUGLVL(10)) {
407 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
410 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
411 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
412 krb5_data_free(&cred_ndr_crypt);
413 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
414 nt_status = ndr_map_error2ntstatus(ndr_err);
415 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
416 nt_errstr(nt_status)));
417 return KRB5KDC_ERR_SVC_UNAVAILABLE;
420 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
421 cred_info_blob->length, (int)pac_cred_info.encryption_type));
422 dump_data_pw("PAC_CREDENTIAL_INFO",
423 cred_info_blob->data, cred_info_blob->length);
425 return 0;
427 #else /* SAMBA4_USES_HEIMDAL */
428 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
429 const krb5_keyblock *pkreplykey,
430 const DATA_BLOB *cred_ndr_blob,
431 TALLOC_CTX *mem_ctx,
432 DATA_BLOB *cred_info_blob)
434 krb5_key cred_key;
435 krb5_enctype cred_enctype;
436 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
437 krb5_error_code code;
438 const char *krb5err;
439 enum ndr_err_code ndr_err;
440 NTSTATUS nt_status;
441 krb5_data cred_ndr_data;
442 krb5_enc_data cred_ndr_crypt;
443 size_t enc_len = 0;
445 *cred_info_blob = data_blob_null;
447 code = krb5_k_create_key(context,
448 pkreplykey,
449 &cred_key);
450 if (code != 0) {
451 krb5err = krb5_get_error_message(context, code);
452 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
453 krb5_free_error_message(context, krb5err);
454 return code;
457 cred_enctype = krb5_k_key_enctype(context, cred_key);
459 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
460 cred_ndr_blob->length));
461 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
462 cred_ndr_blob->data, cred_ndr_blob->length);
464 pac_cred_info.encryption_type = cred_enctype;
466 cred_ndr_data.magic = 0;
467 cred_ndr_data.data = (char *)cred_ndr_blob->data;
468 cred_ndr_data.length = cred_ndr_blob->length;
470 code = krb5_c_encrypt_length(context,
471 cred_enctype,
472 cred_ndr_data.length,
473 &enc_len);
474 if (code != 0) {
475 krb5err = krb5_get_error_message(context, code);
476 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
477 krb5_free_error_message(context, krb5err);
478 return code;
481 pac_cred_info.encrypted_data = data_blob_talloc_zero(mem_ctx, enc_len);
482 if (pac_cred_info.encrypted_data.data == NULL) {
483 DBG_ERR("Out of memory\n");
484 return ENOMEM;
487 cred_ndr_crypt.ciphertext.length = enc_len;
488 cred_ndr_crypt.ciphertext.data = (char *)pac_cred_info.encrypted_data.data;
490 code = krb5_k_encrypt(context,
491 cred_key,
492 KRB5_KU_OTHER_ENCRYPTED,
493 NULL,
494 &cred_ndr_data,
495 &cred_ndr_crypt);
496 krb5_k_free_key(context, cred_key);
497 if (code != 0) {
498 krb5err = krb5_get_error_message(context, code);
499 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
500 krb5_free_error_message(context, krb5err);
501 return code;
504 if (DEBUGLVL(10)) {
505 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
508 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
509 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
510 TALLOC_FREE(pac_cred_info.encrypted_data.data);
511 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
512 nt_status = ndr_map_error2ntstatus(ndr_err);
513 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
514 nt_errstr(nt_status)));
515 return KRB5KDC_ERR_SVC_UNAVAILABLE;
518 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
519 cred_info_blob->length, (int)pac_cred_info.encryption_type));
520 dump_data_pw("PAC_CREDENTIAL_INFO",
521 cred_info_blob->data, cred_info_blob->length);
523 return 0;
525 #endif /* SAMBA4_USES_HEIMDAL */
529 * @brief Create a PAC with the given blobs (logon, credentials, upn and
530 * delegation).
532 * @param[in] context The KRB5 context to use.
534 * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
535 * use NULL to ignore it.
537 * @param[in] cred_blob Fill the credentials info PAC buffer with the given
538 * blob, use NULL to ignore it.
540 * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
541 * NULL to ignore it.
543 * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
544 * blob, use NULL to ignore it.
546 * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
547 * given blob, use NULL to ignore it.
549 * @param[in] device_info_blob Fill the device info PAC buffer with the given
550 * blob, use NULL to ignore it.
552 * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
553 * blob, use NULL to ignore it.
555 * @param[in] pac The pac buffer to fill. This should be allocated with
556 * krb5_pac_init() already.
558 * @returns 0 on success or a corresponding KRB5 error.
560 krb5_error_code samba_make_krb5_pac(krb5_context context,
561 const DATA_BLOB *logon_blob,
562 const DATA_BLOB *cred_blob,
563 const DATA_BLOB *upn_blob,
564 const DATA_BLOB *pac_attrs_blob,
565 const DATA_BLOB *requester_sid_blob,
566 const DATA_BLOB *deleg_blob,
567 const DATA_BLOB *client_claims_blob,
568 const DATA_BLOB *device_info_blob,
569 const DATA_BLOB *device_claims_blob,
570 krb5_pac pac)
572 krb5_data logon_data;
573 krb5_error_code ret;
574 #ifdef SAMBA4_USES_HEIMDAL
575 char null_byte = '\0';
576 krb5_data null_data = smb_krb5_make_data(&null_byte, 0);
577 #endif
579 /* The user account may be set not to want the PAC */
580 if (logon_blob == NULL) {
581 return 0;
584 logon_data = smb_krb5_data_from_blob(*logon_blob);
585 ret = krb5_pac_add_buffer(context, pac, PAC_TYPE_LOGON_INFO, &logon_data);
586 if (ret != 0) {
587 return ret;
590 if (device_info_blob != NULL) {
591 krb5_data device_info_data = smb_krb5_data_from_blob(*device_info_blob);
592 ret = krb5_pac_add_buffer(context, pac,
593 PAC_TYPE_DEVICE_INFO,
594 &device_info_data);
595 if (ret != 0) {
596 return ret;
600 if (client_claims_blob != NULL) {
601 krb5_data client_claims_data = smb_krb5_data_from_blob(*client_claims_blob);
602 ret = krb5_pac_add_buffer(context, pac,
603 PAC_TYPE_CLIENT_CLAIMS_INFO,
604 &client_claims_data);
605 if (ret != 0) {
606 return ret;
610 if (device_claims_blob != NULL) {
611 krb5_data device_claims_data = smb_krb5_data_from_blob(*device_claims_blob);
612 ret = krb5_pac_add_buffer(context, pac,
613 PAC_TYPE_DEVICE_CLAIMS_INFO,
614 &device_claims_data);
615 if (ret != 0) {
616 return ret;
620 if (cred_blob != NULL) {
621 krb5_data cred_data = smb_krb5_data_from_blob(*cred_blob);
622 ret = krb5_pac_add_buffer(context, pac,
623 PAC_TYPE_CREDENTIAL_INFO,
624 &cred_data);
625 if (ret != 0) {
626 return ret;
630 #ifdef SAMBA4_USES_HEIMDAL
632 * null_data will be filled by the generic KDC code in the caller
633 * here we just add it in order to have it before
634 * PAC_TYPE_UPN_DNS_INFO
636 * Not needed with MIT Kerberos - asn
638 ret = krb5_pac_add_buffer(context, pac,
639 PAC_TYPE_LOGON_NAME,
640 &null_data);
641 if (ret != 0) {
642 return ret;
644 #endif
646 if (upn_blob != NULL) {
647 krb5_data upn_data = smb_krb5_data_from_blob(*upn_blob);
648 ret = krb5_pac_add_buffer(context, pac,
649 PAC_TYPE_UPN_DNS_INFO,
650 &upn_data);
651 if (ret != 0) {
652 return ret;
656 if (pac_attrs_blob != NULL) {
657 krb5_data pac_attrs_data = smb_krb5_data_from_blob(*pac_attrs_blob);
658 ret = krb5_pac_add_buffer(context, pac,
659 PAC_TYPE_ATTRIBUTES_INFO,
660 &pac_attrs_data);
661 if (ret != 0) {
662 return ret;
666 if (requester_sid_blob != NULL) {
667 krb5_data requester_sid_data = smb_krb5_data_from_blob(*requester_sid_blob);
668 ret = krb5_pac_add_buffer(context, pac,
669 PAC_TYPE_REQUESTER_SID,
670 &requester_sid_data);
671 if (ret != 0) {
672 return ret;
676 if (deleg_blob != NULL) {
677 krb5_data deleg_data = smb_krb5_data_from_blob(*deleg_blob);
678 ret = krb5_pac_add_buffer(context, pac,
679 PAC_TYPE_CONSTRAINED_DELEGATION,
680 &deleg_data);
681 if (ret != 0) {
682 return ret;
686 return ret;
689 bool samba_princ_needs_pac(const struct samba_kdc_entry *skdc_entry)
692 uint32_t userAccountControl;
694 /* The service account may be set not to want the PAC */
695 userAccountControl = ldb_msg_find_attr_as_uint(skdc_entry->msg, "userAccountControl", 0);
696 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
697 return false;
700 return true;
703 int samba_client_requested_pac(krb5_context context,
704 const krb5_const_pac pac,
705 TALLOC_CTX *mem_ctx,
706 bool *requested_pac)
708 enum ndr_err_code ndr_err;
709 krb5_data k5pac_attrs_in;
710 DATA_BLOB pac_attrs_in;
711 union PAC_INFO pac_attrs;
712 int ret;
714 *requested_pac = true;
716 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_ATTRIBUTES_INFO,
717 &k5pac_attrs_in);
718 if (ret != 0) {
719 return ret == ENOENT ? 0 : ret;
722 pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
723 k5pac_attrs_in.length);
725 ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
726 PAC_TYPE_ATTRIBUTES_INFO,
727 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
728 smb_krb5_free_data_contents(context, &k5pac_attrs_in);
729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
730 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
731 DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status)));
732 return EINVAL;
735 if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
736 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
737 *requested_pac = true;
738 } else {
739 *requested_pac = false;
742 return 0;
745 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
746 int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
747 bool *is_in_db,
748 bool *is_trusted)
750 NTSTATUS status;
751 int rodc_krbtgt_number, trust_direction;
752 uint32_t rid;
754 TALLOC_CTX *mem_ctx = talloc_new(NULL);
755 if (!mem_ctx) {
756 return ENOMEM;
759 trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
761 if (trust_direction != 0) {
762 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
764 This is exactly where we should flag for SID
765 validation when we do inter-foreest trusts
767 talloc_free(mem_ctx);
768 *is_trusted = true;
769 *is_in_db = false;
770 return 0;
773 /* The lack of password controls etc applies to krbtgt by
774 * virtue of being that particular RID */
775 status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"), NULL, &rid);
777 if (!NT_STATUS_IS_OK(status)) {
778 talloc_free(mem_ctx);
779 return EINVAL;
782 rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
784 if (p->kdc_db_ctx->my_krbtgt_number == 0) {
785 if (rid == DOMAIN_RID_KRBTGT) {
786 *is_trusted = true;
787 *is_in_db = true;
788 talloc_free(mem_ctx);
789 return 0;
790 } else if (rodc_krbtgt_number != -1) {
791 *is_in_db = true;
792 *is_trusted = false;
793 talloc_free(mem_ctx);
794 return 0;
796 } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
797 talloc_free(mem_ctx);
798 *is_trusted = true;
799 *is_in_db = true;
800 return 0;
801 } else if (rid == DOMAIN_RID_KRBTGT) {
802 /* krbtgt viewed from an RODC */
803 talloc_free(mem_ctx);
804 *is_trusted = true;
805 *is_in_db = false;
806 return 0;
809 /* Another RODC */
810 talloc_free(mem_ctx);
811 *is_trusted = false;
812 *is_in_db = false;
813 return 0;
817 * Because the KDC does not limit protocol transition, two new well-known SIDs
818 * were introduced to give this control to the resource administrator. These
819 * SIDs identify whether protocol transition has occurred, and can be used with
820 * standard access control lists to grant or limit access as needed.
822 * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
824 static NTSTATUS samba_add_asserted_identity(TALLOC_CTX *mem_ctx,
825 enum samba_asserted_identity ai,
826 struct auth_user_info_dc *user_info_dc)
828 struct dom_sid ai_sid;
829 const char *sid_str = NULL;
831 switch (ai) {
832 case SAMBA_ASSERTED_IDENTITY_SERVICE:
833 sid_str = SID_SERVICE_ASSERTED_IDENTITY;
834 break;
835 case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY:
836 sid_str = SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY;
837 break;
838 case SAMBA_ASSERTED_IDENTITY_IGNORE:
839 return NT_STATUS_OK;
842 dom_sid_parse(sid_str, &ai_sid);
844 return add_sid_to_array_attrs_unique(
845 user_info_dc,
846 &ai_sid,
847 SE_GROUP_DEFAULT_FLAGS,
848 &user_info_dc->sids,
849 &user_info_dc->num_sids);
853 * Look up the user's info in the database and create a auth_user_info_dc
854 * structure. If the resulting structure is not talloc_free()d, it will be
855 * reused on future calls to this function.
857 NTSTATUS samba_kdc_get_user_info_from_db(struct samba_kdc_entry *skdc_entry,
858 const struct ldb_message *msg,
859 struct auth_user_info_dc **user_info_dc)
861 if (skdc_entry->user_info_dc == NULL) {
862 NTSTATUS nt_status;
863 struct loadparm_context *lp_ctx = skdc_entry->kdc_db_ctx->lp_ctx;
865 nt_status = authsam_make_user_info_dc(skdc_entry,
866 skdc_entry->kdc_db_ctx->samdb,
867 lpcfg_netbios_name(lp_ctx),
868 lpcfg_sam_name(lp_ctx),
869 lpcfg_sam_dnsname(lp_ctx),
870 skdc_entry->realm_dn,
871 msg,
872 data_blob_null,
873 data_blob_null,
874 &skdc_entry->user_info_dc);
875 if (!NT_STATUS_IS_OK(nt_status)) {
876 return nt_status;
880 *user_info_dc = skdc_entry->user_info_dc;
881 return NT_STATUS_OK;
884 NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
885 struct samba_kdc_entry *p,
886 enum samba_asserted_identity asserted_identity,
887 const enum auth_group_inclusion group_inclusion,
888 DATA_BLOB **_logon_info_blob,
889 DATA_BLOB **_cred_ndr_blob,
890 DATA_BLOB **_upn_info_blob,
891 DATA_BLOB **_pac_attrs_blob,
892 uint64_t pac_attributes,
893 DATA_BLOB **_requester_sid_blob,
894 DATA_BLOB **_client_claims_blob)
896 struct auth_user_info_dc *user_info_dc = NULL;
897 DATA_BLOB *logon_blob = NULL;
898 DATA_BLOB *cred_blob = NULL;
899 DATA_BLOB *upn_blob = NULL;
900 DATA_BLOB *pac_attrs_blob = NULL;
901 DATA_BLOB *requester_sid_blob = NULL;
902 DATA_BLOB *client_claims_blob = NULL;
903 NTSTATUS nt_status;
905 *_logon_info_blob = NULL;
906 if (_cred_ndr_blob != NULL) {
907 *_cred_ndr_blob = NULL;
909 *_upn_info_blob = NULL;
910 if (_pac_attrs_blob != NULL) {
911 *_pac_attrs_blob = NULL;
913 if (_requester_sid_blob != NULL) {
914 *_requester_sid_blob = NULL;
916 if (_client_claims_blob != NULL) {
917 *_client_claims_blob = NULL;
920 logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
921 if (logon_blob == NULL) {
922 return NT_STATUS_NO_MEMORY;
925 if (_cred_ndr_blob != NULL) {
926 cred_blob = talloc_zero(mem_ctx, DATA_BLOB);
927 if (cred_blob == NULL) {
928 return NT_STATUS_NO_MEMORY;
932 upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
933 if (upn_blob == NULL) {
934 return NT_STATUS_NO_MEMORY;
937 if (_pac_attrs_blob != NULL) {
938 pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
939 if (pac_attrs_blob == NULL) {
940 return NT_STATUS_NO_MEMORY;
944 if (_requester_sid_blob != NULL) {
945 requester_sid_blob = talloc_zero(mem_ctx, DATA_BLOB);
946 if (requester_sid_blob == NULL) {
947 return NT_STATUS_NO_MEMORY;
951 if (_client_claims_blob != NULL) {
953 * Until we support claims we just
954 * return an empty blob,
955 * that matches what Windows is doing
956 * without defined claims
958 client_claims_blob = talloc_zero(mem_ctx, DATA_BLOB);
959 if (client_claims_blob == NULL) {
960 return NT_STATUS_NO_MEMORY;
964 nt_status = samba_kdc_get_user_info_from_db(p,
965 p->msg,
966 &user_info_dc);
967 if (!NT_STATUS_IS_OK(nt_status)) {
968 DEBUG(0, ("Getting user info for PAC failed: %s\n",
969 nt_errstr(nt_status)));
970 return nt_status;
973 nt_status = samba_add_asserted_identity(mem_ctx,
974 asserted_identity,
975 user_info_dc);
976 if (!NT_STATUS_IS_OK(nt_status)) {
977 DBG_ERR("Failed to add assertied identity!\n");
978 return nt_status;
981 nt_status = samba_get_logon_info_pac_blob(logon_blob,
982 user_info_dc,
983 NULL,
984 group_inclusion,
985 logon_blob,
986 requester_sid_blob);
987 if (!NT_STATUS_IS_OK(nt_status)) {
988 DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
989 nt_errstr(nt_status)));
990 return nt_status;
993 if (cred_blob != NULL) {
994 nt_status = samba_get_cred_info_ndr_blob(cred_blob,
995 p->msg,
996 cred_blob);
997 if (!NT_STATUS_IS_OK(nt_status)) {
998 DEBUG(0, ("Building PAC CRED INFO failed: %s\n",
999 nt_errstr(nt_status)));
1000 return nt_status;
1004 nt_status = samba_get_upn_info_pac_blob(upn_blob,
1005 user_info_dc,
1006 upn_blob);
1007 if (!NT_STATUS_IS_OK(nt_status)) {
1008 DEBUG(0, ("Building PAC UPN INFO failed: %s\n",
1009 nt_errstr(nt_status)));
1010 return nt_status;
1013 if (pac_attrs_blob != NULL) {
1014 nt_status = samba_get_pac_attrs_blob(pac_attrs_blob,
1015 pac_attributes,
1016 pac_attrs_blob);
1018 if (!NT_STATUS_IS_OK(nt_status)) {
1019 DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
1020 nt_errstr(nt_status)));
1021 return nt_status;
1025 *_logon_info_blob = logon_blob;
1026 if (_cred_ndr_blob != NULL) {
1027 *_cred_ndr_blob = cred_blob;
1029 *_upn_info_blob = upn_blob;
1030 if (_pac_attrs_blob != NULL) {
1031 *_pac_attrs_blob = pac_attrs_blob;
1033 if (_requester_sid_blob != NULL) {
1034 *_requester_sid_blob = requester_sid_blob;
1036 if (_client_claims_blob != NULL) {
1037 *_client_claims_blob = client_claims_blob;
1039 return NT_STATUS_OK;
1042 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
1043 krb5_context context,
1044 struct ldb_context *samdb,
1045 const enum auth_group_inclusion group_inclusion,
1046 const krb5_pac pac, DATA_BLOB *pac_blob,
1047 struct PAC_SIGNATURE_DATA *pac_srv_sig,
1048 struct PAC_SIGNATURE_DATA *pac_kdc_sig)
1050 struct auth_user_info_dc *user_info_dc;
1051 krb5_error_code ret;
1052 NTSTATUS nt_status;
1053 struct PAC_DOMAIN_GROUP_MEMBERSHIP *_resource_groups = NULL;
1054 struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups = NULL;
1056 if (group_inclusion == AUTH_EXCLUDE_RESOURCE_GROUPS) {
1058 * Since we are creating a TGT, resource groups from our domain
1059 * are not to be put into the PAC. Instead, we take the resource
1060 * groups directly from the original PAC and copy them
1061 * unmodified into the new one.
1063 resource_groups = &_resource_groups;
1066 ret = kerberos_pac_to_user_info_dc(mem_ctx,
1067 pac,
1068 context,
1069 &user_info_dc,
1070 AUTH_EXCLUDE_RESOURCE_GROUPS,
1071 pac_srv_sig,
1072 pac_kdc_sig,
1073 resource_groups);
1074 if (ret) {
1075 return NT_STATUS_UNSUCCESSFUL;
1079 * We need to expand group memberships within our local domain,
1080 * as the token might be generated by a trusted domain.
1082 nt_status = authsam_update_user_info_dc(mem_ctx,
1083 samdb,
1084 user_info_dc);
1085 if (!NT_STATUS_IS_OK(nt_status)) {
1086 TALLOC_FREE(user_info_dc);
1087 return nt_status;
1090 nt_status = samba_get_logon_info_pac_blob(mem_ctx,
1091 user_info_dc,
1092 _resource_groups,
1093 group_inclusion,
1094 pac_blob, NULL);
1097 * The infomation from this is now in the PAC, this memory is
1098 * not used any longer and not passed to the caller
1100 TALLOC_FREE(user_info_dc);
1102 return nt_status;
1105 NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
1106 krb5_context context,
1107 const krb5_const_pac pac,
1108 const krb5_principal server_principal,
1109 const krb5_principal proxy_principal,
1110 DATA_BLOB *new_blob)
1112 krb5_data old_data;
1113 DATA_BLOB old_blob;
1114 krb5_error_code ret;
1115 NTSTATUS nt_status;
1116 enum ndr_err_code ndr_err;
1117 union PAC_INFO info;
1118 struct PAC_CONSTRAINED_DELEGATION _d;
1119 struct PAC_CONSTRAINED_DELEGATION *d = NULL;
1120 char *server = NULL;
1121 char *proxy = NULL;
1122 uint32_t i;
1123 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1125 if (tmp_ctx == NULL) {
1126 return NT_STATUS_NO_MEMORY;
1129 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
1130 if (ret == ENOENT) {
1131 ZERO_STRUCT(old_data);
1132 } else if (ret) {
1133 talloc_free(tmp_ctx);
1134 return NT_STATUS_UNSUCCESSFUL;
1137 old_blob.length = old_data.length;
1138 old_blob.data = (uint8_t *)old_data.data;
1140 ZERO_STRUCT(info);
1141 if (old_blob.length > 0) {
1142 ndr_err = ndr_pull_union_blob(&old_blob, mem_ctx,
1143 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1144 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1145 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1146 smb_krb5_free_data_contents(context, &old_data);
1147 nt_status = ndr_map_error2ntstatus(ndr_err);
1148 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1149 talloc_free(tmp_ctx);
1150 return nt_status;
1152 } else {
1153 ZERO_STRUCT(_d);
1154 info.constrained_delegation.info = &_d;
1156 smb_krb5_free_data_contents(context, &old_data);
1158 ret = krb5_unparse_name_flags(context, server_principal,
1159 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server);
1160 if (ret) {
1161 talloc_free(tmp_ctx);
1162 return NT_STATUS_INTERNAL_ERROR;
1165 ret = krb5_unparse_name(context, proxy_principal, &proxy);
1166 if (ret) {
1167 SAFE_FREE(server);
1168 talloc_free(tmp_ctx);
1169 return NT_STATUS_INTERNAL_ERROR;
1172 d = info.constrained_delegation.info;
1173 i = d->num_transited_services;
1174 d->proxy_target.string = server;
1175 d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
1176 struct lsa_String, i + 1);
1177 d->transited_services[i].string = proxy;
1178 d->num_transited_services = i + 1;
1180 ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
1181 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1182 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1183 SAFE_FREE(server);
1184 SAFE_FREE(proxy);
1185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1186 smb_krb5_free_data_contents(context, &old_data);
1187 nt_status = ndr_map_error2ntstatus(ndr_err);
1188 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1189 talloc_free(tmp_ctx);
1190 return nt_status;
1193 talloc_free(tmp_ctx);
1194 return NT_STATUS_OK;
1197 /* function to map policy errors */
1198 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
1200 krb5_error_code ret;
1202 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
1203 ret = KRB5KDC_ERR_KEY_EXP;
1204 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
1205 ret = KRB5KDC_ERR_KEY_EXP;
1206 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
1207 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1208 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
1209 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1210 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
1211 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1212 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
1213 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1214 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
1215 ret = KRB5KDC_ERR_POLICY;
1216 else
1217 ret = KRB5KDC_ERR_POLICY;
1219 return ret;
1222 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1223 * for consistency */
1224 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
1225 const char *client_name,
1226 const char *workstation,
1227 bool password_change)
1229 TALLOC_CTX *tmp_ctx;
1230 NTSTATUS nt_status;
1232 tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
1233 if (!tmp_ctx) {
1234 return NT_STATUS_NO_MEMORY;
1237 /* we allow all kinds of trusts here */
1238 nt_status = authsam_account_ok(tmp_ctx,
1239 kdc_entry->kdc_db_ctx->samdb,
1240 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
1241 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
1242 kdc_entry->realm_dn, kdc_entry->msg,
1243 workstation, client_name,
1244 true, password_change);
1246 kdc_entry->reject_status = nt_status;
1247 talloc_free(tmp_ctx);
1248 return nt_status;
1251 static krb5_error_code samba_get_requester_sid(TALLOC_CTX *mem_ctx,
1252 krb5_const_pac pac,
1253 krb5_context context,
1254 struct dom_sid *sid)
1256 NTSTATUS nt_status;
1257 enum ndr_err_code ndr_err;
1258 krb5_error_code ret;
1260 DATA_BLOB pac_requester_sid_in;
1261 krb5_data k5pac_requester_sid_in;
1263 union PAC_INFO info;
1265 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1266 if (tmp_ctx == NULL) {
1267 return ENOMEM;
1270 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
1271 &k5pac_requester_sid_in);
1272 if (ret != 0) {
1273 talloc_free(tmp_ctx);
1274 return ret;
1277 pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
1278 k5pac_requester_sid_in.length);
1280 ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
1281 PAC_TYPE_REQUESTER_SID,
1282 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1283 smb_krb5_free_data_contents(context, &k5pac_requester_sid_in);
1284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1285 nt_status = ndr_map_error2ntstatus(ndr_err);
1286 DEBUG(0,("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status)));
1287 talloc_free(tmp_ctx);
1288 return EINVAL;
1291 *sid = info.requester_sid.sid;
1293 talloc_free(tmp_ctx);
1294 return 0;
1297 /* Does a parse and SID check, but no crypto. */
1298 krb5_error_code samba_kdc_validate_pac_blob(
1299 krb5_context context,
1300 const struct samba_kdc_entry *client_skdc_entry,
1301 const krb5_const_pac pac)
1303 TALLOC_CTX *frame = talloc_stackframe();
1304 struct auth_user_info_dc *pac_user_info = NULL;
1305 struct dom_sid *client_sid = NULL;
1306 struct dom_sid pac_sid;
1307 krb5_error_code code;
1308 bool ok;
1311 * First, try to get the SID from the requester SID buffer in the PAC.
1313 code = samba_get_requester_sid(frame, pac, context, &pac_sid);
1315 if (code == ENOENT) {
1317 * If the requester SID buffer isn't present, fall back to the
1318 * SID in the LOGON_INFO PAC buffer.
1320 code = kerberos_pac_to_user_info_dc(frame,
1321 pac,
1322 context,
1323 &pac_user_info,
1324 AUTH_EXCLUDE_RESOURCE_GROUPS,
1325 NULL,
1326 NULL,
1327 NULL);
1328 if (code != 0) {
1329 goto out;
1332 if (pac_user_info->num_sids == 0) {
1333 code = EINVAL;
1334 goto out;
1337 pac_sid = pac_user_info->sids[PRIMARY_USER_SID_INDEX].sid;
1338 } else if (code != 0) {
1339 goto out;
1342 client_sid = samdb_result_dom_sid(frame,
1343 client_skdc_entry->msg,
1344 "objectSid");
1346 ok = dom_sid_equal(&pac_sid, client_sid);
1347 if (!ok) {
1348 struct dom_sid_buf buf1;
1349 struct dom_sid_buf buf2;
1351 DBG_ERR("SID mismatch between PAC and looked up client: "
1352 "PAC[%s] != CLI[%s]\n",
1353 dom_sid_str_buf(&pac_sid, &buf1),
1354 dom_sid_str_buf(client_sid, &buf2));
1355 code = KRB5KDC_ERR_TGT_REVOKED;
1356 goto out;
1359 code = 0;
1360 out:
1361 TALLOC_FREE(frame);
1362 return code;
1367 * In the RODC case, to confirm that the returned user is permitted to
1368 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1370 WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
1371 const struct dom_sid *object_sids,
1372 const struct samba_kdc_entry *rodc,
1373 const struct samba_kdc_entry *object)
1375 int ret;
1376 WERROR werr;
1377 TALLOC_CTX *frame = talloc_stackframe();
1378 const char *rodc_attrs[] = { "msDS-KrbTgtLink",
1379 "msDS-NeverRevealGroup",
1380 "msDS-RevealOnDemandGroup",
1381 "userAccountControl",
1382 "objectSid",
1383 NULL };
1384 struct ldb_result *rodc_machine_account = NULL;
1385 struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
1386 frame,
1387 rodc->msg,
1388 "msDS-KrbTgtLinkBL",
1389 NULL);
1390 const struct dom_sid *rodc_machine_account_sid = NULL;
1392 if (rodc_machine_account_dn == NULL) {
1393 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1394 ldb_dn_get_linearized(rodc->msg->dn));
1395 TALLOC_FREE(frame);
1396 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1400 * Follow the link and get the RODC account (the krbtgt
1401 * account is the krbtgt_XXX account, but the
1402 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1403 * the RODC$ account)
1405 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1406 * out of the extended DNs
1409 ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
1410 frame,
1411 &rodc_machine_account,
1412 rodc_machine_account_dn,
1413 rodc_attrs,
1414 DSDB_SEARCH_SHOW_EXTENDED_DN);
1415 if (ret != LDB_SUCCESS) {
1416 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1417 ldb_dn_get_linearized(rodc_machine_account_dn),
1418 ldb_dn_get_linearized(rodc->msg->dn),
1419 ldb_errstring(rodc->kdc_db_ctx->samdb));
1420 TALLOC_FREE(frame);
1421 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1424 if (rodc_machine_account->count != 1) {
1425 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1426 ldb_dn_get_linearized(rodc_machine_account_dn),
1427 ldb_dn_get_linearized(rodc->msg->dn),
1428 rodc_machine_account->count);
1429 TALLOC_FREE(frame);
1430 return WERR_DS_DRA_BAD_DN;
1433 /* if the object SID is equal to the user_sid, allow */
1434 rodc_machine_account_sid = samdb_result_dom_sid(frame,
1435 rodc_machine_account->msgs[0],
1436 "objectSid");
1437 if (rodc_machine_account_sid == NULL) {
1438 return WERR_DS_DRA_BAD_DN;
1441 werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
1442 rodc_machine_account_sid,
1443 rodc_machine_account->msgs[0],
1444 object->msg,
1445 num_object_sids,
1446 object_sids);
1448 TALLOC_FREE(frame);
1449 return werr;
1453 * @brief Update a PAC
1455 * @param mem_ctx A talloc memory context
1457 * @param context A krb5 context
1459 * @param samdb An open samdb connection.
1461 * @param flags Bitwise OR'ed flags
1463 * @param client The client samba kdc entry.
1465 * @param server_principal The server principal
1467 * @param server The server samba kdc entry.
1469 * @param krbtgt The krbtgt samba kdc entry.
1471 * @param delegated_proxy_principal The delegated proxy principal used for
1472 * updating the constrained delegation PAC
1473 * buffer.
1475 * @param old_pac The old PAC
1477 * @param new_pac The new already allocated PAC
1479 * @return A Kerberos error code. If no PAC should be returned, the code will be
1480 * ENOATTR!
1482 krb5_error_code samba_kdc_update_pac(TALLOC_CTX *mem_ctx,
1483 krb5_context context,
1484 struct ldb_context *samdb,
1485 uint32_t flags,
1486 struct samba_kdc_entry *client,
1487 const krb5_principal server_principal,
1488 const struct samba_kdc_entry *server,
1489 const struct samba_kdc_entry *krbtgt,
1490 const krb5_principal delegated_proxy_principal,
1491 const krb5_pac old_pac,
1492 const krb5_pac new_pac)
1494 krb5_error_code code = EINVAL;
1495 NTSTATUS nt_status;
1496 DATA_BLOB *pac_blob = NULL;
1497 DATA_BLOB *upn_blob = NULL;
1498 DATA_BLOB *deleg_blob = NULL;
1499 DATA_BLOB *requester_sid_blob = NULL;
1500 DATA_BLOB *client_claims_blob = NULL;
1501 bool is_trusted = flags & SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED;
1502 int is_tgs = false;
1503 enum auth_group_inclusion group_inclusion;
1504 size_t num_types = 0;
1505 uint32_t *types = NULL;
1507 * FIXME: Do we really still need forced_next_type? With MIT Kerberos
1508 * the PAC buffers do not get ordered and it works just fine. We are
1509 * not aware of any issues in this regard. This might be just ancient
1510 * code.
1512 uint32_t forced_next_type = 0;
1513 size_t i = 0;
1514 ssize_t logon_info_idx = -1;
1515 ssize_t delegation_idx = -1;
1516 ssize_t logon_name_idx = -1;
1517 ssize_t upn_dns_info_idx = -1;
1518 ssize_t srv_checksum_idx = -1;
1519 ssize_t kdc_checksum_idx = -1;
1520 ssize_t tkt_checksum_idx = -1;
1521 ssize_t attrs_info_idx = -1;
1522 ssize_t requester_sid_idx = -1;
1523 ssize_t full_checksum_idx = -1;
1525 is_tgs = smb_krb5_principal_is_tgs(context, server_principal);
1526 if (is_tgs == -1) {
1527 code = ENOMEM;
1528 goto done;
1531 /* Only include resource groups in a service ticket. */
1532 if (is_tgs) {
1533 group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
1534 } else if (server->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
1535 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
1536 } else {
1537 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
1540 if (client != NULL) {
1542 * Check the objectSID of the client and pac data are the same.
1543 * Does a parse and SID check, but no crypto.
1545 code = samba_kdc_validate_pac_blob(context,
1546 client,
1547 old_pac);
1548 if (code != 0) {
1549 goto done;
1553 if (delegated_proxy_principal != NULL) {
1554 deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
1555 if (deleg_blob == NULL) {
1556 code = ENOMEM;
1557 goto done;
1560 nt_status = samba_kdc_update_delegation_info_blob(
1561 mem_ctx,
1562 context,
1563 old_pac,
1564 server_principal,
1565 delegated_proxy_principal,
1566 deleg_blob);
1567 if (!NT_STATUS_IS_OK(nt_status)) {
1568 DBG_ERR("update delegation info blob failed: %s\n",
1569 nt_errstr(nt_status));
1570 code = EINVAL;
1571 goto done;
1575 if (!is_trusted) {
1576 struct auth_user_info_dc *user_info_dc = NULL;
1577 WERROR werr;
1579 struct dom_sid *object_sids = NULL;
1580 uint32_t j;
1583 * In this case the RWDC discards the PAC an RODC generated.
1584 * Windows adds the asserted_identity in this case too.
1586 * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1587 * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1588 * So we can always use
1589 * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1590 * here.
1592 enum samba_asserted_identity asserted_identity =
1593 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
1595 if (client == NULL) {
1596 code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1597 goto done;
1600 nt_status = samba_kdc_get_pac_blobs(mem_ctx,
1601 client,
1602 asserted_identity,
1603 group_inclusion,
1604 &pac_blob,
1605 NULL,
1606 &upn_blob,
1607 NULL,
1608 PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
1609 &requester_sid_blob,
1610 &client_claims_blob);
1611 if (!NT_STATUS_IS_OK(nt_status)) {
1612 DBG_ERR("samba_kdc_get_pac_blobs failed: %s\n",
1613 nt_errstr(nt_status));
1614 code = KRB5KDC_ERR_TGT_REVOKED;
1615 goto done;
1618 nt_status = samba_kdc_get_user_info_from_db(client,
1619 client->msg,
1620 &user_info_dc);
1621 if (!NT_STATUS_IS_OK(nt_status)) {
1622 DBG_ERR("samba_kdc_get_user_info_from_db failed: %s\n",
1623 nt_errstr(nt_status));
1624 code = KRB5KDC_ERR_TGT_REVOKED;
1625 goto done;
1629 * Check if the SID list in the user_info_dc intersects
1630 * correctly with the RODC allow/deny lists.
1632 object_sids = talloc_array(mem_ctx, struct dom_sid, user_info_dc->num_sids);
1633 if (object_sids == NULL) {
1634 code = ENOMEM;
1635 goto done;
1638 for (j = 0; j < user_info_dc->num_sids; ++j) {
1639 object_sids[j] = user_info_dc->sids[j].sid;
1642 werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
1643 object_sids,
1644 krbtgt,
1645 client);
1646 TALLOC_FREE(object_sids);
1647 TALLOC_FREE(user_info_dc);
1648 if (!W_ERROR_IS_OK(werr)) {
1649 code = KRB5KDC_ERR_TGT_REVOKED;
1650 if (W_ERROR_EQUAL(werr,
1651 WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
1652 code = KRB5KDC_ERR_POLICY;
1654 goto done;
1658 * The RODC PAC data isn't trusted for authorization as it may
1659 * be stale. The only thing meaningful we can do with an RODC
1660 * account on a full DC is exchange the RODC TGT for a 'real'
1661 * TGT.
1663 * So we match Windows (at least server 2022) and
1664 * don't allow S4U2Self.
1666 * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
1668 if (flags & SAMBA_KDC_FLAG_PROTOCOL_TRANSITION) {
1669 code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1670 goto done;
1672 } else {
1673 pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
1674 if (pac_blob == NULL) {
1675 code = ENOMEM;
1676 goto done;
1679 nt_status = samba_kdc_update_pac_blob(mem_ctx,
1680 context,
1681 samdb,
1682 group_inclusion,
1683 old_pac,
1684 pac_blob,
1685 NULL,
1686 NULL);
1687 if (!NT_STATUS_IS_OK(nt_status)) {
1688 DBG_ERR("samba_kdc_update_pac_blob failed: %s\n",
1689 nt_errstr(nt_status));
1690 code = EINVAL;
1691 goto done;
1695 /* Check the types of the given PAC */
1696 code = krb5_pac_get_types(context, old_pac, &num_types, &types);
1697 if (code != 0) {
1698 DBG_ERR("krb5_pac_get_types failed\n");
1699 goto done;
1702 for (i = 0; i < num_types; i++) {
1703 switch (types[i]) {
1704 case PAC_TYPE_LOGON_INFO:
1705 if (logon_info_idx != -1) {
1706 DBG_WARNING("logon info type[%u] twice [%zd] "
1707 "and [%zu]: \n",
1708 types[i],
1709 logon_info_idx,
1711 code = EINVAL;
1712 goto done;
1714 logon_info_idx = i;
1715 break;
1716 case PAC_TYPE_CONSTRAINED_DELEGATION:
1717 if (delegation_idx != -1) {
1718 DBG_WARNING("constrained delegation type[%u] "
1719 "twice [%zd] and [%zu]: \n",
1720 types[i],
1721 delegation_idx,
1723 code = EINVAL;
1724 goto done;
1726 delegation_idx = i;
1727 break;
1728 case PAC_TYPE_LOGON_NAME:
1729 if (logon_name_idx != -1) {
1730 DBG_WARNING("logon name type[%u] twice [%zd] "
1731 "and [%zu]: \n",
1732 types[i],
1733 logon_name_idx,
1735 code = EINVAL;
1736 goto done;
1738 logon_name_idx = i;
1739 break;
1740 case PAC_TYPE_UPN_DNS_INFO:
1741 if (upn_dns_info_idx != -1) {
1742 DBG_WARNING("upn dns info type[%u] twice [%zd] "
1743 "and [%zu]: \n",
1744 types[i],
1745 upn_dns_info_idx,
1747 code = EINVAL;
1748 goto done;
1750 upn_dns_info_idx = i;
1751 break;
1752 case PAC_TYPE_SRV_CHECKSUM:
1753 if (srv_checksum_idx != -1) {
1754 DBG_WARNING("srv checksum type[%u] twice [%zd] "
1755 "and [%zu]: \n",
1756 types[i],
1757 srv_checksum_idx,
1759 code = EINVAL;
1760 goto done;
1762 srv_checksum_idx = i;
1763 break;
1764 case PAC_TYPE_KDC_CHECKSUM:
1765 if (kdc_checksum_idx != -1) {
1766 DBG_WARNING("kdc checksum type[%u] twice [%zd] "
1767 "and [%zu]: \n",
1768 types[i],
1769 kdc_checksum_idx,
1771 code = EINVAL;
1772 goto done;
1774 kdc_checksum_idx = i;
1775 break;
1776 case PAC_TYPE_TICKET_CHECKSUM:
1777 if (tkt_checksum_idx != -1) {
1778 DBG_WARNING("ticket checksum type[%u] twice "
1779 "[%zd] and [%zu]: \n",
1780 types[i],
1781 tkt_checksum_idx,
1783 code = EINVAL;
1784 goto done;
1786 tkt_checksum_idx = i;
1787 break;
1788 case PAC_TYPE_ATTRIBUTES_INFO:
1789 if (attrs_info_idx != -1) {
1790 DBG_WARNING("attributes info type[%u] twice "
1791 "[%zd] and [%zu]: \n",
1792 types[i],
1793 attrs_info_idx,
1795 code = EINVAL;
1796 goto done;
1798 attrs_info_idx = i;
1799 break;
1800 case PAC_TYPE_REQUESTER_SID:
1801 if (requester_sid_idx != -1) {
1802 DBG_WARNING("requester sid type[%u] twice"
1803 "[%zd] and [%zu]: \n",
1804 types[i],
1805 requester_sid_idx,
1807 code = EINVAL;
1808 goto done;
1810 requester_sid_idx = i;
1811 break;
1812 case PAC_TYPE_FULL_CHECKSUM:
1813 if (full_checksum_idx != -1) {
1814 DBG_WARNING("full checksum type[%u] twice "
1815 "[%zd] and [%zu]: \n",
1816 types[i],
1817 full_checksum_idx,
1819 code = EINVAL;
1820 goto done;
1822 full_checksum_idx = i;
1823 break;
1824 default:
1825 continue;
1829 if (logon_info_idx == -1) {
1830 DBG_WARNING("PAC_TYPE_LOGON_INFO missing\n");
1831 code = EINVAL;
1832 goto done;
1834 if (logon_name_idx == -1) {
1835 DBG_WARNING("PAC_TYPE_LOGON_NAME missing\n");
1836 code = EINVAL;
1837 goto done;
1839 if (srv_checksum_idx == -1) {
1840 DBG_WARNING("PAC_TYPE_SRV_CHECKSUM missing\n");
1841 code = EINVAL;
1842 goto done;
1844 if (kdc_checksum_idx == -1) {
1845 DBG_WARNING("PAC_TYPE_KDC_CHECKSUM missing\n");
1846 code = EINVAL;
1847 goto done;
1849 if (!(flags & SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION) &&
1850 requester_sid_idx == -1) {
1851 DBG_WARNING("PAC_TYPE_REQUESTER_SID missing\n");
1852 code = KRB5KDC_ERR_TGT_REVOKED;
1853 goto done;
1857 * The server account may be set not to want the PAC.
1859 * While this is wasteful if the above cacluations were done
1860 * and now thrown away, this is cleaner as we do any ticket
1861 * signature checking etc always.
1863 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
1864 * time (eg not accepting a ticket from the RODC) we do not
1865 * need to re-generate anything anyway.
1867 if (!samba_princ_needs_pac(server)) {
1868 code = ENOATTR;
1869 goto done;
1872 if (is_trusted && !is_tgs) {
1874 * The client may have requested no PAC when obtaining the
1875 * TGT.
1877 bool requested_pac = false;
1879 code = samba_client_requested_pac(context,
1880 old_pac,
1881 mem_ctx,
1882 &requested_pac);
1883 if (code != 0 || !requested_pac) {
1884 if (!requested_pac) {
1885 code = ENOATTR;
1887 goto done;
1891 #define MAX_PAC_BUFFERS 128 /* Avoid infinite loops */
1893 for (i = 0; i < MAX_PAC_BUFFERS;) {
1894 const uint8_t zero_byte = 0;
1895 krb5_data type_data;
1896 DATA_BLOB type_blob = data_blob_null;
1897 uint32_t type;
1899 if (forced_next_type != 0) {
1901 * We need to inject possible missing types
1903 type = forced_next_type;
1904 forced_next_type = 0;
1905 } else if (i < num_types) {
1906 type = types[i];
1907 i++;
1908 } else {
1909 break;
1912 switch (type) {
1913 case PAC_TYPE_LOGON_INFO:
1914 type_blob = *pac_blob;
1916 if (delegation_idx == -1 && deleg_blob != NULL) {
1917 /* inject CONSTRAINED_DELEGATION behind */
1918 forced_next_type =
1919 PAC_TYPE_CONSTRAINED_DELEGATION;
1921 break;
1922 case PAC_TYPE_CONSTRAINED_DELEGATION:
1924 * This is generated in the main KDC code
1926 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1927 continue;
1930 if (deleg_blob != NULL) {
1931 type_blob = *deleg_blob;
1933 break;
1934 case PAC_TYPE_CREDENTIAL_INFO:
1936 * Note that we copy the credential blob,
1937 * as it's only usable with the PKINIT based
1938 * AS-REP reply key, it's only available on the
1939 * host which did the AS-REQ/AS-REP exchange.
1941 * This matches Windows 2008R2...
1943 break;
1944 case PAC_TYPE_LOGON_NAME:
1946 * This is generated in the main KDC code
1948 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1949 continue;
1952 type_blob = data_blob_const(&zero_byte, 1);
1954 if (upn_dns_info_idx == -1 && upn_blob != NULL) {
1955 /* inject UPN_DNS_INFO behind */
1956 forced_next_type = PAC_TYPE_UPN_DNS_INFO;
1958 break;
1959 case PAC_TYPE_UPN_DNS_INFO:
1961 * Replace in the RODC case, otherwise
1962 * upn_blob is NULL and we just copy.
1964 if (upn_blob != NULL) {
1965 type_blob = *upn_blob;
1967 break;
1968 case PAC_TYPE_SRV_CHECKSUM:
1970 * This is generated in the main KDC code
1972 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1973 continue;
1976 type_blob = data_blob_const(&zero_byte, 1);
1978 if (requester_sid_idx == -1 && requester_sid_blob != NULL) {
1979 /* inject REQUESTER_SID behind */
1980 forced_next_type = PAC_TYPE_REQUESTER_SID;
1982 break;
1983 case PAC_TYPE_KDC_CHECKSUM:
1985 * This is generated in the main KDC code
1987 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1988 continue;
1991 type_blob = data_blob_const(&zero_byte, 1);
1993 break;
1994 case PAC_TYPE_TICKET_CHECKSUM:
1996 * This is generated in the main KDC code
1998 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1999 continue;
2002 type_blob = data_blob_const(&zero_byte, 1);
2004 break;
2005 case PAC_TYPE_ATTRIBUTES_INFO:
2006 if (is_trusted && is_tgs) {
2007 /* just copy... */
2008 break;
2011 continue;
2012 case PAC_TYPE_REQUESTER_SID:
2013 if (!is_tgs) {
2014 continue;
2018 * Replace in the RODC case, otherwise
2019 * requester_sid_blob is NULL and we just copy.
2021 if (requester_sid_blob != NULL) {
2022 type_blob = *requester_sid_blob;
2024 break;
2025 case PAC_TYPE_FULL_CHECKSUM:
2027 * This is generated in the main KDC code
2029 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
2030 continue;
2033 type_blob = data_blob_const(&zero_byte, 1);
2035 break;
2036 default:
2037 /* just copy... */
2038 break;
2041 if (type_blob.length != 0) {
2042 code = smb_krb5_copy_data_contents(&type_data,
2043 type_blob.data,
2044 type_blob.length);
2045 if (code != 0) {
2046 goto done;
2048 } else {
2049 code = krb5_pac_get_buffer(context,
2050 old_pac,
2051 type,
2052 &type_data);
2053 if (code != 0) {
2054 goto done;
2058 code = krb5_pac_add_buffer(context,
2059 new_pac,
2060 type,
2061 &type_data);
2062 smb_krb5_free_data_contents(context, &type_data);
2063 if (code != 0) {
2064 goto done;
2068 code = 0;
2069 done:
2070 TALLOC_FREE(pac_blob);
2071 TALLOC_FREE(upn_blob);
2072 TALLOC_FREE(deleg_blob);
2073 SAFE_FREE(types);
2074 return code;