]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
libcli/security: add claims_tf_rule_set_parse_blob() for MS-CTA rules
authorStefan Metzmacher <metze@samba.org>
Mon, 13 Jan 2025 23:35:24 +0000 (00:35 +0100)
committerRalph Boehme <slow@samba.org>
Fri, 14 Feb 2025 10:58:40 +0000 (10:58 +0000)
It parses [MS-CTA] rules into structures.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
libcli/security/claims_transformation.h [new file with mode: 0644]
libcli/security/claims_transformation.l [new file with mode: 0644]
libcli/security/claims_transformation.y [new file with mode: 0644]
libcli/security/wscript_build

diff --git a/libcli/security/claims_transformation.h b/libcli/security/claims_transformation.h
new file mode 100644 (file)
index 0000000..8027d85
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2025
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LIBCLI_SECURITY_CLAIMS_TRANSFORMATION_H_
+#define _LIBCLI_SECURITY_CLAIMS_TRANSFORMATION_H_
+
+#include "librpc/gen_ndr/claims.h"
+
+struct claims_tf_claim {
+       const char *type;
+       enum CLAIM_TYPE value_type;
+       union {
+               int64_t ival;
+               uint64_t uval;
+               const char *string;
+               bool bval;
+       } value;
+};
+
+bool claims_tf_rule_set_parse_blob(const DATA_BLOB *blob,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct claims_tf_rule_set **__rule_set,
+                                  char **_error_string);
+
+#ifdef CLAIMS_TRANSFORMATION_INTERNALS
+
+struct claims_tf_parser_state {
+       struct claims_tf_rule_set *rule_set;
+       struct {
+               int first_line;
+               int first_column;
+               int last_line;
+               int last_column;
+               char *string;
+       } error;
+};
+
+struct claims_tf_condition_ctr {
+       struct claims_tf_condition_ctr *prev;
+       struct claims_tf_condition *c1;
+       struct claims_tf_condition *c2;
+};
+struct claims_tf_condition_set_ctr {
+       struct claims_tf_condition_set_ctr *prev;
+       struct claims_tf_condition_set *set;
+};
+struct claims_tf_rule_ctr {
+       struct claims_tf_rule *rule;
+       struct claims_tf_rule_ctr *next;
+};
+
+struct claim_copy {
+       const char *identifier;
+};
+
+struct Cond_oper {
+       /*
+        * CLAIMS_TF_YY_EQ               => CLAIMS_TF_CONDITION_OPERATOR_EQ
+        * CLAIMS_TF_YY_NEQ              => CLAIMS_TF_CONDITION_OPERATOR_NEQ
+        * CLAIMS_TF_YY_REGEXP_MATCH     => CLAIMS_TF_CONDITION_OPERATOR_REGEXP_MATCH
+        * CLAIMS_TF_YY_REGEXP_NOT_MATCH => CLAIMS_TF_CONDITION_OPERATOR_REGEXP_NOT_MATCH
+        */
+       enum claims_tf_condition_operator operator;
+};
+
+struct Literal {
+       const char *str;
+};
+
+struct claim_prop {
+       /*
+        * CLAIMS_TF_YY_{TYPE,VALUE,VALUE_TYPE}
+        * =>
+        * CLAIMS_TF_PROPERTY_{TYPE,VALUE,VALUE_TYPE}
+        *
+        * Here we only have TYPE or VALUE
+        */
+       enum claims_tf_property_enum property;
+};
+
+struct Expr {
+       bool has_literal;
+       struct Literal literal;
+       struct {
+               const char *identifier;
+               /*
+                * CLAIMS_TF_YY_{TYPE,VALUE,VALUE_TYPE}
+                * =>
+                * CLAIMS_TF_PROPERTY_{TYPE,VALUE,VALUE_TYPE}
+                *
+                * Here we only have TYPE or VALUE
+                */
+               enum claims_tf_property_enum property;
+       } claim;
+};
+
+struct claim_type_assign {
+       struct Expr expr;
+};
+
+struct claim_val_type_assign {
+       struct Expr expr;
+};
+
+struct claim_val_assign {
+       struct Expr expr;
+};
+
+struct claim_value_assign {
+       struct claim_val_type_assign vt;
+       struct claim_val_assign val;
+};
+
+struct claim_new {
+       struct claim_type_assign type;
+       struct claim_value_assign value;
+};
+
+_PRIVATE_ enum CLAIM_TYPE claims_tf_type_from_string(const char *str);
+
+#endif /* CLAIMS_TRANSFORMATION_INTERNALS */
+#endif /* _LIBCLI_SECURITY_CLAIMS_TRANSFORMATION_H_ */
diff --git a/libcli/security/claims_transformation.l b/libcli/security/claims_transformation.l
new file mode 100644 (file)
index 0000000..4594adb
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2025
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+%{
+#include "includes.h"
+#define CLAIMS_TRANSFORMATION_INTERNALS 1
+#include "libcli/security/claims_transformation.h"
+#include "libcli/security/claims_transformation.tab.h"
+
+#undef strcasecmp
+
+static char *strip_quote(const char *phrase);
+
+#define YYSTYPE __CLAIMS_TF_YY_STYPE
+#define YYLTYPE __CLAIMS_TF_YY_LTYPE
+
+_PRIVATE_ int __claims_tf_yy_lex(
+       YYSTYPE * yylval_param,
+       YYLTYPE * yylloc_param,
+       struct claims_tf_parser_state *ctf_ps,
+       yyscan_t yyscanner);
+
+#define YY_DECL int __claims_tf_yy_lex \
+       (YYSTYPE * yylval_param, \
+       YYLTYPE * yylloc_param, \
+       struct claims_tf_parser_state *ctf_ps, \
+       yyscan_t yyscanner)
+
+#define YY_USER_ACTION do { \
+       size_t __idx; \
+       yylloc->first_line = yylloc->last_line; \
+       yylloc->first_column = yylloc->last_column; \
+       for (__idx = 0; yytext[__idx] != '\0'; __idx++) { \
+               if (yytext[__idx] == '\n') { \
+                       yylloc->last_line++; \
+                       yylloc->last_column = 0; \
+               } else { \
+                       yylloc->last_column++; \
+               } \
+       } \
+       ctf_ps->error.first_line = yylloc->first_line; \
+       ctf_ps->error.first_column = yylloc->first_column; \
+       ctf_ps->error.last_line = yylloc->last_line; \
+       ctf_ps->error.last_column = yylloc->last_column; \
+} while(0);
+
+%}
+
+%option prefix="__claims_tf_yy_"
+%option case-insensitive
+%option bison-bridge
+%option bison-locations
+%option reentrant
+
+%option noyywrap
+%option nounput
+%option noyyalloc
+%option noyyrealloc
+%option noyyfree
+
+%option noinput
+%option nounput
+%option noyylineno
+%option noyy_push_state
+%option noyy_pop_state
+%option noyy_top_state
+%option noyyget_leng
+%option noyyget_text
+%option noyyget_lineno
+%option noyyset_lineno
+%option noyyget_in
+%option noyyset_in
+%option noyyget_out
+%option noyyset_out
+%option noyyget_lval
+%option noyyset_lval
+%option noyyget_lloc
+%option noyyset_lloc
+%option noyyget_debug
+%option noyyset_debug
+
+%%
+\=\>                       return CLAIMS_TF_YY_IMPLY;
+\;                         return CLAIMS_TF_YY_SEMICOLON;
+\:                         return CLAIMS_TF_YY_COLON;
+\,                         return CLAIMS_TF_YY_COMMA;
+\.                         return CLAIMS_TF_YY_DOT;
+\[                         return CLAIMS_TF_YY_O_SQ_BRACKET;
+\]                         return CLAIMS_TF_YY_C_SQ_BRACKET;
+\(                         return CLAIMS_TF_YY_O_BRACKET;
+\)                         return CLAIMS_TF_YY_C_BRACKET;
+\=\=                       return CLAIMS_TF_YY_EQ;
+\!\=                       return CLAIMS_TF_YY_NEQ;
+\=\~                       return CLAIMS_TF_YY_REGEXP_MATCH;
+\!\~                       return CLAIMS_TF_YY_REGEXP_NOT_MATCH;
+\=                         return CLAIMS_TF_YY_ASSIGN;
+\&\&                       return CLAIMS_TF_YY_AND;
+issue                      return CLAIMS_TF_YY_ISSUE;
+type                       return CLAIMS_TF_YY_TYPE;
+value                      return CLAIMS_TF_YY_VALUE;
+valuetype                  return CLAIMS_TF_YY_VALUE_TYPE;
+claim                      return CLAIMS_TF_YY_CLAIM;
+[_A-Za-z][_A-Za-z0-9]*     {yylval->sval = talloc_strdup(talloc_tos(), yytext); return CLAIMS_TF_YY_IDENTIFIER;}
+\"[^\"\n]*\"               {yylval->sval = strip_quote(yytext); return CLAIMS_TF_YY_STRING;}
+[ \t\n]                    /* ignore */
+%%
+
+
+
+static char *strip_quote(const char *phrase)
+{
+       size_t phrase_len = 0;
+       char *stripped_phrase = NULL;
+
+       if (phrase == NULL) {
+               return NULL;
+       }
+
+       phrase_len = strlen(phrase);
+       if (phrase_len < 2 ||
+           phrase[0] != '\"' ||
+           phrase[phrase_len - 1] != '\"')
+       {
+               return talloc_strdup(talloc_tos(), phrase);
+       }
+
+       phrase++;
+
+       stripped_phrase = talloc_strndup(talloc_tos(), phrase, phrase_len - 2);
+       if (stripped_phrase == NULL) {
+               return NULL;
+       }
+       return stripped_phrase;
+}
+
+_PRIVATE_ void *yyalloc(yy_size_t bytes, yyscan_t yyscanner)
+{
+       return talloc_size(yyscanner, bytes);
+}
+
+_PRIVATE_ void *yyrealloc(void *ptr, yy_size_t bytes, yyscan_t yyscanner)
+{
+       return talloc_realloc_size(yyscanner, ptr, bytes);
+}
+
+_PRIVATE_ void yyfree(void *ptr, yyscan_t yyscanner)
+{
+       if (ptr == yyscanner) {
+               talloc_free(yyscanner);
+       } else {
+               talloc_unlink(yyscanner, ptr);
+       }
+}
+
+_PRIVATE_ enum CLAIM_TYPE claims_tf_type_from_string(const char *str)
+{
+       int cmp;
+
+       cmp = strcasecmp(str, "int64");
+       if (cmp == 0) {
+               return CLAIM_TYPE_INT64;
+       }
+
+       cmp = strcasecmp(str, "uint64");
+       if (cmp == 0) {
+               return CLAIM_TYPE_UINT64;
+       }
+
+       cmp = strcasecmp(str, "string");
+       if (cmp == 0) {
+               return CLAIM_TYPE_STRING;
+       }
+
+       cmp = strcasecmp(str, "boolean");
+       if (cmp == 0) {
+               return CLAIM_TYPE_STRING;
+       }
+
+       return 0;
+}
+
+static bool claims_tf_rule_verify_conditions(const struct claims_tf_rule *rule)
+{
+       uint32_t csi;
+
+       /*
+        * TODO: do we need to verify that all
+        * optional condition_set identifiers
+        * are unique?
+        *
+        * At least the powershell commands
+        * on Windows don't verify this.
+        */
+
+       for (csi = 0; csi < rule->num_condition_sets; csi++) {
+               const struct claims_tf_condition_set *cs =
+                       &rule->condition_sets[csi];
+               uint32_t ci;
+
+               for (ci = 0; ci < cs->num_conditions; ci++) {
+                       const struct claims_tf_condition *c =
+                               &cs->conditions[ci];
+                       enum CLAIM_TYPE vt;
+
+                       if (c->string == NULL) {
+                               return false;
+                       }
+
+                       if (c->property != CLAIMS_TF_PROPERTY_VALUE_TYPE) {
+                               continue;
+                       }
+
+                       vt = claims_tf_type_from_string(c->string);
+                       if (vt == 0) {
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+static bool claims_tf_rule_verify_vt_action(const struct claims_tf_rule *rule,
+                                     const struct claims_tf_property *property)
+{
+       if (property->ref.property == CLAIMS_TF_PROPERTY_INVALID) {
+               enum CLAIM_TYPE vt;
+
+               if (property->string == NULL) {
+                       return false;
+               }
+
+               vt = claims_tf_type_from_string(property->string);
+               if (vt == 0) {
+                       return false;
+               }
+
+               return true;
+       }
+
+       if (property->ref.property != CLAIMS_TF_PROPERTY_VALUE_TYPE) {
+               return false;
+       }
+
+       return true;
+}
+
+static bool claims_tf_rule_verify_action(const struct claims_tf_rule *rule,
+                                  const struct claims_tf_property *property)
+{
+       uint32_t csi;
+
+       if (property->ref.property == CLAIMS_TF_PROPERTY_INVALID) {
+               if (property->string == NULL) {
+                       return false;
+               }
+               return true;
+       }
+
+       if (property->ref.identifier == NULL) {
+               return false;
+       }
+
+       for (csi = 0; csi < rule->num_condition_sets; csi++) {
+               const struct claims_tf_condition_set *cs =
+                       &rule->condition_sets[csi];
+               bool ok;
+
+               if (cs->opt_identifier == NULL) {
+                       continue;
+               }
+
+               ok = strequal(property->ref.identifier,
+                             cs->opt_identifier);
+               if (ok) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+_PUBLIC_ bool claims_tf_rule_set_parse_blob(const DATA_BLOB *blob,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct claims_tf_rule_set **_rule_set,
+                                     char **_error_string)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct claims_tf_parser_state *ctf_ps = NULL;
+       yyscan_t scanner = NULL;
+       YY_BUFFER_STATE buf = NULL;
+       uint32_t ri;
+       int rc;
+
+#if __CLAIMS_TF_YY_DEBUG != 0
+       __claims_tf_yy_debug = 1;
+#endif
+
+       rc = yylex_init(&scanner);
+       if (rc != 0) {
+               if (_error_string != NULL) {
+                       *_error_string = talloc_asprintf(mem_ctx,
+                                               "yylex_init failed rc=%d",
+                                               rc);
+               }
+
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       buf = yy_scan_bytes((const char *)blob->data,
+                           blob->length,
+                           scanner);
+       if (buf == NULL) {
+               if (_error_string != NULL) {
+                       *_error_string = talloc_asprintf(mem_ctx,
+                                               "yy_scan_bytes(length=%zu) failed",
+                                               blob->length);
+               }
+
+               yylex_destroy(scanner);
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       ctf_ps = talloc_zero(frame, struct claims_tf_parser_state);
+       if (ctf_ps == NULL) {
+               if (_error_string != NULL) {
+                       *_error_string = talloc_asprintf(mem_ctx,
+                                               "talloc_zero failed");
+               }
+
+               yy_delete_buffer(buf, scanner);
+               yylex_destroy(scanner);
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       rc = __claims_tf_yy_parse(ctf_ps, scanner);
+       if (rc != 0) {
+               if (_error_string != NULL && ctf_ps->error.string != NULL) {
+                       *_error_string = talloc_asprintf(mem_ctx,
+                                               "__claims_tf_yy_parse() failed rc=%d "
+                                               "fl=%d,fc=%d,ll=%d,lc=%d: %s",
+                                               rc,
+                                               ctf_ps->error.first_line,
+                                               ctf_ps->error.first_column,
+                                               ctf_ps->error.last_line,
+                                               ctf_ps->error.last_column,
+                                               ctf_ps->error.string);
+               } else if (_error_string != NULL) {
+                       *_error_string = talloc_asprintf(mem_ctx,
+                                               "__claims_tf_yy_parse() failed rc=%d",
+                                               rc);
+               }
+
+               yy_delete_buffer(buf, scanner);
+               yylex_destroy(scanner);
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       yy_delete_buffer(buf, scanner);
+       yylex_destroy(scanner);
+
+       for (ri = 0; ri < ctf_ps->rule_set->num_rules; ri++) {
+               const struct claims_tf_rule *r =
+                       &ctf_ps->rule_set->rules[ri];
+               bool ok;
+
+               ok = claims_tf_rule_verify_conditions(r);
+               if (!ok) {
+                       if (_error_string != NULL) {
+                               *_error_string = talloc_asprintf(mem_ctx,
+                                               "rule[%"PRIu32"] "
+                                               "has invalid conditions",
+                                               ri);
+                       }
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+
+               ok = claims_tf_rule_verify_vt_action(r, &r->action.value_type);
+               if (!ok) {
+                       if (_error_string != NULL) {
+                               *_error_string = talloc_asprintf(mem_ctx,
+                                               "rule[%"PRIu32"] "
+                                               "action.value_type invalid value type specifier",
+                                               ri);
+                       }
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+
+               /*
+                * Now verify that identifiers used
+                * in rule actions are also used
+                * as condition_set identifier.
+                */
+
+               ok = claims_tf_rule_verify_action(r, &r->action.type);
+               if (!ok) {
+                       if (_error_string != NULL) {
+                               *_error_string = talloc_asprintf(mem_ctx,
+                                               "rule[%"PRIu32"] "
+                                               "action.type invalid tidentifier %s",
+                                               ri, r->action.type.ref.identifier);
+                       }
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+
+               ok = claims_tf_rule_verify_action(r, &r->action.value);
+               if (!ok) {
+                       if (_error_string != NULL) {
+                               *_error_string = talloc_asprintf(mem_ctx,
+                                               "rule[%"PRIu32"] "
+                                               "action.value invalid tidentifier %s",
+                                               ri, r->action.type.ref.identifier);
+                       }
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+
+               ok = claims_tf_rule_verify_action(r, &r->action.value_type);
+               if (!ok) {
+                       if (_error_string != NULL) {
+                               *_error_string = talloc_asprintf(mem_ctx,
+                                               "rule[%"PRIu32"] "
+                                               "action.value_type invalid tidentifier %s",
+                                               ri, r->action.type.ref.identifier);
+                       }
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+       }
+
+       *_rule_set = talloc_move(mem_ctx, &ctf_ps->rule_set);
+       TALLOC_FREE(frame);
+
+       if (_error_string != NULL) {
+               *_error_string = NULL;
+       }
+
+       return true;
+}
diff --git a/libcli/security/claims_transformation.y b/libcli/security/claims_transformation.y
new file mode 100644 (file)
index 0000000..9f34a0f
--- /dev/null
@@ -0,0 +1,977 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2025
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+%{
+#include "includes.h"
+#define CLAIMS_TRANSFORMATION_INTERNALS 1
+#include "libcli/security/claims_transformation.h"
+#include "libcli/security/claims_transformation.tab.h"
+#pragma GCC diagnostic ignored "-Wstrict-overflow"
+
+/* forward declarations */
+struct claims_tf_parser_state;
+
+static struct claims_tf_rule_set *
+claims_tf_rule_set_prepare(struct claims_tf_parser_state *ctf_ps,
+                          struct claims_tf_rule_ctr *list);
+static struct claims_tf_rule_ctr *
+claims_tf_rule_ctr_prepare(struct claims_tf_parser_state *ctf_ps,
+                          struct claims_tf_rule *rule,
+                          struct claims_tf_rule_ctr *next);
+static struct claims_tf_rule *
+claims_tf_rule_prepare(struct claims_tf_parser_state *ctf_ps,
+                      const struct claim_copy *c_copy,
+                      const struct claim_new *c_new);
+static struct claims_tf_rule *
+claims_tf_rule_attach_conditions(struct claims_tf_rule *rule,
+                                struct claims_tf_condition_set_ctr *list);
+static struct claims_tf_condition_set_ctr *
+claims_tf_condition_set_ctr_prepare(struct claims_tf_parser_state *ctf_ps,
+                                   struct claims_tf_condition_set *set,
+                                   struct claims_tf_condition_set_ctr *prev);
+static struct claims_tf_condition_set *
+claims_tf_condition_set_prepare(struct claims_tf_parser_state *ctf_ps,
+                               const struct claims_tf_condition_ctr *list,
+                               const char *identifier);
+static struct claims_tf_condition_ctr *
+claims_tf_condition_ctr_prepare(struct claims_tf_parser_state *ctf_ps,
+                               struct claims_tf_condition *c1,
+                               struct claims_tf_condition *c2);
+static struct claims_tf_condition_ctr *
+claims_tf_condition_ctr_attach_prev(struct claims_tf_condition_ctr *ctr,
+                                   struct claims_tf_condition_ctr *prev);
+static struct claims_tf_condition *
+claims_tf_condition_prepare(struct claims_tf_parser_state *ctf_ps,
+                           enum claims_tf_property_enum property,
+                           enum claims_tf_condition_operator operator,
+                           const struct Literal *expr);
+
+static void __claims_tf_yy_error(__CLAIMS_TF_YY_LTYPE *llocp,
+                                struct claims_tf_parser_state *ctf_ps,
+                                void *yyscanner,
+                                const char *str);
+
+_PRIVATE_ int __claims_tf_yy_lex(__CLAIMS_TF_YY_STYPE * yylval_param,
+                                __CLAIMS_TF_YY_LTYPE * yylloc_param ,
+                                struct claims_tf_parser_state *ctf_ps,
+                                void *yyscanner);
+%}
+
+%code provides {
+}
+
+%union {
+       int ival;
+       const char *sval;
+       struct claims_tf_rule_set *rule_set;
+       struct claims_tf_rule_ctr *rule_ctr;
+       struct claims_tf_rule *rule;
+       struct claims_tf_condition_set_ctr *condition_set_ctr;
+       struct claims_tf_condition_set *condition_set;
+       struct claims_tf_condition_ctr *condition_ctr;
+       struct claims_tf_condition *condition;
+       struct claim_prop prop;
+       struct Cond_oper oper;
+       struct Expr expr;
+       struct Literal literal;
+       struct claim_copy c_copy;
+       struct claim_new c_new;
+       struct claim_value_assign value_assign;
+       struct claim_val_assign val_assign;
+       struct claim_val_type_assign val_type_assign;
+       struct claim_type_assign type_assign;
+}
+
+%define api.prefix {__claims_tf_yy_}
+%define parse.error verbose
+
+/* %define parse.trace */
+
+%define api.pure full
+%locations
+%lex-param {struct claims_tf_parser_state *ctf_ps}
+%lex-param {void *yyscanner}
+%parse-param {struct claims_tf_parser_state *ctf_ps}
+%parse-param {void *yyscanner}
+
+
+%type <ival> CLAIMS_TF_YY_TYPE CLAIMS_TF_YY_VALUE CLAIMS_TF_YY_EQ CLAIMS_TF_YY_NEQ CLAIMS_TF_YY_REGEXP_MATCH CLAIMS_TF_YY_REGEXP_NOT_MATCH
+%type <sval> CLAIMS_TF_YY_IDENTIFIER CLAIMS_TF_YY_STRING
+%type <rule_set> Rule_set
+%type <rule_ctr> Rules
+%type <rule> Rule Issue_params Rule_action Rule_body
+%type <condition_set_ctr> Conditions Sel_condition_list
+%type <condition_set> Sel_condition
+%type <condition_ctr> Sel_condition_body Opt_cond_list Cond_list Cond Value_cond
+%type <condition> Type_cond Val_cond Val_type_cond
+%type <prop> claim_prop
+%type <oper> Cond_oper
+%type <expr> Expr
+%type <literal> Literal
+%type <c_copy> claim_copy
+%type <c_new> claim_new claim_prop_assign_list
+%type <value_assign> claim_value_assign
+%type <val_assign> claim_val_assign
+%type <val_type_assign> claim_val_type_assign
+%type <type_assign> claim_type_assign
+
+%token CLAIMS_TF_YY_IMPLY
+%token CLAIMS_TF_YY_SEMICOLON
+%token CLAIMS_TF_YY_COLON
+%token CLAIMS_TF_YY_COMMA
+%token CLAIMS_TF_YY_DOT
+%token CLAIMS_TF_YY_O_SQ_BRACKET
+%token CLAIMS_TF_YY_C_SQ_BRACKET
+%token CLAIMS_TF_YY_O_BRACKET
+%token CLAIMS_TF_YY_C_BRACKET
+%token CLAIMS_TF_YY_EQ
+%token CLAIMS_TF_YY_NEQ
+%token CLAIMS_TF_YY_REGEXP_MATCH
+%token CLAIMS_TF_YY_REGEXP_NOT_MATCH
+%token CLAIMS_TF_YY_ASSIGN
+%token CLAIMS_TF_YY_AND
+%token CLAIMS_TF_YY_ISSUE
+%token CLAIMS_TF_YY_TYPE
+%token CLAIMS_TF_YY_VALUE
+%token CLAIMS_TF_YY_VALUE_TYPE
+%token CLAIMS_TF_YY_CLAIM
+%token CLAIMS_TF_YY_IDENTIFIER
+%token CLAIMS_TF_YY_STRING
+
+%%
+
+Rule_set:
+%empty {
+       $$ = claims_tf_rule_set_prepare(ctf_ps, NULL);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+| Rules {
+       $$ = claims_tf_rule_set_prepare(ctf_ps, $1);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Rules:
+Rule {
+       $$ = claims_tf_rule_ctr_prepare(ctf_ps, $1, NULL);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+|
+Rule Rules {
+       $$ = claims_tf_rule_ctr_prepare(ctf_ps, $1, $2);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Rule:
+Rule_body {
+       $$ = $1;
+}
+;
+
+Rule_body:
+Conditions CLAIMS_TF_YY_IMPLY Rule_action CLAIMS_TF_YY_SEMICOLON {
+       $$ = claims_tf_rule_attach_conditions($3, $1);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Conditions:
+%empty {
+       $$ = NULL;
+}
+|
+Sel_condition_list {
+       $$ = $1;
+}
+;
+
+Sel_condition_list:
+Sel_condition {
+       $$ = claims_tf_condition_set_ctr_prepare(ctf_ps, $1, NULL);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+|
+Sel_condition_list CLAIMS_TF_YY_AND Sel_condition {
+       $$ = claims_tf_condition_set_ctr_prepare(ctf_ps, $3, $1);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Sel_condition:
+Sel_condition_body {
+       $$ = claims_tf_condition_set_prepare(ctf_ps, $1, NULL);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+|
+CLAIMS_TF_YY_IDENTIFIER CLAIMS_TF_YY_COLON Sel_condition_body {
+       if ($1 == NULL) {
+               YYERROR;
+       }
+       $$ = claims_tf_condition_set_prepare(ctf_ps, $3, $1);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Sel_condition_body:
+CLAIMS_TF_YY_O_SQ_BRACKET Opt_cond_list CLAIMS_TF_YY_C_SQ_BRACKET {
+       $$ = $2;
+}
+;
+
+Opt_cond_list:
+%empty {
+       $$ = NULL;
+}
+|
+Cond_list {
+       $$ = $1;
+}
+;
+
+Cond_list:
+Cond {
+       $$ = $1;
+}
+|
+Cond_list CLAIMS_TF_YY_COMMA Cond {
+       $$ = claims_tf_condition_ctr_attach_prev($3, $1);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Cond:
+Value_cond {
+       $$ = $1;
+}
+|
+Type_cond {
+       $$ = claims_tf_condition_ctr_prepare(ctf_ps, $1, NULL);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Type_cond:
+CLAIMS_TF_YY_TYPE Cond_oper Literal {
+       $$ = claims_tf_condition_prepare(ctf_ps,
+                                        CLAIMS_TF_PROPERTY_TYPE,
+                                        $2.operator,
+                                        &$3);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Value_cond:
+Val_cond CLAIMS_TF_YY_COMMA Val_type_cond {
+       $$ = claims_tf_condition_ctr_prepare(ctf_ps, $1, $3);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+|
+Val_type_cond CLAIMS_TF_YY_COMMA Val_cond {
+       $$ = claims_tf_condition_ctr_prepare(ctf_ps, $1, $3);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Val_cond:
+CLAIMS_TF_YY_VALUE Cond_oper Literal {
+       $$ = claims_tf_condition_prepare(ctf_ps,
+                                        CLAIMS_TF_PROPERTY_VALUE,
+                                        $2.operator,
+                                        &$3);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+Val_type_cond:
+CLAIMS_TF_YY_VALUE_TYPE Cond_oper Literal {
+       $$ = claims_tf_condition_prepare(ctf_ps,
+                                        CLAIMS_TF_PROPERTY_VALUE_TYPE,
+                                        $2.operator,
+                                        &$3);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+claim_prop:
+CLAIMS_TF_YY_TYPE {
+       $$ = (struct claim_prop) { .property = CLAIMS_TF_PROPERTY_TYPE, };
+}
+|
+CLAIMS_TF_YY_VALUE {
+       $$ = (struct claim_prop) { .property = CLAIMS_TF_PROPERTY_VALUE, };
+}
+|
+CLAIMS_TF_YY_VALUE_TYPE {
+       $$ = (struct claim_prop) { .property = CLAIMS_TF_PROPERTY_VALUE_TYPE, };
+}
+;
+
+Cond_oper:
+CLAIMS_TF_YY_EQ {
+       $$ = (struct Cond_oper) { .operator = CLAIMS_TF_CONDITION_OPERATOR_EQ, };
+}
+|
+CLAIMS_TF_YY_NEQ {
+       $$ = (struct Cond_oper) { .operator = CLAIMS_TF_CONDITION_OPERATOR_NEQ, };
+}
+|
+CLAIMS_TF_YY_REGEXP_MATCH {
+       $$ = (struct Cond_oper) { .operator = CLAIMS_TF_CONDITION_OPERATOR_REGEXP_MATCH, };
+}
+|
+CLAIMS_TF_YY_REGEXP_NOT_MATCH {
+       $$ = (struct Cond_oper) { .operator = CLAIMS_TF_CONDITION_OPERATOR_REGEXP_NOT_MATCH, };
+}
+;
+
+Expr:
+Literal {
+       $$ = (struct Expr) {
+               .has_literal = true,
+               .literal = $1,
+       };
+}
+|
+CLAIMS_TF_YY_IDENTIFIER CLAIMS_TF_YY_DOT claim_prop {
+       if ($1 == NULL) {
+               YYERROR;
+       }
+       $$ = (struct Expr) {
+               .claim = {
+                       .identifier = $1,
+                       .property = $3.property,
+               },
+       };
+}
+;
+
+Literal:
+CLAIMS_TF_YY_STRING {
+       $$ = (struct Literal) { .str = $1, };
+}
+;
+
+Rule_action:
+CLAIMS_TF_YY_ISSUE CLAIMS_TF_YY_O_BRACKET Issue_params CLAIMS_TF_YY_C_BRACKET {
+       $$ = $3;
+}
+;
+
+Issue_params:
+claim_copy {
+       $$ = claims_tf_rule_prepare(ctf_ps, &$1, NULL);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+|
+claim_new {
+       $$ = claims_tf_rule_prepare(ctf_ps, NULL, &$1);
+       if ($$ == NULL) {
+               YYERROR;
+       }
+}
+;
+
+claim_copy:
+CLAIMS_TF_YY_CLAIM CLAIMS_TF_YY_ASSIGN CLAIMS_TF_YY_IDENTIFIER {
+       $$ = (struct claim_copy) { .identifier = $3, };
+}
+;
+
+claim_new:
+claim_prop_assign_list {
+       $$ = $1;
+}
+;
+
+claim_prop_assign_list:
+claim_value_assign CLAIMS_TF_YY_COMMA claim_type_assign {
+       $$ = (struct claim_new) {
+               .type = $3,
+               .value = $1,
+       };
+}
+|
+claim_type_assign CLAIMS_TF_YY_COMMA claim_value_assign {
+       $$ = (struct claim_new) {
+               .type = $1,
+               .value = $3,
+       };
+}
+;
+
+claim_value_assign:
+claim_val_assign CLAIMS_TF_YY_COMMA claim_val_type_assign {
+       $$ = (struct claim_value_assign) {
+               .vt = $3,
+               .val = $1,
+       };
+}
+|
+claim_val_type_assign CLAIMS_TF_YY_COMMA claim_val_assign {
+       $$ = (struct claim_value_assign) {
+               .vt = $1,
+               .val = $3,
+       };
+}
+;
+
+claim_val_assign:
+CLAIMS_TF_YY_VALUE CLAIMS_TF_YY_ASSIGN Expr {
+       $$ = (struct claim_val_assign) { .expr = $3, };
+}
+;
+
+claim_val_type_assign:
+CLAIMS_TF_YY_VALUE_TYPE CLAIMS_TF_YY_ASSIGN Expr {
+       if ($3.has_literal) {
+               const char *lstr = $3.literal.str;
+               enum CLAIM_TYPE vt;
+
+               if (lstr == NULL) {
+                       YYERROR;
+               }
+
+               vt = claims_tf_type_from_string(lstr);
+               if (vt == 0) {
+                       ctf_ps->error.string = talloc_asprintf(ctf_ps,
+                                                              "Invalid "
+                                                              "ValueType "
+                                                              "string[%s]",
+                                                              lstr);
+                       YYERROR;
+               }
+       } else {
+               if ($3.claim.property != CLAIMS_TF_PROPERTY_VALUE_TYPE) {
+                       const char *istr = $3.claim.identifier;
+
+                       if (istr == NULL) {
+                               istr = "<NULL>";
+                       }
+
+                       ctf_ps->error.string = talloc_asprintf(ctf_ps,
+                                                              "ValueType "
+                                                              "requires "
+                                                              "%s.ValueType",
+                                                              istr);
+                       YYERROR;
+               }
+       }
+       $$ = (struct claim_val_type_assign) { .expr = $3, };
+}
+;
+
+claim_type_assign:
+CLAIMS_TF_YY_TYPE CLAIMS_TF_YY_ASSIGN Expr {
+       $$ = (struct claim_type_assign) { .expr = $3, };
+}
+;
+
+
+%%
+
+static struct claims_tf_rule_set *
+claims_tf_rule_set_prepare(struct claims_tf_parser_state *ctf_ps,
+                          struct claims_tf_rule_ctr *list)
+{
+       struct claims_tf_rule_set *rule_set = NULL;
+       struct claims_tf_rule_ctr *cr = NULL;
+       size_t num_rules = 0;
+       struct claims_tf_rule *rules = NULL;
+       size_t i;
+
+       if (ctf_ps == NULL) {
+               return NULL;
+       }
+       if (ctf_ps->rule_set != NULL) {
+               return NULL;
+       }
+
+       rule_set = talloc_zero(ctf_ps,
+                              struct claims_tf_rule_set);
+       if (rule_set == NULL) {
+               return NULL;
+       }
+
+       for (cr = list; cr != NULL; cr = cr->next) {
+               if (cr->rule == NULL) {
+                       TALLOC_FREE(rule_set);
+                       return NULL;
+               }
+
+               num_rules += 1;
+       }
+
+       if (num_rules >= UINT32_MAX) {
+               TALLOC_FREE(rule_set);
+               return NULL;
+       }
+       if (num_rules > 0) {
+               rules = talloc_zero_array(rule_set,
+                                         struct claims_tf_rule,
+                                         num_rules);
+               if (rules == NULL) {
+                       TALLOC_FREE(rule_set);
+                       return NULL;
+               }
+       }
+
+       i = 0;
+       for (cr = list; cr != NULL; cr = cr->next) {
+               SMB_ASSERT(i < num_rules);
+               talloc_steal(rule_set, cr->rule);
+               rules[i] = *cr->rule;
+               i += 1;
+       }
+       SMB_ASSERT(i == num_rules);
+       rule_set->num_rules = num_rules;
+       rule_set->rules = rules;
+
+       ctf_ps->rule_set = rule_set;
+       return rule_set;
+}
+
+static bool claims_tf_property_from_expr(TALLOC_CTX *mem_ctx,
+                                        const struct Expr *expr,
+                                        struct claims_tf_property *prop)
+{
+       if (expr->has_literal) {
+               if (expr->literal.str == NULL) {
+                       return false;
+               }
+
+               *prop = (struct claims_tf_property) {
+                       .string = talloc_strdup(mem_ctx, expr->literal.str),
+               };
+               if (prop->string == NULL) {
+                       return false;
+               }
+
+               return true;
+       }
+
+       if (expr->claim.identifier == NULL) {
+               return false;
+       }
+
+       *prop = (struct claims_tf_property) {
+               .ref = {
+                       .identifier = talloc_strdup(mem_ctx,
+                                                   expr->claim.identifier),
+                       .property = expr->claim.property,
+               },
+       };
+       if (prop->ref.identifier == NULL) {
+               return false;
+       }
+
+       return true;
+}
+
+static struct claims_tf_rule_ctr *
+claims_tf_rule_ctr_prepare(struct claims_tf_parser_state *ctf_ps,
+                          struct claims_tf_rule *rule,
+                          struct claims_tf_rule_ctr *next)
+{
+       struct claims_tf_rule_ctr *rule_ctr = NULL;
+
+       if (ctf_ps == NULL) {
+               return NULL;
+       }
+
+       rule_ctr = talloc_zero(ctf_ps, struct claims_tf_rule_ctr);
+       if (rule_ctr == NULL) {
+               return NULL;
+       }
+
+       rule_ctr->rule = talloc_steal(rule_ctr, rule);
+       rule_ctr->next = talloc_steal(rule_ctr, next);
+
+       return rule_ctr;
+}
+
+static struct claims_tf_rule *
+claims_tf_rule_prepare(struct claims_tf_parser_state *ctf_ps,
+                      const struct claim_copy *c_copy,
+                      const struct claim_new *c_new)
+{
+       struct claims_tf_rule *rule = NULL;
+       const struct Expr *type_expr = NULL;
+       const struct Expr *vt_expr = NULL;
+       const struct Expr *val_expr = NULL;
+       bool ok;
+
+       if (ctf_ps == NULL) {
+               return NULL;
+       }
+
+       rule = talloc_zero(ctf_ps, struct claims_tf_rule);
+       if (rule == NULL) {
+               return NULL;
+       }
+
+       if (c_copy != NULL) {
+               const char *identifier = NULL;
+
+               if (c_copy->identifier == NULL) {
+                       TALLOC_FREE(rule);
+                       return NULL;
+               }
+
+               identifier = talloc_strdup(rule, c_copy->identifier);
+               if (identifier == NULL) {
+                       TALLOC_FREE(rule);
+                       return NULL;
+               }
+
+               /*
+                * Copy all properties from the given claim identifier
+                */
+               rule->action.type.ref = (struct claims_tf_property_ref) {
+                       .identifier = identifier,
+                       .property = CLAIMS_TF_PROPERTY_TYPE,
+               };
+               rule->action.value_type.ref = (struct claims_tf_property_ref) {
+                       .identifier = identifier,
+                       .property = CLAIMS_TF_PROPERTY_VALUE_TYPE,
+               };
+               rule->action.value.ref = (struct claims_tf_property_ref) {
+                       .identifier = identifier,
+                       .property = CLAIMS_TF_PROPERTY_VALUE,
+               };
+
+               return rule;
+       }
+
+       if (c_new == NULL) {
+               TALLOC_FREE(rule);
+               return NULL;
+       }
+
+       type_expr = &c_new->type.expr;
+       vt_expr = &c_new->value.vt.expr;
+       val_expr = &c_new->value.val.expr;
+
+       ok = claims_tf_property_from_expr(rule, type_expr, &rule->action.type);
+       if (!ok) {
+               TALLOC_FREE(rule);
+               return NULL;
+       }
+
+       ok = claims_tf_property_from_expr(rule, vt_expr, &rule->action.value_type);
+       if (!ok) {
+               TALLOC_FREE(rule);
+               return NULL;
+       }
+
+       ok = claims_tf_property_from_expr(rule, val_expr, &rule->action.value);
+       if (!ok) {
+               TALLOC_FREE(rule);
+               return NULL;
+       }
+
+       return rule;
+}
+
+static struct claims_tf_rule *
+claims_tf_rule_attach_conditions(struct claims_tf_rule *rule,
+                                struct claims_tf_condition_set_ctr *list)
+{
+       struct claims_tf_condition_set_ctr *cl = NULL;
+       size_t num_condition_sets = 0;
+       struct claims_tf_condition_set *condition_sets = NULL;
+       size_t i;
+
+       if (rule == NULL) {
+               return NULL;
+       }
+
+       for (cl = list; cl != NULL; cl = cl->prev) {
+               if (cl->set == NULL) {
+                       TALLOC_FREE(rule);
+                       return NULL;
+               }
+               num_condition_sets += 1;
+       }
+
+       if (num_condition_sets >= UINT32_MAX) {
+               TALLOC_FREE(rule);
+               return NULL;
+       }
+
+       if (num_condition_sets != 0) {
+               condition_sets = talloc_zero_array(rule,
+                                                  struct claims_tf_condition_set,
+                                                  num_condition_sets);
+               if (condition_sets == NULL) {
+                       TALLOC_FREE(rule);
+                       return NULL;
+               }
+       }
+
+       /*
+        * list is a list from tail to head.
+        *
+        * But we want rule->condition_sets to have
+        * head at index 0.
+        */
+       i = num_condition_sets;
+       for (cl = list; cl != NULL; cl = cl->prev) {
+               SMB_ASSERT(i > 0);
+               i -= 1;
+               talloc_steal(rule, cl->set);
+               condition_sets[i] = *cl->set;
+       }
+       SMB_ASSERT(i == 0);
+       rule->num_condition_sets = num_condition_sets;
+       rule->condition_sets = condition_sets;
+
+       return rule;
+}
+
+static struct claims_tf_condition_set_ctr *
+claims_tf_condition_set_ctr_prepare(struct claims_tf_parser_state *ctf_ps,
+                                   struct claims_tf_condition_set *set,
+                                   struct claims_tf_condition_set_ctr *prev)
+{
+       struct claims_tf_condition_set_ctr *condition_set_ctr = NULL;
+
+       if (ctf_ps == NULL) {
+               return NULL;
+       }
+
+       condition_set_ctr = talloc_zero(ctf_ps, struct claims_tf_condition_set_ctr);
+       if (condition_set_ctr == NULL) {
+               return NULL;
+       }
+
+       condition_set_ctr->set = talloc_steal(condition_set_ctr, set);
+       condition_set_ctr->prev = talloc_steal(condition_set_ctr, prev);
+
+       return condition_set_ctr;
+}
+
+static struct claims_tf_condition_set *
+claims_tf_condition_set_prepare(struct claims_tf_parser_state *ctf_ps,
+                               const struct claims_tf_condition_ctr *list,
+                               const char *identifier)
+{
+       struct claims_tf_condition_set *condition_set = NULL;
+       const struct claims_tf_condition_ctr *cl = NULL;
+       size_t num_conditions = 0;
+       struct claims_tf_condition *conditions = NULL;
+       size_t i;
+
+       if (ctf_ps == NULL) {
+               return NULL;
+       }
+
+       condition_set = talloc_zero(ctf_ps, struct claims_tf_condition_set);
+       if (condition_set == NULL) {
+               return NULL;
+       }
+
+       if (identifier != NULL) {
+               condition_set->opt_identifier = talloc_strdup(condition_set,
+                                                             identifier);
+               if (condition_set->opt_identifier == NULL) {
+                       TALLOC_FREE(condition_set);
+                       return NULL;
+               }
+       }
+
+       for (cl = list; cl != NULL; cl = cl->prev) {
+               if (cl->c1 == NULL) {
+                       TALLOC_FREE(condition_set);
+                       return NULL;
+               }
+
+               if (cl->c2 != NULL) {
+                       num_conditions += 1;
+               }
+               num_conditions += 1;
+       }
+
+       if (num_conditions >= UINT32_MAX) {
+               TALLOC_FREE(condition_set);
+               return NULL;
+       }
+
+       if (num_conditions > 0) {
+               conditions = talloc_zero_array(condition_set,
+                                              struct claims_tf_condition,
+                                              num_conditions);
+               if (conditions == NULL) {
+                       TALLOC_FREE(condition_set);
+                       return NULL;
+               }
+       }
+
+       /*
+        * list is a list from tail to head.
+        *
+        * But we want rule->condition_sets to have
+        * head at index 0.
+        */
+       i = num_conditions;
+       for (cl = list; cl != NULL; cl = cl->prev) {
+               if (cl->c2 != NULL) {
+                       SMB_ASSERT(i > 0);
+                       i -= 1;
+                       talloc_steal(condition_set, cl->c2);
+                       conditions[i] = *cl->c2;
+               }
+               SMB_ASSERT(i > 0);
+               i -= 1;
+               talloc_steal(condition_set, cl->c1);
+               conditions[i] = *cl->c1;
+       }
+       SMB_ASSERT(i == 0);
+       condition_set->num_conditions = num_conditions;
+       condition_set->conditions = conditions;
+
+       return condition_set;
+}
+
+static struct claims_tf_condition_ctr *
+claims_tf_condition_ctr_prepare(struct claims_tf_parser_state *ctf_ps,
+                               struct claims_tf_condition *c1,
+                               struct claims_tf_condition *c2)
+{
+       struct claims_tf_condition_ctr *condition_ctr = NULL;
+
+       if (ctf_ps == NULL) {
+               return NULL;
+       }
+
+       condition_ctr = talloc_zero(ctf_ps, struct claims_tf_condition_ctr);
+       if (condition_ctr == NULL) {
+               return NULL;
+       }
+
+       condition_ctr->c1 = talloc_steal(condition_ctr, c1);
+       condition_ctr->c2 = talloc_steal(condition_ctr, c2);
+
+       return condition_ctr;
+}
+
+static struct claims_tf_condition_ctr *
+claims_tf_condition_ctr_attach_prev(struct claims_tf_condition_ctr *ctr,
+                                   struct claims_tf_condition_ctr *prev)
+{
+       ctr->prev = talloc_steal(ctr, prev);
+       return ctr;
+}
+
+static struct claims_tf_condition *
+claims_tf_condition_prepare(struct claims_tf_parser_state *ctf_ps,
+                           enum claims_tf_property_enum property,
+                           enum claims_tf_condition_operator operator,
+                           const struct Literal *expr)
+{
+       struct claims_tf_condition *condition = NULL;
+       const char *match = NULL;
+
+       if (ctf_ps == NULL) {
+               return NULL;
+       }
+
+       condition = talloc_zero(ctf_ps, struct claims_tf_condition);
+       if (condition == NULL) {
+               return NULL;
+       }
+
+       match = expr->str;
+
+       if (match == NULL) {
+               TALLOC_FREE(condition);
+               return NULL;
+       }
+
+       if (property == CLAIMS_TF_PROPERTY_VALUE_TYPE) {
+               enum CLAIM_TYPE vt;
+
+               vt = claims_tf_type_from_string(match);
+               if (vt == 0) {
+                       ctf_ps->error.string = talloc_asprintf(ctf_ps,
+                                                              "Invalid "
+                                                              "ValueType "
+                                                              "string[%s]",
+                                                              match);
+                       TALLOC_FREE(condition);
+                       return NULL;
+               }
+       }
+
+       condition->property = property;
+       condition->operator = operator;
+       condition->string = talloc_strdup(condition, match);
+       if (condition->string == NULL) {
+               TALLOC_FREE(condition);
+               return NULL;
+       }
+
+       return condition;
+}
+
+static void __claims_tf_yy_error(__CLAIMS_TF_YY_LTYPE *llocp,
+                                struct claims_tf_parser_state *ctf_ps,
+                                void *yyscanner,
+                                const char *str)
+{
+       ctf_ps->error.first_line = llocp->first_line;
+       ctf_ps->error.first_column = llocp->first_column;
+       ctf_ps->error.last_line = llocp->last_line;
+       ctf_ps->error.last_column = llocp->last_column;
+       ctf_ps->error.string = talloc_strdup(ctf_ps, str);
+}
index db8a9b94c1e85b51ffe032357ee980f49107985d..d23d3a1268d8643e46acb7336582427719034c49 100644 (file)
@@ -9,7 +9,10 @@ bld.SAMBA_LIBRARY('samba-security',
                           'object_tree.c', 'create_descriptor.c',
                           'util_sid.c', 'session.c', 'secdesc.c',
                           'conditional_ace.c', 'sddl_conditional_ace.c',
-                          'claims-conversions.c'],
+                          'claims-conversions.c',
+                          'claims_transformation.l',
+                          'claims_transformation.y',
+                  ],
                   private_library=True,
                   deps='stable_sort talloc ndr NDR_SECURITY NDR_CONDITIONAL_ACE')