source: branches/samba-3.3.x/source/lib/secdesc.c@ 206

Last change on this file since 206 was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

File size: 15.9 KB
Line 
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.
13 *
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.
18 *
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/>.
21 */
22
23#include "includes.h"
24
25/* Map generic permissions to file object specific permissions */
26
27const struct generic_mapping file_generic_mapping = {
28 FILE_GENERIC_READ,
29 FILE_GENERIC_WRITE,
30 FILE_GENERIC_EXECUTE,
31 FILE_GENERIC_ALL
32};
33
34/*******************************************************************
35 Compares two SEC_DESC structures
36********************************************************************/
37
38bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
39{
40 /* Trivial case */
41
42 if (!s1 && !s2) {
43 goto done;
44 }
45
46 if (!s1 || !s2) {
47 return False;
48 }
49
50 /* Check top level stuff */
51
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;
56 }
57
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;
62 }
63
64 /* Check owner and group */
65
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;
71 }
72
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;
78 }
79
80 /* Check ACLs present in one but not the other */
81
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;
86 }
87
88 /* Sigh - we have to do it the hard way by iterating over all
89 the ACEs in the ACLs */
90
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;
95 }
96
97 done:
98 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
99 return True;
100}
101
102/*******************************************************************
103 Merge part of security descriptor old_sec in to the empty sections of
104 security descriptor new_sec.
105********************************************************************/
106
107SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
108{
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;
115
116 /* Copy over owner and group sids. There seems to be no flag for
117 this so just check the pointer values. */
118
119 owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
120 old_sdb->sd->owner_sid;
121
122 group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
123 old_sdb->sd->group_sid;
124
125 secdesc_type = new_sdb->sd->type;
126
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. */
130
131 sacl = NULL;
132 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
133
134 /* Copy across discretionary ACL */
135
136 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
137 dacl = new_sdb->sd->dacl;
138 } else {
139 dacl = old_sdb->sd->dacl;
140 }
141
142 /* Create new security descriptor from bits */
143
144 psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
145 owner_sid, group_sid, sacl, dacl, &secdesc_size);
146
147 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
148
149 return(return_sdb);
150}
151
152/*******************************************************************
153 Creates a SEC_DESC structure
154********************************************************************/
155
156SEC_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)
161{
162 SEC_DESC *dst;
163 uint32 offset = 0;
164
165 *sd_size = 0;
166
167 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
168 return NULL;
169
170 dst->revision = revision;
171 dst->type = type;
172
173 if (sacl)
174 dst->type |= SEC_DESC_SACL_PRESENT;
175 if (dacl)
176 dst->type |= SEC_DESC_DACL_PRESENT;
177
178 dst->owner_sid = NULL;
179 dst->group_sid = NULL;
180 dst->sacl = NULL;
181 dst->dacl = NULL;
182
183 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
184 goto error_exit;
185
186 if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
187 goto error_exit;
188
189 if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
190 goto error_exit;
191
192 if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
193 goto error_exit;
194
195 offset = SEC_DESC_HEADER_SIZE;
196
197 /*
198 * Work out the linearization sizes.
199 */
200
201 if (dst->sacl != NULL) {
202 offset += dst->sacl->size;
203 }
204 if (dst->dacl != NULL) {
205 offset += dst->dacl->size;
206 }
207
208 if (dst->owner_sid != NULL) {
209 offset += ndr_size_dom_sid(dst->owner_sid, 0);
210 }
211
212 if (dst->group_sid != NULL) {
213 offset += ndr_size_dom_sid(dst->group_sid, 0);
214 }
215
216 *sd_size = (size_t)offset;
217 return dst;
218
219error_exit:
220
221 *sd_size = 0;
222 return NULL;
223}
224
225/*******************************************************************
226 Duplicate a SEC_DESC structure.
227********************************************************************/
228
229SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
230{
231 size_t dummy;
232
233 if(src == NULL)
234 return NULL;
235
236 return make_sec_desc( ctx, src->revision, src->type,
237 src->owner_sid, src->group_sid, src->sacl,
238 src->dacl, &dummy);
239}
240
241/*******************************************************************
242 Convert a secdesc into a byte stream
243********************************************************************/
244NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
245 struct security_descriptor *secdesc,
246 uint8 **data, size_t *len)
247{
248 DATA_BLOB blob;
249 enum ndr_err_code ndr_err;
250
251 ndr_err = ndr_push_struct_blob(
252 &blob, mem_ctx, secdesc,
253 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
254
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);;
259 }
260
261 *data = blob.data;
262 *len = blob.length;
263 return NT_STATUS_OK;
264}
265
266/*******************************************************************
267 Parse a byte stream into a secdesc
268********************************************************************/
269NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
270 struct security_descriptor **psecdesc)
271{
272 DATA_BLOB blob;
273 enum ndr_err_code ndr_err;
274 struct security_descriptor *result;
275
276 if ((data == NULL) || (len == 0)) {
277 return NT_STATUS_INVALID_PARAMETER;
278 }
279
280 result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
281 if (result == NULL) {
282 return NT_STATUS_NO_MEMORY;
283 }
284
285 blob = data_blob_const(data, len);
286
287 ndr_err = ndr_pull_struct_blob(
288 &blob, result, result,
289 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
290
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);;
296 }
297
298 *psecdesc = result;
299 return NT_STATUS_OK;
300}
301
302/*******************************************************************
303 Creates a SEC_DESC structure with typical defaults.
304********************************************************************/
305
306SEC_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)
308{
309 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
310 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
311 dacl, sd_size);
312}
313
314/*******************************************************************
315 Creates a SEC_DESC_BUF structure.
316********************************************************************/
317
318SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
319{
320 SEC_DESC_BUF *dst;
321
322 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
323 return NULL;
324
325 /* max buffer size (allocated size) */
326 dst->sd_size = (uint32)len;
327
328 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
329 return NULL;
330 }
331
332 return dst;
333}
334
335/*******************************************************************
336 Duplicates a SEC_DESC_BUF structure.
337********************************************************************/
338
339SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
340{
341 if(src == NULL)
342 return NULL;
343
344 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
345}
346
347/*******************************************************************
348 Add a new SID with its permissions to SEC_DESC.
349********************************************************************/
350
351NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
352{
353 SEC_DESC *sd = 0;
354 SEC_ACL *dacl = 0;
355 SEC_ACE *ace = 0;
356 NTSTATUS status;
357
358 if (!ctx || !psd || !sid || !sd_size)
359 return NT_STATUS_INVALID_PARAMETER;
360
361 *sd_size = 0;
362
363 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
364
365 if (!NT_STATUS_IS_OK(status))
366 return status;
367
368 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
369 return NT_STATUS_UNSUCCESSFUL;
370
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;
374
375 *psd = sd;
376 sd = 0;
377 return NT_STATUS_OK;
378}
379
380/*******************************************************************
381 Modify a SID's permissions in a SEC_DESC.
382********************************************************************/
383
384NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
385{
386 NTSTATUS status;
387
388 if (!sd || !sid)
389 return NT_STATUS_INVALID_PARAMETER;
390
391 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
392
393 if (!NT_STATUS_IS_OK(status))
394 return status;
395
396 return NT_STATUS_OK;
397}
398
399/*******************************************************************
400 Delete a SID from a SEC_DESC.
401********************************************************************/
402
403NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
404{
405 SEC_DESC *sd = 0;
406 SEC_ACL *dacl = 0;
407 SEC_ACE *ace = 0;
408 NTSTATUS status;
409
410 if (!ctx || !psd[0] || !sid || !sd_size)
411 return NT_STATUS_INVALID_PARAMETER;
412
413 *sd_size = 0;
414
415 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
416
417 if (!NT_STATUS_IS_OK(status))
418 return status;
419
420 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
421 return NT_STATUS_UNSUCCESSFUL;
422
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;
426
427 *psd = sd;
428 sd = 0;
429 return NT_STATUS_OK;
430}
431
432/*
433 * Determine if an ACE is inheritable
434 */
435
436static bool is_inheritable_ace(const SEC_ACE *ace,
437 bool container)
438{
439 if (!container) {
440 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
441 }
442
443 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
444 return true;
445 }
446
447 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
448 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
449 return true;
450 }
451
452 return false;
453}
454
455/* Create a child security descriptor using another security descriptor as
456 the parent container. This child object can either be a container or
457 non-container object. */
458
459NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
460 SEC_DESC **ppsd,
461 size_t *psize,
462 const SEC_DESC *parent_ctr,
463 const DOM_SID *owner_sid,
464 const DOM_SID *group_sid,
465 bool container)
466{
467 SEC_ACL *new_dacl = NULL, *the_acl = NULL;
468 SEC_ACE *new_ace_list = NULL;
469 unsigned int new_ace_list_ndx = 0, i;
470
471 *ppsd = NULL;
472 *psize = 0;
473
474 /* Currently we only process the dacl when creating the child. The
475 sacl should also be processed but this is left out as sacls are
476 not implemented in Samba at the moment.*/
477
478 the_acl = parent_ctr->dacl;
479
480 if (the_acl->num_aces) {
481 if (2*the_acl->num_aces < the_acl->num_aces) {
482 return NT_STATUS_NO_MEMORY;
483 }
484
485 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE,
486 2*the_acl->num_aces))) {
487 return NT_STATUS_NO_MEMORY;
488 }
489 } else {
490 new_ace_list = NULL;
491 }
492
493 for (i = 0; i < the_acl->num_aces; i++) {
494 const SEC_ACE *ace = &the_acl->aces[i];
495 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
496 const DOM_SID *ptrustee = &ace->trustee;
497 const DOM_SID *creator = NULL;
498 uint8 new_flags = ace->flags;
499
500 if (!is_inheritable_ace(ace, container)) {
501 continue;
502 }
503
504 /* see the RAW-ACLS inheritance test for details on these rules */
505 if (!container) {
506 new_flags = 0;
507 } else {
508 new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
509
510 if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
511 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
512 }
513 if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
514 new_flags = 0;
515 }
516 }
517
518 /* The CREATOR sids are special when inherited */
519 if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
520 creator = &global_sid_Creator_Owner;
521 ptrustee = owner_sid;
522 } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
523 creator = &global_sid_Creator_Group;
524 ptrustee = group_sid;
525 }
526
527 if (creator && container &&
528 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
529
530 /* First add the regular ACE entry. */
531 init_sec_ace(new_ace, ptrustee, ace->type,
532 ace->access_mask, 0);
533
534 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
535 " inherited as %s:%d/0x%02x/0x%08x\n",
536 sid_string_dbg(&ace->trustee),
537 ace->type, ace->flags, ace->access_mask,
538 sid_string_dbg(&new_ace->trustee),
539 new_ace->type, new_ace->flags,
540 new_ace->access_mask));
541
542 new_ace_list_ndx++;
543
544 /* Now add the extra creator ACE. */
545 new_ace = &new_ace_list[new_ace_list_ndx];
546
547 ptrustee = creator;
548 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
549 } else if (container &&
550 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
551 ptrustee = &ace->trustee;
552 }
553
554 init_sec_ace(new_ace, ptrustee, ace->type,
555 ace->access_mask, new_flags);
556
557 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
558 " inherited as %s:%d/0x%02x/0x%08x\n",
559 sid_string_dbg(&ace->trustee),
560 ace->type, ace->flags, ace->access_mask,
561 sid_string_dbg(&ace->trustee),
562 new_ace->type, new_ace->flags,
563 new_ace->access_mask));
564
565 new_ace_list_ndx++;
566 }
567
568 /* Create child security descriptor to return */
569 if (new_ace_list_ndx) {
570 new_dacl = make_sec_acl(ctx,
571 NT4_ACL_REVISION,
572 new_ace_list_ndx,
573 new_ace_list);
574
575 if (!new_dacl) {
576 return NT_STATUS_NO_MEMORY;
577 }
578 }
579
580 *ppsd = make_sec_desc(ctx,
581 SECURITY_DESCRIPTOR_REVISION_1,
582 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
583 owner_sid,
584 group_sid,
585 NULL,
586 new_dacl,
587 psize);
588 if (!*ppsd) {
589 return NT_STATUS_NO_MEMORY;
590 }
591 return NT_STATUS_OK;
592}
593
594NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
595 SEC_DESC_BUF **ppsdb,
596 const SEC_DESC *parent_ctr,
597 bool container)
598{
599 NTSTATUS status;
600 size_t size = 0;
601 SEC_DESC *sd = NULL;
602
603 *ppsdb = NULL;
604 status = se_create_child_secdesc(ctx,
605 &sd,
606 &size,
607 parent_ctr,
608 parent_ctr->owner_sid,
609 parent_ctr->group_sid,
610 container);
611 if (!NT_STATUS_IS_OK(status)) {
612 return status;
613 }
614
615 *ppsdb = make_sec_desc_buf(ctx, size, sd);
616 if (!*ppsdb) {
617 return NT_STATUS_NO_MEMORY;
618 }
619 return NT_STATUS_OK;
620}
Note: See TracBrowser for help on using the repository browser.