LCOV - code coverage report
Current view: top level - libcli/security - claims-conversions.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 421 544 77.4 %
Date: 2024-05-31 13:13:24 Functions: 20 22 90.9 %

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

Generated by: LCOV version 1.14