source: vendor/current/libcli/security/secdesc.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 17.4 KB
Line 
1/*
2 * Unix SMB/Netbios implementation.
3 * SEC_DESC handling functions
4 * Copyright (C) Andrew Tridgell 1992-1998,
5 * Copyright (C) Jeremy R. Allison 1995-2003.
6 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
7 * Copyright (C) Paul Ashton 1997-1998.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "includes.h"
24#include "librpc/gen_ndr/ndr_security.h"
25#include "libcli/security/security.h"
26
27/* Map generic permissions to file object specific permissions */
28
29const struct generic_mapping file_generic_mapping = {
30 FILE_GENERIC_READ,
31 FILE_GENERIC_WRITE,
32 FILE_GENERIC_EXECUTE,
33 FILE_GENERIC_ALL
34};
35
36/*******************************************************************
37 Given a security_descriptor return the sec_info.
38********************************************************************/
39
40uint32_t get_sec_info(const struct security_descriptor *sd)
41{
42 uint32_t sec_info = 0;
43
44 SMB_ASSERT(sd);
45
46 if (sd->owner_sid != NULL) {
47 sec_info |= SECINFO_OWNER;
48 }
49 if (sd->group_sid != NULL) {
50 sec_info |= SECINFO_GROUP;
51 }
52 if (sd->sacl != NULL) {
53 sec_info |= SECINFO_SACL;
54 }
55 if (sd->dacl != NULL) {
56 sec_info |= SECINFO_DACL;
57 }
58
59 if (sd->type & SEC_DESC_SACL_PROTECTED) {
60 sec_info |= SECINFO_PROTECTED_SACL;
61 } else if (sd->type & SEC_DESC_SACL_AUTO_INHERITED) {
62 sec_info |= SECINFO_UNPROTECTED_SACL;
63 }
64 if (sd->type & SEC_DESC_DACL_PROTECTED) {
65 sec_info |= SECINFO_PROTECTED_DACL;
66 } else if (sd->type & SEC_DESC_DACL_AUTO_INHERITED) {
67 sec_info |= SECINFO_UNPROTECTED_DACL;
68 }
69
70 return sec_info;
71}
72
73
74/*******************************************************************
75 Merge part of security descriptor old_sec in to the empty sections of
76 security descriptor new_sec.
77********************************************************************/
78
79struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb)
80{
81 struct dom_sid *owner_sid, *group_sid;
82 struct sec_desc_buf *return_sdb;
83 struct security_acl *dacl, *sacl;
84 struct security_descriptor *psd = NULL;
85 uint16_t secdesc_type;
86 size_t secdesc_size;
87
88 /* Copy over owner and group sids. There seems to be no flag for
89 this so just check the pointer values. */
90
91 owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
92 old_sdb->sd->owner_sid;
93
94 group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
95 old_sdb->sd->group_sid;
96
97 secdesc_type = new_sdb->sd->type;
98
99 /* Ignore changes to the system ACL. This has the effect of making
100 changes through the security tab audit button not sticking.
101 Perhaps in future Samba could implement these settings somehow. */
102
103 sacl = NULL;
104 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
105
106 /* Copy across discretionary ACL */
107
108 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
109 dacl = new_sdb->sd->dacl;
110 } else {
111 dacl = old_sdb->sd->dacl;
112 }
113
114 /* Create new security descriptor from bits */
115
116 psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
117 owner_sid, group_sid, sacl, dacl, &secdesc_size);
118
119 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
120
121 return(return_sdb);
122}
123
124struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb)
125{
126 struct dom_sid *owner_sid, *group_sid;
127 struct security_acl *dacl, *sacl;
128 struct security_descriptor *psd = NULL;
129 uint16_t secdesc_type;
130 size_t secdesc_size;
131
132 /* Copy over owner and group sids. There seems to be no flag for
133 this so just check the pointer values. */
134
135 owner_sid = new_sdb->owner_sid ? new_sdb->owner_sid :
136 old_sdb->owner_sid;
137
138 group_sid = new_sdb->group_sid ? new_sdb->group_sid :
139 old_sdb->group_sid;
140
141 secdesc_type = new_sdb->type;
142
143 /* Ignore changes to the system ACL. This has the effect of making
144 changes through the security tab audit button not sticking.
145 Perhaps in future Samba could implement these settings somehow. */
146
147 sacl = NULL;
148 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
149
150 /* Copy across discretionary ACL */
151
152 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
153 dacl = new_sdb->dacl;
154 } else {
155 dacl = old_sdb->dacl;
156 }
157
158 /* Create new security descriptor from bits */
159 psd = make_sec_desc(ctx, new_sdb->revision, secdesc_type,
160 owner_sid, group_sid, sacl, dacl, &secdesc_size);
161
162 return psd;
163}
164
165/*******************************************************************
166 Creates a struct security_descriptor structure
167********************************************************************/
168struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
169 enum security_descriptor_revision revision,
170 uint16_t type,
171 const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
172 struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size)
173{
174 struct security_descriptor *dst;
175
176 if (sd_size != NULL) {
177 *sd_size = 0;
178 }
179
180 dst = security_descriptor_initialise(ctx);
181 if (dst == NULL) {
182 return NULL;
183 }
184
185 dst->revision = revision;
186 dst->type = type;
187
188 if (sacl != NULL) {
189 dst->sacl = security_acl_dup(dst, sacl);
190 if (dst->sacl == NULL) {
191 goto err_sd_free;
192 }
193 dst->type |= SEC_DESC_SACL_PRESENT;
194 }
195
196 if (dacl != NULL) {
197 dst->dacl = security_acl_dup(dst, dacl);
198 if (dst->dacl == NULL) {
199 goto err_sd_free;
200 }
201 dst->type |= SEC_DESC_DACL_PRESENT;
202 }
203
204 if (owner_sid != NULL) {
205 dst->owner_sid = dom_sid_dup(dst, owner_sid);
206 if (dst->owner_sid == NULL) {
207 goto err_sd_free;
208 }
209 }
210
211 if (grp_sid != NULL) {
212 dst->group_sid = dom_sid_dup(dst, grp_sid);
213 if (dst->group_sid == NULL) {
214 goto err_sd_free;
215 }
216 }
217
218 if (sd_size != NULL) {
219 *sd_size = ndr_size_security_descriptor(dst, 0);
220 }
221
222 return dst;
223
224err_sd_free:
225 talloc_free(dst);
226 return NULL;
227}
228
229/*******************************************************************
230 Convert a secdesc into a byte stream
231********************************************************************/
232NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
233 const struct security_descriptor *secdesc,
234 uint8_t **data, size_t *len)
235{
236 DATA_BLOB blob;
237 enum ndr_err_code ndr_err;
238
239 ndr_err = ndr_push_struct_blob(
240 &blob, mem_ctx, secdesc,
241 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
242
243 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
244 DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
245 ndr_errstr(ndr_err)));
246 return ndr_map_error2ntstatus(ndr_err);
247 }
248
249 *data = blob.data;
250 *len = blob.length;
251 return NT_STATUS_OK;
252}
253
254/*******************************************************************
255 Convert a secdesc_buf into a byte stream
256********************************************************************/
257
258NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
259 const struct sec_desc_buf *secdesc_buf,
260 uint8_t **data, size_t *len)
261{
262 DATA_BLOB blob;
263 enum ndr_err_code ndr_err;
264
265 ndr_err = ndr_push_struct_blob(
266 &blob, mem_ctx, secdesc_buf,
267 (ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
268
269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
270 DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
271 ndr_errstr(ndr_err)));
272 return ndr_map_error2ntstatus(ndr_err);
273 }
274
275 *data = blob.data;
276 *len = blob.length;
277 return NT_STATUS_OK;
278}
279
280/*******************************************************************
281 Parse a byte stream into a secdesc
282********************************************************************/
283NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
284 struct security_descriptor **psecdesc)
285{
286 DATA_BLOB blob;
287 enum ndr_err_code ndr_err;
288 struct security_descriptor *result;
289
290 if ((data == NULL) || (len == 0)) {
291 return NT_STATUS_INVALID_PARAMETER;
292 }
293
294 result = talloc_zero(mem_ctx, struct security_descriptor);
295 if (result == NULL) {
296 return NT_STATUS_NO_MEMORY;
297 }
298
299 blob = data_blob_const(data, len);
300
301 ndr_err = ndr_pull_struct_blob(&blob, result, result,
302 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
303
304 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
305 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
306 ndr_errstr(ndr_err)));
307 TALLOC_FREE(result);
308 return ndr_map_error2ntstatus(ndr_err);
309 }
310
311 *psecdesc = result;
312 return NT_STATUS_OK;
313}
314
315/*******************************************************************
316 Parse a byte stream into a sec_desc_buf
317********************************************************************/
318
319NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
320 struct sec_desc_buf **psecdesc_buf)
321{
322 DATA_BLOB blob;
323 enum ndr_err_code ndr_err;
324 struct sec_desc_buf *result;
325
326 if ((data == NULL) || (len == 0)) {
327 return NT_STATUS_INVALID_PARAMETER;
328 }
329
330 result = talloc_zero(mem_ctx, struct sec_desc_buf);
331 if (result == NULL) {
332 return NT_STATUS_NO_MEMORY;
333 }
334
335 blob = data_blob_const(data, len);
336
337 ndr_err = ndr_pull_struct_blob(&blob, result, result,
338 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
339
340 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
341 DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
342 ndr_errstr(ndr_err)));
343 TALLOC_FREE(result);
344 return ndr_map_error2ntstatus(ndr_err);
345 }
346
347 *psecdesc_buf = result;
348 return NT_STATUS_OK;
349}
350
351/*******************************************************************
352 Creates a struct security_descriptor structure with typical defaults.
353********************************************************************/
354
355struct security_descriptor *make_standard_sec_desc(TALLOC_CTX *ctx, const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
356 struct security_acl *dacl, size_t *sd_size)
357{
358 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
359 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
360 dacl, sd_size);
361}
362
363/*******************************************************************
364 Creates a struct sec_desc_buf structure.
365********************************************************************/
366
367struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct security_descriptor *sec_desc)
368{
369 struct sec_desc_buf *dst;
370
371 if((dst = talloc_zero(ctx, struct sec_desc_buf)) == NULL)
372 return NULL;
373
374 /* max buffer size (allocated size) */
375 dst->sd_size = (uint32_t)len;
376
377 if (sec_desc != NULL) {
378 dst->sd = security_descriptor_copy(ctx, sec_desc);
379 if (dst->sd == NULL) {
380 return NULL;
381 }
382 }
383
384 return dst;
385}
386
387/*******************************************************************
388 Duplicates a struct sec_desc_buf structure.
389********************************************************************/
390
391struct sec_desc_buf *dup_sec_desc_buf(TALLOC_CTX *ctx, struct sec_desc_buf *src)
392{
393 if(src == NULL)
394 return NULL;
395
396 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
397}
398
399/*
400 * Determine if an struct security_ace is inheritable
401 */
402
403static bool is_inheritable_ace(const struct security_ace *ace,
404 bool container)
405{
406 if (!container) {
407 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
408 }
409
410 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
411 return true;
412 }
413
414 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
415 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
416 return true;
417 }
418
419 return false;
420}
421
422/*
423 * Does a security descriptor have any inheritable components for
424 * the newly created type ?
425 */
426
427bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container)
428{
429 unsigned int i;
430 const struct security_acl *the_acl = parent_ctr->dacl;
431
432 if (the_acl == NULL) {
433 return false;
434 }
435
436 for (i = 0; i < the_acl->num_aces; i++) {
437 const struct security_ace *ace = &the_acl->aces[i];
438
439 if (is_inheritable_ace(ace, container)) {
440 return true;
441 }
442 }
443 return false;
444}
445
446/* Create a child security descriptor using another security descriptor as
447 the parent container. This child object can either be a container or
448 non-container object. */
449
450NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
451 struct security_descriptor **ppsd,
452 size_t *psize,
453 const struct security_descriptor *parent_ctr,
454 const struct dom_sid *owner_sid,
455 const struct dom_sid *group_sid,
456 bool container)
457{
458 struct security_acl *new_dacl = NULL, *the_acl = NULL;
459 struct security_ace *new_ace_list = NULL;
460 unsigned int new_ace_list_ndx = 0, i;
461 bool set_inherited_flags = (parent_ctr->type & SEC_DESC_DACL_AUTO_INHERITED);
462
463 TALLOC_CTX *frame;
464
465 *ppsd = NULL;
466 *psize = 0;
467
468 /* Currently we only process the dacl when creating the child. The
469 sacl should also be processed but this is left out as sacls are
470 not implemented in Samba at the moment.*/
471
472 the_acl = parent_ctr->dacl;
473
474 if (the_acl->num_aces) {
475 if (2*the_acl->num_aces < the_acl->num_aces) {
476 return NT_STATUS_NO_MEMORY;
477 }
478
479 if (!(new_ace_list = talloc_array(ctx, struct security_ace,
480 2*the_acl->num_aces))) {
481 return NT_STATUS_NO_MEMORY;
482 }
483 } else {
484 new_ace_list = NULL;
485 }
486
487 frame = talloc_stackframe();
488
489 for (i = 0; i < the_acl->num_aces; i++) {
490 const struct security_ace *ace = &the_acl->aces[i];
491 struct security_ace *new_ace = &new_ace_list[new_ace_list_ndx];
492 const struct dom_sid *ptrustee = &ace->trustee;
493 const struct dom_sid *creator = NULL;
494 uint8_t new_flags = ace->flags;
495
496 if (!is_inheritable_ace(ace, container)) {
497 continue;
498 }
499
500 /* see the RAW-ACLS inheritance test for details on these rules */
501 if (!container) {
502 new_flags = 0;
503 } else {
504 /*
505 * We need to remove SEC_ACE_FLAG_INHERITED_ACE here
506 * if present because it should only be set if the
507 * parent has the AUTO_INHERITED bit set in the
508 * type/control field. If we don't it will slip through
509 * and create DACLs with incorrectly ordered ACEs
510 * when there are CREATOR_OWNER or CREATOR_GROUP
511 * ACEs.
512 */
513 new_flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY
514 | SEC_ACE_FLAG_INHERITED_ACE);
515
516 if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
517 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
518 }
519 if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
520 new_flags = 0;
521 }
522 }
523
524 /* The CREATOR sids are special when inherited */
525 if (dom_sid_equal(ptrustee, &global_sid_Creator_Owner)) {
526 creator = &global_sid_Creator_Owner;
527 ptrustee = owner_sid;
528 } else if (dom_sid_equal(ptrustee, &global_sid_Creator_Group)) {
529 creator = &global_sid_Creator_Group;
530 ptrustee = group_sid;
531 }
532
533 if (creator && container &&
534 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
535
536 /* First add the regular ACE entry. */
537 init_sec_ace(new_ace, ptrustee, ace->type,
538 ace->access_mask,
539 set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0);
540
541 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
542 " inherited as %s:%d/0x%02x/0x%08x\n",
543 dom_sid_string(frame, &ace->trustee),
544 ace->type, ace->flags, ace->access_mask,
545 dom_sid_string(frame, &new_ace->trustee),
546 new_ace->type, new_ace->flags,
547 new_ace->access_mask));
548
549 new_ace_list_ndx++;
550
551 /* Now add the extra creator ACE. */
552 new_ace = &new_ace_list[new_ace_list_ndx];
553
554 ptrustee = creator;
555 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
556
557 } else if (container &&
558 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
559 ptrustee = &ace->trustee;
560 }
561
562 init_sec_ace(new_ace, ptrustee, ace->type,
563 ace->access_mask, new_flags |
564 (set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0));
565
566 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
567 " inherited as %s:%d/0x%02x/0x%08x\n",
568 dom_sid_string(frame, &ace->trustee),
569 ace->type, ace->flags, ace->access_mask,
570 dom_sid_string(frame, &new_ace->trustee),
571 new_ace->type, new_ace->flags,
572 new_ace->access_mask));
573
574 new_ace_list_ndx++;
575 }
576
577 talloc_free(frame);
578
579 /*
580 * remove duplicates
581 */
582 for (i=1; i < new_ace_list_ndx;) {
583 struct security_ace *ai = &new_ace_list[i];
584 unsigned int remaining, j;
585 bool remove_ace = false;
586
587 for (j=0; j < i; j++) {
588 struct security_ace *aj = &new_ace_list[j];
589
590 if (!security_ace_equal(ai, aj)) {
591 continue;
592 }
593
594 remove_ace = true;
595 break;
596 }
597
598 if (!remove_ace) {
599 i++;
600 continue;
601 }
602
603 new_ace_list_ndx--;
604 remaining = new_ace_list_ndx - i;
605 if (remaining == 0) {
606 ZERO_STRUCT(new_ace_list[i]);
607 continue;
608 }
609 memmove(&new_ace_list[i], &new_ace_list[i+1],
610 sizeof(new_ace_list[i]) * remaining);
611 }
612
613 /* Create child security descriptor to return */
614 if (new_ace_list_ndx) {
615 new_dacl = make_sec_acl(ctx,
616 NT4_ACL_REVISION,
617 new_ace_list_ndx,
618 new_ace_list);
619
620 if (!new_dacl) {
621 return NT_STATUS_NO_MEMORY;
622 }
623 }
624
625 *ppsd = make_sec_desc(ctx,
626 SECURITY_DESCRIPTOR_REVISION_1,
627 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT|
628 (set_inherited_flags ? SEC_DESC_DACL_AUTO_INHERITED : 0),
629 owner_sid,
630 group_sid,
631 NULL,
632 new_dacl,
633 psize);
634 if (!*ppsd) {
635 return NT_STATUS_NO_MEMORY;
636 }
637 return NT_STATUS_OK;
638}
639
640NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
641 struct sec_desc_buf **ppsdb,
642 const struct security_descriptor *parent_ctr,
643 bool container)
644{
645 NTSTATUS status;
646 size_t size = 0;
647 struct security_descriptor *sd = NULL;
648
649 *ppsdb = NULL;
650 status = se_create_child_secdesc(ctx,
651 &sd,
652 &size,
653 parent_ctr,
654 parent_ctr->owner_sid,
655 parent_ctr->group_sid,
656 container);
657 if (!NT_STATUS_IS_OK(status)) {
658 return status;
659 }
660
661 *ppsdb = make_sec_desc_buf(ctx, size, sd);
662 if (!*ppsdb) {
663 return NT_STATUS_NO_MEMORY;
664 }
665 return NT_STATUS_OK;
666}
Note: See TracBrowser for help on using the repository browser.