/src/samba/libcli/security/conditional_ace.c
Line | Count | Source |
1 | | /* |
2 | | * Unix SMB implementation. |
3 | | * Functions for understanding conditional ACEs |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation; either version 3 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
17 | | */ |
18 | | |
19 | | #include "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" |
32 | | /* |
33 | | * Conditional ACE logic truth tables. |
34 | | * |
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. |
39 | | * |
40 | | * AND true false unknown |
41 | | * true T F ? |
42 | | * false F F F |
43 | | * unknown ? F ? |
44 | | * |
45 | | * OR true false unknown |
46 | | * true T T T |
47 | | * false T F ? |
48 | | * unknown T ? ? |
49 | | * |
50 | | * NOT |
51 | | * true F |
52 | | * false T |
53 | | * unknown ? |
54 | | * |
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). |
58 | | * |
59 | | * What counts as unknown |
60 | | * |
61 | | * - NULL attributes. |
62 | | * - certain comparisons between incompatible types |
63 | | * |
64 | | * What counts as false |
65 | | * |
66 | | * - zero |
67 | | * - empty strings |
68 | | * |
69 | | * An error means the entire expression is unknown. |
70 | | */ |
71 | | |
72 | | |
73 | | static bool check_integer_range(const struct ace_condition_token *tok) |
74 | 583k | { |
75 | 583k | int64_t val = tok->data.int64.value; |
76 | 583k | switch (tok->type) { |
77 | 4.33k | case CONDITIONAL_ACE_TOKEN_INT8: |
78 | 4.33k | if (val < -128 || val > 127) { |
79 | 1.31k | return false; |
80 | 1.31k | } |
81 | 3.02k | break; |
82 | 8.80k | case CONDITIONAL_ACE_TOKEN_INT16: |
83 | 8.80k | if (val < INT16_MIN || val > INT16_MAX) { |
84 | 1.82k | return false; |
85 | 1.82k | } |
86 | 6.98k | break; |
87 | 8.72k | case CONDITIONAL_ACE_TOKEN_INT32: |
88 | 8.72k | if (val < INT32_MIN || val > INT32_MAX) { |
89 | 1.12k | return false; |
90 | 1.12k | } |
91 | 7.59k | break; |
92 | 561k | case CONDITIONAL_ACE_TOKEN_INT64: |
93 | | /* val has these limits naturally */ |
94 | 561k | break; |
95 | 0 | default: |
96 | 0 | return false; |
97 | 583k | } |
98 | | |
99 | 578k | if (tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_8 && |
100 | 524k | tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_10 && |
101 | 44.6k | tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_16) { |
102 | 1.39k | return false; |
103 | 1.39k | } |
104 | 577k | if (tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_POSITIVE && |
105 | 548k | tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NEGATIVE && |
106 | 521k | tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NONE) { |
107 | 418 | return false; |
108 | 418 | } |
109 | 577k | return true; |
110 | 577k | } |
111 | | |
112 | | static ssize_t pull_integer(uint8_t *data, |
113 | | size_t length, |
114 | | struct ace_condition_int *tok) |
115 | 124k | { |
116 | 124k | size_t consumed; |
117 | 124k | enum ndr_err_code ndr_err; |
118 | | |
119 | 124k | ndr_err = ndr_pull_struct_blob_noalloc( |
120 | 124k | data, |
121 | 124k | length, |
122 | 124k | tok, |
123 | 124k | (ndr_pull_flags_fn_t)ndr_pull_ace_condition_int, |
124 | 124k | &consumed); |
125 | 124k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
126 | 1.57k | return -1; |
127 | 1.57k | } |
128 | 122k | return consumed; |
129 | 124k | } |
130 | | |
131 | | static ssize_t push_integer(uint8_t *data, size_t available, |
132 | | const struct ace_condition_int *tok) |
133 | 458k | { |
134 | 458k | enum ndr_err_code ndr_err; |
135 | 458k | DATA_BLOB v; |
136 | 458k | ndr_err = ndr_push_struct_blob(&v, NULL, |
137 | 458k | tok, |
138 | 458k | (ndr_push_flags_fn_t)ndr_push_ace_condition_int); |
139 | 458k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
140 | 0 | return -1; |
141 | 0 | } |
142 | 458k | if (available < v.length) { |
143 | 108 | talloc_free(v.data); |
144 | 108 | return -1; |
145 | 108 | } |
146 | 458k | memcpy(data, v.data, v.length); |
147 | 458k | talloc_free(v.data); |
148 | 458k | return v.length; |
149 | 458k | } |
150 | | |
151 | | |
152 | | static ssize_t pull_unicode(TALLOC_CTX *mem_ctx, |
153 | | uint8_t *data, size_t length, |
154 | | struct ace_condition_unicode *tok) |
155 | 149k | { |
156 | 149k | ssize_t bytes_used; |
157 | 149k | enum ndr_err_code ndr_err; |
158 | 149k | DATA_BLOB v = data_blob_const(data, length); |
159 | 149k | struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx); |
160 | 149k | if (ndr == NULL) { |
161 | 0 | return -1; |
162 | 0 | } |
163 | 149k | ndr_err = ndr_pull_ace_condition_unicode(ndr, NDR_SCALARS|NDR_BUFFERS, tok); |
164 | 149k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
165 | 2.27k | TALLOC_FREE(ndr); |
166 | 2.27k | return -1; |
167 | 2.27k | } |
168 | 146k | bytes_used = ndr->offset; |
169 | 146k | TALLOC_FREE(ndr); |
170 | 146k | return bytes_used; |
171 | 149k | } |
172 | | |
173 | | static ssize_t push_unicode(uint8_t *data, size_t available, |
174 | | const struct ace_condition_unicode *tok) |
175 | 313k | { |
176 | 313k | enum ndr_err_code ndr_err; |
177 | 313k | DATA_BLOB v; |
178 | 313k | ndr_err = ndr_push_struct_blob(&v, NULL, |
179 | 313k | tok, |
180 | 313k | (ndr_push_flags_fn_t)ndr_push_ace_condition_unicode); |
181 | 313k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
182 | 0 | return -1; |
183 | 0 | } |
184 | 313k | if (available < v.length) { |
185 | 392 | talloc_free(v.data); |
186 | 392 | return -1; |
187 | 392 | } |
188 | 312k | memcpy(data, v.data, v.length); |
189 | 312k | talloc_free(v.data); |
190 | 312k | return v.length; |
191 | 313k | } |
192 | | |
193 | | |
194 | | static ssize_t pull_bytes(TALLOC_CTX *mem_ctx, |
195 | | uint8_t *data, size_t length, |
196 | | DATA_BLOB *tok) |
197 | 32.8k | { |
198 | 32.8k | ssize_t bytes_used; |
199 | 32.8k | enum ndr_err_code ndr_err; |
200 | 32.8k | DATA_BLOB v = data_blob_const(data, length); |
201 | 32.8k | struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx); |
202 | 32.8k | if (ndr == NULL) { |
203 | 0 | return -1; |
204 | 0 | } |
205 | 32.8k | ndr_err = ndr_pull_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, tok); |
206 | 32.8k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
207 | 419 | TALLOC_FREE(ndr); |
208 | 419 | return -1; |
209 | 419 | } |
210 | 32.4k | bytes_used = ndr->offset; |
211 | 32.4k | talloc_free(ndr); |
212 | 32.4k | return bytes_used; |
213 | 32.8k | } |
214 | | |
215 | | static ssize_t push_bytes(uint8_t *data, size_t available, |
216 | | const DATA_BLOB *tok) |
217 | 56.8k | { |
218 | 56.8k | size_t offset; |
219 | 56.8k | enum ndr_err_code ndr_err; |
220 | 56.8k | TALLOC_CTX *frame = talloc_stackframe(); |
221 | 56.8k | struct ndr_push *ndr = ndr_push_init_ctx(frame); |
222 | 56.8k | if (ndr == NULL) { |
223 | 0 | TALLOC_FREE(frame); |
224 | 0 | return -1; |
225 | 0 | } |
226 | | |
227 | 56.8k | ndr_err = ndr_push_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, *tok); |
228 | 56.8k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
229 | 0 | TALLOC_FREE(frame); |
230 | 0 | return -1; |
231 | 0 | } |
232 | | |
233 | 56.8k | if (available < ndr->offset) { |
234 | 17 | TALLOC_FREE(frame); |
235 | 17 | return -1; |
236 | 17 | } |
237 | 56.8k | memcpy(data, ndr->data, ndr->offset); |
238 | 56.8k | offset = ndr->offset; |
239 | 56.8k | TALLOC_FREE(frame); |
240 | 56.8k | return offset; |
241 | 56.8k | } |
242 | | |
243 | | static ssize_t pull_sid(TALLOC_CTX *mem_ctx, |
244 | | uint8_t *data, size_t length, |
245 | | struct ace_condition_sid *tok) |
246 | 13.6k | { |
247 | 13.6k | ssize_t bytes_used; |
248 | 13.6k | enum ndr_err_code ndr_err; |
249 | 13.6k | DATA_BLOB v = data_blob_const(data, length); |
250 | 13.6k | struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx); |
251 | 13.6k | if (ndr == NULL) { |
252 | 0 | return -1; |
253 | 0 | } |
254 | 13.6k | ndr->flags |= LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES; |
255 | | |
256 | 13.6k | ndr_err = ndr_pull_ace_condition_sid(ndr, NDR_SCALARS|NDR_BUFFERS, tok); |
257 | 13.6k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
258 | 1.77k | TALLOC_FREE(ndr); |
259 | 1.77k | return -1; |
260 | 1.77k | } |
261 | 11.8k | bytes_used = ndr->offset; |
262 | 11.8k | TALLOC_FREE(ndr); |
263 | 11.8k | return bytes_used; |
264 | 13.6k | } |
265 | | |
266 | | static ssize_t push_sid(uint8_t *data, size_t available, |
267 | | const struct ace_condition_sid *tok) |
268 | 19.2k | { |
269 | 19.2k | enum ndr_err_code ndr_err; |
270 | 19.2k | DATA_BLOB v; |
271 | 19.2k | ndr_err = ndr_push_struct_blob(&v, NULL, |
272 | 19.2k | tok, |
273 | 19.2k | (ndr_push_flags_fn_t)ndr_push_ace_condition_sid); |
274 | 19.2k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
275 | 0 | return -1; |
276 | 0 | } |
277 | 19.2k | if (available < v.length) { |
278 | 12 | talloc_free(v.data); |
279 | 12 | return -1; |
280 | 12 | } |
281 | 19.2k | memcpy(data, v.data, v.length); |
282 | 19.2k | talloc_free(v.data); |
283 | 19.2k | return v.length; |
284 | 19.2k | } |
285 | | |
286 | | |
287 | | static ssize_t pull_composite(TALLOC_CTX *mem_ctx, |
288 | | uint8_t *data, size_t length, |
289 | | struct ace_condition_composite *tok) |
290 | 23.7k | { |
291 | 23.7k | size_t i, j; |
292 | 23.7k | size_t alloc_length; |
293 | 23.7k | size_t byte_size; |
294 | 23.7k | struct ace_condition_token *tokens = NULL; |
295 | 23.7k | if (length < 4) { |
296 | 110 | return -1; |
297 | 110 | } |
298 | 23.6k | byte_size = PULL_LE_U32(data, 0); |
299 | 23.6k | if (byte_size > length - 4) { |
300 | 333 | return -1; |
301 | 333 | } |
302 | | /* |
303 | | * There is a list of other literal tokens (possibly including nested |
304 | | * composites), which we will store in an array. |
305 | | * |
306 | | * This array can *only* be literals. |
307 | | */ |
308 | 23.3k | alloc_length = byte_size; |
309 | 23.3k | tokens = talloc_array(mem_ctx, |
310 | 23.3k | struct ace_condition_token, |
311 | 23.3k | alloc_length); |
312 | 23.3k | if (tokens == NULL) { |
313 | 0 | return -1; |
314 | 0 | } |
315 | 23.3k | byte_size += 4; |
316 | 23.3k | i = 4; |
317 | 23.3k | j = 0; |
318 | 113k | while (i < byte_size) { |
319 | 93.0k | struct ace_condition_token *el = &tokens[j]; |
320 | 93.0k | ssize_t consumed; |
321 | 93.0k | uint8_t *el_data = NULL; |
322 | 93.0k | size_t available; |
323 | 93.0k | bool ok; |
324 | 93.0k | *el = (struct ace_condition_token) { .type = data[i] }; |
325 | 93.0k | i++; |
326 | | |
327 | 93.0k | el_data = data + i; |
328 | 93.0k | available = byte_size - i; |
329 | | |
330 | 93.0k | switch (el->type) { |
331 | 1.08k | case CONDITIONAL_ACE_TOKEN_INT8: |
332 | 2.38k | case CONDITIONAL_ACE_TOKEN_INT16: |
333 | 4.07k | case CONDITIONAL_ACE_TOKEN_INT32: |
334 | 77.3k | case CONDITIONAL_ACE_TOKEN_INT64: |
335 | 77.3k | consumed = pull_integer(el_data, |
336 | 77.3k | available, |
337 | 77.3k | &el->data.int64); |
338 | 77.3k | ok = check_integer_range(el); |
339 | 77.3k | if (! ok) { |
340 | 1.89k | goto error; |
341 | 1.89k | } |
342 | 75.4k | break; |
343 | 75.4k | case CONDITIONAL_ACE_TOKEN_UNICODE: |
344 | 2.24k | consumed = pull_unicode(mem_ctx, |
345 | 2.24k | el_data, |
346 | 2.24k | available, |
347 | 2.24k | &el->data.unicode); |
348 | 2.24k | break; |
349 | | |
350 | 11.6k | case CONDITIONAL_ACE_TOKEN_OCTET_STRING: |
351 | 11.6k | consumed = pull_bytes(mem_ctx, |
352 | 11.6k | el_data, |
353 | 11.6k | available, |
354 | 11.6k | &el->data.bytes); |
355 | 11.6k | break; |
356 | | |
357 | 1.30k | case CONDITIONAL_ACE_TOKEN_SID: |
358 | 1.30k | consumed = pull_sid(mem_ctx, |
359 | 1.30k | el_data, |
360 | 1.30k | available, |
361 | 1.30k | &el->data.sid); |
362 | 1.30k | break; |
363 | | |
364 | 224 | case CONDITIONAL_ACE_TOKEN_COMPOSITE: |
365 | 224 | DBG_ERR("recursive composite tokens in conditional " |
366 | 224 | "ACEs are not currently supported\n"); |
367 | 224 | goto error; |
368 | 286 | default: |
369 | 286 | goto error; |
370 | 93.0k | } |
371 | | |
372 | 90.6k | if (consumed < 0 || consumed + i > length) { |
373 | 251 | goto error; |
374 | 251 | } |
375 | 90.3k | i += consumed; |
376 | 90.3k | j++; |
377 | 90.3k | if (j == UINT16_MAX) { |
378 | 0 | talloc_free(tokens); |
379 | 0 | return -1; |
380 | 0 | } |
381 | 90.3k | if (j == alloc_length) { |
382 | 0 | struct ace_condition_token *new_tokens = NULL; |
383 | |
|
384 | 0 | alloc_length += 5; |
385 | 0 | new_tokens = talloc_realloc(mem_ctx, |
386 | 0 | tokens, |
387 | 0 | struct ace_condition_token, |
388 | 0 | alloc_length); |
389 | |
|
390 | 0 | if (new_tokens == NULL) { |
391 | 0 | goto error; |
392 | 0 | } |
393 | 0 | tokens = new_tokens; |
394 | 0 | } |
395 | 90.3k | } |
396 | 20.6k | tok->n_members = j; |
397 | 20.6k | tok->tokens = tokens; |
398 | 20.6k | return byte_size; |
399 | 2.66k | error: |
400 | 2.66k | talloc_free(tokens); |
401 | 2.66k | return -1; |
402 | 23.3k | } |
403 | | |
404 | | |
405 | | static ssize_t push_composite(uint8_t *data, size_t length, |
406 | | const struct ace_condition_composite *tok) |
407 | 26.3k | { |
408 | 26.3k | size_t i; |
409 | 26.3k | uint8_t *byte_length_ptr; |
410 | 26.3k | size_t used = 0; |
411 | 26.3k | if (length < 4) { |
412 | 11 | return -1; |
413 | 11 | } |
414 | | /* |
415 | | * We have no idea what the eventual length will be, so we keep a |
416 | | * pointer to write it in at the end. |
417 | | */ |
418 | 26.3k | byte_length_ptr = data; |
419 | 26.3k | PUSH_LE_U32(data, 0, 0); |
420 | 26.3k | used = 4; |
421 | | |
422 | 447k | for (i = 0; i < tok->n_members && used < length; i++) { |
423 | 421k | struct ace_condition_token *el = &tok->tokens[i]; |
424 | 421k | ssize_t consumed; |
425 | 421k | uint8_t *el_data = NULL; |
426 | 421k | size_t available; |
427 | 421k | bool ok; |
428 | 421k | data[used] = el->type; |
429 | 421k | used++; |
430 | 421k | if (used == length) { |
431 | | /* |
432 | | * used == length is not expected here; the token |
433 | | * types that only have an opcode and no data are not |
434 | | * literals that can be in composites. |
435 | | */ |
436 | 17 | return -1; |
437 | 17 | } |
438 | 421k | el_data = data + used; |
439 | 421k | available = length - used; |
440 | | |
441 | 421k | switch (el->type) { |
442 | 398 | case CONDITIONAL_ACE_TOKEN_INT8: |
443 | 1.01k | case CONDITIONAL_ACE_TOKEN_INT16: |
444 | 1.73k | case CONDITIONAL_ACE_TOKEN_INT32: |
445 | 384k | case CONDITIONAL_ACE_TOKEN_INT64: |
446 | 384k | ok = check_integer_range(el); |
447 | 384k | if (! ok) { |
448 | 0 | return -1; |
449 | 0 | } |
450 | 384k | consumed = push_integer(el_data, |
451 | 384k | available, |
452 | 384k | &el->data.int64); |
453 | 384k | break; |
454 | 7.70k | case CONDITIONAL_ACE_TOKEN_UNICODE: |
455 | 7.70k | consumed = push_unicode(el_data, |
456 | 7.70k | available, |
457 | 7.70k | &el->data.unicode); |
458 | 7.70k | break; |
459 | | |
460 | 26.2k | case CONDITIONAL_ACE_TOKEN_OCTET_STRING: |
461 | 26.2k | consumed = push_bytes(el_data, |
462 | 26.2k | available, |
463 | 26.2k | &el->data.bytes); |
464 | 26.2k | break; |
465 | | |
466 | 3.11k | case CONDITIONAL_ACE_TOKEN_SID: |
467 | 3.11k | consumed = push_sid(el_data, |
468 | 3.11k | available, |
469 | 3.11k | &el->data.sid); |
470 | 3.11k | break; |
471 | | |
472 | 0 | case CONDITIONAL_ACE_TOKEN_COMPOSITE: |
473 | 0 | consumed = push_composite(el_data, |
474 | 0 | available, |
475 | 0 | &el->data.composite); |
476 | 0 | break; |
477 | | |
478 | 0 | default: |
479 | 0 | return -1; |
480 | 421k | } |
481 | | |
482 | 421k | if (consumed < 0) { |
483 | 342 | return -1; |
484 | 342 | } |
485 | 421k | used += consumed; |
486 | 421k | } |
487 | 25.9k | if (used > length) { |
488 | 0 | return -1; |
489 | 0 | } |
490 | | |
491 | 25.9k | PUSH_LE_U32(byte_length_ptr, 0, used - 4); |
492 | 25.9k | return used; |
493 | 25.9k | } |
494 | | |
495 | | static ssize_t pull_end_padding(uint8_t *data, size_t length) |
496 | 32.7k | { |
497 | | /* |
498 | | * We just check that we have the right kind of number of zero |
499 | | * bytes. The blob must end on a multiple of 4. One zero byte |
500 | | * has already been swallowed as tok->type, which sends us |
501 | | * here, so we expect 1 or two more -- total padding is 0, 1, |
502 | | * 2, or 3. |
503 | | * |
504 | | * zero is also called CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING. |
505 | | */ |
506 | 32.7k | size_t i; |
507 | 32.7k | if (length > 2) { |
508 | 1.08k | return -1; |
509 | 1.08k | } |
510 | 53.4k | for (i = 0; i < length; i++) { |
511 | 22.0k | if (data[i] != 0) { |
512 | 184 | return -1; |
513 | 184 | } |
514 | 22.0k | } |
515 | 31.4k | return length; |
516 | 31.6k | } |
517 | | |
518 | | |
519 | | struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx, |
520 | | DATA_BLOB data) |
521 | 62.9k | { |
522 | 62.9k | size_t i, j; |
523 | 62.9k | struct ace_condition_token *tokens = NULL; |
524 | 62.9k | size_t alloc_length; |
525 | 62.9k | struct ace_condition_script *program = NULL; |
526 | | |
527 | 62.9k | if (data.length < 4 || |
528 | 58.1k | data.data[0] != 'a' || |
529 | 55.9k | data.data[1] != 'r' || |
530 | 55.3k | data.data[2] != 't' || |
531 | 54.8k | data.data[3] != 'x') { |
532 | | /* |
533 | | * lacks the "artx" conditional ace identifier magic. |
534 | | * NULL returns will deny access. |
535 | | */ |
536 | 8.67k | return NULL; |
537 | 8.67k | } |
538 | 54.2k | if (data.length > CONDITIONAL_ACE_MAX_LENGTH || |
539 | 54.2k | (data.length & 3) != 0) { |
540 | | /* |
541 | | * >= 64k or non-multiples of 4 are not possible in the ACE |
542 | | * wire format. |
543 | | */ |
544 | 531 | return NULL; |
545 | 531 | } |
546 | | |
547 | 53.7k | program = talloc(mem_ctx, struct ace_condition_script); |
548 | 53.7k | if (program == NULL) { |
549 | 0 | return NULL; |
550 | 0 | } |
551 | | |
552 | | /* |
553 | | * We will normally end up with fewer than data.length tokens, as |
554 | | * values are stored in multiple bytes (all integers are 10 bytes, |
555 | | * strings and attributes are utf16 + length, SIDs are SID-size + |
556 | | * length, etc). But operators are one byte, so something like |
557 | | * !(!(!(!(!(!(x)))))) -- where each '!(..)' is one byte -- will bring |
558 | | * the number of tokens close to the number of bytes. |
559 | | * |
560 | | * This is all to say we're guessing a token length that hopes to |
561 | | * avoid reallocs without wasting too much up front. |
562 | | */ |
563 | 53.7k | alloc_length = data.length / 2 + 1; |
564 | 53.7k | tokens = talloc_array(program, |
565 | 53.7k | struct ace_condition_token, |
566 | 53.7k | alloc_length); |
567 | 53.7k | if (tokens == NULL) { |
568 | 0 | TALLOC_FREE(program); |
569 | 0 | return NULL; |
570 | 0 | } |
571 | | |
572 | 53.7k | i = 4; |
573 | 53.7k | j = 0; |
574 | 1.36M | while(i < data.length) { |
575 | 1.31M | struct ace_condition_token *tok = &tokens[j]; |
576 | 1.31M | ssize_t consumed = 0; |
577 | 1.31M | uint8_t *tok_data = NULL; |
578 | 1.31M | size_t available; |
579 | 1.31M | bool ok; |
580 | 1.31M | tok->type = data.data[i]; |
581 | 1.31M | tok->flags = 0; |
582 | 1.31M | i++; |
583 | 1.31M | tok_data = data.data + i; |
584 | 1.31M | available = data.length - i; |
585 | | |
586 | 1.31M | switch (tok->type) { |
587 | 2.08k | case CONDITIONAL_ACE_TOKEN_INT8: |
588 | 7.82k | case CONDITIONAL_ACE_TOKEN_INT16: |
589 | 13.3k | case CONDITIONAL_ACE_TOKEN_INT32: |
590 | 47.1k | case CONDITIONAL_ACE_TOKEN_INT64: |
591 | 47.1k | consumed = pull_integer(tok_data, |
592 | 47.1k | available, |
593 | 47.1k | &tok->data.int64); |
594 | 47.1k | ok = check_integer_range(tok); |
595 | 47.1k | if (! ok) { |
596 | 4.17k | goto fail; |
597 | 4.17k | } |
598 | 42.9k | break; |
599 | 42.9k | case CONDITIONAL_ACE_TOKEN_UNICODE: |
600 | | /* |
601 | | * The next four are pulled as unicode, but are |
602 | | * processed as user attribute look-ups. |
603 | | */ |
604 | 89.2k | case CONDITIONAL_ACE_LOCAL_ATTRIBUTE: |
605 | 102k | case CONDITIONAL_ACE_USER_ATTRIBUTE: |
606 | 141k | case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE: |
607 | 146k | case CONDITIONAL_ACE_DEVICE_ATTRIBUTE: |
608 | 146k | consumed = pull_unicode(program, |
609 | 146k | tok_data, |
610 | 146k | available, |
611 | 146k | &tok->data.unicode); |
612 | 146k | break; |
613 | | |
614 | 21.2k | case CONDITIONAL_ACE_TOKEN_OCTET_STRING: |
615 | 21.2k | consumed = pull_bytes(program, |
616 | 21.2k | tok_data, |
617 | 21.2k | available, |
618 | 21.2k | &tok->data.bytes); |
619 | 21.2k | break; |
620 | | |
621 | 12.3k | case CONDITIONAL_ACE_TOKEN_SID: |
622 | 12.3k | consumed = pull_sid(program, |
623 | 12.3k | tok_data, |
624 | 12.3k | available, |
625 | 12.3k | &tok->data.sid); |
626 | 12.3k | break; |
627 | | |
628 | 23.7k | case CONDITIONAL_ACE_TOKEN_COMPOSITE: |
629 | 23.7k | consumed = pull_composite(program, |
630 | 23.7k | tok_data, |
631 | 23.7k | available, |
632 | 23.7k | &tok->data.composite); |
633 | 23.7k | break; |
634 | | |
635 | 8.08k | case CONDITIONAL_ACE_TOKEN_MEMBER_OF: |
636 | 21.2k | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF: |
637 | 27.9k | case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY: |
638 | 38.2k | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY: |
639 | 44.9k | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF: |
640 | 70.1k | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF: |
641 | 82.9k | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY: |
642 | 705k | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY: |
643 | | /* |
644 | | * these require a SID or composite SID list operand, |
645 | | * and we could check that now in most cases. |
646 | | */ |
647 | 705k | break; |
648 | | /* binary relational operators */ |
649 | 8.45k | case CONDITIONAL_ACE_TOKEN_EQUAL: |
650 | 19.6k | case CONDITIONAL_ACE_TOKEN_NOT_EQUAL: |
651 | 36.7k | case CONDITIONAL_ACE_TOKEN_LESS_THAN: |
652 | 40.3k | case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL: |
653 | 67.0k | case CONDITIONAL_ACE_TOKEN_GREATER_THAN: |
654 | 72.6k | case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL: |
655 | 78.0k | case CONDITIONAL_ACE_TOKEN_CONTAINS: |
656 | 80.3k | case CONDITIONAL_ACE_TOKEN_ANY_OF: |
657 | 89.1k | case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS: |
658 | 94.0k | case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF: |
659 | | /* unary logical operators */ |
660 | 117k | case CONDITIONAL_ACE_TOKEN_EXISTS: |
661 | 125k | case CONDITIONAL_ACE_TOKEN_NOT_EXISTS: |
662 | 223k | case CONDITIONAL_ACE_TOKEN_NOT: |
663 | | /* binary logical operators */ |
664 | 267k | case CONDITIONAL_ACE_TOKEN_AND: |
665 | 329k | case CONDITIONAL_ACE_TOKEN_OR: |
666 | 329k | break; |
667 | 32.7k | case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING: |
668 | | /* this is only valid at the end */ |
669 | 32.7k | consumed = pull_end_padding(tok_data, |
670 | 32.7k | available); |
671 | 32.7k | j--; /* don't add this token */ |
672 | 32.7k | break; |
673 | 882 | default: |
674 | 882 | goto fail; |
675 | 1.31M | } |
676 | | |
677 | 1.31M | if (consumed < 0) { |
678 | 8.58k | goto fail; |
679 | 8.58k | } |
680 | 1.30M | if (consumed + i < i || consumed + i > data.length) { |
681 | 0 | goto fail; |
682 | 0 | } |
683 | 1.30M | i += consumed; |
684 | 1.30M | j++; |
685 | 1.30M | if (j == alloc_length) { |
686 | 1.47k | alloc_length *= 2; |
687 | 1.47k | tokens = talloc_realloc(program, |
688 | 1.47k | tokens, |
689 | 1.47k | struct ace_condition_token, |
690 | 1.47k | alloc_length); |
691 | 1.47k | if (tokens == NULL) { |
692 | 0 | goto fail; |
693 | 0 | } |
694 | 1.47k | } |
695 | 1.30M | } |
696 | 40.0k | program->length = j; |
697 | 40.0k | program->tokens = talloc_realloc(program, |
698 | 40.0k | tokens, |
699 | 40.0k | struct ace_condition_token, |
700 | 40.0k | program->length + 1); |
701 | 40.0k | if (program->tokens == NULL) { |
702 | 0 | goto fail; |
703 | 0 | } |
704 | 40.0k | return program; |
705 | 13.6k | fail: |
706 | 13.6k | talloc_free(program); |
707 | 13.6k | return NULL; |
708 | 40.0k | } |
709 | | |
710 | | |
711 | | static bool claim_lookup_internal( |
712 | | TALLOC_CTX *mem_ctx, |
713 | | struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim, |
714 | | struct ace_condition_token *result) |
715 | 47.0k | { |
716 | 47.0k | bool ok = claim_v1_to_ace_token(mem_ctx, claim, result); |
717 | 47.0k | return ok; |
718 | 47.0k | } |
719 | | |
720 | | |
721 | | static bool resource_claim_lookup( |
722 | | TALLOC_CTX *mem_ctx, |
723 | | const struct ace_condition_token *op, |
724 | | const struct security_descriptor *sd, |
725 | | struct ace_condition_token *result) |
726 | 28.6k | { |
727 | | /* |
728 | | * For a @Resource.attr, the claims come from a resource ACE |
729 | | * in the object's SACL. That's why we need a security descriptor. |
730 | | * |
731 | | * If there is no matching resource ACE, a NULL result is returned, |
732 | | * which should compare UNKNOWN to anything. The NULL will have the |
733 | | * CONDITIONAL_ACE_FLAG_NULL_MEANS_ERROR flag set if it seems failure |
734 | | * is not simply due to the sought claim not existing. This is useful for |
735 | | * the Exists and Not_Exists operators. |
736 | | */ |
737 | 28.6k | size_t i; |
738 | 28.6k | struct ace_condition_unicode name; |
739 | | |
740 | 28.6k | result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL; |
741 | | |
742 | 28.6k | if (op->type != CONDITIONAL_ACE_RESOURCE_ATTRIBUTE) { |
743 | | /* what are we even doing here? */ |
744 | 0 | result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR; |
745 | 0 | return false; |
746 | 0 | } |
747 | | |
748 | 28.6k | name = op->data.resource_attr; |
749 | | |
750 | 28.6k | if (sd->sacl == NULL) { |
751 | 2.87k | DBG_NOTICE("Resource attribute ACE '%s' not found, " |
752 | 2.87k | "because there is no SACL\n", |
753 | 2.87k | name.value); |
754 | 2.87k | return true; |
755 | 2.87k | } |
756 | | |
757 | 841k | for (i = 0; i < sd->sacl->num_aces; i++) { |
758 | 835k | struct security_ace *ace = &sd->sacl->aces[i]; |
759 | 835k | bool ok; |
760 | | |
761 | 835k | if (ace->type != SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) { |
762 | 776k | continue; |
763 | 776k | } |
764 | 59.1k | if (strcasecmp_m(name.value, |
765 | 59.1k | ace->coda.claim.name) != 0) { |
766 | 12.1k | continue; |
767 | 12.1k | } |
768 | | /* this is the one */ |
769 | 47.0k | ok = claim_lookup_internal(mem_ctx, &ace->coda.claim, result); |
770 | 47.0k | if (ok) { |
771 | 19.9k | return true; |
772 | 19.9k | } |
773 | 47.0k | } |
774 | 5.87k | DBG_NOTICE("Resource attribute ACE '%s' not found.\n", |
775 | 5.87k | name.value); |
776 | 5.87k | return false; |
777 | 25.8k | } |
778 | | |
779 | | |
780 | | static bool token_claim_lookup( |
781 | | TALLOC_CTX *mem_ctx, |
782 | | const struct security_token *token, |
783 | | const struct ace_condition_token *op, |
784 | | struct ace_condition_token *result) |
785 | 412 | { |
786 | | /* |
787 | | * The operator has an attribute name; if there is a claim of |
788 | | * the right type with that name, that is returned as the result. |
789 | | * |
790 | | * XXX what happens otherwise? NULL result? |
791 | | */ |
792 | 412 | struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL; |
793 | 412 | size_t num_claims; |
794 | 412 | bool ok; |
795 | 412 | const struct ace_condition_unicode *name = NULL; |
796 | 412 | size_t i; |
797 | | |
798 | 412 | result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL; |
799 | | |
800 | 412 | switch (op->type) { |
801 | 183 | case CONDITIONAL_ACE_LOCAL_ATTRIBUTE: |
802 | 183 | claims = token->local_claims; |
803 | 183 | num_claims = token->num_local_claims; |
804 | 183 | name = &op->data.local_attr; |
805 | 183 | break; |
806 | 51 | case CONDITIONAL_ACE_USER_ATTRIBUTE: |
807 | 51 | claims = token->user_claims; |
808 | 51 | num_claims = token->num_user_claims; |
809 | 51 | name = &op->data.user_attr; |
810 | 51 | break; |
811 | 178 | case CONDITIONAL_ACE_DEVICE_ATTRIBUTE: |
812 | 178 | claims = token->device_claims; |
813 | 178 | num_claims = token->num_device_claims; |
814 | 178 | name = &op->data.device_attr; |
815 | 178 | break; |
816 | 0 | default: |
817 | 0 | DBG_WARNING("Conditional ACE claim lookup got bad arg type %u\n", |
818 | 0 | op->type); |
819 | 0 | result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR; |
820 | 0 | return false; |
821 | 412 | } |
822 | | |
823 | 412 | if (num_claims == 0) { |
824 | 356 | DBG_NOTICE("There are no type %u claims\n", op->type); |
825 | 356 | return false; |
826 | 356 | } |
827 | 56 | if (claims == NULL) { |
828 | 0 | DBG_ERR("Type %u claim list unexpectedly NULL!\n", op->type); |
829 | 0 | result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR; |
830 | 0 | return false; |
831 | 0 | } |
832 | | /* |
833 | | * Loop backwards: a later claim will override an earlier one with the |
834 | | * same name. |
835 | | */ |
836 | 295 | for (i = num_claims - 1; i < num_claims; i--) { |
837 | 262 | if (claims[i].name == NULL) { |
838 | 167 | DBG_ERR("claim %zu has no name!\n", i); |
839 | 167 | continue; |
840 | 167 | } |
841 | 95 | if (strcasecmp_m(claims[i].name, name->value) == 0) { |
842 | | /* this is the one */ |
843 | 23 | ok = claim_lookup_internal(mem_ctx, &claims[i], result); |
844 | 23 | return ok; |
845 | 23 | } |
846 | 95 | } |
847 | 33 | DBG_NOTICE("Claim not found\n"); |
848 | 33 | return false; |
849 | 56 | } |
850 | | |
851 | | |
852 | | |
853 | | |
854 | | static bool member_lookup( |
855 | | const struct security_token *token, |
856 | | const struct ace_condition_token *op, |
857 | | const struct ace_condition_token *arg, |
858 | | struct ace_condition_token *result) |
859 | 4.38k | { |
860 | | /* |
861 | | * We need to compare the lists of SIDs in the token with the |
862 | | * SID[s] in the argument. There are 8 combinations of |
863 | | * operation, depending on whether we want to match all or any |
864 | | * of the SIDs, whether we're using the device SIDs or user |
865 | | * SIDs, and whether the operator name starts with "Not_". |
866 | | * |
867 | | * _MEMBER_OF User has all operand SIDs |
868 | | * _DEVICE_MEMBER_OF Device has all operand SIDs |
869 | | * _MEMBER_OF_ANY User has one or more operand SIDs |
870 | | * _DEVICE_MEMBER_OF_ANY Device has one or more operand SIDs |
871 | | * |
872 | | * NOT_* has the effect of !(the operator without NOT_). |
873 | | * |
874 | | * The operand can either be a composite of SIDs or a single SID. |
875 | | * This adds an additional branch. |
876 | | */ |
877 | 4.38k | bool match = false; |
878 | 4.38k | bool it_is_a_not_op; |
879 | 4.38k | bool it_is_an_any_op; |
880 | 4.38k | bool it_is_a_device_op; |
881 | 4.38k | bool arg_is_a_single_sid; |
882 | 4.38k | struct dom_sid *sid_array = NULL; |
883 | 4.38k | size_t num_sids, i, j; |
884 | 4.38k | const struct dom_sid *sid = NULL; |
885 | | |
886 | 4.38k | result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL; |
887 | 4.38k | result->data.result.value = ACE_CONDITION_UNKNOWN; |
888 | | |
889 | 4.38k | switch (arg->type) { |
890 | 2.44k | case CONDITIONAL_ACE_TOKEN_SID: |
891 | 2.44k | arg_is_a_single_sid = true; |
892 | 2.44k | break; |
893 | 1.18k | case CONDITIONAL_ACE_TOKEN_COMPOSITE: |
894 | 1.18k | arg_is_a_single_sid = false; |
895 | 1.18k | break; |
896 | 760 | default: |
897 | 760 | DBG_WARNING("Conditional ACE Member_Of got bad arg type %u\n", |
898 | 760 | arg->type); |
899 | 760 | return false; |
900 | 4.38k | } |
901 | | |
902 | 3.62k | switch (op->type) { |
903 | 563 | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF: |
904 | 1.18k | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY: |
905 | 1.18k | it_is_a_not_op = true; |
906 | 1.18k | it_is_a_device_op = false; |
907 | 1.18k | break; |
908 | 172 | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY: |
909 | 420 | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF: |
910 | 420 | it_is_a_not_op = true; |
911 | 420 | it_is_a_device_op = true; |
912 | 420 | break; |
913 | 247 | case CONDITIONAL_ACE_TOKEN_MEMBER_OF: |
914 | 689 | case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY: |
915 | 689 | it_is_a_not_op = false; |
916 | 689 | it_is_a_device_op = false; |
917 | 689 | break; |
918 | 892 | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY: |
919 | 1.33k | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF: |
920 | 1.33k | it_is_a_not_op = false; |
921 | 1.33k | it_is_a_device_op = true; |
922 | 1.33k | break; |
923 | 0 | default: |
924 | 0 | DBG_WARNING("Conditional ACE Member_Of got bad op type %u\n", |
925 | 0 | op->type); |
926 | 0 | return false; |
927 | 3.62k | } |
928 | | |
929 | 3.62k | switch (op->type) { |
930 | 620 | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY: |
931 | 792 | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY: |
932 | 1.23k | case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY: |
933 | 2.12k | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY: |
934 | 2.12k | it_is_an_any_op = true; |
935 | 2.12k | break; |
936 | 1.49k | default: |
937 | 1.49k | it_is_an_any_op = false; |
938 | 3.62k | } |
939 | | |
940 | 3.62k | if (it_is_a_device_op) { |
941 | 1.75k | sid_array = token->device_sids; |
942 | 1.75k | num_sids = token->num_device_sids; |
943 | 1.87k | } else { |
944 | 1.87k | sid_array = token->sids; |
945 | 1.87k | num_sids = token->num_sids; |
946 | 1.87k | } |
947 | | |
948 | 3.62k | if (arg_is_a_single_sid) { |
949 | | /* |
950 | | * In this case the any and all operations are the |
951 | | * same. |
952 | | */ |
953 | 2.44k | sid = &arg->data.sid.sid; |
954 | 2.44k | match = false; |
955 | 21.7k | for (i = 0; i < num_sids; i++) { |
956 | 19.4k | match = dom_sid_equal(sid, &sid_array[i]); |
957 | 19.4k | if (match) { |
958 | 222 | break; |
959 | 222 | } |
960 | 19.4k | } |
961 | 2.44k | if (it_is_a_not_op) { |
962 | 980 | match = ! match; |
963 | 980 | } |
964 | 2.44k | if (match) { |
965 | 882 | result->data.result.value = ACE_CONDITION_TRUE; |
966 | 1.55k | } else { |
967 | 1.55k | result->data.result.value = ACE_CONDITION_FALSE; |
968 | 1.55k | } |
969 | 2.44k | return true; |
970 | 2.44k | } |
971 | | |
972 | | /* This is a composite list (hopefully of SIDs) */ |
973 | 1.18k | if (arg->data.composite.n_members == 0) { |
974 | 198 | DBG_WARNING("Conditional ACE Member_Of argument is empty\n"); |
975 | 198 | return false; |
976 | 198 | } |
977 | | |
978 | 1.46k | for (j = 0; j < arg->data.composite.n_members; j++) { |
979 | 1.21k | const struct ace_condition_token *member = |
980 | 1.21k | &arg->data.composite.tokens[j]; |
981 | 1.21k | if (member->type != CONDITIONAL_ACE_TOKEN_SID) { |
982 | 252 | DBG_WARNING("Conditional ACE Member_Of argument contains " |
983 | 252 | "non-sid element [%zu]: %u\n", |
984 | 252 | j, member->type); |
985 | 252 | return false; |
986 | 252 | } |
987 | 959 | sid = &member->data.sid.sid; |
988 | 959 | match = false; |
989 | 7.83k | for (i = 0; i < num_sids; i++) { |
990 | 7.07k | match = dom_sid_equal(sid, &sid_array[i]); |
991 | 7.07k | if (match) { |
992 | 203 | break; |
993 | 203 | } |
994 | 7.07k | } |
995 | 959 | if (it_is_an_any_op) { |
996 | 453 | if (match) { |
997 | | /* we have matched one SID, which is enough */ |
998 | 87 | goto apply_not; |
999 | 87 | } |
1000 | 506 | } else { /* an all op */ |
1001 | 506 | if (! match) { |
1002 | | /* failing one is enough */ |
1003 | 390 | goto apply_not; |
1004 | 390 | } |
1005 | 506 | } |
1006 | 959 | } |
1007 | | /* |
1008 | | * Reaching the end of that loop means either: |
1009 | | * 1. it was an ALL op and we never failed to find one, or |
1010 | | * 2. it was an ANY op, and we didn't find one. |
1011 | | */ |
1012 | 257 | match = !it_is_an_any_op; |
1013 | | |
1014 | 734 | apply_not: |
1015 | 734 | if (it_is_a_not_op) { |
1016 | 397 | match = ! match; |
1017 | 397 | } |
1018 | 734 | if (match) { |
1019 | 344 | result->data.result.value = ACE_CONDITION_TRUE; |
1020 | 390 | } else { |
1021 | 390 | result->data.result.value = ACE_CONDITION_FALSE; |
1022 | 390 | } |
1023 | | |
1024 | 734 | return true; |
1025 | 257 | } |
1026 | | |
1027 | | |
1028 | | static bool ternary_value( |
1029 | | const struct ace_condition_token *arg, |
1030 | | struct ace_condition_token *result) |
1031 | 50.3k | { |
1032 | | /* |
1033 | | * Find the truth value of the argument, stored in the result token. |
1034 | | * |
1035 | | * A return value of false means the operation is invalid, and the |
1036 | | * result is undefined. |
1037 | | */ |
1038 | 50.3k | if (arg->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) { |
1039 | | /* pass through */ |
1040 | 32.4k | *result = *arg; |
1041 | 32.4k | return true; |
1042 | 32.4k | } |
1043 | | |
1044 | 17.9k | result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL; |
1045 | 17.9k | result->data.result.value = ACE_CONDITION_UNKNOWN; |
1046 | | |
1047 | 17.9k | if (IS_INT_TOKEN(arg)) { |
1048 | | /* zero is false */ |
1049 | 7.12k | if (arg->data.int64.value == 0) { |
1050 | 1.20k | result->data.result.value = ACE_CONDITION_FALSE; |
1051 | 5.92k | } else { |
1052 | 5.92k | result->data.result.value = ACE_CONDITION_TRUE; |
1053 | 5.92k | } |
1054 | 7.12k | return true; |
1055 | 7.12k | } |
1056 | 10.8k | if (arg->type == CONDITIONAL_ACE_TOKEN_UNICODE) { |
1057 | | /* empty is false */ |
1058 | 2.09k | if (arg->data.unicode.value[0] == '\0') { |
1059 | 1.34k | result->data.result.value = ACE_CONDITION_FALSE; |
1060 | 1.34k | } else { |
1061 | 747 | result->data.result.value = ACE_CONDITION_TRUE; |
1062 | 747 | } |
1063 | 2.09k | return true; |
1064 | 2.09k | } |
1065 | | |
1066 | | /* |
1067 | | * everything else in UNKNOWN. This includes NULL values (i.e. an |
1068 | | * unsuccessful look-up). |
1069 | | */ |
1070 | 8.71k | result->data.result.value = ACE_CONDITION_UNKNOWN; |
1071 | 8.71k | return true; |
1072 | 10.8k | } |
1073 | | |
1074 | | static bool not_operator( |
1075 | | const struct ace_condition_token *arg, |
1076 | | struct ace_condition_token *result) |
1077 | 23.6k | { |
1078 | 23.6k | bool ok; |
1079 | 23.6k | if (IS_LITERAL_TOKEN(arg)) { |
1080 | | /* |
1081 | | * Logic operators don't work on literals. |
1082 | | */ |
1083 | 68 | return false; |
1084 | 68 | } |
1085 | | |
1086 | 23.6k | ok = ternary_value(arg, result); |
1087 | 23.6k | if (! ok) { |
1088 | 0 | return false; |
1089 | 0 | } |
1090 | 23.6k | if (result->data.result.value == ACE_CONDITION_FALSE) { |
1091 | 7.60k | result->data.result.value = ACE_CONDITION_TRUE; |
1092 | 16.0k | } else if (result->data.result.value == ACE_CONDITION_TRUE) { |
1093 | 7.61k | result->data.result.value = ACE_CONDITION_FALSE; |
1094 | 7.61k | } |
1095 | | /* unknown stays unknown */ |
1096 | 23.6k | return true; |
1097 | 23.6k | } |
1098 | | |
1099 | | |
1100 | | static bool unary_logic_operator( |
1101 | | TALLOC_CTX *mem_ctx, |
1102 | | const struct security_token *token, |
1103 | | const struct ace_condition_token *op, |
1104 | | const struct ace_condition_token *arg, |
1105 | | const struct security_descriptor *sd, |
1106 | | struct ace_condition_token *result) |
1107 | 24.3k | { |
1108 | | |
1109 | 24.3k | bool ok; |
1110 | 24.3k | bool found; |
1111 | 24.3k | struct ace_condition_token claim = { |
1112 | 24.3k | .type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR |
1113 | 24.3k | }; |
1114 | 24.3k | if (op->type == CONDITIONAL_ACE_TOKEN_NOT) { |
1115 | 23.6k | return not_operator(arg, result); |
1116 | 23.6k | } |
1117 | 679 | result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL; |
1118 | 679 | result->data.result.value = ACE_CONDITION_UNKNOWN; |
1119 | | |
1120 | | /* |
1121 | | * Not_Exists and Exists require the same work, except we negate the |
1122 | | * answer in one case. From [MS-DTYP] 2.4.4.17.7: |
1123 | | * |
1124 | | * If the type of the operand is "Local Attribute" |
1125 | | * If the value is non-null return TRUE |
1126 | | * Else return FALSE |
1127 | | * Else if the type of the operand is "Resource Attribute" |
1128 | | * Return TRUE if value is non-null; FALSE otherwise. |
1129 | | * Else return Error |
1130 | | */ |
1131 | 679 | switch (op->type) { |
1132 | 0 | case CONDITIONAL_ACE_LOCAL_ATTRIBUTE: |
1133 | 0 | ok = token_claim_lookup(mem_ctx, token, arg, &claim); |
1134 | | /* |
1135 | | * "not ok" usually means a failure to find the attribute, |
1136 | | * which is the false condition and not an error. |
1137 | | * |
1138 | | * XXX or do we need an extra flag? |
1139 | | */ |
1140 | 0 | break; |
1141 | 0 | case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE: |
1142 | 0 | ok = resource_claim_lookup(mem_ctx, arg, sd, &claim); |
1143 | 0 | break; |
1144 | 679 | default: |
1145 | 679 | return false; |
1146 | 679 | } |
1147 | | |
1148 | | /* |
1149 | | * |
1150 | | */ |
1151 | | |
1152 | 0 | if (claim.type != CONDITIONAL_ACE_SAMBA_RESULT_NULL) { |
1153 | 0 | found = true; |
1154 | 0 | } else if (ok) { |
1155 | 0 | found = false; |
1156 | 0 | } else { |
1157 | 0 | return false; |
1158 | 0 | } |
1159 | | |
1160 | | |
1161 | | |
1162 | 0 | if (op->type == CONDITIONAL_ACE_TOKEN_NOT_EXISTS) { |
1163 | 0 | found = ! found; |
1164 | 0 | } else if (op->type != CONDITIONAL_ACE_TOKEN_EXISTS) { |
1165 | | /* should not get here */ |
1166 | 0 | return false; |
1167 | 0 | } |
1168 | | |
1169 | 0 | result->data.result.value = found ? ACE_CONDITION_TRUE: ACE_CONDITION_FALSE; |
1170 | 0 | return true; |
1171 | 0 | } |
1172 | | |
1173 | | |
1174 | | |
1175 | | static bool binary_logic_operator( |
1176 | | const struct security_token *token, |
1177 | | const struct ace_condition_token *op, |
1178 | | const struct ace_condition_token *lhs, |
1179 | | const struct ace_condition_token *rhs, |
1180 | | struct ace_condition_token *result) |
1181 | 12.9k | { |
1182 | 12.9k | struct ace_condition_token at, bt; |
1183 | 12.9k | int a, b; |
1184 | 12.9k | bool ok; |
1185 | | |
1186 | 12.9k | result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL; |
1187 | 12.9k | result->data.result.value = ACE_CONDITION_UNKNOWN; |
1188 | | |
1189 | 12.9k | if (IS_LITERAL_TOKEN(lhs) || IS_LITERAL_TOKEN(rhs)) { |
1190 | | /* |
1191 | | * Logic operators don't work on literals. |
1192 | | */ |
1193 | 263 | return false; |
1194 | 263 | } |
1195 | | |
1196 | 12.7k | ok = ternary_value(lhs, &at); |
1197 | 12.7k | if (! ok) { |
1198 | 0 | return false; |
1199 | 0 | } |
1200 | 12.7k | ok = ternary_value(rhs, &bt); |
1201 | 12.7k | if (! ok) { |
1202 | 0 | return false; |
1203 | 0 | } |
1204 | 12.7k | a = at.data.result.value; |
1205 | 12.7k | b = bt.data.result.value; |
1206 | | |
1207 | 12.7k | if (op->type == CONDITIONAL_ACE_TOKEN_AND) { |
1208 | | /* |
1209 | | * AND true false unknown |
1210 | | * true T F ? |
1211 | | * false F F F |
1212 | | * unknown ? F ? |
1213 | | * |
1214 | | * unknown unless BOTH true or EITHER false |
1215 | | */ |
1216 | 8.97k | if (a == ACE_CONDITION_TRUE && |
1217 | 1.93k | b == ACE_CONDITION_TRUE) { |
1218 | 585 | result->data.result.value = ACE_CONDITION_TRUE; |
1219 | 585 | return true; |
1220 | 585 | } |
1221 | 8.38k | if (a == ACE_CONDITION_FALSE || |
1222 | 7.04k | b == ACE_CONDITION_FALSE) { |
1223 | 2.96k | result->data.result.value = ACE_CONDITION_FALSE; |
1224 | 2.96k | return true; |
1225 | 2.96k | } |
1226 | | /* |
1227 | | * Neither value is False, so the result is Unknown, |
1228 | | * as set at the start of this function. |
1229 | | */ |
1230 | 5.42k | return true; |
1231 | 8.38k | } |
1232 | | /* |
1233 | | * OR true false unknown |
1234 | | * true T T T |
1235 | | * false T F ? |
1236 | | * unknown T ? ? |
1237 | | * |
1238 | | * unknown unless EITHER true or BOTH false |
1239 | | */ |
1240 | 3.72k | if (a == ACE_CONDITION_TRUE || |
1241 | 2.51k | b == ACE_CONDITION_TRUE) { |
1242 | 2.21k | result->data.result.value = ACE_CONDITION_TRUE; |
1243 | 2.21k | return true; |
1244 | 2.21k | } |
1245 | 1.51k | if (a == ACE_CONDITION_FALSE && |
1246 | 534 | b == ACE_CONDITION_FALSE) { |
1247 | 233 | result->data.result.value = ACE_CONDITION_FALSE; |
1248 | 233 | return true; |
1249 | 233 | } |
1250 | 1.28k | return true; |
1251 | 1.51k | } |
1252 | | |
1253 | | |
1254 | | static bool tokens_are_comparable(const struct ace_condition_token *op, |
1255 | | const struct ace_condition_token *lhs, |
1256 | | const struct ace_condition_token *rhs) |
1257 | 1.88k | { |
1258 | 1.88k | uint64_t n; |
1259 | | /* |
1260 | | * we can't compare different types *unless* they are both |
1261 | | * integers, or one is a bool and the other is an integer 0 or |
1262 | | * 1, and the operator is == or != (or NULL, which for convenience, |
1263 | | * is treated as ==). |
1264 | | */ |
1265 | | //XXX actually it says "literal integers", do we need to check flags? |
1266 | 1.88k | if (lhs->type == rhs->type) { |
1267 | 0 | return true; |
1268 | 0 | } |
1269 | | |
1270 | 1.88k | if (IS_INT_TOKEN(lhs) && IS_INT_TOKEN(rhs)) { |
1271 | | /* don't block e.g. comparing an int32 to an int64 */ |
1272 | 0 | return true; |
1273 | 0 | } |
1274 | | |
1275 | | /* is it == or != */ |
1276 | 1.88k | if (op != NULL && |
1277 | 1.88k | op->type != CONDITIONAL_ACE_TOKEN_EQUAL && |
1278 | 139 | op->type != CONDITIONAL_ACE_TOKEN_NOT_EQUAL) { |
1279 | 81 | return false; |
1280 | 81 | } |
1281 | | /* is one a bool and the other an int? */ |
1282 | 1.80k | if (IS_INT_TOKEN(lhs) && IS_BOOL_TOKEN(rhs)) { |
1283 | 113 | n = lhs->data.int64.value; |
1284 | 1.69k | } else if (IS_INT_TOKEN(rhs) && IS_BOOL_TOKEN(lhs)) { |
1285 | 1.11k | n = rhs->data.int64.value; |
1286 | 1.11k | } else { |
1287 | 580 | return false; |
1288 | 580 | } |
1289 | 1.22k | if (n == 0 || n == 1) { |
1290 | 776 | return true; |
1291 | 776 | } |
1292 | 447 | return false; |
1293 | 1.22k | } |
1294 | | |
1295 | | |
1296 | | static bool cmp_to_result(const struct ace_condition_token *op, |
1297 | | struct ace_condition_token *result, |
1298 | | int cmp) |
1299 | 2.75k | { |
1300 | 2.75k | bool answer; |
1301 | 2.75k | switch (op->type) { |
1302 | 1.83k | case CONDITIONAL_ACE_TOKEN_EQUAL: |
1303 | 1.83k | answer = cmp == 0; |
1304 | 1.83k | break; |
1305 | 371 | case CONDITIONAL_ACE_TOKEN_NOT_EQUAL: |
1306 | 371 | answer = cmp != 0; |
1307 | 371 | break; |
1308 | 171 | case CONDITIONAL_ACE_TOKEN_LESS_THAN: |
1309 | 171 | answer = cmp < 0; |
1310 | 171 | break; |
1311 | 97 | case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL: |
1312 | 97 | answer = cmp <= 0; |
1313 | 97 | break; |
1314 | 175 | case CONDITIONAL_ACE_TOKEN_GREATER_THAN: |
1315 | 175 | answer = cmp > 0; |
1316 | 175 | break; |
1317 | 110 | case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL: |
1318 | 110 | answer = cmp >= 0; |
1319 | 110 | break; |
1320 | 0 | default: |
1321 | 0 | result->data.result.value = ACE_CONDITION_UNKNOWN; |
1322 | 0 | return false; |
1323 | 2.75k | } |
1324 | 2.75k | result->data.result.value = \ |
1325 | 2.75k | answer ? ACE_CONDITION_TRUE : ACE_CONDITION_FALSE; |
1326 | 2.75k | return true; |
1327 | 2.75k | } |
1328 | | |
1329 | | |
1330 | | |
1331 | | static bool compare_unicode(const struct ace_condition_token *op, |
1332 | | const struct ace_condition_token *lhs, |
1333 | | const struct ace_condition_token *rhs, |
1334 | | int *cmp) |
1335 | 15.1k | { |
1336 | 15.1k | struct ace_condition_unicode a = lhs->data.unicode; |
1337 | 15.1k | struct ace_condition_unicode b = rhs->data.unicode; |
1338 | | /* |
1339 | | * Comparison is case-insensitive UNLESS the claim structure |
1340 | | * has the case-sensitive flag, which is passed through as a |
1341 | | * flag on the token. Usually only the LHS is a claim value, |
1342 | | * but in the event that they both are, we allow either to |
1343 | | * request case-sensitivity. |
1344 | | * |
1345 | | * For greater than and less than, the sort order is utf-8 order, |
1346 | | * which is not exactly what Windows does, but we don't sort like |
1347 | | * Windows does anywhere else either. |
1348 | | */ |
1349 | 15.1k | uint8_t flags = lhs->flags | rhs->flags; |
1350 | 15.1k | if (flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE) { |
1351 | 9.72k | *cmp = strcmp(a.value, b.value); |
1352 | 9.72k | } else { |
1353 | 5.43k | *cmp = strcasecmp_m(a.value, b.value); |
1354 | 5.43k | } |
1355 | 15.1k | return true; |
1356 | 15.1k | } |
1357 | | |
1358 | | |
1359 | | static bool compare_bytes(const struct ace_condition_token *op, |
1360 | | const struct ace_condition_token *lhs, |
1361 | | const struct ace_condition_token *rhs, |
1362 | | int *cmp) |
1363 | 4.80k | { |
1364 | 4.80k | DATA_BLOB a = lhs->data.bytes; |
1365 | 4.80k | DATA_BLOB b = rhs->data.bytes; |
1366 | 4.80k | *cmp = data_blob_cmp(&a, &b); |
1367 | 4.80k | return true; |
1368 | 4.80k | } |
1369 | | |
1370 | | |
1371 | | static bool compare_sids(const struct ace_condition_token *op, |
1372 | | const struct ace_condition_token *lhs, |
1373 | | const struct ace_condition_token *rhs, |
1374 | | int *cmp) |
1375 | 1.13k | { |
1376 | 1.13k | *cmp = dom_sid_compare(&lhs->data.sid.sid, |
1377 | 1.13k | &rhs->data.sid.sid); |
1378 | 1.13k | return true; |
1379 | 1.13k | } |
1380 | | |
1381 | | |
1382 | | static bool compare_ints(const struct ace_condition_token *op, |
1383 | | const struct ace_condition_token *lhs, |
1384 | | const struct ace_condition_token *rhs, |
1385 | | int *cmp) |
1386 | 13.9k | { |
1387 | 13.9k | int64_t a = lhs->data.int64.value; |
1388 | 13.9k | int64_t b = rhs->data.int64.value; |
1389 | | |
1390 | 13.9k | if (a < b) { |
1391 | 3.60k | *cmp = -1; |
1392 | 10.3k | } else if (a == b) { |
1393 | 5.92k | *cmp = 0; |
1394 | 5.92k | } else { |
1395 | 4.39k | *cmp = 1; |
1396 | 4.39k | } |
1397 | 13.9k | return true; |
1398 | 13.9k | } |
1399 | | |
1400 | | |
1401 | | static bool compare_bools(const struct ace_condition_token *op, |
1402 | | const struct ace_condition_token *lhs, |
1403 | | const struct ace_condition_token *rhs, |
1404 | | int *cmp) |
1405 | 779 | { |
1406 | 779 | bool ok; |
1407 | 779 | struct ace_condition_token a, b; |
1408 | 779 | *cmp = -1; |
1409 | | |
1410 | 779 | if (IS_LITERAL_TOKEN(lhs)) { |
1411 | | /* |
1412 | | * we can compare a boolean LHS to a literal RHS, but not |
1413 | | * vice versa |
1414 | | */ |
1415 | 97 | return false; |
1416 | 97 | } |
1417 | 682 | ok = ternary_value(lhs, &a); |
1418 | 682 | if (! ok) { |
1419 | 0 | return false; |
1420 | 0 | } |
1421 | 682 | ok = ternary_value(rhs, &b); |
1422 | 682 | if (! ok) { |
1423 | 0 | return false; |
1424 | 0 | } |
1425 | 682 | if (a.data.result.value == ACE_CONDITION_UNKNOWN || |
1426 | 617 | b.data.result.value == ACE_CONDITION_UNKNOWN) { |
1427 | 65 | return false; |
1428 | 65 | } |
1429 | | |
1430 | 617 | switch (op->type) { |
1431 | 617 | case CONDITIONAL_ACE_TOKEN_EQUAL: |
1432 | 617 | case CONDITIONAL_ACE_TOKEN_NOT_EQUAL: |
1433 | 617 | *cmp = a.data.result.value - b.data.result.value; |
1434 | 617 | break; |
1435 | 0 | default: |
1436 | | /* we are not allowing non-equality comparisons with bools */ |
1437 | 0 | return false; |
1438 | 617 | } |
1439 | 617 | return true; |
1440 | 617 | } |
1441 | | |
1442 | | |
1443 | | static bool simple_relational_operator(const struct ace_condition_token *op, |
1444 | | const struct ace_condition_token *lhs, |
1445 | | const struct ace_condition_token *rhs, |
1446 | | int *cmp); |
1447 | | |
1448 | | |
1449 | | struct composite_sort_context { |
1450 | | bool failed; |
1451 | | }; |
1452 | | |
1453 | | static int composite_sort_cmp(const struct ace_condition_token *lhs, |
1454 | | const struct ace_condition_token *rhs, |
1455 | | struct composite_sort_context *ctx) |
1456 | 0 | { |
1457 | 0 | bool ok; |
1458 | 0 | int cmp = -1; |
1459 | | /* |
1460 | | * simple_relational_operator uses the operator token only to |
1461 | | * decide whether the comparison is allowed for the type. In |
1462 | | * particular, boolean result and composite arguments can only |
1463 | | * be used with equality operators. We want those to fail (we |
1464 | | * should not see them here, remembering that claim booleans |
1465 | | * become composite integers), so we use a non-equality op. |
1466 | | */ |
1467 | 0 | static const struct ace_condition_token op = { |
1468 | 0 | .type = CONDITIONAL_ACE_TOKEN_LESS_THAN |
1469 | 0 | }; |
1470 | |
|
1471 | 0 | ok = simple_relational_operator(&op, lhs, rhs, &cmp); |
1472 | 0 | if (ok) { |
1473 | 0 | return cmp; |
1474 | 0 | } |
1475 | | /* |
1476 | | * This sort isn't going to work out, but the sort function |
1477 | | * will only find out at the end. |
1478 | | */ |
1479 | 0 | ctx->failed = true; |
1480 | 0 | return cmp; |
1481 | 0 | } |
1482 | | |
1483 | | |
1484 | | /* |
1485 | | * Return a sorted copy of the composite tokens array. |
1486 | | * |
1487 | | * The copy is shallow, so the actual string pointers are the same, which is |
1488 | | * fine for the purposes of comparison. |
1489 | | */ |
1490 | | |
1491 | | static struct ace_condition_token *composite_sorted_copy( |
1492 | | TALLOC_CTX *mem_ctx, |
1493 | | const struct ace_condition_composite *c, |
1494 | | bool case_sensitive) |
1495 | 0 | { |
1496 | 0 | struct ace_condition_token *copy = NULL; |
1497 | 0 | bool ok; |
1498 | 0 | size_t i; |
1499 | 0 | struct composite_sort_context sort_ctx = { |
1500 | 0 | .failed = false |
1501 | 0 | }; |
1502 | | |
1503 | | /* |
1504 | | * Case sensitivity is a bit tricky. Each token can have a flag saying |
1505 | | * it should be sorted case-sensitively and when comparing two tokens, |
1506 | | * we should respect this flag on either side. The flag can only come |
1507 | | * from claims (including resource attribute ACEs), and as there is only |
1508 | | * one flag per claim, it must apply the same to all members (in fact we |
1509 | | * don't set it on the members, only the composite). So to be sure we |
1510 | | * sort in the way we want, we might need to set the flag on all the |
1511 | | * members of the copy *before* sorting it. |
1512 | | * |
1513 | | * When it comes to comparing two composites, we want to be |
1514 | | * case-sensitive if either side has the flag. This can have odd |
1515 | | * effects. Think of these RA claims: |
1516 | | * |
1517 | | * (RA;;;;;WD;("foo",TS,0,"a","A")) |
1518 | | * (RA;;;;;WD;("bar",TS,2,"a","A")) <-- 2 is the case-sensitive flag |
1519 | | * (RA;;;;;WD;("baz",TS,0,"a")) |
1520 | | * |
1521 | | * (@Resource.foo == @Resource.bar) is true |
1522 | | * (@Resource.bar == @Resource.foo) is true |
1523 | | * (@Resource.bar == @Resource.bar) is true |
1524 | | * (@Resource.foo == @Resource.foo) is an error (duplicate values on LHS) |
1525 | | * (@Resource.baz == @Resource.foo) is true (RHS case-folds down) |
1526 | | * (@Resource.baz == @Resource.bar) is false |
1527 | | * (@Resource.bar == {"A", "a"}) is true |
1528 | | * (@Resource.baz == {"A", "a"}) is true |
1529 | | * (@Resource.foo == {"A", "a"}) is an error |
1530 | | */ |
1531 | 0 | copy = talloc_array(mem_ctx, struct ace_condition_token, c->n_members); |
1532 | 0 | if (copy == NULL) { |
1533 | 0 | return NULL; |
1534 | 0 | } |
1535 | 0 | memcpy(copy, c->tokens, sizeof(struct ace_condition_token) * c->n_members); |
1536 | |
|
1537 | 0 | if (case_sensitive) { |
1538 | 0 | for (i = 0; i < c->n_members; i++) { |
1539 | 0 | c->tokens[i].flags |= CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE; |
1540 | 0 | } |
1541 | 0 | } |
1542 | |
|
1543 | 0 | ok = stable_sort_talloc_r(mem_ctx, |
1544 | 0 | copy, |
1545 | 0 | c->n_members, |
1546 | 0 | sizeof(struct ace_condition_token), |
1547 | 0 | (samba_compare_with_context_fn_t)composite_sort_cmp, |
1548 | 0 | &sort_ctx); |
1549 | |
|
1550 | 0 | if (!ok || sort_ctx.failed) { |
1551 | 0 | DBG_NOTICE("composite sort of %"PRIu32" members failed\n", |
1552 | 0 | c->n_members); |
1553 | 0 | TALLOC_FREE(copy); |
1554 | 0 | return NULL; |
1555 | 0 | } |
1556 | 0 | return copy; |
1557 | 0 | } |
1558 | | |
1559 | | |
1560 | | /* |
1561 | | * This is a helper for compare composites. |
1562 | | */ |
1563 | | static bool compare_composites_via_sort(const struct ace_condition_token *lhs, |
1564 | | const struct ace_condition_token *rhs, |
1565 | | int *cmp) |
1566 | 1.60k | { |
1567 | 1.60k | const struct ace_condition_composite *lc = &lhs->data.composite; |
1568 | 1.60k | const struct ace_condition_composite *rc = &rhs->data.composite; |
1569 | 1.60k | size_t i; |
1570 | 1.60k | TALLOC_CTX *tmp_ctx = NULL; |
1571 | 1.60k | bool ok; |
1572 | 1.60k | int cmp_pair; |
1573 | 1.60k | bool case_sensitive, rhs_case_sensitive; |
1574 | 1.60k | bool rhs_sorted; |
1575 | 1.60k | struct ace_condition_token *ltok = lc->tokens; |
1576 | 1.60k | struct ace_condition_token *rtok = rc->tokens; |
1577 | 1.60k | static const struct ace_condition_token eq = { |
1578 | 1.60k | .type = CONDITIONAL_ACE_TOKEN_EQUAL |
1579 | 1.60k | }; |
1580 | 1.60k | *cmp = -1; |
1581 | 1.60k | if (lc->n_members == 0 || |
1582 | 1.60k | rc->n_members < lc->n_members) { |
1583 | | /* we should not have got this far */ |
1584 | 0 | return false; |
1585 | 0 | } |
1586 | | |
1587 | 1.60k | tmp_ctx = talloc_new(NULL); |
1588 | 1.60k | if (tmp_ctx == NULL) { |
1589 | 0 | return false; |
1590 | 0 | } |
1591 | | |
1592 | 1.60k | case_sensitive = lhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE; |
1593 | 1.60k | rhs_case_sensitive = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE; |
1594 | 1.60k | rhs_sorted = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED; |
1595 | | |
1596 | 1.60k | if (lc->tokens[0].type != CONDITIONAL_ACE_TOKEN_UNICODE) { |
1597 | | /* |
1598 | | * All LHS tokens are the same type (because it is a |
1599 | | * claim), and that type is not one that cares about |
1600 | | * case, so nor do we. |
1601 | | */ |
1602 | 1.13k | case_sensitive = false; |
1603 | 1.13k | } else if (case_sensitive == rhs_case_sensitive) { |
1604 | | /* phew, no extra work */ |
1605 | 469 | } else if (case_sensitive) { |
1606 | | /* trigger a sorted copy */ |
1607 | 0 | rhs_sorted = false; |
1608 | 0 | } else if (rhs_case_sensitive) { |
1609 | | /* |
1610 | | * Do we need to rescan for uniqueness, given the new |
1611 | | * comparison function? No! The strings were already |
1612 | | * unique in the looser comparison, and now they can |
1613 | | * only be more so. The number of unique values can't |
1614 | | * change, just their order. |
1615 | | */ |
1616 | 0 | case_sensitive = true; |
1617 | 0 | ltok = composite_sorted_copy(tmp_ctx, lc, case_sensitive); |
1618 | 0 | if (ltok == NULL) { |
1619 | 0 | DBG_WARNING("sort of LHS failed\n"); |
1620 | 0 | goto error; |
1621 | 0 | } |
1622 | 0 | } |
1623 | | |
1624 | 1.60k | if (! rhs_sorted) { |
1625 | | /* |
1626 | | * we need an RHS sorted copy (it's a literal, or |
1627 | | * there was a case sensitivity disagreement). |
1628 | | */ |
1629 | 0 | rtok = composite_sorted_copy(tmp_ctx, rc, case_sensitive); |
1630 | 0 | if (rtok == NULL) { |
1631 | 0 | DBG_WARNING("sort of RHS failed\n"); |
1632 | 0 | goto error; |
1633 | 0 | } |
1634 | 0 | } |
1635 | | /* |
1636 | | * Each member of LHS must match one or more members of RHS. |
1637 | | * Each member of RHS must match at least one of LHS. |
1638 | | * |
1639 | | * If they are the same length we can compare directly, so let's get |
1640 | | * rid of duplicates in RHS. This can only happen with literal |
1641 | | * composites. |
1642 | | */ |
1643 | 1.60k | if (rc->n_members > lc->n_members) { |
1644 | 0 | size_t gap = 0; |
1645 | 0 | for (i = 1; i < rc->n_members; i++) { |
1646 | 0 | ok = simple_relational_operator(&eq, |
1647 | 0 | &rtok[i - 1], |
1648 | 0 | &rtok[i], |
1649 | 0 | &cmp_pair); |
1650 | 0 | if (! ok) { |
1651 | 0 | goto error; |
1652 | 0 | } |
1653 | 0 | if (cmp_pair == 0) { |
1654 | 0 | gap++; |
1655 | 0 | } |
1656 | 0 | if (gap != 0) { |
1657 | 0 | rtok[i - gap] = rtok[i]; |
1658 | 0 | } |
1659 | 0 | } |
1660 | 0 | if (rc->n_members - lc->n_members != gap) { |
1661 | | /* |
1662 | | * There were too many or too few duplicates to account |
1663 | | * for the difference, and no further comparison is |
1664 | | * necessary. |
1665 | | */ |
1666 | 0 | goto not_equal; |
1667 | 0 | } |
1668 | 0 | } |
1669 | | /* |
1670 | | * OK, now we know LHS and RHS are the same length and sorted in the |
1671 | | * same way, so we can just iterate over them and check each pair. |
1672 | | */ |
1673 | | |
1674 | 7.47k | for (i = 0; i < lc->n_members; i++) { |
1675 | 5.86k | ok = simple_relational_operator(&eq, |
1676 | 5.86k | <ok[i], |
1677 | 5.86k | &rtok[i], |
1678 | 5.86k | &cmp_pair); |
1679 | 5.86k | if (! ok){ |
1680 | 0 | goto error; |
1681 | 0 | } |
1682 | 5.86k | if (cmp_pair != 0) { |
1683 | 0 | goto not_equal; |
1684 | 0 | } |
1685 | 5.86k | } |
1686 | | |
1687 | 1.60k | *cmp = 0; |
1688 | | |
1689 | 1.60k | not_equal: |
1690 | 1.60k | TALLOC_FREE(tmp_ctx); |
1691 | 1.60k | return true; |
1692 | 0 | error: |
1693 | 0 | TALLOC_FREE(tmp_ctx); |
1694 | 0 | return false; |
1695 | 1.60k | } |
1696 | | |
1697 | | |
1698 | | static bool composite_is_comparable(const struct ace_condition_token *tok, |
1699 | | const struct ace_condition_token *comp) |
1700 | 0 | { |
1701 | | /* |
1702 | | * Are all members of the composite comparable to the token? |
1703 | | */ |
1704 | 0 | size_t i; |
1705 | 0 | const struct ace_condition_composite *rc = &comp->data.composite; |
1706 | 0 | size_t n = rc->n_members; |
1707 | |
|
1708 | 0 | if ((comp->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED) && |
1709 | 0 | n > 1) { |
1710 | | /* |
1711 | | * all members are known to be the same type, so we |
1712 | | * can just check one. |
1713 | | */ |
1714 | 0 | n = 1; |
1715 | 0 | } |
1716 | |
|
1717 | 0 | for (i = 0; i < n; i++) { |
1718 | 0 | if (! tokens_are_comparable(NULL, |
1719 | 0 | tok, |
1720 | 0 | &rc->tokens[i])) { |
1721 | 0 | DBG_NOTICE("token type %u != composite type %u\n", |
1722 | 0 | tok->type, rc->tokens[i].type); |
1723 | 0 | return false; |
1724 | 0 | } |
1725 | 0 | } |
1726 | 0 | return true; |
1727 | 0 | } |
1728 | | |
1729 | | |
1730 | | static bool compare_composites(const struct ace_condition_token *op, |
1731 | | const struct ace_condition_token *lhs, |
1732 | | const struct ace_condition_token *rhs, |
1733 | | int *cmp) |
1734 | 1.66k | { |
1735 | | /* |
1736 | | * This is for comparing multivalued sets, which includes |
1737 | | * conditional ACE composites and claim sets. Because these |
1738 | | * are sets, there are no < and > operations, just equality or |
1739 | | * otherwise. |
1740 | | * |
1741 | | * Claims are true sets, while composites are multisets -- |
1742 | | * duplicate values are allowed -- but these are reduced to |
1743 | | * sets in evaluation, and the number of duplicates has no |
1744 | | * effect in comparisons. Resource attribute ACEs live in an |
1745 | | * intermediate state -- they can contain duplicates on the |
1746 | | * wire and as ACE structures, but as soon as they are |
1747 | | * evaluated as claims their values must be unique. Windows |
1748 | | * will treat RA ACEs with duplicate values as not existing, |
1749 | | * rather than as UNKNOWN (This is significant for the Exists |
1750 | | * operator). Claims can have a case-sensitive flags set, |
1751 | | * meaning they must be compared case-sensitively. |
1752 | | * |
1753 | | * Some good news is that the LHS of a comparison must always |
1754 | | * be a claim. That means we can assume it has unique values |
1755 | | * when it comes to pairwise comparisons. Using the magic of |
1756 | | * flags, we try to check this only once per claim. |
1757 | | * |
1758 | | * Conditional ACE composites, which can have duplicates (and |
1759 | | * mixed types), can only be on the RHS. |
1760 | | * |
1761 | | * To summarise: |
1762 | | * |
1763 | | * {a, b} vs {a, b} equal |
1764 | | * { } vs { } equal |
1765 | | * {a, b} vs {b, a} equal |
1766 | | * {a, b} vs {a, c} not equal |
1767 | | * {a, b} vs {a, a, b} equal |
1768 | | * {b, a} vs {a, b, a} equal |
1769 | | * {a, b} vs {a, a, b, c} not equal |
1770 | | * {a, b, a} vs {a, b} should not happen, error |
1771 | | * {a, b, a} vs {a, b, a} should not happen, error |
1772 | | * |
1773 | | * mixed types: |
1774 | | * {1, 2} vs {1, "2"} error |
1775 | | * {1, "2"} vs {1, "2"} should not happen, error |
1776 | | * |
1777 | | * case sensitivity (*{ }* indicates case-sensitive flag): |
1778 | | * |
1779 | | * {"a", "b"} vs {"a", "B"} equal |
1780 | | * {"a", "b"} vs *{"a", "B"}* not equal |
1781 | | * *{"a", "b"}* vs {"a", "B"} not equal |
1782 | | * *{"a", "A"}* vs {"a", "A"} equal (if RHS is composite) |
1783 | | * {"a", "A"} vs *{"a", "A"}* impossible (LHS is not unique) |
1784 | | * *{"a"}* vs {"a", "A"} not equal |
1785 | | * |
1786 | | * The naive approach is of course O(n * m) with an additional O(n²) |
1787 | | * if the LHS values are not known to be unique (that is, in resource |
1788 | | * attribute claims). We want to avoid that with big sets. |
1789 | | */ |
1790 | 1.66k | const struct ace_condition_composite *lc = &lhs->data.composite; |
1791 | 1.66k | const struct ace_condition_composite *rc = &rhs->data.composite; |
1792 | 1.66k | bool ok; |
1793 | | |
1794 | 1.66k | if (!(lhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) { |
1795 | | /* |
1796 | | * The LHS needs to be a claim, and it should have gone |
1797 | | * through claim_v1_check_and_sort() to get here. |
1798 | | */ |
1799 | 0 | *cmp = -1; |
1800 | 0 | return false; |
1801 | 0 | } |
1802 | | |
1803 | | /* if one or both are empty, the answer is easy */ |
1804 | 1.66k | if (lc->n_members == 0) { |
1805 | 0 | if (rc->n_members == 0) { |
1806 | 0 | *cmp = 0; |
1807 | 0 | return true; |
1808 | 0 | } |
1809 | 0 | *cmp = -1; |
1810 | 0 | return true; |
1811 | 0 | } |
1812 | 1.66k | if (rc->n_members == 0) { |
1813 | 64 | *cmp = -1; |
1814 | 64 | return true; |
1815 | 64 | } |
1816 | | |
1817 | | /* |
1818 | | * LHS must be a claim, so it must be unique, so if there are |
1819 | | * fewer members on the RHS, we know they can't be equal. |
1820 | | * |
1821 | | * If you think about it too much, you might think this is |
1822 | | * affected by case sensitivity, but it isn't. One side can be |
1823 | | * infected by case-sensitivity by the other, but that can't |
1824 | | * shrink the number of elements on the RHS -- it can only |
1825 | | * make a literal {"a", "A"} have effective length 2 rather |
1826 | | * than 1. |
1827 | | * |
1828 | | * On the other hand, if the RHS is case sensitive, it must be |
1829 | | * a claim and unique in its own terms, and its finer-grained |
1830 | | * distinctions can't collapse members of the case sensitive |
1831 | | * LHS. |
1832 | | */ |
1833 | 1.60k | if (lc->n_members > rc->n_members) { |
1834 | 0 | *cmp = -1; |
1835 | 0 | return composite_is_comparable(&lc->tokens[0], rhs); |
1836 | 0 | } |
1837 | | |
1838 | | /* |
1839 | | * It *could* be that RHS is also unique and we know it. In that |
1840 | | * case we can short circuit if RHS has more members. This is |
1841 | | * the case when both sides are claims. |
1842 | | * |
1843 | | * This is also not affected by case-senstivity. |
1844 | | */ |
1845 | 1.60k | if (lc->n_members < rc->n_members && |
1846 | 0 | (rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) { |
1847 | 0 | *cmp = -1; |
1848 | 0 | return composite_is_comparable(&lc->tokens[0], rhs); |
1849 | 0 | } |
1850 | | |
1851 | 1.60k | ok = compare_composites_via_sort(lhs, rhs, cmp); |
1852 | 1.60k | if (! ok) { |
1853 | 0 | return false; |
1854 | 0 | } |
1855 | 1.60k | return true; |
1856 | 1.60k | } |
1857 | | |
1858 | | |
1859 | | static bool simple_relational_operator(const struct ace_condition_token *op, |
1860 | | const struct ace_condition_token *lhs, |
1861 | | const struct ace_condition_token *rhs, |
1862 | | int *cmp) |
1863 | | |
1864 | 38.5k | { |
1865 | 38.5k | if (lhs->type != rhs->type) { |
1866 | 1.88k | if (! tokens_are_comparable(op, lhs, rhs)) { |
1867 | 1.10k | return false; |
1868 | 1.10k | } |
1869 | 1.88k | } |
1870 | 37.4k | switch (lhs->type) { |
1871 | 0 | case CONDITIONAL_ACE_TOKEN_INT8: |
1872 | 0 | case CONDITIONAL_ACE_TOKEN_INT16: |
1873 | 0 | case CONDITIONAL_ACE_TOKEN_INT32: |
1874 | 14.0k | case CONDITIONAL_ACE_TOKEN_INT64: |
1875 | 14.0k | if (rhs->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) { |
1876 | 97 | return compare_bools(op, lhs, rhs, cmp); |
1877 | 97 | } |
1878 | 13.9k | return compare_ints(op, lhs, rhs, cmp); |
1879 | 682 | case CONDITIONAL_ACE_SAMBA_RESULT_BOOL: |
1880 | 682 | return compare_bools(op, lhs, rhs, cmp); |
1881 | 15.1k | case CONDITIONAL_ACE_TOKEN_UNICODE: |
1882 | 15.1k | return compare_unicode(op, lhs, rhs, cmp); |
1883 | 4.80k | case CONDITIONAL_ACE_TOKEN_OCTET_STRING: |
1884 | 4.80k | return compare_bytes(op, lhs, rhs, cmp); |
1885 | 1.13k | case CONDITIONAL_ACE_TOKEN_SID: |
1886 | 1.13k | return compare_sids(op, lhs, rhs, cmp); |
1887 | 1.66k | case CONDITIONAL_ACE_TOKEN_COMPOSITE: |
1888 | 1.66k | return compare_composites(op, lhs, rhs, cmp); |
1889 | 0 | case CONDITIONAL_ACE_SAMBA_RESULT_NULL: |
1890 | | /* leave the result unknown */ |
1891 | 0 | return false; |
1892 | 0 | default: |
1893 | 0 | DBG_ERR("did not expect ace type %u\n", lhs->type); |
1894 | 0 | return false; |
1895 | 37.4k | } |
1896 | | |
1897 | 0 | return false; |
1898 | 37.4k | } |
1899 | | |
1900 | | |
1901 | | static bool find_in_composite(const struct ace_condition_token *tok, |
1902 | | struct ace_condition_composite candidates, |
1903 | | bool *answer) |
1904 | 10.3k | { |
1905 | 10.3k | size_t i; |
1906 | 10.3k | int cmp; |
1907 | 10.3k | bool ok; |
1908 | 10.3k | const struct ace_condition_token equals = { |
1909 | 10.3k | .type = CONDITIONAL_ACE_TOKEN_EQUAL |
1910 | 10.3k | }; |
1911 | | |
1912 | 10.3k | *answer = false; |
1913 | | |
1914 | 30.4k | for (i = 0; i < candidates.n_members; i++) { |
1915 | 28.5k | ok = simple_relational_operator(&equals, |
1916 | 28.5k | tok, |
1917 | 28.5k | &candidates.tokens[i], |
1918 | 28.5k | &cmp); |
1919 | 28.5k | if (! ok) { |
1920 | 641 | return false; |
1921 | 641 | } |
1922 | 27.9k | if (cmp == 0) { |
1923 | 7.76k | *answer = true; |
1924 | 7.76k | return true; |
1925 | 7.76k | } |
1926 | 27.9k | } |
1927 | 1.91k | return true; |
1928 | 10.3k | } |
1929 | | |
1930 | | |
1931 | | static bool contains_operator(const struct ace_condition_token *lhs, |
1932 | | const struct ace_condition_token *rhs, |
1933 | | bool *answer) |
1934 | 3.78k | { |
1935 | 3.78k | size_t i; |
1936 | 3.78k | bool ok; |
1937 | 3.78k | int cmp; |
1938 | 3.78k | const struct ace_condition_token equals = { |
1939 | 3.78k | .type = CONDITIONAL_ACE_TOKEN_EQUAL |
1940 | 3.78k | }; |
1941 | | |
1942 | | /* |
1943 | | * All the required objects must be identical to something in |
1944 | | * candidates. But what do we mean by *identical*? We'll use |
1945 | | * the equality operator to decide that. |
1946 | | * |
1947 | | * Both the lhs or rhs can be solitary objects or composites. |
1948 | | * This makes it a bit fiddlier. |
1949 | | * |
1950 | | * NOTE: this operator does not take advantage of the |
1951 | | * CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED flag. It could, but it |
1952 | | * doesn't. |
1953 | | */ |
1954 | 3.78k | if (lhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) { |
1955 | 2.84k | struct ace_condition_composite candidates = lhs->data.composite; |
1956 | 2.84k | struct ace_condition_composite required; |
1957 | 2.84k | if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) { |
1958 | 804 | return find_in_composite(rhs, candidates, answer); |
1959 | 804 | } |
1960 | 2.03k | required = rhs->data.composite; |
1961 | 2.03k | if (required.n_members == 0) { |
1962 | 53 | return false; |
1963 | 53 | } |
1964 | 9.29k | for (i = 0; i < required.n_members; i++) { |
1965 | 7.30k | const struct ace_condition_token *t = &required.tokens[i]; |
1966 | 7.30k | ok = find_in_composite(t, candidates, answer); |
1967 | 7.30k | if (! ok) { |
1968 | 0 | return false; |
1969 | 0 | } |
1970 | 7.30k | if (! *answer) { |
1971 | | /* |
1972 | | * one required item was not there, |
1973 | | * *answer is false |
1974 | | */ |
1975 | 0 | return true; |
1976 | 0 | } |
1977 | 7.30k | } |
1978 | | /* all required items are there, *answer will be true */ |
1979 | 1.98k | return true; |
1980 | 1.98k | } |
1981 | | /* LHS is a single item */ |
1982 | 946 | if (rhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) { |
1983 | | /* |
1984 | | * There could be more than one RHS member that is |
1985 | | * equal to the single LHS value, so it doesn't help |
1986 | | * to compare lengths or anything. |
1987 | | */ |
1988 | 130 | struct ace_condition_composite required = rhs->data.composite; |
1989 | 130 | if (required.n_members == 0) { |
1990 | 55 | return false; |
1991 | 55 | } |
1992 | 97 | for (i = 0; i < required.n_members; i++) { |
1993 | 93 | ok = simple_relational_operator(&equals, |
1994 | 93 | lhs, |
1995 | 93 | &required.tokens[i], |
1996 | 93 | &cmp); |
1997 | 93 | if (! ok) { |
1998 | 66 | return false; |
1999 | 66 | } |
2000 | 27 | if (cmp != 0) { |
2001 | | /* |
2002 | | * one required item was not there, |
2003 | | * *answer is false |
2004 | | */ |
2005 | 5 | *answer = false; |
2006 | 5 | return true; |
2007 | 5 | } |
2008 | 27 | } |
2009 | 4 | *answer = true; |
2010 | 4 | return true; |
2011 | 75 | } |
2012 | | /* LHS and RHS are both single */ |
2013 | 816 | ok = simple_relational_operator(&equals, |
2014 | 816 | lhs, |
2015 | 816 | rhs, |
2016 | 816 | &cmp); |
2017 | 816 | if (! ok) { |
2018 | 218 | return false; |
2019 | 218 | } |
2020 | 598 | *answer = (cmp == 0); |
2021 | 598 | return true; |
2022 | 816 | } |
2023 | | |
2024 | | |
2025 | | static bool any_of_operator(const struct ace_condition_token *lhs, |
2026 | | const struct ace_condition_token *rhs, |
2027 | | bool *answer) |
2028 | 1.23k | { |
2029 | 1.23k | size_t i; |
2030 | 1.23k | bool ok; |
2031 | 1.23k | int cmp; |
2032 | 1.23k | const struct ace_condition_token equals = { |
2033 | 1.23k | .type = CONDITIONAL_ACE_TOKEN_EQUAL |
2034 | 1.23k | }; |
2035 | | |
2036 | | /* |
2037 | | * There has to be *some* overlap between the LHS and RHS. |
2038 | | * Both sides can be solitary objects or composites. |
2039 | | * |
2040 | | * We can exploit this symmetry. |
2041 | | */ |
2042 | 1.23k | if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) { |
2043 | 401 | const struct ace_condition_token *tmp = lhs; |
2044 | 401 | lhs = rhs; |
2045 | 401 | rhs = tmp; |
2046 | 401 | } |
2047 | 1.23k | if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) { |
2048 | | /* both singles */ |
2049 | 256 | ok = simple_relational_operator(&equals, |
2050 | 256 | lhs, |
2051 | 256 | rhs, |
2052 | 256 | &cmp); |
2053 | 256 | if (! ok) { |
2054 | 134 | return false; |
2055 | 134 | } |
2056 | 122 | *answer = (cmp == 0); |
2057 | 122 | return true; |
2058 | 256 | } |
2059 | 981 | if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) { |
2060 | 650 | return find_in_composite(rhs, lhs->data.composite, answer); |
2061 | 650 | } |
2062 | | /* both are composites */ |
2063 | 331 | if (lhs->data.composite.n_members == 0) { |
2064 | 0 | return false; |
2065 | 0 | } |
2066 | 1.76k | for (i = 0; i < lhs->data.composite.n_members; i++) { |
2067 | 1.55k | ok = find_in_composite(&lhs->data.composite.tokens[i], |
2068 | 1.55k | rhs->data.composite, |
2069 | 1.55k | answer); |
2070 | 1.55k | if (! ok) { |
2071 | 0 | return false; |
2072 | 0 | } |
2073 | 1.55k | if (*answer) { |
2074 | | /* We have found one match, which is enough. */ |
2075 | 127 | return true; |
2076 | 127 | } |
2077 | 1.55k | } |
2078 | 204 | return true; |
2079 | 331 | } |
2080 | | |
2081 | | |
2082 | | static bool composite_relational_operator(const struct ace_condition_token *op, |
2083 | | const struct ace_condition_token *lhs, |
2084 | | const struct ace_condition_token *rhs, |
2085 | | struct ace_condition_token *result) |
2086 | 5.02k | { |
2087 | 5.02k | bool ok, answer; |
2088 | 5.02k | switch(op->type) { |
2089 | 1.76k | case CONDITIONAL_ACE_TOKEN_CONTAINS: |
2090 | 3.78k | case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS: |
2091 | 3.78k | ok = contains_operator(lhs, rhs, &answer); |
2092 | 3.78k | break; |
2093 | 377 | case CONDITIONAL_ACE_TOKEN_ANY_OF: |
2094 | 1.23k | case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF: |
2095 | 1.23k | ok = any_of_operator(lhs, rhs, &answer); |
2096 | 1.23k | break; |
2097 | 0 | default: |
2098 | 0 | return false; |
2099 | 5.02k | } |
2100 | 5.02k | if (!ok) { |
2101 | 1.16k | return false; |
2102 | 1.16k | } |
2103 | | |
2104 | | /* negate the NOTs */ |
2105 | 3.85k | if (op->type == CONDITIONAL_ACE_TOKEN_NOT_CONTAINS || |
2106 | 2.35k | op->type == CONDITIONAL_ACE_TOKEN_NOT_ANY_OF) |
2107 | 2.10k | { |
2108 | 2.10k | answer = !answer; |
2109 | 2.10k | } |
2110 | | |
2111 | 3.85k | if (answer) { |
2112 | 2.22k | result->data.result.value = ACE_CONDITION_TRUE; |
2113 | 2.22k | } else { |
2114 | 1.63k | result->data.result.value = ACE_CONDITION_FALSE; |
2115 | 1.63k | } |
2116 | 3.85k | return true; |
2117 | 5.02k | } |
2118 | | |
2119 | | |
2120 | | static bool relational_operator( |
2121 | | const struct security_token *token, |
2122 | | const struct ace_condition_token *op, |
2123 | | const struct ace_condition_token *lhs, |
2124 | | const struct ace_condition_token *rhs, |
2125 | | struct ace_condition_token *result) |
2126 | 9.53k | { |
2127 | 9.53k | int cmp; |
2128 | 9.53k | bool ok; |
2129 | 9.53k | result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL; |
2130 | 9.53k | result->data.result.value = ACE_CONDITION_UNKNOWN; |
2131 | | |
2132 | 9.53k | if ((lhs->flags & CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR) == 0) { |
2133 | | /* LHS was not derived from an attribute */ |
2134 | 1.09k | return false; |
2135 | 1.09k | } |
2136 | | |
2137 | | /* |
2138 | | * This first nested switch is ensuring that >, >=, <, <= are |
2139 | | * not being tried on tokens that are not numbers, strings, or |
2140 | | * octet strings. Equality operators are available for all types. |
2141 | | */ |
2142 | 8.43k | switch (lhs->type) { |
2143 | 0 | case CONDITIONAL_ACE_TOKEN_INT8: |
2144 | 0 | case CONDITIONAL_ACE_TOKEN_INT16: |
2145 | 0 | case CONDITIONAL_ACE_TOKEN_INT32: |
2146 | 1.30k | case CONDITIONAL_ACE_TOKEN_INT64: |
2147 | 2.05k | case CONDITIONAL_ACE_TOKEN_UNICODE: |
2148 | 2.47k | case CONDITIONAL_ACE_TOKEN_OCTET_STRING: |
2149 | 2.47k | break; |
2150 | 5.95k | default: |
2151 | 5.95k | switch(op->type) { |
2152 | 130 | case CONDITIONAL_ACE_TOKEN_LESS_THAN: |
2153 | 162 | case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL: |
2154 | 408 | case CONDITIONAL_ACE_TOKEN_GREATER_THAN: |
2155 | 440 | case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL: |
2156 | 440 | return false; |
2157 | 5.51k | default: |
2158 | 5.51k | break; |
2159 | 5.95k | } |
2160 | 8.43k | } |
2161 | | |
2162 | | /* |
2163 | | * Dispatch according to operator type. |
2164 | | */ |
2165 | 7.99k | switch (op->type) { |
2166 | 1.90k | case CONDITIONAL_ACE_TOKEN_EQUAL: |
2167 | 2.33k | case CONDITIONAL_ACE_TOKEN_NOT_EQUAL: |
2168 | 2.53k | case CONDITIONAL_ACE_TOKEN_LESS_THAN: |
2169 | 2.64k | case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL: |
2170 | 2.84k | case CONDITIONAL_ACE_TOKEN_GREATER_THAN: |
2171 | 2.97k | case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL: |
2172 | 2.97k | ok = simple_relational_operator(op, |
2173 | 2.97k | lhs, |
2174 | 2.97k | rhs, |
2175 | 2.97k | &cmp); |
2176 | 2.97k | if (ok) { |
2177 | 2.75k | ok = cmp_to_result(op, result, cmp); |
2178 | 2.75k | } |
2179 | 2.97k | return ok; |
2180 | | |
2181 | 1.76k | case CONDITIONAL_ACE_TOKEN_CONTAINS: |
2182 | 2.14k | case CONDITIONAL_ACE_TOKEN_ANY_OF: |
2183 | 4.16k | case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS: |
2184 | 5.02k | case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF: |
2185 | 5.02k | return composite_relational_operator(op, |
2186 | 5.02k | lhs, |
2187 | 5.02k | rhs, |
2188 | 5.02k | result); |
2189 | 0 | default: |
2190 | 0 | return false; |
2191 | 7.99k | } |
2192 | 7.99k | } |
2193 | | |
2194 | | |
2195 | | int run_conditional_ace(TALLOC_CTX *mem_ctx, |
2196 | | const struct security_token *token, |
2197 | | struct ace_condition_script *program, |
2198 | | const struct security_descriptor *sd) |
2199 | 24.4k | { |
2200 | 24.4k | size_t i; |
2201 | 24.4k | size_t depth = 0; |
2202 | 24.4k | struct ace_condition_token *lhs = NULL; |
2203 | 24.4k | struct ace_condition_token *rhs = NULL; |
2204 | 24.4k | struct ace_condition_token result = {}; |
2205 | 24.4k | struct ace_condition_token *stack = NULL; |
2206 | 24.4k | bool ok; |
2207 | | |
2208 | | /* |
2209 | | * When interpreting the program we will need a stack, which in the |
2210 | | * very worst case can be as deep as the program is long. |
2211 | | */ |
2212 | 24.4k | stack = talloc_array(mem_ctx, |
2213 | 24.4k | struct ace_condition_token, |
2214 | 24.4k | program->length + 1); |
2215 | 24.4k | if (stack == NULL) { |
2216 | 0 | goto error; |
2217 | 0 | } |
2218 | | |
2219 | 117k | for (i = 0; i < program->length; i++) { |
2220 | 107k | struct ace_condition_token *tok = &program->tokens[i]; |
2221 | 107k | switch (tok->type) { |
2222 | 233 | case CONDITIONAL_ACE_TOKEN_INT8: |
2223 | 1.47k | case CONDITIONAL_ACE_TOKEN_INT16: |
2224 | 3.66k | case CONDITIONAL_ACE_TOKEN_INT32: |
2225 | 6.85k | case CONDITIONAL_ACE_TOKEN_INT64: |
2226 | 11.0k | case CONDITIONAL_ACE_TOKEN_UNICODE: |
2227 | 14.9k | case CONDITIONAL_ACE_TOKEN_OCTET_STRING: |
2228 | 18.1k | case CONDITIONAL_ACE_TOKEN_SID: |
2229 | 24.1k | case CONDITIONAL_ACE_TOKEN_COMPOSITE: |
2230 | | /* just plonk these literals on the stack */ |
2231 | 24.1k | stack[depth] = *tok; |
2232 | 24.1k | depth++; |
2233 | 24.1k | break; |
2234 | | |
2235 | 183 | case CONDITIONAL_ACE_LOCAL_ATTRIBUTE: |
2236 | 234 | case CONDITIONAL_ACE_USER_ATTRIBUTE: |
2237 | 412 | case CONDITIONAL_ACE_DEVICE_ATTRIBUTE: |
2238 | 412 | ok = token_claim_lookup(mem_ctx, token, tok, &result); |
2239 | 412 | if (! ok) { |
2240 | 412 | goto error; |
2241 | 412 | } |
2242 | 0 | stack[depth] = result; |
2243 | 0 | depth++; |
2244 | 0 | break; |
2245 | | |
2246 | 28.6k | case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE: |
2247 | 28.6k | ok = resource_claim_lookup(mem_ctx, |
2248 | 28.6k | tok, |
2249 | 28.6k | sd, |
2250 | 28.6k | &result); |
2251 | 28.6k | if (! ok) { |
2252 | 5.87k | goto error; |
2253 | 5.87k | } |
2254 | 22.8k | stack[depth] = result; |
2255 | 22.8k | depth++; |
2256 | 22.8k | break; |
2257 | | |
2258 | 388 | case CONDITIONAL_ACE_TOKEN_MEMBER_OF: |
2259 | 999 | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF: |
2260 | 1.58k | case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY: |
2261 | 2.68k | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY: |
2262 | 3.34k | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF: |
2263 | 3.68k | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF: |
2264 | 4.40k | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY: |
2265 | 4.67k | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY: |
2266 | 4.67k | if (depth == 0) { |
2267 | 290 | goto error; |
2268 | 290 | } |
2269 | 4.38k | depth--; |
2270 | 4.38k | lhs = &stack[depth]; |
2271 | 4.38k | ok = member_lookup(token, tok, lhs, &result); |
2272 | 4.38k | if (! ok) { |
2273 | 1.21k | goto error; |
2274 | 1.21k | } |
2275 | 3.17k | stack[depth] = result; |
2276 | 3.17k | depth++; |
2277 | 3.17k | break; |
2278 | | /* binary relational operators */ |
2279 | 3.13k | case CONDITIONAL_ACE_TOKEN_EQUAL: |
2280 | 3.70k | case CONDITIONAL_ACE_TOKEN_NOT_EQUAL: |
2281 | 4.20k | case CONDITIONAL_ACE_TOKEN_LESS_THAN: |
2282 | 4.39k | case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL: |
2283 | 5.04k | case CONDITIONAL_ACE_TOKEN_GREATER_THAN: |
2284 | 5.42k | case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL: |
2285 | 7.43k | case CONDITIONAL_ACE_TOKEN_CONTAINS: |
2286 | 7.89k | case CONDITIONAL_ACE_TOKEN_ANY_OF: |
2287 | 10.0k | case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS: |
2288 | 11.1k | case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF: |
2289 | 11.1k | if (depth < 2) { |
2290 | 1.60k | goto error; |
2291 | 1.60k | } |
2292 | 9.53k | depth--; |
2293 | 9.53k | rhs = &stack[depth]; |
2294 | 9.53k | depth--; |
2295 | 9.53k | lhs = &stack[depth]; |
2296 | 9.53k | ok = relational_operator(token, tok, lhs, rhs, &result); |
2297 | 9.53k | if (! ok) { |
2298 | 2.91k | goto error; |
2299 | 2.91k | } |
2300 | 6.61k | stack[depth] = result; |
2301 | 6.61k | depth++; |
2302 | 6.61k | break; |
2303 | | /* unary logical operators */ |
2304 | 662 | case CONDITIONAL_ACE_TOKEN_EXISTS: |
2305 | 734 | case CONDITIONAL_ACE_TOKEN_NOT_EXISTS: |
2306 | 24.4k | case CONDITIONAL_ACE_TOKEN_NOT: |
2307 | 24.4k | if (depth == 0) { |
2308 | 69 | goto error; |
2309 | 69 | } |
2310 | 24.3k | depth--; |
2311 | 24.3k | lhs = &stack[depth]; |
2312 | 24.3k | ok = unary_logic_operator(mem_ctx, token, tok, lhs, sd, &result); |
2313 | 24.3k | if (!ok) { |
2314 | 747 | goto error; |
2315 | 747 | } |
2316 | 23.6k | stack[depth] = result; |
2317 | 23.6k | depth++; |
2318 | 23.6k | break; |
2319 | | /* binary logical operators */ |
2320 | 9.51k | case CONDITIONAL_ACE_TOKEN_AND: |
2321 | 13.5k | case CONDITIONAL_ACE_TOKEN_OR: |
2322 | 13.5k | if (depth < 2) { |
2323 | 585 | goto error; |
2324 | 585 | } |
2325 | 12.9k | depth--; |
2326 | 12.9k | rhs = &stack[depth]; |
2327 | 12.9k | depth--; |
2328 | 12.9k | lhs = &stack[depth]; |
2329 | 12.9k | ok = binary_logic_operator(token, tok, lhs, rhs, &result); |
2330 | 12.9k | if (! ok) { |
2331 | 263 | goto error; |
2332 | 263 | } |
2333 | 12.7k | stack[depth] = result; |
2334 | 12.7k | depth++; |
2335 | 12.7k | break; |
2336 | 0 | default: |
2337 | 0 | goto error; |
2338 | 107k | } |
2339 | 107k | } |
2340 | | /* |
2341 | | * The evaluation should have left a single result value (true, false, |
2342 | | * or unknown) on the stack. If not, the expression was malformed. |
2343 | | */ |
2344 | 10.5k | if (depth != 1) { |
2345 | 3.21k | goto error; |
2346 | 3.21k | } |
2347 | 7.31k | result = stack[0]; |
2348 | 7.31k | if (result.type != CONDITIONAL_ACE_SAMBA_RESULT_BOOL) { |
2349 | 667 | goto error; |
2350 | 667 | } |
2351 | 6.64k | TALLOC_FREE(stack); |
2352 | 6.64k | return result.data.result.value; |
2353 | | |
2354 | 17.8k | error: |
2355 | | /* |
2356 | | * the result of an error is always UNKNOWN, which should be |
2357 | | * interpreted pessimistically, not allowing access. |
2358 | | */ |
2359 | 17.8k | TALLOC_FREE(stack); |
2360 | 17.8k | return ACE_CONDITION_UNKNOWN; |
2361 | 7.31k | } |
2362 | | |
2363 | | |
2364 | | /** access_check_conditional_ace() |
2365 | | * |
2366 | | * Run the conditional ACE from the blob form. Return false if it is |
2367 | | * not a valid conditional ACE, true if it is, even if there is some |
2368 | | * other error in running it. The *result parameter is set to |
2369 | | * ACE_CONDITION_FALSE, ACE_CONDITION_TRUE, or ACE_CONDITION_UNKNOWN. |
2370 | | * |
2371 | | * ACE_CONDITION_UNKNOWN should be treated pessimistically, as if it were |
2372 | | * TRUE for deny ACEs, and FALSE for allow ACEs. |
2373 | | * |
2374 | | * @param[in] ace - the ACE being processed. |
2375 | | * @param[in] token - the security token the ACE is processing. |
2376 | | * @param[out] result - a ternary result value. |
2377 | | * |
2378 | | * @return true if it is a valid conditional ACE. |
2379 | | */ |
2380 | | |
2381 | | bool access_check_conditional_ace(const struct security_ace *ace, |
2382 | | const struct security_token *token, |
2383 | | const struct security_descriptor *sd, |
2384 | | int *result) |
2385 | 46.2k | { |
2386 | 46.2k | TALLOC_CTX *tmp_ctx = talloc_new(NULL); |
2387 | 46.2k | struct ace_condition_script *program = NULL; |
2388 | 46.2k | program = parse_conditional_ace(tmp_ctx, ace->coda.conditions); |
2389 | 46.2k | if (program == NULL) { |
2390 | 21.7k | *result = ACE_CONDITION_UNKNOWN; |
2391 | 21.7k | TALLOC_FREE(tmp_ctx); |
2392 | 21.7k | return false; |
2393 | 21.7k | } |
2394 | | |
2395 | 24.4k | *result = run_conditional_ace(tmp_ctx, token, program, sd); |
2396 | | |
2397 | 24.4k | TALLOC_FREE(tmp_ctx); |
2398 | 24.4k | return true; |
2399 | 46.2k | } |
2400 | | |
2401 | | |
2402 | | bool conditional_ace_encode_binary(TALLOC_CTX *mem_ctx, |
2403 | | struct ace_condition_script *program, |
2404 | | DATA_BLOB *dest) |
2405 | 39.8k | { |
2406 | 39.8k | size_t i, j, alloc_size, required_size; |
2407 | 39.8k | uint8_t *data = NULL; |
2408 | 39.8k | uint8_t *new_data = NULL; |
2409 | 39.8k | *dest = (DATA_BLOB){NULL, 0}; |
2410 | | |
2411 | 39.8k | alloc_size = CONDITIONAL_ACE_MAX_LENGTH; |
2412 | 39.8k | data = talloc_array(mem_ctx, |
2413 | 39.8k | uint8_t, |
2414 | 39.8k | alloc_size); |
2415 | 39.8k | if (data == NULL) { |
2416 | 0 | return false; |
2417 | 0 | } |
2418 | | |
2419 | 39.8k | data[0] = 'a'; |
2420 | 39.8k | data[1] = 'r'; |
2421 | 39.8k | data[2] = 't'; |
2422 | 39.8k | data[3] = 'x'; |
2423 | | |
2424 | 39.8k | j = 4; |
2425 | 1.69M | for (i = 0; i < program->length; i++) { |
2426 | 1.65M | struct ace_condition_token *tok = &program->tokens[i]; |
2427 | 1.65M | ssize_t consumed; |
2428 | 1.65M | bool ok; |
2429 | | /* |
2430 | | * In all cases we write the token type byte. |
2431 | | */ |
2432 | 1.65M | data[j] = tok->type; |
2433 | 1.65M | j++; |
2434 | 1.65M | if (j >= alloc_size) { |
2435 | 27 | DBG_ERR("program exceeds %zu bytes\n", alloc_size); |
2436 | 27 | goto error; |
2437 | 27 | } |
2438 | | |
2439 | 1.65M | switch (tok->type) { |
2440 | 3.72k | case CONDITIONAL_ACE_TOKEN_MEMBER_OF: |
2441 | 7.58k | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF: |
2442 | 12.6k | case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY: |
2443 | 18.4k | case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY: |
2444 | 22.1k | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF: |
2445 | 46.0k | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF: |
2446 | 57.3k | case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY: |
2447 | 667k | case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY: |
2448 | 672k | case CONDITIONAL_ACE_TOKEN_EQUAL: |
2449 | 679k | case CONDITIONAL_ACE_TOKEN_NOT_EQUAL: |
2450 | 734k | case CONDITIONAL_ACE_TOKEN_LESS_THAN: |
2451 | 743k | case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL: |
2452 | 812k | case CONDITIONAL_ACE_TOKEN_GREATER_THAN: |
2453 | 820k | case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL: |
2454 | 822k | case CONDITIONAL_ACE_TOKEN_CONTAINS: |
2455 | 824k | case CONDITIONAL_ACE_TOKEN_ANY_OF: |
2456 | 829k | case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS: |
2457 | 833k | case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF: |
2458 | 851k | case CONDITIONAL_ACE_TOKEN_EXISTS: |
2459 | 857k | case CONDITIONAL_ACE_TOKEN_NOT_EXISTS: |
2460 | 951k | case CONDITIONAL_ACE_TOKEN_NOT: |
2461 | 1.05M | case CONDITIONAL_ACE_TOKEN_AND: |
2462 | 1.19M | case CONDITIONAL_ACE_TOKEN_OR: |
2463 | | /* |
2464 | | * All of these are simple operators that operate on |
2465 | | * the stack. We have already added the tok->type and |
2466 | | * there's nothing else to do. |
2467 | | */ |
2468 | 1.19M | continue; |
2469 | | |
2470 | 773 | case CONDITIONAL_ACE_TOKEN_INT8: |
2471 | 1.92k | case CONDITIONAL_ACE_TOKEN_INT16: |
2472 | 2.70k | case CONDITIONAL_ACE_TOKEN_INT32: |
2473 | 73.9k | case CONDITIONAL_ACE_TOKEN_INT64: |
2474 | 73.9k | ok = check_integer_range(tok); |
2475 | 73.9k | if (! ok) { |
2476 | 0 | goto error; |
2477 | 0 | } |
2478 | 73.9k | consumed = push_integer(data + j, |
2479 | 73.9k | alloc_size - j, |
2480 | 73.9k | &tok->data.int64); |
2481 | 73.9k | break; |
2482 | 246k | case CONDITIONAL_ACE_LOCAL_ATTRIBUTE: |
2483 | 273k | case CONDITIONAL_ACE_USER_ATTRIBUTE: |
2484 | 280k | case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE: |
2485 | 295k | case CONDITIONAL_ACE_DEVICE_ATTRIBUTE: |
2486 | 305k | case CONDITIONAL_ACE_TOKEN_UNICODE: |
2487 | 305k | consumed = push_unicode(data + j, |
2488 | 305k | alloc_size - j, |
2489 | 305k | &tok->data.unicode); |
2490 | 305k | break; |
2491 | 30.5k | case CONDITIONAL_ACE_TOKEN_OCTET_STRING: |
2492 | 30.5k | consumed = push_bytes(data + j, |
2493 | 30.5k | alloc_size - j, |
2494 | 30.5k | &tok->data.bytes); |
2495 | 30.5k | break; |
2496 | 16.1k | case CONDITIONAL_ACE_TOKEN_SID: |
2497 | 16.1k | consumed = push_sid(data + j, |
2498 | 16.1k | alloc_size - j, |
2499 | 16.1k | &tok->data.sid); |
2500 | 16.1k | break; |
2501 | 26.3k | case CONDITIONAL_ACE_TOKEN_COMPOSITE: |
2502 | 26.3k | consumed = push_composite(data + j, |
2503 | 26.3k | alloc_size - j, |
2504 | 26.3k | &tok->data.composite); |
2505 | 26.3k | break; |
2506 | | |
2507 | 0 | default: |
2508 | 0 | DBG_ERR("unknown token 0x%02x at position %zu\n", |
2509 | 0 | tok->type, i); |
2510 | 0 | goto error; |
2511 | 1.65M | } |
2512 | 452k | if (consumed == -1) { |
2513 | 557 | DBG_ERR("program exceeds %zu bytes\n", alloc_size); |
2514 | 557 | goto error; |
2515 | 557 | } |
2516 | 451k | j += consumed; |
2517 | 451k | if (j >= alloc_size) { |
2518 | 33 | DBG_ERR("program exceeds %zu bytes\n", alloc_size); |
2519 | 33 | goto error; |
2520 | 33 | } |
2521 | 451k | } |
2522 | | /* align to a 4 byte boundary */ |
2523 | 39.2k | required_size = (j + 3) & ~((size_t)3); |
2524 | 39.2k | if (required_size > alloc_size) { |
2525 | 0 | DBG_ERR("program exceeds %zu bytes\n", alloc_size); |
2526 | 0 | goto error; |
2527 | 0 | } |
2528 | 99.9k | while (j < required_size) { |
2529 | 60.6k | data[j] = 0; |
2530 | 60.6k | j++; |
2531 | 60.6k | } |
2532 | 39.2k | new_data = talloc_realloc(mem_ctx, |
2533 | 39.2k | data, |
2534 | 39.2k | uint8_t, |
2535 | 39.2k | required_size); |
2536 | 39.2k | if (new_data == NULL) { |
2537 | 0 | goto error; |
2538 | 0 | } |
2539 | 39.2k | data = new_data; |
2540 | | |
2541 | 39.2k | (*dest).data = data; |
2542 | 39.2k | (*dest).length = j; |
2543 | 39.2k | return true; |
2544 | 617 | error: |
2545 | 617 | TALLOC_FREE(data); |
2546 | | return false; |
2547 | 39.2k | } |