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 /* Map generic permissions to file object specific permissions */
28 struct generic_mapping file_generic_mapping
= {
35 /*******************************************************************
36 Works out the linearization size of a SEC_DESC.
37 ********************************************************************/
39 size_t sec_desc_size(SEC_DESC
*psd
)
45 offset
= SEC_DESC_HEADER_SIZE
;
49 if (psd
->owner_sid
!= NULL
)
50 offset
+= sid_size(psd
->owner_sid
);
52 if (psd
->grp_sid
!= NULL
)
53 offset
+= sid_size(psd
->grp_sid
);
55 if (psd
->sacl
!= NULL
)
56 offset
+= psd
->sacl
->size
;
58 if (psd
->dacl
!= NULL
)
59 offset
+= psd
->dacl
->size
;
64 /*******************************************************************
65 Compares two SEC_DESC structures
66 ********************************************************************/
68 BOOL
sec_desc_equal(SEC_DESC
*s1
, SEC_DESC
*s2
)
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
));
88 if (s1
->type
!= s2
->type
) {
89 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
94 /* Check owner and group */
96 if (!sid_equal(s1
->owner_sid
, s2
->owner_sid
)) {
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",
107 if (!sid_equal(s1
->grp_sid
, s2
->grp_sid
)) {
110 sid_to_string(str1
, s1
->grp_sid
);
111 sid_to_string(str2
, s2
->grp_sid
);
113 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
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"));
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"));
136 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
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
;
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
->grp_sid
? new_sdb
->sec
->grp_sid
:
161 old_sdb
->sec
->grp_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. */
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
;
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
);
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
*grp_sid
,
196 SEC_ACL
*sacl
, SEC_ACL
*dacl
, size_t *sd_size
)
203 if(( dst
= TALLOC_ZERO_P(ctx
, SEC_DESC
)) == NULL
)
206 dst
->revision
= revision
;
210 dst
->type
|= SEC_DESC_SACL_PRESENT
;
212 dst
->type
|= SEC_DESC_DACL_PRESENT
;
214 dst
->off_owner_sid
= 0;
215 dst
->off_grp_sid
= 0;
219 if(owner_sid
&& ((dst
->owner_sid
= sid_dup_talloc(ctx
,owner_sid
)) == NULL
))
222 if(grp_sid
&& ((dst
->grp_sid
= sid_dup_talloc(ctx
,grp_sid
)) == NULL
))
225 if(sacl
&& ((dst
->sacl
= dup_sec_acl(ctx
, sacl
)) == NULL
))
228 if(dacl
&& ((dst
->dacl
= dup_sec_acl(ctx
, dacl
)) == NULL
))
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
->grp_sid
!= NULL
) {
252 dst
->off_grp_sid
= offset
;
253 offset
+= sid_size(dst
->grp_sid
);
256 *sd_size
= (size_t)offset
;
265 /*******************************************************************
266 Duplicate a SEC_DESC structure.
267 ********************************************************************/
269 SEC_DESC
*dup_sec_desc(TALLOC_CTX
*ctx
, const SEC_DESC
*src
)
276 return make_sec_desc( ctx
, src
->revision
, src
->type
,
277 src
->owner_sid
, src
->grp_sid
, src
->sacl
,
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
*grp_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
, grp_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
)
300 if((dst
= TALLOC_ZERO_P(ctx
, SEC_DESC_BUF
)) == 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
)) {
316 /*******************************************************************
317 Duplicates a SEC_DESC_BUF structure.
318 ********************************************************************/
320 SEC_DESC_BUF
*dup_sec_desc_buf(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*src
)
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
)
339 if (!ctx
|| !psd
|| !sid
|| !sd_size
)
340 return NT_STATUS_INVALID_PARAMETER
;
344 status
= sec_ace_add_sid(ctx
, &ace
, psd
[0]->dacl
->ace
, &psd
[0]->dacl
->num_aces
, sid
, mask
);
346 if (!NT_STATUS_IS_OK(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]->grp_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
354 return NT_STATUS_UNSUCCESSFUL
;
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
)
370 return NT_STATUS_INVALID_PARAMETER
;
372 status
= sec_ace_mod_sid(sd
->dacl
->ace
, sd
->dacl
->num_aces
, sid
, mask
);
374 if (!NT_STATUS_IS_OK(status
))
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
)
391 if (!ctx
|| !psd
[0] || !sid
|| !sd_size
)
392 return NT_STATUS_INVALID_PARAMETER
;
396 status
= sec_ace_del_sid(ctx
, &ace
, psd
[0]->dacl
->ace
, &psd
[0]->dacl
->num_aces
, sid
);
398 if (!NT_STATUS_IS_OK(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]->grp_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
406 return NT_STATUS_UNSUCCESSFUL
;
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
)
422 SEC_ACL
*new_dacl
, *the_acl
;
423 SEC_ACE
*new_ace_list
= NULL
;
424 unsigned int new_ace_list_ndx
= 0, i
;
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 (!(new_ace_list
= TALLOC_ARRAY(ctx
, SEC_ACE
, the_acl
->num_aces
)))
436 for (i
= 0; i
< the_acl
->num_aces
; i
++) {
437 SEC_ACE
*ace
= &the_acl
->ace
[i
];
438 SEC_ACE
*new_ace
= &new_ace_list
[new_ace_list_ndx
];
440 BOOL inherit
= False
;
443 /* The OBJECT_INHERIT_ACE flag causes the ACE to be
444 inherited by non-container children objects. Container
445 children objects will inherit it as an INHERIT_ONLY
448 if (ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) {
450 if (!child_container
) {
451 new_flags
|= SEC_ACE_FLAG_OBJECT_INHERIT
;
453 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
459 /* The CONAINER_INHERIT_ACE flag means all child container
460 objects will inherit and use the ACE. */
462 if (ace
->flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
463 if (!child_container
) {
466 new_flags
|= SEC_ACE_FLAG_CONTAINER_INHERIT
;
470 /* The INHERIT_ONLY_ACE is not used by the se_access_check()
471 function for the parent container, but is inherited by
472 all child objects as a normal ACE. */
474 if (ace
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
475 /* Move along, nothing to see here */
478 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
479 is inherited by child objects but not grandchildren
480 objects. We clear the object inherit and container
481 inherit flags in the inherited ACE. */
483 if (ace
->flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
484 new_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
485 SEC_ACE_FLAG_CONTAINER_INHERIT
);
488 /* Add ACE to ACE list */
493 init_sec_access(&new_ace
->info
, ace
->info
.mask
);
494 init_sec_ace(new_ace
, &ace
->trustee
, ace
->type
,
495 new_ace
->info
, new_flags
);
497 sid_to_string(sid_str
, &ace
->trustee
);
499 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
500 " inherited as %s:%d/0x%02x/0x%08x\n", sid_str
,
501 ace
->type
, ace
->flags
, ace
->info
.mask
,
502 sid_str
, new_ace
->type
, new_ace
->flags
,
503 new_ace
->info
.mask
));
508 /* Create child security descriptor to return */
510 new_dacl
= make_sec_acl(ctx
, ACL_REVISION
, new_ace_list_ndx
, new_ace_list
);
512 /* Use the existing user and group sids. I don't think this is
513 correct. Perhaps the user and group should be passed in as
514 parameters by the caller? */
516 sd
= make_sec_desc(ctx
, SEC_DESC_REVISION
, SEC_DESC_SELF_RELATIVE
,
517 parent_ctr
->owner_sid
,
522 sdb
= make_sec_desc_buf(ctx
, size
, sd
);
527 /*******************************************************************
528 Sets up a SEC_ACCESS structure.
529 ********************************************************************/
531 void init_sec_access(SEC_ACCESS
*t
, uint32 mask
)