[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / lib / secdesc.c
blob160fdb949d2e7b39e8c434baf6432aac5f49544d
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 2 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, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
26 /* Map generic permissions to file object specific permissions */
28 struct generic_mapping file_generic_mapping = {
29 FILE_GENERIC_READ,
30 FILE_GENERIC_WRITE,
31 FILE_GENERIC_EXECUTE,
32 FILE_GENERIC_ALL
35 /*******************************************************************
36 Works out the linearization size of a SEC_DESC.
37 ********************************************************************/
39 size_t sec_desc_size(SEC_DESC *psd)
41 size_t offset;
43 if (!psd) return 0;
45 offset = SEC_DESC_HEADER_SIZE;
47 /* don't align */
49 if (psd->owner_sid != NULL)
50 offset += sid_size(psd->owner_sid);
52 if (psd->group_sid != NULL)
53 offset += sid_size(psd->group_sid);
55 if (psd->sacl != NULL)
56 offset += psd->sacl->size;
58 if (psd->dacl != NULL)
59 offset += psd->dacl->size;
61 return offset;
64 /*******************************************************************
65 Compares two SEC_DESC structures
66 ********************************************************************/
68 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
70 /* Trivial case */
72 if (!s1 && !s2) {
73 goto done;
76 if (!s1 || !s2) {
77 return False;
80 /* Check top level stuff */
82 if (s1->revision != s2->revision) {
83 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
84 s1->revision, s2->revision));
85 return False;
88 if (s1->type!= s2->type) {
89 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
90 s1->type, s2->type));
91 return False;
94 /* Check owner and group */
96 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
97 fstring str1, str2;
99 sid_to_string(str1, s1->owner_sid);
100 sid_to_string(str2, s2->owner_sid);
102 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
103 str1, str2));
104 return False;
107 if (!sid_equal(s1->group_sid, s2->group_sid)) {
108 fstring str1, str2;
110 sid_to_string(str1, s1->group_sid);
111 sid_to_string(str2, s2->group_sid);
113 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
114 str1, str2));
115 return False;
118 /* Check ACLs present in one but not the other */
120 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
121 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
122 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
123 return False;
126 /* Sigh - we have to do it the hard way by iterating over all
127 the ACEs in the ACLs */
129 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
130 !sec_acl_equal(s1->sacl, s2->sacl)) {
131 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
132 return False;
135 done:
136 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
137 return True;
140 /*******************************************************************
141 Merge part of security descriptor old_sec in to the empty sections of
142 security descriptor new_sec.
143 ********************************************************************/
145 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
147 DOM_SID *owner_sid, *group_sid;
148 SEC_DESC_BUF *return_sdb;
149 SEC_ACL *dacl, *sacl;
150 SEC_DESC *psd = NULL;
151 uint16 secdesc_type;
152 size_t secdesc_size;
154 /* Copy over owner and group sids. There seems to be no flag for
155 this so just check the pointer values. */
157 owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
158 old_sdb->sec->owner_sid;
160 group_sid = new_sdb->sec->group_sid ? new_sdb->sec->group_sid :
161 old_sdb->sec->group_sid;
163 secdesc_type = new_sdb->sec->type;
165 /* Ignore changes to the system ACL. This has the effect of making
166 changes through the security tab audit button not sticking.
167 Perhaps in future Samba could implement these settings somehow. */
169 sacl = NULL;
170 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
172 /* Copy across discretionary ACL */
174 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
175 dacl = new_sdb->sec->dacl;
176 } else {
177 dacl = old_sdb->sec->dacl;
180 /* Create new security descriptor from bits */
182 psd = make_sec_desc(ctx, new_sdb->sec->revision, secdesc_type,
183 owner_sid, group_sid, sacl, dacl, &secdesc_size);
185 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
187 return(return_sdb);
190 /*******************************************************************
191 Creates a SEC_DESC structure
192 ********************************************************************/
194 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, uint16 type,
195 const DOM_SID *owner_sid, const DOM_SID *group_sid,
196 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
198 SEC_DESC *dst;
199 uint32 offset = 0;
201 *sd_size = 0;
203 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
204 return NULL;
206 dst->revision = revision;
207 dst->type = type;
209 if (sacl)
210 dst->type |= SEC_DESC_SACL_PRESENT;
211 if (dacl)
212 dst->type |= SEC_DESC_DACL_PRESENT;
214 dst->off_owner_sid = 0;
215 dst->off_grp_sid = 0;
216 dst->off_sacl = 0;
217 dst->off_dacl = 0;
219 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
220 goto error_exit;
222 if(group_sid && ((dst->group_sid = sid_dup_talloc(ctx,group_sid)) == NULL))
223 goto error_exit;
225 if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
226 goto error_exit;
228 if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
229 goto error_exit;
231 offset = SEC_DESC_HEADER_SIZE;
234 * Work out the linearization sizes.
237 if (dst->sacl != NULL) {
238 dst->off_sacl = offset;
239 offset += dst->sacl->size;
241 if (dst->dacl != NULL) {
242 dst->off_dacl = offset;
243 offset += dst->dacl->size;
246 if (dst->owner_sid != NULL) {
247 dst->off_owner_sid = offset;
248 offset += sid_size(dst->owner_sid);
251 if (dst->group_sid != NULL) {
252 dst->off_grp_sid = offset;
253 offset += sid_size(dst->group_sid);
256 *sd_size = (size_t)offset;
257 return dst;
259 error_exit:
261 *sd_size = 0;
262 return NULL;
265 /*******************************************************************
266 Duplicate a SEC_DESC structure.
267 ********************************************************************/
269 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
271 size_t dummy;
273 if(src == NULL)
274 return NULL;
276 return make_sec_desc( ctx, src->revision, src->type,
277 src->owner_sid, src->group_sid, src->sacl,
278 src->dacl, &dummy);
281 /*******************************************************************
282 Creates a SEC_DESC structure with typical defaults.
283 ********************************************************************/
285 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *group_sid,
286 SEC_ACL *dacl, size_t *sd_size)
288 return make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
289 owner_sid, group_sid, NULL, dacl, sd_size);
292 /*******************************************************************
293 Creates a SEC_DESC_BUF structure.
294 ********************************************************************/
296 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
298 SEC_DESC_BUF *dst;
300 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
301 return NULL;
303 /* max buffer size (allocated size) */
304 dst->max_len = (uint32)len;
305 dst->len = (uint32)len;
307 if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
308 return NULL;
311 dst->ptr = 0x1;
313 return dst;
316 /*******************************************************************
317 Duplicates a SEC_DESC_BUF structure.
318 ********************************************************************/
320 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
322 if(src == NULL)
323 return NULL;
325 return make_sec_desc_buf( ctx, src->len, src->sec);
328 /*******************************************************************
329 Add a new SID with its permissions to SEC_DESC.
330 ********************************************************************/
332 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
334 SEC_DESC *sd = 0;
335 SEC_ACL *dacl = 0;
336 SEC_ACE *ace = 0;
337 NTSTATUS status;
339 if (!ctx || !psd || !sid || !sd_size)
340 return NT_STATUS_INVALID_PARAMETER;
342 *sd_size = 0;
344 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
346 if (!NT_STATUS_IS_OK(status))
347 return status;
349 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
350 return NT_STATUS_UNSUCCESSFUL;
352 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
353 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
354 return NT_STATUS_UNSUCCESSFUL;
356 *psd = sd;
357 sd = 0;
358 return NT_STATUS_OK;
361 /*******************************************************************
362 Modify a SID's permissions in a SEC_DESC.
363 ********************************************************************/
365 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
367 NTSTATUS status;
369 if (!sd || !sid)
370 return NT_STATUS_INVALID_PARAMETER;
372 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
374 if (!NT_STATUS_IS_OK(status))
375 return status;
377 return NT_STATUS_OK;
380 /*******************************************************************
381 Delete a SID from a SEC_DESC.
382 ********************************************************************/
384 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
386 SEC_DESC *sd = 0;
387 SEC_ACL *dacl = 0;
388 SEC_ACE *ace = 0;
389 NTSTATUS status;
391 if (!ctx || !psd[0] || !sid || !sd_size)
392 return NT_STATUS_INVALID_PARAMETER;
394 *sd_size = 0;
396 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
398 if (!NT_STATUS_IS_OK(status))
399 return status;
401 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
402 return NT_STATUS_UNSUCCESSFUL;
404 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
405 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
406 return NT_STATUS_UNSUCCESSFUL;
408 *psd = sd;
409 sd = 0;
410 return NT_STATUS_OK;
413 /* Create a child security descriptor using another security descriptor as
414 the parent container. This child object can either be a container or
415 non-container object. */
417 SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
418 BOOL child_container)
420 SEC_DESC_BUF *sdb;
421 SEC_DESC *sd;
422 SEC_ACL *new_dacl, *the_acl;
423 SEC_ACE *new_ace_list = NULL;
424 unsigned int new_ace_list_ndx = 0, i;
425 size_t size;
427 /* Currently we only process the dacl when creating the child. The
428 sacl should also be processed but this is left out as sacls are
429 not implemented in Samba at the moment.*/
431 the_acl = parent_ctr->dacl;
433 if (the_acl->num_aces) {
434 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces)))
435 return NULL;
436 } else {
437 new_ace_list = NULL;
440 for (i = 0; i < the_acl->num_aces; i++) {
441 SEC_ACE *ace = &the_acl->aces[i];
442 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
443 uint8 new_flags = 0;
444 BOOL inherit = False;
445 fstring sid_str;
447 /* The OBJECT_INHERIT_ACE flag causes the ACE to be
448 inherited by non-container children objects. Container
449 children objects will inherit it as an INHERIT_ONLY
450 ACE. */
452 if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
454 if (!child_container) {
455 new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
456 } else {
457 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
460 inherit = True;
463 /* The CONAINER_INHERIT_ACE flag means all child container
464 objects will inherit and use the ACE. */
466 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
467 if (!child_container) {
468 inherit = False;
469 } else {
470 new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
474 /* The INHERIT_ONLY_ACE is not used by the se_access_check()
475 function for the parent container, but is inherited by
476 all child objects as a normal ACE. */
478 if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
479 /* Move along, nothing to see here */
482 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
483 is inherited by child objects but not grandchildren
484 objects. We clear the object inherit and container
485 inherit flags in the inherited ACE. */
487 if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
488 new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
489 SEC_ACE_FLAG_CONTAINER_INHERIT);
492 /* Add ACE to ACE list */
494 if (!inherit)
495 continue;
497 init_sec_access(&new_ace->access_mask, ace->access_mask);
498 init_sec_ace(new_ace, &ace->trustee, ace->type,
499 new_ace->access_mask, new_flags);
501 sid_to_string(sid_str, &ace->trustee);
503 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
504 " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
505 ace->type, ace->flags, ace->access_mask,
506 sid_str, new_ace->type, new_ace->flags,
507 new_ace->access_mask));
509 new_ace_list_ndx++;
512 /* Create child security descriptor to return */
514 new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
516 /* Use the existing user and group sids. I don't think this is
517 correct. Perhaps the user and group should be passed in as
518 parameters by the caller? */
520 sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
521 parent_ctr->owner_sid,
522 parent_ctr->group_sid,
523 parent_ctr->sacl,
524 new_dacl, &size);
526 sdb = make_sec_desc_buf(ctx, size, sd);
528 return sdb;
531 /*******************************************************************
532 Sets up a SEC_ACCESS structure.
533 ********************************************************************/
535 void init_sec_access(SEC_ACCESS *t, uint32 mask)
537 *t = mask;