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