LCOV - code coverage report
Current view: top level - libcli/security - sddl_conditional_ace.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 1047 1504 69.6 %
Date: 2024-04-13 12:30:31 Functions: 47 50 94.0 %

          Line data    Source code
       1             : /*
       2             :  *  Unix SMB implementation.
       3             :  *  Functions for understanding conditional ACEs
       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 "includes.h"
      20             : #include "librpc/gen_ndr/ndr_security.h"
      21             : #include "librpc/gen_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/bytearray.h"
      27             : 
      28             : 
      29             : /* We're only dealing with utf-8 here. Honestly. */
      30             : #undef strncasecmp
      31             : 
      32             : 
      33             : #define SDDL_FLAG_EXPECTING_UNARY_OP          1
      34             : #define SDDL_FLAG_EXPECTING_BINARY_OP         2
      35             : #define SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP   4
      36             : #define SDDL_FLAG_EXPECTING_LOCAL_ATTR        8
      37             : #define SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR   16
      38             : #define SDDL_FLAG_EXPECTING_LITERAL          32
      39             : #define SDDL_FLAG_EXPECTING_PAREN            64
      40             : #define SDDL_FLAG_EXPECTING_PAREN_LITERAL   128
      41             : #define SDDL_FLAG_NOT_EXPECTING_END_PAREN   256
      42             : 
      43             : #define SDDL_FLAG_DEVICE                    512
      44             : 
      45             : #define SDDL_FLAG_IS_UNARY_OP               (1 << 20)
      46             : #define SDDL_FLAG_IS_BINARY_OP              (1 << 21)
      47             : 
      48             : 
      49             : #define SDDL_FLAGS_EXPR_START (SDDL_FLAG_EXPECTING_UNARY_OP | \
      50             :                                SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
      51             :                                SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
      52             :                                SDDL_FLAG_EXPECTING_PAREN)
      53             : 
      54             : #define SDDL_FLAGS_MEMBER_OP (SDDL_FLAG_EXPECTING_LITERAL | \
      55             :                               SDDL_FLAG_EXPECTING_PAREN_LITERAL | \
      56             :                               SDDL_FLAG_IS_UNARY_OP)
      57             : 
      58             : #define SDDL_FLAGS_RELATIONAL_OP (SDDL_FLAG_EXPECTING_LITERAL | \
      59             :                                   SDDL_FLAG_EXPECTING_PAREN_LITERAL |  \
      60             :                                   SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
      61             :                                   SDDL_FLAG_IS_BINARY_OP)
      62             : 
      63             : #define SDDL_FLAGS_CONTAINS_OP (SDDL_FLAG_EXPECTING_LITERAL | \
      64             :                                 SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR |    \
      65             :                                 SDDL_FLAG_IS_BINARY_OP)
      66             : 
      67             : #define SDDL_FLAGS_EXISTS_OP (SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
      68             :                               SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
      69             :                               SDDL_FLAG_IS_UNARY_OP)
      70             : 
      71             : #define SDDL_FLAGS_LOGIC_OP (SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
      72             :                              SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
      73             :                              SDDL_FLAG_EXPECTING_PAREN | \
      74             :                              SDDL_FLAG_EXPECTING_UNARY_OP | \
      75             :                              SDDL_FLAG_IS_BINARY_OP)
      76             : 
      77             : #define SDDL_FLAGS_ATTRIBUTE (SDDL_FLAG_EXPECTING_BINARY_OP | \
      78             :                               SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP)
      79             : 
      80             : #define SDDL_FLAGS_LITERAL SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP
      81             : 
      82             : #define SDDL_FLAGS_PAREN_END (SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP | \
      83             :                               SDDL_FLAG_EXPECTING_BINARY_OP)
      84             : 
      85             : enum {
      86             :         SDDL_NOT_AN_OP = 0,
      87             :         SDDL_PRECEDENCE_EXISTS,
      88             :         SDDL_PRECEDENCE_COMMON,
      89             :         SDDL_PRECEDENCE_NOT,
      90             :         SDDL_PRECEDENCE_AND,
      91             :         SDDL_PRECEDENCE_OR,
      92             :         SDDL_PRECEDENCE_PAREN_END,
      93             :         SDDL_PRECEDENCE_PAREN_START,
      94             : };
      95             : 
      96             : struct ace_condition_sddl_compiler_context {
      97             :         TALLOC_CTX *mem_ctx;
      98             :         const uint8_t *sddl;
      99             :         uint32_t length;
     100             :         uint32_t offset;
     101             :         uint32_t stack_depth;
     102             :         uint32_t max_program_length;
     103             :         uint32_t approx_size;
     104             :         struct ace_condition_script *program;
     105             :         struct ace_condition_token *stack;
     106             :         struct ace_condition_token *target;
     107             :         uint32_t *target_len;
     108             :         const char *message;
     109             :         uint32_t message_offset;
     110             :         struct dom_sid *domain_sid;
     111             :         uint32_t state;
     112             :         uint8_t last_token_type;
     113             :         bool allow_device;
     114             : };
     115             : 
     116             : struct sddl_data {
     117             :         const char *name;
     118             :         uint32_t flags;
     119             :         uint8_t op_precedence;
     120             :         uint8_t nargs;
     121             : };
     122             : 
     123             : static const struct sddl_data sddl_strings[256] = {
     124             :         /* operators */
     125             :         [CONDITIONAL_ACE_TOKEN_MEMBER_OF] = {
     126             :                 "Member_of",
     127             :                 SDDL_FLAGS_MEMBER_OP,
     128             :                 SDDL_PRECEDENCE_COMMON,
     129             :                 1
     130             :         },
     131             :         [CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF] = {
     132             :                 "Device_Member_of",
     133             :                 SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
     134             :                 SDDL_PRECEDENCE_COMMON,
     135             :                 1
     136             :         },
     137             :         [CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY] = {
     138             :                 /* [MS-DTYP] says "_Any", but windows prefers '_any' */
     139             :                 "Member_of_any",
     140             :                 SDDL_FLAGS_MEMBER_OP,
     141             :                 SDDL_PRECEDENCE_COMMON,
     142             :                 1
     143             :         },
     144             :         [CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY] = {
     145             :                 "Device_Member_of_Any",
     146             :                 SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
     147             :                 SDDL_PRECEDENCE_COMMON,
     148             :                 1
     149             :         },
     150             :         [CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF] = {
     151             :                 "Not_Member_of",
     152             :                 SDDL_FLAGS_MEMBER_OP,
     153             :                 SDDL_PRECEDENCE_COMMON,
     154             :                 1
     155             :         },
     156             :         [CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF] = {
     157             :                 "Not_Device_Member_of",
     158             :                 SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
     159             :                 SDDL_PRECEDENCE_COMMON,
     160             :                 1
     161             :         },
     162             :         [CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY] = {
     163             :                 "Not_Member_of_Any",
     164             :                 SDDL_FLAGS_MEMBER_OP,
     165             :                 SDDL_PRECEDENCE_COMMON,
     166             :                 1
     167             :         },
     168             :         [CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY] = {
     169             :                 "Not_Device_Member_of_Any",
     170             :                 SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
     171             :                 SDDL_PRECEDENCE_COMMON,
     172             :                 1
     173             :         },
     174             :         [CONDITIONAL_ACE_TOKEN_EQUAL] = {
     175             :                 "==",
     176             :                 SDDL_FLAGS_RELATIONAL_OP,
     177             :                 SDDL_PRECEDENCE_COMMON,
     178             :                 2
     179             :         },
     180             :         [CONDITIONAL_ACE_TOKEN_NOT_EQUAL] = {
     181             :                 "!=",
     182             :                 SDDL_FLAGS_RELATIONAL_OP,
     183             :                 SDDL_PRECEDENCE_COMMON,
     184             :                 2
     185             :         },
     186             :         [CONDITIONAL_ACE_TOKEN_LESS_THAN] = {
     187             :                 "<",
     188             :                 SDDL_FLAGS_RELATIONAL_OP,
     189             :                 SDDL_PRECEDENCE_COMMON,
     190             :                 2
     191             :         },
     192             :         [CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL] = {
     193             :                 "<=",
     194             :                 SDDL_FLAGS_RELATIONAL_OP,
     195             :                 SDDL_PRECEDENCE_COMMON,
     196             :                 2
     197             :         },
     198             :         [CONDITIONAL_ACE_TOKEN_GREATER_THAN] = {
     199             :                 ">",
     200             :                 SDDL_FLAGS_RELATIONAL_OP,
     201             :                 SDDL_PRECEDENCE_COMMON,
     202             :                 2
     203             :         },
     204             :         [CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL] = {
     205             :                 ">=",
     206             :                 SDDL_FLAGS_RELATIONAL_OP,
     207             :                 SDDL_PRECEDENCE_COMMON,
     208             :                 2
     209             :         },
     210             :         [CONDITIONAL_ACE_TOKEN_CONTAINS] = {
     211             :                 "Contains",
     212             :                 SDDL_FLAGS_CONTAINS_OP,
     213             :                 SDDL_PRECEDENCE_COMMON,
     214             :                 2
     215             :         },
     216             :         [CONDITIONAL_ACE_TOKEN_ANY_OF] = {
     217             :                 "Any_of",
     218             :                 SDDL_FLAGS_CONTAINS_OP,
     219             :                 SDDL_PRECEDENCE_COMMON,
     220             :                 2
     221             :         },
     222             :         [CONDITIONAL_ACE_TOKEN_NOT_CONTAINS] = {
     223             :                 "Not_Contains",
     224             :                 SDDL_FLAGS_CONTAINS_OP,
     225             :                 SDDL_PRECEDENCE_COMMON,
     226             :                 2
     227             :         },
     228             :         [CONDITIONAL_ACE_TOKEN_NOT_ANY_OF] = {
     229             :                 "Not_Any_of",
     230             :                 SDDL_FLAGS_CONTAINS_OP,
     231             :                 SDDL_PRECEDENCE_COMMON,
     232             :                 2
     233             :         },
     234             :         [CONDITIONAL_ACE_TOKEN_AND] = {
     235             :                 "&&",
     236             :                 SDDL_FLAGS_LOGIC_OP,
     237             :                 SDDL_PRECEDENCE_AND,
     238             :                 2
     239             :         },
     240             :         [CONDITIONAL_ACE_TOKEN_OR] = {
     241             :                 "||",
     242             :                 SDDL_FLAGS_LOGIC_OP,
     243             :                 SDDL_PRECEDENCE_OR,
     244             :                 2
     245             :         },
     246             :         [CONDITIONAL_ACE_TOKEN_NOT] = {
     247             :                 "!",
     248             :                 (SDDL_FLAG_EXPECTING_PAREN |
     249             :                  SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR |
     250             :                  SDDL_FLAG_IS_UNARY_OP),
     251             :                 SDDL_PRECEDENCE_NOT,
     252             :                 1
     253             :         },
     254             :         [CONDITIONAL_ACE_TOKEN_EXISTS] = {
     255             :                 "Exists",
     256             :                 SDDL_FLAGS_EXISTS_OP,
     257             :                 SDDL_PRECEDENCE_EXISTS,
     258             :                 1
     259             :         },
     260             :         [CONDITIONAL_ACE_TOKEN_NOT_EXISTS] = {
     261             :                 "Not_Exists",
     262             :                 SDDL_FLAGS_EXISTS_OP,
     263             :                 SDDL_PRECEDENCE_EXISTS,
     264             :                 1
     265             :         },
     266             :         /* pseudo-operator pseudo-tokens */
     267             :         [CONDITIONAL_ACE_SAMBA_SDDL_PAREN] = {
     268             :                 "(",
     269             :                 0,
     270             :                 SDDL_PRECEDENCE_PAREN_START,
     271             :                 0
     272             :         },
     273             :         [CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END] = {
     274             :                 ")",
     275             :                 SDDL_FLAGS_PAREN_END,
     276             :                 SDDL_PRECEDENCE_PAREN_END,
     277             :                 0
     278             :         },
     279             : 
     280             :         /*
     281             :          * non-operators.
     282             :          * The names here are only used for error messages.
     283             :          *
     284             :          * some of them will never actually be encountered (e.g. 8-bit
     285             :          * integers).
     286             :          */
     287             :         [CONDITIONAL_ACE_TOKEN_INT8] = {
     288             :                 .name = "8-bit integer",
     289             :                 .flags = SDDL_FLAGS_LITERAL,
     290             :                 SDDL_NOT_AN_OP,
     291             :                 0
     292             :         },
     293             :         [CONDITIONAL_ACE_TOKEN_INT16] = {
     294             :                 "16-bit integer",
     295             :                 SDDL_FLAGS_LITERAL,
     296             :                 SDDL_NOT_AN_OP,
     297             :                 0
     298             :         },
     299             :         [CONDITIONAL_ACE_TOKEN_INT32] = {
     300             :                 "32-bit integer",
     301             :                 SDDL_FLAGS_LITERAL,
     302             :                 SDDL_NOT_AN_OP,
     303             :                 0
     304             :         },
     305             :         [CONDITIONAL_ACE_TOKEN_INT64] = {
     306             :                 "64-bit integer",
     307             :                 SDDL_FLAGS_LITERAL,
     308             :                 SDDL_NOT_AN_OP,
     309             :                 0
     310             :         },
     311             : 
     312             :         [CONDITIONAL_ACE_TOKEN_UNICODE] = {
     313             :                 "unicode",
     314             :                 SDDL_FLAGS_LITERAL,
     315             :                 SDDL_NOT_AN_OP,
     316             :                 0
     317             :         },
     318             :         [CONDITIONAL_ACE_TOKEN_OCTET_STRING] = {
     319             :                 "byte string",
     320             :                 SDDL_FLAGS_LITERAL,
     321             :                 SDDL_NOT_AN_OP,
     322             :                 0
     323             :         },
     324             :         [CONDITIONAL_ACE_TOKEN_COMPOSITE] = {
     325             :                 "composite list",
     326             :                 SDDL_FLAGS_LITERAL,
     327             :                 SDDL_NOT_AN_OP,
     328             :                 0
     329             :         },
     330             :         [CONDITIONAL_ACE_TOKEN_SID] = {
     331             :                 "SID",
     332             :                 SDDL_FLAGS_LITERAL,
     333             :                 SDDL_NOT_AN_OP,
     334             :                 0
     335             :         },
     336             :         [CONDITIONAL_ACE_LOCAL_ATTRIBUTE] = {
     337             :                 "local attribute",
     338             :                 SDDL_FLAGS_ATTRIBUTE,
     339             :                 SDDL_NOT_AN_OP,
     340             :                 0
     341             :         },
     342             :         [CONDITIONAL_ACE_USER_ATTRIBUTE] = {
     343             :                 "user attribute",
     344             :                 SDDL_FLAGS_ATTRIBUTE,
     345             :                 SDDL_NOT_AN_OP,
     346             :                 0
     347             :         },
     348             :         [CONDITIONAL_ACE_RESOURCE_ATTRIBUTE] = {
     349             :                 "resource attribute",
     350             :                 SDDL_FLAGS_ATTRIBUTE,
     351             :                 SDDL_NOT_AN_OP,
     352             :                 0
     353             :         },
     354             :         [CONDITIONAL_ACE_DEVICE_ATTRIBUTE] = {
     355             :                 "device attribute",
     356             :                 SDDL_FLAGS_ATTRIBUTE|SDDL_FLAG_DEVICE,
     357             :                 SDDL_NOT_AN_OP,
     358             :                 0
     359             :         },
     360             :         [CONDITIONAL_ACE_SAMBA_RESULT_BOOL] = {
     361             :                 "boolean result",
     362             :                 0,
     363             :                 SDDL_NOT_AN_OP,
     364             :                 0
     365             :         },
     366             :         [CONDITIONAL_ACE_SAMBA_RESULT_NULL] = {
     367             :                 "null result",
     368             :                 0,
     369             :                 SDDL_NOT_AN_OP,
     370             :                 0
     371             :         },
     372             :         [CONDITIONAL_ACE_SAMBA_RESULT_ERROR] = {
     373             :                 "error result",
     374             :                 0,
     375             :                 SDDL_NOT_AN_OP,
     376             :                 0
     377             :         },
     378             : };
     379             : 
     380             : struct sddl_attr_type{
     381             :         const char *name;
     382             :         uint8_t code;
     383             : };
     384             : 
     385             : /*
     386             :  * These are the prefixes for non-local attribute types. [MS-DTYP]
     387             :  * styles them in title case ("@User."), but Windows itself seems to
     388             :  * prefer all-caps, so that is how we render them.
     389             :  */
     390             : static const struct sddl_attr_type sddl_attr_types[] = {
     391             :         {"USER.", CONDITIONAL_ACE_USER_ATTRIBUTE},
     392             :         {"RESOURCE.", CONDITIONAL_ACE_RESOURCE_ATTRIBUTE},
     393             :         {"DEVICE.", CONDITIONAL_ACE_DEVICE_ATTRIBUTE},
     394             : };
     395             : 
     396             : 
     397             : struct sddl_write_context {
     398             :         TALLOC_CTX *mem_ctx;
     399             :         char *sddl;
     400             :         size_t len;
     401             :         size_t alloc_len;
     402             : };
     403             : 
     404        8367 : static bool sddl_write(struct sddl_write_context *ctx,
     405             :                        const char *s)
     406             : {
     407        8367 :         size_t len = strlen(s);
     408        8367 :         if (ctx->alloc_len - ctx->len <= len ||
     409        7366 :             ctx->sddl == NULL) {
     410        1001 :                 size_t old = ctx->alloc_len;
     411        1001 :                 ctx->alloc_len = old + MAX(old / 2, len + 50);
     412        1001 :                 if (ctx->alloc_len <= old ||
     413        1001 :                     ctx->alloc_len - ctx->len <= len) {
     414           0 :                         return false;
     415             :                 }
     416        1001 :                 ctx->sddl = talloc_realloc(ctx->mem_ctx, ctx->sddl,
     417             :                                            char, ctx->alloc_len);
     418             : 
     419        1001 :                 if (ctx->sddl == NULL) {
     420           0 :                         return false;
     421             :                 }
     422             :         }
     423        8367 :         memcpy(ctx->sddl + ctx->len, s, len);
     424        8367 :         ctx->len += len;
     425        8367 :         ctx->sddl[ctx->len] = 0;
     426        8367 :         return true;
     427             : }
     428             : 
     429             : /*
     430             :  * This is a helper function to create a representation of a
     431             :  * conditional ACE. This is not SDDL, more like a disassembly,
     432             :  * but it uses some of the same tables.
     433             :  */
     434           0 : char *debug_conditional_ace(TALLOC_CTX *mem_ctx,
     435             :                             struct ace_condition_script *program)
     436             : {
     437           0 :         size_t i;
     438           0 :         size_t depth = 0;
     439           0 :         char stack[] = "          ";
     440           0 :         char line[120];
     441           0 :         struct sddl_write_context ctx = {
     442             :                 .mem_ctx = mem_ctx
     443             :         };
     444             : 
     445           0 :         for (i = 0; i < program->length; i++) {
     446           0 :                 struct ace_condition_token *tok = &program->tokens[i];
     447           0 :                 struct sddl_data s = sddl_strings[tok->type];
     448           0 :                 char hex[21];
     449           0 :                 char *utf8 = NULL;
     450           0 :                 int utf8_len;
     451           0 :                 char type;
     452           0 :                 char nom[40];
     453           0 :                 snprintf(nom, sizeof(nom), "\033[1;33m%20s\033[0m", s.name);
     454           0 :                 switch (tok->type) {
     455           0 :                 case CONDITIONAL_ACE_TOKEN_INT8:
     456             :                 case CONDITIONAL_ACE_TOKEN_INT16:
     457             :                 case CONDITIONAL_ACE_TOKEN_INT32:
     458             :                 case CONDITIONAL_ACE_TOKEN_INT64:
     459           0 :                         if (tok->data.int64.sign > 3 ||
     460           0 :                             tok->data.int64.base > 3) {
     461           0 :                                 goto error;
     462             :                         }
     463           0 :                         snprintf(line, sizeof(line),
     464             :                                  "%s  %"PRIi64" %c%c\n",
     465             :                                  nom,
     466             :                                  tok->data.int64.value,
     467           0 :                                  "?+-_"[tok->data.int64.sign],
     468           0 :                                  "?odh"[tok->data.int64.base]
     469             :                                 );
     470           0 :                         type = 'i';
     471           0 :                         break;
     472             : 
     473           0 :                 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
     474             :                 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
     475             :                 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
     476             :                 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
     477             :                 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
     478             :                 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
     479             :                 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
     480             :                 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
     481           0 :                         snprintf(line, sizeof(line),
     482             :                                  "%s  bool\n",
     483             :                                  nom
     484             :                                 );
     485           0 :                         type = 'b';
     486           0 :                         break;
     487             : 
     488           0 :                 case CONDITIONAL_ACE_TOKEN_EQUAL:
     489             :                 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
     490             :                 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
     491             :                 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
     492             :                 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
     493             :                 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
     494             :                 case CONDITIONAL_ACE_TOKEN_CONTAINS:
     495             :                 case CONDITIONAL_ACE_TOKEN_ANY_OF:
     496             :                 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
     497             :                 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
     498             :                 case CONDITIONAL_ACE_TOKEN_AND:
     499             :                 case CONDITIONAL_ACE_TOKEN_OR:
     500           0 :                         snprintf(line, sizeof(line),
     501             :                                  "%s  bool\n",
     502             :                                  nom
     503             :                                 );
     504           0 :                         type = 'b';
     505           0 :                         break;
     506             : 
     507           0 :                 case CONDITIONAL_ACE_TOKEN_EXISTS:
     508             :                 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
     509             :                 case CONDITIONAL_ACE_TOKEN_NOT:
     510           0 :                         snprintf(line, sizeof(line),
     511             :                                  "%s  bool\n",
     512             :                                  nom
     513             :                                 );
     514           0 :                         type = 'b';
     515           0 :                         break;
     516             : 
     517           0 :                 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
     518             :                 case CONDITIONAL_ACE_USER_ATTRIBUTE:
     519             :                 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
     520             :                 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
     521           0 :                         snprintf(line, sizeof(line),
     522             :                                  "%s.%s  (any type)\n",
     523             :                                  nom,
     524             :                                  tok->data.unicode.value
     525             :                                 );
     526           0 :                         type = '?';
     527           0 :                         break;
     528             : 
     529           0 :                 case CONDITIONAL_ACE_TOKEN_UNICODE:
     530           0 :                         snprintf(line, sizeof(line),
     531             :                                  "%s.%s  (any type)\n",
     532             :                                  nom,
     533             :                                  tok->data.unicode.value
     534             :                                 );
     535           0 :                         type = 'u';
     536           0 :                         break;
     537             : 
     538           0 :                 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
     539           0 :                         utf8_len = MIN(tok->data.bytes.length, 9);
     540           0 :                         hex_encode_buf(hex, tok->data.bytes.data, utf8_len);
     541             : 
     542           0 :                         snprintf(line, sizeof(line),
     543             :                                  "%s %.*s (%d)\n",
     544             :                                  nom, utf8_len * 2, hex, utf8_len);
     545           0 :                         type = 'o';
     546           0 :                         break;
     547           0 :                 case CONDITIONAL_ACE_TOKEN_SID:
     548           0 :                         utf8 = sddl_encode_sid(mem_ctx,
     549           0 :                                                &tok->data.sid.sid,
     550             :                                                NULL);
     551           0 :                         snprintf(line, sizeof(line),
     552             :                                  "%s (%s)\n",
     553             :                                  nom, utf8);
     554           0 :                         type = 'S';
     555           0 :                         break;
     556           0 :                 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
     557           0 :                         snprintf(line, sizeof(line),
     558             :                                  "%s %"PRIu32" direct members\n",
     559             :                                  nom, tok->data.composite.n_members);
     560           0 :                         type = 'C';
     561           0 :                         break;
     562             : 
     563           0 :                 case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
     564           0 :                         snprintf(line, sizeof(line),
     565             :                                  "%s\n", nom);
     566           0 :                         type = '0';
     567           0 :                         break;
     568           0 :                 default:
     569           0 :                         snprintf(line, sizeof(line),
     570           0 :                                  "unknown opcode %#02x\n", tok->type);
     571           0 :                         type = '!';
     572           0 :                         break;
     573             :                 }
     574             : 
     575           0 :                 if (s.nargs > depth) {
     576           0 :                         snprintf(nom, sizeof(nom),
     577           0 :                                  "UNDER: -%zu", s.nargs - depth);
     578           0 :                         depth = 0;
     579           0 :                         sddl_write(&ctx, nom);
     580           0 :                 } else if (depth >= strlen(stack)) {
     581           0 :                         snprintf(nom, sizeof(nom),
     582           0 :                                  "depth %zu", s.nargs - depth);
     583           0 :                         depth -= (s.nargs - 1);
     584           0 :                         sddl_write(&ctx, nom);
     585             :                 } else {
     586           0 :                         depth -= s.nargs;
     587           0 :                         stack[depth] = type;
     588           0 :                         depth++;
     589           0 :                         if (depth < strlen(stack)) {
     590           0 :                                 stack[depth] = ' ';
     591             :                         }
     592           0 :                         sddl_write(&ctx, stack);
     593             :                 }
     594           0 :                 sddl_write(&ctx, line);
     595             :         }
     596           0 :         if (depth == 1 && stack[0] == 'b') {
     597           0 :                 snprintf(line, sizeof(line),
     598             :                          "\033[1;32mGOOD: finishes on a single bool\033[0m\n");
     599             :         } else {
     600           0 :                 snprintf(line, sizeof(line),
     601             :                          "\033[1;31mBAD: should finish with a bool\033[0m\n");
     602             :         }
     603           0 :         sddl_write(&ctx, line);
     604           0 :         return ctx.sddl;
     605             : 
     606           0 :   error:
     607           0 :         TALLOC_FREE(ctx.sddl);
     608           0 :         return NULL;
     609             : }
     610             : 
     611             : 
     612             : struct sddl_node {
     613             :         struct ace_condition_token *tok;
     614             :         struct sddl_node *lhs;
     615             :         struct sddl_node *rhs;
     616             :         bool wants_parens;
     617             : };
     618             : 
     619         153 : static bool sddl_write_int(struct sddl_write_context *ctx,
     620             :                            const struct ace_condition_token *tok)
     621             : {
     622         153 :         int64_t v = tok->data.int64.value;
     623         153 :         uint8_t sign = tok->data.int64.sign;
     624         153 :         uint8_t base = tok->data.int64.base;
     625          81 :         char buf[26]; /* oct(1<<63) + sign + \0 */
     626          81 :         char sign_char;
     627         153 :         if (sign > CONDITIONAL_ACE_INT_SIGN_NONE ||
     628          81 :             base > CONDITIONAL_ACE_INT_BASE_16) {
     629           0 :                 return false;
     630             :         }
     631             : 
     632             :         /*
     633             :          * we have 9 combinations of base/sign (+ some invalid combinations of
     634             :          * actual sign vs claimed sign).
     635             :          */
     636         153 :         if (sign == CONDITIONAL_ACE_INT_SIGN_NONE) {
     637             :                 /* octal and hex will end up unsigned! */
     638         139 :                 if (base == CONDITIONAL_ACE_INT_BASE_8) {
     639           6 :                         snprintf(buf, sizeof(buf), "0%"PRIo64, v);
     640         133 :                 } else if (base == CONDITIONAL_ACE_INT_BASE_10) {
     641         126 :                         snprintf(buf, sizeof(buf), "%"PRId64, v);
     642             :                 } else {
     643           7 :                         snprintf(buf, sizeof(buf), "0x%"PRIx64, v);
     644             :                 }
     645         139 :                 return sddl_write(ctx, buf);
     646             :         }
     647          14 :         if (sign == CONDITIONAL_ACE_INT_SIGN_POSITIVE && v < 0) {
     648           0 :                 return false;
     649             :         }
     650          14 :         if (sign == CONDITIONAL_ACE_INT_SIGN_NEGATIVE && v > 0) {
     651             :                 /* note we allow "-0", because we will parse it. */
     652           0 :                 return false;
     653             :         }
     654          14 :         sign_char = (sign == CONDITIONAL_ACE_INT_SIGN_NEGATIVE) ? '-' : '+';
     655             :         /*
     656             :          * We can use "%+ld" for the decimal sign (except -0), but
     657             :          * "%+lx" and "%+lo" are invalid because %o and %x are
     658             :          * unsigned.
     659             :          */
     660          14 :         if (base == CONDITIONAL_ACE_INT_BASE_10) {
     661           4 :                 if (v == 0) {
     662           4 :                         snprintf(buf, sizeof(buf), "%c0", sign_char);
     663             :                 } else {
     664           0 :                         snprintf(buf, sizeof(buf), "%+"PRId64, v);
     665             :                 }
     666           4 :                 return sddl_write(ctx, buf);
     667             :         }
     668             : 
     669          10 :         if (v == INT64_MIN) {
     670             :                 /*
     671             :                  * llabs(INT64_MIN) will be undefined.
     672             :                  * The lengths we must go to to round trip!
     673             :                  */
     674           0 :                 if (base == CONDITIONAL_ACE_INT_BASE_8) {
     675           0 :                         return sddl_write(ctx, "-01000000000000000000000");
     676             :                 }
     677           0 :                 return sddl_write(ctx, "-0x8000000000000000");
     678             :         }
     679             : 
     680          10 :         if (base == CONDITIONAL_ACE_INT_BASE_8) {
     681           6 :                 snprintf(buf, sizeof(buf), "%c0%llo", sign_char, llabs(v));
     682             :         } else {
     683           4 :                 snprintf(buf, sizeof(buf), "%c0x%llx", sign_char, llabs(v));
     684             :         }
     685          10 :         return sddl_write(ctx, buf);
     686             : }
     687             : 
     688             : 
     689       74159 : static bool sddl_should_escape_utf16(uint16_t c)
     690             : {
     691       74159 :         if (c <= ' ' || c > 126) {
     692       44176 :                 return true;
     693             :         }
     694             : 
     695       29789 :         switch (c) {
     696         120 :         case '!':
     697             :         case '"':
     698             :         case '&':
     699             :         case '(':
     700             :         case ')':
     701             :         case '<':
     702             :         case '=':
     703             :         case '>':
     704             :         case '|':
     705             :         case '%':
     706         120 :                 return true;
     707             :         }
     708             : 
     709       28895 :         return false;
     710             : }
     711             : 
     712         847 : static bool sddl_encode_attr_name(TALLOC_CTX *mem_ctx,
     713             :                                   const char *src,
     714             :                                   char **dest,
     715             :                                   size_t *dest_len)
     716             : {
     717         181 :         size_t i, j;
     718         181 :         bool ok;
     719         847 :         uint16_t *utf16 = NULL;
     720         847 :         char *escaped = NULL;
     721         181 :         size_t utf16_byte_len;
     722         181 :         size_t utf16_len;
     723         847 :         size_t src_len = strlen(src);
     724         181 :         size_t escapees;
     725         181 :         size_t required;
     726         847 :         *dest = NULL;
     727             : 
     728             :         /*
     729             :          * Writing the string escapes can only really happen in
     730             :          * utf-16.
     731             :          */
     732         847 :         ok = convert_string_talloc(mem_ctx,
     733             :                                    CH_UTF8, CH_UTF16LE,
     734             :                                    src, src_len,
     735             :                                    &utf16, &utf16_byte_len);
     736         847 :         if (!ok) {
     737           0 :                 return false;
     738             :         }
     739         847 :         utf16_len = utf16_byte_len / 2;
     740             : 
     741         847 :         escapees = 0;
     742       52268 :         for (i = 0; i < utf16_len; i++) {
     743       51421 :                 uint16_t c = utf16[i];
     744       51421 :                 if (sddl_should_escape_utf16(c)) {
     745       22245 :                         escapees++;
     746             :                 }
     747       51421 :                 if (c == 0) {
     748             :                         /* we can't have '\0' (or "%0000") in a name. */
     749           0 :                         TALLOC_FREE(utf16);
     750           0 :                         return false;
     751             :                 }
     752             :         }
     753             : 
     754         847 :         required = src_len + escapees * 5;
     755         847 :         escaped = talloc_size(mem_ctx, required + 1);
     756         847 :         if (escaped == NULL) {
     757           0 :                 TALLOC_FREE(utf16);
     758           0 :                 return false;
     759             :         }
     760             : 
     761         847 :         if (escapees == 0) {
     762             :                 /* there is nothing to escape: the original string is fine */
     763         826 :                 memcpy(escaped, src, src_len);
     764         826 :                 escaped[src_len] = '\0';
     765         826 :                 *dest = escaped;
     766         826 :                 *dest_len = src_len;
     767         826 :                 TALLOC_FREE(utf16);
     768         826 :                 return true;
     769             :         }
     770             : 
     771       22759 :         for (i = 0, j = 0; i < utf16_len && j < required; i++) {
     772       22738 :                 uint16_t c = utf16[i];
     773       22738 :                 if (sddl_should_escape_utf16(c)) {
     774       22245 :                         if (j + 5 >= required) {
     775           0 :                                 TALLOC_FREE(escaped);
     776           0 :                                 TALLOC_FREE(utf16);
     777           0 :                                 return false;
     778             :                         }
     779       22245 :                         snprintf(escaped + j, 6, "%%%04x", c);
     780       22245 :                         j += 5;
     781             :                 } else {
     782         493 :                         escaped[j] = c;
     783         493 :                         j++;
     784             :                 }
     785             :         }
     786          21 :         escaped[j] = '\0';
     787             : 
     788          21 :         *dest = escaped;
     789          21 :         *dest_len = j;
     790             : 
     791          21 :         TALLOC_FREE(utf16);
     792          18 :         return true;
     793             : }
     794             : 
     795         840 : static bool sddl_write_attr(struct sddl_write_context *ctx,
     796             :                             struct ace_condition_token *tok)
     797             : {
     798         840 :         char *name = NULL;
     799         174 :         size_t name_len;
     800         174 :         size_t i;
     801         840 :         bool ok = sddl_encode_attr_name(ctx->mem_ctx,
     802             :                                         tok->data.local_attr.value,
     803             :                                         &name, &name_len);
     804         840 :         if (!ok) {
     805           0 :                 return false;
     806             :         }
     807        1062 :         for (i = 0; i < ARRAY_SIZE(sddl_attr_types); i++) {
     808        1021 :                 struct sddl_attr_type x = sddl_attr_types[i];
     809        1021 :                 if (x.code == tok->type) {
     810         799 :                         ok = sddl_write(ctx, "@");
     811         799 :                         if (! ok) {
     812           0 :                                 return false;
     813             :                         }
     814         799 :                         ok = sddl_write(ctx, x.name);
     815         799 :                         if (! ok) {
     816           0 :                                 return false;
     817             :                         }
     818         799 :                         break;
     819             :                 }
     820             :         }
     821             : 
     822         840 :         ok = sddl_write(ctx, name);
     823         840 :         talloc_free(name);
     824         840 :         return ok;
     825             : }
     826             : 
     827             : 
     828         293 : static bool sddl_write_unicode(struct sddl_write_context *ctx,
     829             :                                const struct ace_condition_token *tok)
     830             : {
     831         293 :         char *quoted = NULL;
     832          35 :         bool ok;
     833             :         /*
     834             :          * We rely on tok->data.unicode.value being
     835             :          * nul-terminated.
     836             :          */
     837         293 :         if (strchr(tok->data.unicode.value, '"') != NULL) {
     838             :                 /*
     839             :                  * There is a double quote in this string, but SDDL
     840             :                  * has no mechanism for escaping these (or anything
     841             :                  * else) in unicode strings.
     842             :                  *
     843             :                  * The only thing to do is fail.
     844             :                  *
     845             :                  * This cannot happen with an ACE created from SDDL,
     846             :                  * because the same no-escapes rule applies on the way
     847             :                  * in.
     848             :                  */
     849           0 :                 return false;
     850             :         }
     851             : 
     852         293 :         quoted = talloc_asprintf(ctx->mem_ctx, "\"%s\"",
     853         258 :                                  tok->data.unicode.value);
     854         293 :         if (quoted == NULL) {
     855           0 :                 return false;
     856             :         }
     857         293 :         ok = sddl_write(ctx, quoted);
     858         293 :         TALLOC_FREE(quoted);
     859         293 :         return ok;
     860             : }
     861             : 
     862           7 : static bool sddl_write_octet_string(struct sddl_write_context *ctx,
     863             :                                     const struct ace_condition_token *tok)
     864             : {
     865           7 :         bool ok;
     866          14 :         char *hex  = hex_encode_talloc(ctx->mem_ctx,
     867           7 :                                        tok->data.bytes.data,
     868           7 :                                        tok->data.bytes.length);
     869           7 :         ok = sddl_write(ctx, "#");
     870           7 :         if (!ok) {
     871           0 :                 return false;
     872             :         }
     873           7 :         ok = sddl_write(ctx, hex);
     874           7 :         talloc_free(hex);
     875           7 :         return ok;
     876             : }
     877             : 
     878             : /*
     879             :  * For octet strings, the Resource attribute ACE SDDL differs from conditional
     880             :  * ACE SDDL, lacking the leading '#'.
     881             :  */
     882           6 : static bool sddl_write_ra_octet_string(struct sddl_write_context *ctx,
     883             :                                        const struct ace_condition_token *tok)
     884             : {
     885           6 :         bool ok;
     886          12 :         char *hex  = hex_encode_talloc(ctx->mem_ctx,
     887           6 :                                        tok->data.bytes.data,
     888           6 :                                        tok->data.bytes.length);
     889           6 :         ok = sddl_write(ctx, hex);
     890           6 :         talloc_free(hex);
     891           6 :         return ok;
     892             : }
     893             : 
     894             : 
     895         253 : static bool sddl_write_sid(struct sddl_write_context *ctx,
     896             :                            const struct ace_condition_token *tok)
     897             : {
     898          44 :         bool ok;
     899         253 :         char *sddl = NULL;
     900         253 :         char *sid = sddl_encode_sid(ctx->mem_ctx,
     901             :                                     &tok->data.sid.sid,
     902             :                                     NULL);
     903         253 :         if (sid == NULL) {
     904           0 :                 return false;
     905             :         }
     906         253 :         sddl = talloc_asprintf(ctx->mem_ctx, "SID(%s)", sid);
     907         253 :         if (sddl == NULL) {
     908           0 :                 talloc_free(sid);
     909           0 :                 return false;
     910             :         }
     911         253 :         ok = sddl_write(ctx, sddl);
     912         253 :         talloc_free(sid);
     913         253 :         talloc_free(sddl);
     914         253 :         return ok;
     915             : }
     916             : 
     917         280 : static bool sddl_write_composite(struct sddl_write_context *ctx,
     918             :                                  struct ace_condition_token *tok)
     919             : {
     920             :         /*
     921             :          * Looks like {1, 2, 3, "four", {"woah, nesting", {6}}, SID(BA)}.
     922             :          */
     923         280 :         struct ace_condition_composite *c = &tok->data.composite;
     924          43 :         uint32_t i;
     925          43 :         bool ok;
     926         280 :         ok = sddl_write(ctx, "{");
     927         280 :         if (!ok) {
     928           0 :                 return false;
     929             :         }
     930         683 :         for (i = 0;  i < c->n_members; i++) {
     931         403 :                 struct ace_condition_token *t = &c->tokens[i];
     932         403 :                 if (i > 0) {
     933         151 :                         ok = sddl_write(ctx, ", ");
     934         151 :                         if (!ok) {
     935           0 :                                 return false;
     936             :                         }
     937             :                 }
     938         403 :                 switch (t->type) {
     939          71 :                 case CONDITIONAL_ACE_TOKEN_INT8:
     940             :                 case CONDITIONAL_ACE_TOKEN_INT16:
     941             :                 case CONDITIONAL_ACE_TOKEN_INT32:
     942             :                 case CONDITIONAL_ACE_TOKEN_INT64:
     943          71 :                         ok = sddl_write_int(ctx, t);
     944          71 :                         break;
     945         111 :                 case CONDITIONAL_ACE_TOKEN_UNICODE:
     946         111 :                         ok = sddl_write_unicode(ctx, t);
     947         111 :                         break;
     948           0 :                 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
     949           0 :                         ok = sddl_write_octet_string(ctx, t);
     950           0 :                         break;
     951         221 :                 case CONDITIONAL_ACE_TOKEN_SID:
     952         221 :                         ok = sddl_write_sid(ctx, t);
     953         221 :                         break;
     954           0 :                 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
     955           0 :                         return false;
     956           0 :                 default:
     957           0 :                         return false;
     958             :                 }
     959         403 :                 if (!ok) {
     960           0 :                         return false;
     961             :                 }
     962             :         }
     963         280 :         ok = sddl_write(ctx, "}");
     964         280 :         return ok;
     965             : }
     966             : 
     967        2290 : static bool sddl_write_node(struct sddl_write_context *ctx,
     968             :                             struct sddl_node *node)
     969             : {
     970        2290 :         struct ace_condition_token *tok = node->tok;
     971        2290 :         switch (tok->type) {
     972          82 :                 case CONDITIONAL_ACE_TOKEN_INT8:
     973             :                 case CONDITIONAL_ACE_TOKEN_INT16:
     974             :                 case CONDITIONAL_ACE_TOKEN_INT32:
     975             :                 case CONDITIONAL_ACE_TOKEN_INT64:
     976          82 :                         return sddl_write_int(ctx, tok);
     977             : 
     978         877 :                 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
     979             :                 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
     980             :                 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
     981             :                 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
     982             :                 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
     983             :                 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
     984             :                 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
     985             :                 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
     986             :                 case CONDITIONAL_ACE_TOKEN_EQUAL:
     987             :                 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
     988             :                 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
     989             :                 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
     990             :                 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
     991             :                 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
     992             :                 case CONDITIONAL_ACE_TOKEN_CONTAINS:
     993             :                 case CONDITIONAL_ACE_TOKEN_ANY_OF:
     994             :                 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
     995             :                 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
     996             :                 case CONDITIONAL_ACE_TOKEN_AND:
     997             :                 case CONDITIONAL_ACE_TOKEN_OR:
     998             :                 case CONDITIONAL_ACE_TOKEN_EXISTS:
     999             :                 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
    1000             :                 case CONDITIONAL_ACE_TOKEN_NOT:
    1001         877 :                         return sddl_write(ctx, sddl_strings[tok->type].name);
    1002             : 
    1003         840 :                 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
    1004             :                 case CONDITIONAL_ACE_USER_ATTRIBUTE:
    1005             :                 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
    1006             :                 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
    1007         840 :                         return sddl_write_attr(ctx, tok);
    1008             : 
    1009         172 :                 case CONDITIONAL_ACE_TOKEN_UNICODE:
    1010         172 :                         return sddl_write_unicode(ctx, tok);
    1011             : 
    1012           7 :                 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
    1013           7 :                         return sddl_write_octet_string(ctx, tok);
    1014             : 
    1015          32 :                 case CONDITIONAL_ACE_TOKEN_SID:
    1016          32 :                         return sddl_write_sid(ctx, tok);
    1017             : 
    1018         280 :                 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
    1019         280 :                         return sddl_write_composite(ctx, tok);
    1020             : 
    1021           0 :                 case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
    1022             :                         /*
    1023             :                          * This is only expected at the very end, which we
    1024             :                          * can't (and don't need to) check here, but we can at
    1025             :                          * least ensure it's the end of a sub-expression.
    1026             :                          */
    1027           0 :                         return (node->rhs == NULL);
    1028           0 :                 default:
    1029           0 :                         return false;
    1030             :                 }
    1031             :         /* not expecting to get here */
    1032             :         return false;
    1033             : }
    1034             : 
    1035             : 
    1036        2575 : static inline bool sddl_wants_outer_parens(struct sddl_node *node)
    1037             : {
    1038             :         /*
    1039             :          * Binary ops (having a LHS) are always parenthesised "(a == 2)"
    1040             :          *
    1041             :          * Member-of ops are too, for some reason.
    1042             :          */
    1043        4498 :         return (node->lhs != NULL ||
    1044        1923 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_MEMBER_OF ||
    1045        1420 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF ||
    1046        1404 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY ||
    1047        1360 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY ||
    1048        1356 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF ||
    1049        1336 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF ||
    1050        6024 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY ||
    1051        1327 :                 node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY);
    1052             : }
    1053             : 
    1054             : 
    1055        1474 : static inline bool sddl_wants_inner_parens(struct sddl_node *node,
    1056             :                                            struct sddl_node *child)
    1057             : {
    1058             :         /*
    1059             :          * logical operators are serialised with parentheses around their
    1060             :          * arguments (for NOT it is obligatory).
    1061             :          */
    1062        1474 :         if (node->tok->type != CONDITIONAL_ACE_TOKEN_NOT &&
    1063        1365 :             node->tok->type != CONDITIONAL_ACE_TOKEN_AND &&
    1064         993 :             node->tok->type != CONDITIONAL_ACE_TOKEN_OR) {
    1065         903 :                 return false;
    1066             :         }
    1067         345 :         if (sddl_wants_outer_parens(child)) {
    1068          74 :                 return false;
    1069             :         }
    1070         168 :         return true;
    1071             : }
    1072             : 
    1073             : 
    1074        2065 : static void sddl_tree_resolve_parens(struct sddl_node *node)
    1075             : {
    1076        2661 :         if (sddl_wants_outer_parens(node)) {
    1077         800 :                 node->wants_parens = true;
    1078             :         }
    1079        2290 :         if (node->lhs != NULL) {
    1080         597 :                 bool p = sddl_wants_inner_parens(node, node->lhs);
    1081         597 :                 node->lhs->wants_parens = p;
    1082         597 :                 sddl_tree_resolve_parens(node->lhs);
    1083             :         }
    1084        2290 :         if (node->rhs != NULL) {
    1085         877 :                 bool p = sddl_wants_inner_parens(node, node->rhs);
    1086         877 :                 node->rhs->wants_parens = p;
    1087         877 :                 sddl_tree_resolve_parens(node->rhs);
    1088             :         }
    1089        2065 : }
    1090             : 
    1091        2290 : static bool sddl_tree_to_sddl(struct sddl_write_context *ctx,
    1092             :                               struct sddl_node *node)
    1093             : {
    1094         531 :         bool ok;
    1095        2290 :         if (node->wants_parens) {
    1096        1105 :                 ok = sddl_write(ctx, "(");
    1097        1105 :                 if (! ok) {
    1098           0 :                         return false;
    1099             :                 }
    1100             :         }
    1101             : 
    1102        2290 :         if (node->lhs != NULL) {
    1103         597 :                 ok = sddl_tree_to_sddl(ctx, node->lhs);
    1104         597 :                 if (! ok) {
    1105           0 :                         return false;
    1106             :                 }
    1107         597 :                 ok = sddl_write(ctx, " ");
    1108         597 :                 if (!ok) {
    1109           0 :                         return false;
    1110             :                 }
    1111             :         }
    1112             : 
    1113        2290 :         ok = sddl_write_node(ctx, node);
    1114        2290 :         if (!ok) {
    1115           0 :                 return false;
    1116             :         }
    1117        2290 :         if (node->rhs != NULL) {
    1118             :                 /* NOT is a special case: "!(x)", not "! (x)" */
    1119         877 :                 if (node->tok->type != CONDITIONAL_ACE_TOKEN_NOT) {
    1120         806 :                         ok = sddl_write(ctx, " ");
    1121         806 :                         if (!ok) {
    1122           0 :                                 return false;
    1123             :                         }
    1124             :                 }
    1125             : 
    1126         877 :                 ok = sddl_tree_to_sddl(ctx, node->rhs);
    1127         877 :                 if (! ok) {
    1128           0 :                         return false;
    1129             :                 }
    1130             :         }
    1131        2290 :         if (node->wants_parens) {
    1132        1105 :                 ok = sddl_write(ctx, ")");
    1133        1105 :                 if (!ok) {
    1134           0 :                         return false;
    1135             :                 }
    1136             :         }
    1137        1759 :         return true;
    1138             : }
    1139             : 
    1140             : /*
    1141             :  * Convert conditional ACE conditions into SDDL conditions.
    1142             :  *
    1143             :  * @param mem_ctx
    1144             :  * @param program
    1145             :  * @return a string or NULL on error.
    1146             :  */
    1147         816 : char *sddl_from_conditional_ace(TALLOC_CTX *mem_ctx,
    1148             :                                 struct ace_condition_script *program)
    1149             : {
    1150         146 :         size_t i;
    1151         816 :         char *sddl = NULL;
    1152         816 :         struct sddl_node *nodes = NULL;
    1153         816 :         struct sddl_node **trees = NULL;
    1154         816 :         size_t n_trees = 0;
    1155         816 :         struct ace_condition_token *tok = NULL;
    1156         146 :         struct sddl_data s;
    1157         146 :         bool ok;
    1158         816 :         struct sddl_write_context ctx = {
    1159             :                 .mem_ctx = mem_ctx
    1160             :         };
    1161             : 
    1162         816 :         if (program->length == 0) {
    1163             :                 /*
    1164             :                  * The empty program is a special case.
    1165             :                  */
    1166           0 :                 return talloc_strdup(mem_ctx, "()");
    1167             :         }
    1168         816 :         nodes = talloc_zero_array(mem_ctx,
    1169             :                                   struct sddl_node,
    1170             :                                   program->length);
    1171         816 :         if (nodes == NULL) {
    1172           0 :                 talloc_free(sddl);
    1173           0 :                 return NULL;
    1174             :         }
    1175         816 :         trees = talloc_array(mem_ctx,
    1176             :                              struct sddl_node*,
    1177             :                              program->length);
    1178         816 :         if (trees == NULL) {
    1179           0 :                 talloc_free(sddl);
    1180           0 :                 talloc_free(nodes);
    1181           0 :                 return NULL;
    1182             :         }
    1183             : 
    1184             :         /*
    1185             :          * This loop constructs a tree, which we then traverse to get the
    1186             :          * SDDL. Consider this transformation:
    1187             :          *
    1188             :          * {A, B, ==, C, D, ==, &&}  =>  "((A == B) && (C == D))"
    1189             :          *
    1190             :          * We keep an array of sub-trees, and add to it in sequence. When the
    1191             :          * thing we're adding takes arguments, we pop those off the tree list.
    1192             :          * So it would go through this sequence:
    1193             :          *
    1194             :          * len  items
    1195             :          * 1:     A
    1196             :          * 2:     A, B
    1197             :          * 1:     ==(A, B)
    1198             :          * 2:     ==(A, B), C
    1199             :          * 3:     ==(A, B), C, D
    1200             :          * 2:     ==(A, B), ==(C, D)
    1201             :          * 1      &&(==(A, B), ==(C, D))
    1202             :          *
    1203             :          * Without building a tree it would be difficult to know how many
    1204             :          * parentheses to put before A.
    1205             :          *
    1206             :          * (A == B == C) should become
    1207             :          * {A B == C ==} which should be the same as
    1208             :          * ((A == B) == C)
    1209             :          */
    1210             : 
    1211        3106 :         for (i = 0; i < program->length; i++) {
    1212        2290 :                 tok = &program->tokens[i];
    1213        2290 :                 s = sddl_strings[tok->type];
    1214        2290 :                 nodes[i].tok = tok;
    1215        2290 :                 if (s.nargs > n_trees) {
    1216           0 :                         goto error;
    1217             :                 }
    1218        2290 :                 if (s.nargs >= 1) {
    1219             :                         /*
    1220             :                          * Read this note if you're trying to follow
    1221             :                          * [MS-DTYP]. MS-DTYP uses 'LHS' to describe the
    1222             :                          * operand of unary operators even though they are
    1223             :                          * always displayed on the right of the operator. It
    1224             :                          * makes everything much simpler to use rhs
    1225             :                          * instead.
    1226             :                          */
    1227         877 :                         n_trees--;
    1228         877 :                         nodes[i].rhs = trees[n_trees];
    1229             : 
    1230         877 :                         if (s.nargs == 2) {
    1231         597 :                                 n_trees--;
    1232         597 :                                 nodes[i].lhs = trees[n_trees];
    1233             :                         }
    1234             :                 }
    1235        2290 :                 trees[n_trees] = &nodes[i];
    1236        2290 :                 n_trees++;
    1237             :         }
    1238             : 
    1239         816 :         if (n_trees != 1) {
    1240           0 :                 goto error;
    1241             :         }
    1242             : 
    1243             :         /*
    1244             :          * First we walk the tree to work out where to put parentheses (to
    1245             :          * match the canonical Windows representation).
    1246             :          *
    1247             :          * Doing it in the same traverse as the writing would be possible but
    1248             :          * trickier to get right.
    1249             :          */
    1250         816 :         sddl_tree_resolve_parens(trees[0]);
    1251         816 :         trees[0]->wants_parens = true;
    1252             : 
    1253             :         /*
    1254             :          * Clamber over the tree, writing the string.
    1255             :          */
    1256         816 :         ok = sddl_tree_to_sddl(&ctx, trees[0]);
    1257             : 
    1258         816 :         if (! ok) {
    1259           0 :                 goto error;
    1260             :         }
    1261             : 
    1262         816 :         talloc_free(trees);
    1263         816 :         talloc_free(nodes);
    1264         816 :         return ctx.sddl;
    1265             : 
    1266           0 :   error:
    1267           0 :         talloc_free(sddl);
    1268           0 :         talloc_free(trees);
    1269           0 :         talloc_free(nodes);
    1270           0 :         return NULL;
    1271             : }
    1272             : 
    1273             : 
    1274             : 
    1275             : static void comp_error(struct ace_condition_sddl_compiler_context *comp,
    1276             :                        const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
    1277             : 
    1278          43 : static void comp_error(struct ace_condition_sddl_compiler_context *comp,
    1279             :                        const char *fmt, ...)
    1280             : {
    1281          43 :         char *msg = NULL;
    1282          39 :         va_list ap;
    1283          43 :         va_start(ap, fmt);
    1284          43 :         msg = talloc_vasprintf(comp->mem_ctx, fmt, ap);
    1285          43 :         va_end(ap);
    1286          43 :         if (msg == NULL) {
    1287           0 :                 goto fail;
    1288             :         }
    1289             : 
    1290          43 :         if (comp->message == NULL) {
    1291             :                 /*
    1292             :                  * Previously unset message; prepend the position.
    1293             :                  *
    1294             :                  * This is the common case.
    1295             :                  */
    1296          43 :                 comp->message_offset = comp->offset;
    1297          43 :                 comp->message = msg;
    1298          43 :                 return;
    1299             :         }
    1300             :         /*
    1301             :          * There's a message already so we'll try to append.
    1302             :          * This is unlikely to happen.
    1303             :          */
    1304           0 :         comp->message = talloc_asprintf(comp->mem_ctx,
    1305             :                                         "%s AND THEN %s",
    1306             :                                         comp->message,
    1307             :                                         msg);
    1308           0 :         TALLOC_FREE(msg);
    1309           0 :         if (comp->message == NULL) {
    1310           0 :                 goto fail;
    1311             :         }
    1312           0 :         DBG_NOTICE("%s\n", comp->message);
    1313           0 :         return;
    1314           0 : fail:
    1315           0 :         comp->message = talloc_strdup(comp->mem_ctx,
    1316             :                                       "failed to set error message");
    1317           0 :         DBG_WARNING("%s\n", comp->message);
    1318             : }
    1319             : 
    1320             : 
    1321             : 
    1322             : 
    1323             : /*
    1324             : conditional-ace = "(" conditional-ace-type ";" [ace-flag-string] ";" ace-rights
    1325             : ";" [object- guid] ";" [inherit-object-guid] ";" sid-string ";" "(" cond-expr
    1326             : ")" ")"
    1327             : 
    1328             : wspace = 1*(%x09-0D / %x20)
    1329             : 
    1330             : literal-SID = "SID(" sid-string ")"
    1331             : 
    1332             : term = [wspace] (memberof-op / exists-op / rel-op / contains-op / anyof-op /
    1333             : attr-name / rel- op2) [wspace]
    1334             : 
    1335             : cond-expr = term / term [wspace] ("||" / "&&" ) [wspace] cond-expr / (["!"]
    1336             : [wspace] "(" cond-expr ")")
    1337             : 
    1338             : memberof-op = ( "Member_of" / "Not_Member_of" / "Member_of_Any" /
    1339             : "Not_Member_of_Any" / "Device_Member_of" / "Device_Member_of_Any" /
    1340             : "Not_Device_Member_of" / "Not_Device_Member_of_Any" ) wspace sid-array
    1341             : 
    1342             : exists-op = ( "Exists" / "Not_Exists") wspace attr-name
    1343             : 
    1344             : rel-op = attr-name [wspace] ("<" / "<=" / ">" / ">=") [wspace] (attr-name2 /
    1345             : value) ; only scalars
    1346             : 
    1347             : rel-op2 = attr-name [wspace] ("==" / "!=") [wspace] ( attr-name2 / value-array )
    1348             : ; scalar or list
    1349             : 
    1350             : contains-op = attr-name wspace ("Contains" / "Not_Contains") wspace (attr-name2
    1351             : / value- array)
    1352             : 
    1353             : anyof-op = attr-name wspace ("Any_of" / "Not_Any_of") wspace (attr-name2 /
    1354             : value-array)
    1355             : 
    1356             : 
    1357             : attr-name1 = attr-char1 *(attr-char1 / "@")
    1358             : 
    1359             : attr-char1 = 1*(ALPHA / DIGIT / ":" / "." / "/" / "_")
    1360             : 
    1361             : 
    1362             : 
    1363             : attr-name2 = ("@user." / "@device." / "@resource.") 1*attr-char2
    1364             : ; new prefixed name form
    1365             : attr-char2 = attr-char1 / lit-char
    1366             : attr-name = attr-name1 / attr-name2
    1367             :  */
    1368             : 
    1369             : 
    1370             : 
    1371      135044 : static inline bool is_wspace(uint8_t c)
    1372             : {
    1373             :         /* wspace := %x09-0D | %x20 */
    1374      100353 :         return (c == ' ' || c == '\x09' || c == '\x0A' ||
    1375      215358 :                 c == '\x0B' || c == '\x0C' || c == '\x0D');
    1376             : }
    1377             : 
    1378       14946 : static inline bool is_attr_char1(uint8_t c)
    1379             : {
    1380             :         /*
    1381             :          * attr-char1 = 1*(ALPHA / DIGIT / ":" / "." / "/" / "_")
    1382             :          * (ALPHA and DIGIT being ASCII only).
    1383             :          *
    1384             :          * These are used for local attributes, which we don't really
    1385             :          * expect to see in Samba AD.
    1386             :          *
    1387             :          * One example is "WIN://SYSAPPID", which is used in conditional ACEs
    1388             :          * that seem to relate to software installers; another is
    1389             :          * "APPID://PATH", used by Windows Applocker.
    1390             :          */
    1391       14946 :         return (((c >= 'a') && (c <= 'z')) ||
    1392        2263 :                 ((c >= 'A') && (c <= 'Z')) ||
    1393        1255 :                 ((c >= '0') && (c <= '9')) ||
    1394       20017 :                 c == ':' || c == '.' || c == '/' || c == '_');
    1395             : }
    1396             : 
    1397             : 
    1398        1696 : static ssize_t read_attr2_string(
    1399             :         struct ace_condition_sddl_compiler_context *comp,
    1400             :         struct ace_condition_unicode *dest)
    1401             : {
    1402             :         /*
    1403             :          * our SDDL is utf-8, but we need to convert to utf-16 and
    1404             :          * parse the escapes, then back to utf-8, because that's how
    1405             :          * the claims will appear.
    1406             :          *
    1407             :          * attr_char2 is used for attribute names that follow "@Class."
    1408             :          * specifiers. They can consume 5 characters to specify a single code
    1409             :          * unit, using "%1234" style escapes. Certain characters must be
    1410             :          * encoded this way, while others must be literal values. Because the
    1411             :          * %1234 refers to a utf-16 code unit, we really need to do the work
    1412             :          * in that codespace.
    1413             :          */
    1414        1057 :         bool ok;
    1415        1696 :         uint16_t *utf16 = NULL;
    1416        1057 :         size_t utf16_byte_len;
    1417        1057 :         size_t utf16_chars;
    1418        1057 :         size_t utf8_len;
    1419        1057 :         size_t src_len;
    1420        1057 :         ssize_t i, j;
    1421        1696 :         ssize_t max_len = comp->length - comp->offset;
    1422        1696 :         const uint8_t *src = comp->sddl + comp->offset;
    1423             : 
    1424       96061 :         for (i = 0; i < max_len; i++) {
    1425       96061 :                 uint8_t c = src[i];
    1426             :                 /*
    1427             :                  * A double‐byte that must be escaped but isn't tells us that
    1428             :                  * the attribute name has ended.
    1429             :                  *
    1430             :                  * The exception is '%', which must also be escaped
    1431             :                  * (as "%0025"), but is obviously still expected in
    1432             :                  * the escaped string.
    1433             :                  */
    1434      116100 :                 if (strchr("!&()><=| \"", c) != NULL || is_wspace(c)) {
    1435             :                         break;
    1436             :                 }
    1437             :         }
    1438        1696 :         if (i == max_len) {
    1439             :                 /* too long, because we need at least one ')' */
    1440           0 :                 comp_error(comp, "interminable attribute name");
    1441           0 :                 return -1;
    1442             :         }
    1443        1696 :         if (i == 0) {
    1444             :                 /* too short! like "User.>= 4" */
    1445           0 :                 comp_error(comp, "empty attribute name");
    1446           0 :                 return -1;
    1447             :         }
    1448             : 
    1449        1696 :         if (unlikely(i > CONDITIONAL_ACE_MAX_LENGTH)) {
    1450             :                 /*
    1451             :                  * This is imprecise; the limit for the whole ACL is 64k.
    1452             :                  * However there could be many escapes in the SDDL name which
    1453             :                  * would reduce down to single utf16 code units in the
    1454             :                  * compiled string.
    1455             :                  */
    1456           0 :                 comp_error(comp, "attribute is way too long (%zu)", i);
    1457           0 :                 return -1;
    1458             :         }
    1459             : 
    1460        1696 :         src_len = i;
    1461             : 
    1462        1696 :         ok = convert_string_talloc(comp->mem_ctx,
    1463             :                                    CH_UTF8, CH_UTF16LE,
    1464             :                                    src, src_len,
    1465             :                                    &utf16, &utf16_byte_len);
    1466        1696 :         if (!ok) {
    1467           0 :                 comp_error(comp, "could not convert to utf-16");
    1468           0 :                 return -1;
    1469             :         }
    1470             :         /*
    1471             :          * utf16_byte_len is in bytes, we want to count uint16s.
    1472             :          */
    1473        1696 :         utf16_chars = utf16_byte_len / 2;
    1474             : 
    1475             :         /* now the escapes. */
    1476        1696 :         for (i = 0, j = 0;
    1477       66029 :              j < utf16_chars && i < utf16_chars;
    1478       64333 :              j++) {
    1479       64336 :                 uint16_t c = utf16[i];
    1480       64336 :                 if (c == '%') {
    1481        1513 :                         uint16_t v = 0;
    1482        1513 :                         size_t end = i + 5;
    1483             :                         /*
    1484             :                          * we need to read 4 hex characters.
    1485             :                          * hex_byte() won't help because that is 8-bit.
    1486             :                          */
    1487        1513 :                         if (end > utf16_chars) {
    1488           0 :                                 comp_error(comp,
    1489             :                                            "insufficient room for %% escape");
    1490           0 :                                 talloc_free(utf16);
    1491           0 :                                 return -1;
    1492             :                         }
    1493        7565 :                         for (i++; i < end; i++) {
    1494        6052 :                                 v <<= 4;
    1495        6052 :                                 c = utf16[i];
    1496        6052 :                                 if (c >= '0' && c <= '9') {
    1497        5633 :                                         v += c - '0';
    1498         419 :                                 } else if (c >= 'A' && c <= 'F') {
    1499           0 :                                         v += c - 'A' + 10;
    1500         419 :                                 } else if (c >= 'a' && c <= 'f') {
    1501         419 :                                         v += c - 'a' + 10;
    1502             :                                 } else {
    1503           0 :                                         comp_error(comp, "invalid %% escape");
    1504           0 :                                         talloc_free(utf16);
    1505           0 :                                         return -1;
    1506             :                                 }
    1507             :                         }
    1508             :                         /*
    1509             :                          * from MS-DTYP 2.5.1.1 Syntax (text, not ABNF), some
    1510             :                          * characters must be literals, not escaped.
    1511             :                          */
    1512        1513 :                         if ((v >= '0' && v <= '9') ||
    1513        1513 :                             (v >= 'A' && v <= 'Z') ||
    1514        1513 :                             (v >= 'a' && v <= 'z') ||
    1515        1447 :                             (v < 127 &&
    1516        1447 :                              strchr("#$'*+-;?@[\\]^_`{}~:/.", v) != NULL)) {
    1517           3 :                                 comp_error(comp, "invalid %% escape: "
    1518             :                                            "'%%%04x' should be literal '%c'",
    1519             :                                            v, v);
    1520           3 :                                 talloc_free(utf16);
    1521           3 :                                 return -1;
    1522             :                         }
    1523        1510 :                         utf16[j] = v;
    1524        1510 :                         continue;
    1525             :                 }
    1526             :                 /*
    1527             :                  * Note the characters "!&()><=|% \"" must be escaped per
    1528             :                  * [MS-DTYP], but as we found the bounds of this string using
    1529             :                  * those in utf-8 at the top of this function, we are not
    1530             :                  * going to find them in the utf-16 now.
    1531             :                  *
    1532             :                  * Also, per [MS-DTYP], un-escaped whitespace is allowed, but
    1533             :                  * effectively disallowed by Samba.
    1534             :                  */
    1535       62823 :                 utf16[j] = utf16[i];
    1536       62823 :                 i++;
    1537             :         }
    1538             : 
    1539        2747 :         ok = convert_string_talloc(comp->mem_ctx,
    1540             :                                    CH_UTF16LE, CH_UTF8,
    1541        1693 :                                    utf16, j * 2,
    1542        1693 :                                    &dest->value, &utf8_len);
    1543        1693 :         TALLOC_FREE(utf16);
    1544        1693 :         if (!ok) {
    1545           0 :                 comp_error(comp, "could not convert to utf-16");
    1546           0 :                 return -1;
    1547             :         }
    1548             : 
    1549             :         /* returning bytes consumed, not necessarily the length of token */
    1550         639 :         return src_len;
    1551             : }
    1552             : 
    1553             : 
    1554             : 
    1555       31758 : static bool eat_whitespace(struct ace_condition_sddl_compiler_context *comp,
    1556             :                            bool trailing)
    1557             : {
    1558             :         /*
    1559             :          * Advance the offset to the first non-whitespace character.
    1560             :          *
    1561             :          * If trailing is false, there has to be something before the end of
    1562             :          * the string.
    1563             :          */
    1564       40760 :         while (comp->offset < comp->length) {
    1565       48485 :                 if (! is_wspace(comp->sddl[comp->offset])) {
    1566        5988 :                         break;
    1567             :                 }
    1568        9002 :                 comp->offset++;
    1569             :         }
    1570       31758 :         if ((!trailing) && comp->offset == comp->length) {
    1571           0 :                 comp_error(comp, "input ends unexpectedly");
    1572           0 :                 return false;
    1573             :         }
    1574        5988 :         return true;
    1575             : }
    1576             : 
    1577             : static bool pop_sddl_token(struct ace_condition_sddl_compiler_context *comp,
    1578             :                            struct ace_condition_token *token);
    1579             : 
    1580             : static bool write_sddl_token(struct ace_condition_sddl_compiler_context *comp,
    1581             :                              struct ace_condition_token token);
    1582             : 
    1583             : static bool pop_write_sddl_token(
    1584             :         struct ace_condition_sddl_compiler_context *comp);
    1585             : 
    1586             : 
    1587        7074 : static bool flush_stack_tokens(struct ace_condition_sddl_compiler_context *comp,
    1588             :                                uint8_t type)
    1589             : {
    1590        4795 :         bool ok;
    1591        7074 :         uint8_t precedence = sddl_strings[type].op_precedence;
    1592        7074 :         if (precedence == SDDL_PRECEDENCE_PAREN_START) {
    1593             :                 /* paren has a special role */
    1594         787 :                 return true;
    1595             :         }
    1596             :         /*
    1597             :          * Any operators on the top of the stack that have a "higher"
    1598             :          * precedence (tighter binding) to this one get popped off and written
    1599             :          * to the output. "higher" is in quotes because it means lower enum
    1600             :          * value.
    1601             :          *
    1602             :          * This works for binary operators, for example, with "(a == b == c)"
    1603             :          * (which is equivalent to "((a == b) == c)" via the left-to-right
    1604             :          * rule), we have:
    1605             :          * TOKEN dest  PROGRAM            STACK
    1606             :          *   (
    1607             :          *   a    p
    1608             :          *   ==   s       a
    1609             :          *   b    p       a                ==
    1610             :          *   ==   s       a b              ==
    1611             :          *                                        flush stack
    1612             :          *        s->p    a b              == ==
    1613             :          *   c    p       a b ==
    1614             :          *   )            a b == c         ==
    1615             :          *                                        flush stack
    1616             :          *                a b == c ==
    1617             :          *
    1618             :          * but it is not right for unary operators, as in "(!(!(Exists
    1619             :          * a)))". As it turns out though, >= works for the unary
    1620             :          * operators and syntactic rules we have.
    1621             :          */
    1622        6810 :         while (comp->stack_depth > 0) {
    1623        6810 :                 struct ace_condition_token *op =
    1624        6810 :                         &comp->stack[comp->stack_depth - 1];
    1625        6810 :                 if(sddl_strings[op->type].op_precedence > precedence) {
    1626        1492 :                         break;
    1627             :                 }
    1628        2185 :                 if(sddl_strings[op->type].op_precedence == precedence &&
    1629           9 :                    sddl_strings[op->type].flags & SDDL_FLAG_IS_UNARY_OP) {
    1630           0 :                         break;
    1631             :                 }
    1632             : 
    1633        2185 :                 ok = pop_write_sddl_token(comp);
    1634        2185 :                 if (! ok) {
    1635           0 :                         comp_error(comp,
    1636             :                                    "could not flush '%s' to program",
    1637           0 :                                    sddl_strings[op->type].name);
    1638           0 :                         return false;
    1639             :                 }
    1640             :         }
    1641        1492 :         return true;
    1642             : }
    1643             : 
    1644        4664 : static bool push_sddl_token(struct ace_condition_sddl_compiler_context *comp,
    1645             :                             struct ace_condition_token token)
    1646             : {
    1647        4664 :         if (comp->stack_depth >= CONDITIONAL_ACE_MAX_TOKENS - 1) {
    1648           0 :                 comp_error(comp, "excessive recursion");
    1649           0 :                 return false;
    1650             :         }
    1651        4664 :         if (sddl_strings[token.type].op_precedence == SDDL_NOT_AN_OP) {
    1652           0 :                 comp_error(comp,
    1653             :                            "wrong kind of token for the SDDL stack: %s",
    1654           0 :                            sddl_strings[token.type].name);
    1655           0 :                 return false;
    1656             :         }
    1657             :         /*
    1658             :          * Any operators on the top of the stack that have a "greater" or
    1659             :          * equal precedence to this one get popped off and written to the
    1660             :          * output.
    1661             :          */
    1662        4664 :         flush_stack_tokens(comp, token.type);
    1663             : 
    1664        4664 :         token.data.op.sddl_position = comp->offset;
    1665             : 
    1666        4664 :         comp->stack[comp->stack_depth] = token;
    1667        4664 :         comp->stack_depth++;
    1668        4664 :         if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
    1669        2215 :                 comp->last_token_type = token.type;
    1670             :         }
    1671        1496 :         return true;
    1672             : }
    1673             : 
    1674        2185 : static bool pop_sddl_token(struct ace_condition_sddl_compiler_context *comp,
    1675             :                             struct ace_condition_token *token)
    1676             : {
    1677        2185 :         if (comp->stack_depth == 0) {
    1678           0 :                 comp_error(comp, "misbalanced expression");
    1679           0 :                 return false;
    1680             :         }
    1681        2185 :         comp->stack_depth--;
    1682        2185 :         *token = comp->stack[comp->stack_depth];
    1683        2185 :         return true;
    1684             : }
    1685             : 
    1686             : 
    1687       13005 : static bool write_sddl_token(struct ace_condition_sddl_compiler_context *comp,
    1688             :                              struct ace_condition_token token)
    1689             : {
    1690             :         /*
    1691             :          * This is adding a token to the program. Normally it will be to the
    1692             :          * main program list, but if we are constructing a composite list, then
    1693             :          * will be redirected there (via comp->target).
    1694             :          *
    1695             :          * We also conservatively track the overall size, so we don't waste
    1696             :          * time compiling something that is way too big.
    1697             :          */
    1698       13005 :         DBG_INFO("writing %"PRIu32" %x %s\n",
    1699             :                  *comp->target_len,
    1700             :                  token.type,
    1701             :                  sddl_strings[token.type].name);
    1702       13005 :         comp->approx_size++;
    1703       13005 :         if (comp->approx_size > CONDITIONAL_ACE_MAX_TOKENS) {
    1704           0 :                 comp_error(comp, "program is too long "
    1705             :                            "(over %d tokens)",
    1706             :                            CONDITIONAL_ACE_MAX_TOKENS);
    1707           0 :                 return false;
    1708             :         }
    1709       13005 :         if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
    1710       13005 :                 comp->last_token_type = token.type;
    1711             :         }
    1712       13005 :         comp->target[*comp->target_len] = token;
    1713       13005 :         (*comp->target_len)++;
    1714       13005 :         return true;
    1715             : }
    1716             : 
    1717        2185 : static bool pop_write_sddl_token(
    1718             :         struct ace_condition_sddl_compiler_context *comp)
    1719             : {
    1720        1479 :         bool ok;
    1721        2185 :         struct ace_condition_token token = {};
    1722        2185 :         ok = pop_sddl_token(comp, &token);
    1723        2185 :         if (!ok) {
    1724           0 :                 comp_error(comp, "could not pop from op stack");
    1725           0 :                 return false;
    1726             :         }
    1727        2185 :         if (comp->target != comp->program->tokens) {
    1728           0 :                 comp_error(comp, "compiler is seriously confused");
    1729           0 :                 return false;
    1730             :         }
    1731             : 
    1732        2185 :         ok =  write_sddl_token(comp, token);
    1733        2185 :         if (!ok) {
    1734           0 :                 comp_error(comp,
    1735             :                            "could not write '%s' to program",
    1736           0 :                            sddl_strings[token.type].name);
    1737           0 :                 return false;
    1738             :         }
    1739        2185 :         DBG_INFO("    written '%s'\n", sddl_strings[token.type].name);
    1740         706 :         return true;
    1741             : }
    1742             : 
    1743             : 
    1744             : 
    1745             : static bool parse_expression(struct ace_condition_sddl_compiler_context *comp);
    1746             : static bool parse_composite(struct ace_condition_sddl_compiler_context *comp);
    1747             : 
    1748             : 
    1749             : 
    1750             : 
    1751        1395 : static bool parse_oppy_op(struct ace_condition_sddl_compiler_context *comp)
    1752             : {
    1753             :         /*
    1754             :          * These ones look like operators and are operators.
    1755             :          */
    1756        1026 :         bool ok;
    1757        1395 :         struct ace_condition_token token = {};
    1758        1026 :         uint8_t c, d;
    1759        1395 :         uint32_t flag = SDDL_FLAG_EXPECTING_BINARY_OP;
    1760             : 
    1761        1395 :         if (comp->offset + 1 >= comp->length) {
    1762           0 :                 comp_error(comp, "syntax error");
    1763           0 :                 return false;
    1764             :         }
    1765             : 
    1766        1395 :         token.data.sddl_op.start = comp->offset;
    1767             : 
    1768             :         /*
    1769             :          * These are all one or two characters long, and we always have room
    1770             :          * to peek ahead.
    1771             :          */
    1772        1395 :         c = comp->sddl[comp->offset];
    1773        1395 :         d = comp->sddl[comp->offset + 1];
    1774             : 
    1775        1395 :         if (c == '!') {
    1776         213 :                 if (d == '=') {
    1777          42 :                         comp->offset++;
    1778          42 :                         token.type = CONDITIONAL_ACE_TOKEN_NOT_EQUAL;
    1779             : 
    1780             :                 } else {
    1781         171 :                         token.type = CONDITIONAL_ACE_TOKEN_NOT;
    1782         171 :                         flag = SDDL_FLAG_EXPECTING_UNARY_OP;
    1783             :                 }
    1784        1182 :         } else if (c == '=' && d == '=') {
    1785         479 :                 comp->offset++;
    1786         479 :                 token.type = CONDITIONAL_ACE_TOKEN_EQUAL;
    1787         703 :         } else if (c == '>') {
    1788          73 :                 if (d == '=') {
    1789          19 :                         comp->offset++;
    1790          19 :                         token.type = CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL;
    1791             : 
    1792             :                 } else {
    1793          54 :                         token.type = CONDITIONAL_ACE_TOKEN_GREATER_THAN;
    1794             :                 }
    1795         630 :         } else if (c == '<') {
    1796         111 :                 if (d == '=') {
    1797          10 :                         comp->offset++;
    1798          10 :                         token.type = CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL;
    1799             : 
    1800             :                 } else {
    1801         101 :                         token.type = CONDITIONAL_ACE_TOKEN_LESS_THAN;
    1802             :                 }
    1803         519 :         } else if (c == '&' && d == '&') {
    1804         418 :                 comp->offset++;
    1805         418 :                 token.type = CONDITIONAL_ACE_TOKEN_AND;
    1806         418 :                 flag = SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP;
    1807         101 :         } else if (c == '|' && d == '|') {
    1808         100 :                 comp->offset++;
    1809         100 :                 token.type = CONDITIONAL_ACE_TOKEN_OR;
    1810         100 :                 flag = SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP;
    1811             :         } else {
    1812           1 :                 comp_error(comp, "unknown operator");
    1813           1 :                 return false;
    1814             :         }
    1815             : 
    1816        1394 :         if ((comp->state & flag) == 0) {
    1817           5 :                 comp_error(comp, "unexpected operator");
    1818           5 :                 return false;
    1819             :         }
    1820             : 
    1821        1389 :         comp->offset++;
    1822             : 
    1823        1389 :         ok = push_sddl_token(comp, token);
    1824        1389 :         if (!ok) {
    1825           0 :                 return false;
    1826             :         }
    1827             : 
    1828        1389 :         ok = eat_whitespace(comp, true);
    1829        1389 :         return ok;
    1830             : }
    1831             : 
    1832        5600 : static bool parse_unicode(struct ace_condition_sddl_compiler_context *comp)
    1833             : {
    1834             :         /*
    1835             :          * This looks like "hello" (including the double quotes).
    1836             :          *
    1837             :          * Fortunately (for now), there is no mechanism for escaping
    1838             :          * double quotes in conditional ace strings, so we can simply
    1839             :          * look for the second quote without worrying about things
    1840             :          * like «\\\"».
    1841             :          */
    1842        5600 :         struct ace_condition_token token = {};
    1843        5600 :         char *s = NULL;
    1844        5600 :         const uint8_t *src = NULL;
    1845        5600 :         char *utf16 = NULL;
    1846        5369 :         size_t len, max_len;
    1847        5369 :         bool ok;
    1848        5600 :         if (comp->sddl[comp->offset] != '"') {
    1849           0 :                 comp_error(comp, "was expecting '\"' for Unicode string");
    1850           0 :                 return false;
    1851             :         }
    1852        5600 :         comp->offset++;
    1853        5600 :         src = comp->sddl + comp->offset;
    1854        5600 :         max_len = comp->length - comp->offset;
    1855             :         /* strnchr */
    1856       50135 :         for (len = 0; len < max_len; len++) {
    1857       50135 :                 if (src[len] == '"') {
    1858         231 :                         break;
    1859             :                 }
    1860             :         }
    1861        5600 :         if (len == max_len) {
    1862           0 :                 comp_error(comp, "unterminated unicode string");
    1863           0 :                 return false;
    1864             :         }
    1865             : 
    1866             :         /*
    1867             :          * Look, this is wasteful, but it probably doesn't matter. We want to
    1868             :          * check that the string we're putting into the descriptor is valid,
    1869             :          * or we'll see errors down the track.
    1870             :          */
    1871        5600 :         ok = convert_string_talloc(comp->mem_ctx,
    1872             :                                    CH_UTF8, CH_UTF16LE,
    1873             :                                    src, len,
    1874             :                                    &utf16, NULL);
    1875        5600 :         if (!ok) {
    1876           0 :                 comp_error(comp, "not valid unicode");
    1877           0 :                 return false;
    1878             :         }
    1879        5600 :         TALLOC_FREE(utf16);
    1880             : 
    1881        5600 :         s = talloc_array_size(comp->mem_ctx, 1, len + 1);
    1882        5600 :         if (s == NULL) {
    1883           0 :                 comp_error(comp, "allocation error");
    1884           0 :                 return false;
    1885             :         }
    1886        5600 :         memcpy(s, src, len);
    1887        5600 :         s[len] = 0;
    1888        5600 :         comp->offset += len + 1;     /* +1 for the final quote */
    1889        5600 :         token.type = CONDITIONAL_ACE_TOKEN_UNICODE;
    1890        5600 :         token.data.unicode.value = s;
    1891             : 
    1892        5600 :         return write_sddl_token(comp, token);
    1893             : }
    1894             : 
    1895             : 
    1896          15 : static bool parse_octet_string(struct ace_condition_sddl_compiler_context *comp)
    1897             : {
    1898             :         /*
    1899             :          * This looks like '#hhhh...', where each 'hh' is hex for a byte, with
    1900             :          * the weird and annoying complication that '#' can be used to mean
    1901             :          * '0'.
    1902             :          */
    1903          15 :         struct ace_condition_token token = {};
    1904          15 :         size_t length, i;
    1905             : 
    1906          15 :         if (comp->sddl[comp->offset] != '#') {
    1907           0 :                 comp_error(comp, "was expecting '#' for octet string");
    1908           0 :                 return false;
    1909             :         }
    1910          15 :         comp->offset++;
    1911          15 :         length = strspn((const char*)(comp->sddl + comp->offset),
    1912             :                         "#0123456789abcdefABCDEF");
    1913             : 
    1914          15 :         if (length & 1) {
    1915           2 :                 comp_error(comp, "octet string has odd number of hex digits");
    1916           2 :                 return false;
    1917             :         }
    1918             : 
    1919          13 :         length /= 2;
    1920             : 
    1921          13 :         token.data.bytes = data_blob_talloc_zero(comp->mem_ctx, length);
    1922          13 :         token.type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
    1923             : 
    1924          60 :         for (i = 0; i < length; i++) {
    1925             :                 /*
    1926             :                  * Why not just strhex_to_str()?
    1927             :                  *
    1928             :                  * Because we need to treat '#' as '0' in octet string values,
    1929             :                  * so all of the following are the same
    1930             :                  * (equaling {0x10, 0x20, 0x30, 0x0}).
    1931             :                  *
    1932             :                  *  #10203000
    1933             :                  *  #10203###
    1934             :                  *  #1#2#3###
    1935             :                  *  #10203#00
    1936             :                  */
    1937          47 :                 bool ok;
    1938          47 :                 char pair[2];
    1939          47 :                 size_t j = comp->offset + i * 2;
    1940          47 :                 pair[0] = (comp->sddl[j]     == '#') ? '0' : comp->sddl[j];
    1941          47 :                 pair[1] = (comp->sddl[j + 1] == '#') ? '0' : comp->sddl[j + 1];
    1942             : 
    1943          47 :                 ok = hex_byte(pair, &token.data.bytes.data[i]);
    1944          47 :                 if (!ok) {
    1945           0 :                         talloc_free(token.data.bytes.data);
    1946           0 :                         comp_error(comp, "inexplicable error in octet string");
    1947           0 :                         return false;
    1948             :                 }
    1949             :         }
    1950          13 :         comp->offset += length * 2;
    1951          13 :         return write_sddl_token(comp, token);
    1952             : }
    1953             : 
    1954             : 
    1955         522 : static bool parse_ra_octet_string(struct ace_condition_sddl_compiler_context *comp)
    1956             : {
    1957             :         /*
    1958             :          * Resource attribute octet strings resemble conditional ace octet
    1959             :          * strings, but have some important differences:
    1960             :          *
    1961             :          * 1. The '#' at the start is optional, and if present is
    1962             :          * counted as a zero.
    1963             :          *
    1964             :          * 2. An odd number of characters is implicitly left-padded with a zero.
    1965             :          *
    1966             :          * That is, "abc" means "0abc", "#12" means "0012", "f##"
    1967             :          * means "0f00", and "##" means 00.
    1968             :          */
    1969         522 :         struct ace_condition_token token = {};
    1970         522 :         size_t string_length, bytes_length, i, j;
    1971         522 :         bool ok;
    1972         522 :         char pair[2];
    1973             : 
    1974         522 :         string_length = strspn((const char*)(comp->sddl + comp->offset),
    1975             :                         "#0123456789abcdefABCDEF");
    1976             : 
    1977         522 :         bytes_length = (string_length + 1) / 2;
    1978             : 
    1979         522 :         if (bytes_length == 0) {
    1980           0 :                 comp_error(comp, "zero length octet bytes");
    1981           0 :                 return false;
    1982             :         }
    1983             : 
    1984         522 :         token.data.bytes = data_blob_talloc_zero(comp->mem_ctx, bytes_length);
    1985         522 :         if (token.data.bytes.data == NULL) {
    1986           0 :                 return false;
    1987             :         }
    1988         522 :         token.type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
    1989             : 
    1990         522 :         j = comp->offset;
    1991         522 :         i = 0;
    1992         522 :         if (string_length & 1) {
    1993             :                 /*
    1994             :                  * An odd number of characters means the first
    1995             :                  * character gains an implicit 0 for the high nybble.
    1996             :                  */
    1997           0 :                 pair[0] = 0;
    1998           0 :                 pair[1] = (comp->sddl[0] == '#') ? '0' : comp->sddl[0];
    1999             : 
    2000           0 :                 ok = hex_byte(pair, &token.data.bytes.data[i]);
    2001           0 :                 if (!ok) {
    2002           0 :                         goto fail;
    2003             :                 }
    2004           0 :                 j++;
    2005           0 :                 i++;
    2006             :         }
    2007             : 
    2008        1602 :         for (; i < bytes_length; i++) {
    2009             :                 /*
    2010             :                  * Why not just strhex_to_str() ?
    2011             :                  *
    2012             :                  * Because we need to treat '#' as '0' in octet string values.
    2013             :                  */
    2014        1080 :                 if (comp->length - j < 2) {
    2015           0 :                         goto fail;
    2016             :                 }
    2017             : 
    2018        1080 :                 pair[0] = (comp->sddl[j]     == '#') ? '0' : comp->sddl[j];
    2019        1080 :                 pair[1] = (comp->sddl[j + 1] == '#') ? '0' : comp->sddl[j + 1];
    2020             : 
    2021        1080 :                 ok = hex_byte(pair, &token.data.bytes.data[i]);
    2022        1080 :                 if (!ok) {
    2023           0 :                         goto fail;
    2024             :                 }
    2025        1080 :                 j += 2;
    2026             :         }
    2027         522 :         comp->offset = j;
    2028         522 :         return write_sddl_token(comp, token);
    2029             : 
    2030           0 : fail:
    2031           0 :         comp_error(comp, "inexplicable error in octet string");
    2032           0 :         talloc_free(token.data.bytes.data);
    2033           0 :         return false;
    2034             : }
    2035             : 
    2036             : 
    2037         786 : static bool parse_sid(struct ace_condition_sddl_compiler_context *comp)
    2038             : {
    2039         786 :         struct dom_sid *sid = NULL;
    2040         786 :         const uint8_t *sidstr = NULL;
    2041         786 :         struct ace_condition_token token = {};
    2042         498 :         size_t end;
    2043         786 :         if (comp->length - comp->offset < 7) {
    2044             :                 /* minimum: "SID(AA)" */
    2045           1 :                 comp_error(comp, "no room for a complete SID");
    2046           1 :                 return false;
    2047             :         }
    2048             :         /* conditional ACE SID string */
    2049         785 :         if (comp->sddl[comp->offset    ] != 'S' ||
    2050         785 :             comp->sddl[comp->offset + 1] != 'I' ||
    2051         785 :             comp->sddl[comp->offset + 2] != 'D' ||
    2052         785 :             comp->sddl[comp->offset + 3] != '(') {
    2053           0 :                 comp_error(comp, "malformed SID() constructor");
    2054           0 :                 return false;
    2055             :         } else {
    2056         785 :                 comp->offset += 4;
    2057             :         }
    2058             : 
    2059         785 :         sidstr = comp->sddl + comp->offset;
    2060             : 
    2061        1282 :         sid = sddl_decode_sid(comp->mem_ctx,
    2062             :                               (const char **)&sidstr,
    2063         785 :                               comp->domain_sid);
    2064             : 
    2065         785 :         if (sid == NULL) {
    2066           2 :                 comp_error(comp, "could not parse SID");
    2067           2 :                 return false;
    2068             :         }
    2069         783 :         end = sidstr - comp->sddl;
    2070         783 :         if (end >= comp->length || end < comp->offset) {
    2071           0 :                 comp_error(comp, "apparent overflow in SID parsing");
    2072           0 :                 return false;
    2073             :         }
    2074         783 :         comp->offset = end;
    2075             :         /*
    2076             :          * offset is now at the end of the SID, but we need to account
    2077             :          * for the ')'.
    2078             :          */
    2079         783 :         if (comp->sddl[comp->offset] != ')') {
    2080           0 :                 comp_error(comp, "expected ')' to follow SID");
    2081           0 :                 return false;
    2082             :         }
    2083         783 :         comp->offset++;
    2084             : 
    2085         783 :         token.type = CONDITIONAL_ACE_TOKEN_SID;
    2086         783 :         token.data.sid.sid = *sid;
    2087         783 :         return write_sddl_token(comp, token);
    2088             : }
    2089             : 
    2090             : 
    2091             : 
    2092           0 : static bool parse_ra_sid(struct ace_condition_sddl_compiler_context *comp)
    2093             : {
    2094           0 :         struct dom_sid *sid = NULL;
    2095           0 :         const uint8_t *sidstr = NULL;
    2096           0 :         struct ace_condition_token token = {};
    2097           0 :         size_t end;
    2098             : 
    2099           0 :         if ((comp->state & SDDL_FLAG_EXPECTING_LITERAL) == 0) {
    2100           0 :                 comp_error(comp, "did not expect a SID here");
    2101           0 :                 return false;
    2102             :         }
    2103             :         /*
    2104             :          *  Here we are parsing a resource attribute ACE which doesn't
    2105             :          *  have the SID() wrapper around the SID string (unlike a
    2106             :          *  conditional ACE).
    2107             :          *
    2108             :          * The resource ACE doesn't need this because there is no
    2109             :          * ambiguity with local attribute names, besides which the
    2110             :          * type has already been specified earlier in the ACE.
    2111             :          */
    2112           0 :         if (comp->length - comp->offset < 2){
    2113           0 :                 comp_error(comp, "no room for a complete SID");
    2114           0 :                 return false;
    2115             :         }
    2116             : 
    2117           0 :         sidstr = comp->sddl + comp->offset;
    2118             : 
    2119           0 :         sid = sddl_decode_sid(comp->mem_ctx,
    2120             :                               (const char **)&sidstr,
    2121           0 :                               comp->domain_sid);
    2122             : 
    2123           0 :         if (sid == NULL) {
    2124           0 :                 comp_error(comp, "could not parse SID");
    2125           0 :                 return false;
    2126             :         }
    2127           0 :         end = sidstr - comp->sddl;
    2128           0 :         if (end >= comp->length || end < comp->offset) {
    2129           0 :                 comp_error(comp, "apparent overflow in SID parsing");
    2130           0 :                 return false;
    2131             :         }
    2132           0 :         comp->offset = end;
    2133           0 :         token.type = CONDITIONAL_ACE_TOKEN_SID;
    2134           0 :         token.data.sid.sid = *sid;
    2135           0 :         return write_sddl_token(comp, token);
    2136             : }
    2137             : 
    2138             : 
    2139        1235 : static bool parse_int(struct ace_condition_sddl_compiler_context *comp)
    2140             : {
    2141             :         /*
    2142             :          * This one is relatively simple. strtoll() does the work.
    2143             :          */
    2144        1163 :         long long v;
    2145        1235 :         struct ace_condition_token token = {};
    2146        1235 :         const char *start = (const char *)comp->sddl + comp->offset;
    2147        1235 :         char *end = NULL;
    2148        1235 :         const char *first_digit = start;
    2149        1163 :         size_t len;
    2150        1235 :         errno = 0;
    2151        1235 :         v = strtoll(start, &end, 0);
    2152        1235 :         if (errno != 0) {
    2153           0 :                 comp_error(comp, "bad integer: %s", strerror(errno));
    2154           0 :                 return false;
    2155             :         }
    2156        1235 :         len = end - start;
    2157             : 
    2158        1235 :         if (len == 0) {
    2159           0 :                 comp_error(comp, "unexpected non-integer");
    2160           0 :                 return false;
    2161             :         }
    2162        1235 :         if (comp->offset + len > comp->length) {
    2163           0 :                 comp_error(comp, "impossible integer length: %zu!", len);
    2164           0 :                 return false;
    2165             :         }
    2166             : 
    2167        1235 :         comp->offset += len;
    2168             : 
    2169             :         /*
    2170             :          * Record the base and sign, which are used for recreating the SDDL.
    2171             :          *
    2172             :          * 'Sign' indicates whether there is a '+' or '-' sign. Base indicates
    2173             :          * whether the number was in hex, octal, or decimal. These make no
    2174             :          * difference to the evaluation of the ACE, just the display.
    2175             :          *
    2176             :          * This would not work reliably if eat_whitespace() is not called
    2177             :          * before parse_int(), but a) we know it is, and b) we don't *really*
    2178             :          * care if we lose these display hints.
    2179             :          */
    2180        1235 :         if (*start == '-') {
    2181          81 :                 token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NEGATIVE;
    2182          81 :                 first_digit++;
    2183        1154 :         } else if (*start == '+') {
    2184           2 :                 token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_POSITIVE;
    2185           2 :                 first_digit++;
    2186             :         } else {
    2187        1152 :                 token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
    2188             :         }
    2189        1235 :         if (*first_digit == '0' && (end - first_digit) > 1) {
    2190         149 :                 if ((end - first_digit > 2) &&
    2191         141 :                     (first_digit[1] == 'x' ||
    2192           0 :                      first_digit[1] == 'X')) {
    2193         100 :                         token.data.int64.base = CONDITIONAL_ACE_INT_BASE_16;
    2194             :                 } else {
    2195          49 :                         token.data.int64.base = CONDITIONAL_ACE_INT_BASE_8;
    2196             :                 }
    2197             :         } else {
    2198        1086 :                 token.data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
    2199             :         }
    2200             : 
    2201        1235 :         token.data.int64.value = v;
    2202        1235 :         token.type = CONDITIONAL_ACE_TOKEN_INT64;
    2203        1235 :         return write_sddl_token(comp, token);
    2204             : }
    2205             : 
    2206             : 
    2207         349 : static bool parse_uint(struct ace_condition_sddl_compiler_context *comp)
    2208             : {
    2209         349 :         struct ace_condition_token *tok = NULL;
    2210         349 :         bool ok = parse_int(comp);
    2211         349 :         if (ok == false) {
    2212           0 :                 return false;
    2213             :         }
    2214             :         /*
    2215             :          * check that the token's value is positive.
    2216             :          */
    2217         349 :         if (comp->target_len == 0) {
    2218           0 :                 return false;
    2219             :         }
    2220         349 :         tok = &comp->target[*comp->target_len - 1];
    2221         349 :         if (tok->type != CONDITIONAL_ACE_TOKEN_INT64) {
    2222           0 :                 return false;
    2223             :         }
    2224         349 :         if (tok->data.int64.value < 0) {
    2225           0 :                 comp_error(comp, "invalid resource ACE value for unsigned TU claim");
    2226           0 :                 return false;
    2227             :         }
    2228           0 :         return true;
    2229             : }
    2230             : 
    2231             : 
    2232           0 : static bool parse_bool(struct ace_condition_sddl_compiler_context *comp)
    2233             : {
    2234           0 :         struct ace_condition_token *tok = NULL;
    2235           0 :         bool ok = parse_int(comp);
    2236           0 :         if (ok == false || comp->target_len == 0) {
    2237           0 :                 return false;
    2238             :         }
    2239             :         /*
    2240             :          * check that the token is 0 or 1.
    2241             :          */
    2242           0 :         tok = &comp->target[*comp->target_len - 1];
    2243           0 :         if (tok->type != CONDITIONAL_ACE_TOKEN_INT64) {
    2244           0 :                 return false;
    2245             :         }
    2246           0 :         if (tok->data.int64.value != 0 && tok->data.int64.value != 1) {
    2247           0 :                 comp_error(comp, "invalid resource ACE Boolean value");
    2248           0 :                 return false;
    2249             :         }
    2250           0 :         return true;
    2251             : }
    2252             : 
    2253             : 
    2254         322 : static bool could_be_an_int(struct ace_condition_sddl_compiler_context *comp)
    2255             : {
    2256         322 :         const char *start = (const char*)(comp->sddl + comp->offset);
    2257         322 :         char* end = NULL;
    2258             : 
    2259         322 :         if ((comp->state & SDDL_FLAG_EXPECTING_LITERAL) == 0) {
    2260           0 :                 return false;
    2261             :         }
    2262             : 
    2263         139 :         errno = 0;
    2264             :         /*
    2265             :          * See, we don't care about the strtoll return value, only
    2266             :          * whether it succeeds or not and what it finds at the end. If
    2267             :          * it succeeds, parse_int() will do it again for the value.
    2268             :          *
    2269             :          * Note that an out of range int will raise ERANGE (probably
    2270             :          * 34), so it will be read as a local attribute.
    2271             :          */
    2272         139 :         strtoll(start, &end, 0);
    2273         139 :         if (errno != 0 ||
    2274         131 :             end == start ||
    2275         129 :             end >= (const char*)comp->sddl + comp->length) {
    2276           0 :                 return false;
    2277             :         }
    2278             :         /*
    2279             :          * We know *some* characters form an int, but if we run right
    2280             :          * into other attr1 characters (basically, letters), we won't
    2281             :          * count it as an int.
    2282             :          *
    2283             :          * For example, the "17" in "17p" is not an int. The "17" in
    2284             :          * "17||" is.
    2285             :          */
    2286         129 :         if (is_attr_char1(*end)) {
    2287           0 :                 return false;
    2288             :         }
    2289          28 :         return true;
    2290             : }
    2291             : 
    2292             : 
    2293        1292 : static bool parse_word(struct ace_condition_sddl_compiler_context *comp)
    2294             : {
    2295             :         /*
    2296             :          * Sometimes a bare word must be a local attribute, while in other
    2297             :          * cases it could also be a member-of or exists operator. Sometimes it
    2298             :          * could actually be a SID, which we discover when we've read as far
    2299             :          * as "SID(". Sometimes it might be a literal integer (attribute
    2300             :          * names can also consist entirely of digits).
    2301             :          *
    2302             :          * When it is an operator name, we have the complication that a match
    2303             :          * does not necessarily end the token. Consider "Member_of_Any" which
    2304             :          * contains the operator "Member_of". According to [MS-DTYP], a space
    2305             :          * is not necessary between the operator and the next token, but it
    2306             :          * does seem to be required for Windows 2022.
    2307             :          *
    2308             :          * Also, "Member_of" et. al. *could* be valid local attributes, which
    2309             :          * would make "(Member_of == 123)" a valid expression that we will
    2310             :          * fail to parse. This is not much of an issue for Samba AD where
    2311             :          * local attributes are not used.
    2312             :          *
    2313             :          * Operators are matched case-insensitively.
    2314             :          *
    2315             :          * There's another kind of attribute that starts with a '@', which we
    2316             :          * deal with in parse_attr2(). Those ones have full unicode glory;
    2317             :          * these ones are ASCII only.
    2318             :          */
    2319         835 :         size_t i, j, k;
    2320         835 :         bool ok;
    2321         835 :         uint8_t candidates[8];
    2322        1292 :         size_t n_candidates = 0;
    2323        1292 :         struct ace_condition_token token = {};
    2324        1292 :         bool expecting_unary = comp->state & SDDL_FLAG_EXPECTING_UNARY_OP;
    2325        1292 :         bool expecting_binary = comp->state & SDDL_FLAG_EXPECTING_BINARY_OP;
    2326        1292 :         bool expecting_attr = comp->state & SDDL_FLAG_EXPECTING_LOCAL_ATTR;
    2327        1292 :         bool expecting_literal = comp->state & SDDL_FLAG_EXPECTING_LITERAL;
    2328        1292 :         const uint8_t *start = comp->sddl + comp->offset;
    2329        1292 :         uint8_t c = start[0];
    2330        1292 :         char *s = NULL;
    2331        2127 :         if (! is_attr_char1(*start)) {
    2332             :                 /* we shouldn't get here, because we peeked first */
    2333           0 :                 return false;
    2334             :         }
    2335             : 
    2336             :         /*
    2337             :          *  We'll look for a SID first, because it simplifies the rest.
    2338             :          */
    2339        1292 :         if (expecting_literal &&
    2340         284 :             comp->offset + 4 < comp->length &&
    2341         161 :             start[0] == 'S' &&
    2342         145 :             start[1] == 'I' &&
    2343         145 :             start[2] == 'D' &&
    2344         145 :             start[3] == '(') {
    2345             :                 /* actually, we are parsing a SID. */
    2346         145 :                 return parse_sid(comp);
    2347             :         }
    2348             : 
    2349        1488 :         if (expecting_binary || expecting_unary) {
    2350             :                 /*
    2351             :                  * Collect up the operators that can possibly be used
    2352             :                  * here, including only those that start with the
    2353             :                  * current letter and have the right arity/syntax.
    2354             :                  *
    2355             :                  * We don't expect more than 5 (for 'N', beginning the
    2356             :                  * "Not_..." unary ops), and we'll winnow them down as
    2357             :                  * we progress through the word.
    2358             :                  */
    2359        1005 :                 int uc = toupper(c);
    2360      258285 :                 for (i = 0; i < 256; i++) {
    2361      257280 :                         const struct sddl_data *d = &sddl_strings[i];
    2362      257280 :                         if (sddl_strings[i].op_precedence != SDDL_NOT_AN_OP &&
    2363       25125 :                             uc == toupper((unsigned char)d->name[0])) {
    2364        1773 :                                 if (d->flags & SDDL_FLAG_IS_UNARY_OP) {
    2365        1240 :                                         if (!expecting_unary) {
    2366         190 :                                                 continue;
    2367             :                                         }
    2368         533 :                                 } else if (!expecting_binary) {
    2369         116 :                                         continue;
    2370             :                                 }
    2371        1467 :                                 candidates[n_candidates] = i;
    2372        1467 :                                 n_candidates++;
    2373        1467 :                                 if (n_candidates == ARRAY_SIZE(candidates)) {
    2374             :                                         /* impossible, really. */
    2375           0 :                                         return false;
    2376             :                                 }
    2377             :                         }
    2378             :                 }
    2379         142 :         } else if (could_be_an_int(comp)) {
    2380             :                 /*
    2381             :                  * if looks like an integer, and we expect an integer, it is
    2382             :                  * an integer. If we don't expect an integer, it is a local
    2383             :                  * attribute with a STUPID NAME. Or an error.
    2384             :                  */
    2385         129 :                 return parse_int(comp);
    2386          13 :         } else if (! expecting_attr) {
    2387          11 :                 comp_error(comp, "did not expect this word here");
    2388          11 :                 return false;
    2389             :         }
    2390             : 
    2391         341 :         i = 1;
    2392       11217 :         while (comp->offset + i < comp->length) {
    2393       11217 :                 c = start[i];
    2394       18039 :                 if (! is_attr_char1(c)) {
    2395         341 :                         break;
    2396             :                 }
    2397       10210 :                 if (n_candidates != 0) {
    2398             :                         /*
    2399             :                          * Filter out candidate operators that no longer
    2400             :                          * match.
    2401             :                          */
    2402        7341 :                         int uc = toupper(c);
    2403        7341 :                         k = 0;
    2404       19969 :                         for (j = 0; j < n_candidates; j++) {
    2405       12628 :                                 size_t o = candidates[j];
    2406       12628 :                                 uint8_t c2 = sddl_strings[o].name[i];
    2407       12628 :                                 if (uc == toupper(c2)) {
    2408       12373 :                                         candidates[k] = candidates[j];
    2409       12373 :                                         k++;
    2410             :                                 }
    2411             :                         }
    2412        3409 :                         n_candidates = k;
    2413             :                 }
    2414       10210 :                 i++;
    2415             :         }
    2416             : 
    2417             :         /*
    2418             :          * We have finished and there is a complete word. If it could be an
    2419             :          * operator we'll assume it is one.
    2420             :          *
    2421             :          * A complication is we could have matched more than one operator, for
    2422             :          * example "Member_of" and "Member_of_Any", so we have to look through
    2423             :          * the list of candidates for the one that ends.
    2424             :          */
    2425        1007 :         if (n_candidates != 0) {
    2426         827 :                 for (j = 0; j < n_candidates; j++) {
    2427         827 :                         size_t o = candidates[j];
    2428         827 :                         if (sddl_strings[o].name[i] == '\0') {
    2429             :                                 /* it is this one */
    2430             : 
    2431         827 :                                 if (!comp->allow_device &&
    2432          11 :                                     (sddl_strings[o].flags & SDDL_FLAG_DEVICE))
    2433             :                                 {
    2434           1 :                                         comp_error(
    2435             :                                                 comp,
    2436             :                                                 "a device‐relative expression "
    2437             :                                                 "will never evaluate to true "
    2438             :                                                 "in this context (did you "
    2439             :                                                 "intend a user‐relative "
    2440             :                                                 "expression?)");
    2441           1 :                                         return false;
    2442             :                                 }
    2443             : 
    2444         826 :                                 token.type = o;
    2445         826 :                                 token.data.sddl_op.start = comp->offset;
    2446         826 :                                 comp->offset += i;
    2447         826 :                                 ok = push_sddl_token(comp, token);
    2448         826 :                                 return ok;
    2449             :                         }
    2450             :                 }
    2451             :         }
    2452             :         /*
    2453             :          * if looks like an integer, and we expect an integer, it is
    2454             :          * an integer. If we don't expect an integer, it is a local
    2455             :          * attribute with a STUPID NAME.
    2456             :          */
    2457         180 :         if (could_be_an_int(comp)) {
    2458           0 :                 return parse_int(comp);
    2459             :         }
    2460             : 
    2461         180 :         if (! expecting_attr) {
    2462           0 :                 comp_error(comp, "word makes no sense here");
    2463           0 :                 return false;
    2464             :         }
    2465             :         /* it's definitely an attribute name */
    2466         180 :         token.type = CONDITIONAL_ACE_LOCAL_ATTRIBUTE;
    2467         180 :         if (comp->offset + i >= comp->length) {
    2468           0 :                 comp_error(comp, "missing trailing ')'?");
    2469           0 :                 return false;
    2470             :         }
    2471             : 
    2472         180 :         s = talloc_memdup(comp->mem_ctx, start, i + 1);
    2473         180 :         if (s == NULL) {
    2474           0 :                 comp_error(comp, "allocation error");
    2475           0 :                 return false;
    2476             :         }
    2477         180 :         s[i] = 0;
    2478         180 :         token.data.local_attr.value = s;
    2479         180 :         comp->offset += i;
    2480         180 :         return write_sddl_token(comp, token);
    2481             : }
    2482             : 
    2483        1592 : static bool parse_attr2(struct ace_condition_sddl_compiler_context *comp)
    2484             : {
    2485             :         /*
    2486             :          * Attributes in the form @class.attr
    2487             :          *
    2488             :          * class can be "User", "Device", or "Resource", case insensitive.
    2489             :          */
    2490         952 :         size_t i;
    2491         952 :         bool ok;
    2492         952 :         size_t len;
    2493        1592 :         struct ace_condition_token token = {};
    2494             : 
    2495        1592 :         if ((comp->state & SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR) == 0) {
    2496           0 :                 comp_error(comp, "did not expect @attr here");
    2497           0 :                 return false;
    2498             :         }
    2499        1592 :         if (comp->sddl[comp->offset] != '@') {
    2500           0 :                 comp_error(comp, "Expected '@'");
    2501           0 :                 return false;
    2502             :         }
    2503        1592 :         comp->offset++;
    2504             : 
    2505        2785 :         for (i = 0; i < ARRAY_SIZE(sddl_attr_types); i++) {
    2506        2131 :                 int ret;
    2507        2785 :                 size_t attr_len = strlen(sddl_attr_types[i].name);
    2508        2785 :                 if (attr_len >= comp->length - comp->offset) {
    2509           2 :                         continue;
    2510             :                 }
    2511        2783 :                 ret = strncasecmp(sddl_attr_types[i].name,
    2512        2783 :                                   (const char *) (comp->sddl + comp->offset),
    2513             :                                   attr_len);
    2514        2783 :                 if (ret == 0) {
    2515        1592 :                         const uint8_t code = sddl_attr_types[i].code;
    2516             : 
    2517        1592 :                         if (!comp->allow_device &&
    2518           8 :                             (sddl_strings[code].flags & SDDL_FLAG_DEVICE))
    2519             :                         {
    2520           1 :                                 comp_error(comp,
    2521             :                                            "a device attribute is not "
    2522             :                                            "applicable in this context (did "
    2523             :                                            "you intend a user attribute?)");
    2524           1 :                                 return false;
    2525             :                         }
    2526             : 
    2527        1591 :                         token.type = code;
    2528        1591 :                         comp->offset += attr_len;
    2529        1591 :                         break;
    2530             :                 }
    2531             :         }
    2532        1591 :         if (i == ARRAY_SIZE(sddl_attr_types)) {
    2533           0 :                 comp_error(comp, "unknown attribute class");
    2534           0 :                 return false;
    2535             :         }
    2536             : 
    2537             :         /*
    2538             :          * Now we are past the class and the '.', and into the
    2539             :          * attribute name. The attribute name can be almost
    2540             :          * anything, but some characters need to be escaped.
    2541             :          */
    2542             : 
    2543        1591 :         len = read_attr2_string(comp, &token.data.unicode);
    2544        1591 :         if (len == -1) {
    2545             :                 /* read_attr2_string has set a message */
    2546           0 :                 return false;
    2547             :         }
    2548        1588 :         ok = write_sddl_token(comp, token);
    2549        1588 :         if (! ok) {
    2550           0 :                 return false;
    2551             :         }
    2552        1588 :         comp->offset += len;
    2553        1588 :         ok = eat_whitespace(comp, false);
    2554        1588 :         return ok;
    2555             : }
    2556             : 
    2557        7394 : static bool parse_literal(struct ace_condition_sddl_compiler_context *comp,
    2558             :                           bool in_composite)
    2559             : {
    2560        7394 :         uint8_t c = comp->sddl[comp->offset];
    2561        7394 :         if (!(comp->state & SDDL_FLAG_EXPECTING_LITERAL)) {
    2562           0 :                 comp_error(comp, "did not expect to be parsing a literal now");
    2563           0 :                 return false;
    2564             :         }
    2565        7394 :         switch(c) {
    2566          15 :         case '#':
    2567          15 :                 return parse_octet_string(comp);
    2568        5305 :         case '"':
    2569        5305 :                 return parse_unicode(comp);
    2570         641 :         case 'S':
    2571         641 :                 return parse_sid(comp);
    2572         799 :         case '{':
    2573         799 :                 if (in_composite) {
    2574             :                         /* nested composites are not supported */
    2575           0 :                         return false;
    2576             :                 } else {
    2577         799 :                         return parse_composite(comp);
    2578             :                 }
    2579         634 :         default:
    2580         634 :                 if (strchr("1234567890-+", c) != NULL) {
    2581         629 :                         return parse_int(comp);
    2582             :                 }
    2583             :         }
    2584           5 :         if (c > 31 && c < 127) {
    2585           5 :                 comp_error(comp,
    2586             :                            "unexpected byte 0x%02x '%c' parsing literal", c, c);
    2587             :         } else {
    2588           0 :                 comp_error(comp, "unexpected byte 0x%02x parsing literal", c);
    2589             :         }
    2590           2 :         return false;
    2591             : }
    2592             : 
    2593             : 
    2594         799 : static bool parse_composite(struct ace_condition_sddl_compiler_context *comp)
    2595             : {
    2596             :         /*
    2597             :          * This jumps into a different parser, expecting a comma separated
    2598             :          * list of literal values, which might include nested literal
    2599             :          * composites.
    2600             :          *
    2601             :          * To handle the nesting, we redirect the pointers that determine
    2602             :          * where write_sddl_token() writes.
    2603             :          */
    2604         547 :         bool ok;
    2605         799 :         bool first = true;
    2606         799 :         struct ace_condition_token token = {
    2607             :                 .type = CONDITIONAL_ACE_TOKEN_COMPOSITE
    2608             :         };
    2609         799 :         uint32_t start = comp->offset;
    2610         547 :         size_t alloc_size;
    2611         799 :         struct ace_condition_token *old_target = comp->target;
    2612         799 :         uint32_t *old_target_len = comp->target_len;
    2613             : 
    2614         799 :         if (comp->sddl[start] != '{') {
    2615           0 :                 comp_error(comp, "expected '{' for composite list");
    2616           0 :                 return false;
    2617             :         }
    2618         799 :         if (!(comp->state & SDDL_FLAG_EXPECTING_LITERAL)) {
    2619           0 :                 comp_error(comp, "did not expect '{' for composite list");
    2620           0 :                 return false;
    2621             :         }
    2622         799 :         comp->offset++; /* past '{' */
    2623             : 
    2624             :         /*
    2625             :          * the worst case is one token for every two bytes: {1,1,1}, and we
    2626             :          * allocate for that (counting commas and finding '}' gets hard because
    2627             :          * string literals).
    2628             :          */
    2629         799 :         alloc_size = MIN((comp->length - start) / 2 + 1,
    2630             :                          CONDITIONAL_ACE_MAX_LENGTH);
    2631             : 
    2632         799 :         token.data.composite.tokens = talloc_array(
    2633             :                 comp->mem_ctx,
    2634             :                 struct ace_condition_token,
    2635             :                 alloc_size);
    2636         799 :         if (token.data.composite.tokens == NULL) {
    2637           0 :                 comp_error(comp, "allocation failure");
    2638           0 :                 return false;
    2639             :         }
    2640             : 
    2641         799 :         comp->target = token.data.composite.tokens;
    2642         799 :         comp->target_len = &token.data.composite.n_members;
    2643             : 
    2644             :         /*
    2645             :          * in this loop we are looking for:
    2646             :          *
    2647             :          * a) possible whitespace.
    2648             :          * b) a comma (or terminating '}')
    2649             :          * c) more possible whitespace
    2650             :          * d) a literal
    2651             :          *
    2652             :          * Failures use a goto to reset comp->target, just in case we ever try
    2653             :          * continuing after error.
    2654             :          */
    2655        7026 :         while (comp->offset < comp->length) {
    2656        6426 :                 uint8_t c;
    2657        7026 :                 ok = eat_whitespace(comp, false);
    2658        7026 :                 if (! ok) {
    2659           0 :                         goto fail;
    2660             :                 }
    2661        7026 :                 c = comp->sddl[comp->offset];
    2662        7026 :                 if (c == '}') {
    2663         794 :                         comp->offset++;
    2664         794 :                         break;
    2665             :                 }
    2666        6232 :                 if (!first) {
    2667        5461 :                         if (c != ',') {
    2668           1 :                                 comp_error(comp,
    2669             :                                            "malformed composite (expected comma)");
    2670           1 :                                 goto fail;
    2671             :                         }
    2672        5460 :                         comp->offset++;
    2673             : 
    2674        5460 :                         ok = eat_whitespace(comp, false);
    2675        5460 :                         if (! ok) {
    2676           0 :                                 goto fail;
    2677             :                         }
    2678             :                 }
    2679        6231 :                 first = false;
    2680        6231 :                 if (*comp->target_len >= alloc_size) {
    2681           0 :                         comp_error(comp,
    2682             :                                    "Too many tokens in composite "
    2683             :                                    "(>= %"PRIu32" tokens)",
    2684           0 :                                    *comp->target_len);
    2685           0 :                         goto fail;
    2686             :                 }
    2687        6231 :                 ok = parse_literal(comp, true);
    2688        6231 :                 if (!ok) {
    2689           4 :                         goto fail;
    2690             :                 }
    2691             :         }
    2692         794 :         comp->target = old_target;
    2693         794 :         comp->target_len = old_target_len;
    2694         794 :         write_sddl_token(comp, token);
    2695         794 :         return true;
    2696           5 : fail:
    2697           5 :         talloc_free(token.data.composite.tokens);
    2698           5 :         comp->target = old_target;
    2699           5 :         comp->target_len = old_target_len;
    2700           5 :         return false;
    2701             : }
    2702             : 
    2703             : 
    2704           3 : static bool parse_paren_literal(struct ace_condition_sddl_compiler_context *comp)
    2705             : {
    2706           3 :         bool ok;
    2707           3 :         if (comp->sddl[comp->offset] != '(') {
    2708           0 :                 comp_error(comp, "expected '('");
    2709           0 :                 return false;
    2710             :         }
    2711           3 :         comp->offset++;
    2712           3 :         ok = parse_literal(comp, false);
    2713           3 :         if (!ok) {
    2714           0 :                 return false;
    2715             :         }
    2716           2 :         if (comp->sddl[comp->offset] != ')') {
    2717           0 :                 comp_error(comp, "expected ')'");
    2718           0 :                 return false;
    2719             :         }
    2720           2 :         comp->offset++;
    2721           2 :         return true;
    2722             : }
    2723             : 
    2724        2457 : static bool parse_expression(struct ace_condition_sddl_compiler_context *comp)
    2725             : {
    2726             :         /*
    2727             :          * This expects a parenthesised expression.
    2728             :          */
    2729        1670 :         bool ok;
    2730        2457 :         struct ace_condition_token token = {};
    2731        2457 :         uint32_t start = comp->offset;
    2732             : 
    2733        2457 :         if (comp->state & SDDL_FLAG_EXPECTING_PAREN_LITERAL) {
    2734             :                 /*
    2735             :                  * Syntactically we allow parentheses to wrap a
    2736             :                  * literal value after a Member_of or >= op, but we
    2737             :                  * want to remember that it just wants a single
    2738             :                  * literal, not a general expression.
    2739             :                  */
    2740           3 :                 return parse_paren_literal(comp);
    2741             :         }
    2742             : 
    2743        2454 :         if (comp->sddl[start] != '(') {
    2744           4 :                 comp_error(comp, "expected '('");
    2745           4 :                 return false;
    2746             :         }
    2747             : 
    2748        2450 :         if (!(comp->state & SDDL_FLAG_EXPECTING_PAREN)) {
    2749           1 :                 comp_error(comp, "did not expect '('");
    2750           1 :                 return false;
    2751             :         }
    2752             : 
    2753        2449 :         token.type = CONDITIONAL_ACE_SAMBA_SDDL_PAREN;
    2754        2449 :         token.data.sddl_op.start = start;
    2755        2449 :         ok = push_sddl_token(comp, token);
    2756        2449 :         if (!ok) {
    2757           0 :                 return false;
    2758             :         }
    2759        2449 :         comp->offset++; /* over the '(' */
    2760        2449 :         comp->state = SDDL_FLAGS_EXPR_START;
    2761        2449 :         DBG_INFO("%3"PRIu32": (\n", comp->offset);
    2762             : 
    2763        2449 :         comp->state |= SDDL_FLAG_NOT_EXPECTING_END_PAREN;
    2764             : 
    2765       10339 :         while (comp->offset < comp->length) {
    2766        5985 :                 uint8_t c;
    2767        8677 :                 ok = eat_whitespace(comp, false);
    2768        8677 :                 if (! ok) {
    2769           0 :                         return false;
    2770             :                 }
    2771        8677 :                 c = comp->sddl[comp->offset];
    2772        8677 :                 if (c == '(') {
    2773         968 :                         ok = parse_expression(comp);
    2774        7709 :                 } else if (c == ')') {
    2775        2414 :                         if (comp->state & (SDDL_FLAG_IS_BINARY_OP |
    2776             :                                            SDDL_FLAG_IS_UNARY_OP)) {
    2777             :                                 /*
    2778             :                                  * You can't have "(a ==)" or "(!)"
    2779             :                                  */
    2780           3 :                                 comp_error(comp,
    2781             :                                            "operator lacks right hand argument");
    2782           3 :                                 return false;
    2783             :                         }
    2784        2411 :                         if (comp->state & SDDL_FLAG_NOT_EXPECTING_END_PAREN) {
    2785             :                                 /*
    2786             :                                  * You can't have "( )"
    2787             :                                  */
    2788           1 :                                 comp_error(comp, "empty expression");
    2789           1 :                                 return false;
    2790             :                         }
    2791         783 :                         break;
    2792        5295 :                 } else if (c == '@') {
    2793        1592 :                         ok = parse_attr2(comp);
    2794        3703 :                 } else if (strchr("!<>=&|", c)) {
    2795        1395 :                         ok = parse_oppy_op(comp);
    2796        3143 :                 } else if (is_attr_char1(c)) {
    2797        1292 :                         ok = parse_word(comp);
    2798        1016 :                 } else if (comp->state & SDDL_FLAG_EXPECTING_LITERAL) {
    2799        1015 :                         ok = parse_literal(comp, false);
    2800             :                 } else {
    2801           1 :                         if (c > 31 && c < 127) {
    2802           1 :                                 comp_error(comp,
    2803             :                                            "unexpected byte 0x%02x '%c'", c, c);
    2804             :                         } else {
    2805           0 :                                 comp_error(comp, "unexpected byte 0x%02x", c);
    2806             :                         }
    2807           0 :                         ok = false;
    2808             :                 }
    2809             : 
    2810        6262 :                 if (! ok) {
    2811          35 :                         return false;
    2812             :                 }
    2813             :                 /*
    2814             :                  * what did we just find? Set what we expect accordingly.
    2815             :                  */
    2816        6228 :                 comp->state = sddl_strings[comp->last_token_type].flags;
    2817        6228 :                 DBG_INFO("%3"PRIu32": %s\n",
    2818             :                         comp->offset,
    2819             :                         sddl_strings[comp->last_token_type].name);
    2820             :         }
    2821        2410 :         ok = eat_whitespace(comp, false);
    2822        2410 :         if (!ok) {
    2823           0 :                 return false;
    2824             :         }
    2825             : 
    2826        2410 :         if (comp->sddl[comp->offset] != ')') {
    2827           0 :                 comp_error(comp, "expected ')' to match '(' at %"PRIu32, start);
    2828           0 :                 return false;
    2829             :         }
    2830             :         /*
    2831             :          * we won't comp->offset++ until after these other error checks, so
    2832             :          * that their messages have consistent locations.
    2833             :          */
    2834        2410 :         ok = flush_stack_tokens(comp, CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END);
    2835        2410 :         if (!ok) {
    2836           0 :                 return false;
    2837             :         }
    2838        2410 :         if (comp->stack_depth == 0) {
    2839           0 :                 comp_error(comp, "mysterious nesting error between %"
    2840             :                            PRIu32" and here",
    2841             :                            start);
    2842           0 :                 return false;
    2843             :         }
    2844        2410 :         token = comp->stack[comp->stack_depth - 1];
    2845        2410 :         if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
    2846           0 :                 comp_error(comp, "nesting error between %"PRIu32" and here",
    2847             :                            start);
    2848           0 :                 return false;
    2849             :         }
    2850        2410 :         if (token.data.sddl_op.start != start) {
    2851           0 :                 comp_error(comp, "')' should match '(' at %"PRIu32
    2852             :                            ", not %"PRIu32,
    2853             :                            token.data.sddl_op.start, start);
    2854           0 :                 return false;
    2855             :         }
    2856        2410 :         comp->stack_depth--;
    2857        2410 :         DBG_INFO("%3"PRIu32": )\n", comp->offset);
    2858             : 
    2859        2410 :         comp->offset++;  /* for the ')' */
    2860        2410 :         comp->last_token_type = CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END;
    2861        2410 :         comp->state = sddl_strings[comp->last_token_type].flags;
    2862             : 
    2863        2410 :         ok = eat_whitespace(comp, true);
    2864        2410 :         return ok;
    2865             : }
    2866             : 
    2867             : 
    2868             : 
    2869        1634 : static bool init_compiler_context(
    2870             :         TALLOC_CTX *mem_ctx,
    2871             :         struct ace_condition_sddl_compiler_context *comp,
    2872             :         const enum ace_condition_flags ace_condition_flags,
    2873             :         const char *sddl,
    2874             :         size_t max_length,
    2875             :         size_t max_stack)
    2876             : {
    2877        1634 :         struct ace_condition_script *program = NULL;
    2878             : 
    2879        1634 :         comp->sddl = (const uint8_t*)sddl;
    2880        1634 :         comp->mem_ctx = mem_ctx;
    2881             : 
    2882        1634 :         program = talloc_zero(mem_ctx, struct ace_condition_script);
    2883        1634 :         if (program == NULL) {
    2884           0 :                 return false;
    2885             :         }
    2886             :         /*
    2887             :          * For the moment, we allocate for the worst case up front.
    2888             :          */
    2889        1634 :         program->tokens = talloc_array(program,
    2890             :                                        struct ace_condition_token,
    2891             :                                        max_length);
    2892        1634 :         if (program->tokens == NULL) {
    2893           0 :                 TALLOC_FREE(program);
    2894           0 :                 return false;
    2895             :         }
    2896        1634 :         program->stack = talloc_array(program,
    2897             :                                       struct ace_condition_token,
    2898             :                                       max_stack + 1);
    2899        1634 :         if (program->stack == NULL) {
    2900           0 :                 TALLOC_FREE(program);
    2901           0 :                 return false;
    2902             :         }
    2903        1634 :         comp->program = program;
    2904             :         /* we can borrow the program stack for the operator stack */
    2905        1634 :         comp->stack = program->stack;
    2906        1634 :         comp->target = program->tokens;
    2907        1634 :         comp->target_len = &program->length;
    2908        1634 :         comp->length = strlen(sddl);
    2909        1634 :         comp->state =  SDDL_FLAG_EXPECTING_PAREN;
    2910        1634 :         comp->allow_device = ace_condition_flags & ACE_CONDITION_FLAG_ALLOW_DEVICE;
    2911        1634 :         return true;
    2912             : }
    2913             : 
    2914             : /*
    2915             :  * Compile SDDL conditional ACE conditions.
    2916             :  *
    2917             :  * @param mem_ctx
    2918             :  * @param sddl - the string to be parsed
    2919             :  * @param ace_condition_flags - flags controlling compiler behaviour
    2920             :  * @param message - on error, a pointer to a compiler message
    2921             :  * @param message_offset - where the error occurred
    2922             :  * @param consumed_length - how much of the SDDL was used
    2923             :  * @return a struct ace_condition_script (or NULL).
    2924             :  */
    2925        1489 : struct ace_condition_script * ace_conditions_compile_sddl(
    2926             :         TALLOC_CTX *mem_ctx,
    2927             :         const enum ace_condition_flags ace_condition_flags,
    2928             :         const char *sddl,
    2929             :         const char **message,
    2930             :         size_t *message_offset,
    2931             :         size_t *consumed_length)
    2932             : {
    2933         766 :         bool ok;
    2934        1489 :         struct ace_condition_sddl_compiler_context comp = {};
    2935             : 
    2936        1489 :         *message = NULL;
    2937        1489 :         *message_offset = 0;
    2938             : 
    2939        1489 :         ok = init_compiler_context(mem_ctx,
    2940             :                                    &comp,
    2941             :                                    ace_condition_flags,
    2942             :                                    sddl,
    2943             :                                    CONDITIONAL_ACE_MAX_LENGTH,
    2944             :                                    CONDITIONAL_ACE_MAX_TOKENS);
    2945        1489 :         if (!ok) {
    2946           0 :                 return NULL;
    2947             :         }
    2948             : 
    2949        1489 :         ok = parse_expression(&comp);
    2950        1489 :         if (!ok) {
    2951          43 :                 goto error;
    2952             :         }
    2953        1446 :         if (comp.stack_depth != 0) {
    2954           0 :                 comp_error(&comp, "incomplete expression");
    2955           0 :                 goto error;
    2956             :         }
    2957        1446 :         if (consumed_length != NULL) {
    2958        1446 :                 *consumed_length = comp.offset;
    2959             :         }
    2960        1446 :         *message = comp.message;
    2961        1446 :         *message_offset = comp.message_offset;
    2962        1446 :         return comp.program;
    2963          43 :   error:
    2964          43 :         *message = comp.message;
    2965          43 :         *message_offset = comp.message_offset;
    2966          43 :         TALLOC_FREE(comp.program);
    2967           4 :         return NULL;
    2968             : }
    2969             : 
    2970             : 
    2971             : 
    2972         105 : static bool parse_resource_attr_list(
    2973             :         struct ace_condition_sddl_compiler_context *comp,
    2974             :         char attr_type_char)
    2975             : {
    2976             :         /*
    2977             :          * This is a bit like parse_composite() above, but with the following
    2978             :          * differences:
    2979             :          *
    2980             :          * - it doesn't want '{...}' around the list.
    2981             :          * - if there is just one value, it is not a composite
    2982             :          * - all the values must be the expected type.
    2983             :          * - there is no nesting.
    2984             :          * - SIDs are not written with SID(...) around them.
    2985             :          */
    2986         105 :         bool ok;
    2987         105 :         bool first = true;
    2988         105 :         struct ace_condition_token composite = {
    2989             :                 .type = CONDITIONAL_ACE_TOKEN_COMPOSITE
    2990             :         };
    2991         105 :         uint32_t start = comp->offset;
    2992         105 :         size_t alloc_size;
    2993         105 :         struct ace_condition_token *old_target = comp->target;
    2994         105 :         uint32_t *old_target_len = comp->target_len;
    2995             : 
    2996         105 :         comp->state = SDDL_FLAG_EXPECTING_LITERAL;
    2997             : 
    2998             :         /*
    2999             :          * the worst case is one token for every two bytes: {1,1,1}, and we
    3000             :          * allocate for that (counting commas and finding '}' gets hard because
    3001             :          * string literals).
    3002             :          */
    3003         105 :         alloc_size = MIN((comp->length - start) / 2 + 1,
    3004             :                          CONDITIONAL_ACE_MAX_LENGTH);
    3005             : 
    3006         105 :         composite.data.composite.tokens = talloc_array(
    3007             :                 comp->mem_ctx,
    3008             :                 struct ace_condition_token,
    3009             :                 alloc_size);
    3010         105 :         if (composite.data.composite.tokens == NULL) {
    3011           0 :                 comp_error(comp, "allocation failure");
    3012           0 :                 return false;
    3013             :         }
    3014             : 
    3015         105 :         comp->target = composite.data.composite.tokens;
    3016         105 :         comp->target_len = &composite.data.composite.n_members;
    3017             : 
    3018             :         /*
    3019             :          * in this loop we are looking for:
    3020             :          *
    3021             :          * a) possible whitespace.
    3022             :          * b) a comma (or terminating ')')
    3023             :          * c) more possible whitespace
    3024             :          * d) a literal, of the right type (checked after)
    3025             :          *
    3026             :          * Failures use a goto to reset comp->target, just in case we ever try
    3027             :          * continuing after error.
    3028             :          */
    3029        1399 :         while (comp->offset < comp->length) {
    3030        1399 :                 uint8_t c;
    3031        1399 :                 ok = eat_whitespace(comp, false);
    3032        1399 :                 if (! ok) {
    3033           0 :                         goto fail;
    3034             :                 }
    3035        1399 :                 c = comp->sddl[comp->offset];
    3036        1399 :                 if (c == ')') {
    3037           0 :                         break;
    3038             :                 }
    3039        1294 :                 if (!first) {
    3040        1189 :                         if (c != ',') {
    3041           0 :                                 comp_error(comp,
    3042             :                                            "malformed resource attribute ACE "
    3043             :                                            "(expected comma)");
    3044           0 :                                 goto fail;
    3045             :                         }
    3046        1189 :                         comp->offset++;
    3047             : 
    3048        1189 :                         ok = eat_whitespace(comp, false);
    3049        1189 :                         if (! ok) {
    3050           0 :                                 goto fail;
    3051             :                         }
    3052             :                 }
    3053        1294 :                 first = false;
    3054        1294 :                 if (*comp->target_len >= alloc_size) {
    3055           0 :                         comp_error(comp,
    3056             :                                    "Too many tokens in resource attribute ACE "
    3057             :                                    "(>= %"PRIu32" tokens)",
    3058           0 :                                    *comp->target_len);
    3059           0 :                         goto fail;
    3060             :                 }
    3061        1294 :                 switch(attr_type_char) {
    3062         522 :                 case 'X':
    3063         522 :                         ok = parse_ra_octet_string(comp);
    3064         522 :                         break;
    3065         295 :                 case 'S':
    3066         295 :                         ok = parse_unicode(comp);
    3067         295 :                         break;
    3068         349 :                 case 'U':
    3069         349 :                         ok = parse_uint(comp);
    3070         349 :                         break;
    3071           0 :                 case 'B':
    3072           0 :                         ok = parse_bool(comp);
    3073           0 :                         break;
    3074         128 :                 case 'I':
    3075         128 :                         ok = parse_int(comp);
    3076         128 :                         break;
    3077           0 :                 case 'D':
    3078           0 :                         ok = parse_ra_sid(comp);
    3079           0 :                         break;
    3080           0 :                 default:
    3081             :                         /* it's a mystery we got this far */
    3082           0 :                         comp_error(comp,
    3083             :                                    "unknown attribute type T%c",
    3084             :                                    attr_type_char);
    3085           0 :                         goto fail;
    3086             :                 }
    3087        1294 :                 if (!ok) {
    3088           0 :                         goto fail;
    3089             :                 }
    3090             : 
    3091        1294 :                 if (*comp->target_len == 0) {
    3092           0 :                         goto fail;
    3093             :                 }
    3094             :         }
    3095         105 :         comp->target = old_target;
    3096         105 :         comp->target_len = old_target_len;
    3097             : 
    3098             :         /*
    3099             :          * If we only ended up collecting one token into the composite, we
    3100             :          * write that instead.
    3101             :          */
    3102         105 :         if (composite.data.composite.n_members == 1) {
    3103          34 :                 ok = write_sddl_token(comp, composite.data.composite.tokens[0]);
    3104          34 :                 talloc_free(composite.data.composite.tokens);
    3105             :         } else {
    3106          71 :                 ok = write_sddl_token(comp, composite);
    3107             :         }
    3108         105 :         if (! ok) {
    3109           0 :                 goto fail;
    3110             :         }
    3111             : 
    3112           0 :         return true;
    3113           0 : fail:
    3114           0 :         comp->target = old_target;
    3115           0 :         comp->target_len = old_target_len;
    3116           0 :         TALLOC_FREE(composite.data.composite.tokens);
    3117           0 :         return false;
    3118             : }
    3119             : 
    3120             : 
    3121             : 
    3122         105 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sddl_decode_resource_attr (
    3123             :         TALLOC_CTX *mem_ctx,
    3124             :         const char *str,
    3125             :         size_t *length)
    3126             : {
    3127             :         /*
    3128             :          * Resource attribute ACEs define claims in object SACLs. They look like
    3129             :          *
    3130             :          *  "(RA; «flags» ;;;;WD;( «attribute-data» ))"
    3131             :          *
    3132             :          * attribute-data = DQUOTE 1*attr-char2 DQUOTE "," \
    3133             :          *     ( TI-attr / TU-attr / TS-attr / TD-attr / TX-attr / TB-attr )
    3134             :          * TI-attr = "TI" "," attr-flags *("," int-64)
    3135             :          * TU-attr = "TU" "," attr-flags *("," uint-64)
    3136             :          * TS-attr = "TS" "," attr-flags *("," char-string)
    3137             :          * TD-attr = "TD" "," attr-flags *("," sid-string)
    3138             :          * TX-attr = "TX" "," attr-flags *("," octet-string)
    3139             :          * TB-attr = "TB" "," attr-flags *("," ( "0" / "1" ) )
    3140             :          *
    3141             :          * and the data types are *mostly* parsed in the SDDL way,
    3142             :          * though there are significant differences for octet-strings.
    3143             :          *
    3144             :          * At this point we only have the "(«attribute-data»)".
    3145             :          *
    3146             :          * What we do is set up a conditional ACE compiler to be expecting a
    3147             :          * literal, and ask it to parse the strings between the commas. It's a
    3148             :          * hack.
    3149             :          */
    3150         105 :         bool ok;
    3151         105 :         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
    3152         105 :         struct ace_condition_sddl_compiler_context comp = {};
    3153         105 :         char attr_type;
    3154         105 :         struct ace_condition_token *tok;
    3155         105 :         uint32_t flags;
    3156         105 :         size_t len;
    3157         105 :         struct ace_condition_unicode attr_name = {};
    3158             : 
    3159         105 :         ok = init_compiler_context(mem_ctx,
    3160             :                                    &comp,
    3161             :                                    ACE_CONDITION_FLAG_ALLOW_DEVICE,
    3162             :                                    str,
    3163             :                                    3,
    3164             :                                    3);
    3165         105 :         if (!ok) {
    3166           0 :                 return NULL;
    3167             :         }
    3168         105 :         if (comp.length < 6 || comp.length > CONDITIONAL_ACE_MAX_LENGTH) {
    3169           0 :                 DBG_WARNING("invalid resource attribute: '%s'\n", str);
    3170           0 :                 goto error;
    3171             :         }
    3172             :         /*
    3173             :          *  Resource attribute ACEs list SIDs in a bare form "S-1-2-3", while
    3174             :          *  conditional ACEs use a wrapper syntax "SID(S-1-2-3)". As almost
    3175             :          *  everything is the same, we are reusing the conditional ACE parser,
    3176             :          *  with a flag set to tell the SID parser which form to expect.
    3177             :          */
    3178             : 
    3179             :         /* Most examples on the web have leading whitespace */
    3180         105 :         ok = eat_whitespace(&comp, false);
    3181         105 :         if (!ok) {
    3182           0 :                 return NULL;
    3183             :         }
    3184         105 :         if (comp.sddl[comp.offset] != '(' ||
    3185         105 :             comp.sddl[comp.offset + 1] != '"') {
    3186           0 :                 DBG_WARNING("invalid resource attribute --  expected '(\"'\n");
    3187           0 :                 goto error;
    3188             :         }
    3189         105 :         comp.offset += 2;
    3190             : 
    3191             :         /*
    3192             :          * Read the name. Here we are not reading a token into comp->program,
    3193             :          * just into a unicode blob.
    3194             :          */
    3195         105 :         len = read_attr2_string(&comp, &attr_name);
    3196             : 
    3197         105 :         if (len == -1) {
    3198           0 :                 DBG_WARNING("invalid resource attr name: %s\n", str);
    3199           0 :                 goto error;
    3200             :         }
    3201         105 :         comp.offset += len;
    3202             : 
    3203         105 :         ok = eat_whitespace(&comp, false);
    3204         105 :         if (comp.offset + 6 > comp.length) {
    3205           0 :                 DBG_WARNING("invalid resource attribute (too short): '%s'\n",
    3206             :                             str);
    3207           0 :                 goto error;
    3208             :         }
    3209             :         /*
    3210             :          * now we have the name. Next comes '",«T[IUSDXB]»,' followed
    3211             :          * by the flags, which are a 32 bit number.
    3212             :          */
    3213         105 :         if (comp.sddl[comp.offset] != '"' ||
    3214         105 :             comp.sddl[comp.offset + 1] != ','||
    3215         105 :             comp.sddl[comp.offset + 2] != 'T') {
    3216           0 :                 DBG_WARNING("expected '\",T[IUSDXB]' after attr name\n");
    3217           0 :                 goto error;
    3218             :         }
    3219         105 :         attr_type = comp.sddl[comp.offset + 3];
    3220             : 
    3221         105 :         if (comp.sddl[comp.offset + 4] != ',') {
    3222           0 :                 DBG_WARNING("expected ',' after attr type\n");
    3223           0 :                 goto error;
    3224             :         }
    3225         105 :         comp.offset += 5;
    3226         105 :         comp.state = SDDL_FLAG_EXPECTING_LITERAL;
    3227         105 :         ok = parse_literal(&comp, false);
    3228         105 :         if (!ok ||
    3229         105 :             comp.program->length != 1) {
    3230           0 :                 DBG_WARNING("invalid attr flags: %s\n", str);
    3231           0 :                 goto error;
    3232             :         }
    3233             : 
    3234         105 :         tok = &comp.program->tokens[0];
    3235         105 :         if (tok->type != CONDITIONAL_ACE_TOKEN_INT64 ||
    3236         105 :             tok->data.int64.value < 0 ||
    3237           0 :             tok->data.int64.value > UINT32_MAX) {
    3238           0 :                 DBG_WARNING("invalid attr flags (want 32 bit int): %s\n", str);
    3239           0 :                 goto error;
    3240             :         }
    3241         105 :         flags = tok->data.int64.value;
    3242         105 :         if (flags & 0xff00) {
    3243           0 :                 DBG_WARNING("invalid attr flags, "
    3244             :                             "stepping on reserved 0xff00 range: %s\n",
    3245             :                             str);
    3246           0 :                 goto error;
    3247             :         }
    3248         105 :         if (comp.offset + 3 > comp.length) {
    3249           0 :                 DBG_WARNING("invalid resource attribute (too short): '%s'\n",
    3250             :                             str);
    3251           0 :                 goto error;
    3252             :         }
    3253         105 :         if (comp.sddl[comp.offset] != ',') {
    3254           0 :                 DBG_WARNING("invalid resource attribute ace\n");
    3255           0 :                 goto error;
    3256             :         }
    3257         105 :         comp.offset++;
    3258             : 
    3259         105 :         ok = parse_resource_attr_list(&comp, attr_type);
    3260         105 :         if (!ok || comp.program->length != 2) {
    3261           0 :                 DBG_WARNING("invalid attribute type or value: T%c, %s\n",
    3262             :                             attr_type, str);
    3263           0 :                 goto error;
    3264             :         }
    3265         105 :         if (comp.sddl[comp.offset] != ')') {
    3266           0 :                 DBG_WARNING("expected trailing ')'\n");
    3267           0 :                 goto error;
    3268             :         }
    3269         105 :         comp.offset++;
    3270         105 :         *length = comp.offset;
    3271             : 
    3272         210 :         ok = ace_token_to_claim_v1(mem_ctx,
    3273             :                                    attr_name.value,
    3274         105 :                                    &comp.program->tokens[1],
    3275             :                                    &claim,
    3276             :                                    flags);
    3277         105 :         if (!ok) {
    3278           0 :                 goto error;
    3279             :         }
    3280         105 :         TALLOC_FREE(comp.program);
    3281         105 :         return claim;
    3282           0 :   error:
    3283           0 :         TALLOC_FREE(comp.program);
    3284           0 :         return NULL;
    3285             : }
    3286             : 
    3287             : 
    3288          23 : static bool write_resource_attr_from_token(struct sddl_write_context *ctx,
    3289             :                                            const struct ace_condition_token *tok)
    3290             : {
    3291             :         /*
    3292             :          * this is a helper for sddl_resource_attr_from_claim(),
    3293             :          * recursing into composites if necessary.
    3294             :          */
    3295          23 :         bool ok;
    3296          23 :         char *sid = NULL;
    3297          23 :         size_t i;
    3298          23 :         const struct ace_condition_composite *c = NULL;
    3299          23 :         switch (tok->type) {
    3300           0 :         case CONDITIONAL_ACE_TOKEN_INT64:
    3301             :                 /*
    3302             :                  * Note that this includes uint and bool claim types,
    3303             :                  * but we don't check the validity of the ranges (0|1
    3304             :                  * and >=0, respectively), rather we trust the claim
    3305             :                  * to be self-consistent in this regard. Going the
    3306             :                  * other way, string-to-claim, we do check.
    3307             :                  */
    3308           0 :                 return sddl_write_int(ctx, tok);
    3309             : 
    3310          10 :         case CONDITIONAL_ACE_TOKEN_UNICODE:
    3311          10 :                 return sddl_write_unicode(ctx, tok);
    3312             : 
    3313           0 :         case CONDITIONAL_ACE_TOKEN_SID:
    3314             :                 /* unlike conditional ACE, SID does not have a "SID()" wrapper. */
    3315           0 :                 sid = sddl_encode_sid(ctx->mem_ctx, &tok->data.sid.sid, NULL);
    3316           0 :                 if (sid == NULL) {
    3317           0 :                         return false;
    3318             :                 }
    3319           0 :                 return sddl_write(ctx, sid);
    3320             : 
    3321           6 :         case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
    3322           6 :                 return sddl_write_ra_octet_string(ctx, tok);
    3323             : 
    3324           0 :         case CONDITIONAL_ACE_TOKEN_COMPOSITE:
    3325             :                 /*
    3326             :                  * write each token, separated by commas. If there
    3327             :                  * were nested composites, this would flatten them,
    3328             :                  * but that isn't really possible because the token we
    3329             :                  * are dealing with came from a claim, which has no
    3330             :                  * facility for nesting.
    3331             :                  */
    3332          23 :                 c = &tok->data.composite;
    3333          23 :                 for(i = 0; i < c->n_members; i++) {
    3334          16 :                         ok = write_resource_attr_from_token(ctx, &c->tokens[i]);
    3335          16 :                         if (!ok) {
    3336           0 :                                 return false;
    3337             :                         }
    3338          16 :                         if (i != c->n_members - 1) {
    3339           9 :                                 ok = sddl_write(ctx, ",");
    3340           9 :                                 if (!ok) {
    3341           0 :                                         return false;
    3342             :                                 }
    3343             :                         }
    3344             :                 }
    3345           0 :                 return true;
    3346           0 :         default:
    3347             :                 /* We really really don't expect to get here */
    3348           0 :                 return false;
    3349             :         }
    3350             : }
    3351             : 
    3352           7 : char *sddl_resource_attr_from_claim(
    3353             :         TALLOC_CTX *mem_ctx,
    3354             :         const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim)
    3355             : {
    3356           7 :         char *s = NULL;
    3357           7 :         char attr_type;
    3358           7 :         bool ok;
    3359           7 :         struct ace_condition_token tok = {};
    3360           7 :         struct sddl_write_context ctx = {};
    3361           7 :         TALLOC_CTX *tmp_ctx = NULL;
    3362           7 :         char *name = NULL;
    3363           7 :         size_t name_len;
    3364             : 
    3365           7 :         switch(claim->value_type) {
    3366           0 :         case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
    3367           0 :                 attr_type = 'I';
    3368           0 :                 break;
    3369           0 :         case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
    3370           0 :                 attr_type = 'U';
    3371           0 :                 break;
    3372           6 :         case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
    3373           6 :                 attr_type = 'S';
    3374           6 :                 break;
    3375           0 :         case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
    3376           0 :                 attr_type = 'D';
    3377           0 :                 break;
    3378           0 :         case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
    3379           0 :                 attr_type = 'B';
    3380           0 :                 break;
    3381           1 :         case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
    3382           1 :                 attr_type = 'X';
    3383           1 :                 break;
    3384           0 :         default:
    3385           0 :                 return NULL;
    3386             :         }
    3387             : 
    3388           7 :         tmp_ctx = talloc_new(mem_ctx);
    3389           7 :         if (tmp_ctx == NULL) {
    3390           0 :                 return NULL;
    3391             :         }
    3392           7 :         ctx.mem_ctx = tmp_ctx;
    3393             : 
    3394           7 :         ok = claim_v1_to_ace_composite_unchecked(tmp_ctx, claim, &tok);
    3395           7 :         if (!ok) {
    3396           0 :                 TALLOC_FREE(tmp_ctx);
    3397           0 :                 return NULL;
    3398             :         }
    3399             : 
    3400             :         /* this will construct the proper string in ctx.sddl */
    3401           7 :         ok = write_resource_attr_from_token(&ctx, &tok);
    3402           7 :         if (!ok) {
    3403           0 :                 TALLOC_FREE(tmp_ctx);
    3404           0 :                 return NULL;
    3405             :         }
    3406             : 
    3407             :         /* escape the claim name */
    3408          14 :         ok = sddl_encode_attr_name(tmp_ctx,
    3409           7 :                                    claim->name,
    3410             :                                    &name, &name_len);
    3411             : 
    3412           7 :         if (!ok) {
    3413           0 :                 TALLOC_FREE(tmp_ctx);
    3414           0 :                 return NULL;
    3415             :         }
    3416             : 
    3417          14 :         s = talloc_asprintf(mem_ctx,
    3418             :                             "(\"%s\",T%c,0x%x,%s)",
    3419             :                             name,
    3420             :                             attr_type,
    3421           7 :                             claim->flags,
    3422             :                             ctx.sddl);
    3423           7 :         TALLOC_FREE(tmp_ctx);
    3424           7 :         return s;
    3425             : }
    3426             : 
    3427             : 
    3428          40 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *parse_sddl_literal_as_claim(
    3429             :         TALLOC_CTX *mem_ctx,
    3430             :         const char *name,
    3431             :         const char *str)
    3432             : {
    3433             :         /*
    3434             :          * For testing purposes (and possibly for client tools), we
    3435             :          * want to be able to create claim literals, and we might as
    3436             :          * well use the SDDL syntax. So we pretend to be parsing SDDL
    3437             :          * for one literal.
    3438             :          */
    3439          40 :         bool ok;
    3440          40 :         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
    3441          40 :         struct ace_condition_sddl_compiler_context comp = {};
    3442             : 
    3443          40 :         ok = init_compiler_context(mem_ctx,
    3444             :                                    &comp,
    3445             :                                    ACE_CONDITION_FLAG_ALLOW_DEVICE,
    3446             :                                    str,
    3447             :                                    2,
    3448             :                                    2);
    3449          40 :         if (!ok) {
    3450           0 :                 return NULL;
    3451             :         }
    3452             : 
    3453          40 :         comp.state = SDDL_FLAG_EXPECTING_LITERAL;
    3454          40 :         ok = parse_literal(&comp, false);
    3455             : 
    3456          40 :         if (!ok) {
    3457           0 :                 goto error;
    3458             :         }
    3459          40 :         if (comp.program->length != 1) {
    3460           0 :                 goto error;
    3461             :         }
    3462             : 
    3463          80 :         ok = ace_token_to_claim_v1(mem_ctx,
    3464             :                                    name,
    3465          40 :                                    &comp.program->tokens[0],
    3466             :                                    &claim,
    3467             :                                    0);
    3468          40 :         if (!ok) {
    3469           0 :                 goto error;
    3470             :         }
    3471          40 :         TALLOC_FREE(comp.program);
    3472          40 :         return claim;
    3473           0 :   error:
    3474           0 :         TALLOC_FREE(comp.program);
    3475           0 :         return NULL;
    3476             : }

Generated by: LCOV version 1.14