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