r4231: commiting changes to 3.0.10
[Samba.git] / source / lib / secdesc.c
blob686a4edf77ccb60f9a6ba9e661abc484cc3a0bfa
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 /*******************************************************************
27 Works out the linearization size of a SEC_DESC.
28 ********************************************************************/
30 size_t sec_desc_size(SEC_DESC *psd)
32 size_t offset;
34 if (!psd) return 0;
36 offset = SEC_DESC_HEADER_SIZE;
38 /* don't align */
40 if (psd->owner_sid != NULL)
41 offset += sid_size(psd->owner_sid);
43 if (psd->grp_sid != NULL)
44 offset += sid_size(psd->grp_sid);
46 if (psd->sacl != NULL)
47 offset += psd->sacl->size;
49 if (psd->dacl != NULL)
50 offset += psd->dacl->size;
52 return offset;
55 /*******************************************************************
56 Compares two SEC_DESC structures
57 ********************************************************************/
59 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
61 /* Trivial case */
63 if (!s1 && !s2) {
64 goto done;
67 /* Check top level stuff */
69 if (s1->revision != s2->revision) {
70 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
71 s1->revision, s2->revision));
72 return False;
75 if (s1->type!= s2->type) {
76 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
77 s1->type, s2->type));
78 return False;
81 /* Check owner and group */
83 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
84 fstring str1, str2;
86 sid_to_string(str1, s1->owner_sid);
87 sid_to_string(str2, s2->owner_sid);
89 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
90 str1, str2));
91 return False;
94 if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
95 fstring str1, str2;
97 sid_to_string(str1, s1->grp_sid);
98 sid_to_string(str2, s2->grp_sid);
100 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
101 str1, str2));
102 return False;
105 /* Check ACLs present in one but not the other */
107 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
108 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
109 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
110 return False;
113 /* Sigh - we have to do it the hard way by iterating over all
114 the ACEs in the ACLs */
116 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
117 !sec_acl_equal(s1->sacl, s2->sacl)) {
118 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
119 return False;
122 done:
123 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
124 return True;
127 /*******************************************************************
128 Merge part of security descriptor old_sec in to the empty sections of
129 security descriptor new_sec.
130 ********************************************************************/
132 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
134 DOM_SID *owner_sid, *group_sid;
135 SEC_DESC_BUF *return_sdb;
136 SEC_ACL *dacl, *sacl;
137 SEC_DESC *psd = NULL;
138 uint16 secdesc_type;
139 size_t secdesc_size;
141 /* Copy over owner and group sids. There seems to be no flag for
142 this so just check the pointer values. */
144 owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
145 old_sdb->sec->owner_sid;
147 group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
148 old_sdb->sec->grp_sid;
150 secdesc_type = new_sdb->sec->type;
152 /* Ignore changes to the system ACL. This has the effect of making
153 changes through the security tab audit button not sticking.
154 Perhaps in future Samba could implement these settings somehow. */
156 sacl = NULL;
157 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
159 /* Copy across discretionary ACL */
161 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
162 dacl = new_sdb->sec->dacl;
163 } else {
164 dacl = old_sdb->sec->dacl;
167 /* Create new security descriptor from bits */
169 psd = make_sec_desc(ctx, new_sdb->sec->revision, secdesc_type,
170 owner_sid, group_sid, sacl, dacl, &secdesc_size);
172 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
174 return(return_sdb);
177 /*******************************************************************
178 Creates a SEC_DESC structure
179 ********************************************************************/
181 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, uint16 type,
182 DOM_SID *owner_sid, DOM_SID *grp_sid,
183 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
185 SEC_DESC *dst;
186 uint32 offset = 0;
188 *sd_size = 0;
190 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
191 return NULL;
193 dst->revision = revision;
194 dst->type = type;
196 if (sacl)
197 dst->type |= SEC_DESC_SACL_PRESENT;
198 if (dacl)
199 dst->type |= SEC_DESC_DACL_PRESENT;
201 dst->off_owner_sid = 0;
202 dst->off_grp_sid = 0;
203 dst->off_sacl = 0;
204 dst->off_dacl = 0;
206 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
207 goto error_exit;
209 if(grp_sid && ((dst->grp_sid = sid_dup_talloc(ctx,grp_sid)) == NULL))
210 goto error_exit;
212 if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
213 goto error_exit;
215 if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
216 goto error_exit;
218 offset = SEC_DESC_HEADER_SIZE;
221 * Work out the linearization sizes.
224 if (dst->sacl != NULL) {
225 dst->off_sacl = offset;
226 offset += dst->sacl->size;
228 if (dst->dacl != NULL) {
229 dst->off_dacl = offset;
230 offset += dst->dacl->size;
233 if (dst->owner_sid != NULL) {
234 dst->off_owner_sid = offset;
235 offset += sid_size(dst->owner_sid);
238 if (dst->grp_sid != NULL) {
239 dst->off_grp_sid = offset;
240 offset += sid_size(dst->grp_sid);
243 *sd_size = (size_t)offset;
244 return dst;
246 error_exit:
248 *sd_size = 0;
249 return NULL;
252 /*******************************************************************
253 Duplicate a SEC_DESC structure.
254 ********************************************************************/
256 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
258 size_t dummy;
260 if(src == NULL)
261 return NULL;
263 return make_sec_desc( ctx, src->revision, src->type,
264 src->owner_sid, src->grp_sid, src->sacl,
265 src->dacl, &dummy);
268 /*******************************************************************
269 Creates a SEC_DESC structure with typical defaults.
270 ********************************************************************/
272 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, DOM_SID *owner_sid, DOM_SID *grp_sid,
273 SEC_ACL *dacl, size_t *sd_size)
275 return make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
276 owner_sid, grp_sid, NULL, dacl, sd_size);
279 /*******************************************************************
280 Creates a SEC_DESC_BUF structure.
281 ********************************************************************/
283 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
285 SEC_DESC_BUF *dst;
287 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
288 return NULL;
290 /* max buffer size (allocated size) */
291 dst->max_len = (uint32)len;
292 dst->len = (uint32)len;
294 if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
295 return NULL;
298 dst->ptr = 0x1;
300 return dst;
303 /*******************************************************************
304 Duplicates a SEC_DESC_BUF structure.
305 ********************************************************************/
307 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
309 if(src == NULL)
310 return NULL;
312 return make_sec_desc_buf( ctx, src->len, src->sec);
315 /*******************************************************************
316 Add a new SID with its permissions to SEC_DESC.
317 ********************************************************************/
319 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
321 SEC_DESC *sd = 0;
322 SEC_ACL *dacl = 0;
323 SEC_ACE *ace = 0;
324 NTSTATUS status;
326 *sd_size = 0;
328 if (!ctx || !psd || !sid || !sd_size)
329 return NT_STATUS_INVALID_PARAMETER;
331 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid, mask);
333 if (!NT_STATUS_IS_OK(status))
334 return status;
336 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
337 return NT_STATUS_UNSUCCESSFUL;
339 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
340 psd[0]->grp_sid, psd[0]->sacl, dacl, sd_size)))
341 return NT_STATUS_UNSUCCESSFUL;
343 *psd = sd;
344 sd = 0;
345 return NT_STATUS_OK;
348 /*******************************************************************
349 Modify a SID's permissions in a SEC_DESC.
350 ********************************************************************/
352 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
354 NTSTATUS status;
356 if (!sd || !sid)
357 return NT_STATUS_INVALID_PARAMETER;
359 status = sec_ace_mod_sid(sd->dacl->ace, sd->dacl->num_aces, sid, mask);
361 if (!NT_STATUS_IS_OK(status))
362 return status;
364 return NT_STATUS_OK;
367 /*******************************************************************
368 Delete a SID from a SEC_DESC.
369 ********************************************************************/
371 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
373 SEC_DESC *sd = 0;
374 SEC_ACL *dacl = 0;
375 SEC_ACE *ace = 0;
376 NTSTATUS status;
378 *sd_size = 0;
380 if (!ctx || !psd[0] || !sid || !sd_size)
381 return NT_STATUS_INVALID_PARAMETER;
383 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid);
385 if (!NT_STATUS_IS_OK(status))
386 return status;
388 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
389 return NT_STATUS_UNSUCCESSFUL;
391 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
392 psd[0]->grp_sid, psd[0]->sacl, dacl, sd_size)))
393 return NT_STATUS_UNSUCCESSFUL;
395 *psd = sd;
396 sd = 0;
397 return NT_STATUS_OK;
400 /* Create a child security descriptor using another security descriptor as
401 the parent container. This child object can either be a container or
402 non-container object. */
404 SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
405 BOOL child_container)
407 SEC_DESC_BUF *sdb;
408 SEC_DESC *sd;
409 SEC_ACL *new_dacl, *the_acl;
410 SEC_ACE *new_ace_list = NULL;
411 unsigned int new_ace_list_ndx = 0, i;
412 size_t size;
414 /* Currently we only process the dacl when creating the child. The
415 sacl should also be processed but this is left out as sacls are
416 not implemented in Samba at the moment.*/
418 the_acl = parent_ctr->dacl;
420 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces)))
421 return NULL;
423 for (i = 0; the_acl && i < the_acl->num_aces; i++) {
424 SEC_ACE *ace = &the_acl->ace[i];
425 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
426 uint8 new_flags = 0;
427 BOOL inherit = False;
428 fstring sid_str;
430 /* The OBJECT_INHERIT_ACE flag causes the ACE to be
431 inherited by non-container children objects. Container
432 children objects will inherit it as an INHERIT_ONLY
433 ACE. */
435 if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
437 if (!child_container) {
438 new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
439 } else {
440 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
443 inherit = True;
446 /* The CONAINER_INHERIT_ACE flag means all child container
447 objects will inherit and use the ACE. */
449 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
450 if (!child_container) {
451 inherit = False;
452 } else {
453 new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
457 /* The INHERIT_ONLY_ACE is not used by the se_access_check()
458 function for the parent container, but is inherited by
459 all child objects as a normal ACE. */
461 if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
462 /* Move along, nothing to see here */
465 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
466 is inherited by child objects but not grandchildren
467 objects. We clear the object inherit and container
468 inherit flags in the inherited ACE. */
470 if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
471 new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
472 SEC_ACE_FLAG_CONTAINER_INHERIT);
475 /* Add ACE to ACE list */
477 if (!inherit)
478 continue;
480 init_sec_access(&new_ace->info, ace->info.mask);
481 init_sec_ace(new_ace, &ace->trustee, ace->type,
482 new_ace->info, new_flags);
484 sid_to_string(sid_str, &ace->trustee);
486 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
487 " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
488 ace->type, ace->flags, ace->info.mask,
489 sid_str, new_ace->type, new_ace->flags,
490 new_ace->info.mask));
492 new_ace_list_ndx++;
495 /* Create child security descriptor to return */
497 new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
499 /* Use the existing user and group sids. I don't think this is
500 correct. Perhaps the user and group should be passed in as
501 parameters by the caller? */
503 sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
504 parent_ctr->owner_sid,
505 parent_ctr->grp_sid,
506 parent_ctr->sacl,
507 new_dacl, &size);
509 sdb = make_sec_desc_buf(ctx, size, sd);
511 return sdb;
514 /*******************************************************************
515 Sets up a SEC_ACCESS structure.
516 ********************************************************************/
518 void init_sec_access(SEC_ACCESS *t, uint32 mask)
520 t->mask = mask;