Add iconv_convenience argument to size functions.
[samba.git] / source3 / 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 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
27 const 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
38 bool 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  Given a security_descriptor return the sec_info.
104 ********************************************************************/
105
106 uint32_t get_sec_info(const SEC_DESC *sd)
107 {
108         uint32_t sec_info = ALL_SECURITY_INFORMATION;
109
110         SMB_ASSERT(sd);
111
112         if (sd->owner_sid == NULL) {
113                 sec_info &= ~OWNER_SECURITY_INFORMATION;
114         }
115         if (sd->group_sid == NULL) {
116                 sec_info &= ~GROUP_SECURITY_INFORMATION;
117         }
118         if (sd->sacl == NULL) {
119                 sec_info &= ~SACL_SECURITY_INFORMATION;
120         }
121         if (sd->dacl == NULL) {
122                 sec_info &= ~DACL_SECURITY_INFORMATION;
123         }
124
125         return sec_info;
126 }
127
128
129 /*******************************************************************
130  Merge part of security descriptor old_sec in to the empty sections of 
131  security descriptor new_sec.
132 ********************************************************************/
133
134 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
135 {
136         DOM_SID *owner_sid, *group_sid;
137         SEC_DESC_BUF *return_sdb;
138         SEC_ACL *dacl, *sacl;
139         SEC_DESC *psd = NULL;
140         uint16 secdesc_type;
141         size_t secdesc_size;
142
143         /* Copy over owner and group sids.  There seems to be no flag for
144            this so just check the pointer values. */
145
146         owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
147                 old_sdb->sd->owner_sid;
148
149         group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
150                 old_sdb->sd->group_sid;
151         
152         secdesc_type = new_sdb->sd->type;
153
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. */
157
158         sacl = NULL;
159         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
160
161         /* Copy across discretionary ACL */
162
163         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
164                 dacl = new_sdb->sd->dacl;
165         } else {
166                 dacl = old_sdb->sd->dacl;
167         }
168
169         /* Create new security descriptor from bits */
170
171         psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
172                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
173
174         return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
175
176         return(return_sdb);
177 }
178
179 /*******************************************************************
180  Creates a SEC_DESC structure
181 ********************************************************************/
182
183 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx,
184                         enum security_descriptor_revision revision,
185                         uint16 type,
186                         const DOM_SID *owner_sid, const DOM_SID *grp_sid,
187                         SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
188 {
189         SEC_DESC *dst;
190         uint32 offset     = 0;
191
192         *sd_size = 0;
193
194         if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
195                 return NULL;
196
197         dst->revision = revision;
198         dst->type = type;
199
200         if (sacl)
201                 dst->type |= SEC_DESC_SACL_PRESENT;
202         if (dacl)
203                 dst->type |= SEC_DESC_DACL_PRESENT;
204
205         dst->owner_sid = NULL;
206         dst->group_sid   = NULL;
207         dst->sacl      = NULL;
208         dst->dacl      = NULL;
209
210         if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
211                 goto error_exit;
212
213         if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
214                 goto error_exit;
215
216         if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
217                 goto error_exit;
218
219         if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
220                 goto error_exit;
221
222         offset = SEC_DESC_HEADER_SIZE;
223
224         /*
225          * Work out the linearization sizes.
226          */
227
228         if (dst->sacl != NULL) {
229                 offset += dst->sacl->size;
230         }
231         if (dst->dacl != NULL) {
232                 offset += dst->dacl->size;
233         }
234
235         if (dst->owner_sid != NULL) {
236                 offset += ndr_size_dom_sid(dst->owner_sid, NULL, 0);
237         }
238
239         if (dst->group_sid != NULL) {
240                 offset += ndr_size_dom_sid(dst->group_sid, NULL, 0);
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->group_sid, src->sacl,
265                                 src->dacl, &dummy);
266 }
267
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)
274 {
275         DATA_BLOB blob;
276         enum ndr_err_code ndr_err;
277
278         ndr_err = ndr_push_struct_blob(
279                 &blob, mem_ctx, NULL, secdesc,
280                 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
281
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);;
286         }
287
288         *data = blob.data;
289         *len = blob.length;
290         return NT_STATUS_OK;
291 }
292
293 /*******************************************************************
294  Parse a byte stream into a secdesc
295 ********************************************************************/
296 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
297                              struct security_descriptor **psecdesc)
298 {
299         DATA_BLOB blob;
300         enum ndr_err_code ndr_err;
301         struct security_descriptor *result;
302
303         if ((data == NULL) || (len == 0)) {
304                 return NT_STATUS_INVALID_PARAMETER;
305         }
306
307         result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
308         if (result == NULL) {
309                 return NT_STATUS_NO_MEMORY;
310         }
311
312         blob = data_blob_const(data, len);
313
314         ndr_err = ndr_pull_struct_blob(
315                 &blob, result, NULL, result,
316                 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
317
318         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
319                 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
320                           ndr_errstr(ndr_err)));
321                 TALLOC_FREE(result);
322                 return ndr_map_error2ntstatus(ndr_err);;
323         }
324
325         *psecdesc = result;
326         return NT_STATUS_OK;
327 }
328
329 /*******************************************************************
330  Creates a SEC_DESC structure with typical defaults.
331 ********************************************************************/
332
333 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
334                                  SEC_ACL *dacl, size_t *sd_size)
335 {
336         return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
337                              SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
338                              dacl, sd_size);
339 }
340
341 /*******************************************************************
342  Creates a SEC_DESC_BUF structure.
343 ********************************************************************/
344
345 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
346 {
347         SEC_DESC_BUF *dst;
348
349         if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
350                 return NULL;
351
352         /* max buffer size (allocated size) */
353         dst->sd_size = (uint32)len;
354         
355         if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
356                 return NULL;
357         }
358
359         return dst;
360 }
361
362 /*******************************************************************
363  Duplicates a SEC_DESC_BUF structure.
364 ********************************************************************/
365
366 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
367 {
368         if(src == NULL)
369                 return NULL;
370
371         return make_sec_desc_buf( ctx, src->sd_size, src->sd);
372 }
373
374 /*******************************************************************
375  Add a new SID with its permissions to SEC_DESC.
376 ********************************************************************/
377
378 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
379 {
380         SEC_DESC *sd   = 0;
381         SEC_ACL  *dacl = 0;
382         SEC_ACE  *ace  = 0;
383         NTSTATUS  status;
384
385         if (!ctx || !psd || !sid || !sd_size)
386                 return NT_STATUS_INVALID_PARAMETER;
387
388         *sd_size = 0;
389
390         status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
391         
392         if (!NT_STATUS_IS_OK(status))
393                 return status;
394
395         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
396                 return NT_STATUS_UNSUCCESSFUL;
397         
398         if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid, 
399                 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
400                 return NT_STATUS_UNSUCCESSFUL;
401
402         *psd = sd;
403          sd  = 0;
404         return NT_STATUS_OK;
405 }
406
407 /*******************************************************************
408  Modify a SID's permissions in a SEC_DESC.
409 ********************************************************************/
410
411 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
412 {
413         NTSTATUS status;
414
415         if (!sd || !sid)
416                 return NT_STATUS_INVALID_PARAMETER;
417
418         status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
419
420         if (!NT_STATUS_IS_OK(status))
421                 return status;
422         
423         return NT_STATUS_OK;
424 }
425
426 /*******************************************************************
427  Delete a SID from a SEC_DESC.
428 ********************************************************************/
429
430 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
431 {
432         SEC_DESC *sd   = 0;
433         SEC_ACL  *dacl = 0;
434         SEC_ACE  *ace  = 0;
435         NTSTATUS  status;
436
437         if (!ctx || !psd[0] || !sid || !sd_size)
438                 return NT_STATUS_INVALID_PARAMETER;
439
440         *sd_size = 0;
441         
442         status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
443
444         if (!NT_STATUS_IS_OK(status))
445                 return status;
446
447         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
448                 return NT_STATUS_UNSUCCESSFUL;
449         
450         if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid, 
451                 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
452                 return NT_STATUS_UNSUCCESSFUL;
453
454         *psd = sd;
455          sd  = 0;
456         return NT_STATUS_OK;
457 }
458
459 /*
460  * Determine if an ACE is inheritable
461  */
462
463 static bool is_inheritable_ace(const SEC_ACE *ace,
464                                 bool container)
465 {
466         if (!container) {
467                 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
468         }
469
470         if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
471                 return true;
472         }
473
474         if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
475                         !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
476                 return true;
477         }
478
479         return false;
480 }
481
482 /* Create a child security descriptor using another security descriptor as
483    the parent container.  This child object can either be a container or
484    non-container object. */
485
486 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
487                                         SEC_DESC **ppsd,
488                                         size_t *psize,
489                                         const SEC_DESC *parent_ctr,
490                                         const DOM_SID *owner_sid,
491                                         const DOM_SID *group_sid,
492                                         bool container)
493 {
494         SEC_ACL *new_dacl = NULL, *the_acl = NULL;
495         SEC_ACE *new_ace_list = NULL;
496         unsigned int new_ace_list_ndx = 0, i;
497
498         *ppsd = NULL;
499         *psize = 0;
500
501         /* Currently we only process the dacl when creating the child.  The
502            sacl should also be processed but this is left out as sacls are
503            not implemented in Samba at the moment.*/
504
505         the_acl = parent_ctr->dacl;
506
507         if (the_acl->num_aces) {
508                 if (2*the_acl->num_aces < the_acl->num_aces) {
509                         return NT_STATUS_NO_MEMORY;
510                 }
511
512                 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE,
513                                                 2*the_acl->num_aces))) {
514                         return NT_STATUS_NO_MEMORY;
515                 }
516         } else {
517                 new_ace_list = NULL;
518         }
519
520         for (i = 0; i < the_acl->num_aces; i++) {
521                 const SEC_ACE *ace = &the_acl->aces[i];
522                 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
523                 const DOM_SID *ptrustee = &ace->trustee;
524                 const DOM_SID *creator = NULL;
525                 uint8 new_flags = ace->flags;
526
527                 if (!is_inheritable_ace(ace, container)) {
528                         continue;
529                 }
530
531                 /* see the RAW-ACLS inheritance test for details on these rules */
532                 if (!container) {
533                         new_flags = 0;
534                 } else {
535                         new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
536
537                         if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
538                                 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
539                         }
540                         if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
541                                 new_flags = 0;
542                         }
543                 }
544
545                 /* The CREATOR sids are special when inherited */
546                 if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
547                         creator = &global_sid_Creator_Owner;
548                         ptrustee = owner_sid;
549                 } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
550                         creator = &global_sid_Creator_Group;
551                         ptrustee = group_sid;
552                 }
553
554                 if (creator && container &&
555                                 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
556
557                         /* First add the regular ACE entry. */
558                         init_sec_ace(new_ace, ptrustee, ace->type,
559                                 ace->access_mask, 0);
560
561                         DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
562                                 " inherited as %s:%d/0x%02x/0x%08x\n",
563                                 sid_string_dbg(&ace->trustee),
564                                 ace->type, ace->flags, ace->access_mask,
565                                 sid_string_dbg(&new_ace->trustee),
566                                 new_ace->type, new_ace->flags,
567                                 new_ace->access_mask));
568
569                         new_ace_list_ndx++;
570
571                         /* Now add the extra creator ACE. */
572                         new_ace = &new_ace_list[new_ace_list_ndx];
573
574                         ptrustee = creator;
575                         new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
576                 } else if (container &&
577                                 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
578                         ptrustee = &ace->trustee;
579                 }
580
581                 init_sec_ace(new_ace, ptrustee, ace->type,
582                              ace->access_mask, new_flags);
583
584                 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
585                           " inherited as %s:%d/0x%02x/0x%08x\n",
586                           sid_string_dbg(&ace->trustee),
587                           ace->type, ace->flags, ace->access_mask,
588                           sid_string_dbg(&ace->trustee),
589                           new_ace->type, new_ace->flags,
590                           new_ace->access_mask));
591
592                 new_ace_list_ndx++;
593         }
594
595         /* Create child security descriptor to return */
596         if (new_ace_list_ndx) {
597                 new_dacl = make_sec_acl(ctx,
598                                 NT4_ACL_REVISION,
599                                 new_ace_list_ndx,
600                                 new_ace_list);
601
602                 if (!new_dacl) {
603                         return NT_STATUS_NO_MEMORY;
604                 }
605         }
606
607         *ppsd = make_sec_desc(ctx,
608                         SECURITY_DESCRIPTOR_REVISION_1,
609                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
610                         owner_sid,
611                         group_sid,
612                         NULL,
613                         new_dacl,
614                         psize);
615         if (!*ppsd) {
616                 return NT_STATUS_NO_MEMORY;
617         }
618         return NT_STATUS_OK;
619 }
620
621 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
622                                         SEC_DESC_BUF **ppsdb,
623                                         const SEC_DESC *parent_ctr,
624                                         bool container)
625 {
626         NTSTATUS status;
627         size_t size = 0;
628         SEC_DESC *sd = NULL;
629
630         *ppsdb = NULL;
631         status = se_create_child_secdesc(ctx,
632                                         &sd,
633                                         &size,
634                                         parent_ctr,
635                                         parent_ctr->owner_sid,
636                                         parent_ctr->group_sid,
637                                         container);
638         if (!NT_STATUS_IS_OK(status)) {
639                 return status;
640         }
641
642         *ppsdb = make_sec_desc_buf(ctx, size, sd);
643         if (!*ppsdb) {
644                 return NT_STATUS_NO_MEMORY;
645         }
646         return NT_STATUS_OK;
647 }