2 Unix SMB/CIFS implementation.
4 PAC Glue between Samba and the KDC
6 Copyright (C) Catalyst.Net Ltd 2023
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "source4/kdc/pac-blobs.h"
24 #include "lib/util/debug.h"
25 #include "lib/util/samba_util.h"
27 static inline size_t *pac_blobs_get_index(struct pac_blobs
*pac_blobs
, size_t type
)
29 /* Ensure the type is valid. */
30 SMB_ASSERT(type
>= PAC_TYPE_BEGIN
);
31 SMB_ASSERT(type
< PAC_TYPE_END
);
33 return &pac_blobs
->type_index
[type
- PAC_TYPE_BEGIN
];
36 static inline struct type_data
*pac_blobs_get(struct pac_blobs
*pac_blobs
, size_t type
)
38 size_t index
= *pac_blobs_get_index(pac_blobs
, type
);
39 SMB_ASSERT(index
< pac_blobs
->num_types
);
41 return &pac_blobs
->type_blobs
[index
];
44 krb5_error_code
pac_blobs_from_krb5_pac(TALLOC_CTX
*mem_ctx
,
46 const krb5_const_pac pac
,
47 struct pac_blobs
**pac_blobs
)
49 krb5_error_code code
= 0;
50 uint32_t *types
= NULL
;
51 struct pac_blobs
*blobs
= NULL
;
54 SMB_ASSERT(pac_blobs
!= NULL
);
57 blobs
= talloc(mem_ctx
, struct pac_blobs
);
63 *blobs
= (struct pac_blobs
) {};
65 /* Initialize the array indices. */
66 for (i
= 0; i
< ARRAY_SIZE(blobs
->type_index
); ++i
) {
67 blobs
->type_index
[i
] = SIZE_MAX
;
70 code
= krb5_pac_get_types(context
, pac
, &blobs
->num_types
, &types
);
72 DBG_ERR("krb5_pac_get_types failed\n");
76 blobs
->type_blobs
= talloc_array(blobs
, struct type_data
, blobs
->num_types
);
77 if (blobs
->type_blobs
== NULL
) {
78 DBG_ERR("Out of memory\n");
83 for (i
= 0; i
< blobs
->num_types
; ++i
) {
84 uint32_t type
= types
[i
];
85 size_t *type_index
= NULL
;
87 blobs
->type_blobs
[i
] = (struct type_data
) {
93 /* PAC buffer types that we support. */
94 case PAC_TYPE_LOGON_INFO
:
95 case PAC_TYPE_CREDENTIAL_INFO
:
96 case PAC_TYPE_SRV_CHECKSUM
:
97 case PAC_TYPE_KDC_CHECKSUM
:
98 case PAC_TYPE_LOGON_NAME
:
99 case PAC_TYPE_CONSTRAINED_DELEGATION
:
100 case PAC_TYPE_UPN_DNS_INFO
:
101 case PAC_TYPE_CLIENT_CLAIMS_INFO
:
102 case PAC_TYPE_DEVICE_INFO
:
103 case PAC_TYPE_DEVICE_CLAIMS_INFO
:
104 case PAC_TYPE_TICKET_CHECKSUM
:
105 case PAC_TYPE_ATTRIBUTES_INFO
:
106 case PAC_TYPE_REQUESTER_SID
:
107 case PAC_TYPE_FULL_CHECKSUM
:
108 type_index
= pac_blobs_get_index(blobs
, type
);
109 if (*type_index
!= SIZE_MAX
) {
110 DBG_WARNING("PAC buffer type[%"PRIu32
"] twice\n", type
);
131 krb5_error_code
_pac_blobs_ensure_exists(struct pac_blobs
*pac_blobs
,
134 const char *location
,
135 const char *function
)
137 if (*pac_blobs_get_index(pac_blobs
, type
) == SIZE_MAX
) {
138 DEBUGLF(DBGLVL_ERR
, ("%s: %s missing\n", function
, name
), location
, function
);
145 krb5_error_code
_pac_blobs_replace_existing(struct pac_blobs
*pac_blobs
,
148 const DATA_BLOB
*blob
,
149 const char *location
,
150 const char *function
)
152 krb5_error_code code
;
154 code
= _pac_blobs_ensure_exists(pac_blobs
,
163 pac_blobs_get(pac_blobs
, type
)->data
= blob
;
168 krb5_error_code
pac_blobs_add_blob(struct pac_blobs
*pac_blobs
,
170 const DATA_BLOB
*blob
)
172 size_t *index
= NULL
;
178 index
= pac_blobs_get_index(pac_blobs
, type
);
179 if (*index
== SIZE_MAX
) {
180 struct type_data
*type_blobs
= NULL
;
182 type_blobs
= talloc_realloc(pac_blobs
,
183 pac_blobs
->type_blobs
,
185 pac_blobs
->num_types
+ 1);
186 if (type_blobs
== NULL
) {
187 DBG_ERR("Out of memory\n");
191 pac_blobs
->type_blobs
= type_blobs
;
192 *index
= pac_blobs
->num_types
++;
195 *pac_blobs_get(pac_blobs
, type
) = (struct type_data
) {
203 void pac_blobs_remove_blob(struct pac_blobs
*pac_blobs
,
206 struct type_data
*type_blobs
= NULL
;
210 /* Get the index of this PAC buffer type. */
211 found_index
= *pac_blobs_get_index(pac_blobs
, type
);
212 if (found_index
== SIZE_MAX
) {
213 /* We don't have a PAC buffer of this type, so we're done. */
217 /* Since the PAC buffer is present, there will be at least one type in the array. */
218 SMB_ASSERT(pac_blobs
->num_types
> 0);
220 /* The index should be valid. */
221 SMB_ASSERT(found_index
< pac_blobs
->num_types
);
224 * Even though a consistent ordering of PAC buffers is not to be relied
225 * upon, we must still maintain the ordering we are given.
227 for (i
= found_index
; i
< pac_blobs
->num_types
- 1; ++i
) {
230 /* Shift each following element backwards by one. */
231 pac_blobs
->type_blobs
[i
] = pac_blobs
->type_blobs
[i
+ 1];
233 /* Mark the new position of the moved element in the index. */
234 moved_type
= pac_blobs
->type_blobs
[i
].type
;
235 if (moved_type
>= PAC_TYPE_BEGIN
&& moved_type
< PAC_TYPE_END
) {
236 *pac_blobs_get_index(pac_blobs
, moved_type
) = i
;
240 /* Mark the removed element as no longer present. */
241 *pac_blobs_get_index(pac_blobs
, type
) = SIZE_MAX
;
243 /* We do not free the removed data blob, as it may be statically allocated (e.g., a null blob). */
245 /* Remove the last element from the array. */
246 type_blobs
= talloc_realloc(pac_blobs
,
247 pac_blobs
->type_blobs
,
249 --pac_blobs
->num_types
);
250 if (type_blobs
!= NULL
) {
251 pac_blobs
->type_blobs
= type_blobs
;