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