Samba3-HOWTO: Add improvements/fixes.
[Samba.git] / source / lib / secdesc.c
blob44ae23271ef45261ea1d6a4a0cce868e78e31703
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 Compares two SEC_DESC structures
36 ********************************************************************/
38 bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
40 /* Trivial case */
42 if (!s1 && !s2) {
43 goto done;
46 if (!s1 || !s2) {
47 return False;
50 /* Check top level stuff */
52 if (s1->revision != s2->revision) {
53 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
54 s1->revision, s2->revision));
55 return False;
58 if (s1->type!= s2->type) {
59 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
60 s1->type, s2->type));
61 return False;
64 /* Check owner and group */
66 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
67 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
68 sid_string_dbg(s1->owner_sid),
69 sid_string_dbg(s2->owner_sid)));
70 return False;
73 if (!sid_equal(s1->group_sid, s2->group_sid)) {
74 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
75 sid_string_dbg(s1->group_sid),
76 sid_string_dbg(s2->group_sid)));
77 return False;
80 /* Check ACLs present in one but not the other */
82 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
83 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
84 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
85 return False;
88 /* Sigh - we have to do it the hard way by iterating over all
89 the ACEs in the ACLs */
91 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
92 !sec_acl_equal(s1->sacl, s2->sacl)) {
93 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
94 return False;
97 done:
98 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
99 return True;
102 /*******************************************************************
103 Merge part of security descriptor old_sec in to the empty sections of
104 security descriptor new_sec.
105 ********************************************************************/
107 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
109 DOM_SID *owner_sid, *group_sid;
110 SEC_DESC_BUF *return_sdb;
111 SEC_ACL *dacl, *sacl;
112 SEC_DESC *psd = NULL;
113 uint16 secdesc_type;
114 size_t secdesc_size;
116 /* Copy over owner and group sids. There seems to be no flag for
117 this so just check the pointer values. */
119 owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
120 old_sdb->sd->owner_sid;
122 group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
123 old_sdb->sd->group_sid;
125 secdesc_type = new_sdb->sd->type;
127 /* Ignore changes to the system ACL. This has the effect of making
128 changes through the security tab audit button not sticking.
129 Perhaps in future Samba could implement these settings somehow. */
131 sacl = NULL;
132 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
134 /* Copy across discretionary ACL */
136 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
137 dacl = new_sdb->sd->dacl;
138 } else {
139 dacl = old_sdb->sd->dacl;
142 /* Create new security descriptor from bits */
144 psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
145 owner_sid, group_sid, sacl, dacl, &secdesc_size);
147 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
149 return(return_sdb);
152 /*******************************************************************
153 Creates a SEC_DESC structure
154 ********************************************************************/
156 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx,
157 enum security_descriptor_revision revision,
158 uint16 type,
159 const DOM_SID *owner_sid, const DOM_SID *grp_sid,
160 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
162 SEC_DESC *dst;
163 uint32 offset = 0;
165 *sd_size = 0;
167 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
168 return NULL;
170 dst->revision = revision;
171 dst->type = type;
173 if (sacl)
174 dst->type |= SEC_DESC_SACL_PRESENT;
175 if (dacl)
176 dst->type |= SEC_DESC_DACL_PRESENT;
178 dst->owner_sid = NULL;
179 dst->group_sid = NULL;
180 dst->sacl = NULL;
181 dst->dacl = NULL;
183 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
184 goto error_exit;
186 if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
187 goto error_exit;
189 if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
190 goto error_exit;
192 if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
193 goto error_exit;
195 offset = SEC_DESC_HEADER_SIZE;
198 * Work out the linearization sizes.
201 if (dst->sacl != NULL) {
202 offset += dst->sacl->size;
204 if (dst->dacl != NULL) {
205 offset += dst->dacl->size;
208 if (dst->owner_sid != NULL) {
209 offset += ndr_size_dom_sid(dst->owner_sid, 0);
212 if (dst->group_sid != NULL) {
213 offset += ndr_size_dom_sid(dst->group_sid, 0);
216 *sd_size = (size_t)offset;
217 return dst;
219 error_exit:
221 *sd_size = 0;
222 return NULL;
225 /*******************************************************************
226 Duplicate a SEC_DESC structure.
227 ********************************************************************/
229 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
231 size_t dummy;
233 if(src == NULL)
234 return NULL;
236 return make_sec_desc( ctx, src->revision, src->type,
237 src->owner_sid, src->group_sid, src->sacl,
238 src->dacl, &dummy);
241 /*******************************************************************
242 Convert a secdesc into a byte stream
243 ********************************************************************/
244 NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
245 struct security_descriptor *secdesc,
246 uint8 **data, size_t *len)
248 DATA_BLOB blob;
249 enum ndr_err_code ndr_err;
251 ndr_err = ndr_push_struct_blob(
252 &blob, mem_ctx, secdesc,
253 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
255 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
256 DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
257 ndr_errstr(ndr_err)));
258 return ndr_map_error2ntstatus(ndr_err);;
261 *data = blob.data;
262 *len = blob.length;
263 return NT_STATUS_OK;
266 /*******************************************************************
267 Parse a byte stream into a secdesc
268 ********************************************************************/
269 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
270 struct security_descriptor **psecdesc)
272 DATA_BLOB blob;
273 enum ndr_err_code ndr_err;
274 struct security_descriptor *result;
276 if ((data == NULL) || (len == 0)) {
277 return NT_STATUS_INVALID_PARAMETER;
280 result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
281 if (result == NULL) {
282 return NT_STATUS_NO_MEMORY;
285 blob = data_blob_const(data, len);
287 ndr_err = ndr_pull_struct_blob(
288 &blob, result, result,
289 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
291 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
292 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
293 ndr_errstr(ndr_err)));
294 TALLOC_FREE(result);
295 return ndr_map_error2ntstatus(ndr_err);;
298 *psecdesc = result;
299 return NT_STATUS_OK;
302 /*******************************************************************
303 Creates a SEC_DESC structure with typical defaults.
304 ********************************************************************/
306 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
307 SEC_ACL *dacl, size_t *sd_size)
309 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
310 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
311 dacl, sd_size);
314 /*******************************************************************
315 Creates a SEC_DESC_BUF structure.
316 ********************************************************************/
318 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
320 SEC_DESC_BUF *dst;
322 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
323 return NULL;
325 /* max buffer size (allocated size) */
326 dst->sd_size = (uint32)len;
328 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
329 return NULL;
332 return dst;
335 /*******************************************************************
336 Duplicates a SEC_DESC_BUF structure.
337 ********************************************************************/
339 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
341 if(src == NULL)
342 return NULL;
344 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
347 /*******************************************************************
348 Add a new SID with its permissions to SEC_DESC.
349 ********************************************************************/
351 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
353 SEC_DESC *sd = 0;
354 SEC_ACL *dacl = 0;
355 SEC_ACE *ace = 0;
356 NTSTATUS status;
358 if (!ctx || !psd || !sid || !sd_size)
359 return NT_STATUS_INVALID_PARAMETER;
361 *sd_size = 0;
363 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
365 if (!NT_STATUS_IS_OK(status))
366 return status;
368 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
369 return NT_STATUS_UNSUCCESSFUL;
371 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
372 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
373 return NT_STATUS_UNSUCCESSFUL;
375 *psd = sd;
376 sd = 0;
377 return NT_STATUS_OK;
380 /*******************************************************************
381 Modify a SID's permissions in a SEC_DESC.
382 ********************************************************************/
384 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
386 NTSTATUS status;
388 if (!sd || !sid)
389 return NT_STATUS_INVALID_PARAMETER;
391 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
393 if (!NT_STATUS_IS_OK(status))
394 return status;
396 return NT_STATUS_OK;
399 /*******************************************************************
400 Delete a SID from a SEC_DESC.
401 ********************************************************************/
403 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
405 SEC_DESC *sd = 0;
406 SEC_ACL *dacl = 0;
407 SEC_ACE *ace = 0;
408 NTSTATUS status;
410 if (!ctx || !psd[0] || !sid || !sd_size)
411 return NT_STATUS_INVALID_PARAMETER;
413 *sd_size = 0;
415 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
417 if (!NT_STATUS_IS_OK(status))
418 return status;
420 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
421 return NT_STATUS_UNSUCCESSFUL;
423 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
424 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
425 return NT_STATUS_UNSUCCESSFUL;
427 *psd = sd;
428 sd = 0;
429 return NT_STATUS_OK;
432 /* Create a child security descriptor using another security descriptor as
433 the parent container. This child object can either be a container or
434 non-container object. */
436 SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
437 bool child_container)
439 SEC_DESC_BUF *sdb;
440 SEC_DESC *sd;
441 SEC_ACL *new_dacl, *the_acl;
442 SEC_ACE *new_ace_list = NULL;
443 unsigned int new_ace_list_ndx = 0, i;
444 size_t size;
446 /* Currently we only process the dacl when creating the child. The
447 sacl should also be processed but this is left out as sacls are
448 not implemented in Samba at the moment.*/
450 the_acl = parent_ctr->dacl;
452 if (the_acl->num_aces) {
453 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces)))
454 return NULL;
455 } else {
456 new_ace_list = NULL;
459 for (i = 0; i < the_acl->num_aces; i++) {
460 SEC_ACE *ace = &the_acl->aces[i];
461 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
462 uint8 new_flags = 0;
463 bool inherit = False;
465 /* The OBJECT_INHERIT_ACE flag causes the ACE to be
466 inherited by non-container children objects. Container
467 children objects will inherit it as an INHERIT_ONLY
468 ACE. */
470 if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
472 if (!child_container) {
473 new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
474 } else {
475 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
478 inherit = True;
481 /* The CONAINER_INHERIT_ACE flag means all child container
482 objects will inherit and use the ACE. */
484 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
485 if (!child_container) {
486 inherit = False;
487 } else {
488 new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
492 /* The INHERIT_ONLY_ACE is not used by the se_access_check()
493 function for the parent container, but is inherited by
494 all child objects as a normal ACE. */
496 if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
497 /* Move along, nothing to see here */
500 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
501 is inherited by child objects but not grandchildren
502 objects. We clear the object inherit and container
503 inherit flags in the inherited ACE. */
505 if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
506 new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
507 SEC_ACE_FLAG_CONTAINER_INHERIT);
510 /* Add ACE to ACE list */
512 if (!inherit)
513 continue;
515 init_sec_access(&new_ace->access_mask, ace->access_mask);
516 init_sec_ace(new_ace, &ace->trustee, ace->type,
517 new_ace->access_mask, new_flags);
519 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
520 " inherited as %s:%d/0x%02x/0x%08x\n",
521 sid_string_dbg(&ace->trustee),
522 ace->type, ace->flags, ace->access_mask,
523 sid_string_dbg(&ace->trustee),
524 new_ace->type, new_ace->flags,
525 new_ace->access_mask));
527 new_ace_list_ndx++;
530 /* Create child security descriptor to return */
532 new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
534 /* Use the existing user and group sids. I don't think this is
535 correct. Perhaps the user and group should be passed in as
536 parameters by the caller? */
538 sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
539 SEC_DESC_SELF_RELATIVE,
540 parent_ctr->owner_sid,
541 parent_ctr->group_sid,
542 parent_ctr->sacl,
543 new_dacl, &size);
545 sdb = make_sec_desc_buf(ctx, size, sd);
547 return sdb;
550 /*******************************************************************
551 Sets up a SEC_ACCESS structure.
552 ********************************************************************/
554 void init_sec_access(uint32 *t, uint32 mask)
556 *t = mask;