s3:script: Replace --merge by --merge-by-timestamp in samba-log-parser
[Samba.git] / source4 / kdc / pac-blobs.c
blob2c0bce6f7c6008ff455b653c511a539d0b20009f
1 /*
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 void pac_blobs_init(struct pac_blobs *pac_blobs)
29 size_t i;
31 for (i = 0; i < ARRAY_SIZE(pac_blobs->type_index); ++i) {
32 pac_blobs->type_index[i] = SIZE_MAX;
35 pac_blobs->type_blobs = NULL;
36 pac_blobs->num_types = 0;
39 void pac_blobs_destroy(struct pac_blobs *pac_blobs)
41 TALLOC_FREE(pac_blobs->type_blobs);
44 static inline size_t *pac_blobs_get_index(struct pac_blobs *pac_blobs, size_t type)
46 /* Ensure the type is valid. */
47 SMB_ASSERT(type >= PAC_TYPE_BEGIN);
48 SMB_ASSERT(type < PAC_TYPE_END);
50 return &pac_blobs->type_index[type - PAC_TYPE_BEGIN];
53 static inline struct type_data *pac_blobs_get(struct pac_blobs *pac_blobs, size_t type)
55 size_t index = *pac_blobs_get_index(pac_blobs, type);
56 SMB_ASSERT(index < pac_blobs->num_types);
58 return &pac_blobs->type_blobs[index];
61 krb5_error_code pac_blobs_from_krb5_pac(struct pac_blobs *pac_blobs,
62 TALLOC_CTX *mem_ctx,
63 krb5_context context,
64 const krb5_const_pac pac)
66 krb5_error_code code;
67 uint32_t *types = NULL;
68 size_t i;
70 code = krb5_pac_get_types(context, pac, &pac_blobs->num_types, &types);
71 if (code != 0) {
72 DBG_ERR("krb5_pac_get_types failed\n");
73 return code;
76 pac_blobs->type_blobs = talloc_array(mem_ctx, struct type_data, pac_blobs->num_types);
77 if (pac_blobs->type_blobs == NULL) {
78 DBG_ERR("Out of memory\n");
79 SAFE_FREE(types);
80 return ENOMEM;
83 for (i = 0; i < pac_blobs->num_types; ++i) {
84 uint32_t type = types[i];
85 size_t *type_index = NULL;
87 pac_blobs->type_blobs[i] = (struct type_data) {
88 .type = type,
89 .data = NULL,
92 switch (type) {
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(pac_blobs, type);
109 if (*type_index != SIZE_MAX) {
110 DBG_WARNING("PAC buffer type[%"PRIu32"] twice\n", type);
111 pac_blobs_destroy(pac_blobs);
112 SAFE_FREE(types);
113 return EINVAL;
115 *type_index = i;
117 break;
118 default:
119 break;
123 SAFE_FREE(types);
124 return 0;
127 krb5_error_code _pac_blobs_ensure_exists(struct pac_blobs *pac_blobs,
128 const uint32_t type,
129 const char *name,
130 const char *location,
131 const char *function)
133 if (*pac_blobs_get_index(pac_blobs, type) == SIZE_MAX) {
134 DEBUGLF(DBGLVL_ERR, ("%s: %s missing\n", function, name), location, function);
135 return EINVAL;
138 return 0;
141 krb5_error_code _pac_blobs_replace_existing(struct pac_blobs *pac_blobs,
142 const uint32_t type,
143 const char *name,
144 const DATA_BLOB *blob,
145 const char *location,
146 const char *function)
148 krb5_error_code code;
150 code = _pac_blobs_ensure_exists(pac_blobs,
151 type,
152 name,
153 location,
154 function);
155 if (code != 0) {
156 return code;
159 pac_blobs_get(pac_blobs, type)->data = blob;
161 return 0;
164 krb5_error_code pac_blobs_add_blob(struct pac_blobs *pac_blobs,
165 TALLOC_CTX *mem_ctx,
166 const uint32_t type,
167 const DATA_BLOB *blob)
169 size_t *index = NULL;
171 if (blob == NULL) {
172 return 0;
175 index = pac_blobs_get_index(pac_blobs, type);
176 if (*index == SIZE_MAX) {
177 pac_blobs->type_blobs = talloc_realloc(mem_ctx,
178 pac_blobs->type_blobs,
179 struct type_data,
180 pac_blobs->num_types + 1);
181 if (pac_blobs->type_blobs == NULL) {
182 DBG_ERR("Out of memory\n");
183 return ENOMEM;
186 *index = pac_blobs->num_types++;
189 *pac_blobs_get(pac_blobs, type) = (struct type_data) {
190 .type = type,
191 .data = blob,
194 return 0;
197 krb5_error_code pac_blobs_remove_blob(struct pac_blobs *pac_blobs,
198 TALLOC_CTX *mem_ctx,
199 const uint32_t type)
201 size_t found_index;
202 size_t i;
204 /* Get the index of this PAC buffer type. */
205 found_index = *pac_blobs_get_index(pac_blobs, type);
206 if (found_index == SIZE_MAX) {
207 /* We don't have a PAC buffer of this type, so we're done. */
208 return 0;
211 /* Since the PAC buffer is present, there will be at least one type in the array. */
212 SMB_ASSERT(pac_blobs->num_types > 0);
214 /* The index should be valid. */
215 SMB_ASSERT(found_index < pac_blobs->num_types);
218 * Even though a consistent ordering of PAC buffers is not to be relied
219 * upon, we must still maintain the ordering we are given.
221 for (i = found_index; i < pac_blobs->num_types - 1; ++i) {
222 size_t moved_type;
224 /* Shift each following element backwards by one. */
225 pac_blobs->type_blobs[i] = pac_blobs->type_blobs[i + 1];
227 /* Mark the new position of the moved element in the index. */
228 moved_type = pac_blobs->type_blobs[i].type;
229 if (moved_type >= PAC_TYPE_BEGIN && moved_type < PAC_TYPE_END) {
230 *pac_blobs_get_index(pac_blobs, moved_type) = i;
234 /* Mark the removed element as no longer present. */
235 *pac_blobs_get_index(pac_blobs, type) = SIZE_MAX;
237 /* We do not free the removed data blob, as it may be statically allocated (e.g., a null blob). */
239 /* Remove the last element from the array. */
240 pac_blobs->type_blobs = talloc_realloc(mem_ctx,
241 pac_blobs->type_blobs,
242 struct type_data,
243 --pac_blobs->num_types);
244 if (pac_blobs->type_blobs == NULL) {
245 DBG_ERR("Out of memory\n");
246 return ENOMEM;
249 return 0;