added jeremy's new c++-like code for parsing of security descriptors.
[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-1999,
6  *  Copyright (C) Jeremy R. Allison            1995-1999
7  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1999,
8  *  Copyright (C) Paul Ashton                  1997-1999.
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
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         {
48                 return False;
49         }
50
51         prs_debug(ps, depth, desc, "sec_io_access");
52         depth++;
53
54         prs_align(ps);
55         
56         prs_uint32("mask", ps, depth, &(t->mask));
57         return True;
58 }
59
60
61 /*******************************************************************
62  Sets up a SEC_ACE structure.
63 ********************************************************************/
64
65 void init_sec_ace(SEC_ACE *t, DOM_SID *sid, uint8 type, SEC_ACCESS mask,
66                                 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         {
88                 return False;
89         }
90
91         prs_debug(ps, depth, desc, "sec_io_ace");
92         depth++;
93
94         prs_align(ps);
95         
96         old_offset = ps->offset;
97
98         prs_uint8     ("type ", ps, depth, &psa->type);
99         prs_uint8     ("flags", ps, depth, &psa->flags);
100         prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size);
101
102         if (!sec_io_access("info ", &psa->info, ps, depth))
103         {
104                 return False;
105         }
106
107         prs_align(ps);
108         if (!smb_io_dom_sid("sid  ", &psa->sid , ps, depth))
109         {
110                 return False;
111         }
112
113
114         prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset);
115         return True;
116 }
117
118 /*******************************************************************
119  Create a SEC_ACL structure.  
120 ********************************************************************/
121
122 SEC_ACL *make_sec_acl(uint16 revision, int num_aces, SEC_ACE *ace_list)
123 {
124         SEC_ACL *dst;
125         int i;
126
127         dst = (SEC_ACL *)malloc(sizeof(SEC_ACL));
128         if (dst == NULL)
129         {
130                 return NULL;
131         }
132
133         ZERO_STRUCTP(dst);
134
135         dst->revision = revision;
136         dst->num_aces = num_aces;
137         dst->size = 4;
138
139         if ((dst->ace_list = (SEC_ACE *)malloc( sizeof(SEC_ACE) * num_aces )) == NULL) {
140                 free_sec_acl(&dst);
141                 return NULL;
142         }
143
144         for (i = 0; i < num_aces; i++)
145         {
146                 dst->ace_list[i] = ace_list[i]; /* Structure copy. */
147                 dst->size += ace_list[i].size;
148         }
149
150         return dst;
151 }
152
153 /*******************************************************************
154  Duplicate a SEC_ACL structure.  
155 ********************************************************************/
156
157 SEC_ACL *dup_sec_acl( SEC_ACL *src)
158 {
159         if (src == NULL)
160         {
161                 return NULL;
162         }
163
164         return make_sec_acl( src->revision, src->num_aces, src->ace_list);
165 }
166
167 /*******************************************************************
168  Delete a SEC_ACL structure.  
169 ********************************************************************/
170
171 void free_sec_acl(SEC_ACL **ppsa)
172 {
173         SEC_ACL *psa;
174
175         if (ppsa == NULL || *ppsa == NULL)
176         {
177                 return;
178         }
179
180         psa = *ppsa;
181         if (psa->ace_list != NULL)
182         {
183                 free(psa->ace_list);
184         }
185
186         free(psa);
187         *ppsa = NULL;
188 }
189
190 /*******************************************************************
191  Reads or writes a SEC_ACL structure.  
192
193  First of the xx_io_xx functions that allocates its data structures
194  for you as it reads them.
195 ********************************************************************/
196
197 BOOL sec_io_acl(char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth)
198 {
199         int i;
200         uint32 old_offset;
201         uint32 offset_acl_size;
202         SEC_ACL *psa;
203
204         if (ppsa == NULL)
205         {
206                 return False;
207         }
208
209         psa = *ppsa;
210
211         if (ps->io && psa == NULL)
212         {
213                 /*
214                  * This is a read and we must allocate the stuct to read into.
215                  */
216                 psa = (SEC_ACL *)malloc(sizeof(SEC_ACL));
217                 if (psa == NULL)
218                 {
219                         return False;
220                 }
221                 ZERO_STRUCTP(psa);
222                 *ppsa = psa;
223         }
224
225         prs_debug(ps, depth, desc, "sec_io_acl");
226         depth++;
227
228         prs_align(ps);
229         
230         old_offset = ps->offset;
231
232         prs_uint16("revision", ps, depth, &psa->revision);
233         prs_uint16_pre("size     ", ps, depth, &psa->size, &offset_acl_size);
234         prs_uint32("num_aces ", ps, depth, &psa->num_aces);
235
236         if (ps->io && psa->num_aces != 0)
237         {
238                 /* reading */
239                 psa->ace_list = malloc(sizeof(psa->ace_list[0]) * psa->num_aces);
240                 if (psa->ace_list == NULL)
241                 {
242                         return False;
243                 }
244                 ZERO_STRUCTP(psa->ace_list);
245         }
246
247         for (i = 0; i < MIN(psa->num_aces, MAX_SEC_ACES); i++)
248         {
249                 fstring tmp;
250                 slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
251                 if (!sec_io_ace(tmp, &psa->ace_list[i], ps, depth))
252                 {
253                         return False;
254                 }
255         }
256
257         prs_align(ps);
258
259         prs_uint16_post("size     ", ps, depth, &psa->size, offset_acl_size, old_offset);
260
261         return True;
262 }
263
264
265 /*******************************************************************
266  Creates a SEC_DESC structure
267 ********************************************************************/
268
269 SEC_DESC *make_sec_desc(uint16 revision, uint16 type,
270                         DOM_SID *owner_sid, DOM_SID *grp_sid,
271                         SEC_ACL *sacl, SEC_ACL *dacl, size_t *sec_desc_size)
272 {
273         SEC_DESC *dst;
274         uint32 offset;
275
276         *sec_desc_size = 0;
277
278         dst = (SEC_DESC *)malloc(sizeof(SEC_DESC));
279
280         if (dst == NULL)
281         {
282                 return NULL;
283         }
284
285         ZERO_STRUCTP(dst);
286
287         dst->revision = revision;
288         dst->type     = type;
289
290         dst->off_owner_sid = 0;
291         dst->off_grp_sid   = 0;
292         dst->off_sacl      = 0;
293         dst->off_dacl      = 0;
294
295         /* duplicate sids and acls as necessary */
296
297         if (dacl      != NULL) dst->dacl      = dup_sec_acl(dacl);
298         if (sacl      != NULL) dst->sacl      = dup_sec_acl(sacl);
299         if (owner_sid != NULL) dst->owner_sid = sid_dup(owner_sid);
300         if (grp_sid   != NULL) dst->grp_sid   = sid_dup(grp_sid);
301
302         /* having duplicated sids and acls as necessary, check success */
303
304         if ((dacl      != NULL && dst->dacl      == NULL) ||
305             (sacl      != NULL && dst->sacl      == NULL) ||
306             (owner_sid != NULL && dst->owner_sid == NULL) ||
307             (grp_sid   != NULL && dst->grp_sid   == NULL))
308         {
309                 *sec_desc_size = 0;
310                 free_sec_desc(&dst);
311
312                 return NULL;
313         }
314
315         offset = 0x0;
316
317         /*
318          * Work out the linearization sizes.
319          */
320
321         if (dst->dacl != NULL)
322         {
323                 if (offset == 0)
324                 {
325                         offset = 0x14;
326                 }
327                 dst->off_dacl = offset;
328                 offset += dacl->size;
329         }
330
331         if (dst->sacl != NULL)
332         {
333                 if (offset == 0)
334                 {
335                         offset = 0x14;
336                 }
337                 dst->off_sacl = offset;
338                 offset += sacl->size;
339         }
340
341         if (dst->owner_sid != NULL)
342         {
343                 if (offset == 0)
344                 {
345                         offset = 0x14;
346                 }
347                 dst->off_owner_sid = offset;
348                 offset += sid_size(dst->owner_sid);
349         }
350
351         if (dst->grp_sid != NULL)
352         {
353                 if (offset == 0)
354                 {
355                         offset = 0x14;
356                 }
357                 dst->off_grp_sid = offset;
358                 offset += sid_size(dst->grp_sid);
359         }
360
361         *sec_desc_size = (size_t)((offset == 0) ? 0x14 : offset);
362         return dst;
363 }
364
365 /*******************************************************************
366  Duplicate a SEC_DESC structure.  
367 ********************************************************************/
368
369 SEC_DESC *dup_sec_desc( SEC_DESC *src)
370 {
371         size_t dummy;
372
373         if (src == NULL)
374                 return NULL;
375
376         return make_sec_desc( src->revision, src->type, 
377                                 src->owner_sid, src->grp_sid, src->sacl,
378                                 src->dacl, &dummy);
379 }
380
381 /*******************************************************************
382  Deletes a SEC_DESC structure
383 ********************************************************************/
384
385 void free_sec_desc(SEC_DESC **ppsd)
386 {
387         SEC_DESC *psd;
388
389         if (ppsd == NULL || *ppsd == NULL)
390         {
391                 return;
392         }
393
394         psd = *ppsd;
395
396         free_sec_acl(&psd->dacl);
397         free_sec_acl(&psd->dacl);
398         free(psd->owner_sid);
399         free(psd->grp_sid);
400         free(psd);
401         *ppsd = NULL;
402 }
403
404 /*******************************************************************
405  Creates a SEC_DESC structure with typical defaults.
406 ********************************************************************/
407
408 SEC_DESC *make_standard_sec_desc(DOM_SID *owner_sid, DOM_SID *grp_sid,
409                                  SEC_ACL *dacl, size_t *sec_desc_size)
410 {
411         return make_sec_desc(1, SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
412                              owner_sid, grp_sid, NULL, dacl, sec_desc_size);
413 }
414
415
416 /*******************************************************************
417  Reads or writes a SEC_DESC structure.
418  If reading and the *ppsd = NULL, allocates the structure.
419 ********************************************************************/
420
421 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
422 {
423         uint32 old_offset;
424         uint32 max_offset = 0; /* after we're done, move offset to end */
425         SEC_DESC *psd;
426
427         if (ppsd == NULL)
428                 return False;
429
430         psd = *ppsd;
431
432         if (ps->io && psd == NULL)
433         {
434                 psd = (SEC_DESC *)malloc(sizeof(SEC_DESC));
435                 if (psd == NULL)
436                 {
437                         return False;
438                 }
439                 ZERO_STRUCTP(psd);
440                 *ppsd = psd;
441         }
442
443         prs_debug(ps, depth, desc, "sec_io_desc");
444         depth++;
445
446         prs_align(ps);
447         
448         /* start of security descriptor stored for back-calc offset purposes */
449         old_offset = ps->offset;
450
451         prs_uint16("revision ", ps, depth, &psd->revision);
452         prs_uint16("type     ", ps, depth, &psd->type);
453
454         prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid);
455         prs_uint32("off_grp_sid  ", ps, depth, &psd->off_grp_sid);
456         prs_uint32("off_sacl     ", ps, depth, &psd->off_sacl);
457         prs_uint32("off_dacl     ", ps, depth, &psd->off_dacl);
458
459         max_offset = MAX(max_offset, ps->offset);
460
461         if (IS_BITS_SET_ALL(psd->type, SEC_DESC_DACL_PRESENT) && psd->dacl)
462         {
463                 ps->offset = old_offset + psd->off_dacl;
464                 if (!sec_io_acl("dacl", &psd->dacl, ps, depth))
465                 {
466                         return False;
467                 }
468                 prs_align(ps);
469         }
470
471         max_offset = MAX(max_offset, ps->offset);
472
473         if (IS_BITS_SET_ALL(psd->type, SEC_DESC_SACL_PRESENT) && psd->sacl)
474         {
475                 ps->offset = old_offset + psd->off_sacl;
476                 if (!sec_io_acl("sacl", &psd->sacl, ps, depth))
477                 {
478                         return False;
479                 }
480                 prs_align(ps);
481         }
482
483         max_offset = MAX(max_offset, ps->offset);
484
485         if (psd->off_owner_sid != 0)
486         {
487                 if (ps->io)
488                 {
489                         ps->offset = old_offset + psd->off_owner_sid;
490                         /* reading */
491                         psd->owner_sid = malloc(sizeof(*psd->owner_sid));
492                         if (psd->owner_sid == NULL)
493                         {
494                                 return False;
495                         }
496                         ZERO_STRUCTP(psd->owner_sid);
497                 }
498
499                 if (!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
500                 {
501                         return False;
502                 }
503                 prs_align(ps);
504         }
505
506         max_offset = MAX(max_offset, ps->offset);
507
508         if (psd->off_grp_sid != 0)
509         {
510                 if (ps->io)
511                 {
512                         /* reading */
513                         ps->offset = old_offset + psd->off_grp_sid;
514                         psd->grp_sid = malloc(sizeof(*psd->grp_sid));
515                         if (psd->grp_sid == NULL)
516                         {
517                                 return False;
518                         }
519                         ZERO_STRUCTP(psd->grp_sid);
520                 }
521
522                 if (!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
523                 {
524                         return False;
525                 }
526                 prs_align(ps);
527         }
528
529         max_offset = MAX(max_offset, ps->offset);
530
531         ps->offset = max_offset;
532         return True;
533 }
534
535 /*******************************************************************
536  Creates a SEC_DESC_BUF structure.
537 ********************************************************************/
538
539 SEC_DESC_BUF *make_sec_desc_buf(int len, SEC_DESC *sec_desc)
540 {
541         SEC_DESC_BUF *dst;
542
543         dst = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF));
544         if (dst == NULL)
545         {
546                 return NULL;
547         }
548
549         ZERO_STRUCTP(dst);
550
551         /* max buffer size (allocated size) */
552         dst->max_len = len;
553         dst->len = len;
554
555         if (sec_desc && ((dst->sec = dup_sec_desc(sec_desc)) == NULL))
556         {
557                 free_sec_desc_buf(&dst);
558                 return NULL;
559         }
560
561         return dst;
562 }
563
564 /*******************************************************************
565  Duplicates a SEC_DESC_BUF structure.
566 ********************************************************************/
567
568 SEC_DESC_BUF *dup_sec_desc_buf(SEC_DESC_BUF *src)
569 {
570         if (src == NULL)
571         {
572                 return NULL;
573         }
574
575         return make_sec_desc_buf( src->len, src->sec);
576 }
577
578 /*******************************************************************
579  Deletes a SEC_DESC_BUF structure.
580 ********************************************************************/
581
582 void free_sec_desc_buf(SEC_DESC_BUF **ppsdb)
583 {
584         SEC_DESC_BUF *psdb;
585
586         if (ppsdb == NULL || *ppsdb == NULL)
587         {
588                 return;
589         }
590
591         psdb = *ppsdb;
592         free_sec_desc(&psdb->sec);
593         free(psdb);
594         *ppsdb = NULL;
595 }
596
597
598 /*******************************************************************
599  Reads or writes a SEC_DESC_BUF structure.
600 ********************************************************************/
601
602 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
603 {
604         uint32 off_len;
605         uint32 off_max_len;
606         uint32 old_offset;
607         uint32 size;
608         SEC_DESC_BUF *psdb;
609
610         if (ppsdb == NULL)
611         {
612                 return False;
613         }
614
615         psdb = *ppsdb;
616
617         if (ps->io && psdb == NULL)
618         {
619                 psdb = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF));
620                 if (psdb == NULL)
621                 {
622                         return False;
623                 }
624                 ZERO_STRUCTP(psdb);
625                 *ppsdb = psdb;
626         }
627
628         prs_debug(ps, depth, desc, "sec_io_desc_buf");
629         depth++;
630
631         prs_align(ps);
632         
633         prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len);
634         prs_uint32    ("undoc  ", ps, depth, &psdb->undoc);
635         prs_uint32_pre("len    ", ps, depth, &psdb->len, &off_len);
636
637         old_offset = ps->offset;
638
639         /* reading, length is non-zero; writing, descriptor is non-NULL */
640         if ((psdb->len != 0 || (!ps->io)) && psdb->sec != NULL)
641         {
642                 if (!sec_io_desc("sec   ", &psdb->sec, ps, depth))
643                 {
644                         return False;
645                 }
646         }
647
648         size = ps->offset - old_offset;
649         prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size);
650         prs_uint32_post("len    ", ps, depth, &psdb->len, off_len, size);
651
652         return True;
653 }
654