e2ca2202e1647f0b8373daf2de467a1869bedf99
[samba.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
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                 ZERO_STRUCTP(psa);
210                 *ppsa = psa;
211         }
212
213         prs_debug(ps, depth, desc, "sec_io_acl");
214         depth++;
215
216         if(!prs_align(ps))
217                 return False;
218         
219         old_offset = prs_offset(ps);
220
221         if(!prs_uint16("revision", ps, depth, &psa->revision))
222                 return False;
223
224         if(!prs_uint16_pre("size     ", ps, depth, &psa->size, &offset_acl_size))
225                 return False;
226
227         if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
228                 return False;
229
230         if (UNMARSHALLING(ps) && psa->num_aces != 0) {
231                 /* reading */
232                 if((psa->ace = malloc(sizeof(psa->ace[0]) * psa->num_aces)) == NULL)
233                         return False;
234                 ZERO_STRUCTP(psa->ace);
235         }
236
237         for (i = 0; i < psa->num_aces; i++) {
238                 fstring tmp;
239                 slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
240                 if(!sec_io_ace(tmp, &psa->ace[i], ps, depth))
241                         return False;
242         }
243
244         if(!prs_align(ps))
245                 return False;
246
247         if(!prs_uint16_post("size     ", ps, depth, &psa->size, offset_acl_size, old_offset))
248                 return False;
249
250         return True;
251 }
252
253 /*******************************************************************
254  Works out the linearization size of a SEC_DESC.
255 ********************************************************************/
256
257 size_t sec_desc_size(SEC_DESC *psd)
258 {
259         size_t offset;
260
261         if (!psd) return 0;
262
263         offset = SD_HEADER_SIZE;
264
265         if (psd->owner_sid != NULL)
266                 offset += ((sid_size(psd->owner_sid) + 3) & ~3);
267
268         if (psd->grp_sid != NULL)
269                 offset += ((sid_size(psd->grp_sid) + 3) & ~3);
270
271         if (psd->sacl != NULL)
272                 offset += ((psd->sacl->size + 3) & ~3);
273
274         if (psd->dacl != NULL)
275                 offset += ((psd->dacl->size + 3) & ~3);
276
277         return offset;
278 }
279
280 /*******************************************************************
281  Compares two SEC_ACE structures
282 ********************************************************************/
283
284 BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
285 {
286         /* Trivial case */
287
288         if (!s1 && !s2) return True;
289
290         /* Check top level stuff */
291
292         if (s1->type != s2->type || s1->flags != s2->flags ||
293             s1->info.mask != s2->info.mask) {
294                 return False;
295         }
296
297         /* Check SID */
298
299         if (!sid_equal(&s1->sid, &s2->sid)) {
300                 return False;
301         }
302
303         return True;
304 }
305
306 /*******************************************************************
307  Compares two SEC_ACL structures
308 ********************************************************************/
309
310 BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
311 {
312         int i, j;
313
314         /* Trivial case */
315
316         if (!s1 && !s2) return True;
317
318         /* Check top level stuff */
319
320         if (s1->revision != s2->revision) {
321                 DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
322                            s1->revision, s2->revision));
323                 return False;
324         }
325
326         if (s1->num_aces != s2->num_aces) {
327                 DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
328                            s1->revision, s2->revision));
329                 return False;
330         }
331
332         /* The ACEs could be in any order so check each ACE in s1 against 
333            each ACE in s2. */
334
335         for (i = 0; i < s1->num_aces; i++) {
336                 BOOL found = False;
337
338                 for (j = 0; j < s2->num_aces; j++) {
339                         if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
340                                 found = True;
341                                 break;
342                         }
343                 }
344
345                 if (!found) return False;
346         }
347
348         return True;
349 }
350
351 /*******************************************************************
352  Compares two SEC_DESC structures
353 ********************************************************************/
354
355 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
356 {
357         /* Trivial case */
358
359         if (!s1 && !s2) {
360                 goto done;
361         }
362
363         /* Check top level stuff */
364
365         if (s1->revision != s2->revision) {
366                 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
367                            s1->revision, s2->revision));
368                 return False;
369         }
370
371         if (s1->type!= s2->type) {
372                 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
373                            s1->type, s2->type));
374                 return False;
375         }
376
377         /* Check owner and group */
378
379         if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
380                 fstring str1, str2;
381
382                 sid_to_string(str1, s1->owner_sid);
383                 sid_to_string(str2, s2->owner_sid);
384
385                 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
386                            str1, str2));
387                 return False;
388         }
389
390         if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
391                 fstring str1, str2;
392
393                 sid_to_string(str1, s1->grp_sid);
394                 sid_to_string(str2, s2->grp_sid);
395
396                 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
397                            str1, str2));
398                 return False;
399         }
400
401         /* Check ACLs present in one but not the other */
402
403         if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
404             (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
405                 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
406                 return False;
407         }
408
409         /* Sigh - we have to do it the hard way by iterating over all
410            the ACEs in the ACLs */
411
412         if (!sec_acl_equal(s1->dacl, s2->dacl) ||
413             !sec_acl_equal(s1->sacl, s2->sacl)) {
414                 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
415                 return False;
416         }
417
418  done:
419         DEBUG(10, ("sec_equal(): secdescs are identical\n"));
420         return True;
421 }
422
423 /*******************************************************************
424  Merge part of security descriptor old_sec in to the empty sections of 
425  security descriptor new_sec.
426 ********************************************************************/
427
428 SEC_DESC_BUF *sec_desc_merge(SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
429 {
430         DOM_SID *owner_sid, *group_sid;
431         SEC_DESC_BUF *return_sdb;
432         SEC_ACL *dacl, *sacl;
433         SEC_DESC *psd = NULL;
434         uint16 secdesc_type;
435         size_t secdesc_size;
436
437         /* Copy over owner and group sids.  There seems to be no flag for
438            this so just check the pointer values. */
439
440         owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
441                 old_sdb->sec->owner_sid;
442
443         group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
444                 old_sdb->sec->grp_sid;
445         
446         secdesc_type = new_sdb->sec->type;
447
448         /* Ignore changes to the system ACL.  This has the effect of making
449            changes through the security tab audit button not sticking. 
450            Perhaps in future Samba could implement these settings somehow. */
451
452         sacl = NULL;
453         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
454
455         /* Copy across discretionary ACL */
456
457         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
458                 dacl = new_sdb->sec->dacl;
459         } else {
460                 dacl = old_sdb->sec->dacl;
461         }
462
463         /* Create new security descriptor from bits */
464
465         psd = make_sec_desc(new_sdb->sec->revision, 
466                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
467
468         return_sdb = make_sec_desc_buf(secdesc_size, psd);
469
470         free_sec_desc(&psd);
471
472         return(return_sdb);
473 }
474
475 /*******************************************************************
476  Creates a SEC_DESC structure
477 ********************************************************************/
478
479 SEC_DESC *make_sec_desc(uint16 revision, 
480                         DOM_SID *owner_sid, DOM_SID *grp_sid,
481                         SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
482 {
483         SEC_DESC *dst;
484         uint32 offset;
485
486         *sd_size = 0;
487
488         if(( dst = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
489                 return NULL;
490
491         ZERO_STRUCTP(dst);
492
493         dst->revision = revision;
494         dst->type     = SEC_DESC_SELF_RELATIVE;
495
496         if (sacl) dst->type |= SEC_DESC_SACL_PRESENT;
497         if (dacl) dst->type |= SEC_DESC_DACL_PRESENT;
498
499         dst->off_owner_sid = 0;
500         dst->off_grp_sid   = 0;
501         dst->off_sacl      = 0;
502         dst->off_dacl      = 0;
503
504         if(owner_sid && ((dst->owner_sid = sid_dup(owner_sid)) == NULL))
505                 goto error_exit;
506
507         if(grp_sid && ((dst->grp_sid = sid_dup(grp_sid)) == NULL))
508                 goto error_exit;
509
510         if(sacl && ((dst->sacl = dup_sec_acl(sacl)) == NULL))
511                 goto error_exit;
512
513         if(dacl && ((dst->dacl = dup_sec_acl(dacl)) == NULL))
514                 goto error_exit;
515                 
516         offset = 0;
517
518         /*
519          * Work out the linearization sizes.
520          */
521
522         if (dst->owner_sid != NULL) {
523
524                 if (offset == 0)
525                         offset = SD_HEADER_SIZE;
526
527                 dst->off_owner_sid = offset;
528                 offset += ((sid_size(dst->owner_sid) + 3) & ~3);
529         }
530
531         if (dst->grp_sid != NULL) {
532
533                 if (offset == 0)
534                         offset = SD_HEADER_SIZE;
535
536                 dst->off_grp_sid = offset;
537                 offset += ((sid_size(dst->grp_sid) + 3) & ~3);
538         }
539
540         if (dst->sacl != NULL) {
541
542                 if (offset == 0)
543                         offset = SD_HEADER_SIZE;
544
545                 dst->off_sacl = offset;
546                 offset += ((sacl->size + 3) & ~3);
547         }
548
549         if (dst->dacl != NULL) {
550
551                 if (offset == 0)
552                         offset = SD_HEADER_SIZE;
553
554                 dst->off_dacl = offset;
555                 offset += ((dacl->size + 3) & ~3);
556         }
557
558         *sd_size = (size_t)((offset == 0) ? SD_HEADER_SIZE : offset);
559         return dst;
560
561 error_exit:
562
563         *sd_size = 0;
564         free_sec_desc(&dst);
565         return NULL;
566 }
567
568 /*******************************************************************
569  Duplicate a SEC_DESC structure.  
570 ********************************************************************/
571
572 SEC_DESC *dup_sec_desc( SEC_DESC *src)
573 {
574         size_t dummy;
575
576         if(src == NULL)
577                 return NULL;
578
579         return make_sec_desc( src->revision, 
580                                 src->owner_sid, src->grp_sid, src->sacl,
581                                 src->dacl, &dummy);
582 }
583
584 /*******************************************************************
585  Deletes a SEC_DESC structure
586 ********************************************************************/
587
588 void free_sec_desc(SEC_DESC **ppsd)
589 {
590         SEC_DESC *psd;
591
592         if(ppsd == NULL || *ppsd == NULL)
593                 return;
594
595         psd = *ppsd;
596
597         free_sec_acl(&psd->dacl);
598         free_sec_acl(&psd->dacl);
599         free(psd->owner_sid);
600         free(psd->grp_sid);
601         free(psd);
602         *ppsd = NULL;
603 }
604
605 /*******************************************************************
606  Creates a SEC_DESC structure with typical defaults.
607 ********************************************************************/
608
609 SEC_DESC *make_standard_sec_desc(DOM_SID *owner_sid, DOM_SID *grp_sid,
610                                  SEC_ACL *dacl, size_t *sd_size)
611 {
612         return make_sec_desc(SEC_DESC_REVISION,
613                              owner_sid, grp_sid, NULL, dacl, sd_size);
614 }
615
616 /*******************************************************************
617  Reads or writes a SEC_DESC structure.
618  If reading and the *ppsd = NULL, allocates the structure.
619 ********************************************************************/
620
621 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
622 {
623         uint32 old_offset;
624         uint32 max_offset = 0; /* after we're done, move offset to end */
625         SEC_DESC *psd;
626
627         if (ppsd == NULL)
628                 return False;
629
630         psd = *ppsd;
631
632         if (psd == NULL) {
633                 if(UNMARSHALLING(ps)) {
634                         if((psd = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
635                                 return False;
636                         ZERO_STRUCTP(psd);
637                         *ppsd = psd;
638                 } else {
639                         /* Marshalling - just ignore. */
640                         return True;
641                 }
642         }
643
644         prs_debug(ps, depth, desc, "sec_io_desc");
645         depth++;
646
647         if(!prs_align(ps))
648                 return False;
649         
650         /* start of security descriptor stored for back-calc offset purposes */
651         old_offset = prs_offset(ps);
652
653         if(!prs_uint16("revision ", ps, depth, &psd->revision))
654                 return False;
655
656         if(!prs_uint16("type     ", ps, depth, &psd->type))
657                 return False;
658
659         if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
660                 return False;
661
662         if(!prs_uint32("off_grp_sid  ", ps, depth, &psd->off_grp_sid))
663                 return False;
664
665         if(!prs_uint32("off_sacl     ", ps, depth, &psd->off_sacl))
666                 return False;
667
668         if(!prs_uint32("off_dacl     ", ps, depth, &psd->off_dacl))
669                 return False;
670
671         max_offset = MAX(max_offset, prs_offset(ps));
672
673         if (psd->off_owner_sid != 0) {
674
675                 if (UNMARSHALLING(ps)) {
676                         if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
677                                 return False;
678                         /* reading */
679                         if((psd->owner_sid = malloc(sizeof(*psd->owner_sid))) == NULL)
680                                 return False;
681                         ZERO_STRUCTP(psd->owner_sid);
682                 }
683
684                 if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
685                         return False;
686                 if(!prs_align(ps))
687                         return False;
688         }
689
690         max_offset = MAX(max_offset, prs_offset(ps));
691
692         if (psd->off_grp_sid != 0) {
693
694                 if (UNMARSHALLING(ps)) {
695                         /* reading */
696                         if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
697                                 return False;
698                         if((psd->grp_sid = malloc(sizeof(*psd->grp_sid))) == NULL)
699                                 return False;
700                         ZERO_STRUCTP(psd->grp_sid);
701                 }
702
703                 if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
704                         return False;
705                 if(!prs_align(ps))
706                         return False;
707         }
708
709         max_offset = MAX(max_offset, prs_offset(ps));
710
711         if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
712                 if(!prs_set_offset(ps, old_offset + psd->off_sacl))
713                         return False;
714                 if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
715                         return False;
716                 if(!prs_align(ps))
717                         return False;
718         }
719
720         max_offset = MAX(max_offset, prs_offset(ps));
721
722         if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
723                 if(!prs_set_offset(ps, old_offset + psd->off_dacl))
724                         return False;
725                 if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
726                         return False;
727                 if(!prs_align(ps))
728                         return False;
729         }
730
731         max_offset = MAX(max_offset, prs_offset(ps));
732
733         if(!prs_set_offset(ps, max_offset))
734                 return False;
735         return True;
736 }
737
738 /*******************************************************************
739  Creates a SEC_DESC_BUF structure.
740 ********************************************************************/
741
742 SEC_DESC_BUF *make_sec_desc_buf(size_t len, SEC_DESC *sec_desc)
743 {
744         SEC_DESC_BUF *dst;
745
746         if((dst = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
747                 return NULL;
748
749         ZERO_STRUCTP(dst);
750
751         /* max buffer size (allocated size) */
752         dst->max_len = (uint32)len;
753         dst->len = (uint32)len;
754
755         if(sec_desc && ((dst->sec = dup_sec_desc(sec_desc)) == NULL)) {
756                 free_sec_desc_buf(&dst);
757                 return NULL;
758         }
759
760         return dst;
761 }
762
763 /*******************************************************************
764  Duplicates a SEC_DESC_BUF structure.
765 ********************************************************************/
766
767 SEC_DESC_BUF *dup_sec_desc_buf(SEC_DESC_BUF *src)
768 {
769         if(src == NULL)
770                 return NULL;
771
772         return make_sec_desc_buf( src->len, src->sec);
773 }
774
775 /*******************************************************************
776  Deletes a SEC_DESC_BUF structure.
777 ********************************************************************/
778
779 void free_sec_desc_buf(SEC_DESC_BUF **ppsdb)
780 {
781         SEC_DESC_BUF *psdb;
782
783         if(ppsdb == NULL || *ppsdb == NULL)
784                 return;
785
786         psdb = *ppsdb;
787         free_sec_desc(&psdb->sec);
788         free(psdb);
789         *ppsdb = NULL;
790 }
791
792
793 /*******************************************************************
794  Reads or writes a SEC_DESC_BUF structure.
795 ********************************************************************/
796
797 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
798 {
799         uint32 off_len;
800         uint32 off_max_len;
801         uint32 old_offset;
802         uint32 size;
803         SEC_DESC_BUF *psdb;
804
805         if (ppsdb == NULL)
806                 return False;
807
808         psdb = *ppsdb;
809
810         if (UNMARSHALLING(ps) && psdb == NULL) {
811                 if((psdb = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
812                         return False;
813                 ZERO_STRUCTP(psdb);
814                 *ppsdb = psdb;
815         }
816
817         prs_debug(ps, depth, desc, "sec_io_desc_buf");
818         depth++;
819
820         if(!prs_align(ps))
821                 return False;
822         
823         if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
824                 return False;
825
826         if(!prs_uint32    ("undoc  ", ps, depth, &psdb->undoc))
827                 return False;
828
829         if(!prs_uint32_pre("len    ", ps, depth, &psdb->len, &off_len))
830                 return False;
831
832         old_offset = prs_offset(ps);
833
834         /* reading, length is non-zero; writing, descriptor is non-NULL */
835         if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
836                 if(!sec_io_desc("sec   ", &psdb->sec, ps, depth))
837                         return False;
838         }
839
840         if(!prs_align(ps))
841                 return False;
842         
843         size = prs_offset(ps) - old_offset;
844         if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
845                 return False;
846
847         if(!prs_uint32_post("len    ", ps, depth, &psdb->len, off_len, size))
848                 return False;
849
850         return True;
851 }