ctdb-scripts: Improve update and listing code
[samba4-gss.git] / libcli / security / conditional_ace.c
blobc2411c4649e083aaa05ac422f9029dd8075fb8a5
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/ndr_conditional_ace.h"
22 #include "librpc/gen_ndr/conditional_ace.h"
23 #include "libcli/security/security.h"
24 #include "libcli/security/conditional_ace.h"
25 #include "libcli/security/claims-conversions.h"
26 #include "lib/util/tsort.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/bytearray.h"
29 #include "lib/util/talloc_stack.h"
30 #include "util/discard.h"
31 #include "lib/util/stable_sort.h"
33 * Conditional ACE logic truth tables.
35 * Conditional ACES use a ternary logic, with "unknown" as well as true and
36 * false. The ultimate meaning of unknown depends on the context; in a deny
37 * ace, unknown means yes, in an allow ace, unknown means no. That is, we
38 * treat unknown results with maximum suspicion.
40 * AND true false unknown
41 * true T F ?
42 * false F F F
43 * unknown ? F ?
45 * OR true false unknown
46 * true T T T
47 * false T F ?
48 * unknown T ? ?
50 * NOT
51 * true F
52 * false T
53 * unknown ?
55 * This can be summed up by saying unknown values taint the result except in
56 * the cases where short circuit evaluation could apply (true OR anything,
57 * false AND anything, which hold their value).
59 * What counts as unknown
61 * - NULL attributes.
62 * - certain comparisons between incompatible types
64 * What counts as false
66 * - zero
67 * - empty strings
69 * An error means the entire expression is unknown.
73 static bool check_integer_range(const struct ace_condition_token *tok)
75 int64_t val = tok->data.int64.value;
76 switch (tok->type) {
77 case CONDITIONAL_ACE_TOKEN_INT8:
78 if (val < -128 || val > 127) {
79 return false;
81 break;
82 case CONDITIONAL_ACE_TOKEN_INT16:
83 if (val < INT16_MIN || val > INT16_MAX) {
84 return false;
86 break;
87 case CONDITIONAL_ACE_TOKEN_INT32:
88 if (val < INT32_MIN || val > INT32_MAX) {
89 return false;
91 break;
92 case CONDITIONAL_ACE_TOKEN_INT64:
93 /* val has these limits naturally */
94 break;
95 default:
96 return false;
99 if (tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_8 &&
100 tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_10 &&
101 tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_16) {
102 return false;
104 if (tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_POSITIVE &&
105 tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NEGATIVE &&
106 tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NONE) {
107 return false;
109 return true;
113 static ssize_t pull_integer(TALLOC_CTX *mem_ctx,
114 uint8_t *data, size_t length,
115 struct ace_condition_int *tok)
117 ssize_t bytes_used;
118 enum ndr_err_code ndr_err;
119 DATA_BLOB v = data_blob_const(data, length);
120 struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
121 if (ndr == NULL) {
122 return -1;
124 ndr_err = ndr_pull_ace_condition_int(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
125 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
126 TALLOC_FREE(ndr);
127 return -1;
129 bytes_used = ndr->offset;
130 TALLOC_FREE(ndr);
131 return bytes_used;
134 static ssize_t push_integer(uint8_t *data, size_t available,
135 const struct ace_condition_int *tok)
137 enum ndr_err_code ndr_err;
138 DATA_BLOB v;
139 ndr_err = ndr_push_struct_blob(&v, NULL,
140 tok,
141 (ndr_push_flags_fn_t)ndr_push_ace_condition_int);
142 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
143 return -1;
145 if (available < v.length) {
146 talloc_free(v.data);
147 return -1;
149 memcpy(data, v.data, v.length);
150 talloc_free(v.data);
151 return v.length;
155 static ssize_t pull_unicode(TALLOC_CTX *mem_ctx,
156 uint8_t *data, size_t length,
157 struct ace_condition_unicode *tok)
159 ssize_t bytes_used;
160 enum ndr_err_code ndr_err;
161 DATA_BLOB v = data_blob_const(data, length);
162 struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
163 if (ndr == NULL) {
164 return -1;
166 ndr_err = ndr_pull_ace_condition_unicode(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
167 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
168 TALLOC_FREE(ndr);
169 return -1;
171 bytes_used = ndr->offset;
172 TALLOC_FREE(ndr);
173 return bytes_used;
176 static ssize_t push_unicode(uint8_t *data, size_t available,
177 const struct ace_condition_unicode *tok)
179 enum ndr_err_code ndr_err;
180 DATA_BLOB v;
181 ndr_err = ndr_push_struct_blob(&v, NULL,
182 tok,
183 (ndr_push_flags_fn_t)ndr_push_ace_condition_unicode);
184 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
185 return -1;
187 if (available < v.length) {
188 talloc_free(v.data);
189 return -1;
191 memcpy(data, v.data, v.length);
192 talloc_free(v.data);
193 return v.length;
197 static ssize_t pull_bytes(TALLOC_CTX *mem_ctx,
198 uint8_t *data, size_t length,
199 DATA_BLOB *tok)
201 ssize_t bytes_used;
202 enum ndr_err_code ndr_err;
203 DATA_BLOB v = data_blob_const(data, length);
204 struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
205 if (ndr == NULL) {
206 return -1;
208 ndr_err = ndr_pull_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
210 TALLOC_FREE(ndr);
211 return -1;
213 bytes_used = ndr->offset;
214 talloc_free(ndr);
215 return bytes_used;
218 static ssize_t push_bytes(uint8_t *data, size_t available,
219 const DATA_BLOB *tok)
221 size_t offset;
222 enum ndr_err_code ndr_err;
223 TALLOC_CTX *frame = talloc_stackframe();
224 struct ndr_push *ndr = ndr_push_init_ctx(frame);
225 if (ndr == NULL) {
226 TALLOC_FREE(frame);
227 return -1;
230 ndr_err = ndr_push_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, *tok);
231 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232 TALLOC_FREE(frame);
233 return -1;
236 if (available < ndr->offset) {
237 TALLOC_FREE(frame);
238 return -1;
240 memcpy(data, ndr->data, ndr->offset);
241 offset = ndr->offset;
242 TALLOC_FREE(frame);
243 return offset;
246 static ssize_t pull_sid(TALLOC_CTX *mem_ctx,
247 uint8_t *data, size_t length,
248 struct ace_condition_sid *tok)
250 ssize_t bytes_used;
251 enum ndr_err_code ndr_err;
252 DATA_BLOB v = data_blob_const(data, length);
253 struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
254 if (ndr == NULL) {
255 return -1;
257 ndr->flags |= LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES;
259 ndr_err = ndr_pull_ace_condition_sid(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
260 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
261 TALLOC_FREE(ndr);
262 return -1;
264 bytes_used = ndr->offset;
265 TALLOC_FREE(ndr);
266 return bytes_used;
269 static ssize_t push_sid(uint8_t *data, size_t available,
270 const struct ace_condition_sid *tok)
272 enum ndr_err_code ndr_err;
273 DATA_BLOB v;
274 ndr_err = ndr_push_struct_blob(&v, NULL,
275 tok,
276 (ndr_push_flags_fn_t)ndr_push_ace_condition_sid);
277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
278 return -1;
280 if (available < v.length) {
281 talloc_free(v.data);
282 return -1;
284 memcpy(data, v.data, v.length);
285 talloc_free(v.data);
286 return v.length;
290 static ssize_t pull_composite(TALLOC_CTX *mem_ctx,
291 uint8_t *data, size_t length,
292 struct ace_condition_composite *tok)
294 size_t i, j;
295 size_t alloc_length;
296 size_t byte_size;
297 struct ace_condition_token *tokens = NULL;
298 if (length < 4) {
299 return -1;
301 byte_size = PULL_LE_U32(data, 0);
302 if (byte_size > length - 4) {
303 return -1;
306 * There is a list of other literal tokens (possibly including nested
307 * composites), which we will store in an array.
309 * This array can *only* be literals.
311 alloc_length = byte_size;
312 tokens = talloc_array(mem_ctx,
313 struct ace_condition_token,
314 alloc_length);
315 if (tokens == NULL) {
316 return -1;
318 byte_size += 4;
319 i = 4;
320 j = 0;
321 while (i < byte_size) {
322 struct ace_condition_token *el = &tokens[j];
323 ssize_t consumed;
324 uint8_t *el_data = NULL;
325 size_t available;
326 bool ok;
327 *el = (struct ace_condition_token) { .type = data[i] };
328 i++;
330 el_data = data + i;
331 available = byte_size - i;
333 switch (el->type) {
334 case CONDITIONAL_ACE_TOKEN_INT8:
335 case CONDITIONAL_ACE_TOKEN_INT16:
336 case CONDITIONAL_ACE_TOKEN_INT32:
337 case CONDITIONAL_ACE_TOKEN_INT64:
338 consumed = pull_integer(mem_ctx,
339 el_data,
340 available,
341 &el->data.int64);
342 ok = check_integer_range(el);
343 if (! ok) {
344 goto error;
346 break;
347 case CONDITIONAL_ACE_TOKEN_UNICODE:
348 consumed = pull_unicode(mem_ctx,
349 el_data,
350 available,
351 &el->data.unicode);
352 break;
354 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
355 consumed = pull_bytes(mem_ctx,
356 el_data,
357 available,
358 &el->data.bytes);
359 break;
361 case CONDITIONAL_ACE_TOKEN_SID:
362 consumed = pull_sid(mem_ctx,
363 el_data,
364 available,
365 &el->data.sid);
366 break;
368 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
369 DBG_ERR("recursive composite tokens in conditional "
370 "ACEs are not currently supported\n");
371 goto error;
372 default:
373 goto error;
376 if (consumed < 0 || consumed + i > length) {
377 goto error;
379 i += consumed;
380 j++;
381 if (j == UINT16_MAX) {
382 talloc_free(tokens);
383 return -1;
385 if (j == alloc_length) {
386 struct ace_condition_token *new_tokens = NULL;
388 alloc_length += 5;
389 new_tokens = talloc_realloc(mem_ctx,
390 tokens,
391 struct ace_condition_token,
392 alloc_length);
394 if (new_tokens == NULL) {
395 goto error;
397 tokens = new_tokens;
400 tok->n_members = j;
401 tok->tokens = tokens;
402 return byte_size;
403 error:
404 talloc_free(tokens);
405 return -1;
409 static ssize_t push_composite(uint8_t *data, size_t length,
410 const struct ace_condition_composite *tok)
412 size_t i;
413 uint8_t *byte_length_ptr;
414 size_t used = 0;
415 if (length < 4) {
416 return -1;
419 * We have no idea what the eventual length will be, so we keep a
420 * pointer to write it in at the end.
422 byte_length_ptr = data;
423 PUSH_LE_U32(data, 0, 0);
424 used = 4;
426 for (i = 0; i < tok->n_members && used < length; i++) {
427 struct ace_condition_token *el = &tok->tokens[i];
428 ssize_t consumed;
429 uint8_t *el_data = NULL;
430 size_t available;
431 bool ok;
432 data[used] = el->type;
433 used++;
434 if (used == length) {
436 * used == length is not expected here; the token
437 * types that only have an opcode and no data are not
438 * literals that can be in composites.
440 return -1;
442 el_data = data + used;
443 available = length - used;
445 switch (el->type) {
446 case CONDITIONAL_ACE_TOKEN_INT8:
447 case CONDITIONAL_ACE_TOKEN_INT16:
448 case CONDITIONAL_ACE_TOKEN_INT32:
449 case CONDITIONAL_ACE_TOKEN_INT64:
450 ok = check_integer_range(el);
451 if (! ok) {
452 return -1;
454 consumed = push_integer(el_data,
455 available,
456 &el->data.int64);
457 break;
458 case CONDITIONAL_ACE_TOKEN_UNICODE:
459 consumed = push_unicode(el_data,
460 available,
461 &el->data.unicode);
462 break;
464 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
465 consumed = push_bytes(el_data,
466 available,
467 &el->data.bytes);
468 break;
470 case CONDITIONAL_ACE_TOKEN_SID:
471 consumed = push_sid(el_data,
472 available,
473 &el->data.sid);
474 break;
476 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
477 consumed = push_composite(el_data,
478 available,
479 &el->data.composite);
480 break;
482 default:
483 return -1;
486 if (consumed < 0) {
487 return -1;
489 used += consumed;
491 if (used > length) {
492 return -1;
495 PUSH_LE_U32(byte_length_ptr, 0, used - 4);
496 return used;
499 static ssize_t pull_end_padding(uint8_t *data, size_t length)
502 * We just check that we have the right kind of number of zero
503 * bytes. The blob must end on a multiple of 4. One zero byte
504 * has already been swallowed as tok->type, which sends us
505 * here, so we expect 1 or two more -- total padding is 0, 1,
506 * 2, or 3.
508 * zero is also called CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING.
510 ssize_t i;
511 if (length > 2) {
512 return -1;
514 for (i = 0; i < length; i++) {
515 if (data[i] != 0) {
516 return -1;
519 return length;
523 struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx,
524 DATA_BLOB data)
526 size_t i, j;
527 struct ace_condition_token *tokens = NULL;
528 size_t alloc_length;
529 struct ace_condition_script *program = NULL;
531 if (data.length < 4 ||
532 data.data[0] != 'a' ||
533 data.data[1] != 'r' ||
534 data.data[2] != 't' ||
535 data.data[3] != 'x') {
537 * lacks the "artx" conditional ace identifier magic.
538 * NULL returns will deny access.
540 return NULL;
542 if (data.length > CONDITIONAL_ACE_MAX_LENGTH ||
543 (data.length & 3) != 0) {
545 * >= 64k or non-multiples of 4 are not possible in the ACE
546 * wire format.
548 return NULL;
551 program = talloc(mem_ctx, struct ace_condition_script);
552 if (program == NULL) {
553 return NULL;
557 * We will normally end up with fewer than data.length tokens, as
558 * values are stored in multiple bytes (all integers are 10 bytes,
559 * strings and attributes are utf16 + length, SIDs are SID-size +
560 * length, etc). But operators are one byte, so something like
561 * !(!(!(!(!(!(x)))))) -- where each '!(..)' is one byte -- will bring
562 * the number of tokens close to the number of bytes.
564 * This is all to say we're guessing a token length that hopes to
565 * avoid reallocs without wasting too much up front.
567 alloc_length = data.length / 2 + 1;
568 tokens = talloc_array(program,
569 struct ace_condition_token,
570 alloc_length);
571 if (tokens == NULL) {
572 TALLOC_FREE(program);
573 return NULL;
576 i = 4;
577 j = 0;
578 while(i < data.length) {
579 struct ace_condition_token *tok = &tokens[j];
580 ssize_t consumed = 0;
581 uint8_t *tok_data = NULL;
582 size_t available;
583 bool ok;
584 tok->type = data.data[i];
585 tok->flags = 0;
586 i++;
587 tok_data = data.data + i;
588 available = data.length - i;
590 switch (tok->type) {
591 case CONDITIONAL_ACE_TOKEN_INT8:
592 case CONDITIONAL_ACE_TOKEN_INT16:
593 case CONDITIONAL_ACE_TOKEN_INT32:
594 case CONDITIONAL_ACE_TOKEN_INT64:
595 consumed = pull_integer(program,
596 tok_data,
597 available,
598 &tok->data.int64);
599 ok = check_integer_range(tok);
600 if (! ok) {
601 goto fail;
603 break;
604 case CONDITIONAL_ACE_TOKEN_UNICODE:
606 * The next four are pulled as unicode, but are
607 * processed as user attribute look-ups.
609 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
610 case CONDITIONAL_ACE_USER_ATTRIBUTE:
611 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
612 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
613 consumed = pull_unicode(program,
614 tok_data,
615 available,
616 &tok->data.unicode);
617 break;
619 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
620 consumed = pull_bytes(program,
621 tok_data,
622 available,
623 &tok->data.bytes);
624 break;
626 case CONDITIONAL_ACE_TOKEN_SID:
627 consumed = pull_sid(program,
628 tok_data,
629 available,
630 &tok->data.sid);
631 break;
633 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
634 consumed = pull_composite(program,
635 tok_data,
636 available,
637 &tok->data.composite);
638 break;
640 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
641 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
642 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
643 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
644 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
645 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
646 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
647 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
649 * these require a SID or composite SID list operand,
650 * and we could check that now in most cases.
652 break;
653 /* binary relational operators */
654 case CONDITIONAL_ACE_TOKEN_EQUAL:
655 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
656 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
657 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
658 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
659 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
660 case CONDITIONAL_ACE_TOKEN_CONTAINS:
661 case CONDITIONAL_ACE_TOKEN_ANY_OF:
662 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
663 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
664 /* unary logical operators */
665 case CONDITIONAL_ACE_TOKEN_EXISTS:
666 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
667 case CONDITIONAL_ACE_TOKEN_NOT:
668 /* binary logical operators */
669 case CONDITIONAL_ACE_TOKEN_AND:
670 case CONDITIONAL_ACE_TOKEN_OR:
671 break;
672 case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
673 /* this is only valid at the end */
674 consumed = pull_end_padding(tok_data,
675 available);
676 j--; /* don't add this token */
677 break;
678 default:
679 goto fail;
682 if (consumed < 0) {
683 goto fail;
685 if (consumed + i < i || consumed + i > data.length) {
686 goto fail;
688 i += consumed;
689 j++;
690 if (j == alloc_length) {
691 alloc_length *= 2;
692 tokens = talloc_realloc(program,
693 tokens,
694 struct ace_condition_token,
695 alloc_length);
696 if (tokens == NULL) {
697 goto fail;
701 program->length = j;
702 program->tokens = talloc_realloc(program,
703 tokens,
704 struct ace_condition_token,
705 program->length + 1);
706 if (program->tokens == NULL) {
707 goto fail;
709 return program;
710 fail:
711 talloc_free(program);
712 return NULL;
716 static bool claim_lookup_internal(
717 TALLOC_CTX *mem_ctx,
718 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
719 struct ace_condition_token *result)
721 bool ok = claim_v1_to_ace_token(mem_ctx, claim, result);
722 return ok;
726 static bool resource_claim_lookup(
727 TALLOC_CTX *mem_ctx,
728 const struct ace_condition_token *op,
729 const struct security_descriptor *sd,
730 struct ace_condition_token *result)
733 * For a @Resource.attr, the claims come from a resource ACE
734 * in the object's SACL. That's why we need a security descriptor.
736 * If there is no matching resource ACE, a NULL result is returned,
737 * which should compare UNKNOWN to anything. The NULL will have the
738 * CONDITIONAL_ACE_FLAG_NULL_MEANS_ERROR flag set if it seems failure
739 * is not simply due to the sought claim not existing. This is useful for
740 * the Exists and Not_Exists operators.
742 size_t i;
743 struct ace_condition_unicode name;
745 result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
747 if (op->type != CONDITIONAL_ACE_RESOURCE_ATTRIBUTE) {
748 /* what are we even doing here? */
749 result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
750 return false;
753 name = op->data.resource_attr;
755 if (sd->sacl == NULL) {
756 DBG_NOTICE("Resource attribute ACE '%s' not found, "
757 "because there is no SACL\n",
758 name.value);
759 return true;
762 for (i = 0; i < sd->sacl->num_aces; i++) {
763 struct security_ace *ace = &sd->sacl->aces[i];
764 bool ok;
766 if (ace->type != SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) {
767 continue;
769 if (strcasecmp_m(name.value,
770 ace->coda.claim.name) != 0) {
771 continue;
773 /* this is the one */
774 ok = claim_lookup_internal(mem_ctx, &ace->coda.claim, result);
775 if (ok) {
776 return true;
779 DBG_NOTICE("Resource attribute ACE '%s' not found.\n",
780 name.value);
781 return false;
785 static bool token_claim_lookup(
786 TALLOC_CTX *mem_ctx,
787 const struct security_token *token,
788 const struct ace_condition_token *op,
789 struct ace_condition_token *result)
792 * The operator has an attribute name; if there is a claim of
793 * the right type with that name, that is returned as the result.
795 * XXX what happens otherwise? NULL result?
797 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
798 size_t num_claims;
799 bool ok;
800 const struct ace_condition_unicode *name = NULL;
801 size_t i;
803 result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
805 switch (op->type) {
806 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
807 claims = token->local_claims;
808 num_claims = token->num_local_claims;
809 name = &op->data.local_attr;
810 break;
811 case CONDITIONAL_ACE_USER_ATTRIBUTE:
812 claims = token->user_claims;
813 num_claims = token->num_user_claims;
814 name = &op->data.user_attr;
815 break;
816 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
817 claims = token->device_claims;
818 num_claims = token->num_device_claims;
819 name = &op->data.device_attr;
820 break;
821 default:
822 DBG_WARNING("Conditional ACE claim lookup got bad arg type %u\n",
823 op->type);
824 result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
825 return false;
828 if (num_claims == 0) {
829 DBG_NOTICE("There are no type %u claims\n", op->type);
830 return false;
832 if (claims == NULL) {
833 DBG_ERR("Type %u claim list unexpectedly NULL!\n", op->type);
834 result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
835 return false;
838 * Loop backwards: a later claim will override an earlier one with the
839 * same name.
841 for (i = num_claims - 1; i < num_claims; i--) {
842 if (claims[i].name == NULL) {
843 DBG_ERR("claim %zu has no name!\n", i);
844 continue;
846 if (strcasecmp_m(claims[i].name, name->value) == 0) {
847 /* this is the one */
848 ok = claim_lookup_internal(mem_ctx, &claims[i], result);
849 return ok;
852 DBG_NOTICE("Claim not found\n");
853 return false;
859 static bool member_lookup(
860 const struct security_token *token,
861 const struct ace_condition_token *op,
862 const struct ace_condition_token *arg,
863 struct ace_condition_token *result)
866 * We need to compare the lists of SIDs in the token with the
867 * SID[s] in the argument. There are 8 combinations of
868 * operation, depending on whether we want to match all or any
869 * of the SIDs, whether we're using the device SIDs or user
870 * SIDs, and whether the operator name starts with "Not_".
872 * _MEMBER_OF User has all operand SIDs
873 * _DEVICE_MEMBER_OF Device has all operand SIDs
874 * _MEMBER_OF_ANY User has one or more operand SIDs
875 * _DEVICE_MEMBER_OF_ANY Device has one or more operand SIDs
877 * NOT_* has the effect of !(the operator without NOT_).
879 * The operand can either be a composite of SIDs or a single SID.
880 * This adds an additional branch.
882 bool match = false;
883 bool it_is_a_not_op;
884 bool it_is_an_any_op;
885 bool it_is_a_device_op;
886 bool arg_is_a_single_sid;
887 struct dom_sid *sid_array = NULL;
888 size_t num_sids, i, j;
889 const struct dom_sid *sid = NULL;
891 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
892 result->data.result.value = ACE_CONDITION_UNKNOWN;
894 switch (arg->type) {
895 case CONDITIONAL_ACE_TOKEN_SID:
896 arg_is_a_single_sid = true;
897 break;
898 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
899 arg_is_a_single_sid = false;
900 break;
901 default:
902 DBG_WARNING("Conditional ACE Member_Of got bad arg type %u\n",
903 arg->type);
904 return false;
907 switch (op->type) {
908 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
909 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
910 it_is_a_not_op = true;
911 it_is_a_device_op = false;
912 break;
913 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
914 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
915 it_is_a_not_op = true;
916 it_is_a_device_op = true;
917 break;
918 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
919 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
920 it_is_a_not_op = false;
921 it_is_a_device_op = false;
922 break;
923 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
924 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
925 it_is_a_not_op = false;
926 it_is_a_device_op = true;
927 break;
928 default:
929 DBG_WARNING("Conditional ACE Member_Of got bad op type %u\n",
930 op->type);
931 return false;
934 switch (op->type) {
935 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
936 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
937 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
938 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
939 it_is_an_any_op = true;
940 break;
941 default:
942 it_is_an_any_op = false;
945 if (it_is_a_device_op) {
946 sid_array = token->device_sids;
947 num_sids = token->num_device_sids;
948 } else {
949 sid_array = token->sids;
950 num_sids = token->num_sids;
953 if (arg_is_a_single_sid) {
955 * In this case the any and all operations are the
956 * same.
958 sid = &arg->data.sid.sid;
959 match = false;
960 for (i = 0; i < num_sids; i++) {
961 match = dom_sid_equal(sid, &sid_array[i]);
962 if (match) {
963 break;
966 if (it_is_a_not_op) {
967 match = ! match;
969 if (match) {
970 result->data.result.value = ACE_CONDITION_TRUE;
971 } else {
972 result->data.result.value = ACE_CONDITION_FALSE;
974 return true;
977 /* This is a composite list (hopefully of SIDs) */
978 if (arg->data.composite.n_members == 0) {
979 DBG_WARNING("Conditional ACE Member_Of argument is empty\n");
980 return false;
983 for (j = 0; j < arg->data.composite.n_members; j++) {
984 const struct ace_condition_token *member =
985 &arg->data.composite.tokens[j];
986 if (member->type != CONDITIONAL_ACE_TOKEN_SID) {
987 DBG_WARNING("Conditional ACE Member_Of argument contains "
988 "non-sid element [%zu]: %u\n",
989 j, member->type);
990 return false;
992 sid = &member->data.sid.sid;
993 match = false;
994 for (i = 0; i < num_sids; i++) {
995 match = dom_sid_equal(sid, &sid_array[i]);
996 if (match) {
997 break;
1000 if (it_is_an_any_op) {
1001 if (match) {
1002 /* we have matched one SID, which is enough */
1003 goto apply_not;
1005 } else { /* an all op */
1006 if (! match) {
1007 /* failing one is enough */
1008 goto apply_not;
1013 * Reaching the end of that loop means either:
1014 * 1. it was an ALL op and we never failed to find one, or
1015 * 2. it was an ANY op, and we didn't find one.
1017 match = !it_is_an_any_op;
1019 apply_not:
1020 if (it_is_a_not_op) {
1021 match = ! match;
1023 if (match) {
1024 result->data.result.value = ACE_CONDITION_TRUE;
1025 } else {
1026 result->data.result.value = ACE_CONDITION_FALSE;
1029 return true;
1033 static bool ternary_value(
1034 const struct ace_condition_token *arg,
1035 struct ace_condition_token *result)
1038 * Find the truth value of the argument, stored in the result token.
1040 * A return value of false means the operation is invalid, and the
1041 * result is undefined.
1043 if (arg->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
1044 /* pass through */
1045 *result = *arg;
1046 return true;
1049 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
1050 result->data.result.value = ACE_CONDITION_UNKNOWN;
1052 if (IS_INT_TOKEN(arg)) {
1053 /* zero is false */
1054 if (arg->data.int64.value == 0) {
1055 result->data.result.value = ACE_CONDITION_FALSE;
1056 } else {
1057 result->data.result.value = ACE_CONDITION_TRUE;
1059 return true;
1061 if (arg->type == CONDITIONAL_ACE_TOKEN_UNICODE) {
1062 /* empty is false */
1063 if (arg->data.unicode.value[0] == '\0') {
1064 result->data.result.value = ACE_CONDITION_FALSE;
1065 } else {
1066 result->data.result.value = ACE_CONDITION_TRUE;
1068 return true;
1072 * everything else in UNKNOWN. This includes NULL values (i.e. an
1073 * unsuccessful look-up).
1075 result->data.result.value = ACE_CONDITION_UNKNOWN;
1076 return true;
1079 static bool not_operator(
1080 const struct ace_condition_token *arg,
1081 struct ace_condition_token *result)
1083 bool ok;
1084 if (IS_LITERAL_TOKEN(arg)) {
1086 * Logic operators don't work on literals.
1088 return false;
1091 ok = ternary_value(arg, result);
1092 if (! ok) {
1093 return false;
1095 if (result->data.result.value == ACE_CONDITION_FALSE) {
1096 result->data.result.value = ACE_CONDITION_TRUE;
1097 } else if (result->data.result.value == ACE_CONDITION_TRUE) {
1098 result->data.result.value = ACE_CONDITION_FALSE;
1100 /* unknown stays unknown */
1101 return true;
1105 static bool unary_logic_operator(
1106 TALLOC_CTX *mem_ctx,
1107 const struct security_token *token,
1108 const struct ace_condition_token *op,
1109 const struct ace_condition_token *arg,
1110 const struct security_descriptor *sd,
1111 struct ace_condition_token *result)
1114 bool ok;
1115 bool found;
1116 struct ace_condition_token claim = {
1117 .type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR
1119 if (op->type == CONDITIONAL_ACE_TOKEN_NOT) {
1120 return not_operator(arg, result);
1122 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
1123 result->data.result.value = ACE_CONDITION_UNKNOWN;
1126 * Not_Exists and Exists require the same work, except we negate the
1127 * answer in one case. From [MS-DTYP] 2.4.4.17.7:
1129 * If the type of the operand is "Local Attribute"
1130 * If the value is non-null return TRUE
1131 * Else return FALSE
1132 * Else if the type of the operand is "Resource Attribute"
1133 * Return TRUE if value is non-null; FALSE otherwise.
1134 * Else return Error
1136 switch (op->type) {
1137 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
1138 ok = token_claim_lookup(mem_ctx, token, arg, &claim);
1140 * "not ok" usually means a failure to find the attribute,
1141 * which is the false condition and not an error.
1143 * XXX or do we need an extra flag?
1145 break;
1146 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
1147 ok = resource_claim_lookup(mem_ctx, arg, sd, &claim);
1148 break;
1149 default:
1150 return false;
1157 if (claim.type != CONDITIONAL_ACE_SAMBA_RESULT_NULL) {
1158 found = true;
1159 } else if (ok) {
1160 found = false;
1161 } else {
1162 return false;
1167 if (op->type == CONDITIONAL_ACE_TOKEN_NOT_EXISTS) {
1168 found = ! found;
1169 } else if (op->type != CONDITIONAL_ACE_TOKEN_EXISTS) {
1170 /* should not get here */
1171 return false;
1174 result->data.result.value = found ? ACE_CONDITION_TRUE: ACE_CONDITION_FALSE;
1175 return true;
1180 static bool binary_logic_operator(
1181 const struct security_token *token,
1182 const struct ace_condition_token *op,
1183 const struct ace_condition_token *lhs,
1184 const struct ace_condition_token *rhs,
1185 struct ace_condition_token *result)
1187 struct ace_condition_token at, bt;
1188 int a, b;
1189 bool ok;
1191 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
1192 result->data.result.value = ACE_CONDITION_UNKNOWN;
1194 if (IS_LITERAL_TOKEN(lhs) || IS_LITERAL_TOKEN(rhs)) {
1196 * Logic operators don't work on literals.
1198 return false;
1201 ok = ternary_value(lhs, &at);
1202 if (! ok) {
1203 return false;
1205 ok = ternary_value(rhs, &bt);
1206 if (! ok) {
1207 return false;
1209 a = at.data.result.value;
1210 b = bt.data.result.value;
1212 if (op->type == CONDITIONAL_ACE_TOKEN_AND) {
1214 * AND true false unknown
1215 * true T F ?
1216 * false F F F
1217 * unknown ? F ?
1219 * unknown unless BOTH true or EITHER false
1221 if (a == ACE_CONDITION_TRUE &&
1222 b == ACE_CONDITION_TRUE) {
1223 result->data.result.value = ACE_CONDITION_TRUE;
1224 return true;
1226 if (a == ACE_CONDITION_FALSE ||
1227 b == ACE_CONDITION_FALSE) {
1228 result->data.result.value = ACE_CONDITION_FALSE;
1229 return true;
1232 * Neither value is False, so the result is Unknown,
1233 * as set at the start of this function.
1235 return true;
1238 * OR true false unknown
1239 * true T T T
1240 * false T F ?
1241 * unknown T ? ?
1243 * unknown unless EITHER true or BOTH false
1245 if (a == ACE_CONDITION_TRUE ||
1246 b == ACE_CONDITION_TRUE) {
1247 result->data.result.value = ACE_CONDITION_TRUE;
1248 return true;
1250 if (a == ACE_CONDITION_FALSE &&
1251 b == ACE_CONDITION_FALSE) {
1252 result->data.result.value = ACE_CONDITION_FALSE;
1253 return true;
1255 return true;
1259 static bool tokens_are_comparable(const struct ace_condition_token *op,
1260 const struct ace_condition_token *lhs,
1261 const struct ace_condition_token *rhs)
1263 uint64_t n;
1265 * we can't compare different types *unless* they are both
1266 * integers, or one is a bool and the other is an integer 0 or
1267 * 1, and the operator is == or != (or NULL, which for convenience,
1268 * is treated as ==).
1270 //XXX actually it says "literal integers", do we need to check flags?
1271 if (lhs->type == rhs->type) {
1272 return true;
1275 if (IS_INT_TOKEN(lhs) && IS_INT_TOKEN(rhs)) {
1276 /* don't block e.g. comparing an int32 to an int64 */
1277 return true;
1280 /* is it == or != */
1281 if (op != NULL &&
1282 op->type != CONDITIONAL_ACE_TOKEN_EQUAL &&
1283 op->type != CONDITIONAL_ACE_TOKEN_NOT_EQUAL) {
1284 return false;
1286 /* is one a bool and the other an int? */
1287 if (IS_INT_TOKEN(lhs) && IS_BOOL_TOKEN(rhs)) {
1288 n = lhs->data.int64.value;
1289 } else if (IS_INT_TOKEN(rhs) && IS_BOOL_TOKEN(lhs)) {
1290 n = rhs->data.int64.value;
1291 } else {
1292 return false;
1294 if (n == 0 || n == 1) {
1295 return true;
1297 return false;
1301 static bool cmp_to_result(const struct ace_condition_token *op,
1302 struct ace_condition_token *result,
1303 int cmp)
1305 bool answer;
1306 switch (op->type) {
1307 case CONDITIONAL_ACE_TOKEN_EQUAL:
1308 answer = cmp == 0;
1309 break;
1310 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
1311 answer = cmp != 0;
1312 break;
1313 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
1314 answer = cmp < 0;
1315 break;
1316 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
1317 answer = cmp <= 0;
1318 break;
1319 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
1320 answer = cmp > 0;
1321 break;
1322 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
1323 answer = cmp >= 0;
1324 break;
1325 default:
1326 result->data.result.value = ACE_CONDITION_UNKNOWN;
1327 return false;
1329 result->data.result.value = \
1330 answer ? ACE_CONDITION_TRUE : ACE_CONDITION_FALSE;
1331 return true;
1336 static bool compare_unicode(const struct ace_condition_token *op,
1337 const struct ace_condition_token *lhs,
1338 const struct ace_condition_token *rhs,
1339 int *cmp)
1341 struct ace_condition_unicode a = lhs->data.unicode;
1342 struct ace_condition_unicode b = rhs->data.unicode;
1344 * Comparison is case-insensitive UNLESS the claim structure
1345 * has the case-sensitive flag, which is passed through as a
1346 * flag on the token. Usually only the LHS is a claim value,
1347 * but in the event that they both are, we allow either to
1348 * request case-sensitivity.
1350 * For greater than and less than, the sort order is utf-8 order,
1351 * which is not exactly what Windows does, but we don't sort like
1352 * Windows does anywhere else either.
1354 uint8_t flags = lhs->flags | rhs->flags;
1355 if (flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE) {
1356 *cmp = strcmp(a.value, b.value);
1357 } else {
1358 *cmp = strcasecmp_m(a.value, b.value);
1360 return true;
1364 static bool compare_bytes(const struct ace_condition_token *op,
1365 const struct ace_condition_token *lhs,
1366 const struct ace_condition_token *rhs,
1367 int *cmp)
1369 DATA_BLOB a = lhs->data.bytes;
1370 DATA_BLOB b = rhs->data.bytes;
1371 *cmp = data_blob_cmp(&a, &b);
1372 return true;
1376 static bool compare_sids(const struct ace_condition_token *op,
1377 const struct ace_condition_token *lhs,
1378 const struct ace_condition_token *rhs,
1379 int *cmp)
1381 *cmp = dom_sid_compare(&lhs->data.sid.sid,
1382 &rhs->data.sid.sid);
1383 return true;
1387 static bool compare_ints(const struct ace_condition_token *op,
1388 const struct ace_condition_token *lhs,
1389 const struct ace_condition_token *rhs,
1390 int *cmp)
1392 int64_t a = lhs->data.int64.value;
1393 int64_t b = rhs->data.int64.value;
1395 if (a < b) {
1396 *cmp = -1;
1397 } else if (a == b) {
1398 *cmp = 0;
1399 } else {
1400 *cmp = 1;
1402 return true;
1406 static bool compare_bools(const struct ace_condition_token *op,
1407 const struct ace_condition_token *lhs,
1408 const struct ace_condition_token *rhs,
1409 int *cmp)
1411 bool ok;
1412 struct ace_condition_token a, b;
1413 *cmp = -1;
1415 if (IS_LITERAL_TOKEN(lhs)) {
1417 * we can compare a boolean LHS to a literal RHS, but not
1418 * vice versa
1420 return false;
1422 ok = ternary_value(lhs, &a);
1423 if (! ok) {
1424 return false;
1426 ok = ternary_value(rhs, &b);
1427 if (! ok) {
1428 return false;
1430 if (a.data.result.value == ACE_CONDITION_UNKNOWN ||
1431 b.data.result.value == ACE_CONDITION_UNKNOWN) {
1432 return false;
1435 switch (op->type) {
1436 case CONDITIONAL_ACE_TOKEN_EQUAL:
1437 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
1438 *cmp = a.data.result.value - b.data.result.value;
1439 break;
1440 default:
1441 /* we are not allowing non-equality comparisons with bools */
1442 return false;
1444 return true;
1448 static bool simple_relational_operator(const struct ace_condition_token *op,
1449 const struct ace_condition_token *lhs,
1450 const struct ace_condition_token *rhs,
1451 int *cmp);
1454 struct composite_sort_context {
1455 bool failed;
1458 static int composite_sort_cmp(const struct ace_condition_token *lhs,
1459 const struct ace_condition_token *rhs,
1460 struct composite_sort_context *ctx)
1462 bool ok;
1463 int cmp = -1;
1465 * simple_relational_operator uses the operator token only to
1466 * decide whether the comparison is allowed for the type. In
1467 * particular, boolean result and composite arguments can only
1468 * be used with equality operators. We want those to fail (we
1469 * should not see them here, remembering that claim booleans
1470 * become composite integers), so we use a non-equality op.
1472 static const struct ace_condition_token op = {
1473 .type = CONDITIONAL_ACE_TOKEN_LESS_THAN
1476 ok = simple_relational_operator(&op, lhs, rhs, &cmp);
1477 if (ok) {
1478 return cmp;
1481 * This sort isn't going to work out, but the sort function
1482 * will only find out at the end.
1484 ctx->failed = true;
1485 return cmp;
1490 * Return a sorted copy of the composite tokens array.
1492 * The copy is shallow, so the actual string pointers are the same, which is
1493 * fine for the purposes of comparison.
1496 static struct ace_condition_token *composite_sorted_copy(
1497 TALLOC_CTX *mem_ctx,
1498 const struct ace_condition_composite *c,
1499 bool case_sensitive)
1501 struct ace_condition_token *copy = NULL;
1502 bool ok;
1503 size_t i;
1504 struct composite_sort_context sort_ctx = {
1505 .failed = false
1509 * Case sensitivity is a bit tricky. Each token can have a flag saying
1510 * it should be sorted case-sensitively and when comparing two tokens,
1511 * we should respect this flag on either side. The flag can only come
1512 * from claims (including resource attribute ACEs), and as there is only
1513 * one flag per claim, it must apply the same to all members (in fact we
1514 * don't set it on the members, only the composite). So to be sure we
1515 * sort in the way we want, we might need to set the flag on all the
1516 * members of the copy *before* sorting it.
1518 * When it comes to comparing two composites, we want to be
1519 * case-sensitive if either side has the flag. This can have odd
1520 * effects. Think of these RA claims:
1522 * (RA;;;;;WD;("foo",TS,0,"a","A"))
1523 * (RA;;;;;WD;("bar",TS,2,"a","A")) <-- 2 is the case-sensitive flag
1524 * (RA;;;;;WD;("baz",TS,0,"a"))
1526 * (@Resource.foo == @Resource.bar) is true
1527 * (@Resource.bar == @Resource.foo) is true
1528 * (@Resource.bar == @Resource.bar) is true
1529 * (@Resource.foo == @Resource.foo) is an error (duplicate values on LHS)
1530 * (@Resource.baz == @Resource.foo) is true (RHS case-folds down)
1531 * (@Resource.baz == @Resource.bar) is false
1532 * (@Resource.bar == {"A", "a"}) is true
1533 * (@Resource.baz == {"A", "a"}) is true
1534 * (@Resource.foo == {"A", "a"}) is an error
1536 copy = talloc_array(mem_ctx, struct ace_condition_token, c->n_members);
1537 if (copy == NULL) {
1538 return NULL;
1540 memcpy(copy, c->tokens, sizeof(struct ace_condition_token) * c->n_members);
1542 if (case_sensitive) {
1543 for (i = 0; i < c->n_members; i++) {
1544 c->tokens[i].flags |= CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
1548 ok = stable_sort_talloc_r(mem_ctx,
1549 copy,
1550 c->n_members,
1551 sizeof(struct ace_condition_token),
1552 (samba_compare_with_context_fn_t)composite_sort_cmp,
1553 &sort_ctx);
1555 if (!ok || sort_ctx.failed) {
1556 DBG_NOTICE("composite sort of %"PRIu32" members failed\n",
1557 c->n_members);
1558 TALLOC_FREE(copy);
1559 return NULL;
1561 return copy;
1566 * This is a helper for compare composites.
1568 static bool compare_composites_via_sort(const struct ace_condition_token *lhs,
1569 const struct ace_condition_token *rhs,
1570 int *cmp)
1572 const struct ace_condition_composite *lc = &lhs->data.composite;
1573 const struct ace_condition_composite *rc = &rhs->data.composite;
1574 size_t i;
1575 TALLOC_CTX *tmp_ctx = NULL;
1576 bool ok;
1577 int cmp_pair;
1578 bool case_sensitive, rhs_case_sensitive;
1579 bool rhs_sorted;
1580 struct ace_condition_token *ltok = lc->tokens;
1581 struct ace_condition_token *rtok = rc->tokens;
1582 static const struct ace_condition_token eq = {
1583 .type = CONDITIONAL_ACE_TOKEN_EQUAL
1585 *cmp = -1;
1586 if (lc->n_members == 0 ||
1587 rc->n_members < lc->n_members) {
1588 /* we should not have got this far */
1589 return false;
1592 tmp_ctx = talloc_new(NULL);
1593 if (tmp_ctx == NULL) {
1594 return false;
1597 case_sensitive = lhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
1598 rhs_case_sensitive = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
1599 rhs_sorted = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
1601 if (lc->tokens[0].type != CONDITIONAL_ACE_TOKEN_UNICODE) {
1603 * All LHS tokens are the same type (because it is a
1604 * claim), and that type is not one that cares about
1605 * case, so nor do we.
1607 case_sensitive = false;
1608 } else if (case_sensitive == rhs_case_sensitive) {
1609 /* phew, no extra work */
1610 } else if (case_sensitive) {
1611 /* trigger a sorted copy */
1612 rhs_sorted = false;
1613 } else if (rhs_case_sensitive) {
1615 * Do we need to rescan for uniqueness, given the new
1616 * comparison function? No! The strings were already
1617 * unique in the looser comparison, and now they can
1618 * only be more so. The number of unique values can't
1619 * change, just their order.
1621 case_sensitive = true;
1622 ltok = composite_sorted_copy(tmp_ctx, lc, case_sensitive);
1623 if (ltok == NULL) {
1624 DBG_WARNING("sort of LHS failed\n");
1625 goto error;
1629 if (! rhs_sorted) {
1631 * we need an RHS sorted copy (it's a literal, or
1632 * there was a case sensitivity disagreement).
1634 rtok = composite_sorted_copy(tmp_ctx, rc, case_sensitive);
1635 if (rtok == NULL) {
1636 DBG_WARNING("sort of RHS failed\n");
1637 goto error;
1641 * Each member of LHS must match one or more members of RHS.
1642 * Each member of RHS must match at least one of LHS.
1644 * If they are the same length we can compare directly, so let's get
1645 * rid of duplicates in RHS. This can only happen with literal
1646 * composites.
1648 if (rc->n_members > lc->n_members) {
1649 size_t gap = 0;
1650 for (i = 1; i < rc->n_members; i++) {
1651 ok = simple_relational_operator(&eq,
1652 &rtok[i - 1],
1653 &rtok[i],
1654 &cmp_pair);
1655 if (! ok) {
1656 goto error;
1658 if (cmp_pair == 0) {
1659 gap++;
1661 if (gap != 0) {
1662 rtok[i - gap] = rtok[i];
1665 if (rc->n_members - lc->n_members != gap) {
1667 * There were too many or too few duplicates to account
1668 * for the difference, and no further comparison is
1669 * necessary.
1671 goto not_equal;
1675 * OK, now we know LHS and RHS are the same length and sorted in the
1676 * same way, so we can just iterate over them and check each pair.
1679 for (i = 0; i < lc->n_members; i++) {
1680 ok = simple_relational_operator(&eq,
1681 &ltok[i],
1682 &rtok[i],
1683 &cmp_pair);
1684 if (! ok){
1685 goto error;
1687 if (cmp_pair != 0) {
1688 goto not_equal;
1692 *cmp = 0;
1694 not_equal:
1695 TALLOC_FREE(tmp_ctx);
1696 return true;
1697 error:
1698 TALLOC_FREE(tmp_ctx);
1699 return false;
1703 static bool composite_is_comparable(const struct ace_condition_token *tok,
1704 const struct ace_condition_token *comp)
1707 * Are all members of the composite comparable to the token?
1709 size_t i;
1710 const struct ace_condition_composite *rc = &comp->data.composite;
1711 size_t n = rc->n_members;
1713 if ((comp->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED) &&
1714 n > 1) {
1716 * all members are known to be the same type, so we
1717 * can just check one.
1719 n = 1;
1722 for (i = 0; i < n; i++) {
1723 if (! tokens_are_comparable(NULL,
1724 tok,
1725 &rc->tokens[i])) {
1726 DBG_NOTICE("token type %u != composite type %u\n",
1727 tok->type, rc->tokens[i].type);
1728 return false;
1731 return true;
1735 static bool compare_composites(const struct ace_condition_token *op,
1736 const struct ace_condition_token *lhs,
1737 const struct ace_condition_token *rhs,
1738 int *cmp)
1741 * This is for comparing multivalued sets, which includes
1742 * conditional ACE composites and claim sets. Because these
1743 * are sets, there are no < and > operations, just equality or
1744 * otherwise.
1746 * Claims are true sets, while composites are multisets --
1747 * duplicate values are allowed -- but these are reduced to
1748 * sets in evaluation, and the number of duplicates has no
1749 * effect in comparisons. Resource attribute ACEs live in an
1750 * intermediate state -- they can contain duplicates on the
1751 * wire and as ACE structures, but as soon as they are
1752 * evaluated as claims their values must be unique. Windows
1753 * will treat RA ACEs with duplicate values as not existing,
1754 * rather than as UNKNOWN (This is significant for the Exists
1755 * operator). Claims can have a case-sensitive flags set,
1756 * meaning they must be compared case-sensitively.
1758 * Some good news is that the LHS of a comparison must always
1759 * be a claim. That means we can assume it has unique values
1760 * when it comes to pairwise comparisons. Using the magic of
1761 * flags, we try to check this only once per claim.
1763 * Conditional ACE composites, which can have duplicates (and
1764 * mixed types), can only be on the RHS.
1766 * To summarise:
1768 * {a, b} vs {a, b} equal
1769 * { } vs { } equal
1770 * {a, b} vs {b, a} equal
1771 * {a, b} vs {a, c} not equal
1772 * {a, b} vs {a, a, b} equal
1773 * {b, a} vs {a, b, a} equal
1774 * {a, b} vs {a, a, b, c} not equal
1775 * {a, b, a} vs {a, b} should not happen, error
1776 * {a, b, a} vs {a, b, a} should not happen, error
1778 * mixed types:
1779 * {1, 2} vs {1, "2"} error
1780 * {1, "2"} vs {1, "2"} should not happen, error
1782 * case sensitivity (*{ }* indicates case-sensitive flag):
1784 * {"a", "b"} vs {"a", "B"} equal
1785 * {"a", "b"} vs *{"a", "B"}* not equal
1786 * *{"a", "b"}* vs {"a", "B"} not equal
1787 * *{"a", "A"}* vs {"a", "A"} equal (if RHS is composite)
1788 * {"a", "A"} vs *{"a", "A"}* impossible (LHS is not unique)
1789 * *{"a"}* vs {"a", "A"} not equal
1791 * The naive approach is of course O(n * m) with an additional O(n²)
1792 * if the LHS values are not known to be unique (that is, in resource
1793 * attribute claims). We want to avoid that with big sets.
1795 const struct ace_condition_composite *lc = &lhs->data.composite;
1796 const struct ace_condition_composite *rc = &rhs->data.composite;
1797 bool ok;
1799 if (!(lhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) {
1801 * The LHS needs to be a claim, and it should have gone
1802 * through claim_v1_check_and_sort() to get here.
1804 *cmp = -1;
1805 return false;
1808 /* if one or both are empty, the answer is easy */
1809 if (lc->n_members == 0) {
1810 if (rc->n_members == 0) {
1811 *cmp = 0;
1812 return true;
1814 *cmp = -1;
1815 return true;
1817 if (rc->n_members == 0) {
1818 *cmp = -1;
1819 return true;
1823 * LHS must be a claim, so it must be unique, so if there are
1824 * fewer members on the RHS, we know they can't be equal.
1826 * If you think about it too much, you might think this is
1827 * affected by case sensitivity, but it isn't. One side can be
1828 * infected by case-sensitivity by the other, but that can't
1829 * shrink the number of elements on the RHS -- it can only
1830 * make a literal {"a", "A"} have effective length 2 rather
1831 * than 1.
1833 * On the other hand, if the RHS is case sensitive, it must be
1834 * a claim and unique in its own terms, and its finer-grained
1835 * distinctions can't collapse members of the case sensitive
1836 * LHS.
1838 if (lc->n_members > rc->n_members) {
1839 *cmp = -1;
1840 return composite_is_comparable(&lc->tokens[0], rhs);
1844 * It *could* be that RHS is also unique and we know it. In that
1845 * case we can short circuit if RHS has more members. This is
1846 * the case when both sides are claims.
1848 * This is also not affected by case-senstivity.
1850 if (lc->n_members < rc->n_members &&
1851 (rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) {
1852 *cmp = -1;
1853 return composite_is_comparable(&lc->tokens[0], rhs);
1856 ok = compare_composites_via_sort(lhs, rhs, cmp);
1857 if (! ok) {
1858 return false;
1860 return true;
1864 static bool simple_relational_operator(const struct ace_condition_token *op,
1865 const struct ace_condition_token *lhs,
1866 const struct ace_condition_token *rhs,
1867 int *cmp)
1870 if (lhs->type != rhs->type) {
1871 if (! tokens_are_comparable(op, lhs, rhs)) {
1872 return false;
1875 switch (lhs->type) {
1876 case CONDITIONAL_ACE_TOKEN_INT8:
1877 case CONDITIONAL_ACE_TOKEN_INT16:
1878 case CONDITIONAL_ACE_TOKEN_INT32:
1879 case CONDITIONAL_ACE_TOKEN_INT64:
1880 if (rhs->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
1881 return compare_bools(op, lhs, rhs, cmp);
1883 return compare_ints(op, lhs, rhs, cmp);
1884 case CONDITIONAL_ACE_SAMBA_RESULT_BOOL:
1885 return compare_bools(op, lhs, rhs, cmp);
1886 case CONDITIONAL_ACE_TOKEN_UNICODE:
1887 return compare_unicode(op, lhs, rhs, cmp);
1888 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
1889 return compare_bytes(op, lhs, rhs, cmp);
1890 case CONDITIONAL_ACE_TOKEN_SID:
1891 return compare_sids(op, lhs, rhs, cmp);
1892 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
1893 return compare_composites(op, lhs, rhs, cmp);
1894 case CONDITIONAL_ACE_SAMBA_RESULT_NULL:
1895 /* leave the result unknown */
1896 return false;
1897 default:
1898 DBG_ERR("did not expect ace type %u\n", lhs->type);
1899 return false;
1902 return false;
1906 static bool find_in_composite(const struct ace_condition_token *tok,
1907 struct ace_condition_composite candidates,
1908 bool *answer)
1910 size_t i;
1911 int cmp;
1912 bool ok;
1913 const struct ace_condition_token equals = {
1914 .type = CONDITIONAL_ACE_TOKEN_EQUAL
1917 *answer = false;
1919 for (i = 0; i < candidates.n_members; i++) {
1920 ok = simple_relational_operator(&equals,
1921 tok,
1922 &candidates.tokens[i],
1923 &cmp);
1924 if (! ok) {
1925 return false;
1927 if (cmp == 0) {
1928 *answer = true;
1929 return true;
1932 return true;
1936 static bool contains_operator(const struct ace_condition_token *lhs,
1937 const struct ace_condition_token *rhs,
1938 bool *answer)
1940 size_t i;
1941 bool ok;
1942 int cmp;
1943 const struct ace_condition_token equals = {
1944 .type = CONDITIONAL_ACE_TOKEN_EQUAL
1948 * All the required objects must be identical to something in
1949 * candidates. But what do we mean by *identical*? We'll use
1950 * the equality operator to decide that.
1952 * Both the lhs or rhs can be solitary objects or composites.
1953 * This makes it a bit fiddlier.
1955 * NOTE: this operator does not take advantage of the
1956 * CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED flag. It could, but it
1957 * doesn't.
1959 if (lhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1960 struct ace_condition_composite candidates = lhs->data.composite;
1961 struct ace_condition_composite required;
1962 if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1963 return find_in_composite(rhs, candidates, answer);
1965 required = rhs->data.composite;
1966 if (required.n_members == 0) {
1967 return false;
1969 for (i = 0; i < required.n_members; i++) {
1970 const struct ace_condition_token *t = &required.tokens[i];
1971 ok = find_in_composite(t, candidates, answer);
1972 if (! ok) {
1973 return false;
1975 if (! *answer) {
1977 * one required item was not there,
1978 * *answer is false
1980 return true;
1983 /* all required items are there, *answer will be true */
1984 return true;
1986 /* LHS is a single item */
1987 if (rhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
1989 * There could be more than one RHS member that is
1990 * equal to the single LHS value, so it doesn't help
1991 * to compare lengths or anything.
1993 struct ace_condition_composite required = rhs->data.composite;
1994 if (required.n_members == 0) {
1995 return false;
1997 for (i = 0; i < required.n_members; i++) {
1998 ok = simple_relational_operator(&equals,
1999 lhs,
2000 &required.tokens[i],
2001 &cmp);
2002 if (! ok) {
2003 return false;
2005 if (cmp != 0) {
2007 * one required item was not there,
2008 * *answer is false
2010 *answer = false;
2011 return true;
2014 *answer = true;
2015 return true;
2017 /* LHS and RHS are both single */
2018 ok = simple_relational_operator(&equals,
2019 lhs,
2020 rhs,
2021 &cmp);
2022 if (! ok) {
2023 return false;
2025 *answer = (cmp == 0);
2026 return true;
2030 static bool any_of_operator(const struct ace_condition_token *lhs,
2031 const struct ace_condition_token *rhs,
2032 bool *answer)
2034 size_t i;
2035 bool ok;
2036 int cmp;
2037 const struct ace_condition_token equals = {
2038 .type = CONDITIONAL_ACE_TOKEN_EQUAL
2042 * There has to be *some* overlap between the LHS and RHS.
2043 * Both sides can be solitary objects or composites.
2045 * We can exploit this symmetry.
2047 if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
2048 const struct ace_condition_token *tmp = lhs;
2049 lhs = rhs;
2050 rhs = tmp;
2052 if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
2053 /* both singles */
2054 ok = simple_relational_operator(&equals,
2055 lhs,
2056 rhs,
2057 &cmp);
2058 if (! ok) {
2059 return false;
2061 *answer = (cmp == 0);
2062 return true;
2064 if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
2065 return find_in_composite(rhs, lhs->data.composite, answer);
2067 /* both are composites */
2068 if (lhs->data.composite.n_members == 0) {
2069 return false;
2071 for (i = 0; i < lhs->data.composite.n_members; i++) {
2072 ok = find_in_composite(&lhs->data.composite.tokens[i],
2073 rhs->data.composite,
2074 answer);
2075 if (! ok) {
2076 return false;
2078 if (*answer) {
2079 /* We have found one match, which is enough. */
2080 return true;
2083 return true;
2087 static bool composite_relational_operator(const struct ace_condition_token *op,
2088 const struct ace_condition_token *lhs,
2089 const struct ace_condition_token *rhs,
2090 struct ace_condition_token *result)
2092 bool ok, answer;
2093 switch(op->type) {
2094 case CONDITIONAL_ACE_TOKEN_CONTAINS:
2095 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
2096 ok = contains_operator(lhs, rhs, &answer);
2097 break;
2098 case CONDITIONAL_ACE_TOKEN_ANY_OF:
2099 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
2100 ok = any_of_operator(lhs, rhs, &answer);
2101 break;
2102 default:
2103 return false;
2105 if (!ok) {
2106 return false;
2109 /* negate the NOTs */
2110 if (op->type == CONDITIONAL_ACE_TOKEN_NOT_CONTAINS ||
2111 op->type == CONDITIONAL_ACE_TOKEN_NOT_ANY_OF)
2113 answer = !answer;
2116 if (answer) {
2117 result->data.result.value = ACE_CONDITION_TRUE;
2118 } else {
2119 result->data.result.value = ACE_CONDITION_FALSE;
2121 return true;
2125 static bool relational_operator(
2126 const struct security_token *token,
2127 const struct ace_condition_token *op,
2128 const struct ace_condition_token *lhs,
2129 const struct ace_condition_token *rhs,
2130 struct ace_condition_token *result)
2132 int cmp;
2133 bool ok;
2134 result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
2135 result->data.result.value = ACE_CONDITION_UNKNOWN;
2137 if ((lhs->flags & CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR) == 0) {
2138 /* LHS was not derived from an attribute */
2139 return false;
2143 * This first nested switch is ensuring that >, >=, <, <= are
2144 * not being tried on tokens that are not numbers, strings, or
2145 * octet strings. Equality operators are available for all types.
2147 switch (lhs->type) {
2148 case CONDITIONAL_ACE_TOKEN_INT8:
2149 case CONDITIONAL_ACE_TOKEN_INT16:
2150 case CONDITIONAL_ACE_TOKEN_INT32:
2151 case CONDITIONAL_ACE_TOKEN_INT64:
2152 case CONDITIONAL_ACE_TOKEN_UNICODE:
2153 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
2154 break;
2155 default:
2156 switch(op->type) {
2157 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
2158 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
2159 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
2160 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
2161 return false;
2162 default:
2163 break;
2168 * Dispatch according to operator type.
2170 switch (op->type) {
2171 case CONDITIONAL_ACE_TOKEN_EQUAL:
2172 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
2173 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
2174 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
2175 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
2176 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
2177 ok = simple_relational_operator(op,
2178 lhs,
2179 rhs,
2180 &cmp);
2181 if (ok) {
2182 ok = cmp_to_result(op, result, cmp);
2184 return ok;
2186 case CONDITIONAL_ACE_TOKEN_CONTAINS:
2187 case CONDITIONAL_ACE_TOKEN_ANY_OF:
2188 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
2189 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
2190 return composite_relational_operator(op,
2191 lhs,
2192 rhs,
2193 result);
2194 default:
2195 return false;
2200 int run_conditional_ace(TALLOC_CTX *mem_ctx,
2201 const struct security_token *token,
2202 struct ace_condition_script *program,
2203 const struct security_descriptor *sd)
2205 size_t i;
2206 size_t depth = 0;
2207 struct ace_condition_token *lhs = NULL;
2208 struct ace_condition_token *rhs = NULL;
2209 struct ace_condition_token result = {};
2210 struct ace_condition_token *stack = NULL;
2211 bool ok;
2214 * When interpreting the program we will need a stack, which in the
2215 * very worst case can be as deep as the program is long.
2217 stack = talloc_array(mem_ctx,
2218 struct ace_condition_token,
2219 program->length + 1);
2220 if (stack == NULL) {
2221 goto error;
2224 for (i = 0; i < program->length; i++) {
2225 struct ace_condition_token *tok = &program->tokens[i];
2226 switch (tok->type) {
2227 case CONDITIONAL_ACE_TOKEN_INT8:
2228 case CONDITIONAL_ACE_TOKEN_INT16:
2229 case CONDITIONAL_ACE_TOKEN_INT32:
2230 case CONDITIONAL_ACE_TOKEN_INT64:
2231 case CONDITIONAL_ACE_TOKEN_UNICODE:
2232 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
2233 case CONDITIONAL_ACE_TOKEN_SID:
2234 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
2235 /* just plonk these literals on the stack */
2236 stack[depth] = *tok;
2237 depth++;
2238 break;
2240 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
2241 case CONDITIONAL_ACE_USER_ATTRIBUTE:
2242 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
2243 ok = token_claim_lookup(mem_ctx, token, tok, &result);
2244 if (! ok) {
2245 goto error;
2247 stack[depth] = result;
2248 depth++;
2249 break;
2251 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
2252 ok = resource_claim_lookup(mem_ctx,
2253 tok,
2255 &result);
2256 if (! ok) {
2257 goto error;
2259 stack[depth] = result;
2260 depth++;
2261 break;
2263 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
2264 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
2265 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
2266 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
2267 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
2268 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
2269 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
2270 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
2271 if (depth == 0) {
2272 goto error;
2274 depth--;
2275 lhs = &stack[depth];
2276 ok = member_lookup(token, tok, lhs, &result);
2277 if (! ok) {
2278 goto error;
2280 stack[depth] = result;
2281 depth++;
2282 break;
2283 /* binary relational operators */
2284 case CONDITIONAL_ACE_TOKEN_EQUAL:
2285 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
2286 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
2287 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
2288 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
2289 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
2290 case CONDITIONAL_ACE_TOKEN_CONTAINS:
2291 case CONDITIONAL_ACE_TOKEN_ANY_OF:
2292 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
2293 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
2294 if (depth < 2) {
2295 goto error;
2297 depth--;
2298 rhs = &stack[depth];
2299 depth--;
2300 lhs = &stack[depth];
2301 ok = relational_operator(token, tok, lhs, rhs, &result);
2302 if (! ok) {
2303 goto error;
2305 stack[depth] = result;
2306 depth++;
2307 break;
2308 /* unary logical operators */
2309 case CONDITIONAL_ACE_TOKEN_EXISTS:
2310 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
2311 case CONDITIONAL_ACE_TOKEN_NOT:
2312 if (depth == 0) {
2313 goto error;
2315 depth--;
2316 lhs = &stack[depth];
2317 ok = unary_logic_operator(mem_ctx, token, tok, lhs, sd, &result);
2318 if (!ok) {
2319 goto error;
2321 stack[depth] = result;
2322 depth++;
2323 break;
2324 /* binary logical operators */
2325 case CONDITIONAL_ACE_TOKEN_AND:
2326 case CONDITIONAL_ACE_TOKEN_OR:
2327 if (depth < 2) {
2328 goto error;
2330 depth--;
2331 rhs = &stack[depth];
2332 depth--;
2333 lhs = &stack[depth];
2334 ok = binary_logic_operator(token, tok, lhs, rhs, &result);
2335 if (! ok) {
2336 goto error;
2338 stack[depth] = result;
2339 depth++;
2340 break;
2341 default:
2342 goto error;
2346 * The evaluation should have left a single result value (true, false,
2347 * or unknown) on the stack. If not, the expression was malformed.
2349 if (depth != 1) {
2350 goto error;
2352 result = stack[0];
2353 if (result.type != CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
2354 goto error;
2356 TALLOC_FREE(stack);
2357 return result.data.result.value;
2359 error:
2361 * the result of an error is always UNKNOWN, which should be
2362 * interpreted pessimistically, not allowing access.
2364 TALLOC_FREE(stack);
2365 return ACE_CONDITION_UNKNOWN;
2369 /** access_check_conditional_ace()
2371 * Run the conditional ACE from the blob form. Return false if it is
2372 * not a valid conditional ACE, true if it is, even if there is some
2373 * other error in running it. The *result parameter is set to
2374 * ACE_CONDITION_FALSE, ACE_CONDITION_TRUE, or ACE_CONDITION_UNKNOWN.
2376 * ACE_CONDITION_UNKNOWN should be treated pessimistically, as if it were
2377 * TRUE for deny ACEs, and FALSE for allow ACEs.
2379 * @param[in] ace - the ACE being processed.
2380 * @param[in] token - the security token the ACE is processing.
2381 * @param[out] result - a ternary result value.
2383 * @return true if it is a valid conditional ACE.
2386 bool access_check_conditional_ace(const struct security_ace *ace,
2387 const struct security_token *token,
2388 const struct security_descriptor *sd,
2389 int *result)
2391 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
2392 struct ace_condition_script *program = NULL;
2393 program = parse_conditional_ace(tmp_ctx, ace->coda.conditions);
2394 if (program == NULL) {
2395 *result = ACE_CONDITION_UNKNOWN;
2396 TALLOC_FREE(tmp_ctx);
2397 return false;
2400 *result = run_conditional_ace(tmp_ctx, token, program, sd);
2402 TALLOC_FREE(tmp_ctx);
2403 return true;
2407 bool conditional_ace_encode_binary(TALLOC_CTX *mem_ctx,
2408 struct ace_condition_script *program,
2409 DATA_BLOB *dest)
2411 size_t i, j, alloc_size, required_size;
2412 uint8_t *data = NULL;
2413 uint8_t *new_data = NULL;
2414 *dest = (DATA_BLOB){NULL, 0};
2416 alloc_size = CONDITIONAL_ACE_MAX_LENGTH;
2417 data = talloc_array(mem_ctx,
2418 uint8_t,
2419 alloc_size);
2420 if (data == NULL) {
2421 return false;
2424 data[0] = 'a';
2425 data[1] = 'r';
2426 data[2] = 't';
2427 data[3] = 'x';
2429 j = 4;
2430 for (i = 0; i < program->length; i++) {
2431 struct ace_condition_token *tok = &program->tokens[i];
2432 ssize_t consumed;
2433 bool ok;
2435 * In all cases we write the token type byte.
2437 data[j] = tok->type;
2438 j++;
2439 if (j >= alloc_size) {
2440 DBG_ERR("program exceeds %zu bytes\n", alloc_size);
2441 goto error;
2444 switch (tok->type) {
2445 case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
2446 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
2447 case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
2448 case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
2449 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
2450 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
2451 case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
2452 case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
2453 case CONDITIONAL_ACE_TOKEN_EQUAL:
2454 case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
2455 case CONDITIONAL_ACE_TOKEN_LESS_THAN:
2456 case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
2457 case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
2458 case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
2459 case CONDITIONAL_ACE_TOKEN_CONTAINS:
2460 case CONDITIONAL_ACE_TOKEN_ANY_OF:
2461 case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
2462 case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
2463 case CONDITIONAL_ACE_TOKEN_EXISTS:
2464 case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
2465 case CONDITIONAL_ACE_TOKEN_NOT:
2466 case CONDITIONAL_ACE_TOKEN_AND:
2467 case CONDITIONAL_ACE_TOKEN_OR:
2469 * All of these are simple operators that operate on
2470 * the stack. We have already added the tok->type and
2471 * there's nothing else to do.
2473 continue;
2475 case CONDITIONAL_ACE_TOKEN_INT8:
2476 case CONDITIONAL_ACE_TOKEN_INT16:
2477 case CONDITIONAL_ACE_TOKEN_INT32:
2478 case CONDITIONAL_ACE_TOKEN_INT64:
2479 ok = check_integer_range(tok);
2480 if (! ok) {
2481 goto error;
2483 consumed = push_integer(data + j,
2484 alloc_size - j,
2485 &tok->data.int64);
2486 break;
2487 case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
2488 case CONDITIONAL_ACE_USER_ATTRIBUTE:
2489 case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
2490 case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
2491 case CONDITIONAL_ACE_TOKEN_UNICODE:
2492 consumed = push_unicode(data + j,
2493 alloc_size - j,
2494 &tok->data.unicode);
2495 break;
2496 case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
2497 consumed = push_bytes(data + j,
2498 alloc_size - j,
2499 &tok->data.bytes);
2500 break;
2501 case CONDITIONAL_ACE_TOKEN_SID:
2502 consumed = push_sid(data + j,
2503 alloc_size - j,
2504 &tok->data.sid);
2505 break;
2506 case CONDITIONAL_ACE_TOKEN_COMPOSITE:
2507 consumed = push_composite(data + j,
2508 alloc_size - j,
2509 &tok->data.composite);
2510 break;
2512 default:
2513 DBG_ERR("unknown token 0x%02x at position %zu\n",
2514 tok->type, i);
2515 goto error;
2517 if (consumed == -1) {
2518 DBG_ERR("program exceeds %zu bytes\n", alloc_size);
2519 goto error;
2521 j += consumed;
2522 if (j >= alloc_size) {
2523 DBG_ERR("program exceeds %zu bytes\n", alloc_size);
2524 goto error;
2527 /* align to a 4 byte boundary */
2528 required_size = (j + 3) & ~((size_t)3);
2529 if (required_size > alloc_size) {
2530 DBG_ERR("program exceeds %zu bytes\n", alloc_size);
2531 goto error;
2533 while (j < required_size) {
2534 data[j] = 0;
2535 j++;
2537 new_data = talloc_realloc(mem_ctx,
2538 data,
2539 uint8_t,
2540 required_size);
2541 if (new_data == NULL) {
2542 goto error;
2544 data = new_data;
2546 (*dest).data = data;
2547 (*dest).length = j;
2548 return true;
2549 error:
2550 TALLOC_FREE(data);
2551 return false;