libcli/security/conditional ACEs: compare composites as sets
[Samba.git] / libcli / security / conditional_ace.c
blob169e024605f80aeb9cd745702e0d3a21a5c3d360
1 /*
2 * Unix SMB implementation.
3 * Functions for understanding conditional ACEs
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.
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.
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/>.
19 #include "replace.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/debug.h"
27 #include "lib/util/bytearray.h"
28 #include "util/discard.h"
31 * Conditional ACE logic truth tables.
33 * Conditional ACES use a ternary logic, with "unknown" as well as true and
34 * false. The ultmate meaning of unknown depends on the context; in a deny
35 * ace, unknown means yes, in an allow ace, unknown means no. That is, we
36 * treat unknown results with maximum suspicion.
38 * AND true false unknown
39 * true T F ?
40 * false F F F
41 * unknown ? F ?
43 * OR true false unknown
44 * true T T T
45 * false T F ?
46 * unknown T ? ?
48 * NOT
49 * true F
50 * false T
51 * unknown ?
53 * This can be summed up by saying unknown values taint the result except in
54 * the cases where short circuit evaluation could apply (true OR anything,
55 * false AND anything, which hold their value).
57 * What counts as unknown
59 * - NULL attributes.
60 * - certain comparisons between incompatible types
62 * What counts as false
64 * - zero
65 * - empty strings
67 * An error means the entire expression is unknown.
71 static bool check_integer_range(const struct ace_condition_token *tok)
73 int64_t val = tok->data.int64.value;
74 switch (tok->type) {
75 case CONDITIONAL_ACE_TOKEN_INT8:
76 if (val < -128 || val > 127) {
77 return false;
79 break;
80 case CONDITIONAL_ACE_TOKEN_INT16:
81 if (val < INT16_MIN || val > INT16_MAX) {
82 return false;
84 break;
85 case CONDITIONAL_ACE_TOKEN_INT32:
86 if (val < INT32_MIN || val > INT32_MAX) {
87 return false;
89 break;
90 case CONDITIONAL_ACE_TOKEN_INT64:
91 /* val has these limits naturally */
92 break;
93 default:
94 return false;
97 if (tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_8 &&
98 tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_10 &&
99 tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_16) {
100 return false;
102 if (tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_POSITIVE &&
103 tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NEGATIVE &&
104 tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NONE) {
105 return false;
107 return true;
111 static ssize_t pull_integer(uint8_t *data, size_t length,
112 struct ace_condition_int *tok)
114 if (length < 10) {
115 return -1;
117 tok->value = PULL_LE_I64(data, 0);
118 tok->sign = data[8];
119 tok->base = data[9];
120 return 10;
123 static ssize_t push_integer(uint8_t *data, size_t length,
124 const struct ace_condition_int *tok)
126 if (length < 10) {
127 return -1;
129 PUSH_LE_I64(data, 0, tok->value);
130 data[8] = tok->sign;
131 data[9] = tok->base;
132 return 10;
136 static ssize_t pull_unicode(TALLOC_CTX *mem_ctx, uint8_t *data, size_t length,
137 struct ace_condition_unicode *tok)
139 char *utf8 = NULL;
140 uint8_t *utf16 = NULL;
141 size_t utf8_len;
142 uint32_t utf16_len;
143 uint32_t i;
144 bool ok;
145 if (length < 4) {
146 return -1;
148 utf16_len = PULL_LE_U32(data, 0);
149 if (utf16_len > length - 4) {
150 return -1;
152 if (utf16_len & 1) {
153 /* we need an even number of bytes */
154 return -1;
156 utf16 = data + 4;
158 * The string in the ACE blob is utf-16, which we convert to
159 * utf-8 for further processing.
161 * There may be inefficencies here (FIXME, etc, if you dare),
162 * and we might prefer to keep it as utf-16 in the runtime.
163 * But maybe not.
165 for (i = 0; i < utf16_len; i += 2) {
167 * A 0x0000 codepoint is illegal. The string is length-bound,
168 * not NUL-terminated. If we don't do this the string will be
169 * truncated at the first 0x0000, which is not terrible, but
170 * not expected, and it makes round-trip assertions
171 * impossible.
173 if (utf16[i] == 0 && utf16[i + 1] == 0) {
174 return -1;
178 ok = convert_string_talloc(mem_ctx,
179 CH_UTF16LE, CH_UTF8,
180 utf16, utf16_len,
181 &utf8, &utf8_len);
182 if (!ok) {
183 return -1;
185 if (utf16_len == 0) {
187 * This is a special case, because convert_string_talloc()
188 * will turn a length 0 string into a length 1 string
189 * containing a zero byte. This is not the same as returning
190 * the truly allocated size, counting the '\0' for all strings
191 * -- it only happens for the empty string.
193 utf8_len = 0;
195 tok->value = utf8;
196 tok->length = utf8_len;
197 return utf16_len + 4;
200 static ssize_t push_unicode(uint8_t *data, size_t length,
201 const struct ace_condition_unicode *tok)
204 * The string stored in the token is utf-8, but must be
205 * converted to utf-16 in the compiled ACE.
207 bool ok;
208 size_t bytes_written;
209 uint8_t *length_goes_here = data;
211 if (length < 4) {
212 return -1;
214 length -= 4;
215 data += 4;
217 //XXX do we allow an empty string?
218 ok = convert_string_error(CH_UTF8, CH_UTF16LE,
219 tok->value, tok->length,
220 data, length,
221 &bytes_written);
222 if (! ok || bytes_written > length) {
223 return -1;
225 PUSH_LE_U32(length_goes_here, 0, bytes_written);
226 return bytes_written + 4;
230 static ssize_t pull_bytes(TALLOC_CTX *mem_ctx,
231 uint8_t *data, size_t length,
232 struct ace_condition_bytes *tok)
234 if (length < 4) {
235 return -1;
237 tok->length = PULL_LE_U32(data, 0);
238 if (tok->length > length - 4) {
239 return -1;
241 tok->bytes = talloc_size(mem_ctx, tok->length + 1);
242 if (tok->bytes == NULL) {
243 return -1;
245 memcpy(tok->bytes, data + 4, tok->length);
246 tok->bytes[tok->length] = 0;
247 return tok->length + 4;
251 static ssize_t push_bytes(uint8_t *data, size_t length,
252 const struct ace_condition_bytes *tok)
254 if (length < tok->length + 4) {
255 return -1;
257 PUSH_LE_U32(data, 0, tok->length);
258 memcpy(data + 4, tok->bytes, tok->length);
259 return tok->length + 4;
263 static ssize_t pull_sid(TALLOC_CTX *mem_ctx,
264 uint8_t *data, size_t length,
265 struct ace_condition_sid *tok)
267 uint32_t tok_length;
268 ssize_t sidlen;
269 if (length < 4) {
270 return -1;
272 tok_length = PULL_LE_U32(data, 0);
273 if (tok_length > length - 4) {
274 return -1;
276 tok->sid = talloc(mem_ctx, struct dom_sid);
277 if (tok->sid == NULL) {
278 return -1;
280 sidlen = sid_parse(data + 4, tok_length, tok->sid);
281 if (sidlen == -1) {
282 talloc_free(tok->sid);
283 return -1;
285 return tok_length + 4;
288 static ssize_t push_sid(uint8_t *data, size_t available,
289 const struct ace_condition_sid *tok)
291 enum ndr_err_code ndr_err;
292 DATA_BLOB v;
293 ssize_t total_length;
294 ndr_err = ndr_push_struct_blob(&v, NULL,
295 tok->sid,
296 (ndr_push_flags_fn_t)ndr_push_dom_sid);
297 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
298 return -1;
300 total_length = v.length + 4;
301 if (available < total_length) {
302 talloc_free(v.data);
303 return -1;
305 PUSH_LE_U32(data, 0, v.length);
306 memcpy(data + 4, v.data, v.length);
307 talloc_free(v.data);
308 return total_length;
312 static ssize_t pull_composite(TALLOC_CTX *mem_ctx,
313 uint8_t *data, size_t length,
314 struct ace_condition_composite *tok)
316 size_t i, j;
317 size_t alloc_length;
318 size_t byte_size;
319 struct ace_condition_token *tokens = NULL;
320 if (length < 4) {
321 return -1;
323 byte_size = PULL_LE_U32(data, 0);
324 if (byte_size > length - 4) {
325 return -1;
328 * There is a list of other literal tokens (possibly including nested
329 * composites), which we will store in an array.
331 * This array can *only* be literals.
333 alloc_length = byte_size;
334 tokens = talloc_array(mem_ctx,
335 struct ace_condition_token,
336 alloc_length);
337 if (tokens == NULL) {
338 return -1;
340 byte_size += 4;
341 i = 4;
342 j = 0;
343 while (i < byte_size) {
344 struct ace_condition_token *el = &tokens[j];
345 ssize_t consumed;
346 uint8_t *el_data = NULL;
347 size_t available;
348 bool ok;
349 el->type = data[i];
350 i++;
352 el_data = data + i;
353 available = byte_size - i;
355 switch (el->type) {
356 case CONDITIONAL_ACE_TOKEN_INT8:
357 case CONDITIONAL_ACE_TOKEN_INT16:
358 case CONDITIONAL_ACE_TOKEN_INT32:
359 case CONDITIONAL_ACE_TOKEN_INT64:
360 consumed = pull_integer(el_data,
361 available,
362 &el->data.int64);
363 ok = check_integer_range(el);
364 if (! ok) {
365 goto error;
367 break;
368 case CONDITIONAL_ACE_TOKEN_UNICODE:
369 consumed = pull_unicode(mem_ctx,
370 el_data,
371 available,
372 &el->data.unicode);
373 break;
375 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
376 consumed = pull_bytes(mem_ctx,
377 el_data,
378 available,
379 &el->data.bytes);
380 break;
382 case CONDITIONAL_ACE_TOKEN_SID:
383 consumed = pull_sid(mem_ctx,
384 el_data,
385 available,
386 &el->data.sid);
387 break;
389 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
390 consumed = pull_composite(mem_ctx,
391 el_data,
392 available,
393 &el->data.composite);
394 break;
395 default:
396 goto error;
399 if (consumed < 0 || consumed + i > length) {
400 goto error;
402 i += consumed;
403 j++;
404 if (j == UINT16_MAX) {
405 talloc_free(tokens);
406 return -1;
408 if (j == alloc_length) {
409 alloc_length += 5;
410 tokens = talloc_realloc(mem_ctx,
411 tokens,
412 struct ace_condition_token,
413 alloc_length);
415 if (tokens == NULL) {
416 return -1;
420 tok->n_members = j;
421 tok->tokens = tokens;
422 return byte_size;
423 error:
424 talloc_free(tokens);
425 return -1;
429 static ssize_t push_composite(uint8_t *data, size_t length,
430 const struct ace_condition_composite *tok)
432 size_t i;
433 uint8_t *byte_length_ptr;
434 size_t used = 0;
435 if (length < 4) {
436 return -1;
439 * We have no idea what the eventual length will be, so we keep a
440 * pointer to write it in at the end.
442 byte_length_ptr = data;
443 PUSH_LE_U32(data, 0, 0);
444 used = 4;
446 for (i = 0; i < tok->n_members && used < length; i++) {
447 struct ace_condition_token *el = &tok->tokens[i];
448 ssize_t consumed;
449 uint8_t *el_data = NULL;
450 size_t available;
451 bool ok;
452 data[used] = el->type;
453 used++;
454 if (used == length) {
456 * used == length is not expected here; the token
457 * types that only have an opcode and no data are not
458 * literals that can be in composites.
460 return -1;
462 el_data = data + used;
463 available = length - used;
465 switch (el->type) {
466 case CONDITIONAL_ACE_TOKEN_INT8:
467 case CONDITIONAL_ACE_TOKEN_INT16:
468 case CONDITIONAL_ACE_TOKEN_INT32:
469 case CONDITIONAL_ACE_TOKEN_INT64:
470 ok = check_integer_range(el);
471 if (! ok) {
472 return -1;
474 consumed = push_integer(el_data,
475 available,
476 &el->data.int64);
477 break;
478 case CONDITIONAL_ACE_TOKEN_UNICODE:
479 consumed = push_unicode(el_data,
480 available,
481 &el->data.unicode);
482 break;
484 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
485 consumed = push_bytes(el_data,
486 available,
487 &el->data.bytes);
488 break;
490 case CONDITIONAL_ACE_TOKEN_SID:
491 consumed = push_sid(el_data,
492 available,
493 &el->data.sid);
494 break;
496 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
497 consumed = push_composite(el_data,
498 available,
499 &el->data.composite);
500 break;
502 default:
503 return -1;
506 if (consumed < 0) {
507 return -1;
509 used += consumed;
511 if (used > length) {
512 return -1;
515 PUSH_LE_U32(byte_length_ptr, 0, used - 4);
516 return used;
519 static ssize_t pull_end_padding(uint8_t *data, size_t length)
522 * We just check that we have the right kind of number of zero
523 * bytes. The blob must end on a multiple of 4. One zero byte
524 * has already been swallowed as tok->type, which sends us
525 * here, so we expect 1 or two more -- total padding is 0, 1,
526 * 2, or 3.
528 * zero is also called CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING.
530 ssize_t i;
531 if (length > 2) {
532 return -1;
534 for (i = 0; i < length; i++) {
535 if (data[i] != 0) {
536 return -1;
539 return length;
543 struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx,
544 DATA_BLOB data)
546 size_t i, j;
547 struct ace_condition_token *tokens = NULL;
548 size_t alloc_length;
549 struct ace_condition_script *program = NULL;
551 if (data.length < 4 ||
552 data.data[0] != 'a' ||
553 data.data[1] != 'r' ||
554 data.data[2] != 't' ||
555 data.data[3] != 'x') {
557 * lacks the "artx" conditional ace identifier magic.
558 * NULL returns will deny access.
560 return NULL;
562 if (data.length > CONDITIONAL_ACE_MAX_LENGTH ||
563 (data.length & 3) != 0) {
565 * >= 64k or non-multiples of 4 are not possible in the ACE
566 * wire format.
568 return NULL;
571 program = talloc(mem_ctx, struct ace_condition_script);
572 if (program == NULL) {
573 return NULL;
577 * We will normally end up with fewer than data.length tokens, as
578 * values are stored in multiple bytes (all integers are 10 bytes,
579 * strings and attributes are utf16 + length, SIDs are SID-size +
580 * length, etc). But operators are one byte, so something like
581 * !(!(!(!(!(!(x)))))) -- where each '!(..)' is one byte -- will bring
582 * the number of tokens close to the number of bytes.
584 * This is all to say we're guessing a token length that hopes to
585 * avoid reallocs without wasting too much up front.
587 alloc_length = data.length / 2 + 1;
588 tokens = talloc_array(program,
589 struct ace_condition_token,
590 alloc_length);
591 if (tokens == NULL) {
592 TALLOC_FREE(program);
593 return NULL;
596 i = 4;
597 j = 0;
598 while(i < data.length) {
599 struct ace_condition_token *tok = &tokens[j];
600 ssize_t consumed = 0;
601 uint8_t *tok_data = NULL;
602 size_t available;
603 bool ok;
604 tok->type = data.data[i];
605 i++;
606 tok_data = data.data + i;
607 available = data.length - i;
609 switch (tok->type) {
610 case CONDITIONAL_ACE_TOKEN_INT8:
611 case CONDITIONAL_ACE_TOKEN_INT16:
612 case CONDITIONAL_ACE_TOKEN_INT32:
613 case CONDITIONAL_ACE_TOKEN_INT64:
614 consumed = pull_integer(tok_data,
615 available,
616 &tok->data.int64);
617 ok = check_integer_range(tok);
618 if (! ok) {
619 goto fail;
621 break;
622 case CONDITIONAL_ACE_TOKEN_UNICODE:
624 * The next four are pulled as unicode, but are
625 * processed as user attribute look-ups.
627 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
628 case CONDITIONAL_ACE_USER_ATTRIBUTE:
629 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
630 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
631 consumed = pull_unicode(program,
632 tok_data,
633 available,
634 &tok->data.unicode);
635 break;
637 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
638 consumed = pull_bytes(program,
639 tok_data,
640 available,
641 &tok->data.bytes);
642 break;
644 case CONDITIONAL_ACE_TOKEN_SID:
645 consumed = pull_sid(program,
646 tok_data,
647 available,
648 &tok->data.sid);
649 break;
651 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
652 consumed = pull_composite(program,
653 tok_data,
654 available,
655 &tok->data.composite);
656 break;
658 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
659 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
660 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
661 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
662 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
663 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
664 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
665 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
667 * these require a SID or composite SID list operand,
668 * and we could check that now in most cases.
670 break;
671 /* binary relational operators */
672 case CONDITIONAL_ACE_TOKEN_EQUAL:
673 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
674 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
675 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
676 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
677 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
678 case CONDITIONAL_ACE_TOKEN_CONTAINS:
679 case CONDITIONAL_ACE_TOKEN_ANY_OF:
680 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
681 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
682 /* unary logical operators */
683 case CONDITIONAL_ACE_TOKEN_EXISTS:
684 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
685 case CONDITIONAL_ACE_TOKEN_NOT:
686 /* binary logical operators */
687 case CONDITIONAL_ACE_TOKEN_AND:
688 case CONDITIONAL_ACE_TOKEN_OR:
689 break;
690 case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
691 /* this is only valid at the end */
692 consumed = pull_end_padding(tok_data,
693 available);
694 j--; /* don't add this token */
695 break;
696 default:
697 goto fail;
700 if (consumed + i < i || consumed + i > data.length) {
701 goto fail;
703 i += consumed;
704 j++;
705 if (j == alloc_length) {
706 alloc_length *= 2;
707 tokens = talloc_realloc(program,
708 tokens,
709 struct ace_condition_token,
710 alloc_length);
711 if (tokens == NULL) {
712 goto fail;
716 program->length = j;
717 program->tokens = talloc_realloc(program,
718 tokens,
719 struct ace_condition_token,
720 program->length + 1);
721 if (program->tokens == NULL) {
722 goto fail;
725 * When interpreting the program we will need a stack, which in the
726 * very worst case can be as deep as the program is long.
728 program->stack = talloc_array(program,
729 struct ace_condition_token,
730 program->length + 1);
731 if (program->stack == NULL) {
732 goto fail;
735 return program;
736 fail:
737 talloc_free(program);
738 return NULL;
742 static bool claim_lookup_internal(
743 TALLOC_CTX *mem_ctx,
744 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
745 struct ace_condition_token *result)
747 bool ok = claim_v1_to_ace_token(mem_ctx, claim, result);
748 return ok;
752 static bool resource_claim_lookup(
753 TALLOC_CTX *mem_ctx,
754 const struct ace_condition_token *op,
755 const struct security_descriptor *sd,
756 struct ace_condition_token *result)
759 * For a @Resource.attr, the claims come from a resource ACE
760 * in the object's SACL. That's why we need a security descriptor.
762 * If there is no matching resource ACE, a NULL result is returned,
763 * which should compare UNKNOWN to anything. The NULL will have the
764 * CONDITIONAL_ACE_FLAG_NULL_MEANS_ERROR flag set if it seems failure
765 * is not simply due to the sought claim not existing. This useful for
766 * the Exists and Not_Exists operators.
768 size_t i;
769 struct ace_condition_unicode name;
771 result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
773 if (op->type != CONDITIONAL_ACE_RESOURCE_ATTRIBUTE) {
774 /* what are we even doing here? */
775 result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
776 return false;
779 name = op->data.resource_attr;
781 if (sd->sacl == NULL) {
782 DBG_NOTICE("Resource attribute ACE '%*s' not found, "
783 "because there is no SACL\n",
784 name.length, name.value);
785 return true;
788 for (i = 0; i < sd->sacl->num_aces; i++) {
789 struct security_ace *ace = &sd->sacl->aces[i];
790 bool ok;
792 if (ace->type != SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) {
793 continue;
795 if (strncasecmp_m(name.value,
796 ace->coda.claim.name,
797 name.length) != 0) {
798 continue;
800 /* this is the one */
801 ok = claim_lookup_internal(mem_ctx, &ace->coda.claim, result);
802 if (ok) {
803 return true;
806 DBG_NOTICE("Resource attribute ACE '%*s' not found.\n",
807 name.length, name.value);
808 return false;
812 static bool token_claim_lookup(
813 TALLOC_CTX *mem_ctx,
814 const struct security_token *token,
815 const struct ace_condition_token *op,
816 struct ace_condition_token *result)
819 * The operator has an attribute name; if there is a claim of
820 * the right type with that name, that is returned as the result.
822 * XXX what happens otherwise? NULL result?
824 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
825 size_t num_claims;
826 bool ok;
827 const struct ace_condition_unicode *name = NULL;
828 size_t i;
830 result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
832 switch (op->type) {
833 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
834 claims = token->local_claims;
835 num_claims = token->num_local_claims;
836 name = &op->data.local_attr;
837 break;
838 case CONDITIONAL_ACE_USER_ATTRIBUTE:
839 claims = token->user_claims;
840 num_claims = token->num_user_claims;
841 name = &op->data.user_attr;
842 break;
843 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
844 claims = token->device_claims;
845 num_claims = token->num_device_claims;
846 name = &op->data.device_attr;
847 break;
848 default:
849 DBG_WARNING("Conditional ACE claim lookup got bad arg type %u\n",
850 op->type);
851 result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
852 return false;
856 * Loop backwards: a later claim will override an earlier one with the
857 * same name.
859 for (i = num_claims - 1; i < num_claims; i--) {
860 if (claims[i].name == NULL) {
861 DBG_ERR("claim %zu has no name!\n", i);
862 continue;
864 if (strncasecmp_m(claims[i].name, name->value, name->length) == 0) {
865 /* this is the one */
866 ok = claim_lookup_internal(mem_ctx, &claims[i], result);
867 return ok;
870 DBG_NOTICE("Claim not found\n");
871 return false;
877 static bool member_lookup(
878 const struct security_token *token,
879 const struct ace_condition_token *op,
880 const struct ace_condition_token *arg,
881 struct ace_condition_token *result)
884 * We need to compare the lists of SIDs in the token with the
885 * SID[s] in the argument. There are 8 combinations of
886 * operation, depending on whether we want to match all or any
887 * of the SIDs, whether we're using the device SIDs or user
888 * SIDs, and whether the operator name starts with "Not_".
890 * _MEMBER_OF User has all operand SIDs
891 * _DEVICE_MEMBER_OF Device has all operand SIDs
892 * _MEMBER_OF_ANY User has one or more operand SIDs
893 * _DEVICE_MEMBER_OF_ANY Device has one or more operand SIDs
895 * NOT_* has the effect of !(the operator without NOT_).
897 * The operand can either be a composite of SIDs or a single SID.
898 * This adds an additional branch.
900 bool match = false;
901 bool it_is_a_not_op;
902 bool it_is_an_any_op;
903 bool it_is_a_device_op;
904 bool arg_is_a_single_sid;
905 struct dom_sid *sid_array = NULL;
906 size_t num_sids, i, j;
907 struct dom_sid *sid = NULL;
909 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
910 result->data.result.value = ACE_CONDITION_UNKNOWN;
912 switch (arg->type) {
913 case CONDITIONAL_ACE_TOKEN_SID:
914 arg_is_a_single_sid = true;
915 break;
916 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
917 arg_is_a_single_sid = false;
918 break;
919 default:
920 DBG_WARNING("Conditional ACE Member_Of got bad arg type %u\n",
921 arg->type);
922 return false;
925 switch (op->type) {
926 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
927 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
928 it_is_a_not_op = true;
929 it_is_a_device_op = false;
930 break;
931 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
932 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
933 it_is_a_not_op = true;
934 it_is_a_device_op = true;
935 break;
936 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
937 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
938 it_is_a_not_op = false;
939 it_is_a_device_op = false;
940 break;
941 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
942 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
943 it_is_a_not_op = false;
944 it_is_a_device_op = true;
945 break;
946 default:
947 DBG_WARNING("Conditional ACE Member_Of got bad op type %u\n",
948 op->type);
949 return false;
952 switch (op->type) {
953 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
954 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
955 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
956 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
957 it_is_an_any_op = true;
958 break;
959 default:
960 it_is_an_any_op = false;
963 if (it_is_a_device_op) {
964 sid_array = token->device_sids;
965 num_sids = token->num_device_sids;
966 } else {
967 sid_array = token->sids;
968 num_sids = token->num_sids;
971 if (arg_is_a_single_sid) {
973 * In this case the any and all operations are the
974 * same.
976 sid = arg->data.sid.sid;
977 match = false;
978 for (i = 0; i < num_sids; i++) {
979 match = dom_sid_equal(sid, &sid_array[i]);
980 if (match) {
981 break;
984 if (it_is_a_not_op) {
985 match = ! match;
987 if (match) {
988 result->data.result.value = ACE_CONDITION_TRUE;
989 } else {
990 result->data.result.value = ACE_CONDITION_FALSE;
992 return true;
995 /* This is a composite list (hopefully of SIDs) */
996 if (arg->data.composite.n_members == 0) {
997 DBG_WARNING("Conditional ACE Member_Of argument is empty\n");
998 return false;
1001 for (j = 0; j < arg->data.composite.n_members; j++) {
1002 const struct ace_condition_token *member =
1003 &arg->data.composite.tokens[j];
1004 if (member->type != CONDITIONAL_ACE_TOKEN_SID) {
1005 DBG_WARNING("Conditional ACE Member_Of argument contains "
1006 "non-sid element [%zu]: %u\n",
1007 j, member->type);
1008 return false;
1010 sid = member->data.sid.sid;
1011 match = false;
1012 for (i = 0; i < num_sids; i++) {
1013 match = dom_sid_equal(sid, &sid_array[i]);
1014 if (match) {
1015 break;
1018 if (it_is_an_any_op) {
1019 if (match) {
1020 /* we have matched one SID, which is enough */
1021 goto apply_not;
1023 } else { /* an all op */
1024 if (! match) {
1025 /* failing one is enough */
1026 goto apply_not;
1031 * Reaching the end of that loop means either:
1032 * 1. it was an ALL op and we never failed to find one, or
1033 * 2. it was an ANY op, and we didn't find one.
1035 match = !it_is_an_any_op;
1037 apply_not:
1038 if (it_is_a_not_op) {
1039 match = ! match;
1041 if (match) {
1042 result->data.result.value = ACE_CONDITION_TRUE;
1043 } else {
1044 result->data.result.value = ACE_CONDITION_FALSE;
1047 return true;
1051 static bool ternary_value(
1052 const struct ace_condition_token *arg,
1053 struct ace_condition_token *result)
1056 * Find the truth value of the argument, stored in the result token.
1058 * A return value of false means the operation is invalid, and the
1059 * result is undefined.
1061 if (arg->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
1062 /* pass through */
1063 *result = *arg;
1064 return true;
1067 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
1068 result->data.result.value = ACE_CONDITION_UNKNOWN;
1070 if (IS_INT_TOKEN(arg)) {
1071 /* zero is false */
1072 if (arg->data.int64.value == 0) {
1073 result->data.result.value = ACE_CONDITION_FALSE;
1074 } else {
1075 result->data.result.value = ACE_CONDITION_TRUE;
1077 return true;
1079 if (arg->type == CONDITIONAL_ACE_TOKEN_UNICODE) {
1080 /* empty is false */
1081 if (arg->data.unicode.length == 0) {
1082 result->data.result.value = ACE_CONDITION_FALSE;
1083 } else {
1084 result->data.result.value = ACE_CONDITION_TRUE;
1086 return true;
1090 * everything else in UNKNOWN. This includes NULL values (i.e. an
1091 * unsuccessful look-up).
1093 result->data.result.value = ACE_CONDITION_UNKNOWN;
1094 return true;
1097 static bool not_operator(
1098 const struct ace_condition_token *arg,
1099 struct ace_condition_token *result)
1101 bool ok;
1102 if (IS_LITERAL_TOKEN(arg)) {
1104 * Logic operators don't work on literals.
1106 return false;
1109 ok = ternary_value(arg, result);
1110 if (! ok) {
1111 return false;
1113 if (result->data.result.value == ACE_CONDITION_FALSE) {
1114 result->data.result.value = ACE_CONDITION_TRUE;
1115 } else if (result->data.result.value == ACE_CONDITION_TRUE) {
1116 result->data.result.value = ACE_CONDITION_FALSE;
1118 /* unknown stays unknown */
1119 return true;
1123 static bool unary_logic_operator(
1124 TALLOC_CTX *mem_ctx,
1125 const struct security_token *token,
1126 const struct ace_condition_token *op,
1127 const struct ace_condition_token *arg,
1128 const struct security_descriptor *sd,
1129 struct ace_condition_token *result)
1132 bool ok;
1133 bool found;
1134 struct ace_condition_token claim = {
1135 .type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR
1137 if (op->type == CONDITIONAL_ACE_TOKEN_NOT) {
1138 return not_operator(arg, result);
1140 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
1141 result->data.result.value = ACE_CONDITION_UNKNOWN;
1144 * Not_Exists and Exists require the same work, except we negate the
1145 * answer in one case. From [MS-DTYP] 2.4.4.17.7:
1147 * If the type of the operand is "Local Attribute"
1148 * If the value is non-null return TRUE
1149 * Else return FALSE
1150 * Else if the type of the operand is "Resource Attribute"
1151 * Return TRUE if value is non-null; FALSE otherwise.
1152 * Else return Error
1154 switch (op->type) {
1155 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
1156 ok = token_claim_lookup(mem_ctx, token, arg, &claim);
1158 * "not ok" usually means a failure to find the attribute,
1159 * which is the false condition and not an error.
1161 * XXX or do we need an extra flag?
1163 break;
1164 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
1165 ok = resource_claim_lookup(mem_ctx, arg, sd, &claim);
1166 break;
1167 default:
1168 return false;
1175 if (claim.type != CONDITIONAL_ACE_SAMBA_RESULT_NULL) {
1176 found = true;
1177 } else if (ok) {
1178 found = false;
1179 } else {
1180 return false;
1185 if (op->type == CONDITIONAL_ACE_TOKEN_NOT_EXISTS) {
1186 found = ! found;
1187 } else if (op->type != CONDITIONAL_ACE_TOKEN_EXISTS) {
1188 /* should not get here */
1189 return false;
1192 result->data.result.value = found ? ACE_CONDITION_TRUE: ACE_CONDITION_FALSE;
1193 return true;
1198 static bool binary_logic_operator(
1199 const struct security_token *token,
1200 const struct ace_condition_token *op,
1201 const struct ace_condition_token *lhs,
1202 const struct ace_condition_token *rhs,
1203 struct ace_condition_token *result)
1205 struct ace_condition_token at, bt;
1206 int a, b;
1207 bool ok;
1209 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
1210 result->data.result.value = ACE_CONDITION_UNKNOWN;
1212 if (IS_LITERAL_TOKEN(lhs) || IS_LITERAL_TOKEN(rhs)) {
1214 * Logic operators don't work on literals.
1216 return false;
1219 ok = ternary_value(lhs, &at);
1220 if (! ok) {
1221 return false;
1223 ok = ternary_value(rhs, &bt);
1224 if (! ok) {
1225 return false;
1227 a = at.data.result.value;
1228 b = bt.data.result.value;
1230 if (op->type == CONDITIONAL_ACE_TOKEN_AND) {
1232 * AND true false unknown
1233 * true T F ?
1234 * false F F F
1235 * unknown ? F ?
1237 * unknown unless BOTH true or EITHER false
1239 if (a == ACE_CONDITION_TRUE &&
1240 b == ACE_CONDITION_TRUE) {
1241 result->data.result.value = ACE_CONDITION_TRUE;
1242 return true;
1244 if (a == ACE_CONDITION_FALSE ||
1245 b == ACE_CONDITION_FALSE) {
1246 result->data.result.value = ACE_CONDITION_FALSE;
1247 return true;
1250 * Neither value is False, so the result is Unknown,
1251 * as set at the start of this function.
1253 return true;
1256 * OR true false unknown
1257 * true T T T
1258 * false T F ?
1259 * unknown T ? ?
1261 * unknown unless EITHER true or BOTH false
1263 if (a == ACE_CONDITION_TRUE ||
1264 b == ACE_CONDITION_TRUE) {
1265 result->data.result.value = ACE_CONDITION_TRUE;
1266 return true;
1268 if (a == ACE_CONDITION_FALSE &&
1269 b == ACE_CONDITION_FALSE) {
1270 result->data.result.value = ACE_CONDITION_FALSE;
1271 return true;
1273 return true;
1277 static bool tokens_are_comparable(const struct ace_condition_token *op,
1278 const struct ace_condition_token *lhs,
1279 const struct ace_condition_token *rhs)
1281 uint64_t n;
1283 * we can't compare different types *unless* they are both
1284 * integers, or one is a bool and the other is an integer 0 or
1285 * 1, and the operator is == or !=.
1287 //XXX actually it says "literal integers", do we need to check flags?
1289 if (IS_INT_TOKEN(lhs) && IS_INT_TOKEN(rhs)) {
1290 /* don't block e.g. comparing an int32 to an int64 */
1291 return true;
1294 /* is it == or != */
1295 if (op->type != CONDITIONAL_ACE_TOKEN_EQUAL &&
1296 op->type != CONDITIONAL_ACE_TOKEN_NOT_EQUAL) {
1297 return false;
1299 /* is one a bool and the other an int? */
1300 if (IS_INT_TOKEN(lhs) && IS_BOOL_TOKEN(rhs)) {
1301 n = lhs->data.int64.value;
1302 } else if (IS_INT_TOKEN(rhs) && IS_BOOL_TOKEN(lhs)) {
1303 n = rhs->data.int64.value;
1304 } else {
1305 return false;
1307 if (n == 0 || n == 1) {
1308 return true;
1310 return false;
1314 static bool cmp_to_result(const struct ace_condition_token *op,
1315 struct ace_condition_token *result,
1316 int cmp)
1318 bool answer;
1319 switch (op->type) {
1320 case CONDITIONAL_ACE_TOKEN_EQUAL:
1321 answer = cmp == 0;
1322 break;
1323 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
1324 answer = cmp != 0;
1325 break;
1326 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
1327 answer = cmp < 0;
1328 break;
1329 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
1330 answer = cmp <= 0;
1331 break;
1332 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
1333 answer = cmp > 0;
1334 break;
1335 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
1336 answer = cmp >= 0;
1337 break;
1338 default:
1339 result->data.result.value = ACE_CONDITION_UNKNOWN;
1340 return false;
1342 result->data.result.value = \
1343 answer ? ACE_CONDITION_TRUE : ACE_CONDITION_FALSE;
1344 return true;
1349 static bool compare_unicode(const struct ace_condition_token *op,
1350 const struct ace_condition_token *lhs,
1351 const struct ace_condition_token *rhs,
1352 int *cmp)
1354 struct ace_condition_unicode a = lhs->data.unicode;
1355 struct ace_condition_unicode b = rhs->data.unicode;
1357 * Comparison is case-insensitive UNLESS the claim structure
1358 * has the case-sensitive flag, which is passed through as a
1359 * flag on the token. Usually only the LHS is a claim value,
1360 * but in the event that they both are, we allow either to
1361 * request case-sensitivity.
1363 * For greater than and less than, the sort order is utf-8 order,
1364 * which is not exactly what Windows does, but we don't sort like
1365 * Windows does anywhere else either.
1367 uint8_t flags = lhs->flags | rhs->flags;
1368 if (flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE) {
1369 *cmp = memcmp(a.value, b.value, MIN(a.length, b.length));
1370 } else {
1371 *cmp = strncasecmp_m(a.value, b.value, MIN(a.length, b.length));
1373 if (*cmp == 0) {
1374 *cmp = a.length - b.length;
1376 return true;
1380 static bool compare_bytes(const struct ace_condition_token *op,
1381 const struct ace_condition_token *lhs,
1382 const struct ace_condition_token *rhs,
1383 int *cmp)
1385 struct ace_condition_bytes a = lhs->data.bytes;
1386 struct ace_condition_bytes b = rhs->data.bytes;
1387 *cmp = memcmp(a.bytes, b.bytes, MIN(a.length, b.length));
1388 if (*cmp == 0) {
1389 *cmp = a.length - b.length;
1391 return true;
1395 static bool compare_sids(const struct ace_condition_token *op,
1396 const struct ace_condition_token *lhs,
1397 const struct ace_condition_token *rhs,
1398 int *cmp)
1400 *cmp = dom_sid_compare(lhs->data.sid.sid,
1401 rhs->data.sid.sid);
1402 return true;
1406 static bool compare_ints(const struct ace_condition_token *op,
1407 const struct ace_condition_token *lhs,
1408 const struct ace_condition_token *rhs,
1409 int *cmp)
1411 int64_t a = lhs->data.int64.value;
1412 int64_t b = rhs->data.int64.value;
1414 if (a < b) {
1415 *cmp = -1;
1416 } else if (a == b) {
1417 *cmp = 0;
1418 } else {
1419 *cmp = 1;
1421 return true;
1425 static bool compare_bools(const struct ace_condition_token *op,
1426 const struct ace_condition_token *lhs,
1427 const struct ace_condition_token *rhs,
1428 int *cmp)
1430 bool ok;
1431 struct ace_condition_token a, b;
1432 *cmp = -1;
1434 if (IS_LITERAL_TOKEN(lhs)) {
1436 * we can compare a boolean LHS to a literal RHS, but not
1437 * vice versa
1439 return false;
1441 ok = ternary_value(lhs, &a);
1442 if (! ok) {
1443 return false;
1445 ok = ternary_value(rhs, &b);
1446 if (! ok) {
1447 return false;
1449 if (a.data.result.value == ACE_CONDITION_UNKNOWN ||
1450 b.data.result.value == ACE_CONDITION_UNKNOWN) {
1451 return false;
1454 switch (op->type) {
1455 case CONDITIONAL_ACE_TOKEN_EQUAL:
1456 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
1457 *cmp = a.data.result.value - b.data.result.value;
1458 break;
1459 default:
1460 /* we are not allowing non-equality comparisons with bools */
1461 return false;
1463 return true;
1467 static bool simple_relational_operator(const struct ace_condition_token *op,
1468 const struct ace_condition_token *lhs,
1469 const struct ace_condition_token *rhs,
1470 int *cmp);
1473 static bool compare_composites(const struct ace_condition_token *op,
1474 const struct ace_condition_token *lhs,
1475 const struct ace_condition_token *rhs,
1476 int *cmp)
1479 * We treat composites as if they are sets, which is to say we
1480 * don't care about order. This rules out < and > operations.
1482 * In Kerberos clams it is not possible to add duplicate
1483 * values to a composite, but in Conditional ACEs you can do
1484 * that. This means we can't short-cut by comparing the
1485 * lengths.
1487 * THe extra sad thing is we might have to do it both ways
1488 * round. For example, comparing {a, a, b, a} to {a, b, c}, we
1489 * find all of the first group in the second, but that doesn't
1490 * mean all of the second are in the first.
1492 struct ace_condition_composite args[2] = {
1493 lhs->data.composite,
1494 rhs->data.composite
1496 size_t i, j, k;
1498 for (k = 0; k < 2; k++) {
1499 struct ace_condition_composite a = args[k];
1500 struct ace_condition_composite b = args[1 - k];
1502 for (i = 0; i < a.n_members; i++) {
1503 const struct ace_condition_token *lhs2 = &a.tokens[i];
1504 bool found = false;
1505 for (j = 0; j < b.n_members; j++) {
1506 const struct ace_condition_token *rhs2 = &b.tokens[j];
1507 int cmp_pair;
1508 bool ok = simple_relational_operator(op, lhs2, rhs2, &cmp_pair);
1509 if (! ok) {
1510 return false;
1512 if (cmp_pair == 0) {
1513 /* This item in A is also in B. */
1514 found = true;
1515 break;
1518 if (! found) {
1519 *cmp = -1;
1520 return true;
1524 *cmp = 0;
1525 return true;
1529 static bool simple_relational_operator(const struct ace_condition_token *op,
1530 const struct ace_condition_token *lhs,
1531 const struct ace_condition_token *rhs,
1532 int *cmp)
1535 if (lhs->type != rhs->type) {
1536 if (! tokens_are_comparable(op, lhs, rhs)) {
1537 return false;
1540 switch (lhs->type) {
1541 case CONDITIONAL_ACE_TOKEN_INT8:
1542 case CONDITIONAL_ACE_TOKEN_INT16:
1543 case CONDITIONAL_ACE_TOKEN_INT32:
1544 case CONDITIONAL_ACE_TOKEN_INT64:
1545 if (rhs->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
1546 return compare_bools(op, lhs, rhs, cmp);
1548 return compare_ints(op, lhs, rhs, cmp);
1549 case CONDITIONAL_ACE_SAMBA_RESULT_BOOL:
1550 return compare_bools(op, lhs, rhs, cmp);
1551 case CONDITIONAL_ACE_TOKEN_UNICODE:
1552 return compare_unicode(op, lhs, rhs, cmp);
1553 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
1554 return compare_bytes(op, lhs, rhs, cmp);
1555 case CONDITIONAL_ACE_TOKEN_SID:
1556 return compare_sids(op, lhs, rhs, cmp);
1557 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
1558 return compare_composites(op, lhs, rhs, cmp);
1559 case CONDITIONAL_ACE_SAMBA_RESULT_NULL:
1560 /* leave the result unknown */
1561 return false;
1562 default:
1563 DBG_ERR("did not expect ace type %u\n", lhs->type);
1564 return false;
1567 return false;
1571 static bool find_in_composite(const struct ace_condition_token *tok,
1572 struct ace_condition_composite candidates,
1573 bool *answer)
1575 size_t i;
1576 int cmp;
1577 bool ok;
1578 const struct ace_condition_token equals = {
1579 .type = CONDITIONAL_ACE_TOKEN_EQUAL
1582 *answer = false;
1584 for (i = 0; i < candidates.n_members; i++) {
1585 ok = simple_relational_operator(&equals,
1586 tok,
1587 &candidates.tokens[i],
1588 &cmp);
1589 if (! ok) {
1590 return false;
1592 if (cmp == 0) {
1593 *answer = true;
1594 return true;
1597 return true;
1601 static bool contains_operator(const struct ace_condition_token *lhs,
1602 const struct ace_condition_token *rhs,
1603 bool *answer)
1605 size_t i;
1606 bool ok;
1607 int cmp;
1608 const struct ace_condition_token equals = {
1609 .type = CONDITIONAL_ACE_TOKEN_EQUAL
1613 * All the required objects must be identical to something in
1614 * candidates. But what do we mean by *identical*? We'll use
1615 * the equality operator to decide that.
1617 * Both the lhs or rhs can be solitary objects or composites.
1618 * This makes it a bit fiddlier.
1620 if (lhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1621 struct ace_condition_composite candidates = lhs->data.composite;
1622 struct ace_condition_composite required;
1623 if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1624 return find_in_composite(rhs, candidates, answer);
1626 required = rhs->data.composite;
1627 if (required.n_members == 0) {
1628 return false;
1630 for (i = 0; i < required.n_members; i++) {
1631 const struct ace_condition_token *t = &required.tokens[i];
1632 ok = find_in_composite(t, candidates, answer);
1633 if (! ok) {
1634 return false;
1636 if (! *answer) {
1638 * one required item was not there,
1639 * *answer is false
1641 return true;
1644 /* all required items are there, *answer will be true */
1645 return true;
1647 /* LHS is a single item */
1648 if (rhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1650 * There could be more than one RHS member that is
1651 * equal to the single LHS value, so it doesn't help
1652 * to compare lengths or anything.
1654 struct ace_condition_composite required = rhs->data.composite;
1655 if (required.n_members == 0) {
1656 return false;
1658 for (i = 0; i < required.n_members; i++) {
1659 ok = simple_relational_operator(&equals,
1660 lhs,
1661 &required.tokens[i],
1662 &cmp);
1663 if (! ok) {
1664 return false;
1666 if (cmp != 0) {
1668 * one required item was not there,
1669 * *answer is false
1671 *answer = false;
1672 return true;
1675 *answer = true;
1676 return true;
1678 /* LHS and RHS are both single */
1679 ok = simple_relational_operator(&equals,
1680 lhs,
1681 rhs,
1682 &cmp);
1683 if (! ok) {
1684 return false;
1686 *answer = (cmp == 0);
1687 return true;
1691 static bool any_of_operator(const struct ace_condition_token *lhs,
1692 const struct ace_condition_token *rhs,
1693 bool *answer)
1695 size_t i;
1696 bool ok;
1697 int cmp;
1698 const struct ace_condition_token equals = {
1699 .type = CONDITIONAL_ACE_TOKEN_EQUAL
1703 * There has to be *some* overlap between the LHS and RHS.
1704 * Both sides can be solitary objects or composites.
1706 * We can exploit this symmetry.
1708 if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1709 const struct ace_condition_token *tmp = lhs;
1710 lhs = rhs;
1711 rhs = tmp;
1713 if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1714 /* both singles */
1715 ok = simple_relational_operator(&equals,
1716 lhs,
1717 rhs,
1718 &cmp);
1719 if (! ok) {
1720 return false;
1722 *answer = (cmp == 0);
1723 return true;
1725 if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1726 return find_in_composite(rhs, lhs->data.composite, answer);
1728 /* both are composites */
1729 if (lhs->data.composite.n_members == 0) {
1730 return false;
1732 for (i = 0; i < lhs->data.composite.n_members; i++) {
1733 ok = find_in_composite(&lhs->data.composite.tokens[i],
1734 rhs->data.composite,
1735 answer);
1736 if (! ok) {
1737 return false;
1739 if (*answer) {
1740 /* We have found one match, which is enough. */
1741 return true;
1744 return true;
1748 static bool composite_relational_operator(const struct ace_condition_token *op,
1749 const struct ace_condition_token *lhs,
1750 const struct ace_condition_token *rhs,
1751 struct ace_condition_token *result)
1753 bool ok, answer;
1754 switch(op->type) {
1755 case CONDITIONAL_ACE_TOKEN_CONTAINS:
1756 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
1757 ok = contains_operator(lhs, rhs, &answer);
1758 break;
1759 case CONDITIONAL_ACE_TOKEN_ANY_OF:
1760 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
1761 ok = any_of_operator(lhs, rhs, &answer);
1762 break;
1763 default:
1764 return false;
1766 if (!ok) {
1767 return false;
1770 /* negate the NOTs */
1771 if (op->type == CONDITIONAL_ACE_TOKEN_NOT_CONTAINS ||
1772 op->type == CONDITIONAL_ACE_TOKEN_NOT_ANY_OF) {
1773 answer = !answer;
1776 if (answer) {
1777 result->data.result.value = ACE_CONDITION_TRUE;
1778 } else {
1779 result->data.result.value = ACE_CONDITION_FALSE;
1781 return true;
1785 static bool relational_operator(
1786 const struct security_token *token,
1787 const struct ace_condition_token *op,
1788 const struct ace_condition_token *lhs,
1789 const struct ace_condition_token *rhs,
1790 struct ace_condition_token *result)
1792 int cmp;
1793 bool ok;
1794 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
1795 result->data.result.value = ACE_CONDITION_UNKNOWN;
1797 if ((lhs->flags & CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR) == 0) {
1798 /* LHS was not derived from an attribute */
1799 return false;
1803 * This first nested switch is ensuring that >, >=, <, <= are
1804 * not being tried on tokens that are not numbers, strings, or
1805 * octet strings. Equality operators are available for all types.
1807 switch (lhs->type) {
1808 case CONDITIONAL_ACE_TOKEN_INT8:
1809 case CONDITIONAL_ACE_TOKEN_INT16:
1810 case CONDITIONAL_ACE_TOKEN_INT32:
1811 case CONDITIONAL_ACE_TOKEN_INT64:
1812 case CONDITIONAL_ACE_TOKEN_UNICODE:
1813 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
1814 break;
1815 default:
1816 switch(op->type) {
1817 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
1818 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
1819 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
1820 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
1821 return false;
1822 default:
1823 break;
1828 * Dispatch according to operator type.
1830 switch (op->type) {
1831 case CONDITIONAL_ACE_TOKEN_EQUAL:
1832 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
1833 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
1834 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
1835 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
1836 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
1837 ok = simple_relational_operator(op,
1838 lhs,
1839 rhs,
1840 &cmp);
1841 if (ok) {
1842 ok = cmp_to_result(op, result, cmp);
1844 return ok;
1846 case CONDITIONAL_ACE_TOKEN_CONTAINS:
1847 case CONDITIONAL_ACE_TOKEN_ANY_OF:
1848 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
1849 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
1850 return composite_relational_operator(op,
1851 lhs,
1852 rhs,
1853 result);
1854 default:
1855 return false;
1860 int run_conditional_ace(TALLOC_CTX *mem_ctx,
1861 const struct security_token *token,
1862 struct ace_condition_script *program,
1863 const struct security_descriptor *sd)
1865 size_t i;
1866 size_t depth = 0;
1867 struct ace_condition_token *lhs = NULL;
1868 struct ace_condition_token *rhs = NULL;
1869 struct ace_condition_token result = {};
1870 bool ok;
1872 for (i = 0; i < program->length; i++) {
1873 struct ace_condition_token *tok = &program->tokens[i];
1874 switch (tok->type) {
1875 case CONDITIONAL_ACE_TOKEN_INT8:
1876 case CONDITIONAL_ACE_TOKEN_INT16:
1877 case CONDITIONAL_ACE_TOKEN_INT32:
1878 case CONDITIONAL_ACE_TOKEN_INT64:
1879 case CONDITIONAL_ACE_TOKEN_UNICODE:
1880 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
1881 case CONDITIONAL_ACE_TOKEN_SID:
1882 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
1883 /* just plonk these literals on the stack */
1884 program->stack[depth] = *tok;
1885 depth++;
1886 break;
1888 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
1889 case CONDITIONAL_ACE_USER_ATTRIBUTE:
1890 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
1891 ok = token_claim_lookup(mem_ctx, token, tok, &result);
1892 if (! ok) {
1893 goto error;
1895 program->stack[depth] = result;
1896 depth++;
1897 break;
1899 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
1900 ok = resource_claim_lookup(mem_ctx,
1901 tok,
1903 &result);
1904 if (! ok) {
1905 goto error;
1907 program->stack[depth] = result;
1908 depth++;
1909 break;
1911 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
1912 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
1913 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
1914 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
1915 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
1916 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
1917 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
1918 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
1919 if (depth == 0) {
1920 goto error;
1922 depth--;
1923 lhs = &program->stack[depth];
1924 ok = member_lookup(token, tok, lhs, &result);
1925 if (! ok) {
1926 goto error;
1928 program->stack[depth] = result;
1929 depth++;
1930 break;
1931 /* binary relational operators */
1932 case CONDITIONAL_ACE_TOKEN_EQUAL:
1933 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
1934 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
1935 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
1936 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
1937 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
1938 case CONDITIONAL_ACE_TOKEN_CONTAINS:
1939 case CONDITIONAL_ACE_TOKEN_ANY_OF:
1940 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
1941 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
1942 if (depth < 2) {
1943 goto error;
1945 depth--;
1946 rhs = &program->stack[depth];
1947 depth--;
1948 lhs = &program->stack[depth];
1949 ok = relational_operator(token, tok, lhs, rhs, &result);
1950 if (! ok) {
1951 goto error;
1953 program->stack[depth] = result;
1954 depth++;
1955 break;
1956 /* unary logical operators */
1957 case CONDITIONAL_ACE_TOKEN_EXISTS:
1958 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
1959 case CONDITIONAL_ACE_TOKEN_NOT:
1960 if (depth == 0) {
1961 goto error;
1963 depth--;
1964 lhs = &program->stack[depth];
1965 ok = unary_logic_operator(mem_ctx, token, tok, lhs, sd, &result);
1966 if (!ok) {
1967 goto error;
1969 program->stack[depth] = result;
1970 depth++;
1971 break;
1972 /* binary logical operators */
1973 case CONDITIONAL_ACE_TOKEN_AND:
1974 case CONDITIONAL_ACE_TOKEN_OR:
1975 if (depth < 2) {
1976 goto error;
1978 depth--;
1979 rhs = &program->stack[depth];
1980 depth--;
1981 lhs = &program->stack[depth];
1982 ok = binary_logic_operator(token, tok, lhs, rhs, &result);
1983 if (! ok) {
1984 goto error;
1986 program->stack[depth] = result;
1987 depth++;
1988 break;
1989 default:
1990 goto error;
1994 * The evaluation should have left a single result value (true, false,
1995 * or unknown) on the stack. If not, the expression was malformed.
1997 if (depth != 1) {
1998 goto error;
2000 result = program->stack[0];
2001 if (result.type != CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
2002 goto error;
2005 return result.data.result.value;
2007 error:
2009 * the result of an error is always UNKNOWN, which should be
2010 * interpreted pessimistically, not allowing access.
2012 return ACE_CONDITION_UNKNOWN;
2016 /** access_check_conditional_ace()
2018 * Run the conditional ACE from the blob form. Return false if it is
2019 * not a valid conditional ACE, true if it is, even if there is some
2020 * other error in running it. The *result parameter is set to
2021 * ACE_CONDITION_FALSE, ACE_CONDITION_TRUE, or ACE_CONDITION_UNKNOWN.
2023 * ACE_CONDITION_UNKNOWN should be treated pessimistically, as if were
2024 * TRUE for deny ACEs, and FALSE for allow ACEs.
2026 * @param[in] ace - the ACE being processed.
2027 * @param[in] token - the security token the ACE is processing.
2028 * @param[out] result - a ternary result value.
2030 * @return true if it is a valid conditional ACE.
2033 bool access_check_conditional_ace(const struct security_ace *ace,
2034 const struct security_token *token,
2035 const struct security_descriptor *sd,
2036 int *result)
2038 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
2039 struct ace_condition_script *program = NULL;
2040 program = parse_conditional_ace(tmp_ctx, ace->coda.conditions);
2041 if (program == NULL) {
2042 *result = ACE_CONDITION_UNKNOWN;
2043 TALLOC_FREE(tmp_ctx);
2044 return false;
2047 *result = run_conditional_ace(tmp_ctx, token, program, sd);
2049 TALLOC_FREE(tmp_ctx);
2050 return true;
2054 bool conditional_ace_encode_binary(TALLOC_CTX *mem_ctx,
2055 struct ace_condition_script *program,
2056 DATA_BLOB *dest)
2058 size_t i, j, alloc_size, required_size;
2059 uint8_t *data = NULL;
2060 *dest = (DATA_BLOB){NULL, 0};
2062 alloc_size = CONDITIONAL_ACE_MAX_LENGTH;
2063 data = talloc_array(mem_ctx,
2064 uint8_t,
2065 alloc_size);
2066 if (data == NULL) {
2067 return false;
2070 data[0] = 'a';
2071 data[1] = 'r';
2072 data[2] = 't';
2073 data[3] = 'x';
2075 j = 4;
2076 for (i = 0; i < program->length; i++) {
2077 struct ace_condition_token *tok = &program->tokens[i];
2078 ssize_t consumed;
2079 bool ok;
2081 * In all cases we write the token type byte.
2083 data[j] = tok->type;
2084 j++;
2085 if (j >= alloc_size) {
2086 goto error;
2089 switch (tok->type) {
2090 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
2091 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
2092 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
2093 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
2094 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
2095 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
2096 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
2097 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
2098 case CONDITIONAL_ACE_TOKEN_EQUAL:
2099 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
2100 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
2101 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
2102 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
2103 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
2104 case CONDITIONAL_ACE_TOKEN_CONTAINS:
2105 case CONDITIONAL_ACE_TOKEN_ANY_OF:
2106 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
2107 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
2108 case CONDITIONAL_ACE_TOKEN_EXISTS:
2109 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
2110 case CONDITIONAL_ACE_TOKEN_NOT:
2111 case CONDITIONAL_ACE_TOKEN_AND:
2112 case CONDITIONAL_ACE_TOKEN_OR:
2114 * All of these are simple operators that operate on
2115 * the stack. We have already added the tok->type and
2116 * there's nothing else to do.
2118 continue;
2120 case CONDITIONAL_ACE_TOKEN_INT8:
2121 case CONDITIONAL_ACE_TOKEN_INT16:
2122 case CONDITIONAL_ACE_TOKEN_INT32:
2123 case CONDITIONAL_ACE_TOKEN_INT64:
2124 ok = check_integer_range(tok);
2125 if (! ok) {
2126 goto error;
2128 consumed = push_integer(data + j,
2129 alloc_size - j,
2130 &tok->data.int64);
2131 break;
2132 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
2133 case CONDITIONAL_ACE_USER_ATTRIBUTE:
2134 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
2135 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
2136 case CONDITIONAL_ACE_TOKEN_UNICODE:
2137 consumed = push_unicode(data + j,
2138 alloc_size - j,
2139 &tok->data.unicode);
2140 break;
2141 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
2142 consumed = push_bytes(data + j,
2143 alloc_size - j,
2144 &tok->data.bytes);
2145 break;
2146 case CONDITIONAL_ACE_TOKEN_SID:
2147 consumed = push_sid(data + j,
2148 alloc_size - j,
2149 &tok->data.sid);
2150 break;
2151 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
2152 consumed = push_composite(data + j,
2153 alloc_size - j,
2154 &tok->data.composite);
2155 break;
2157 default:
2158 DBG_ERR("unknown token 0x%02x at position %zu\n",
2159 tok->type, i);
2160 goto error;
2162 if (consumed == -1) {
2163 goto error;
2165 j += consumed;
2166 if (j >= alloc_size) {
2167 goto error;
2170 /* align to a 4 byte boundary */
2171 required_size = (j + 3) & ~((size_t)3);
2172 if (required_size > alloc_size) {
2173 goto error;
2175 while (j < required_size) {
2176 data[j] = 0;
2177 j++;
2179 data = talloc_realloc(mem_ctx,
2180 data,
2181 uint8_t,
2182 required_size);
2183 if (data == NULL) {
2184 return false;
2187 (*dest).data = data;
2188 (*dest).length = j;
2189 return true;
2190 error:
2191 TALLOC_FREE(data);
2192 return false;