r8302: import mini HEIMDAL into the tree
[samba.git] / source4 / heimdal / lib / asn1 / gen_decode.c
1 /*
2  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "gen_locl.h"
35
36 RCSID("$Id: gen_decode.c,v 1.21 2005/05/29 14:23:01 lha Exp $");
37
38 static void
39 decode_primitive (const char *typename, const char *name)
40 {
41     fprintf (codefile,
42              "e = decode_%s(p, len, %s, &l);\n"
43              "FORW;\n",
44              typename,
45              name);
46 }
47
48 static void
49 decode_type (const char *name, const Type *t)
50 {
51     switch (t->type) {
52     case TType:
53 #if 0
54         decode_type (name, t->symbol->type);
55 #endif
56         fprintf (codefile,
57                  "e = decode_%s(p, len, %s, &l);\n"
58                  "FORW;\n",
59                  t->symbol->gen_name, name);
60         break;
61     case TInteger:
62         if(t->members == NULL)
63             decode_primitive ("integer", name);
64         else {
65             char *s;
66             asprintf(&s, "(int*)%s", name);
67             if(s == NULL)
68                 errx (1, "out of memory");
69             decode_primitive ("integer", s);
70             free(s);
71         }
72         break;
73     case TUInteger:
74         decode_primitive ("unsigned", name);
75         break;
76     case TEnumerated:
77         decode_primitive ("enumerated", name);
78         break;
79     case TOctetString:
80         decode_primitive ("octet_string", name);
81         break;
82     case TOID :
83         decode_primitive ("oid", name);
84         break;
85     case TBitString: {
86         Member *m;
87         int tag = -1;
88         int pos;
89
90         fprintf (codefile,
91                  "e = der_match_tag_and_length (p, len, ASN1_C_UNIV, PRIM, UT_BitString,"
92                  "&reallen, &l);\n"
93                  "FORW;\n"
94                  "if(len < reallen)\n"
95                  "return ASN1_OVERRUN;\n"
96                  "p++;\n"
97                  "len--;\n"
98                  "reallen--;\n"
99                  "ret++;\n");
100         pos = 0;
101         for (m = t->members; m && tag != m->val; m = m->next) {
102             while (m->val / 8 > pos / 8) {
103                 fprintf (codefile,
104                          "p++; len--; reallen--; ret++;\n");
105                 pos += 8;
106             }
107             fprintf (codefile,
108                      "%s->%s = (*p >> %d) & 1;\n",
109                      name, m->gen_name, 7 - m->val % 8);
110             if (tag == -1)
111                 tag = m->val;
112         }
113         fprintf (codefile,
114                  "p += reallen; len -= reallen; ret += reallen;\n");
115         break;
116     }
117     case TSequence: {
118         Member *m;
119         int tag = -1;
120         int fd_counter = unique_get_next();
121         int fd_counter_inner = unique_get_next();
122
123         if (t->members == NULL)
124             break;
125
126         fprintf (codefile,
127                  "e = der_match_tag_and_length (p, len, ASN1_C_UNIV, CONS, UT_Sequence,"
128                  "&reallen, &l);\n"
129                  "FORW;\n"
130                  "{\n"
131                  "int dce_fix%d;\n"
132                  "if((dce_fix%d = fix_dce(reallen, &len)) < 0)\n"
133                  "return ASN1_BAD_FORMAT;\n",
134                  fd_counter, fd_counter);
135
136         for (m = t->members; m && tag != m->val; m = m->next) {
137             char *s;
138
139             asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
140             if (0 && m->type->type == TType){
141                 if(m->optional)
142                     fprintf (codefile,
143                              "%s = malloc(sizeof(*%s));\n"
144                              "if(%s == NULL) return ENOMEM;\n", s, s, s);
145                 fprintf (codefile, 
146                          "e = decode_seq_%s(p, len, %d, %d, %s, &l);\n",
147                          m->type->symbol->gen_name,
148                          m->val, 
149                          m->optional,
150                          s);
151                 if(m->optional)
152                     fprintf (codefile, 
153                              "if (e == ASN1_MISSING_FIELD) {\n"
154                              "free(%s);\n"
155                              "%s = NULL;\n"
156                              "e = l = 0;\n"
157                              "}\n",
158                              s, s);
159           
160                 fprintf (codefile, "FORW;\n");
161           
162             }else{
163                 fprintf (codefile, "{\n"
164                          "size_t newlen, oldlen;\n\n"
165                          "e = der_match_tag (p, len, ASN1_C_CONTEXT, CONS, %d, &l);\n",
166                          m->val);
167                 fprintf (codefile,
168                          "if (e)\n");
169                 if(m->optional)
170                     /* XXX should look at e */
171                     fprintf (codefile,
172                              "%s = NULL;\n", s);
173                 else
174                     fprintf (codefile,
175                              "return e;\n");
176                 fprintf (codefile, 
177                          "else {\n");
178                 fprintf (codefile,
179                          "p += l;\n"
180                          "len -= l;\n"
181                          "ret += l;\n"
182                          "e = der_get_length (p, len, &newlen, &l);\n"
183                          "FORW;\n"
184                          "{\n"
185                
186                          "int dce_fix%d;\n"
187                          "oldlen = len;\n"
188                          "if((dce_fix%d = fix_dce(newlen, &len)) < 0)"
189                          "return ASN1_BAD_FORMAT;\n",
190                          fd_counter_inner,
191                          fd_counter_inner);
192                 if (m->optional)
193                     fprintf (codefile,
194                              "%s = malloc(sizeof(*%s));\n"
195                              "if(%s == NULL) return ENOMEM;\n", s, s, s);
196                 decode_type (s, m->type);
197                 fprintf (codefile,
198                          "if(dce_fix%d){\n"
199                          "e = der_match_tag_and_length (p, len, "
200                          "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
201                          "FORW;\n"
202                          "}else \n"
203                          "len = oldlen - newlen;\n"
204                          "}\n"
205                          "}\n",
206                          fd_counter_inner);
207                 fprintf (codefile,
208                          "}\n");
209             }
210             if (tag == -1)
211                 tag = m->val;
212             free (s);
213         }
214         fprintf(codefile,
215                 "if(dce_fix%d){\n"
216                 "e = der_match_tag_and_length (p, len, "
217                 "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
218                 "FORW;\n"
219                 "}\n"
220                 "}\n",
221                 fd_counter);
222
223         break;
224     }
225     case TSequenceOf: {
226         char *n;
227         int oldret_counter = unique_get_next();
228
229         fprintf (codefile,
230                  "e = der_match_tag_and_length (p, len, ASN1_C_UNIV, CONS, UT_Sequence,"
231                  "&reallen, &l);\n"
232                  "FORW;\n"
233                  "if(len < reallen)\n"
234                  "return ASN1_OVERRUN;\n"
235                  "len = reallen;\n");
236
237         fprintf (codefile,
238                  "{\n"
239                  "size_t origlen = len;\n"
240                  "int oldret%d = ret;\n"
241                  "ret = 0;\n"
242                  "(%s)->len = 0;\n"
243                  "(%s)->val = NULL;\n"
244                  "while(ret < origlen) {\n"
245                  "(%s)->len++;\n"
246                  "(%s)->val = realloc((%s)->val, sizeof(*((%s)->val)) * (%s)->len);\n",
247                  oldret_counter, name, name, name, name, name, name, name);
248         asprintf (&n, "&(%s)->val[(%s)->len-1]", name, name);
249         decode_type (n, t->subtype);
250         fprintf (codefile, 
251                  "len = origlen - ret;\n"
252                  "}\n"
253                  "ret += oldret%d;\n"
254                  "}\n",
255                  oldret_counter);
256         free (n);
257         break;
258     }
259     case TGeneralizedTime:
260         decode_primitive ("generalized_time", name);
261         break;
262     case TGeneralString:
263         decode_primitive ("general_string", name);
264         break;
265     case TUTF8String:
266         decode_primitive ("utf8string", name);
267         break;
268     case TNull:
269         fprintf (codefile,
270                  "e = decode_nulltype(p, len, &l);\n"
271                  "FORW;\n");
272         break;
273     case TApplication:
274         fprintf (codefile,
275                  "e = der_match_tag_and_length (p, len, ASN1_C_APPL, CONS, %d, "
276                  "&reallen, &l);\n"
277                  "FORW;\n"
278                  "{\n"
279                  "int dce_fix;\n"
280                  "if((dce_fix = fix_dce(reallen, &len)) < 0)\n"
281                  "return ASN1_BAD_FORMAT;\n", 
282                  t->application);
283         decode_type (name, t->subtype);
284         fprintf(codefile,
285                 "if(dce_fix){\n"
286                 "e = der_match_tag_and_length (p, len, "
287                 "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
288                 "FORW;\n"
289                 "}\n"
290                 "}\n");
291
292         break;
293     case TBoolean:
294         decode_primitive ("boolean", name);
295         break;
296     default :
297         abort ();
298     }
299 }
300
301 void
302 generate_type_decode (const Symbol *s)
303 {
304   unique_reset();
305   fprintf (headerfile,
306            "int    "
307            "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
308            s->gen_name, s->gen_name);
309
310   fprintf (codefile, "#define FORW "
311            "if(e) goto fail; "
312            "p += l; "
313            "len -= l; "
314            "ret += l\n\n");
315
316
317   fprintf (codefile, "int\n"
318            "decode_%s(const unsigned char *p,"
319            " size_t len, %s *data, size_t *size)\n"
320            "{\n",
321            s->gen_name, s->gen_name);
322
323   switch (s->type->type) {
324   case TInteger:
325   case TUInteger:
326   case TBoolean:
327   case TOctetString:
328   case TOID:
329   case TGeneralizedTime:
330   case TGeneralString:
331   case TUTF8String:
332   case TNull:
333   case TEnumerated:
334   case TBitString:
335   case TSequence:
336   case TSequenceOf:
337   case TApplication:
338   case TType:
339     fprintf (codefile,
340              "size_t ret = 0, reallen;\n"
341              "size_t l;\n"
342              "int e;\n\n");
343     fprintf (codefile, "memset(data, 0, sizeof(*data));\n");
344     fprintf (codefile, "reallen = 0;\n"); /* hack to avoid `unused variable' */
345
346     decode_type ("data", s->type);
347     fprintf (codefile, 
348              "if(size) *size = ret;\n"
349              "return 0;\n");
350     fprintf (codefile,
351              "fail:\n"
352              "free_%s(data);\n"
353              "return e;\n",
354              s->gen_name);
355     break;
356   default:
357     abort ();
358   }
359   fprintf (codefile, "}\n\n");
360 }
361
362 void
363 generate_seq_type_decode (const Symbol *s)
364 {
365     fprintf (headerfile,
366              "int decode_seq_%s(const unsigned char *, size_t, int, int, "
367              "%s *, size_t *);\n",
368              s->gen_name, s->gen_name);
369
370     fprintf (codefile, "int\n"
371              "decode_seq_%s(const unsigned char *p, size_t len, int tag, "
372              "int optional, %s *data, size_t *size)\n"
373              "{\n",
374              s->gen_name, s->gen_name);
375
376     fprintf (codefile,
377              "size_t newlen, oldlen;\n"
378              "size_t l, ret = 0;\n"
379              "int e;\n"
380              "int dce_fix;\n");
381     
382     fprintf (codefile,
383              "e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, tag, &l);\n"
384              "if (e)\n"
385              "return e;\n");
386     fprintf (codefile, 
387              "p += l;\n"
388              "len -= l;\n"
389              "ret += l;\n"
390              "e = der_get_length(p, len, &newlen, &l);\n"
391              "if (e)\n"
392              "return e;\n"
393              "p += l;\n"
394              "len -= l;\n"
395              "ret += l;\n"
396              "oldlen = len;\n"
397              "if ((dce_fix = fix_dce(newlen, &len)) < 0)\n"
398              "return ASN1_BAD_FORMAT;\n"
399              "e = decode_%s(p, len, data, &l);\n"
400              "if (e)\n"
401              "return e;\n"
402              "p += l;\n"
403              "len -= l;\n"
404              "ret += l;\n"
405              "if (dce_fix) {\n"
406              "size_t reallen;\n\n"
407              "e = der_match_tag_and_length(p, len, "
408              "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
409              "if (e)\n"
410              "return e;\n"
411              "ret += l;\n"
412              "}\n",
413              s->gen_name);
414     fprintf (codefile, 
415              "if(size) *size = ret;\n"
416              "return 0;\n");
417
418     fprintf (codefile, "}\n\n");
419 }