merge from APP_HEAD
[metze/samba/wip.git] / source3 / rpc_parse / parse_sec.c
1 /* 
2  *  Unix SMB/Netbios implementation.
3  *  Version 1.9.
4  *  RPC Pipe client / server routines
5  *  Copyright (C) Andrew Tridgell              1992-1998,
6  *  Copyright (C) Jeremy R. Allison            1995-1998
7  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
8  *  Copyright (C) Paul Ashton                  1997-1998.
9  *  
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *  
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *  
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_RPC_PARSE
29
30 /*******************************************************************
31  Sets up a SEC_ACCESS structure.
32 ********************************************************************/
33
34 void init_sec_access(SEC_ACCESS *t, uint32 mask)
35 {
36         t->mask = mask;
37 }
38
39 /*******************************************************************
40  Reads or writes a SEC_ACCESS structure.
41 ********************************************************************/
42
43 BOOL sec_io_access(char *desc, SEC_ACCESS *t, prs_struct *ps, int depth)
44 {
45         if (t == NULL)
46                 return False;
47
48         prs_debug(ps, depth, desc, "sec_io_access");
49         depth++;
50         
51         if(!prs_uint32("mask", ps, depth, &(t->mask)))
52                 return False;
53
54         return True;
55 }
56
57 /*******************************************************************
58  Check if ACE has OBJECT type.
59 ********************************************************************/
60
61 BOOL sec_ace_object(uint8 type)
62 {
63         if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
64             type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
65             type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
66             type == SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT) {
67                 return True;
68         }
69         return False;
70 }
71
72 /*******************************************************************
73  copy a SEC_ACE structure.
74 ********************************************************************/
75 void sec_ace_copy(SEC_ACE *ace_dest, SEC_ACE *ace_src)
76 {
77         ace_dest->type  = ace_src->type;
78         ace_dest->flags = ace_src->flags;
79         ace_dest->size  = ace_src->size;
80         ace_dest->info.mask = ace_src->info.mask;
81         ace_dest->obj_flags = ace_src->obj_flags;
82         memcpy(&ace_dest->obj_guid, &ace_src->obj_guid, GUID_SIZE);
83         memcpy(&ace_dest->inh_guid, &ace_src->inh_guid, GUID_SIZE);     
84         sid_copy(&ace_dest->trustee, &ace_src->trustee);
85 }
86
87 /*******************************************************************
88  Sets up a SEC_ACE structure.
89 ********************************************************************/
90
91 void init_sec_ace(SEC_ACE *t, DOM_SID *sid, uint8 type, SEC_ACCESS mask, uint8 flag)
92 {
93         t->type = type;
94         t->flags = flag;
95         t->size = sid_size(sid) + 8;
96         t->info = mask;
97
98         ZERO_STRUCTP(&t->trustee);
99         sid_copy(&t->trustee, sid);
100 }
101
102 /*******************************************************************
103  Reads or writes a SEC_ACE structure.
104 ********************************************************************/
105
106 BOOL sec_io_ace(char *desc, SEC_ACE *psa, prs_struct *ps, int depth)
107 {
108         uint32 old_offset;
109         uint32 offset_ace_size;
110
111         if (psa == NULL)
112                 return False;
113
114         prs_debug(ps, depth, desc, "sec_io_ace");
115         depth++;
116         
117         old_offset = prs_offset(ps);
118
119         if(!prs_uint8("type ", ps, depth, &psa->type))
120                 return False;
121
122         if(!prs_uint8("flags", ps, depth, &psa->flags))
123                 return False;
124
125         if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size))
126                 return False;
127
128         if(!sec_io_access("info ", &psa->info, ps, depth))
129                 return False;
130
131         if(!prs_align(ps))
132                 return False;
133
134         /* check whether object access is present */
135         if (!sec_ace_object(psa->type)) {
136                 if (!smb_io_dom_sid("trustee  ", &psa->trustee , ps, depth))
137                         return False;
138         } else {
139                 if (!prs_uint32("obj_flags", ps, depth, &psa->obj_flags))
140                         return False;
141
142                 if (psa->obj_flags & SEC_ACE_OBJECT_PRESENT)
143                         if (!prs_uint8s(False, "obj_guid", ps, depth, psa->obj_guid.info, GUID_SIZE))
144                                 return False;
145
146                 if (psa->obj_flags & SEC_ACE_OBJECT_INHERITED_PRESENT)
147                         if (!prs_uint8s(False, "inh_guid", ps, depth, psa->inh_guid.info, GUID_SIZE))
148                                 return False;
149
150                 if(!smb_io_dom_sid("trustee  ", &psa->trustee , ps, depth))
151                         return False;
152         }
153
154         if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset))
155                 return False;
156         return True;
157 }
158
159 /*******************************************************************
160  adds new SID with its permissions to ACE list
161 ********************************************************************/
162
163 NTSTATUS sec_ace_add_sid(TALLOC_CTX *ctx, SEC_ACE **new, SEC_ACE *old, size_t *num, DOM_SID *sid, uint32 mask)
164 {
165         int i = 0;
166         
167         if (!ctx || !new || !old || !sid || !num)  return NT_STATUS_INVALID_PARAMETER;
168
169         *num += 1;
170         
171         if((new[0] = (SEC_ACE *) talloc_zero(ctx, *num * sizeof(SEC_ACE))) == 0)
172                 return NT_STATUS_NO_MEMORY;
173
174         for (i = 0; i < *num - 1; i ++)
175                 sec_ace_copy(&(*new)[i], &old[i]);
176
177         (*new)[i].type  = 0;
178         (*new)[i].flags = 0;
179         (*new)[i].size  = SEC_ACE_HEADER_SIZE + sid_size(sid);
180         (*new)[i].info.mask = mask;
181         sid_copy(&(*new)[i].trustee, sid);
182         return NT_STATUS_OK;
183 }
184
185 /*******************************************************************
186   modify SID's permissions at ACL 
187 ********************************************************************/
188
189 NTSTATUS sec_ace_mod_sid(SEC_ACE *ace, size_t num, DOM_SID *sid, uint32 mask)
190 {
191         int i = 0;
192
193         if (!ace || !sid)  return NT_STATUS_INVALID_PARAMETER;
194
195         for (i = 0; i < num; i ++) {
196                 if (sid_compare(&ace[i].trustee, sid) == 0) {
197                         ace[i].info.mask = mask;
198                         return NT_STATUS_OK;
199                 }
200         }
201         return NT_STATUS_NOT_FOUND;
202 }
203
204 /*******************************************************************
205  delete SID from ACL
206 ********************************************************************/
207
208 NTSTATUS sec_ace_del_sid(TALLOC_CTX *ctx, SEC_ACE **new, SEC_ACE *old, size_t *num, DOM_SID *sid)
209 {
210         int i     = 0;
211         int n_del = 0;
212
213         if (!ctx || !new || !old || !sid || !num)  return NT_STATUS_INVALID_PARAMETER;
214
215         if((new[0] = (SEC_ACE *) talloc_zero(ctx, *num * sizeof(SEC_ACE))) == 0)
216                 return NT_STATUS_NO_MEMORY;
217
218         for (i = 0; i < *num; i ++) {
219                 if (sid_compare(&old[i].trustee, sid) != 0)
220                         sec_ace_copy(&(*new)[i], &old[i]);
221                 else
222                         n_del ++;
223         }
224         if (n_del == 0)
225                 return NT_STATUS_NOT_FOUND;
226         else {
227                 *num -= n_del;
228                 return NT_STATUS_OK;
229         }
230 }
231
232 /*******************************************************************
233  Create a SEC_ACL structure.  
234 ********************************************************************/
235
236 SEC_ACL *make_sec_acl(TALLOC_CTX *ctx, uint16 revision, int num_aces, SEC_ACE *ace_list)
237 {
238         SEC_ACL *dst;
239         int i;
240
241         if((dst = (SEC_ACL *)talloc_zero(ctx,sizeof(SEC_ACL))) == NULL)
242                 return NULL;
243
244         dst->revision = revision;
245         dst->num_aces = num_aces;
246         dst->size = SEC_ACL_HEADER_SIZE;
247
248         /* Now we need to return a non-NULL address for the ace list even
249            if the number of aces required is zero.  This is because there
250            is a distinct difference between a NULL ace and an ace with zero
251            entries in it.  This is achieved by checking that num_aces is a
252            positive number. */
253
254         if ((num_aces) && 
255             ((dst->ace = (SEC_ACE *)talloc(ctx, sizeof(SEC_ACE) * num_aces)) 
256              == NULL)) {
257                 return NULL;
258         }
259         
260         for (i = 0; i < num_aces; i++) {
261                 dst->ace[i] = ace_list[i]; /* Structure copy. */
262                 dst->size += ace_list[i].size;
263         }
264
265         return dst;
266 }
267
268 /*******************************************************************
269  Duplicate a SEC_ACL structure.  
270 ********************************************************************/
271
272 SEC_ACL *dup_sec_acl(TALLOC_CTX *ctx, SEC_ACL *src)
273 {
274         if(src == NULL)
275                 return NULL;
276
277         return make_sec_acl(ctx, src->revision, src->num_aces, src->ace);
278 }
279
280 /*******************************************************************
281  Reads or writes a SEC_ACL structure.  
282
283  First of the xx_io_xx functions that allocates its data structures
284  for you as it reads them.
285 ********************************************************************/
286
287 BOOL sec_io_acl(char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth)
288 {
289         int i;
290         uint32 old_offset;
291         uint32 offset_acl_size;
292         SEC_ACL *psa;
293
294         /*
295          * Note that the size is always a multiple of 4 bytes due to the
296          * nature of the data structure.  Therefore the prs_align() calls
297          * have been removed as they through us off when doing two-layer
298          * marshalling such as in the printing code (NEW_BUFFER).  --jerry
299          */
300
301         if (ppsa == NULL)
302                 return False;
303
304         psa = *ppsa;
305
306         if(UNMARSHALLING(ps) && psa == NULL) {
307                 /*
308                  * This is a read and we must allocate the stuct to read into.
309                  */
310                 if((psa = (SEC_ACL *)prs_alloc_mem(ps, sizeof(SEC_ACL))) == NULL)
311                         return False;
312                 *ppsa = psa;
313         }
314
315         prs_debug(ps, depth, desc, "sec_io_acl");
316         depth++;
317         
318         old_offset = prs_offset(ps);
319
320         if(!prs_uint16("revision", ps, depth, &psa->revision))
321                 return False;
322
323         if(!prs_uint16_pre("size     ", ps, depth, &psa->size, &offset_acl_size))
324                 return False;
325
326         if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
327                 return False;
328
329         if (UNMARSHALLING(ps)) {
330                 /*
331                  * Even if the num_aces is zero, allocate memory as there's a difference
332                  * between a non-present DACL (allow all access) and a DACL with no ACE's
333                  * (allow no access).
334                  */
335                 if((psa->ace = (SEC_ACE *)prs_alloc_mem(ps,sizeof(psa->ace[0]) * (psa->num_aces+1))) == NULL)
336                         return False;
337         }
338
339         for (i = 0; i < psa->num_aces; i++) {
340                 fstring tmp;
341                 slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
342                 if(!sec_io_ace(tmp, &psa->ace[i], ps, depth))
343                         return False;
344         }
345
346         if(!prs_uint16_post("size     ", ps, depth, &psa->size, offset_acl_size, old_offset))
347                 return False;
348
349         return True;
350 }
351
352 /*******************************************************************
353  Works out the linearization size of a SEC_DESC.
354 ********************************************************************/
355
356 size_t sec_desc_size(SEC_DESC *psd)
357 {
358         size_t offset;
359
360         if (!psd) return 0;
361
362         offset = SEC_DESC_HEADER_SIZE;
363
364         /* don't align */
365
366         if (psd->owner_sid != NULL)
367                 offset += sid_size(psd->owner_sid);
368
369         if (psd->grp_sid != NULL)
370                 offset += sid_size(psd->grp_sid);
371
372         if (psd->sacl != NULL)
373                 offset += psd->sacl->size;
374
375         if (psd->dacl != NULL)
376                 offset += psd->dacl->size;
377
378         return offset;
379 }
380
381 /*******************************************************************
382  Compares two SEC_ACE structures
383 ********************************************************************/
384
385 BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
386 {
387         /* Trivial case */
388
389         if (!s1 && !s2) return True;
390
391         /* Check top level stuff */
392
393         if (s1->type != s2->type || s1->flags != s2->flags ||
394             s1->info.mask != s2->info.mask) {
395                 return False;
396         }
397
398         /* Check SID */
399
400         if (!sid_equal(&s1->trustee, &s2->trustee)) {
401                 return False;
402         }
403
404         return True;
405 }
406
407 /*******************************************************************
408  Compares two SEC_ACL structures
409 ********************************************************************/
410
411 BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
412 {
413         int i, j;
414
415         /* Trivial cases */
416
417         if (!s1 && !s2) return True;
418         if (!s1 || !s2) return False;
419
420         /* Check top level stuff */
421
422         if (s1->revision != s2->revision) {
423                 DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
424                            s1->revision, s2->revision));
425                 return False;
426         }
427
428         if (s1->num_aces != s2->num_aces) {
429                 DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
430                            s1->revision, s2->revision));
431                 return False;
432         }
433
434         /* The ACEs could be in any order so check each ACE in s1 against 
435            each ACE in s2. */
436
437         for (i = 0; i < s1->num_aces; i++) {
438                 BOOL found = False;
439
440                 for (j = 0; j < s2->num_aces; j++) {
441                         if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
442                                 found = True;
443                                 break;
444                         }
445                 }
446
447                 if (!found) return False;
448         }
449
450         return True;
451 }
452
453 /*******************************************************************
454  Compares two SEC_DESC structures
455 ********************************************************************/
456
457 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
458 {
459         /* Trivial case */
460
461         if (!s1 && !s2) {
462                 goto done;
463         }
464
465         /* Check top level stuff */
466
467         if (s1->revision != s2->revision) {
468                 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
469                            s1->revision, s2->revision));
470                 return False;
471         }
472
473         if (s1->type!= s2->type) {
474                 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
475                            s1->type, s2->type));
476                 return False;
477         }
478
479         /* Check owner and group */
480
481         if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
482                 fstring str1, str2;
483
484                 sid_to_string(str1, s1->owner_sid);
485                 sid_to_string(str2, s2->owner_sid);
486
487                 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
488                            str1, str2));
489                 return False;
490         }
491
492         if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
493                 fstring str1, str2;
494
495                 sid_to_string(str1, s1->grp_sid);
496                 sid_to_string(str2, s2->grp_sid);
497
498                 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
499                            str1, str2));
500                 return False;
501         }
502
503         /* Check ACLs present in one but not the other */
504
505         if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
506             (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
507                 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
508                 return False;
509         }
510
511         /* Sigh - we have to do it the hard way by iterating over all
512            the ACEs in the ACLs */
513
514         if (!sec_acl_equal(s1->dacl, s2->dacl) ||
515             !sec_acl_equal(s1->sacl, s2->sacl)) {
516                 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
517                 return False;
518         }
519
520  done:
521         DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
522         return True;
523 }
524
525 /*******************************************************************
526  Merge part of security descriptor old_sec in to the empty sections of 
527  security descriptor new_sec.
528 ********************************************************************/
529
530 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
531 {
532         DOM_SID *owner_sid, *group_sid;
533         SEC_DESC_BUF *return_sdb;
534         SEC_ACL *dacl, *sacl;
535         SEC_DESC *psd = NULL;
536         uint16 secdesc_type;
537         size_t secdesc_size;
538
539         /* Copy over owner and group sids.  There seems to be no flag for
540            this so just check the pointer values. */
541
542         owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
543                 old_sdb->sec->owner_sid;
544
545         group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
546                 old_sdb->sec->grp_sid;
547         
548         secdesc_type = new_sdb->sec->type;
549
550         /* Ignore changes to the system ACL.  This has the effect of making
551            changes through the security tab audit button not sticking. 
552            Perhaps in future Samba could implement these settings somehow. */
553
554         sacl = NULL;
555         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
556
557         /* Copy across discretionary ACL */
558
559         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
560                 dacl = new_sdb->sec->dacl;
561         } else {
562                 dacl = old_sdb->sec->dacl;
563         }
564
565         /* Create new security descriptor from bits */
566
567         psd = make_sec_desc(ctx, new_sdb->sec->revision, 
568                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
569
570         return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
571
572         return(return_sdb);
573 }
574
575 /*******************************************************************
576  Tallocs a duplicate SID. 
577 ********************************************************************/ 
578
579 static DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, DOM_SID *src)
580 {
581   DOM_SID *dst;
582
583   if(!src)
584     return NULL;
585
586   if((dst = talloc_zero(ctx, sizeof(DOM_SID))) != NULL) {
587     sid_copy( dst, src);
588   }
589
590   return dst;
591 }
592
593 /*******************************************************************
594  Creates a SEC_DESC structure
595 ********************************************************************/
596
597 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, 
598                         DOM_SID *owner_sid, DOM_SID *grp_sid,
599                         SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
600 {
601         SEC_DESC *dst;
602         uint32 offset     = 0;
603         uint32 offset_sid = SEC_DESC_HEADER_SIZE;
604         uint32 offset_acl = 0;
605
606         *sd_size = 0;
607
608         if(( dst = (SEC_DESC *)talloc_zero(ctx, sizeof(SEC_DESC))) == NULL)
609                 return NULL;
610
611         dst->revision = revision;
612         dst->type     = SEC_DESC_SELF_RELATIVE;
613
614         if (sacl) dst->type |= SEC_DESC_SACL_PRESENT;
615         if (dacl) dst->type |= SEC_DESC_DACL_PRESENT;
616
617         dst->off_owner_sid = 0;
618         dst->off_grp_sid   = 0;
619         dst->off_sacl      = 0;
620         dst->off_dacl      = 0;
621
622         if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
623                 goto error_exit;
624
625         if(grp_sid && ((dst->grp_sid = sid_dup_talloc(ctx,grp_sid)) == NULL))
626                 goto error_exit;
627
628         if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
629                 goto error_exit;
630
631         if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
632                 goto error_exit;
633
634         offset = 0;
635
636         /*
637          * Work out the linearization sizes.
638          */
639         if (dst->owner_sid != NULL) {
640
641                 if (offset == 0)
642                         offset = SEC_DESC_HEADER_SIZE;
643
644                 offset += sid_size(dst->owner_sid);
645         }
646
647         if (dst->grp_sid != NULL) {
648
649                 if (offset == 0)
650                         offset = SEC_DESC_HEADER_SIZE;
651
652                 offset += sid_size(dst->grp_sid);
653         }
654
655         if (dst->sacl != NULL) {
656
657                 offset_acl = SEC_DESC_HEADER_SIZE;
658
659                 dst->off_sacl  = offset_acl;
660                 offset_acl    += dst->sacl->size;
661                 offset        += dst->sacl->size;
662                 offset_sid    += dst->sacl->size;
663         }
664
665         if (dst->dacl != NULL) {
666
667                 if (offset_acl == 0)
668                         offset_acl = SEC_DESC_HEADER_SIZE;
669
670                 dst->off_dacl  = offset_acl;
671                 offset_acl    += dst->dacl->size;
672                 offset        += dst->dacl->size;
673                 offset_sid    += dst->dacl->size;
674         }
675
676         *sd_size = (size_t)((offset == 0) ? SEC_DESC_HEADER_SIZE : offset);
677
678         if (dst->owner_sid != NULL) {
679                 dst->off_owner_sid = offset_sid;
680                 dst->off_grp_sid = offset_sid + sid_size(dst->owner_sid);
681         }
682         else
683                 if (dst->grp_sid != NULL)
684                         dst->off_grp_sid = offset_sid;
685
686         return dst;
687
688 error_exit:
689
690         *sd_size = 0;
691         return NULL;
692 }
693
694 /*******************************************************************
695  Duplicate a SEC_DESC structure.  
696 ********************************************************************/
697
698 SEC_DESC *dup_sec_desc( TALLOC_CTX *ctx, SEC_DESC *src)
699 {
700         size_t dummy;
701
702         if(src == NULL)
703                 return NULL;
704
705         return make_sec_desc( ctx, src->revision, 
706                                 src->owner_sid, src->grp_sid, src->sacl,
707                                 src->dacl, &dummy);
708 }
709
710 /*******************************************************************
711  Creates a SEC_DESC structure with typical defaults.
712 ********************************************************************/
713
714 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, DOM_SID *owner_sid, DOM_SID *grp_sid,
715                                  SEC_ACL *dacl, size_t *sd_size)
716 {
717         return make_sec_desc(ctx, SEC_DESC_REVISION,
718                              owner_sid, grp_sid, NULL, dacl, sd_size);
719 }
720
721 /*******************************************************************
722  Reads or writes a SEC_DESC structure.
723  If reading and the *ppsd = NULL, allocates the structure.
724 ********************************************************************/
725
726 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
727 {
728         uint32 old_offset;
729         uint32 max_offset = 0; /* after we're done, move offset to end */
730         uint32 tmp_offset = 0;
731         
732         SEC_DESC *psd;
733
734         if (ppsd == NULL)
735                 return False;
736
737         psd = *ppsd;
738
739         if (psd == NULL) {
740                 if(UNMARSHALLING(ps)) {
741                         if((psd = (SEC_DESC *)prs_alloc_mem(ps,sizeof(SEC_DESC))) == NULL)
742                                 return False;
743                         *ppsd = psd;
744                 } else {
745                         /* Marshalling - just ignore. */
746                         return True;
747                 }
748         }
749
750         prs_debug(ps, depth, desc, "sec_io_desc");
751         depth++;
752
753 #if 0   
754         /*
755          * if alignment is needed, should be done by the the 
756          * caller.  Not here.  This caused me problems when marshalling
757          * printer info into a buffer.   --jerry
758          */
759         if(!prs_align(ps))
760                 return False;
761 #endif
762         
763         /* start of security descriptor stored for back-calc offset purposes */
764         old_offset = prs_offset(ps);
765
766         if(!prs_uint16("revision ", ps, depth, &psd->revision))
767                 return False;
768
769         if(!prs_uint16("type     ", ps, depth, &psd->type))
770                 return False;
771
772         if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
773                 return False;
774
775         if(!prs_uint32("off_grp_sid  ", ps, depth, &psd->off_grp_sid))
776                 return False;
777
778         if(!prs_uint32("off_sacl     ", ps, depth, &psd->off_sacl))
779                 return False;
780
781         if(!prs_uint32("off_dacl     ", ps, depth, &psd->off_dacl))
782                 return False;
783
784         max_offset = MAX(max_offset, prs_offset(ps));
785
786         if (psd->off_owner_sid != 0) {
787
788                 if (UNMARSHALLING(ps)) {
789                         if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
790                                 return False;
791                         /* reading */
792                         if((psd->owner_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->owner_sid))) == NULL)
793                                 return False;
794                 }
795
796                 tmp_offset = ps->data_offset;
797                 ps->data_offset = psd->off_owner_sid;
798
799                 if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
800                         return False;
801                 if(!prs_align(ps))
802                         return False;
803
804                 ps->data_offset = tmp_offset;
805         }
806
807         max_offset = MAX(max_offset, prs_offset(ps));
808
809         if (psd->off_grp_sid != 0) {
810
811                 if (UNMARSHALLING(ps)) {
812                         /* reading */
813                         if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
814                                 return False;
815                         if((psd->grp_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->grp_sid))) == NULL)
816                                 return False;
817                 }
818
819                 tmp_offset = ps->data_offset;
820                 ps->data_offset = psd->off_grp_sid;
821
822                 if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
823                         return False;
824                 ps->data_offset = tmp_offset;
825         }
826
827         max_offset = MAX(max_offset, prs_offset(ps));
828
829         if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
830                 if(!prs_set_offset(ps, old_offset + psd->off_sacl))
831                         return False;
832                 if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
833                         return False;
834         }
835
836         max_offset = MAX(max_offset, prs_offset(ps));
837
838         if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
839                 if(!prs_set_offset(ps, old_offset + psd->off_dacl))
840                         return False;
841                 if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
842                         return False;
843         }
844
845         max_offset = MAX(max_offset, prs_offset(ps));
846
847         if(!prs_set_offset(ps, max_offset))
848                 return False;
849         return True;
850 }
851
852 /*******************************************************************
853  Creates a SEC_DESC_BUF structure.
854 ********************************************************************/
855
856 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
857 {
858         SEC_DESC_BUF *dst;
859
860         if((dst = (SEC_DESC_BUF *)talloc_zero(ctx, sizeof(SEC_DESC_BUF))) == NULL)
861                 return NULL;
862
863         /* max buffer size (allocated size) */
864         dst->max_len = (uint32)len;
865         dst->len = (uint32)len;
866         
867         if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
868                 return NULL;
869         }
870
871         dst->ptr = 0x1;
872
873         return dst;
874 }
875
876 /*******************************************************************
877  Duplicates a SEC_DESC_BUF structure.
878 ********************************************************************/
879
880 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
881 {
882         if(src == NULL)
883                 return NULL;
884
885         return make_sec_desc_buf( ctx, src->len, src->sec);
886 }
887
888 /*******************************************************************
889  Reads or writes a SEC_DESC_BUF structure.
890 ********************************************************************/
891
892 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
893 {
894         uint32 off_len;
895         uint32 off_max_len;
896         uint32 old_offset;
897         uint32 size;
898         SEC_DESC_BUF *psdb;
899
900         if (ppsdb == NULL)
901                 return False;
902
903         psdb = *ppsdb;
904
905         if (UNMARSHALLING(ps) && psdb == NULL) {
906                 if((psdb = (SEC_DESC_BUF *)prs_alloc_mem(ps,sizeof(SEC_DESC_BUF))) == NULL)
907                         return False;
908                 *ppsdb = psdb;
909         }
910
911         prs_debug(ps, depth, desc, "sec_io_desc_buf");
912         depth++;
913
914         if(!prs_align(ps))
915                 return False;
916         
917         if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
918                 return False;
919
920         if(!prs_uint32    ("ptr  ", ps, depth, &psdb->ptr))
921                 return False;
922
923         if(!prs_uint32_pre("len    ", ps, depth, &psdb->len, &off_len))
924                 return False;
925
926         old_offset = prs_offset(ps);
927
928         /* reading, length is non-zero; writing, descriptor is non-NULL */
929         if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
930                 if(!sec_io_desc("sec   ", &psdb->sec, ps, depth))
931                         return False;
932         }
933
934         if(!prs_align(ps))
935                 return False;
936         
937         size = prs_offset(ps) - old_offset;
938         if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
939                 return False;
940
941         if(!prs_uint32_post("len    ", ps, depth, &psdb->len, off_len, size))
942                 return False;
943
944         return True;
945 }
946
947 /*******************************************************************
948  adds new SID with its permissions to SEC_DESC
949 ********************************************************************/
950
951 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
952 {
953         SEC_DESC *sd   = 0;
954         SEC_ACL  *dacl = 0;
955         SEC_ACE  *ace  = 0;
956         NTSTATUS  status;
957
958         *sd_size = 0;
959
960         if (!ctx || !psd || !sid || !sd_size)  return NT_STATUS_INVALID_PARAMETER;
961
962         status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid, mask);
963         
964         if (!NT_STATUS_IS_OK(status))
965                 return status;
966
967         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
968                 return NT_STATUS_UNSUCCESSFUL;
969         
970         if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->owner_sid, 
971                 psd[0]->grp_sid, psd[0]->sacl, dacl, sd_size)))
972                 return NT_STATUS_UNSUCCESSFUL;
973
974         *psd = sd;
975          sd  = 0;
976         return NT_STATUS_OK;
977 }
978
979 /*******************************************************************
980  modify SID's permissions at SEC_DESC
981 ********************************************************************/
982
983 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
984 {
985         NTSTATUS status;
986
987         if (!sd || !sid) return NT_STATUS_INVALID_PARAMETER;
988
989         status = sec_ace_mod_sid(sd->dacl->ace, sd->dacl->num_aces, sid, mask);
990
991         if (!NT_STATUS_IS_OK(status))
992                 return status;
993         
994         return NT_STATUS_OK;
995 }
996
997 /*******************************************************************
998  delete SID from SEC_DESC
999 ********************************************************************/
1000
1001 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
1002 {
1003         SEC_DESC *sd   = 0;
1004         SEC_ACL  *dacl = 0;
1005         SEC_ACE  *ace  = 0;
1006         NTSTATUS  status;
1007
1008         *sd_size = 0;
1009         
1010         if (!ctx || !psd[0] || !sid || !sd_size) return NT_STATUS_INVALID_PARAMETER;
1011
1012         status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid);
1013
1014         if (!NT_STATUS_IS_OK(status))
1015                 return status;
1016
1017         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
1018                 return NT_STATUS_UNSUCCESSFUL;
1019         
1020         if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->owner_sid, 
1021                 psd[0]->grp_sid, psd[0]->sacl, dacl, sd_size)))
1022                 return NT_STATUS_UNSUCCESSFUL;
1023
1024         *psd = sd;
1025          sd  = 0;
1026         return NT_STATUS_OK;
1027 }