LCOV - code coverage report
Current view: top level - libcli/security - claims-conversions.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 303 400 75.8 %
Date: 2023-11-21 12:31:41 Functions: 15 17 88.2 %

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

Generated by: LCOV version 1.14