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