Coverage Report

Created: 2025-12-31 06:20

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