Merge of printer security descriptor, info level and printerdata
[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) 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                 secdesc_type |= SEC_DESC_DACL_PRESENT;
423         }
424
425         /* Create new security descriptor from bits */
426
427         psd = make_sec_desc(new_sdb->sec->revision, secdesc_type,
428                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
429
430         return_sdb = make_sec_desc_buf(secdesc_size, psd);
431
432         free_sec_desc(&psd);
433
434         return(return_sdb);
435 }
436
437 /*******************************************************************
438  Creates a SEC_DESC structure
439 ********************************************************************/
440
441 SEC_DESC *make_sec_desc(uint16 revision, uint16 type,
442                         DOM_SID *owner_sid, DOM_SID *grp_sid,
443                         SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
444 {
445         SEC_DESC *dst;
446         uint32 offset;
447
448         *sd_size = 0;
449
450         if(( dst = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
451                 return NULL;
452
453         ZERO_STRUCTP(dst);
454
455         dst->revision = revision;
456         dst->type     = type;
457
458         dst->off_owner_sid = 0;
459         dst->off_grp_sid   = 0;
460         dst->off_sacl      = 0;
461         dst->off_dacl      = 0;
462
463         if(owner_sid && ((dst->owner_sid = sid_dup(owner_sid)) == NULL))
464                 goto error_exit;
465
466         if(grp_sid && ((dst->grp_sid = sid_dup(grp_sid)) == NULL))
467                 goto error_exit;
468
469         if(sacl && ((dst->sacl = dup_sec_acl(sacl)) == NULL))
470                 goto error_exit;
471
472         if(dacl && ((dst->dacl = dup_sec_acl(dacl)) == NULL))
473                 goto error_exit;
474                 
475         offset = 0;
476
477         /*
478          * Work out the linearization sizes.
479          */
480
481         if (dst->owner_sid != NULL) {
482
483                 if (offset == 0)
484                         offset = SD_HEADER_SIZE;
485
486                 dst->off_owner_sid = offset;
487                 offset += ((sid_size(dst->owner_sid) + 3) & ~3);
488         }
489
490         if (dst->grp_sid != NULL) {
491
492                 if (offset == 0)
493                         offset = SD_HEADER_SIZE;
494
495                 dst->off_grp_sid = offset;
496                 offset += ((sid_size(dst->grp_sid) + 3) & ~3);
497         }
498
499         if (dst->sacl != NULL) {
500
501                 if (offset == 0)
502                         offset = SD_HEADER_SIZE;
503
504                 dst->off_sacl = offset;
505                 offset += ((sacl->size + 3) & ~3);
506         }
507
508         if (dst->dacl != NULL) {
509
510                 if (offset == 0)
511                         offset = SD_HEADER_SIZE;
512
513                 dst->off_dacl = offset;
514                 offset += ((dacl->size + 3) & ~3);
515         }
516
517         *sd_size = (size_t)((offset == 0) ? SD_HEADER_SIZE : offset);
518         return dst;
519
520 error_exit:
521
522         *sd_size = 0;
523         free_sec_desc(&dst);
524         return NULL;
525 }
526
527 /*******************************************************************
528  Duplicate a SEC_DESC structure.  
529 ********************************************************************/
530
531 SEC_DESC *dup_sec_desc( SEC_DESC *src)
532 {
533         size_t dummy;
534
535         if(src == NULL)
536                 return NULL;
537
538         return make_sec_desc( src->revision, src->type, 
539                                 src->owner_sid, src->grp_sid, src->sacl,
540                                 src->dacl, &dummy);
541 }
542
543 /*******************************************************************
544  Deletes a SEC_DESC structure
545 ********************************************************************/
546
547 void free_sec_desc(SEC_DESC **ppsd)
548 {
549         SEC_DESC *psd;
550
551         if(ppsd == NULL || *ppsd == NULL)
552                 return;
553
554         psd = *ppsd;
555
556         free_sec_acl(&psd->dacl);
557         free_sec_acl(&psd->dacl);
558         free(psd->owner_sid);
559         free(psd->grp_sid);
560         free(psd);
561         *ppsd = NULL;
562 }
563
564 /*******************************************************************
565  Creates a SEC_DESC structure with typical defaults.
566 ********************************************************************/
567
568 SEC_DESC *make_standard_sec_desc(DOM_SID *owner_sid, DOM_SID *grp_sid,
569                                  SEC_ACL *dacl, size_t *sd_size)
570 {
571         return make_sec_desc(SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
572                              owner_sid, grp_sid, NULL, dacl, sd_size);
573 }
574
575 /*******************************************************************
576  Reads or writes a SEC_DESC structure.
577  If reading and the *ppsd = NULL, allocates the structure.
578 ********************************************************************/
579
580 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
581 {
582         uint32 old_offset;
583         uint32 max_offset = 0; /* after we're done, move offset to end */
584         SEC_DESC *psd;
585
586         if (ppsd == NULL)
587                 return False;
588
589         psd = *ppsd;
590
591         if (psd == NULL) {
592                 if(UNMARSHALLING(ps)) {
593                         if((psd = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
594                                 return False;
595                         ZERO_STRUCTP(psd);
596                         *ppsd = psd;
597                 } else {
598                         /* Marshalling - just ignore. */
599                         return True;
600                 }
601         }
602
603         prs_debug(ps, depth, desc, "sec_io_desc");
604         depth++;
605
606         if(!prs_align(ps))
607                 return False;
608         
609         /* start of security descriptor stored for back-calc offset purposes */
610         old_offset = prs_offset(ps);
611
612         if(!prs_uint16("revision ", ps, depth, &psd->revision))
613                 return False;
614
615         if(!prs_uint16("type     ", ps, depth, &psd->type))
616                 return False;
617
618         if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
619                 return False;
620
621         if(!prs_uint32("off_grp_sid  ", ps, depth, &psd->off_grp_sid))
622                 return False;
623
624         if(!prs_uint32("off_sacl     ", ps, depth, &psd->off_sacl))
625                 return False;
626
627         if(!prs_uint32("off_dacl     ", ps, depth, &psd->off_dacl))
628                 return False;
629
630         max_offset = MAX(max_offset, prs_offset(ps));
631
632         if (psd->off_owner_sid != 0) {
633
634                 if (UNMARSHALLING(ps)) {
635                         if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
636                                 return False;
637                         /* reading */
638                         if((psd->owner_sid = malloc(sizeof(*psd->owner_sid))) == NULL)
639                                 return False;
640                         ZERO_STRUCTP(psd->owner_sid);
641                 }
642
643                 if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
644                         return False;
645                 if(!prs_align(ps))
646                         return False;
647         }
648
649         max_offset = MAX(max_offset, prs_offset(ps));
650
651         if (psd->off_grp_sid != 0) {
652
653                 if (UNMARSHALLING(ps)) {
654                         /* reading */
655                         if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
656                                 return False;
657                         if((psd->grp_sid = malloc(sizeof(*psd->grp_sid))) == NULL)
658                                 return False;
659                         ZERO_STRUCTP(psd->grp_sid);
660                 }
661
662                 if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
663                         return False;
664                 if(!prs_align(ps))
665                         return False;
666         }
667
668         max_offset = MAX(max_offset, prs_offset(ps));
669
670         if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
671                 if(!prs_set_offset(ps, old_offset + psd->off_sacl))
672                         return False;
673                 if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
674                         return False;
675                 if(!prs_align(ps))
676                         return False;
677         }
678
679         max_offset = MAX(max_offset, prs_offset(ps));
680
681         if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
682                 if(!prs_set_offset(ps, old_offset + psd->off_dacl))
683                         return False;
684                 if(!sec_io_acl("dacl", &psd->dacl, 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(!prs_set_offset(ps, max_offset))
693                 return False;
694         return True;
695 }
696
697 /*******************************************************************
698  Creates a SEC_DESC_BUF structure.
699 ********************************************************************/
700
701 SEC_DESC_BUF *make_sec_desc_buf(size_t len, SEC_DESC *sec_desc)
702 {
703         SEC_DESC_BUF *dst;
704
705         if((dst = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
706                 return NULL;
707
708         ZERO_STRUCTP(dst);
709
710         /* max buffer size (allocated size) */
711         dst->max_len = (uint32)len;
712         dst->len = (uint32)len;
713
714         if(sec_desc && ((dst->sec = dup_sec_desc(sec_desc)) == NULL)) {
715                 free_sec_desc_buf(&dst);
716                 return NULL;
717         }
718
719         return dst;
720 }
721
722 /*******************************************************************
723  Duplicates a SEC_DESC_BUF structure.
724 ********************************************************************/
725
726 SEC_DESC_BUF *dup_sec_desc_buf(SEC_DESC_BUF *src)
727 {
728         if(src == NULL)
729                 return NULL;
730
731         return make_sec_desc_buf( src->len, src->sec);
732 }
733
734 /*******************************************************************
735  Deletes a SEC_DESC_BUF structure.
736 ********************************************************************/
737
738 void free_sec_desc_buf(SEC_DESC_BUF **ppsdb)
739 {
740         SEC_DESC_BUF *psdb;
741
742         if(ppsdb == NULL || *ppsdb == NULL)
743                 return;
744
745         psdb = *ppsdb;
746         free_sec_desc(&psdb->sec);
747         free(psdb);
748         *ppsdb = NULL;
749 }
750
751
752 /*******************************************************************
753  Reads or writes a SEC_DESC_BUF structure.
754 ********************************************************************/
755
756 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
757 {
758         uint32 off_len;
759         uint32 off_max_len;
760         uint32 old_offset;
761         uint32 size;
762         SEC_DESC_BUF *psdb;
763
764         if (ppsdb == NULL)
765                 return False;
766
767         psdb = *ppsdb;
768
769         if (UNMARSHALLING(ps) && psdb == NULL) {
770                 if((psdb = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
771                         return False;
772                 ZERO_STRUCTP(psdb);
773                 *ppsdb = psdb;
774         }
775
776         prs_debug(ps, depth, desc, "sec_io_desc_buf");
777         depth++;
778
779         if(!prs_align(ps))
780                 return False;
781         
782         if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
783                 return False;
784
785         if(!prs_uint32    ("undoc  ", ps, depth, &psdb->undoc))
786                 return False;
787
788         if(!prs_uint32_pre("len    ", ps, depth, &psdb->len, &off_len))
789                 return False;
790
791         old_offset = prs_offset(ps);
792
793         /* reading, length is non-zero; writing, descriptor is non-NULL */
794         if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
795                 if(!sec_io_desc("sec   ", &psdb->sec, ps, depth))
796                         return False;
797         }
798
799         if(!prs_align(ps))
800                 return False;
801         
802         size = prs_offset(ps) - old_offset;
803         if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
804                 return False;
805
806         if(!prs_uint32_post("len    ", ps, depth, &psdb->len, off_len, size))
807                 return False;
808
809         return True;
810 }