source: branches/samba-3.5.x/source3/lib/secdesc.c@ 774

Last change on this file since 774 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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