Some C++ fixes
[Samba/gbeck.git] / source3 / lib / secdesc.c
blob123c3bcc9bad35ddf5e38811c37c5138efc7dbe9
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.
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.
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/>.
23 #include "includes.h"
25 /* Map generic permissions to file object specific permissions */
27 const struct generic_mapping file_generic_mapping = {
28 FILE_GENERIC_READ,
29 FILE_GENERIC_WRITE,
30 FILE_GENERIC_EXECUTE,
31 FILE_GENERIC_ALL
34 /*******************************************************************
35 Works out the linearization size of a SEC_DESC.
36 ********************************************************************/
38 size_t sec_desc_size(SEC_DESC *psd)
40 size_t offset;
42 if (!psd) return 0;
44 offset = SEC_DESC_HEADER_SIZE;
46 /* don't align */
48 if (psd->owner_sid != NULL)
49 offset += sid_size(psd->owner_sid);
51 if (psd->group_sid != NULL)
52 offset += sid_size(psd->group_sid);
54 if (psd->sacl != NULL)
55 offset += psd->sacl->size;
57 if (psd->dacl != NULL)
58 offset += psd->dacl->size;
60 return offset;
63 /*******************************************************************
64 Compares two SEC_DESC structures
65 ********************************************************************/
67 bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
69 /* Trivial case */
71 if (!s1 && !s2) {
72 goto done;
75 if (!s1 || !s2) {
76 return False;
79 /* Check top level stuff */
81 if (s1->revision != s2->revision) {
82 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
83 s1->revision, s2->revision));
84 return False;
87 if (s1->type!= s2->type) {
88 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
89 s1->type, s2->type));
90 return False;
93 /* Check owner and group */
95 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
96 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
97 sid_string_dbg(s1->owner_sid),
98 sid_string_dbg(s2->owner_sid)));
99 return False;
102 if (!sid_equal(s1->group_sid, s2->group_sid)) {
103 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
104 sid_string_dbg(s1->group_sid),
105 sid_string_dbg(s2->group_sid)));
106 return False;
109 /* Check ACLs present in one but not the other */
111 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
112 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
113 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
114 return False;
117 /* Sigh - we have to do it the hard way by iterating over all
118 the ACEs in the ACLs */
120 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
121 !sec_acl_equal(s1->sacl, s2->sacl)) {
122 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
123 return False;
126 done:
127 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
128 return True;
131 /*******************************************************************
132 Merge part of security descriptor old_sec in to the empty sections of
133 security descriptor new_sec.
134 ********************************************************************/
136 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
138 DOM_SID *owner_sid, *group_sid;
139 SEC_DESC_BUF *return_sdb;
140 SEC_ACL *dacl, *sacl;
141 SEC_DESC *psd = NULL;
142 uint16 secdesc_type;
143 size_t secdesc_size;
145 /* Copy over owner and group sids. There seems to be no flag for
146 this so just check the pointer values. */
148 owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
149 old_sdb->sd->owner_sid;
151 group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
152 old_sdb->sd->group_sid;
154 secdesc_type = new_sdb->sd->type;
156 /* Ignore changes to the system ACL. This has the effect of making
157 changes through the security tab audit button not sticking.
158 Perhaps in future Samba could implement these settings somehow. */
160 sacl = NULL;
161 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
163 /* Copy across discretionary ACL */
165 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
166 dacl = new_sdb->sd->dacl;
167 } else {
168 dacl = old_sdb->sd->dacl;
171 /* Create new security descriptor from bits */
173 psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
174 owner_sid, group_sid, sacl, dacl, &secdesc_size);
176 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
178 return(return_sdb);
181 /*******************************************************************
182 Creates a SEC_DESC structure
183 ********************************************************************/
185 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx,
186 enum security_descriptor_revision revision,
187 uint16 type,
188 const DOM_SID *owner_sid, const DOM_SID *grp_sid,
189 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
191 SEC_DESC *dst;
192 uint32 offset = 0;
194 *sd_size = 0;
196 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
197 return NULL;
199 dst->revision = revision;
200 dst->type = type;
202 if (sacl)
203 dst->type |= SEC_DESC_SACL_PRESENT;
204 if (dacl)
205 dst->type |= SEC_DESC_DACL_PRESENT;
207 dst->owner_sid = NULL;
208 dst->group_sid = NULL;
209 dst->sacl = NULL;
210 dst->dacl = NULL;
212 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
213 goto error_exit;
215 if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
216 goto error_exit;
218 if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
219 goto error_exit;
221 if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
222 goto error_exit;
224 offset = SEC_DESC_HEADER_SIZE;
227 * Work out the linearization sizes.
230 if (dst->sacl != NULL) {
231 offset += dst->sacl->size;
233 if (dst->dacl != NULL) {
234 offset += dst->dacl->size;
237 if (dst->owner_sid != NULL) {
238 offset += sid_size(dst->owner_sid);
241 if (dst->group_sid != NULL) {
242 offset += sid_size(dst->group_sid);
245 *sd_size = (size_t)offset;
246 return dst;
248 error_exit:
250 *sd_size = 0;
251 return NULL;
254 /*******************************************************************
255 Duplicate a SEC_DESC structure.
256 ********************************************************************/
258 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
260 size_t dummy;
262 if(src == NULL)
263 return NULL;
265 return make_sec_desc( ctx, src->revision, src->type,
266 src->owner_sid, src->group_sid, src->sacl,
267 src->dacl, &dummy);
270 /*******************************************************************
271 Convert a secdesc into a byte stream
272 ********************************************************************/
273 NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
274 struct security_descriptor *secdesc,
275 uint8 **data, size_t *len)
277 prs_struct ps;
279 if (!prs_init(&ps, sec_desc_size(secdesc), mem_ctx, MARSHALL)) {
280 return NT_STATUS_NO_MEMORY;
283 if (!sec_io_desc("security_descriptor", &secdesc, &ps, 1)) {
284 prs_mem_free(&ps);
285 return NT_STATUS_INVALID_PARAMETER;
288 if (!(*data = (uint8 *)talloc_memdup(mem_ctx, ps.data_p,
289 prs_offset(&ps)))) {
290 prs_mem_free(&ps);
291 return NT_STATUS_NO_MEMORY;
294 *len = prs_offset(&ps);
295 prs_mem_free(&ps);
296 return NT_STATUS_OK;
299 /*******************************************************************
300 Parse a byte stream into a secdesc
301 ********************************************************************/
302 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
303 struct security_descriptor **psecdesc)
305 prs_struct ps;
306 struct security_descriptor *secdesc = NULL;
308 if (!(secdesc = TALLOC_ZERO_P(mem_ctx, struct security_descriptor))) {
309 return NT_STATUS_NO_MEMORY;
312 if (!prs_init(&ps, 0, secdesc, UNMARSHALL)) {
313 return NT_STATUS_NO_MEMORY;
316 prs_give_memory(&ps, (char *)data, len, False);
318 if (!sec_io_desc("security_descriptor", &secdesc, &ps, 1)) {
319 return NT_STATUS_INVALID_PARAMETER;
322 prs_mem_free(&ps);
323 *psecdesc = secdesc;
324 return NT_STATUS_OK;
327 /*******************************************************************
328 Creates a SEC_DESC structure with typical defaults.
329 ********************************************************************/
331 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
332 SEC_ACL *dacl, size_t *sd_size)
334 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
335 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
336 dacl, sd_size);
339 /*******************************************************************
340 Creates a SEC_DESC_BUF structure.
341 ********************************************************************/
343 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
345 SEC_DESC_BUF *dst;
347 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
348 return NULL;
350 /* max buffer size (allocated size) */
351 dst->sd_size = (uint32)len;
353 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
354 return NULL;
357 return dst;
360 /*******************************************************************
361 Duplicates a SEC_DESC_BUF structure.
362 ********************************************************************/
364 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
366 if(src == NULL)
367 return NULL;
369 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
372 /*******************************************************************
373 Add a new SID with its permissions to SEC_DESC.
374 ********************************************************************/
376 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
378 SEC_DESC *sd = 0;
379 SEC_ACL *dacl = 0;
380 SEC_ACE *ace = 0;
381 NTSTATUS status;
383 if (!ctx || !psd || !sid || !sd_size)
384 return NT_STATUS_INVALID_PARAMETER;
386 *sd_size = 0;
388 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
390 if (!NT_STATUS_IS_OK(status))
391 return status;
393 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
394 return NT_STATUS_UNSUCCESSFUL;
396 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
397 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
398 return NT_STATUS_UNSUCCESSFUL;
400 *psd = sd;
401 sd = 0;
402 return NT_STATUS_OK;
405 /*******************************************************************
406 Modify a SID's permissions in a SEC_DESC.
407 ********************************************************************/
409 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
411 NTSTATUS status;
413 if (!sd || !sid)
414 return NT_STATUS_INVALID_PARAMETER;
416 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
418 if (!NT_STATUS_IS_OK(status))
419 return status;
421 return NT_STATUS_OK;
424 /*******************************************************************
425 Delete a SID from a SEC_DESC.
426 ********************************************************************/
428 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
430 SEC_DESC *sd = 0;
431 SEC_ACL *dacl = 0;
432 SEC_ACE *ace = 0;
433 NTSTATUS status;
435 if (!ctx || !psd[0] || !sid || !sd_size)
436 return NT_STATUS_INVALID_PARAMETER;
438 *sd_size = 0;
440 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
442 if (!NT_STATUS_IS_OK(status))
443 return status;
445 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
446 return NT_STATUS_UNSUCCESSFUL;
448 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
449 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
450 return NT_STATUS_UNSUCCESSFUL;
452 *psd = sd;
453 sd = 0;
454 return NT_STATUS_OK;
457 /* Create a child security descriptor using another security descriptor as
458 the parent container. This child object can either be a container or
459 non-container object. */
461 SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
462 bool child_container)
464 SEC_DESC_BUF *sdb;
465 SEC_DESC *sd;
466 SEC_ACL *new_dacl, *the_acl;
467 SEC_ACE *new_ace_list = NULL;
468 unsigned int new_ace_list_ndx = 0, i;
469 size_t size;
471 /* Currently we only process the dacl when creating the child. The
472 sacl should also be processed but this is left out as sacls are
473 not implemented in Samba at the moment.*/
475 the_acl = parent_ctr->dacl;
477 if (the_acl->num_aces) {
478 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces)))
479 return NULL;
480 } else {
481 new_ace_list = NULL;
484 for (i = 0; i < the_acl->num_aces; i++) {
485 SEC_ACE *ace = &the_acl->aces[i];
486 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
487 uint8 new_flags = 0;
488 bool inherit = False;
490 /* The OBJECT_INHERIT_ACE flag causes the ACE to be
491 inherited by non-container children objects. Container
492 children objects will inherit it as an INHERIT_ONLY
493 ACE. */
495 if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
497 if (!child_container) {
498 new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
499 } else {
500 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
503 inherit = True;
506 /* The CONAINER_INHERIT_ACE flag means all child container
507 objects will inherit and use the ACE. */
509 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
510 if (!child_container) {
511 inherit = False;
512 } else {
513 new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
517 /* The INHERIT_ONLY_ACE is not used by the se_access_check()
518 function for the parent container, but is inherited by
519 all child objects as a normal ACE. */
521 if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
522 /* Move along, nothing to see here */
525 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
526 is inherited by child objects but not grandchildren
527 objects. We clear the object inherit and container
528 inherit flags in the inherited ACE. */
530 if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
531 new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
532 SEC_ACE_FLAG_CONTAINER_INHERIT);
535 /* Add ACE to ACE list */
537 if (!inherit)
538 continue;
540 init_sec_access(&new_ace->access_mask, ace->access_mask);
541 init_sec_ace(new_ace, &ace->trustee, ace->type,
542 new_ace->access_mask, new_flags);
544 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
545 " inherited as %s:%d/0x%02x/0x%08x\n",
546 sid_string_dbg(&ace->trustee),
547 ace->type, ace->flags, ace->access_mask,
548 sid_string_dbg(&ace->trustee),
549 new_ace->type, new_ace->flags,
550 new_ace->access_mask));
552 new_ace_list_ndx++;
555 /* Create child security descriptor to return */
557 new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
559 /* Use the existing user and group sids. I don't think this is
560 correct. Perhaps the user and group should be passed in as
561 parameters by the caller? */
563 sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
564 SEC_DESC_SELF_RELATIVE,
565 parent_ctr->owner_sid,
566 parent_ctr->group_sid,
567 parent_ctr->sacl,
568 new_dacl, &size);
570 sdb = make_sec_desc_buf(ctx, size, sd);
572 return sdb;
575 /*******************************************************************
576 Sets up a SEC_ACCESS structure.
577 ********************************************************************/
579 void init_sec_access(uint32 *t, uint32 mask)
581 *t = mask;