Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Andrew Tridgell 2004
5 : Copyright (C) Gerald Carter 2005
6 : Copyright (C) Volker Lendecke 2007
7 : Copyright (C) Jeremy Allison 2008
8 : Copyright (C) Andrew Bartlett 2010
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "libcli/security/security.h"
26 :
27 : /* Map generic access rights to object specific rights. This technique is
28 : used to give meaning to assigning read, write, execute and all access to
29 : objects. Each type of object has its own mapping of generic to object
30 : specific access rights. */
31 :
32 62680 : void se_map_generic(uint32_t *access_mask, const struct generic_mapping *mapping)
33 : {
34 62680 : uint32_t old_mask = *access_mask;
35 :
36 62680 : if (*access_mask & GENERIC_READ_ACCESS) {
37 108 : *access_mask &= ~GENERIC_READ_ACCESS;
38 108 : *access_mask |= mapping->generic_read;
39 : }
40 :
41 62680 : if (*access_mask & GENERIC_WRITE_ACCESS) {
42 2 : *access_mask &= ~GENERIC_WRITE_ACCESS;
43 2 : *access_mask |= mapping->generic_write;
44 : }
45 :
46 62680 : if (*access_mask & GENERIC_EXECUTE_ACCESS) {
47 106 : *access_mask &= ~GENERIC_EXECUTE_ACCESS;
48 106 : *access_mask |= mapping->generic_execute;
49 : }
50 :
51 62680 : if (*access_mask & GENERIC_ALL_ACCESS) {
52 111 : *access_mask &= ~GENERIC_ALL_ACCESS;
53 111 : *access_mask |= mapping->generic_all;
54 : }
55 :
56 62680 : if (old_mask != *access_mask) {
57 116 : DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
58 : old_mask, *access_mask));
59 : }
60 62680 : }
61 :
62 : /* Map generic access rights to object specific rights for all the ACE's
63 : * in a security_acl.
64 : */
65 :
66 3188 : void security_acl_map_generic(struct security_acl *sa,
67 : const struct generic_mapping *mapping)
68 : {
69 : unsigned int i;
70 :
71 3188 : if (!sa) {
72 0 : return;
73 : }
74 :
75 31672 : for (i = 0; i < sa->num_aces; i++) {
76 28484 : se_map_generic(&sa->aces[i].access_mask, mapping);
77 : }
78 : }
79 :
80 : /* Map standard access rights to object specific rights. This technique is
81 : used to give meaning to assigning read, write, execute and all access to
82 : objects. Each type of object has its own mapping of standard to object
83 : specific access rights. */
84 :
85 2 : void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mapping)
86 : {
87 2 : uint32_t old_mask = *access_mask;
88 :
89 2 : if (*access_mask & SEC_STD_READ_CONTROL) {
90 0 : *access_mask &= ~SEC_STD_READ_CONTROL;
91 0 : *access_mask |= mapping->std_read;
92 : }
93 :
94 2 : if (*access_mask & (SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE)) {
95 0 : *access_mask &= ~(SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE);
96 0 : *access_mask |= mapping->std_all;
97 : }
98 :
99 2 : if (old_mask != *access_mask) {
100 0 : DEBUG(10, ("se_map_standard(): mapped mask 0x%08x to 0x%08x\n",
101 : old_mask, *access_mask));
102 : }
103 2 : }
104 :
105 : /*
106 : perform a SEC_FLAG_MAXIMUM_ALLOWED access check
107 : */
108 15959 : static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
109 : const struct security_token *token)
110 : {
111 15959 : uint32_t denied = 0, granted = 0;
112 15959 : bool am_owner = false;
113 15959 : bool have_owner_rights_ace = false;
114 : unsigned i;
115 :
116 15959 : if (sd->dacl == NULL) {
117 0 : if (security_token_has_sid(token, sd->owner_sid)) {
118 0 : granted |= SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL;
119 : }
120 0 : return granted;
121 : }
122 :
123 15959 : if (security_token_has_sid(token, sd->owner_sid)) {
124 : /*
125 : * Check for explicit owner rights: if there are none, we remove
126 : * the default owner right SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL
127 : * from remaining_access. Otherwise we just process the
128 : * explicitly granted rights when processing the ACEs.
129 : */
130 2293 : am_owner = true;
131 :
132 22735 : for (i=0; i < sd->dacl->num_aces; i++) {
133 20442 : struct security_ace *ace = &sd->dacl->aces[i];
134 :
135 20442 : if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
136 9 : continue;
137 : }
138 :
139 20433 : have_owner_rights_ace = dom_sid_equal(
140 20433 : &ace->trustee, &global_sid_Owner_Rights);
141 20433 : if (have_owner_rights_ace) {
142 0 : break;
143 : }
144 : }
145 : }
146 :
147 15959 : if (am_owner && !have_owner_rights_ace) {
148 2293 : granted |= SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL;
149 : }
150 :
151 50347 : for (i = 0;i<sd->dacl->num_aces; i++) {
152 34388 : struct security_ace *ace = &sd->dacl->aces[i];
153 34388 : bool is_owner_rights_ace = false;
154 :
155 34388 : if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
156 9 : continue;
157 : }
158 :
159 34379 : if (am_owner) {
160 20433 : is_owner_rights_ace = dom_sid_equal(
161 20433 : &ace->trustee, &global_sid_Owner_Rights);
162 : }
163 :
164 57100 : if (!is_owner_rights_ace &&
165 34379 : !security_token_has_sid(token, &ace->trustee))
166 : {
167 17282 : continue;
168 : }
169 :
170 17097 : switch (ace->type) {
171 17088 : case SEC_ACE_TYPE_ACCESS_ALLOWED:
172 17088 : granted |= ace->access_mask;
173 17088 : break;
174 0 : case SEC_ACE_TYPE_ACCESS_DENIED:
175 : case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
176 0 : denied |= ~granted & ace->access_mask;
177 0 : break;
178 9 : default: /* Other ACE types not handled/supported */
179 9 : break;
180 : }
181 : }
182 :
183 15959 : return granted & ~denied;
184 : }
185 :
186 : /*
187 : The main entry point for access checking. If returning ACCESS_DENIED
188 : this function returns the denied bits in the uint32_t pointed
189 : to by the access_granted pointer.
190 : */
191 22212 : NTSTATUS se_access_check(const struct security_descriptor *sd,
192 : const struct security_token *token,
193 : uint32_t access_desired,
194 : uint32_t *access_granted)
195 : {
196 : uint32_t i;
197 : uint32_t bits_remaining;
198 22212 : uint32_t explicitly_denied_bits = 0;
199 22212 : bool am_owner = false;
200 22212 : bool have_owner_rights_ace = false;
201 :
202 22212 : *access_granted = access_desired;
203 22212 : bits_remaining = access_desired;
204 :
205 : /* handle the maximum allowed flag */
206 22212 : if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
207 2340 : uint32_t orig_access_desired = access_desired;
208 :
209 2340 : access_desired |= access_check_max_allowed(sd, token);
210 2340 : access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
211 2340 : *access_granted = access_desired;
212 2340 : bits_remaining = access_desired;
213 :
214 2340 : DEBUG(10,("se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x\n",
215 : orig_access_desired,
216 : *access_granted,
217 : bits_remaining));
218 : }
219 :
220 : /* a NULL dacl allows access */
221 22212 : if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
222 18 : *access_granted = access_desired;
223 18 : return NT_STATUS_OK;
224 : }
225 :
226 22194 : if (sd->dacl == NULL) {
227 0 : goto done;
228 : }
229 :
230 22194 : if (security_token_has_sid(token, sd->owner_sid)) {
231 : /*
232 : * Check for explicit owner rights: if there are none, we remove
233 : * the default owner right SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL
234 : * from remaining_access. Otherwise we just process the
235 : * explicitly granted rights when processing the ACEs.
236 : */
237 6705 : am_owner = true;
238 :
239 56425 : for (i=0; i < sd->dacl->num_aces; i++) {
240 49720 : struct security_ace *ace = &sd->dacl->aces[i];
241 :
242 49720 : if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
243 4537 : continue;
244 : }
245 :
246 45183 : have_owner_rights_ace = dom_sid_equal(
247 45183 : &ace->trustee, &global_sid_Owner_Rights);
248 45183 : if (have_owner_rights_ace) {
249 0 : break;
250 : }
251 : }
252 : }
253 22194 : if (am_owner && !have_owner_rights_ace) {
254 6705 : bits_remaining &= ~(SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL);
255 : }
256 :
257 : /* check each ace in turn. */
258 50906 : for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
259 28712 : struct security_ace *ace = &sd->dacl->aces[i];
260 28712 : bool is_owner_rights_ace = false;
261 :
262 28712 : if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
263 446 : continue;
264 : }
265 :
266 28266 : if (am_owner) {
267 9587 : is_owner_rights_ace = dom_sid_equal(
268 9587 : &ace->trustee, &global_sid_Owner_Rights);
269 : }
270 :
271 48974 : if (!is_owner_rights_ace &&
272 28266 : !security_token_has_sid(token, &ace->trustee))
273 : {
274 7433 : continue;
275 : }
276 :
277 20833 : switch (ace->type) {
278 20721 : case SEC_ACE_TYPE_ACCESS_ALLOWED:
279 20721 : bits_remaining &= ~ace->access_mask;
280 20721 : break;
281 0 : case SEC_ACE_TYPE_ACCESS_DENIED:
282 : case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
283 0 : explicitly_denied_bits |= (bits_remaining & ace->access_mask);
284 0 : break;
285 112 : default: /* Other ACE types not handled/supported */
286 112 : break;
287 : }
288 : }
289 :
290 : /* Explicitly denied bits always override */
291 22194 : bits_remaining |= explicitly_denied_bits;
292 :
293 : /*
294 : * We check privileges here because they override even DENY entries.
295 : */
296 :
297 : /* Does the user have the privilege to gain SEC_PRIV_SECURITY? */
298 22194 : if (bits_remaining & SEC_FLAG_SYSTEM_SECURITY) {
299 8373 : if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
300 8373 : bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
301 : } else {
302 0 : return NT_STATUS_PRIVILEGE_NOT_HELD;
303 : }
304 : }
305 :
306 23455 : if ((bits_remaining & SEC_STD_WRITE_OWNER) &&
307 1261 : security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
308 1259 : bits_remaining &= ~(SEC_STD_WRITE_OWNER);
309 : }
310 :
311 37017 : done:
312 22194 : if (bits_remaining != 0) {
313 1326 : *access_granted = bits_remaining;
314 1326 : return NT_STATUS_ACCESS_DENIED;
315 : }
316 :
317 20868 : return NT_STATUS_OK;
318 : }
319 :
320 : /*
321 : The main entry point for access checking FOR THE FILE SERVER ONLY !
322 : If returning ACCESS_DENIED this function returns the denied bits in
323 : the uint32_t pointed to by the access_granted pointer.
324 : */
325 17108 : NTSTATUS se_file_access_check(const struct security_descriptor *sd,
326 : const struct security_token *token,
327 : bool priv_open_requested,
328 : uint32_t access_desired,
329 : uint32_t *access_granted)
330 : {
331 : uint32_t bits_remaining;
332 : NTSTATUS status;
333 :
334 17108 : if (!priv_open_requested) {
335 : /* Fall back to generic se_access_check(). */
336 3489 : return se_access_check(sd,
337 : token,
338 : access_desired,
339 : access_granted);
340 : }
341 :
342 : /*
343 : * We need to handle the maximum allowed flag
344 : * outside of se_access_check(), as we need to
345 : * add in the access allowed by the privileges
346 : * as well.
347 : */
348 :
349 13619 : if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
350 13619 : uint32_t orig_access_desired = access_desired;
351 :
352 13619 : access_desired |= access_check_max_allowed(sd, token);
353 13619 : access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
354 :
355 13619 : if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
356 8215 : access_desired |= SEC_RIGHTS_PRIV_BACKUP;
357 : }
358 :
359 13619 : if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
360 8215 : access_desired |= SEC_RIGHTS_PRIV_RESTORE;
361 : }
362 :
363 13619 : DEBUG(10,("se_file_access_check: MAX desired = 0x%x "
364 : "mapped to 0x%x\n",
365 : orig_access_desired,
366 : access_desired));
367 : }
368 :
369 13619 : status = se_access_check(sd,
370 : token,
371 : access_desired,
372 : access_granted);
373 :
374 13619 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
375 12448 : return status;
376 : }
377 :
378 1171 : bits_remaining = *access_granted;
379 :
380 : /* Check if we should override with privileges. */
381 2342 : if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
382 1171 : security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
383 1171 : bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
384 : }
385 2342 : if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
386 1171 : security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
387 1171 : bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
388 : }
389 1171 : if (bits_remaining != 0) {
390 0 : *access_granted = bits_remaining;
391 0 : return NT_STATUS_ACCESS_DENIED;
392 : }
393 :
394 1171 : return NT_STATUS_OK;
395 : }
396 :
397 5025340 : static const struct GUID *get_ace_object_type(const struct security_ace *ace)
398 : {
399 5025340 : if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
400 4753827 : return &ace->object.object.type.type;
401 : }
402 :
403 271513 : return NULL;
404 : }
405 :
406 : /**
407 : * Evaluates access rights specified in a object-specific ACE for an AD object.
408 : * This logic corresponds to MS-ADTS 5.1.3.3.3 Checking Object-Specific Access.
409 : * @param[in] ace - the ACE being processed
410 : * @param[in/out] tree - remaining_access gets updated for the tree
411 : * @param[out] grant_access - set to true if the ACE grants sufficient access
412 : * rights to the object/attribute
413 : * @returns NT_STATUS_OK, unless access was denied
414 : */
415 5694376 : static NTSTATUS check_object_specific_access(const struct security_ace *ace,
416 : struct object_tree *tree,
417 : bool *grant_access)
418 : {
419 5694376 : struct object_tree *node = NULL;
420 5694376 : const struct GUID *type = NULL;
421 :
422 5694376 : *grant_access = false;
423 :
424 : /* if no tree was supplied, we can't do object-specific access checks */
425 5694376 : if (!tree) {
426 669036 : return NT_STATUS_OK;
427 : }
428 :
429 : /* Get the ObjectType GUID this ACE applies to */
430 5025340 : type = get_ace_object_type(ace);
431 :
432 : /*
433 : * If the ACE doesn't have a type, then apply it to the whole tree, i.e.
434 : * treat 'OA' ACEs as 'A' and 'OD' as 'D'
435 : */
436 5025340 : if (!type) {
437 271513 : node = tree;
438 : } else {
439 :
440 : /* skip it if the ACE's ObjectType GUID is not in the tree */
441 4753827 : node = get_object_tree_by_GUID(tree, type);
442 4753827 : if (!node) {
443 4098192 : return NT_STATUS_OK;
444 : }
445 : }
446 :
447 927148 : if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) {
448 :
449 : /* apply the access rights to this node, and any children */
450 926569 : object_tree_modify_access(node, ace->access_mask);
451 :
452 : /*
453 : * Currently all nodes in the tree request the same access mask,
454 : * so we can use any node to check if processing this ACE now
455 : * means the requested access has been granted
456 : */
457 926569 : if (node->remaining_access == 0) {
458 914419 : *grant_access = true;
459 914419 : return NT_STATUS_OK;
460 : }
461 :
462 : /*
463 : * As per 5.1.3.3.4 Checking Control Access Right-Based Access,
464 : * if the CONTROL_ACCESS right is present, then we can grant
465 : * access and stop any further access checks
466 : */
467 12150 : if (ace->access_mask & SEC_ADS_CONTROL_ACCESS) {
468 894 : *grant_access = true;
469 894 : return NT_STATUS_OK;
470 : }
471 : } else {
472 :
473 : /* this ACE denies access to the requested object/attribute */
474 579 : if (node->remaining_access & ace->access_mask){
475 552 : return NT_STATUS_ACCESS_DENIED;
476 : }
477 : }
478 11283 : return NT_STATUS_OK;
479 : }
480 :
481 : /**
482 : * @brief Perform directoryservice (DS) related access checks for a given user
483 : *
484 : * Perform DS access checks for the user represented by its security_token, on
485 : * the provided security descriptor. If an tree associating GUID and access
486 : * required is provided then object access (OA) are checked as well. *
487 : * @param[in] sd The security descritor against which the required
488 : * access are requested
489 : *
490 : * @param[in] token The security_token associated with the user to
491 : * test
492 : *
493 : * @param[in] access_desired A bitfield of rights that must be granted for the
494 : * given user in the specified SD.
495 : *
496 : * If one
497 : * of the entry in the tree grants all the requested rights for the given GUID
498 : * FIXME
499 : * tree can be null if not null it's the
500 : * Lots of code duplication, it will be united in just one
501 : * function eventually */
502 :
503 7384148 : NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
504 : const struct security_token *token,
505 : uint32_t access_desired,
506 : uint32_t *access_granted,
507 : struct object_tree *tree,
508 : const struct dom_sid *replace_sid)
509 : {
510 : uint32_t i;
511 : uint32_t bits_remaining;
512 : struct dom_sid self_sid;
513 :
514 7384148 : dom_sid_parse(SID_NT_SELF, &self_sid);
515 :
516 7384148 : *access_granted = access_desired;
517 7384148 : bits_remaining = access_desired;
518 :
519 : /* handle the maximum allowed flag */
520 7384148 : if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
521 0 : access_desired |= access_check_max_allowed(sd, token);
522 0 : access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
523 0 : *access_granted = access_desired;
524 0 : bits_remaining = access_desired;
525 : }
526 :
527 7384148 : if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
528 31733 : if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
529 31307 : bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
530 : } else {
531 426 : return NT_STATUS_PRIVILEGE_NOT_HELD;
532 : }
533 : }
534 :
535 : /* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
536 7429151 : if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
537 45429 : security_token_has_sid(token, sd->owner_sid)) {
538 44529 : bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL);
539 : }
540 :
541 : /* SEC_PRIV_TAKE_OWNERSHIP grants SEC_STD_WRITE_OWNER */
542 7395142 : if ((bits_remaining & (SEC_STD_WRITE_OWNER)) &&
543 11420 : security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
544 11390 : bits_remaining &= ~(SEC_STD_WRITE_OWNER);
545 : }
546 :
547 : /* a NULL dacl allows access */
548 7383722 : if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
549 0 : *access_granted = access_desired;
550 0 : return NT_STATUS_OK;
551 : }
552 :
553 7383722 : if (sd->dacl == NULL) {
554 0 : goto done;
555 : }
556 :
557 : /* check each ace in turn. */
558 73228915 : for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
559 : const struct dom_sid *trustee;
560 34241552 : const struct security_ace *ace = &sd->dacl->aces[i];
561 : NTSTATUS status;
562 34241552 : bool grant_access = false;
563 :
564 34241552 : if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
565 25125774 : continue;
566 : }
567 :
568 29683298 : if (dom_sid_equal(&ace->trustee, &self_sid) && replace_sid) {
569 6321584 : trustee = replace_sid;
570 : } else {
571 23361714 : trustee = &ace->trustee;
572 : }
573 :
574 29683298 : if (!security_token_has_sid(token, trustee)) {
575 16354088 : continue;
576 : }
577 :
578 13329210 : switch (ace->type) {
579 7603001 : case SEC_ACE_TYPE_ACCESS_ALLOWED:
580 7603001 : if (tree) {
581 6826171 : object_tree_modify_access(tree, ace->access_mask);
582 : }
583 :
584 7603001 : bits_remaining &= ~ace->access_mask;
585 7603001 : break;
586 31833 : case SEC_ACE_TYPE_ACCESS_DENIED:
587 31833 : if (bits_remaining & ace->access_mask) {
588 937800 : return NT_STATUS_ACCESS_DENIED;
589 : }
590 16375 : break;
591 5694376 : case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
592 : case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
593 5694376 : status = check_object_specific_access(ace, tree,
594 : &grant_access);
595 :
596 5694376 : if (!NT_STATUS_IS_OK(status)) {
597 552 : return status;
598 : }
599 :
600 5693824 : if (grant_access) {
601 915313 : return NT_STATUS_OK;
602 : }
603 4778511 : break;
604 0 : default: /* Other ACE types not handled/supported */
605 0 : break;
606 : }
607 : }
608 :
609 6452399 : done:
610 6452399 : if (bits_remaining != 0) {
611 64129 : return NT_STATUS_ACCESS_DENIED;
612 : }
613 :
614 6388270 : return NT_STATUS_OK;
615 : }
|