411185dbfa6948d5dc23c6931c796fb28c85e2b8
[tprouty/samba.git] / source / lib / secdesc.c
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 2 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, write to the Free Software
21  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include "includes.h"
25
26 /*******************************************************************
27  Works out the linearization size of a SEC_DESC.
28 ********************************************************************/
29
30 size_t sec_desc_size(SEC_DESC *psd)
31 {
32         size_t offset;
33
34         if (!psd) return 0;
35
36         offset = SEC_DESC_HEADER_SIZE;
37
38         /* don't align */
39
40         if (psd->owner_sid != NULL)
41                 offset += sid_size(psd->owner_sid);
42
43         if (psd->grp_sid != NULL)
44                 offset += sid_size(psd->grp_sid);
45
46         if (psd->sacl != NULL)
47                 offset += psd->sacl->size;
48
49         if (psd->dacl != NULL)
50                 offset += psd->dacl->size;
51
52         return offset;
53 }
54
55 /*******************************************************************
56  Compares two SEC_DESC structures
57 ********************************************************************/
58
59 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
60 {
61         /* Trivial case */
62
63         if (!s1 && !s2) {
64                 goto done;
65         }
66
67         /* Check top level stuff */
68
69         if (s1->revision != s2->revision) {
70                 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
71                            s1->revision, s2->revision));
72                 return False;
73         }
74
75         if (s1->type!= s2->type) {
76                 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
77                            s1->type, s2->type));
78                 return False;
79         }
80
81         /* Check owner and group */
82
83         if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
84                 fstring str1, str2;
85
86                 sid_to_string(str1, s1->owner_sid);
87                 sid_to_string(str2, s2->owner_sid);
88
89                 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
90                            str1, str2));
91                 return False;
92         }
93
94         if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
95                 fstring str1, str2;
96
97                 sid_to_string(str1, s1->grp_sid);
98                 sid_to_string(str2, s2->grp_sid);
99
100                 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
101                            str1, str2));
102                 return False;
103         }
104
105         /* Check ACLs present in one but not the other */
106
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"));
110                 return False;
111         }
112
113         /* Sigh - we have to do it the hard way by iterating over all
114            the ACEs in the ACLs */
115
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"));
119                 return False;
120         }
121
122  done:
123         DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
124         return True;
125 }
126
127 /*******************************************************************
128  Merge part of security descriptor old_sec in to the empty sections of 
129  security descriptor new_sec.
130 ********************************************************************/
131
132 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
133 {
134         DOM_SID *owner_sid, *group_sid;
135         SEC_DESC_BUF *return_sdb;
136         SEC_ACL *dacl, *sacl;
137         SEC_DESC *psd = NULL;
138         uint16 secdesc_type;
139         size_t secdesc_size;
140
141         /* Copy over owner and group sids.  There seems to be no flag for
142            this so just check the pointer values. */
143
144         owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
145                 old_sdb->sec->owner_sid;
146
147         group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
148                 old_sdb->sec->grp_sid;
149         
150         secdesc_type = new_sdb->sec->type;
151
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. */
155
156         sacl = NULL;
157         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
158
159         /* Copy across discretionary ACL */
160
161         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
162                 dacl = new_sdb->sec->dacl;
163         } else {
164                 dacl = old_sdb->sec->dacl;
165         }
166
167         /* Create new security descriptor from bits */
168
169         psd = make_sec_desc(ctx, new_sdb->sec->revision, secdesc_type,
170                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
171
172         return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
173
174         return(return_sdb);
175 }
176
177 /*******************************************************************
178  Creates a SEC_DESC structure
179 ********************************************************************/
180
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)
184 {
185         SEC_DESC *dst;
186         uint32 offset     = 0;
187
188         *sd_size = 0;
189
190         if(( dst = (SEC_DESC *)talloc_zero(ctx, sizeof(SEC_DESC))) == NULL)
191                 return NULL;
192
193         dst->revision = revision;
194         dst->type = type;
195
196         if (sacl)
197                 dst->type |= SEC_DESC_SACL_PRESENT;
198         if (dacl)
199                 dst->type |= SEC_DESC_DACL_PRESENT;
200
201         dst->off_owner_sid = 0;
202         dst->off_grp_sid   = 0;
203         dst->off_sacl      = 0;
204         dst->off_dacl      = 0;
205
206         if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
207                 goto error_exit;
208
209         if(grp_sid && ((dst->grp_sid = sid_dup_talloc(ctx,grp_sid)) == NULL))
210                 goto error_exit;
211
212         if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
213                 goto error_exit;
214
215         if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
216                 goto error_exit;
217
218         offset = SEC_DESC_HEADER_SIZE;
219
220         /*
221          * Work out the linearization sizes.
222          */
223
224         if (dst->sacl != NULL) {
225                 dst->off_sacl = offset;
226                 offset += dst->sacl->size;
227         }
228         if (dst->dacl != NULL) {
229                 dst->off_dacl = offset;
230                 offset += dst->dacl->size;
231         }
232
233         if (dst->owner_sid != NULL) {
234                 dst->off_owner_sid = offset;
235                 offset += sid_size(dst->owner_sid);
236         }
237
238         if (dst->grp_sid != NULL) {
239                 dst->off_grp_sid = offset;
240                 offset += sid_size(dst->grp_sid);
241         }
242
243         *sd_size = (size_t)offset;
244         return dst;
245
246 error_exit:
247
248         *sd_size = 0;
249         return NULL;
250 }
251
252 /*******************************************************************
253  Duplicate a SEC_DESC structure.  
254 ********************************************************************/
255
256 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
257 {
258         size_t dummy;
259
260         if(src == NULL)
261                 return NULL;
262
263         return make_sec_desc( ctx, src->revision, src->type,
264                                 src->owner_sid, src->grp_sid, src->sacl,
265                                 src->dacl, &dummy);
266 }
267
268 /*******************************************************************
269  Creates a SEC_DESC structure with typical defaults.
270 ********************************************************************/
271
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)
274 {
275         return make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
276                              owner_sid, grp_sid, NULL, dacl, sd_size);
277 }
278
279 /*******************************************************************
280  Creates a SEC_DESC_BUF structure.
281 ********************************************************************/
282
283 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
284 {
285         SEC_DESC_BUF *dst;
286
287         if((dst = (SEC_DESC_BUF *)talloc_zero(ctx, sizeof(SEC_DESC_BUF))) == NULL)
288                 return NULL;
289
290         /* max buffer size (allocated size) */
291         dst->max_len = (uint32)len;
292         dst->len = (uint32)len;
293         
294         if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
295                 return NULL;
296         }
297
298         dst->ptr = 0x1;
299
300         return dst;
301 }
302
303 /*******************************************************************
304  Duplicates a SEC_DESC_BUF structure.
305 ********************************************************************/
306
307 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
308 {
309         if(src == NULL)
310                 return NULL;
311
312         return make_sec_desc_buf( ctx, src->len, src->sec);
313 }
314
315 /*******************************************************************
316  Add a new SID with its permissions to SEC_DESC.
317 ********************************************************************/
318
319 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
320 {
321         SEC_DESC *sd   = 0;
322         SEC_ACL  *dacl = 0;
323         SEC_ACE  *ace  = 0;
324         NTSTATUS  status;
325
326         *sd_size = 0;
327
328         if (!ctx || !psd || !sid || !sd_size)
329                 return NT_STATUS_INVALID_PARAMETER;
330
331         status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid, mask);
332         
333         if (!NT_STATUS_IS_OK(status))
334                 return status;
335
336         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
337                 return NT_STATUS_UNSUCCESSFUL;
338         
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;
342
343         *psd = sd;
344          sd  = 0;
345         return NT_STATUS_OK;
346 }
347
348 /*******************************************************************
349  Modify a SID's permissions in a SEC_DESC.
350 ********************************************************************/
351
352 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
353 {
354         NTSTATUS status;
355
356         if (!sd || !sid)
357                 return NT_STATUS_INVALID_PARAMETER;
358
359         status = sec_ace_mod_sid(sd->dacl->ace, sd->dacl->num_aces, sid, mask);
360
361         if (!NT_STATUS_IS_OK(status))
362                 return status;
363         
364         return NT_STATUS_OK;
365 }
366
367 /*******************************************************************
368  Delete a SID from a SEC_DESC.
369 ********************************************************************/
370
371 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
372 {
373         SEC_DESC *sd   = 0;
374         SEC_ACL  *dacl = 0;
375         SEC_ACE  *ace  = 0;
376         NTSTATUS  status;
377
378         *sd_size = 0;
379         
380         if (!ctx || !psd[0] || !sid || !sd_size)
381                 return NT_STATUS_INVALID_PARAMETER;
382
383         status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid);
384
385         if (!NT_STATUS_IS_OK(status))
386                 return status;
387
388         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
389                 return NT_STATUS_UNSUCCESSFUL;
390         
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;
394
395         *psd = sd;
396          sd  = 0;
397         return NT_STATUS_OK;
398 }
399
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. */
403
404 SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr, 
405                                       BOOL child_container)
406 {
407         SEC_DESC_BUF *sdb;
408         SEC_DESC *sd;
409         SEC_ACL *new_dacl, *the_acl;
410         SEC_ACE *new_ace_list = NULL;
411         unsigned int new_ace_list_ndx = 0, i;
412         size_t size;
413
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.*/
417
418         the_acl = parent_ctr->dacl;
419
420         if (!(new_ace_list = talloc(ctx, sizeof(SEC_ACE) * the_acl->num_aces))) 
421                 return NULL;
422
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];
426                 uint8 new_flags = 0;
427                 BOOL inherit = False;
428                 fstring sid_str;
429
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
433                    ACE. */
434
435                 if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
436
437                         if (!child_container) {
438                                 new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
439                         } else {
440                                 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
441                         }
442
443                         inherit = True;
444                 }
445
446                 /* The CONAINER_INHERIT_ACE flag means all child container
447                    objects will inherit and use the ACE. */
448
449                 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
450                         if (!child_container) {
451                                 inherit = False;
452                         } else {
453                                 new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
454                         }
455                 }
456
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. */
460
461                 if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
462                         /* Move along, nothing to see here */
463                 }
464
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. */
469
470                 if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
471                         new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
472                                        SEC_ACE_FLAG_CONTAINER_INHERIT);
473                 }
474
475                 /* Add ACE to ACE list */
476
477                 if (!inherit)
478                         continue;
479
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);
483
484                 sid_to_string(sid_str, &ace->trustee);
485
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));
491
492                 new_ace_list_ndx++;
493         }
494
495         /* Create child security descriptor to return */
496         
497         new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
498
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? */
502
503         sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
504                            parent_ctr->owner_sid,
505                            parent_ctr->grp_sid,
506                            parent_ctr->sacl,
507                            new_dacl, &size);
508
509         sdb = make_sec_desc_buf(ctx, size, sd);
510
511         return sdb;
512 }
513
514 /*******************************************************************
515  Sets up a SEC_ACCESS structure.
516 ********************************************************************/
517
518 void init_sec_access(SEC_ACCESS *t, uint32 mask)
519 {
520         t->mask = mask;
521 }
522