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