Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : PAC Glue between Samba and the KDC
5 :
6 : Copyright (C) Catalyst.Net Ltd 2023
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "source4/kdc/pac-blobs.h"
23 :
24 : #include "lib/util/debug.h"
25 : #include "lib/util/samba_util.h"
26 :
27 1619884 : static inline size_t *pac_blobs_get_index(struct pac_blobs *pac_blobs, size_t type)
28 : {
29 : /* Ensure the type is valid. */
30 1619884 : SMB_ASSERT(type >= PAC_TYPE_BEGIN);
31 1619884 : SMB_ASSERT(type < PAC_TYPE_END);
32 :
33 1619884 : return &pac_blobs->type_index[type - PAC_TYPE_BEGIN];
34 : }
35 :
36 195181 : static inline struct type_data *pac_blobs_get(struct pac_blobs *pac_blobs, size_t type)
37 : {
38 195181 : size_t index = *pac_blobs_get_index(pac_blobs, type);
39 195181 : SMB_ASSERT(index < pac_blobs->num_types);
40 :
41 195181 : return &pac_blobs->type_blobs[index];
42 : }
43 :
44 99088 : krb5_error_code pac_blobs_from_krb5_pac(TALLOC_CTX *mem_ctx,
45 : krb5_context context,
46 : const krb5_const_pac pac,
47 : struct pac_blobs **pac_blobs)
48 : {
49 99088 : krb5_error_code code = 0;
50 99088 : uint32_t *types = NULL;
51 99088 : struct pac_blobs *blobs = NULL;
52 3316 : size_t i;
53 :
54 99088 : SMB_ASSERT(pac_blobs != NULL);
55 99088 : *pac_blobs = NULL;
56 :
57 99088 : blobs = talloc(mem_ctx, struct pac_blobs);
58 99088 : if (blobs == NULL) {
59 0 : code = ENOMEM;
60 0 : goto out;
61 : }
62 :
63 99088 : *blobs = (struct pac_blobs) {};
64 :
65 : /* Initialize the array indices. */
66 1981760 : for (i = 0; i < ARRAY_SIZE(blobs->type_index); ++i) {
67 1882672 : blobs->type_index[i] = SIZE_MAX;
68 : }
69 :
70 99088 : code = krb5_pac_get_types(context, pac, &blobs->num_types, &types);
71 99088 : if (code != 0) {
72 0 : DBG_ERR("krb5_pac_get_types failed\n");
73 0 : goto out;
74 : }
75 :
76 99088 : blobs->type_blobs = talloc_array(blobs, struct type_data, blobs->num_types);
77 99088 : if (blobs->type_blobs == NULL) {
78 0 : DBG_ERR("Out of memory\n");
79 0 : code = ENOMEM;
80 0 : goto out;
81 : }
82 :
83 891958 : for (i = 0; i < blobs->num_types; ++i) {
84 792870 : uint32_t type = types[i];
85 792870 : size_t *type_index = NULL;
86 :
87 792870 : blobs->type_blobs[i] = (struct type_data) {
88 : .type = type,
89 : .data = NULL,
90 : };
91 :
92 792870 : switch (type) {
93 : /* PAC buffer types that we support. */
94 792858 : 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 792858 : type_index = pac_blobs_get_index(blobs, type);
109 792858 : if (*type_index != SIZE_MAX) {
110 0 : DBG_WARNING("PAC buffer type[%"PRIu32"] twice\n", type);
111 0 : code = EINVAL;
112 0 : goto out;
113 : }
114 792858 : *type_index = i;
115 :
116 792858 : break;
117 12 : default:
118 12 : break;
119 : }
120 : }
121 :
122 99088 : *pac_blobs = blobs;
123 99088 : blobs = NULL;
124 :
125 99088 : out:
126 99088 : SAFE_FREE(types);
127 99088 : TALLOC_FREE(blobs);
128 99088 : return code;
129 : }
130 :
131 446636 : krb5_error_code _pac_blobs_ensure_exists(struct pac_blobs *pac_blobs,
132 : const uint32_t type,
133 : const char *name,
134 : const char *location,
135 : const char *function)
136 : {
137 446636 : if (*pac_blobs_get_index(pac_blobs, type) == SIZE_MAX) {
138 6 : DEBUGLF(DBGLVL_ERR, ("%s: %s missing\n", function, name), location, function);
139 6 : return EINVAL;
140 : }
141 :
142 431708 : return 0;
143 : }
144 :
145 194596 : krb5_error_code _pac_blobs_replace_existing(struct pac_blobs *pac_blobs,
146 : const uint32_t type,
147 : const char *name,
148 : const DATA_BLOB *blob,
149 : const char *location,
150 : const char *function)
151 : {
152 6632 : krb5_error_code code;
153 :
154 194596 : code = _pac_blobs_ensure_exists(pac_blobs,
155 : type,
156 : name,
157 : location,
158 : function);
159 194596 : if (code != 0) {
160 0 : return code;
161 : }
162 :
163 194596 : pac_blobs_get(pac_blobs, type)->data = blob;
164 :
165 194596 : return 0;
166 : }
167 :
168 291894 : krb5_error_code pac_blobs_add_blob(struct pac_blobs *pac_blobs,
169 : const uint32_t type,
170 : const DATA_BLOB *blob)
171 : {
172 291894 : size_t *index = NULL;
173 :
174 291894 : if (blob == NULL) {
175 281361 : return 0;
176 : }
177 :
178 585 : index = pac_blobs_get_index(pac_blobs, type);
179 585 : if (*index == SIZE_MAX) {
180 261 : struct type_data *type_blobs = NULL;
181 :
182 261 : type_blobs = talloc_realloc(pac_blobs,
183 : pac_blobs->type_blobs,
184 : struct type_data,
185 : pac_blobs->num_types + 1);
186 261 : if (type_blobs == NULL) {
187 0 : DBG_ERR("Out of memory\n");
188 0 : return ENOMEM;
189 : }
190 :
191 261 : pac_blobs->type_blobs = type_blobs;
192 261 : *index = pac_blobs->num_types++;
193 : }
194 :
195 585 : *pac_blobs_get(pac_blobs, type) = (struct type_data) {
196 : .type = type,
197 : .data = blob,
198 : };
199 :
200 585 : return 0;
201 : }
202 :
203 41178 : void pac_blobs_remove_blob(struct pac_blobs *pac_blobs,
204 : const uint32_t type)
205 : {
206 41178 : struct type_data *type_blobs = NULL;
207 1246 : size_t found_index;
208 1246 : size_t i;
209 :
210 : /* Get the index of this PAC buffer type. */
211 41178 : found_index = *pac_blobs_get_index(pac_blobs, type);
212 41178 : if (found_index == SIZE_MAX) {
213 : /* We don't have a PAC buffer of this type, so we're done. */
214 292 : return;
215 : }
216 :
217 : /* Since the PAC buffer is present, there will be at least one type in the array. */
218 40886 : SMB_ASSERT(pac_blobs->num_types > 0);
219 :
220 : /* The index should be valid. */
221 40886 : SMB_ASSERT(found_index < pac_blobs->num_types);
222 :
223 : /*
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.
226 : */
227 143458 : for (i = found_index; i < pac_blobs->num_types - 1; ++i) {
228 3115 : size_t moved_type;
229 :
230 : /* Shift each following element backwards by one. */
231 102572 : pac_blobs->type_blobs[i] = pac_blobs->type_blobs[i + 1];
232 :
233 : /* Mark the new position of the moved element in the index. */
234 102572 : moved_type = pac_blobs->type_blobs[i].type;
235 102572 : if (moved_type >= PAC_TYPE_BEGIN && moved_type < PAC_TYPE_END) {
236 102560 : *pac_blobs_get_index(pac_blobs, moved_type) = i;
237 : }
238 : }
239 :
240 : /* Mark the removed element as no longer present. */
241 40886 : *pac_blobs_get_index(pac_blobs, type) = SIZE_MAX;
242 :
243 : /* We do not free the removed data blob, as it may be statically allocated (e.g., a null blob). */
244 :
245 : /* Remove the last element from the array. */
246 40886 : type_blobs = talloc_realloc(pac_blobs,
247 : pac_blobs->type_blobs,
248 : struct type_data,
249 : --pac_blobs->num_types);
250 40886 : if (type_blobs != NULL) {
251 40886 : pac_blobs->type_blobs = type_blobs;
252 : }
253 : }
|