Line data Source code
1 : /*
2 : * Unix SMB implementation.
3 : * Utility functions for converting between claims formats.
4 : *
5 : * This program is free software; you can redistribute it and/or modify
6 : * it under the terms of the GNU General Public License as published by
7 : * the Free Software Foundation; either version 3 of the License, or
8 : * (at your option) any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 : */
18 :
19 : #include "replace.h"
20 : #include "librpc/gen_ndr/ndr_security.h"
21 : #include "librpc/gen_ndr/ndr_conditional_ace.h"
22 : #include "libcli/security/security.h"
23 : #include "libcli/security/conditional_ace.h"
24 : #include "libcli/security/claims-conversions.h"
25 : #include "lib/util/tsort.h"
26 : #include "lib/util/debug.h"
27 : #include "lib/util/bytearray.h"
28 :
29 : #include "librpc/gen_ndr/conditional_ace.h"
30 : #include "librpc/gen_ndr/claims.h"
31 :
32 : /*
33 : * We support three formats for claims, all slightly different.
34 : *
35 : * 1. MS-ADTS 2.2.18.* claims sets, blobs, arrays, or whatever, which
36 : * are used in the PAC.
37 : *
38 : * 2. MS-DTYP 2.4.10.1 CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1
39 : * structures, used in security tokens and resource SACL ACEs.
40 : *
41 : * 3. MS-DTYP 2.4.4.17 Conditional ACE tokens.
42 : *
43 : * The types don't map perfectly onto each other -- in particular,
44 : * Conditional ACEs don't have unsigned integer or boolean types, but
45 : * do have short integer types which the other forms don't.
46 : *
47 : * We don't support the format used by the Win32 API function
48 : * AddResourceAttributeAce(), which is called CLAIM_SECURITY_ATTRIBUTE_V1.
49 : * Nobody has ever used that function in public, and the format is not used
50 : * on the wire.
51 : */
52 :
53 :
54 513 : static bool claim_v1_string_to_ace_string(
55 : TALLOC_CTX *mem_ctx,
56 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
57 : size_t offset,
58 : struct ace_condition_token *result)
59 : {
60 605 : char *s = talloc_strdup(mem_ctx,
61 513 : claim->values[offset].string_value);
62 513 : if (s == NULL) {
63 0 : return false;
64 : }
65 :
66 513 : result->type = CONDITIONAL_ACE_TOKEN_UNICODE;
67 513 : result->data.unicode.value = s;
68 513 : return true;
69 : }
70 :
71 :
72 6 : static bool claim_v1_octet_string_to_ace_octet_string(
73 : TALLOC_CTX *mem_ctx,
74 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
75 : size_t offset,
76 : struct ace_condition_token *result)
77 : {
78 6 : DATA_BLOB *v = NULL;
79 6 : DATA_BLOB w = data_blob_null;
80 :
81 6 : v = claim->values[offset].octet_value;
82 :
83 6 : if (v->length > CONDITIONAL_ACE_MAX_LENGTH) {
84 0 : DBG_WARNING("claim has octet string of unexpected length %zu "
85 : "(expected range 1 - %u)\n",
86 : v->length, CONDITIONAL_ACE_MAX_LENGTH);
87 0 : return false;
88 : }
89 6 : if (v->length != 0) {
90 6 : w = data_blob_talloc(mem_ctx, v->data, v->length);
91 6 : if (w.data == NULL) {
92 0 : return false;
93 : }
94 : }
95 :
96 6 : result->type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
97 6 : result->data.bytes = w;
98 6 : return true;
99 : }
100 :
101 :
102 6 : static bool claim_v1_sid_to_ace_sid(
103 : TALLOC_CTX *mem_ctx,
104 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
105 : size_t offset,
106 : struct ace_condition_token *result)
107 : {
108 : /*
109 : * In the _V1 struct, SIDs are stored as octet string blobs,
110 : * as *SID strings*.
111 : *
112 : * In the conditional ACE they are stored as struct dom_sid.
113 : *
114 : * There are no SIDs in ADTS claims, but there can be in
115 : * resource ACEs.
116 : */
117 6 : struct dom_sid *sid = NULL;
118 6 : DATA_BLOB *v = NULL;
119 :
120 6 : v = claim->values[offset].sid_value;
121 :
122 6 : if (v->length == 0 || v->length > CONDITIONAL_ACE_MAX_LENGTH) {
123 0 : DBG_WARNING("claim has SID string of unexpected length %zu, "
124 : "(expected range 1 - %u)\n",
125 : v->length, CONDITIONAL_ACE_MAX_LENGTH);
126 0 : return false;
127 : }
128 :
129 6 : sid = dom_sid_parse_length(mem_ctx, v);
130 6 : if (sid == NULL) {
131 0 : DBG_WARNING("claim has invalid SID string of length %zu.\n",
132 : v->length);
133 0 : return false;
134 : }
135 :
136 6 : result->type = CONDITIONAL_ACE_TOKEN_SID;
137 6 : result->data.sid.sid = *sid;
138 6 : return true;
139 : }
140 :
141 :
142 13 : static bool claim_v1_int_to_ace_int(
143 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
144 : size_t offset,
145 : struct ace_condition_token *result)
146 : {
147 13 : int64_t v = *claim->values[offset].int_value;
148 13 : result->type = CONDITIONAL_ACE_TOKEN_INT64;
149 13 : result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
150 13 : result->data.int64.value = v;
151 :
152 : /*
153 : * The sign flag (and the base flag above) determines how the
154 : * ACE token will be displayed if converted to SDDL. These
155 : * values are not likely to end up as SDDL, but we might as
156 : * well get it right. A negative flag means it will be
157 : * displayed with a minus sign, and a positive flag means a
158 : * plus sign is shown. The none flag means no + or -.
159 : */
160 13 : if (v < 0) {
161 0 : result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NEGATIVE;
162 : } else {
163 13 : result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
164 : }
165 :
166 11 : return true;
167 : }
168 :
169 :
170 26 : static bool claim_v1_unsigned_int_to_ace_int(
171 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
172 : size_t offset,
173 : struct ace_condition_token *result)
174 : {
175 26 : uint64_t v = *claim->values[offset].uint_value;
176 26 : if (v > INT64_MAX) {
177 : /*
178 : * The unsigned value can't be represented in a
179 : * conditional ACE type.
180 : *
181 : * XXX or can it? does the positive flag make it
182 : * unsigned?
183 : */
184 0 : return false;
185 : }
186 26 : result->type = CONDITIONAL_ACE_TOKEN_INT64;
187 26 : result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
188 26 : result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_POSITIVE;
189 26 : result->data.int64.value = v;
190 26 : return true;
191 : }
192 :
193 :
194 56 : static bool claim_v1_bool_to_ace_int(
195 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
196 : size_t offset,
197 : struct ace_condition_token *result)
198 : {
199 56 : uint64_t v = *claim->values[offset].uint_value;
200 56 : result->type = CONDITIONAL_ACE_TOKEN_INT64;
201 56 : result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
202 56 : result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
203 56 : result->data.int64.value = v ? 1 : 0;
204 56 : return true;
205 : }
206 :
207 :
208 620 : static bool claim_v1_offset_to_ace_token(
209 : TALLOC_CTX *mem_ctx,
210 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
211 : size_t offset,
212 : struct ace_condition_token *result)
213 : {
214 : /*
215 : * A claim structure has an array of claims of a certain type,
216 : * and this converts a single one into a conditional ACE token.
217 : *
218 : * For example, if offset is 3, claim->values[3] will be
219 : * turned into *result.
220 : *
221 : * conditional ace token will have flags to indicate that it
222 : * comes from a claim attribute, and whether or not that
223 : * attribute should be compared case-sensitively (only
224 : * affecting unicode strings).
225 : *
226 : * The CLAIM_SECURITY_ATTRIBUTE_CASE_SENSITIVE (from the
227 : * claim_flags enum in security.idl) is used for both.
228 : */
229 620 : uint8_t f = claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
230 620 : result->flags = f | CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR;
231 :
232 620 : switch (claim->value_type) {
233 11 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
234 13 : return claim_v1_int_to_ace_int(claim, offset, result);
235 25 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
236 26 : return claim_v1_unsigned_int_to_ace_int(claim, offset, result);
237 421 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
238 513 : return claim_v1_string_to_ace_string(mem_ctx, claim, offset,
239 : result);
240 6 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
241 6 : return claim_v1_sid_to_ace_sid(mem_ctx, claim, offset, result);
242 56 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
243 56 : return claim_v1_bool_to_ace_int(claim, offset, result);
244 6 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
245 6 : return claim_v1_octet_string_to_ace_octet_string(mem_ctx,
246 : claim,
247 : offset,
248 : result);
249 0 : default:
250 0 : return false;
251 : }
252 : }
253 :
254 :
255 452 : bool claim_v1_to_ace_token(TALLOC_CTX *mem_ctx,
256 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
257 : struct ace_condition_token *result)
258 : {
259 61 : size_t i;
260 452 : struct ace_condition_token *tokens = NULL;
261 452 : if (claim->value_count < 1 ||
262 385 : claim->value_count >= CONDITIONAL_ACE_MAX_TOKENS) {
263 7 : return false;
264 : }
265 : /*
266 : * if there is one, we return a single thing of that type; if
267 : * there are many, we return a composite.
268 : */
269 :
270 445 : if (claim->value_count == 1) {
271 296 : return claim_v1_offset_to_ace_token(mem_ctx,
272 : claim,
273 : 0,
274 : result);
275 : }
276 : /*
277 : * The multiple values will get turned into a composite
278 : * literal in the conditional ACE. Each element of the
279 : * composite will have flags set by
280 : * claim_v1_offset_to_ace_token(), but they also need to be
281 : * set here (at least the _FROM_ATTR flag) or the child values
282 : * will not be reached.
283 : */
284 :
285 149 : result->flags = (
286 149 : CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR |
287 149 : (claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE));
288 :
289 149 : tokens = talloc_array(mem_ctx,
290 : struct ace_condition_token,
291 : claim->value_count);
292 149 : if (tokens == NULL) {
293 0 : return false;
294 : }
295 :
296 473 : for (i = 0; i < claim->value_count; i++) {
297 408 : bool ok = claim_v1_offset_to_ace_token(tokens,
298 : claim,
299 : i,
300 324 : &tokens[i]);
301 324 : if (! ok) {
302 0 : TALLOC_FREE(tokens);
303 0 : return false;
304 : }
305 : }
306 :
307 149 : result->type = CONDITIONAL_ACE_TOKEN_COMPOSITE;
308 149 : result->data.composite.tokens = tokens;
309 149 : result->data.composite.n_members = claim->value_count;
310 :
311 149 : return true;
312 : }
313 :
314 :
315 :
316 478 : static bool ace_int_to_claim_v1_int(TALLOC_CTX *mem_ctx,
317 : const struct ace_condition_token *tok,
318 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
319 : size_t offset)
320 : {
321 956 : int64_t *v = talloc(mem_ctx, int64_t);
322 478 : if (v == NULL) {
323 0 : return false;
324 : }
325 478 : *v = tok->data.int64.value;
326 478 : claim->values[offset].int_value = v;
327 478 : return true;
328 : }
329 :
330 :
331 109 : static bool ace_string_to_claim_v1_string(TALLOC_CTX *mem_ctx,
332 : const struct ace_condition_token *tok,
333 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
334 : size_t offset)
335 : {
336 218 : const char *s = talloc_strdup(mem_ctx,
337 109 : tok->data.unicode.value);
338 109 : if (s == NULL) {
339 0 : return false;
340 : }
341 109 : claim->values[offset].string_value = s;
342 109 : return true;
343 :
344 : }
345 :
346 :
347 6 : static bool ace_sid_to_claim_v1_sid(TALLOC_CTX *mem_ctx,
348 : const struct ace_condition_token *tok,
349 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
350 : size_t offset)
351 : {
352 : /* claim_v1 sid is an "S-1-*" string data blob, not struct dom_sid. */
353 6 : char *s = NULL;
354 :
355 6 : DATA_BLOB *blob = NULL;
356 6 : blob = talloc(mem_ctx, DATA_BLOB);
357 6 : if (blob == NULL) {
358 0 : return false;
359 : }
360 6 : s = dom_sid_string(blob, &tok->data.sid.sid);
361 6 : if (s == NULL) {
362 0 : TALLOC_FREE(blob);
363 0 : return false;
364 : }
365 6 : *blob = data_blob_string_const(s);
366 6 : claim->values[offset].sid_value = blob;
367 6 : return true;
368 : }
369 :
370 45 : static bool ace_octet_string_to_claim_v1_octet_string(
371 : TALLOC_CTX *mem_ctx,
372 : const struct ace_condition_token *tok,
373 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
374 : size_t offset)
375 : {
376 45 : DATA_BLOB *v = talloc(mem_ctx, DATA_BLOB);
377 45 : if (v == NULL) {
378 0 : return false;
379 : }
380 :
381 45 : *v = data_blob_talloc(v,
382 : tok->data.bytes.data,
383 : tok->data.bytes.length);
384 45 : if (v->data == NULL) {
385 0 : return false;
386 : }
387 :
388 45 : claim->values[offset].octet_value = v;
389 45 : return true;
390 : }
391 :
392 :
393 :
394 638 : static bool ace_token_to_claim_v1_offset(TALLOC_CTX *mem_ctx,
395 : const struct ace_condition_token *tok,
396 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
397 : size_t offset)
398 : {
399 : /*
400 : * A claim structure has an array of claims of a certain type,
401 : * and this converts a single one into a conditional ACE token.
402 : *
403 : * For example, if offset is 3, claim->values[3] will be
404 : * turned into *result.
405 : */
406 638 : if (offset >= claim->value_count) {
407 0 : return false;
408 : }
409 638 : switch (claim->value_type) {
410 0 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
411 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
412 478 : return ace_int_to_claim_v1_int(mem_ctx, tok, claim, offset);
413 0 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
414 109 : return ace_string_to_claim_v1_string(mem_ctx, tok, claim, offset);
415 6 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
416 6 : return ace_sid_to_claim_v1_sid(mem_ctx, tok, claim, offset);
417 45 : case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
418 45 : return ace_octet_string_to_claim_v1_octet_string(mem_ctx,
419 : tok,
420 : claim,
421 : offset);
422 0 : default:
423 : /*bool unimplemented, because unreachable */
424 0 : return false;
425 : }
426 : }
427 :
428 :
429 125 : bool ace_token_to_claim_v1(TALLOC_CTX *mem_ctx,
430 : const char *name,
431 : const struct ace_condition_token *tok,
432 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **claim,
433 : uint32_t flags)
434 : {
435 125 : size_t i;
436 125 : bool ok;
437 125 : bool is_comp = false;
438 125 : int claim_type = -1;
439 125 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *_claim = NULL;
440 125 : uint32_t value_count;
441 :
442 125 : if (name == NULL || claim == NULL || tok == NULL) {
443 0 : return false;
444 : }
445 125 : *claim = NULL;
446 :
447 125 : if (tok->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
448 82 : is_comp = true;
449 : /* there must be values, all of the same type */
450 82 : if (tok->data.composite.n_members == 0) {
451 0 : DBG_WARNING("Empty ACE composite list\n");
452 0 : return false;
453 : }
454 82 : if (tok->data.composite.n_members > 1) {
455 595 : for (i = 1; i < tok->data.composite.n_members; i++) {
456 513 : if (tok->data.composite.tokens[i].type !=
457 513 : tok->data.composite.tokens[0].type) {
458 0 : DBG_WARNING(
459 : "ACE composite list has varying "
460 : "types (at least %u and %u)\n",
461 : tok->data.composite.tokens[i].type,
462 : tok->data.composite.tokens[0].type);
463 0 : return false;
464 : }
465 : }
466 : }
467 82 : value_count = tok->data.composite.n_members;
468 :
469 82 : switch (tok->data.composite.tokens[0].type) {
470 0 : case CONDITIONAL_ACE_TOKEN_INT8:
471 : case CONDITIONAL_ACE_TOKEN_INT16:
472 : case CONDITIONAL_ACE_TOKEN_INT32:
473 : case CONDITIONAL_ACE_TOKEN_INT64:
474 0 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
475 0 : break;
476 40 : case CONDITIONAL_ACE_TOKEN_UNICODE:
477 40 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
478 40 : break;
479 2 : case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
480 2 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
481 2 : break;
482 2 : case CONDITIONAL_ACE_TOKEN_SID:
483 2 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
484 2 : break;
485 0 : default:
486 : /* reject nested composites, no uint or bool. */
487 0 : DBG_WARNING("ACE composite list has invalid type %u\n",
488 : tok->data.composite.tokens[0].type);
489 0 : return false;
490 : }
491 : } else {
492 43 : value_count = 1;
493 43 : switch(tok->type) {
494 0 : case CONDITIONAL_ACE_TOKEN_INT8:
495 : case CONDITIONAL_ACE_TOKEN_INT16:
496 : case CONDITIONAL_ACE_TOKEN_INT32:
497 : case CONDITIONAL_ACE_TOKEN_INT64:
498 0 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
499 0 : break;
500 21 : case CONDITIONAL_ACE_TOKEN_UNICODE:
501 21 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
502 21 : break;
503 1 : case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
504 1 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
505 1 : break;
506 0 : case CONDITIONAL_ACE_TOKEN_SID:
507 0 : claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
508 0 : break;
509 0 : default:
510 : /*
511 : * no way of creating bool or uint values,
512 : * composite is handled above.
513 : */
514 0 : DBG_WARNING("ACE token has invalid type %u\n",
515 : tok->data.composite.tokens[0].type);
516 0 : return false;
517 : }
518 : }
519 :
520 125 : _claim = talloc(mem_ctx, struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
521 125 : if (_claim == NULL) {
522 0 : return false;
523 : }
524 :
525 125 : _claim->value_count = value_count;
526 125 : _claim->value_type = claim_type;
527 125 : _claim->flags = flags;
528 125 : _claim->name = talloc_strdup(mem_ctx, name);
529 125 : if (_claim->name == NULL) {
530 0 : TALLOC_FREE(_claim);
531 0 : return false;
532 : }
533 : /*
534 : * The values array is actually an array of pointers to
535 : * values, even when the values are ints or bools.
536 : */
537 125 : _claim->values = talloc_array(_claim, union claim_values, value_count);
538 125 : if (_claim->values == NULL) {
539 0 : TALLOC_FREE(_claim);
540 0 : return false;
541 : }
542 125 : if (! is_comp) {
543 : /* there is one value, not a list */
544 43 : ok = ace_token_to_claim_v1_offset(_claim,
545 : tok,
546 : _claim,
547 : 0);
548 43 : if (! ok) {
549 0 : TALLOC_FREE(_claim);
550 0 : return false;
551 : }
552 : } else {
553 : /* a composite list of values */
554 677 : for (i = 0; i < value_count; i++) {
555 595 : struct ace_condition_token *t = &tok->data.composite.tokens[i];
556 595 : ok = ace_token_to_claim_v1_offset(mem_ctx,
557 : t,
558 : _claim,
559 : i);
560 595 : if (! ok) {
561 0 : TALLOC_FREE(_claim);
562 0 : return false;
563 : }
564 : }
565 : }
566 :
567 :
568 125 : if (_claim->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64) {
569 : /*
570 : * Conditional ACE tokens don't have a UINT type but
571 : * claims do. Windows tends to use UINT types in
572 : * claims when it can, so so do we.
573 : */
574 427 : bool could_be_uint = true;
575 427 : for (i = 0; i < value_count; i++) {
576 374 : if (*_claim->values[i].int_value < 0) {
577 0 : could_be_uint = false;
578 0 : break;
579 : }
580 : }
581 59 : if (could_be_uint) {
582 53 : _claim->value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64;
583 : }
584 : }
585 :
586 125 : *claim = _claim;
587 125 : return true;
588 : }
589 :
590 :
591 :
592 36 : static bool claim_v1_copy(
593 : TALLOC_CTX *mem_ctx,
594 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *dest,
595 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *src)
596 : {
597 36 : DATA_BLOB blob = {0};
598 36 : enum ndr_err_code ndr_err;
599 :
600 : /*
601 : * FIXME, could be more efficient! but copying these
602 : * structures is fiddly, and it might be worth coming up
603 : * with a better API for adding claims.
604 : */
605 :
606 36 : ndr_err = ndr_push_struct_blob(
607 : &blob, mem_ctx, src,
608 : (ndr_push_flags_fn_t)ndr_push_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
609 :
610 36 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
611 0 : return false;
612 : }
613 :
614 36 : ndr_err = ndr_pull_struct_blob(
615 : &blob, mem_ctx, dest,
616 : (ndr_pull_flags_fn_t)ndr_pull_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
617 :
618 36 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
619 0 : TALLOC_FREE(blob.data);
620 0 : return false;
621 : }
622 36 : TALLOC_FREE(blob.data);
623 0 : return true;
624 : }
625 :
626 :
627 :
628 36 : bool add_claim_to_token(TALLOC_CTX *mem_ctx,
629 : struct security_token *token,
630 : const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
631 : const char *claim_type)
632 : {
633 36 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *tmp = NULL;
634 36 : uint32_t *n = NULL;
635 36 : bool ok;
636 36 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **list = NULL;
637 36 : if (strcmp(claim_type, "device") == 0) {
638 34 : n = &token->num_device_claims;
639 34 : list = &token->device_claims;
640 2 : } else if (strcmp(claim_type, "local") == 0) {
641 0 : n = &token->num_local_claims;
642 0 : list = &token->local_claims;
643 2 : } else if (strcmp(claim_type, "user") == 0) {
644 2 : n = &token->num_user_claims;
645 2 : list = &token->user_claims;
646 : } else {
647 0 : return false;
648 : }
649 36 : if ((*n) == UINT32_MAX) {
650 0 : return false;
651 : }
652 :
653 36 : tmp = talloc_realloc(mem_ctx,
654 : *list,
655 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
656 : (*n) + 1);
657 36 : if (tmp == NULL) {
658 0 : return false;
659 : }
660 :
661 36 : ok = claim_v1_copy(mem_ctx, &tmp[*n], claim);
662 36 : if (! ok ) {
663 0 : return false;
664 : }
665 36 : (*n)++;
666 36 : *list = tmp;
667 36 : return true;
668 : }
669 :
670 292 : NTSTATUS token_claims_to_claims_v1(TALLOC_CTX *mem_ctx,
671 : const struct CLAIMS_SET *claims_set,
672 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **out_claims,
673 : uint32_t *out_n_claims)
674 : {
675 292 : TALLOC_CTX *tmp_ctx = NULL;
676 292 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
677 292 : uint32_t n_claims = 0;
678 0 : uint32_t i;
679 :
680 292 : if (out_claims == NULL) {
681 0 : return NT_STATUS_INVALID_PARAMETER;
682 : }
683 292 : if (out_n_claims == NULL) {
684 0 : return NT_STATUS_INVALID_PARAMETER;
685 : }
686 :
687 292 : *out_claims = NULL;
688 292 : *out_n_claims = 0;
689 :
690 292 : if (claims_set == NULL) {
691 0 : return NT_STATUS_OK;
692 : }
693 :
694 292 : tmp_ctx = talloc_new(mem_ctx);
695 292 : if (tmp_ctx == NULL) {
696 0 : return NT_STATUS_NO_MEMORY;
697 : }
698 :
699 578 : for (i = 0; i < claims_set->claims_array_count; ++i) {
700 302 : const struct CLAIMS_ARRAY *claims_array = &claims_set->claims_arrays[i];
701 0 : uint32_t j;
702 :
703 302 : switch (claims_array->claims_source_type) {
704 296 : case CLAIMS_SOURCE_TYPE_AD:
705 : case CLAIMS_SOURCE_TYPE_CERTIFICATE:
706 296 : break;
707 6 : default:
708 : /* Ignore any claims of a type we don’t recognize. */
709 6 : continue;
710 : }
711 :
712 1024 : for (j = 0; j < claims_array->claims_count; ++j) {
713 744 : const struct CLAIM_ENTRY *claim_entry = &claims_array->claim_entries[j];
714 744 : const char *name = NULL;
715 744 : union claim_values *claim_values = NULL;
716 0 : uint32_t n_values;
717 0 : enum security_claim_value_type value_type;
718 :
719 744 : switch (claim_entry->type) {
720 15 : case CLAIM_TYPE_INT64:
721 : {
722 15 : const struct CLAIM_INT64 *values = &claim_entry->values.claim_int64;
723 0 : uint32_t k;
724 :
725 15 : n_values = values->value_count;
726 15 : value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
727 :
728 15 : claim_values = talloc_array(claims,
729 : union claim_values,
730 : n_values);
731 15 : if (claim_values == NULL) {
732 0 : talloc_free(tmp_ctx);
733 0 : return NT_STATUS_NO_MEMORY;
734 : }
735 :
736 30 : for (k = 0; k < n_values; ++k) {
737 19 : int64_t *value = NULL;
738 : uint32_t m;
739 :
740 : /*
741 : * Ensure that there are no duplicate
742 : * values (very inefficiently, in
743 : * O(n²)).
744 : */
745 21 : for (m = 0; m < k; ++m) {
746 6 : if (values->values[m] == values->values[k]) {
747 4 : talloc_free(tmp_ctx);
748 4 : return NT_STATUS_INVALID_PARAMETER;
749 : }
750 : }
751 :
752 15 : value = talloc(mem_ctx, int64_t);
753 15 : if (value == NULL) {
754 0 : talloc_free(tmp_ctx);
755 0 : return NT_STATUS_NO_MEMORY;
756 : }
757 :
758 15 : *value = values->values[k];
759 15 : claim_values[k].int_value = value;
760 : }
761 :
762 11 : break;
763 : }
764 81 : case CLAIM_TYPE_UINT64:
765 : case CLAIM_TYPE_BOOLEAN:
766 : {
767 81 : const struct CLAIM_UINT64 *values = &claim_entry->values.claim_uint64;
768 0 : uint32_t k;
769 :
770 81 : n_values = values->value_count;
771 162 : value_type = (claim_entry->type == CLAIM_TYPE_UINT64)
772 : ? CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64
773 81 : : CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN;
774 :
775 81 : claim_values = talloc_array(claims,
776 : union claim_values,
777 : n_values);
778 81 : if (claim_values == NULL) {
779 0 : talloc_free(tmp_ctx);
780 0 : return NT_STATUS_NO_MEMORY;
781 : }
782 :
783 100167 : for (k = 0; k < n_values; ++k) {
784 100094 : uint64_t *value = NULL;
785 : uint32_t m;
786 :
787 : /*
788 : * Ensure that there are no duplicate
789 : * values (very inefficiently, in
790 : * O(n²)).
791 : */
792 5000050110 : for (m = 0; m < k; ++m) {
793 4999950024 : if (values->values[m] == values->values[k]) {
794 8 : talloc_free(tmp_ctx);
795 8 : return NT_STATUS_INVALID_PARAMETER;
796 : }
797 : }
798 :
799 100086 : value = talloc(mem_ctx, uint64_t);
800 100086 : if (value == NULL) {
801 0 : talloc_free(tmp_ctx);
802 0 : return NT_STATUS_NO_MEMORY;
803 : }
804 :
805 100086 : *value = values->values[k];
806 100086 : claim_values[k].uint_value = value;
807 : }
808 :
809 73 : break;
810 : }
811 644 : case CLAIM_TYPE_STRING:
812 : {
813 644 : const struct CLAIM_STRING *values = &claim_entry->values.claim_string;
814 0 : uint32_t k;
815 :
816 644 : n_values = values->value_count;
817 644 : value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
818 :
819 644 : claim_values = talloc_array(claims,
820 : union claim_values,
821 : n_values);
822 644 : if (claim_values == NULL) {
823 0 : talloc_free(tmp_ctx);
824 0 : return NT_STATUS_NO_MEMORY;
825 : }
826 :
827 1525 : for (k = 0; k < n_values; ++k) {
828 885 : const char *string_value = NULL;
829 : uint32_t m;
830 :
831 : /*
832 : * Ensure that there are no duplicate
833 : * values (very inefficiently, in
834 : * O(n²)).
835 : */
836 1140 : for (m = 0; m < k; ++m) {
837 259 : if (values->values[m] == NULL && values->values[k] == NULL) {
838 0 : talloc_free(tmp_ctx);
839 0 : return NT_STATUS_INVALID_PARAMETER;
840 : }
841 :
842 259 : if (values->values[m] != NULL &&
843 518 : values->values[k] != NULL &&
844 259 : strcasecmp_m(values->values[m], values->values[k]) == 0)
845 : {
846 4 : talloc_free(tmp_ctx);
847 4 : return NT_STATUS_INVALID_PARAMETER;
848 : }
849 : }
850 :
851 881 : if (values->values[k] != NULL) {
852 881 : string_value = talloc_strdup(claim_values, values->values[k]);
853 881 : if (string_value == NULL) {
854 0 : talloc_free(tmp_ctx);
855 0 : return NT_STATUS_NO_MEMORY;
856 : }
857 : }
858 :
859 881 : claim_values[k].string_value = string_value;
860 : }
861 :
862 640 : break;
863 : }
864 4 : default:
865 : /*
866 : * Other claim types are unsupported — just skip
867 : * them.
868 : */
869 4 : continue;
870 : }
871 :
872 724 : claims = talloc_realloc(tmp_ctx,
873 : claims,
874 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
875 : ++n_claims);
876 724 : if (claims == NULL) {
877 0 : talloc_free(tmp_ctx);
878 0 : return NT_STATUS_NO_MEMORY;
879 : }
880 :
881 724 : if (claim_entry->id != NULL) {
882 724 : name = talloc_strdup(claims, claim_entry->id);
883 724 : if (name == NULL) {
884 0 : talloc_free(tmp_ctx);
885 0 : return NT_STATUS_NO_MEMORY;
886 : }
887 : }
888 :
889 724 : claims[n_claims - 1] = (struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1) {
890 : .name = name,
891 : .value_type = value_type,
892 : .flags = 0,
893 : .value_count = n_values,
894 : .values = claim_values,
895 : };
896 : }
897 : }
898 :
899 276 : *out_claims = talloc_move(mem_ctx, &claims);
900 276 : *out_n_claims = n_claims;
901 :
902 276 : talloc_free(tmp_ctx);
903 276 : return NT_STATUS_OK;
904 : }
|