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.
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.
26 /*******************************************************************
27 Works out the linearization size of a SEC_DESC.
28 ********************************************************************/
30 size_t sec_desc_size(SEC_DESC
*psd
)
36 offset
= SEC_DESC_HEADER_SIZE
;
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
;
55 /*******************************************************************
56 Compares two SEC_DESC structures
57 ********************************************************************/
59 BOOL
sec_desc_equal(SEC_DESC
*s1
, SEC_DESC
*s2
)
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
));
75 if (s1
->type
!= s2
->type
) {
76 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
81 /* Check owner and group */
83 if (!sid_equal(s1
->owner_sid
, s2
->owner_sid
)) {
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",
94 if (!sid_equal(s1
->grp_sid
, s2
->grp_sid
)) {
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",
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"));
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"));
123 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
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
;
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. */
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
;
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
);
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
)
190 if(( dst
= (SEC_DESC
*)talloc_zero(ctx
, sizeof(SEC_DESC
))) == NULL
)
193 dst
->revision
= revision
;
197 dst
->type
|= SEC_DESC_SACL_PRESENT
;
199 dst
->type
|= SEC_DESC_DACL_PRESENT
;
201 dst
->off_owner_sid
= 0;
202 dst
->off_grp_sid
= 0;
206 if(owner_sid
&& ((dst
->owner_sid
= sid_dup_talloc(ctx
,owner_sid
)) == NULL
))
209 if(grp_sid
&& ((dst
->grp_sid
= sid_dup_talloc(ctx
,grp_sid
)) == NULL
))
212 if(sacl
&& ((dst
->sacl
= dup_sec_acl(ctx
, sacl
)) == NULL
))
215 if(dacl
&& ((dst
->dacl
= dup_sec_acl(ctx
, dacl
)) == NULL
))
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
;
252 /*******************************************************************
253 Duplicate a SEC_DESC structure.
254 ********************************************************************/
256 SEC_DESC
*dup_sec_desc(TALLOC_CTX
*ctx
, const SEC_DESC
*src
)
263 return make_sec_desc( ctx
, src
->revision
, src
->type
,
264 src
->owner_sid
, src
->grp_sid
, src
->sacl
,
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
)
287 if((dst
= (SEC_DESC_BUF
*)talloc_zero(ctx
, sizeof(SEC_DESC_BUF
))) == 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
)) {
303 /*******************************************************************
304 Duplicates a SEC_DESC_BUF structure.
305 ********************************************************************/
307 SEC_DESC_BUF
*dup_sec_desc_buf(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*src
)
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
)
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
))
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
;
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
)
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
))
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
)
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
))
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
;
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
)
409 SEC_ACL
*new_dacl
, *the_acl
;
410 SEC_ACE
*new_ace_list
= NULL
;
411 unsigned int new_ace_list_ndx
= 0, i
;
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(ctx
, sizeof(SEC_ACE
) * the_acl
->num_aces
)))
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
];
427 BOOL inherit
= False
;
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
435 if (ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) {
437 if (!child_container
) {
438 new_flags
|= SEC_ACE_FLAG_OBJECT_INHERIT
;
440 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
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
) {
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 */
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
));
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
,
509 sdb
= make_sec_desc_buf(ctx
, size
, sd
);
514 /*******************************************************************
515 Sets up a SEC_ACCESS structure.
516 ********************************************************************/
518 void init_sec_access(SEC_ACCESS
*t
, uint32 mask
)