libcli/security: Fix code spelling
[samba.git] / libcli / security / claims-conversions.c
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/claims-conversions.h"
23 #include "lib/util/debug.h"
24 #include "lib/util/stable_sort.h"
25
26 #include "librpc/gen_ndr/conditional_ace.h"
27 #include "librpc/gen_ndr/claims.h"
28
29 /*
30  * We support three formats for claims, all slightly different.
31  *
32  * 1. MS-ADTS 2.2.18.* claims sets, blobs, arrays, or whatever, which
33  *    are used in the PAC.
34  *
35  * 2. MS-DTYP 2.4.10.1 CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1
36  *    structures, used in security tokens and resource SACL ACEs.
37  *
38  * 3. MS-DTYP 2.4.4.17 Conditional ACE tokens.
39  *
40  * The types don't map perfectly onto each other -- in particular,
41  * Conditional ACEs don't have unsigned integer or boolean types, but
42  * do have short integer types which the other forms don't.
43  *
44  * We don't support the format used by the Win32 API function
45  * AddResourceAttributeAce(), which is called CLAIM_SECURITY_ATTRIBUTE_V1.
46  * Nobody has ever used that function in public, and the format is not used
47  * on the wire.
48  */
49
50
51 static bool claim_v1_string_to_ace_string(
52         TALLOC_CTX *mem_ctx,
53         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
54         size_t offset,
55         struct ace_condition_token *result)
56 {
57         char *s = talloc_strdup(mem_ctx,
58                                 claim->values[offset].string_value);
59         if (s == NULL) {
60                 return false;
61         }
62
63         result->type = CONDITIONAL_ACE_TOKEN_UNICODE;
64         result->data.unicode.value = s;
65         return true;
66 }
67
68
69 static bool claim_v1_octet_string_to_ace_octet_string(
70         TALLOC_CTX *mem_ctx,
71         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
72         size_t offset,
73         struct ace_condition_token *result)
74 {
75         DATA_BLOB *v = NULL;
76         DATA_BLOB w = data_blob_null;
77
78         v = claim->values[offset].octet_value;
79
80         if (v->length > CONDITIONAL_ACE_MAX_LENGTH) {
81                 DBG_WARNING("claim has octet string of unexpected length %zu "
82                             "(expected range 1 - %u)\n",
83                             v->length, CONDITIONAL_ACE_MAX_LENGTH);
84                 return false;
85         }
86         if (v->length != 0) {
87                 w = data_blob_talloc(mem_ctx, v->data, v->length);
88                 if (w.data == NULL) {
89                         return false;
90                 }
91         }
92
93         result->type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
94         result->data.bytes = w;
95         return true;
96 }
97
98
99 static bool blob_string_sid_to_sid(DATA_BLOB *blob,
100                                    struct dom_sid *sid)
101 {
102         /*
103          * Resource ACE claim SIDs are stored as SID strings in
104          * CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_RELATIVE blobs. These are in
105          * ACEs, which means we don't quite know who wrote them, and it is
106          * unspecified whether the blob should contain a terminating NUL byte.
107          * Therefore we accept either form, copying into a temporary buffer if
108          * there is no '\0'. Apart from this special case, we don't accept
109          * SIDs that are shorter than the blob.
110          *
111          * It doesn't seem like SDDL short SIDs ("WD") are accepted here. This
112          * isn't SDDL.
113          */
114         bool ok;
115         size_t len = blob->length;
116         char buf[DOM_SID_STR_BUFLEN + 1];   /* 191 + 1 */
117         const char *end = NULL;
118         char *str = NULL;
119
120         if (len < 5 || len >= DOM_SID_STR_BUFLEN) {
121                 return false;
122         }
123         if (blob->data[len - 1] == '\0') {
124                 str = (char *)blob->data;
125                 len--;
126         } else {
127                 memcpy(buf, blob->data, len);
128                 buf[len] = 0;
129                 str = buf;
130         }
131
132         ok = dom_sid_parse_endp(str, sid, &end);
133         if (!ok) {
134                 return false;
135         }
136
137         if (end - str != len) {
138                 return false;
139         }
140         return true;
141 }
142
143
144 static bool claim_v1_sid_to_ace_sid(
145         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
146         size_t offset,
147         struct ace_condition_token *result)
148 {
149         /*
150          * In the _V1 struct, SIDs are stored as octet string blobs,
151          * as *SID strings*.
152          *
153          * In the conditional ACE they are stored as struct dom_sid.
154          *
155          * There are no SIDs in ADTS claims, but there can be in
156          * resource ACEs.
157          */
158         DATA_BLOB *v = NULL;
159         bool ok;
160
161         v = claim->values[offset].sid_value;
162
163         ok = blob_string_sid_to_sid(v, &result->data.sid.sid);
164         if (! ok) {
165                 DBG_WARNING("claim has invalid SID string of length %zu.\n",
166                             v->length);
167                 return false;
168         }
169
170         result->type = CONDITIONAL_ACE_TOKEN_SID;
171         return true;
172 }
173
174
175 static bool claim_v1_int_to_ace_int(
176         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
177         size_t offset,
178         struct ace_condition_token *result)
179 {
180         int64_t v = *claim->values[offset].int_value;
181         result->type = CONDITIONAL_ACE_TOKEN_INT64;
182         result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
183         result->data.int64.value = v;
184
185         /*
186          * The sign flag (and the base flag above) determines how the
187          * ACE token will be displayed if converted to SDDL. These
188          * values are not likely to end up as SDDL, but we might as
189          * well get it right. A negative flag means it will be
190          * displayed with a minus sign, and a positive flag means a
191          * plus sign is shown. The none flag means no + or -.
192          */
193         if (v < 0) {
194                 result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NEGATIVE;
195         } else {
196                 result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
197         }
198
199         return true;
200 }
201
202
203 static bool claim_v1_unsigned_int_to_ace_int(
204         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
205         size_t offset,
206         struct ace_condition_token *result)
207 {
208         uint64_t v = *claim->values[offset].uint_value;
209         if (v > INT64_MAX) {
210                 /*
211                  * The unsigned value can't be represented in a
212                  * conditional ACE type.
213                  *
214                  * XXX or can it? does the positive flag make it
215                  * unsigned?
216                  */
217                 return false;
218         }
219         result->type = CONDITIONAL_ACE_TOKEN_INT64;
220         result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
221         result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_POSITIVE;
222         result->data.int64.value = v;
223         return true;
224 }
225
226
227 static bool claim_v1_bool_to_ace_int(
228         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
229         size_t offset,
230         struct ace_condition_token *result)
231 {
232         uint64_t v = *claim->values[offset].uint_value;
233         result->type = CONDITIONAL_ACE_TOKEN_INT64;
234         result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
235         result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
236         result->data.int64.value = v ? 1 : 0;
237         return true;
238 }
239
240
241 static bool claim_v1_offset_to_ace_token(
242         TALLOC_CTX *mem_ctx,
243         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
244         size_t offset,
245         struct ace_condition_token *result)
246 {
247         /*
248          * A claim structure has an array of claims of a certain type,
249          * and this converts a single one into a conditional ACE token.
250          *
251          * For example, if offset is 3, claim->values[3] will be
252          * turned into *result.
253          *
254          * conditional ace token will have flags to indicate that it
255          * comes from a claim attribute, and whether or not that
256          * attribute should be compared case-sensitively (only
257          * affecting unicode strings).
258          *
259          * The CLAIM_SECURITY_ATTRIBUTE_CASE_SENSITIVE (from the
260          * claim_flags enum in security.idl) is used for both.
261          */
262         uint8_t f = claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
263         result->flags = f | CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR;
264
265         switch (claim->value_type) {
266         case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
267                 return claim_v1_int_to_ace_int(claim, offset, result);
268         case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
269                 return claim_v1_unsigned_int_to_ace_int(claim, offset, result);
270         case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
271                 return claim_v1_string_to_ace_string(mem_ctx, claim, offset,
272                                                      result);
273         case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
274                 return claim_v1_sid_to_ace_sid(claim, offset, result);
275         case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
276                 return claim_v1_bool_to_ace_int(claim, offset, result);
277         case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
278                 return claim_v1_octet_string_to_ace_octet_string(mem_ctx,
279                                                                  claim,
280                                                                  offset,
281                                                                  result);
282         default:
283                 return false;
284         }
285 }
286
287
288 static bool claim_v1_copy(
289         TALLOC_CTX *mem_ctx,
290         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *dest,
291         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *src);
292
293
294
295 bool claim_v1_to_ace_composite_unchecked(
296         TALLOC_CTX *mem_ctx,
297         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
298         struct ace_condition_token *result)
299 {
300         /*
301          * This converts a claim object into a conditional ACE
302          * composite without checking whether it is a valid and sorted
303          * claim. It is called in two places:
304          *
305          * 1. claim_v1_to_ace_token() below (which does do those
306          * checks, and is the function you want).
307          *
308          * 2. sddl_resource_attr_from_claim() in which a resource
309          * attribute claim needs to pass through a conditional ACE
310          * composite structure on its way to becoming SDDL. In that
311          * case we don't want to check validity.
312          */
313         size_t i;
314         struct ace_condition_token *tokens = NULL;
315         bool ok;
316
317         tokens = talloc_array(mem_ctx,
318                               struct ace_condition_token,
319                               claim->value_count);
320         if (tokens == NULL) {
321                 return false;
322         }
323
324         for (i = 0; i < claim->value_count; i++) {
325                 ok = claim_v1_offset_to_ace_token(tokens,
326                                                   claim,
327                                                   i,
328                                                   &tokens[i]);
329                 if (! ok) {
330                         TALLOC_FREE(tokens);
331                         return false;
332                 }
333         }
334
335         result->type = CONDITIONAL_ACE_TOKEN_COMPOSITE;
336         result->data.composite.tokens = tokens;
337         result->data.composite.n_members = claim->value_count;
338         result->flags = claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
339         return true;
340 }
341
342
343 bool claim_v1_to_ace_token(TALLOC_CTX *mem_ctx,
344                            const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
345                            struct ace_condition_token *result)
346 {
347         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim_copy = NULL;
348         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sorted_claim = NULL;
349         NTSTATUS status;
350         bool ok;
351         bool case_sensitive = claim->flags &                    \
352                 CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
353
354         if (claim->value_count < 1 ||
355             claim->value_count >= CONDITIONAL_ACE_MAX_TOKENS) {
356                 DBG_WARNING("rejecting claim with %"PRIu32" tokens\n",
357                             claim->value_count);
358                 return false;
359         }
360         /*
361          * if there is one, we return a single thing of that type; if
362          * there are many, we return a composite.
363          */
364
365         if (claim->value_count == 1) {
366                 return claim_v1_offset_to_ace_token(mem_ctx,
367                                                     claim,
368                                                     0,
369                                                     result);
370         }
371
372         if (claim->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED) {
373                 /*
374                  * We can avoid making a sorted copy.
375                  *
376                  * This is normal case for wire claims, where the
377                  * sorting and duplicate checking happens earlier in
378                  * token_claims_to_claims_v1().
379                 */
380                 sorted_claim = claim;
381         } else {
382                 /*
383                  * This is presumably a resource attribute ACE, which
384                  * is stored in the ACE as struct
385                  * CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1, and we don't
386                  * really want to mutate that copy -- even if there
387                  * aren't currently realistic pathways that read an
388                  * ACE, trigger this, and write it back (outside of
389                  * tests).
390                  */
391                 claim_copy = talloc(mem_ctx, struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
392                 if (claim_copy == NULL) {
393                         return false;
394                 }
395
396                 ok = claim_v1_copy(claim_copy, claim_copy, claim);
397                 if (!ok) {
398                         TALLOC_FREE(claim_copy);
399                         return false;
400                 }
401
402                 status = claim_v1_check_and_sort(claim_copy, claim_copy,
403                                                  case_sensitive);
404                 if (!NT_STATUS_IS_OK(status)) {
405                         DBG_WARNING("resource attribute claim sort failed with %s\n",
406                                     nt_errstr(status));
407                         TALLOC_FREE(claim_copy);
408                         return false;
409                 }
410                 sorted_claim = claim_copy;
411         }
412         ok = claim_v1_to_ace_composite_unchecked(mem_ctx, sorted_claim, result);
413         if (! ok) {
414                 TALLOC_FREE(claim_copy);
415                 return false;
416         }
417
418         /*
419          * The multiple values will get turned into a composite
420          * literal in the conditional ACE. Each element of the
421          * composite will have flags set by
422          * claim_v1_offset_to_ace_token(), but they also need to be
423          * set here (at least the _FROM_ATTR flag) or the child values
424          * will not be reached.
425          */
426         result->flags |= (
427                 CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR |
428                 CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED);
429
430         return true;
431 }
432
433
434
435 static bool ace_int_to_claim_v1_int(TALLOC_CTX *mem_ctx,
436                                     const struct ace_condition_token *tok,
437                                     struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
438                                     size_t offset)
439 {
440         int64_t *v = talloc(mem_ctx, int64_t);
441         if (v == NULL) {
442                 return false;
443         }
444         *v = tok->data.int64.value;
445         claim->values[offset].int_value = v;
446         return true;
447 }
448
449
450 static bool ace_string_to_claim_v1_string(TALLOC_CTX *mem_ctx,
451                                           const struct ace_condition_token *tok,
452                                           struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
453                                           size_t offset)
454 {
455         const char *s = talloc_strdup(mem_ctx,
456                                       tok->data.unicode.value);
457         if (s == NULL) {
458                 return false;
459         }
460         claim->values[offset].string_value = s;
461         return true;
462
463 }
464
465
466 static bool ace_sid_to_claim_v1_sid(TALLOC_CTX *mem_ctx,
467                                     const struct ace_condition_token *tok,
468                                     struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
469                                     size_t offset)
470 {
471         /* claim_v1 sid is an "S-1-*" string data blob, not struct dom_sid. */
472         char *s = NULL;
473
474         DATA_BLOB *blob = NULL;
475         blob = talloc(mem_ctx, DATA_BLOB);
476         if (blob == NULL) {
477                 return false;
478         }
479         s = dom_sid_string(blob, &tok->data.sid.sid);
480         if (s == NULL) {
481                 TALLOC_FREE(blob);
482                 return false;
483         }
484         *blob = data_blob_string_const(s);
485         claim->values[offset].sid_value = blob;
486         return true;
487 }
488
489 static bool ace_octet_string_to_claim_v1_octet_string(
490         TALLOC_CTX *mem_ctx,
491         const struct ace_condition_token *tok,
492         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
493         size_t offset)
494 {
495         DATA_BLOB *v = talloc(mem_ctx, DATA_BLOB);
496         if (v == NULL) {
497                 return false;
498         }
499
500         *v = data_blob_talloc(v,
501                               tok->data.bytes.data,
502                               tok->data.bytes.length);
503         if (v->data == NULL) {
504                 return false;
505         }
506
507         claim->values[offset].octet_value = v;
508         return true;
509 }
510
511
512
513 static bool ace_token_to_claim_v1_offset(TALLOC_CTX *mem_ctx,
514                                          const struct ace_condition_token *tok,
515                                          struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
516                                          size_t offset)
517 {
518         /*
519          * A claim structure has an array of claims of a certain type,
520          * and this converts a single one into a conditional ACE token.
521          *
522          * For example, if offset is 3, claim->values[3] will be
523          * turned into *result.
524          */
525         if (offset >= claim->value_count) {
526                 return false;
527         }
528         switch (claim->value_type) {
529         case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
530         case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
531                 return ace_int_to_claim_v1_int(mem_ctx, tok, claim, offset);
532         case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
533                 return ace_string_to_claim_v1_string(mem_ctx, tok, claim, offset);
534         case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
535                 return ace_sid_to_claim_v1_sid(mem_ctx, tok, claim, offset);
536         case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
537                 return ace_octet_string_to_claim_v1_octet_string(mem_ctx,
538                                                                  tok,
539                                                                  claim,
540                                                                  offset);
541         default:
542                 /*bool unimplemented, because unreachable */
543                 return false;
544         }
545 }
546
547
548 bool ace_token_to_claim_v1(TALLOC_CTX *mem_ctx,
549                            const char *name,
550                            const struct ace_condition_token *tok,
551                            struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **claim,
552                            uint32_t flags)
553 {
554         size_t i;
555         bool ok;
556         bool is_comp = false;
557         int claim_type = -1;
558         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *_claim = NULL;
559         uint32_t value_count;
560
561         if (name == NULL || claim == NULL || tok == NULL) {
562                 return false;
563         }
564         *claim = NULL;
565
566         if (tok->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
567                 is_comp = true;
568                 /* there must be values, all of the same type */
569                 if (tok->data.composite.n_members == 0) {
570                         DBG_WARNING("Empty ACE composite list\n");
571                         return false;
572                 }
573                 if (tok->data.composite.n_members > 1) {
574                         for (i = 1; i < tok->data.composite.n_members; i++) {
575                                 if (tok->data.composite.tokens[i].type !=
576                                     tok->data.composite.tokens[0].type) {
577                                         DBG_WARNING(
578                                                 "ACE composite list has varying "
579                                                 "types (at least %u and %u)\n",
580                                                 tok->data.composite.tokens[i].type,
581                                                 tok->data.composite.tokens[0].type);
582                                         return false;
583                                 }
584                         }
585                 }
586                 value_count = tok->data.composite.n_members;
587
588                 switch (tok->data.composite.tokens[0].type) {
589                 case CONDITIONAL_ACE_TOKEN_INT8:
590                 case CONDITIONAL_ACE_TOKEN_INT16:
591                 case CONDITIONAL_ACE_TOKEN_INT32:
592                 case CONDITIONAL_ACE_TOKEN_INT64:
593                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
594                         break;
595                 case CONDITIONAL_ACE_TOKEN_UNICODE:
596                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
597                         break;
598                 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
599                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
600                         break;
601                 case CONDITIONAL_ACE_TOKEN_SID:
602                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
603                         break;
604                 default:
605                         /* reject nested composites, no uint or bool. */
606                         DBG_WARNING("ACE composite list has invalid type %u\n",
607                                     tok->data.composite.tokens[0].type);
608                         return false;
609                 }
610         } else {
611                 value_count = 1;
612                 switch(tok->type) {
613                 case CONDITIONAL_ACE_TOKEN_INT8:
614                 case CONDITIONAL_ACE_TOKEN_INT16:
615                 case CONDITIONAL_ACE_TOKEN_INT32:
616                 case CONDITIONAL_ACE_TOKEN_INT64:
617                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
618                         break;
619                 case CONDITIONAL_ACE_TOKEN_UNICODE:
620                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
621                         break;
622                 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
623                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
624                         break;
625                 case CONDITIONAL_ACE_TOKEN_SID:
626                         claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
627                         break;
628                 default:
629                         /*
630                          * no way of creating bool or uint values,
631                          * composite is handled above.
632                          */
633                         DBG_WARNING("ACE token has invalid type %u\n",
634                                     tok->data.composite.tokens[0].type);
635                         return false;
636                 }
637         }
638
639         _claim = talloc(mem_ctx, struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
640         if (_claim == NULL) {
641                 return false;
642         }
643
644         _claim->value_count = value_count;
645         _claim->value_type = claim_type;
646         _claim->flags = flags;
647         _claim->name = talloc_strdup(mem_ctx, name);
648         if (_claim->name == NULL) {
649                 TALLOC_FREE(_claim);
650                 return false;
651         }
652         /*
653          * The values array is actually an array of pointers to
654          * values, even when the values are ints or bools.
655          */
656         _claim->values = talloc_array(_claim, union claim_values, value_count);
657         if (_claim->values == NULL) {
658                 TALLOC_FREE(_claim);
659                 return false;
660         }
661         if (! is_comp) {
662                 /* there is one value, not a list */
663                 ok = ace_token_to_claim_v1_offset(_claim,
664                                                   tok,
665                                                   _claim,
666                                                   0);
667                 if (! ok) {
668                         TALLOC_FREE(_claim);
669                         return false;
670                 }
671         } else {
672                 /* a composite list of values */
673                 for (i = 0; i < value_count; i++) {
674                         struct ace_condition_token *t = &tok->data.composite.tokens[i];
675                         ok = ace_token_to_claim_v1_offset(mem_ctx,
676                                                           t,
677                                                           _claim,
678                                                           i);
679                         if (! ok) {
680                                 TALLOC_FREE(_claim);
681                                 return false;
682                         }
683                 }
684         }
685
686
687         if (_claim->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64) {
688                 /*
689                  * Conditional ACE tokens don't have a UINT type but
690                  * claims do. Windows tends to use UINT types in
691                  * claims when it can, so so do we.
692                  */
693                 bool could_be_uint = true;
694                 for (i = 0; i < value_count; i++) {
695                         if (*_claim->values[i].int_value < 0) {
696                                 could_be_uint = false;
697                                 break;
698                         }
699                 }
700                 if (could_be_uint) {
701                         _claim->value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64;
702                 }
703         }
704
705         *claim = _claim;
706         return true;
707 }
708
709
710
711 static bool claim_v1_copy(
712         TALLOC_CTX *mem_ctx,
713         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *dest,
714         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *src)
715 {
716         DATA_BLOB blob = {0};
717         enum ndr_err_code ndr_err;
718
719         /*
720          * FIXME, could be more efficient! but copying these
721          * structures is fiddly, and it might be worth coming up
722          * with a better API for adding claims.
723          */
724
725         ndr_err = ndr_push_struct_blob(
726                 &blob, mem_ctx, src,
727                 (ndr_push_flags_fn_t)ndr_push_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
728
729         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
730                 return false;
731         }
732
733         ndr_err = ndr_pull_struct_blob(
734                 &blob, mem_ctx, dest,
735                 (ndr_pull_flags_fn_t)ndr_pull_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
736
737         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
738                 TALLOC_FREE(blob.data);
739                 return false;
740         }
741         TALLOC_FREE(blob.data);
742         return true;
743 }
744
745
746
747 bool add_claim_to_token(TALLOC_CTX *mem_ctx,
748                         struct security_token *token,
749                         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
750                         const char *claim_type)
751 {
752         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *tmp = NULL;
753         NTSTATUS status;
754         uint32_t *n = NULL;
755         bool ok;
756         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **list = NULL;
757         if (strcmp(claim_type, "device") == 0) {
758                 n = &token->num_device_claims;
759                 list = &token->device_claims;
760         } else if (strcmp(claim_type, "local") == 0) {
761                 n = &token->num_local_claims;
762                 list = &token->local_claims;
763         } else if (strcmp(claim_type, "user") == 0) {
764                 n = &token->num_user_claims;
765                 list = &token->user_claims;
766         } else {
767                 return false;
768         }
769         if ((*n) == UINT32_MAX) {
770                 return false;
771         }
772
773         tmp = talloc_realloc(mem_ctx,
774                              *list,
775                              struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
776                              (*n) + 1);
777         if (tmp == NULL) {
778                 return false;
779         }
780
781         ok = claim_v1_copy(mem_ctx, &tmp[*n], claim);
782         if (! ok ) {
783                 TALLOC_FREE(tmp);
784                 return false;
785         }
786
787         status = claim_v1_check_and_sort(tmp, &tmp[*n],
788                                          claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE);
789         if (!NT_STATUS_IS_OK(status)) {
790                 DBG_WARNING("resource attribute claim sort failed with %s\n",
791                             nt_errstr(status));
792                 TALLOC_FREE(tmp);
793                 return false;
794         }
795
796         (*n)++;
797         *list = tmp;
798         return true;
799 }
800
801
802 static NTSTATUS claim_v1_check_and_sort_boolean(
803         TALLOC_CTX *mem_ctx,
804         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim)
805 {
806         /*
807          * There are so few valid orders in a boolean claim that we can
808          * enumerate them all.
809          */
810         switch (claim->value_count) {
811         case 0:
812                 return NT_STATUS_OK;
813         case 1:
814                 if (*claim->values[0].uint_value == 0 ||
815                     *claim->values[0].uint_value == 1) {
816                         return NT_STATUS_OK;
817                 }
818                 break;
819         case 2:
820                 if (*claim->values[0].uint_value == 1) {
821                         /* switch the order. */
822                         *claim->values[0].uint_value = *claim->values[1].uint_value;
823                         *claim->values[1].uint_value = 1;
824                 }
825                 if (*claim->values[0].uint_value == 0 &&
826                     *claim->values[1].uint_value == 1) {
827                         return NT_STATUS_OK;
828                 }
829                 break;
830         default:
831                 /* 3 or more must have duplicates. */
832                 break;
833         }
834         return NT_STATUS_INVALID_PARAMETER;
835 }
836
837
838 struct claim_sort_context {
839         uint16_t value_type;
840         bool failed;
841         bool case_sensitive;
842 };
843
844 static int claim_sort_cmp(const union claim_values *lhs,
845                           const union claim_values *rhs,
846                           struct claim_sort_context *ctx)
847 {
848         /*
849          * These comparisons have to match those used in
850          * conditional_ace.c.
851          */
852         int cmp;
853
854         switch (ctx->value_type) {
855         case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
856         case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
857         {
858                 /*
859                  * We sort as signed integers, even for uint64,
860                  * because a) we don't actually care about the true
861                  * order, just uniqueness, and b) the conditional ACEs
862                  * only know of signed values.
863                  */
864                 int64_t a, b;
865                 if (ctx->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64) {
866                         a = *lhs->int_value;
867                         b = *rhs->int_value;
868                 } else {
869                         a = (int64_t)*lhs->uint_value;
870                         b = (int64_t)*rhs->uint_value;
871                 }
872                 if (a < b) {
873                         return -1;
874                 }
875                 if (a == b) {
876                         return 0;
877                 }
878                 return 1;
879         }
880         case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
881         {
882                 const char *a = lhs->string_value;
883                 const char *b = rhs->string_value;
884                 if (ctx->case_sensitive) {
885                         return strcmp(a, b);
886                 }
887                 return strcasecmp_m(a, b);
888         }
889
890         case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
891         {
892                 /*
893                  * The blobs in a claim are "S-1-.." strings, not struct
894                  * dom_sid as used in conditional ACEs, and to sort them the
895                  * same as ACEs we need to make temporary structs.
896                  *
897                  * We don't accept SID claims over the wire -- these
898                  * are resource attribute ACEs only.
899                  */
900                 struct dom_sid a, b;
901                 bool lhs_ok, rhs_ok;
902
903                 lhs_ok = blob_string_sid_to_sid(lhs->sid_value, &a);
904                 rhs_ok = blob_string_sid_to_sid(rhs->sid_value, &b);
905                 if (!(lhs_ok && rhs_ok)) {
906                         ctx->failed = true;
907                         return -1;
908                 }
909                 cmp = dom_sid_compare(&a, &b);
910                 return cmp;
911         }
912         case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
913         {
914                 const DATA_BLOB *a = lhs->octet_value;
915                 const DATA_BLOB *b = rhs->octet_value;
916                 return data_blob_cmp(a, b);
917         }
918         default:
919                 ctx->failed = true;
920                 break;
921         }
922         return -1;
923 }
924
925
926 NTSTATUS claim_v1_check_and_sort(TALLOC_CTX *mem_ctx,
927                                  struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
928                                  bool case_sensitive)
929 {
930         bool ok;
931         uint32_t i;
932         struct claim_sort_context sort_ctx = {
933                 .failed = false,
934                 .value_type = claim->value_type,
935                 .case_sensitive = case_sensitive
936         };
937
938         if (claim->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN) {
939                 NTSTATUS status = claim_v1_check_and_sort_boolean(mem_ctx, claim);
940                 if (NT_STATUS_IS_OK(status)) {
941                         claim->flags |= CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
942                 }
943                 return status;
944         }
945
946         ok =  stable_sort_talloc_r(mem_ctx,
947                                    claim->values,
948                                    claim->value_count,
949                                    sizeof(union claim_values),
950                                    (samba_compare_with_context_fn_t)claim_sort_cmp,
951                                    &sort_ctx);
952         if (!ok) {
953                 return NT_STATUS_NO_MEMORY;
954         }
955
956         if (sort_ctx.failed) {
957                 /* this failure probably means a bad SID string */
958                 DBG_WARNING("claim sort of %"PRIu32" members, type %"PRIu16" failed\n",
959                             claim->value_count,
960                             claim->value_type);
961                 return NT_STATUS_INVALID_PARAMETER;
962         }
963
964         for (i = 1; i < claim->value_count; i++) {
965                 int cmp = claim_sort_cmp(&claim->values[i - 1],
966                                          &claim->values[i],
967                                          &sort_ctx);
968                 if (cmp == 0) {
969                         DBG_WARNING("duplicate values in claim\n");
970                         return NT_STATUS_INVALID_PARAMETER;
971                 }
972                 if (cmp > 0) {
973                         DBG_ERR("claim sort failed!\n");
974                         return NT_STATUS_INVALID_PARAMETER;
975                 }
976         }
977         if (case_sensitive) {
978                 claim->flags |= CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
979         }
980         claim->flags |= CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
981         return NT_STATUS_OK;
982 }
983
984
985 NTSTATUS token_claims_to_claims_v1(TALLOC_CTX *mem_ctx,
986                                    const struct CLAIMS_SET *claims_set,
987                                    struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **out_claims,
988                                    uint32_t *out_n_claims)
989 {
990         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
991         uint32_t n_claims = 0;
992         uint32_t expected_n_claims = 0;
993         uint32_t i;
994         NTSTATUS status;
995
996         if (out_claims == NULL) {
997                 return NT_STATUS_INVALID_PARAMETER;
998         }
999         if (out_n_claims == NULL) {
1000                 return NT_STATUS_INVALID_PARAMETER;
1001         }
1002
1003         *out_claims = NULL;
1004         *out_n_claims = 0;
1005
1006         if (claims_set == NULL) {
1007                 return NT_STATUS_OK;
1008         }
1009
1010         /*
1011          * The outgoing number of claims is (at most) the sum of the
1012          * claims_counts of each claims_array.
1013          */
1014         for (i = 0; i < claims_set->claims_array_count; ++i) {
1015                 uint32_t count = claims_set->claims_arrays[i].claims_count;
1016                 expected_n_claims += count;
1017                 if (expected_n_claims < count) {
1018                         return NT_STATUS_INVALID_PARAMETER;
1019                 }
1020         }
1021
1022         claims = talloc_array(mem_ctx,
1023                               struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
1024                               expected_n_claims);
1025         if (claims == NULL) {
1026                 return NT_STATUS_NO_MEMORY;
1027         }
1028
1029         for (i = 0; i < claims_set->claims_array_count; ++i) {
1030                 const struct CLAIMS_ARRAY *claims_array = &claims_set->claims_arrays[i];
1031                 uint32_t j;
1032
1033                 switch (claims_array->claims_source_type) {
1034                 case CLAIMS_SOURCE_TYPE_AD:
1035                 case CLAIMS_SOURCE_TYPE_CERTIFICATE:
1036                         break;
1037                 default:
1038                         /* Ignore any claims of a type we don’t recognize. */
1039                         continue;
1040                 }
1041
1042                 for (j = 0; j < claims_array->claims_count; ++j) {
1043                         const struct CLAIM_ENTRY *claim_entry = &claims_array->claim_entries[j];
1044                         const char *name = NULL;
1045                         union claim_values *claim_values = NULL;
1046                         uint32_t n_values;
1047                         enum security_claim_value_type value_type;
1048
1049                         switch (claim_entry->type) {
1050                         case CLAIM_TYPE_INT64:
1051                         {
1052                                 const struct CLAIM_INT64 *values = &claim_entry->values.claim_int64;
1053                                 uint32_t k;
1054                                 int64_t *claim_values_int64 = NULL;
1055
1056                                 n_values = values->value_count;
1057                                 value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
1058
1059                                 claim_values = talloc_array(claims,
1060                                                             union claim_values,
1061                                                             n_values);
1062                                 if (claim_values == NULL) {
1063                                         talloc_free(claims);
1064                                         return NT_STATUS_NO_MEMORY;
1065                                 }
1066                                 claim_values_int64 = talloc_array(claims,
1067                                                                   int64_t,
1068                                                                   n_values);
1069                                 if (claim_values_int64 == NULL) {
1070                                         talloc_free(claims);
1071                                         return NT_STATUS_NO_MEMORY;
1072                                 }
1073
1074                                 for (k = 0; k < n_values; ++k) {
1075                                         claim_values_int64[k] = values->values[k];
1076                                         claim_values[k].int_value = &claim_values_int64[k];
1077                                 }
1078
1079                                 break;
1080                         }
1081                         case CLAIM_TYPE_UINT64:
1082                         case CLAIM_TYPE_BOOLEAN:
1083                         {
1084                                 const struct CLAIM_UINT64 *values = &claim_entry->values.claim_uint64;
1085                                 uint32_t k;
1086                                 uint64_t *claim_values_uint64 = NULL;
1087
1088                                 n_values = values->value_count;
1089                                 value_type = (claim_entry->type == CLAIM_TYPE_UINT64)
1090                                         ? CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64
1091                                         : CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN;
1092
1093                                 claim_values = talloc_array(claims,
1094                                                             union claim_values,
1095                                                             n_values);
1096                                 if (claim_values == NULL) {
1097                                         talloc_free(claims);
1098                                         return NT_STATUS_NO_MEMORY;
1099                                 }
1100
1101                                 claim_values_uint64 = talloc_array(claims,
1102                                                                    uint64_t,
1103                                                                    n_values);
1104                                 if (claim_values_uint64 == NULL) {
1105                                         talloc_free(claims);
1106                                         return NT_STATUS_NO_MEMORY;
1107                                 }
1108
1109                                 for (k = 0; k < n_values; ++k) {
1110                                         claim_values_uint64[k] = values->values[k];
1111                                         claim_values[k].uint_value = &claim_values_uint64[k];
1112                                 }
1113
1114                                 break;
1115                         }
1116                         case CLAIM_TYPE_STRING:
1117                         {
1118                                 const struct CLAIM_STRING *values = &claim_entry->values.claim_string;
1119                                 uint32_t k, m;
1120                                 bool seen_empty = false;
1121                                 n_values = values->value_count;
1122                                 value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
1123
1124                                 claim_values = talloc_array(claims,
1125                                                             union claim_values,
1126                                                             n_values);
1127                                 if (claim_values == NULL) {
1128                                         talloc_free(claims);
1129                                         return NT_STATUS_NO_MEMORY;
1130                                 }
1131
1132                                 m = 0;
1133                                 for (k = 0; k < n_values; ++k) {
1134                                         const char *string_value = NULL;
1135
1136                                         if (values->values[k] != NULL) {
1137                                                 string_value = talloc_strdup(claim_values, values->values[k]);
1138                                                 if (string_value == NULL) {
1139                                                         talloc_free(claims);
1140                                                         return NT_STATUS_NO_MEMORY;
1141                                                 }
1142                                                 claim_values[m].string_value = string_value;
1143                                                 m++;
1144                                         } else {
1145                                                 /*
1146                                                  * We allow one NULL string
1147                                                  * per claim, but not two,
1148                                                  * because two would be a
1149                                                  * duplicate, and we don't
1150                                                  * want those (duplicates in
1151                                                  * actual values are checked
1152                                                  * later).
1153                                                  */
1154                                                 if (seen_empty) {
1155                                                         talloc_free(claims);
1156                                                         return NT_STATUS_INVALID_PARAMETER;
1157                                                 }
1158                                                 seen_empty = true;
1159                                         }
1160                                 }
1161                                 n_values = m;
1162                                 break;
1163                         }
1164                         default:
1165                                 /*
1166                                  * Other claim types are unsupported — just skip
1167                                  * them.
1168                                  */
1169                                 continue;
1170                         }
1171
1172                         if (claim_entry->id != NULL) {
1173                                 name = talloc_strdup(claims, claim_entry->id);
1174                                 if (name == NULL) {
1175                                         talloc_free(claims);
1176                                         return NT_STATUS_NO_MEMORY;
1177                                 }
1178                         }
1179
1180                         claims[n_claims] = (struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1) {
1181                                 .name = name,
1182                                 .value_type = value_type,
1183                                 .flags = 0,
1184                                 .value_count = n_values,
1185                                 .values = claim_values,
1186                         };
1187
1188                         status = claim_v1_check_and_sort(claims, &claims[n_claims],
1189                                                          false);
1190                         if (!NT_STATUS_IS_OK(status)) {
1191                                 talloc_free(claims);
1192                                 DBG_WARNING("claim sort and uniqueness test failed with %s\n",
1193                                             nt_errstr(status));
1194                                 return status;
1195                         }
1196                         n_claims++;
1197                 }
1198         }
1199         *out_claims = claims;
1200         *out_n_claims = n_claims;
1201
1202         return NT_STATUS_OK;
1203 }