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