As prs_alloc_mem now zeros memory, remove superfluous memsets after it.
[bbaumbach/samba-autobuild/.git] / source / 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
26 #include "includes.h"
27
28 extern int DEBUGLEVEL;
29
30 #define SD_HEADER_SIZE 0x14
31
32 /*******************************************************************
33  Sets up a SEC_ACCESS structure.
34 ********************************************************************/
35
36 void init_sec_access(SEC_ACCESS *t, uint32 mask)
37 {
38         t->mask = mask;
39 }
40
41 /*******************************************************************
42  Reads or writes a SEC_ACCESS structure.
43 ********************************************************************/
44
45 BOOL sec_io_access(char *desc, SEC_ACCESS *t, prs_struct *ps, int depth)
46 {
47         if (t == NULL)
48                 return False;
49
50         prs_debug(ps, depth, desc, "sec_io_access");
51         depth++;
52
53         if(!prs_align(ps))
54                 return False;
55         
56         if(!prs_uint32("mask", ps, depth, &(t->mask)))
57                 return False;
58
59         return True;
60 }
61
62
63 /*******************************************************************
64  Sets up a SEC_ACE structure.
65 ********************************************************************/
66
67 void init_sec_ace(SEC_ACE *t, DOM_SID *sid, uint8 type, SEC_ACCESS mask, uint8 flag)
68 {
69         t->type = type;
70         t->flags = flag;
71         t->size = sid_size(sid) + 8;
72         t->info = mask;
73
74         ZERO_STRUCTP(&t->sid);
75         sid_copy(&t->sid, sid);
76 }
77
78 /*******************************************************************
79  Reads or writes a SEC_ACE structure.
80 ********************************************************************/
81
82 BOOL sec_io_ace(char *desc, SEC_ACE *psa, prs_struct *ps, int depth)
83 {
84         uint32 old_offset;
85         uint32 offset_ace_size;
86
87         if (psa == NULL)
88                 return False;
89
90         prs_debug(ps, depth, desc, "sec_io_ace");
91         depth++;
92
93         if(!prs_align(ps))
94                 return False;
95         
96         old_offset = prs_offset(ps);
97
98         if(!prs_uint8("type ", ps, depth, &psa->type))
99                 return False;
100
101         if(!prs_uint8("flags", ps, depth, &psa->flags))
102                 return False;
103
104         if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size))
105                 return False;
106
107         if(!sec_io_access("info ", &psa->info, ps, depth))
108                 return False;
109
110         if(!prs_align(ps))
111                 return False;
112
113         if(!smb_io_dom_sid("sid  ", &psa->sid , ps, depth))
114                 return False;
115
116         if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset))
117                 return False;
118
119         return True;
120 }
121
122 /*******************************************************************
123  Create a SEC_ACL structure.  
124 ********************************************************************/
125
126 SEC_ACL *make_sec_acl(uint16 revision, int num_aces, SEC_ACE *ace_list)
127 {
128         SEC_ACL *dst;
129         int i;
130
131         if((dst = (SEC_ACL *)malloc(sizeof(SEC_ACL))) == NULL)
132                 return NULL;
133
134         ZERO_STRUCTP(dst);
135
136         dst->revision = revision;
137         dst->num_aces = num_aces;
138         dst->size = 8;
139
140         if((dst->ace = (SEC_ACE *)malloc( sizeof(SEC_ACE) * num_aces )) == NULL) {
141                 free_sec_acl(&dst);
142                 return NULL;
143         }
144
145         for (i = 0; i < num_aces; i++) {
146                 dst->ace[i] = ace_list[i]; /* Structure copy. */
147                 dst->size += ace_list[i].size;
148         }
149
150         return dst;
151 }
152
153 /*******************************************************************
154  Duplicate a SEC_ACL structure.  
155 ********************************************************************/
156
157 SEC_ACL *dup_sec_acl( SEC_ACL *src)
158 {
159         if(src == NULL)
160                 return NULL;
161
162         return make_sec_acl( src->revision, src->num_aces, src->ace);
163 }
164
165 /*******************************************************************
166  Delete a SEC_ACL structure.  
167 ********************************************************************/
168
169 void free_sec_acl(SEC_ACL **ppsa)
170 {
171         SEC_ACL *psa;
172
173         if(ppsa == NULL || *ppsa == NULL)
174                 return;
175
176         psa = *ppsa;
177         if (psa->ace != NULL)
178                 free(psa->ace);
179
180         free(psa);
181         *ppsa = NULL;
182 }
183
184 /*******************************************************************
185  Reads or writes a SEC_ACL structure.  
186
187  First of the xx_io_xx functions that allocates its data structures
188  for you as it reads them.
189 ********************************************************************/
190
191 BOOL sec_io_acl(char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth)
192 {
193         int i;
194         uint32 old_offset;
195         uint32 offset_acl_size;
196         SEC_ACL *psa;
197
198         if (ppsa == NULL)
199                 return False;
200
201         psa = *ppsa;
202
203         if(UNMARSHALLING(ps) && psa == NULL) {
204                 /*
205                  * This is a read and we must allocate the stuct to read into.
206                  */
207                 if((psa = (SEC_ACL *)malloc(sizeof(SEC_ACL))) == NULL)
208                         return False;
209                 *ppsa = psa;
210         }
211
212         prs_debug(ps, depth, desc, "sec_io_acl");
213         depth++;
214
215         if(!prs_align(ps))
216                 return False;
217         
218         old_offset = prs_offset(ps);
219
220         if(!prs_uint16("revision", ps, depth, &psa->revision))
221                 return False;
222
223         if(!prs_uint16_pre("size     ", ps, depth, &psa->size, &offset_acl_size))
224                 return False;
225
226         if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
227                 return False;
228
229         if (UNMARSHALLING(ps) && psa->num_aces != 0) {
230                 /* reading */
231                 if((psa->ace = malloc(sizeof(psa->ace[0]) * psa->num_aces)) == NULL)
232                         return False;
233         }
234
235         for (i = 0; i < psa->num_aces; i++) {
236                 fstring tmp;
237                 slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
238                 if(!sec_io_ace(tmp, &psa->ace[i], ps, depth))
239                         return False;
240         }
241
242         if(!prs_align(ps))
243                 return False;
244
245         if(!prs_uint16_post("size     ", ps, depth, &psa->size, offset_acl_size, old_offset))
246                 return False;
247
248         return True;
249 }
250
251 /*******************************************************************
252  Works out the linearization size of a SEC_DESC.
253 ********************************************************************/
254
255 size_t sec_desc_size(SEC_DESC *psd)
256 {
257         size_t offset;
258
259         if (!psd) return 0;
260
261         offset = SD_HEADER_SIZE;
262
263         if (psd->owner_sid != NULL)
264                 offset += ((sid_size(psd->owner_sid) + 3) & ~3);
265
266         if (psd->grp_sid != NULL)
267                 offset += ((sid_size(psd->grp_sid) + 3) & ~3);
268
269         if (psd->sacl != NULL)
270                 offset += ((psd->sacl->size + 3) & ~3);
271
272         if (psd->dacl != NULL)
273                 offset += ((psd->dacl->size + 3) & ~3);
274
275         return offset;
276 }
277
278 /*******************************************************************
279  Compares two SEC_ACE structures
280 ********************************************************************/
281
282 BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
283 {
284         /* Trivial case */
285
286         if (!s1 && !s2) return True;
287
288         /* Check top level stuff */
289
290         if (s1->type != s2->type || s1->flags != s2->flags ||
291             s1->info.mask != s2->info.mask) {
292                 return False;
293         }
294
295         /* Check SID */
296
297         if (!sid_equal(&s1->sid, &s2->sid)) {
298                 return False;
299         }
300
301         return True;
302 }
303
304 /*******************************************************************
305  Compares two SEC_ACL structures
306 ********************************************************************/
307
308 BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
309 {
310         int i, j;
311
312         /* Trivial case */
313
314         if (!s1 && !s2) return True;
315
316         /* Check top level stuff */
317
318         if (s1->revision != s2->revision) {
319                 DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
320                            s1->revision, s2->revision));
321                 return False;
322         }
323
324         if (s1->num_aces != s2->num_aces) {
325                 DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
326                            s1->revision, s2->revision));
327                 return False;
328         }
329
330         /* The ACEs could be in any order so check each ACE in s1 against 
331            each ACE in s2. */
332
333         for (i = 0; i < s1->num_aces; i++) {
334                 BOOL found = False;
335
336                 for (j = 0; j < s2->num_aces; j++) {
337                         if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
338                                 found = True;
339                                 break;
340                         }
341                 }
342
343                 if (!found) return False;
344         }
345
346         return True;
347 }
348
349 /*******************************************************************
350  Compares two SEC_DESC structures
351 ********************************************************************/
352
353 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
354 {
355         /* Trivial case */
356
357         if (!s1 && !s2) {
358                 goto done;
359         }
360
361         /* Check top level stuff */
362
363         if (s1->revision != s2->revision) {
364                 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
365                            s1->revision, s2->revision));
366                 return False;
367         }
368
369         if (s1->type!= s2->type) {
370                 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
371                            s1->type, s2->type));
372                 return False;
373         }
374
375         /* Check owner and group */
376
377         if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
378                 fstring str1, str2;
379
380                 sid_to_string(str1, s1->owner_sid);
381                 sid_to_string(str2, s2->owner_sid);
382
383                 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
384                            str1, str2));
385                 return False;
386         }
387
388         if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
389                 fstring str1, str2;
390
391                 sid_to_string(str1, s1->grp_sid);
392                 sid_to_string(str2, s2->grp_sid);
393
394                 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
395                            str1, str2));
396                 return False;
397         }
398
399         /* Check ACLs present in one but not the other */
400
401         if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
402             (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
403                 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
404                 return False;
405         }
406
407         /* Sigh - we have to do it the hard way by iterating over all
408            the ACEs in the ACLs */
409
410         if (!sec_acl_equal(s1->dacl, s2->dacl) ||
411             !sec_acl_equal(s1->sacl, s2->sacl)) {
412                 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
413                 return False;
414         }
415
416  done:
417         DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
418         return True;
419 }
420
421 /*******************************************************************
422  Merge part of security descriptor old_sec in to the empty sections of 
423  security descriptor new_sec.
424 ********************************************************************/
425
426 SEC_DESC_BUF *sec_desc_merge(SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
427 {
428         DOM_SID *owner_sid, *group_sid;
429         SEC_DESC_BUF *return_sdb;
430         SEC_ACL *dacl, *sacl;
431         SEC_DESC *psd = NULL;
432         uint16 secdesc_type;
433         size_t secdesc_size;
434
435         /* Copy over owner and group sids.  There seems to be no flag for
436            this so just check the pointer values. */
437
438         owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
439                 old_sdb->sec->owner_sid;
440
441         group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
442                 old_sdb->sec->grp_sid;
443         
444         secdesc_type = new_sdb->sec->type;
445
446         /* Ignore changes to the system ACL.  This has the effect of making
447            changes through the security tab audit button not sticking. 
448            Perhaps in future Samba could implement these settings somehow. */
449
450         sacl = NULL;
451         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
452
453         /* Copy across discretionary ACL */
454
455         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
456                 dacl = new_sdb->sec->dacl;
457         } else {
458                 dacl = old_sdb->sec->dacl;
459         }
460
461         /* Create new security descriptor from bits */
462
463         psd = make_sec_desc(new_sdb->sec->revision, 
464                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
465
466         return_sdb = make_sec_desc_buf(secdesc_size, psd);
467
468         free_sec_desc(&psd);
469
470         return(return_sdb);
471 }
472
473 /*******************************************************************
474  Creates a SEC_DESC structure
475 ********************************************************************/
476
477 SEC_DESC *make_sec_desc(uint16 revision, 
478                         DOM_SID *owner_sid, DOM_SID *grp_sid,
479                         SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
480 {
481         SEC_DESC *dst;
482         uint32 offset;
483
484         *sd_size = 0;
485
486         if(( dst = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
487                 return NULL;
488
489         ZERO_STRUCTP(dst);
490
491         dst->revision = revision;
492         dst->type     = SEC_DESC_SELF_RELATIVE;
493
494         if (sacl) dst->type |= SEC_DESC_SACL_PRESENT;
495         if (dacl) dst->type |= SEC_DESC_DACL_PRESENT;
496
497         dst->off_owner_sid = 0;
498         dst->off_grp_sid   = 0;
499         dst->off_sacl      = 0;
500         dst->off_dacl      = 0;
501
502         if(owner_sid && ((dst->owner_sid = sid_dup(owner_sid)) == NULL))
503                 goto error_exit;
504
505         if(grp_sid && ((dst->grp_sid = sid_dup(grp_sid)) == NULL))
506                 goto error_exit;
507
508         if(sacl && ((dst->sacl = dup_sec_acl(sacl)) == NULL))
509                 goto error_exit;
510
511         if(dacl && ((dst->dacl = dup_sec_acl(dacl)) == NULL))
512                 goto error_exit;
513                 
514         offset = 0;
515
516         /*
517          * Work out the linearization sizes.
518          */
519
520         if (dst->owner_sid != NULL) {
521
522                 if (offset == 0)
523                         offset = SD_HEADER_SIZE;
524
525                 dst->off_owner_sid = offset;
526                 offset += ((sid_size(dst->owner_sid) + 3) & ~3);
527         }
528
529         if (dst->grp_sid != NULL) {
530
531                 if (offset == 0)
532                         offset = SD_HEADER_SIZE;
533
534                 dst->off_grp_sid = offset;
535                 offset += ((sid_size(dst->grp_sid) + 3) & ~3);
536         }
537
538         if (dst->sacl != NULL) {
539
540                 if (offset == 0)
541                         offset = SD_HEADER_SIZE;
542
543                 dst->off_sacl = offset;
544                 offset += ((sacl->size + 3) & ~3);
545         }
546
547         if (dst->dacl != NULL) {
548
549                 if (offset == 0)
550                         offset = SD_HEADER_SIZE;
551
552                 dst->off_dacl = offset;
553                 offset += ((dacl->size + 3) & ~3);
554         }
555
556         *sd_size = (size_t)((offset == 0) ? SD_HEADER_SIZE : offset);
557         return dst;
558
559 error_exit:
560
561         *sd_size = 0;
562         free_sec_desc(&dst);
563         return NULL;
564 }
565
566 /*******************************************************************
567  Duplicate a SEC_DESC structure.  
568 ********************************************************************/
569
570 SEC_DESC *dup_sec_desc( SEC_DESC *src)
571 {
572         size_t dummy;
573
574         if(src == NULL)
575                 return NULL;
576
577         return make_sec_desc( src->revision, 
578                                 src->owner_sid, src->grp_sid, src->sacl,
579                                 src->dacl, &dummy);
580 }
581
582 /*******************************************************************
583  Deletes a SEC_DESC structure
584 ********************************************************************/
585
586 void free_sec_desc(SEC_DESC **ppsd)
587 {
588         SEC_DESC *psd;
589
590         if(ppsd == NULL || *ppsd == NULL)
591                 return;
592
593         psd = *ppsd;
594
595         free_sec_acl(&psd->dacl);
596         free_sec_acl(&psd->sacl);
597         free(psd->owner_sid);
598         free(psd->grp_sid);
599         free(psd);
600         *ppsd = NULL;
601 }
602
603 /*******************************************************************
604  Creates a SEC_DESC structure with typical defaults.
605 ********************************************************************/
606
607 SEC_DESC *make_standard_sec_desc(DOM_SID *owner_sid, DOM_SID *grp_sid,
608                                  SEC_ACL *dacl, size_t *sd_size)
609 {
610         return make_sec_desc(SEC_DESC_REVISION,
611                              owner_sid, grp_sid, NULL, dacl, sd_size);
612 }
613
614 /*******************************************************************
615  Reads or writes a SEC_DESC structure.
616  If reading and the *ppsd = NULL, allocates the structure.
617 ********************************************************************/
618
619 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
620 {
621         uint32 old_offset;
622         uint32 max_offset = 0; /* after we're done, move offset to end */
623         SEC_DESC *psd;
624
625         if (ppsd == NULL)
626                 return False;
627
628         psd = *ppsd;
629
630         if (psd == NULL) {
631                 if(UNMARSHALLING(ps)) {
632                         if((psd = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
633                                 return False;
634                         *ppsd = psd;
635                 } else {
636                         /* Marshalling - just ignore. */
637                         return True;
638                 }
639         }
640
641         prs_debug(ps, depth, desc, "sec_io_desc");
642         depth++;
643
644         if(!prs_align(ps))
645                 return False;
646         
647         /* start of security descriptor stored for back-calc offset purposes */
648         old_offset = prs_offset(ps);
649
650         if(!prs_uint16("revision ", ps, depth, &psd->revision))
651                 return False;
652
653         if(!prs_uint16("type     ", ps, depth, &psd->type))
654                 return False;
655
656         if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
657                 return False;
658
659         if(!prs_uint32("off_grp_sid  ", ps, depth, &psd->off_grp_sid))
660                 return False;
661
662         if(!prs_uint32("off_sacl     ", ps, depth, &psd->off_sacl))
663                 return False;
664
665         if(!prs_uint32("off_dacl     ", ps, depth, &psd->off_dacl))
666                 return False;
667
668         max_offset = MAX(max_offset, prs_offset(ps));
669
670         if (psd->off_owner_sid != 0) {
671
672                 if (UNMARSHALLING(ps)) {
673                         if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
674                                 return False;
675                         /* reading */
676                         if((psd->owner_sid = malloc(sizeof(*psd->owner_sid))) == NULL)
677                                 return False;
678                 }
679
680                 if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
681                         return False;
682                 if(!prs_align(ps))
683                         return False;
684         }
685
686         max_offset = MAX(max_offset, prs_offset(ps));
687
688         if (psd->off_grp_sid != 0) {
689
690                 if (UNMARSHALLING(ps)) {
691                         /* reading */
692                         if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
693                                 return False;
694                         if((psd->grp_sid = malloc(sizeof(*psd->grp_sid))) == NULL)
695                                 return False;
696                 }
697
698                 if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
699                         return False;
700                 if(!prs_align(ps))
701                         return False;
702         }
703
704         max_offset = MAX(max_offset, prs_offset(ps));
705
706         if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
707                 if(!prs_set_offset(ps, old_offset + psd->off_sacl))
708                         return False;
709                 if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
710                         return False;
711                 if(!prs_align(ps))
712                         return False;
713         }
714
715         max_offset = MAX(max_offset, prs_offset(ps));
716
717         if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
718                 if(!prs_set_offset(ps, old_offset + psd->off_dacl))
719                         return False;
720                 if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
721                         return False;
722                 if(!prs_align(ps))
723                         return False;
724         }
725
726         max_offset = MAX(max_offset, prs_offset(ps));
727
728         if(!prs_set_offset(ps, max_offset))
729                 return False;
730         return True;
731 }
732
733 /*******************************************************************
734  Creates a SEC_DESC_BUF structure.
735 ********************************************************************/
736
737 SEC_DESC_BUF *make_sec_desc_buf(size_t len, SEC_DESC *sec_desc)
738 {
739         SEC_DESC_BUF *dst;
740
741         if((dst = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
742                 return NULL;
743
744         ZERO_STRUCTP(dst);
745
746         /* max buffer size (allocated size) */
747         dst->max_len = (uint32)len;
748         dst->len = (uint32)len;
749
750         if(sec_desc && ((dst->sec = dup_sec_desc(sec_desc)) == NULL)) {
751                 free_sec_desc_buf(&dst);
752                 return NULL;
753         }
754
755         return dst;
756 }
757
758 /*******************************************************************
759  Duplicates a SEC_DESC_BUF structure.
760 ********************************************************************/
761
762 SEC_DESC_BUF *dup_sec_desc_buf(SEC_DESC_BUF *src)
763 {
764         if(src == NULL)
765                 return NULL;
766
767         return make_sec_desc_buf( src->len, src->sec);
768 }
769
770 /*******************************************************************
771  Deletes a SEC_DESC_BUF structure.
772 ********************************************************************/
773
774 void free_sec_desc_buf(SEC_DESC_BUF **ppsdb)
775 {
776         SEC_DESC_BUF *psdb;
777
778         if(ppsdb == NULL || *ppsdb == NULL)
779                 return;
780
781         psdb = *ppsdb;
782         free_sec_desc(&psdb->sec);
783         free(psdb);
784         *ppsdb = NULL;
785 }
786
787
788 /*******************************************************************
789  Reads or writes a SEC_DESC_BUF structure.
790 ********************************************************************/
791
792 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
793 {
794         uint32 off_len;
795         uint32 off_max_len;
796         uint32 old_offset;
797         uint32 size;
798         SEC_DESC_BUF *psdb;
799
800         if (ppsdb == NULL)
801                 return False;
802
803         psdb = *ppsdb;
804
805         if (UNMARSHALLING(ps) && psdb == NULL) {
806                 if((psdb = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
807                         return False;
808                 *ppsdb = psdb;
809         }
810
811         prs_debug(ps, depth, desc, "sec_io_desc_buf");
812         depth++;
813
814         if(!prs_align(ps))
815                 return False;
816         
817         if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
818                 return False;
819
820         if(!prs_uint32    ("undoc  ", ps, depth, &psdb->undoc))
821                 return False;
822
823         if(!prs_uint32_pre("len    ", ps, depth, &psdb->len, &off_len))
824                 return False;
825
826         old_offset = prs_offset(ps);
827
828         /* reading, length is non-zero; writing, descriptor is non-NULL */
829         if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
830                 if(!sec_io_desc("sec   ", &psdb->sec, ps, depth))
831                         return False;
832         }
833
834         if(!prs_align(ps))
835                 return False;
836         
837         size = prs_offset(ps) - old_offset;
838         if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
839                 return False;
840
841         if(!prs_uint32_post("len    ", ps, depth, &psdb->len, off_len, size))
842                 return False;
843
844         return True;
845 }