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 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/>.
25
/* Map generic permissions to file object specific permissions */
27
const struct generic_mapping file_generic_mapping = {
34
/*******************************************************************
35
Compares two SEC_DESC structures
36
********************************************************************/
38
bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
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));
58
if (s1->type!= s2->type) {
59
DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
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)));
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)));
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"));
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"));
98
DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
102
/*******************************************************************
103
Given a security_descriptor return the sec_info.
104
********************************************************************/
106
uint32_t get_sec_info(const SEC_DESC *sd)
108
uint32_t sec_info = ALL_SECURITY_INFORMATION;
112
if (sd->owner_sid == NULL) {
113
sec_info &= ~OWNER_SECURITY_INFORMATION;
115
if (sd->group_sid == NULL) {
116
sec_info &= ~GROUP_SECURITY_INFORMATION;
118
if (sd->sacl == NULL) {
119
sec_info &= ~SACL_SECURITY_INFORMATION;
121
if (sd->dacl == NULL) {
122
sec_info &= ~DACL_SECURITY_INFORMATION;
129
/*******************************************************************
130
Merge part of security descriptor old_sec in to the empty sections of
131
security descriptor new_sec.
132
********************************************************************/
134
SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
136
DOM_SID *owner_sid, *group_sid;
137
SEC_DESC_BUF *return_sdb;
138
SEC_ACL *dacl, *sacl;
139
SEC_DESC *psd = NULL;
143
/* Copy over owner and group sids. There seems to be no flag for
144
this so just check the pointer values. */
146
owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
147
old_sdb->sd->owner_sid;
149
group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
150
old_sdb->sd->group_sid;
152
secdesc_type = new_sdb->sd->type;
154
/* Ignore changes to the system ACL. This has the effect of making
155
changes through the security tab audit button not sticking.
156
Perhaps in future Samba could implement these settings somehow. */
159
secdesc_type &= ~SEC_DESC_SACL_PRESENT;
161
/* Copy across discretionary ACL */
163
if (secdesc_type & SEC_DESC_DACL_PRESENT) {
164
dacl = new_sdb->sd->dacl;
166
dacl = old_sdb->sd->dacl;
169
/* Create new security descriptor from bits */
171
psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
172
owner_sid, group_sid, sacl, dacl, &secdesc_size);
174
return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
179
/*******************************************************************
180
Creates a SEC_DESC structure
181
********************************************************************/
183
SEC_DESC *make_sec_desc(TALLOC_CTX *ctx,
184
enum security_descriptor_revision revision,
186
const DOM_SID *owner_sid, const DOM_SID *grp_sid,
187
SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
194
if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
197
dst->revision = revision;
201
dst->type |= SEC_DESC_SACL_PRESENT;
203
dst->type |= SEC_DESC_DACL_PRESENT;
205
dst->owner_sid = NULL;
206
dst->group_sid = NULL;
210
if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
213
if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
216
if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
219
if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
222
offset = SEC_DESC_HEADER_SIZE;
225
* Work out the linearization sizes.
228
if (dst->sacl != NULL) {
229
offset += dst->sacl->size;
231
if (dst->dacl != NULL) {
232
offset += dst->dacl->size;
235
if (dst->owner_sid != NULL) {
236
offset += ndr_size_dom_sid(dst->owner_sid, NULL, 0);
239
if (dst->group_sid != NULL) {
240
offset += ndr_size_dom_sid(dst->group_sid, NULL, 0);
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->group_sid, src->sacl,
268
/*******************************************************************
269
Convert a secdesc into a byte stream
270
********************************************************************/
271
NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
272
struct security_descriptor *secdesc,
273
uint8 **data, size_t *len)
276
enum ndr_err_code ndr_err;
278
ndr_err = ndr_push_struct_blob(
279
&blob, mem_ctx, NULL, secdesc,
280
(ndr_push_flags_fn_t)ndr_push_security_descriptor);
282
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
283
DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
284
ndr_errstr(ndr_err)));
285
return ndr_map_error2ntstatus(ndr_err);;
293
/*******************************************************************
294
Convert a secdesc_buf into a byte stream
295
********************************************************************/
297
NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
298
struct sec_desc_buf *secdesc_buf,
299
uint8_t **data, size_t *len)
302
enum ndr_err_code ndr_err;
304
ndr_err = ndr_push_struct_blob(
305
&blob, mem_ctx, NULL, secdesc_buf,
306
(ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
308
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
309
DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
310
ndr_errstr(ndr_err)));
311
return ndr_map_error2ntstatus(ndr_err);;
319
/*******************************************************************
320
Parse a byte stream into a secdesc
321
********************************************************************/
322
NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
323
struct security_descriptor **psecdesc)
326
enum ndr_err_code ndr_err;
327
struct security_descriptor *result;
329
if ((data == NULL) || (len == 0)) {
330
return NT_STATUS_INVALID_PARAMETER;
333
result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
334
if (result == NULL) {
335
return NT_STATUS_NO_MEMORY;
338
blob = data_blob_const(data, len);
340
ndr_err = ndr_pull_struct_blob(
341
&blob, result, NULL, result,
342
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
344
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
345
DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
346
ndr_errstr(ndr_err)));
348
return ndr_map_error2ntstatus(ndr_err);;
355
/*******************************************************************
356
Parse a byte stream into a sec_desc_buf
357
********************************************************************/
359
NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
360
struct sec_desc_buf **psecdesc_buf)
363
enum ndr_err_code ndr_err;
364
struct sec_desc_buf *result;
366
if ((data == NULL) || (len == 0)) {
367
return NT_STATUS_INVALID_PARAMETER;
370
result = TALLOC_ZERO_P(mem_ctx, struct sec_desc_buf);
371
if (result == NULL) {
372
return NT_STATUS_NO_MEMORY;
375
blob = data_blob_const(data, len);
377
ndr_err = ndr_pull_struct_blob(
378
&blob, result, NULL, result,
379
(ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
381
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
382
DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
383
ndr_errstr(ndr_err)));
385
return ndr_map_error2ntstatus(ndr_err);;
388
*psecdesc_buf = result;
392
/*******************************************************************
393
Creates a SEC_DESC structure with typical defaults.
394
********************************************************************/
396
SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
397
SEC_ACL *dacl, size_t *sd_size)
399
return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
400
SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
404
/*******************************************************************
405
Creates a SEC_DESC_BUF structure.
406
********************************************************************/
408
SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
412
if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
415
/* max buffer size (allocated size) */
416
dst->sd_size = (uint32)len;
418
if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
425
/*******************************************************************
426
Duplicates a SEC_DESC_BUF structure.
427
********************************************************************/
429
SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
434
return make_sec_desc_buf( ctx, src->sd_size, src->sd);
437
/*******************************************************************
438
Add a new SID with its permissions to SEC_DESC.
439
********************************************************************/
441
NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
448
if (!ctx || !psd || !sid || !sd_size)
449
return NT_STATUS_INVALID_PARAMETER;
453
status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
455
if (!NT_STATUS_IS_OK(status))
458
if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
459
return NT_STATUS_UNSUCCESSFUL;
461
if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
462
psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
463
return NT_STATUS_UNSUCCESSFUL;
470
/*******************************************************************
471
Modify a SID's permissions in a SEC_DESC.
472
********************************************************************/
474
NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
479
return NT_STATUS_INVALID_PARAMETER;
481
status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
483
if (!NT_STATUS_IS_OK(status))
489
/*******************************************************************
490
Delete a SID from a SEC_DESC.
491
********************************************************************/
493
NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
500
if (!ctx || !psd[0] || !sid || !sd_size)
501
return NT_STATUS_INVALID_PARAMETER;
505
status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
507
if (!NT_STATUS_IS_OK(status))
510
if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
511
return NT_STATUS_UNSUCCESSFUL;
513
if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
514
psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
515
return NT_STATUS_UNSUCCESSFUL;
523
* Determine if an ACE is inheritable
526
static bool is_inheritable_ace(const SEC_ACE *ace,
530
return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
533
if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
537
if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
538
!(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
545
/* Create a child security descriptor using another security descriptor as
546
the parent container. This child object can either be a container or
547
non-container object. */
549
NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
552
const SEC_DESC *parent_ctr,
553
const DOM_SID *owner_sid,
554
const DOM_SID *group_sid,
557
SEC_ACL *new_dacl = NULL, *the_acl = NULL;
558
SEC_ACE *new_ace_list = NULL;
559
unsigned int new_ace_list_ndx = 0, i;
564
/* Currently we only process the dacl when creating the child. The
565
sacl should also be processed but this is left out as sacls are
566
not implemented in Samba at the moment.*/
568
the_acl = parent_ctr->dacl;
570
if (the_acl->num_aces) {
571
if (2*the_acl->num_aces < the_acl->num_aces) {
572
return NT_STATUS_NO_MEMORY;
575
if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE,
576
2*the_acl->num_aces))) {
577
return NT_STATUS_NO_MEMORY;
583
for (i = 0; i < the_acl->num_aces; i++) {
584
const SEC_ACE *ace = &the_acl->aces[i];
585
SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
586
const DOM_SID *ptrustee = &ace->trustee;
587
const DOM_SID *creator = NULL;
588
uint8 new_flags = ace->flags;
590
if (!is_inheritable_ace(ace, container)) {
594
/* see the RAW-ACLS inheritance test for details on these rules */
598
new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
600
if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
601
new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
603
if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
608
/* The CREATOR sids are special when inherited */
609
if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
610
creator = &global_sid_Creator_Owner;
611
ptrustee = owner_sid;
612
} else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
613
creator = &global_sid_Creator_Group;
614
ptrustee = group_sid;
617
if (creator && container &&
618
(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
620
/* First add the regular ACE entry. */
621
init_sec_ace(new_ace, ptrustee, ace->type,
622
ace->access_mask, 0);
624
DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
625
" inherited as %s:%d/0x%02x/0x%08x\n",
626
sid_string_dbg(&ace->trustee),
627
ace->type, ace->flags, ace->access_mask,
628
sid_string_dbg(&new_ace->trustee),
629
new_ace->type, new_ace->flags,
630
new_ace->access_mask));
634
/* Now add the extra creator ACE. */
635
new_ace = &new_ace_list[new_ace_list_ndx];
638
new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
639
} else if (container &&
640
!(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
641
ptrustee = &ace->trustee;
644
init_sec_ace(new_ace, ptrustee, ace->type,
645
ace->access_mask, new_flags);
647
DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
648
" inherited as %s:%d/0x%02x/0x%08x\n",
649
sid_string_dbg(&ace->trustee),
650
ace->type, ace->flags, ace->access_mask,
651
sid_string_dbg(&ace->trustee),
652
new_ace->type, new_ace->flags,
653
new_ace->access_mask));
658
/* Create child security descriptor to return */
659
if (new_ace_list_ndx) {
660
new_dacl = make_sec_acl(ctx,
666
return NT_STATUS_NO_MEMORY;
670
*ppsd = make_sec_desc(ctx,
671
SECURITY_DESCRIPTOR_REVISION_1,
672
SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
679
return NT_STATUS_NO_MEMORY;
684
NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
685
SEC_DESC_BUF **ppsdb,
686
const SEC_DESC *parent_ctr,
694
status = se_create_child_secdesc(ctx,
698
parent_ctr->owner_sid,
699
parent_ctr->group_sid,
701
if (!NT_STATUS_IS_OK(status)) {
705
*ppsdb = make_sec_desc_buf(ctx, size, sd);
707
return NT_STATUS_NO_MEMORY;