Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * 3. Neither the name of the Institute nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : */
35 :
36 : /*
37 : * Currently we generate C source code defining constant arrays of structures
38 : * containing a sort of a "byte-coded" template of an ASN.1 compiler to be
39 : * interpreted at run-time.
40 : */
41 :
42 : #include "gen_locl.h"
43 : #include <vis.h>
44 : #include <vis-extras.h>
45 :
46 : static const char *symbol_name(const char *, const Type *);
47 : static void generate_template_type(const char *, const char **, const char *, const char *, const char *,
48 : Type *, int, int, int);
49 :
50 : static const char *
51 6412 : ttype_symbol(const char *basename, const Type *t)
52 : {
53 6412 : return t->symbol->gen_name;
54 : }
55 :
56 : static const char *
57 1708 : integer_symbol(const char *basename, const Type *t)
58 : {
59 1708 : if (t->members)
60 : /*
61 : * XXX enum foo -- compute the size either from inspecting the members
62 : * and applying the ABI's rules for enum size, OR infer the field
63 : * size from a template by using the offsetof field. The latter is
64 : * hard to do though.
65 : */
66 336 : return "int";
67 1372 : else if (t->range == NULL)
68 770 : return "heim_integer";
69 756 : else if (t->range->min < 0 &&
70 308 : (t->range->min < INT_MIN || t->range->max > INT_MAX))
71 0 : return "int64_t";
72 602 : else if (t->range->min < 0)
73 154 : return "int";
74 448 : else if (t->range->max > UINT_MAX)
75 0 : return "uint64_t";
76 : else
77 448 : return "unsigned";
78 : }
79 :
80 : static const char *
81 280 : boolean_symbol(const char *basename, const Type *t)
82 : {
83 280 : return "int";
84 : }
85 :
86 :
87 : static const char *
88 2562 : octetstring_symbol(const char *basename, const Type *t)
89 : {
90 2562 : return "heim_octet_string";
91 : }
92 :
93 : static const char *
94 56 : sequence_symbol(const char *basename, const Type *t)
95 : {
96 56 : return basename;
97 : }
98 :
99 : static const char *
100 224 : time_symbol(const char *basename, const Type *t)
101 : {
102 224 : return "time_t";
103 : }
104 :
105 : static const char *
106 3822 : tag_symbol(const char *basename, const Type *t)
107 : {
108 3822 : return symbol_name(basename, t->subtype);
109 : }
110 :
111 : static const char *
112 322 : generalstring_symbol(const char *basename, const Type *t)
113 : {
114 322 : return "heim_general_string";
115 : }
116 :
117 : static const char *
118 42 : printablestring_symbol(const char *basename, const Type *t)
119 : {
120 42 : return "heim_printable_string";
121 : }
122 :
123 : static const char *
124 266 : ia5string_symbol(const char *basename, const Type *t)
125 : {
126 266 : return "heim_ia5_string";
127 : }
128 :
129 : static const char *
130 28 : teletexstring_symbol(const char *basename, const Type *t)
131 : {
132 28 : return "heim_general_string";
133 : }
134 :
135 : static const char *
136 56 : visiblestring_symbol(const char *basename, const Type *t)
137 : {
138 56 : return "heim_visible_string";
139 : }
140 :
141 : static const char *
142 896 : utf8string_symbol(const char *basename, const Type *t)
143 : {
144 896 : return "heim_utf8_string";
145 : }
146 :
147 : static const char *
148 70 : bmpstring_symbol(const char *basename, const Type *t)
149 : {
150 70 : return "heim_bmp_string";
151 : }
152 :
153 : static const char *
154 28 : universalstring_symbol(const char *basename, const Type *t)
155 : {
156 28 : return "heim_universal_string";
157 : }
158 :
159 : static const char *
160 672 : oid_symbol(const char *basename, const Type *t)
161 : {
162 672 : return "heim_oid";
163 : }
164 :
165 : static const char *
166 420 : bitstring_symbol(const char *basename, const Type *t)
167 : {
168 420 : if (t->members)
169 420 : return basename;
170 0 : return "heim_bit_string";
171 : }
172 :
173 :
174 :
175 : /* Keep this sorted by `type' so we can just index this by type */
176 : const struct {
177 : enum typetype type;
178 : const char *(*symbol_name)(const char *, const Type *);
179 : int is_struct;
180 : } types[] = {
181 : { TBitString, bitstring_symbol, 0 },
182 : { TBoolean, boolean_symbol, 0 },
183 : { TChoice, sequence_symbol, 1 },
184 : { TEnumerated, integer_symbol, 0 },
185 : { TGeneralString, generalstring_symbol, 0 },
186 : { TTeletexString, teletexstring_symbol, 0 },
187 : { TGeneralizedTime, time_symbol, 0 },
188 : { TIA5String, ia5string_symbol, 0 },
189 : { TInteger, integer_symbol, 0 },
190 : { TNull, integer_symbol, 1 },
191 : { TOID, oid_symbol, 0 },
192 : { TOctetString, octetstring_symbol, 0 },
193 : { TPrintableString, printablestring_symbol, 0 },
194 : { TSequence, sequence_symbol, 1 },
195 : { TSequenceOf, tag_symbol, 1 },
196 : { TSet, sequence_symbol, 1 },
197 : { TSetOf, tag_symbol, 1 },
198 : { TTag, tag_symbol, 1 },
199 : { TType, ttype_symbol, 1 },
200 : { TUTCTime, time_symbol, 0 },
201 : { TUTF8String, utf8string_symbol, 0 },
202 : { TBMPString, bmpstring_symbol, 0 },
203 : { TUniversalString, universalstring_symbol, 0 },
204 : { TVisibleString, visiblestring_symbol, 0 },
205 : };
206 :
207 : static FILE *
208 68670 : get_code_file(void)
209 : {
210 68670 : if (!one_code_file)
211 0 : return templatefile;
212 68670 : return codefile;
213 : }
214 :
215 :
216 : static int
217 5026 : is_supported_type_p(const Type *t)
218 : {
219 10052 : return t->type >= 0 && t->type <= TVisibleString &&
220 5026 : types[t->type].type == t->type;
221 : }
222 :
223 : int
224 5026 : is_template_compat (const Symbol *s)
225 : {
226 5026 : return is_supported_type_p(s->type);
227 : }
228 :
229 : static const char *
230 17864 : symbol_name(const char *basename, const Type *t)
231 : {
232 35728 : if (t->type >= 0 && t->type <= TVisibleString &&
233 17864 : types[t->type].type == t->type)
234 17864 : return (types[t->type].symbol_name)(basename, t);
235 0 : if (t->type >= 0 && t->type <= TVisibleString)
236 0 : errx(1, "types[] is not sorted");
237 0 : errx(1, "unknown der type: %d\n", t->type);
238 : return NULL;
239 : }
240 :
241 :
242 : static char *
243 32284 : partial_offset(const char *basetype, const char *name, int need_offset, int isstruct)
244 : {
245 : char *str;
246 32284 : if (name == NULL || need_offset == 0)
247 22722 : return strdup("0");
248 9562 : if (asprintf(&str, "offsetof(%s%s, %s)", isstruct ? "struct " : "", basetype, name) < 0 || str == NULL)
249 0 : errx(1, "malloc");
250 9562 : return str;
251 : }
252 :
253 : struct template {
254 : char *line;
255 : char *tt;
256 : char *offset;
257 : char *ptr;
258 : HEIM_TAILQ_ENTRY(template) members;
259 : };
260 :
261 : HEIM_TAILQ_HEAD(templatehead, template);
262 :
263 : struct tlist {
264 : char *name;
265 : char *header;
266 : struct templatehead template;
267 : HEIM_TAILQ_ENTRY(tlist) tmembers;
268 : };
269 :
270 : HEIM_TAILQ_HEAD(tlisthead, tlist);
271 :
272 : static void tlist_header(struct tlist *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
273 : static struct template *
274 : add_line(struct templatehead *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
275 : static int tlist_cmp(const struct tlist *, const struct tlist *);
276 :
277 : static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...)
278 : __attribute__ ((__format__ (__printf__, 4, 5)));
279 : static void add_line_string(struct templatehead *, const char *, const char *, const char *, ...)
280 : __attribute__ ((__format__ (__printf__, 4, 5)));
281 : static void add_line_pointer_reference(struct templatehead *, const char *, const char *, const char *, ...)
282 : __attribute__ ((__format__ (__printf__, 4, 5)));
283 :
284 :
285 : static struct tlisthead tlistmaster = HEIM_TAILQ_HEAD_INITIALIZER(tlistmaster);
286 : static unsigned long numdups = 0;
287 :
288 : static struct tlist *
289 23128 : tlist_new(const char *name)
290 : {
291 23128 : struct tlist *tl = calloc(1, sizeof(*tl));
292 23128 : tl->name = strdup(name);
293 23128 : HEIM_TAILQ_INIT(&tl->template);
294 23128 : return tl;
295 : }
296 :
297 : static void
298 23128 : tlist_header(struct tlist *t, const char *fmt, ...)
299 : {
300 : va_list ap;
301 23128 : va_start(ap, fmt);
302 23128 : if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL)
303 0 : errx(1, "malloc");
304 23128 : va_end(ap);
305 23128 : }
306 :
307 : static unsigned long
308 22722 : tlist_count(struct tlist *tl)
309 : {
310 22722 : unsigned int count = 0;
311 : struct template *q;
312 :
313 65128 : HEIM_TAILQ_FOREACH(q, &tl->template, members) {
314 42406 : count++;
315 : }
316 22722 : return count;
317 : }
318 :
319 : static void
320 14406 : tlist_add(struct tlist *tl)
321 : {
322 14406 : HEIM_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers);
323 14406 : }
324 :
325 : static void
326 14406 : tlist_print(struct tlist *tl)
327 : {
328 : struct template *q;
329 14406 : unsigned int i = 1;
330 14406 : FILE *f = get_code_file();
331 :
332 14406 : fprintf(f, "const struct asn1_template asn1_%s[] = {\n", tl->name);
333 14406 : fprintf(f, "/* 0 */ %s,\n", tl->header);
334 54292 : HEIM_TAILQ_FOREACH(q, &tl->template, members) {
335 39886 : int last = (HEIM_TAILQ_LAST(&tl->template, templatehead) == q);
336 39886 : fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
337 : }
338 14406 : fprintf(f, "};\n");
339 14406 : }
340 :
341 : static struct tlist *
342 9660 : tlist_find_by_name(const char *name)
343 : {
344 : struct tlist *ql;
345 384608 : HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
346 384608 : if (strcmp(ql->name, name) == 0)
347 9660 : return ql;
348 : }
349 0 : return NULL;
350 : }
351 :
352 : static int
353 4830 : tlist_cmp_name(const char *tname, const char *qname)
354 : {
355 4830 : struct tlist *tl = tlist_find_by_name(tname);
356 4830 : struct tlist *ql = tlist_find_by_name(qname);
357 4830 : if (tl == NULL)
358 0 : return 1;
359 4830 : if (ql == NULL)
360 0 : return -1;
361 4830 : return tlist_cmp(tl, ql);
362 : }
363 :
364 : static int
365 1771798 : tlist_cmp(const struct tlist *tl, const struct tlist *ql)
366 : {
367 : int ret;
368 : struct template *t, *q;
369 :
370 1771798 : if (tl == ql)
371 4830 : return 0;
372 1766968 : ret = strcmp(tl->header, ql->header);
373 1766968 : if (ret != 0) return ret;
374 :
375 21630 : q = HEIM_TAILQ_FIRST(&ql->template);
376 30338 : HEIM_TAILQ_FOREACH(t, &tl->template, members) {
377 21616 : if (q == NULL) return 1;
378 :
379 21616 : if (t->ptr == NULL || q->ptr == NULL) {
380 11326 : ret = strcmp(t->line, q->line);
381 11326 : if (ret != 0) return ret;
382 : } else {
383 10290 : ret = strcmp(t->tt, q->tt);
384 10290 : if (ret != 0) return ret;
385 :
386 4858 : ret = strcmp(t->offset, q->offset);
387 4858 : if (ret != 0) return ret;
388 :
389 9688 : if ((ret = strcmp(t->ptr, q->ptr)) != 0 ||
390 4830 : (ret = tlist_cmp_name(t->ptr, q->ptr)) != 0)
391 28 : return ret;
392 : }
393 8708 : q = HEIM_TAILQ_NEXT(q, members);
394 : }
395 8722 : if (q != NULL) return -1;
396 8722 : return 0;
397 : }
398 :
399 :
400 : static const char *
401 23058 : tlist_find_dup(const struct tlist *tl)
402 : {
403 : struct tlist *ql;
404 :
405 1781304 : HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
406 1766968 : if (tlist_cmp(ql, tl) == 0) {
407 8722 : numdups++;
408 8722 : return ql->name;
409 : }
410 : }
411 14336 : return NULL;
412 : }
413 :
414 :
415 : /*
416 : * Add an entry to a template.
417 : */
418 :
419 : static struct template *
420 51562 : add_line(struct templatehead *t, const char *fmt, ...)
421 : {
422 51562 : struct template *q = calloc(1, sizeof(*q));
423 : va_list ap;
424 51562 : va_start(ap, fmt);
425 51562 : if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL)
426 0 : errx(1, "malloc");
427 51562 : va_end(ap);
428 51562 : HEIM_TAILQ_INSERT_TAIL(t, q, members);
429 51562 : return q;
430 : }
431 :
432 : /*
433 : * Add an entry to a template, with the pointer field being a symbol name of a
434 : * template (i.e., an array, which decays to a pointer as usual in C).
435 : */
436 : static void
437 22274 : add_line_pointer(struct templatehead *t,
438 : const char *ptr,
439 : const char *offset,
440 : const char *ttfmt,
441 : ...)
442 : {
443 : struct template *q;
444 : va_list ap;
445 22274 : char *tt = NULL;
446 :
447 22274 : va_start(ap, ttfmt);
448 22274 : if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
449 0 : errx(1, "malloc");
450 22274 : va_end(ap);
451 :
452 22274 : if (ptr[0] == '&')
453 14 : q = add_line(t, "{ %s, %s, %s }", tt, offset, ptr);
454 : else
455 22260 : q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr);
456 22274 : q->tt = tt;
457 22274 : q->offset = strdup(offset);
458 22274 : q->ptr = strdup(ptr);
459 22274 : }
460 :
461 : /*
462 : * Add an entry to a template where the pointer field is a string literal.
463 : */
464 : static void
465 12600 : add_line_string(struct templatehead *t,
466 : const char *str,
467 : const char *offset,
468 : const char *ttfmt,
469 : ...)
470 : {
471 : struct template *q;
472 : va_list ap;
473 12600 : char *tt = NULL;
474 :
475 12600 : va_start(ap, ttfmt);
476 12600 : if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
477 0 : errx(1, "malloc");
478 12600 : va_end(ap);
479 :
480 12600 : q = add_line(t, "{ %s, %s, \"%s\" }", tt, offset, str);
481 12600 : q->tt = tt;
482 12600 : q->offset = strdup(offset);
483 12600 : q->ptr = strdup(str);
484 12600 : }
485 :
486 : /*
487 : * Add an entry to a template, with the pointer field being a reference to
488 : * named object of a type other than a template or other array type.
489 : */
490 : static void
491 1428 : add_line_pointer_reference(struct templatehead *t,
492 : const char *ptr,
493 : const char *offset,
494 : const char *ttfmt,
495 : ...)
496 : {
497 : struct template *q;
498 : va_list ap;
499 1428 : char *tt = NULL;
500 :
501 1428 : va_start(ap, ttfmt);
502 1428 : if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
503 0 : errx(1, "malloc");
504 1428 : va_end(ap);
505 :
506 1428 : q = add_line(t, "{ %s, %s, (const void *)&asn1_%s }", tt, offset, ptr);
507 1428 : q->tt = tt;
508 1428 : q->offset = strdup(offset);
509 1428 : q->ptr = strdup(ptr);
510 1428 : }
511 :
512 : static int
513 12446 : use_extern(const Symbol *s)
514 : {
515 12446 : if (s->type == NULL)
516 1064 : return 1;
517 11382 : return 0;
518 : }
519 :
520 : static int
521 21364 : is_struct(const Type *t, int isstruct)
522 : {
523 21364 : if (t->type == TType)
524 5810 : return 0;
525 15554 : if (t->type == TSequence || t->type == TSet || t->type == TChoice)
526 2996 : return 1;
527 12558 : if (t->type == TTag)
528 3668 : return is_struct(t->subtype, isstruct);
529 :
530 17780 : if (t->type >= 0 && t->type <= TVisibleString &&
531 8890 : types[t->type].type == t->type) {
532 8890 : if (types[t->type].is_struct == 0)
533 7364 : return 0;
534 1526 : return isstruct;
535 : }
536 0 : if (t->type >= 0 && t->type <= TVisibleString)
537 0 : errx(1, "types[] is not sorted");
538 0 : errx(1, "unknown der type: %d\n", t->type);
539 : return isstruct;
540 : }
541 :
542 : static const Type *
543 56 : compact_tag(const Type *t)
544 : {
545 112 : while (t->type == TTag)
546 0 : t = t->subtype;
547 56 : return t;
548 : }
549 :
550 : static void
551 154 : defval(struct templatehead *temp, Member *m)
552 : {
553 154 : switch (m->defval->type) {
554 84 : case booleanvalue:
555 84 : add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)(uintptr_t)%u }",
556 84 : m->defval->u.booleanvalue);
557 84 : break;
558 0 : case nullvalue:
559 0 : add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)(uintptr_t)0 }");
560 0 : break;
561 70 : case integervalue: {
562 70 : const char *dv = "A1_DV_INTEGER";
563 70 : Type *t = m->type;
564 :
565 : for (;;) {
566 434 : if (t->range)
567 28 : break;
568 224 : if (t->type == TInteger && t->members)
569 42 : break;
570 182 : if (t->type == TEnumerated)
571 0 : break;
572 182 : if (t->subtype)
573 98 : t = t->subtype;
574 84 : else if (t->symbol && t->symbol->type)
575 84 : t = t->symbol->type;
576 : else
577 0 : errx(1, "DEFAULT values for unconstrained INTEGER members not supported");
578 : }
579 :
580 70 : if (t->members)
581 42 : dv = "A1_DV_INTEGER32"; /* XXX Enum size assumptions! No good! */
582 42 : else if (t->range && t->range->min < 0 &&
583 28 : (t->range->min < INT_MIN || t->range->max > INT_MAX))
584 0 : dv = "A1_DV_INTEGER64";
585 28 : else if (t->range && t->range->min < 0)
586 14 : dv = "A1_DV_INTEGER32";
587 14 : else if (t->range && t->range->max > UINT_MAX)
588 0 : dv = "A1_DV_INTEGER64";
589 : else
590 14 : dv = "A1_DV_INTEGER32";
591 70 : add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)(uintptr_t)%llu }",
592 70 : dv, (long long)m->defval->u.integervalue);
593 70 : break;
594 : }
595 0 : case stringvalue: {
596 : char *quoted;
597 :
598 0 : if (rk_strasvis("ed, m->defval->u.stringvalue,
599 : VIS_CSTYLE | VIS_NL, "\"") < 0)
600 0 : err(1, "Could not quote a string");
601 0 : add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)(uintptr_t)\"%s\" }",
602 : quoted);
603 0 : free(quoted);
604 0 : break;
605 : }
606 0 : case objectidentifiervalue: {
607 : struct objid *o;
608 0 : size_t sz = sizeof("{ }");
609 : char *s, *p;
610 : int len;
611 :
612 0 : for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) {
613 0 : if ((len = snprintf(0, 0, " %d", o->value)) < 0)
614 0 : err(1, "Could not format integer");
615 0 : sz += len;
616 : }
617 :
618 0 : if ((p = s = malloc(sz)) == NULL)
619 0 : err(1, "Could not allocate string");
620 :
621 0 : len = snprintf(p, sz, "{");
622 0 : sz -= len;
623 0 : p += len;
624 0 : for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) {
625 0 : if ((len = snprintf(p, sz, " %d", o->value)) < 0 || len > sz - 1)
626 0 : err(1, "Could not format integer");
627 0 : sz -= len;
628 0 : p += len;
629 : }
630 0 : if ((len = snprintf(p, sz, " }")) >= sz)
631 0 : abort();
632 0 : sz -= len;
633 0 : if (sz != 0)
634 0 : abort();
635 :
636 0 : add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)(uintptr_t)\"%s\" }", s);
637 0 : free(s);
638 0 : break;
639 : }
640 0 : default: abort();
641 : }
642 154 : }
643 :
644 : int
645 6944 : objid_cmp(struct objid *oida, struct objid *oidb)
646 : {
647 : struct objid *p;
648 : size_t ai, bi, alen, blen;
649 : int avals[20];
650 : int bvals[20];
651 : int c;
652 :
653 : /*
654 : * Our OID values are backwards here. Comparing them is hard.
655 : */
656 :
657 46410 : for (p = oida, alen = 0;
658 32522 : p && alen < sizeof(avals)/sizeof(avals[0]);
659 32522 : p = p->next)
660 32522 : avals[alen++] = p->value;
661 49070 : for (p = oidb, blen = 0;
662 35182 : p && blen < sizeof(bvals)/sizeof(bvals[0]);
663 35182 : p = p->next)
664 35182 : bvals[blen++] = p->value;
665 6944 : if (alen >= sizeof(avals)/sizeof(avals[0]) ||
666 : blen >= sizeof(bvals)/sizeof(bvals[0]))
667 0 : err(1, "OIDs with more components than %llu not supported",
668 : (unsigned long long)sizeof(avals)/sizeof(avals[0]));
669 :
670 33614 : for (ai = 0, bi = 0; ai < alen && bi < blen;)
671 26670 : if ((c = avals[(alen-1)-(ai++)] - bvals[(blen-1)-(bi++)]))
672 6944 : return c;
673 :
674 0 : if (ai == alen && bi == blen)
675 0 : return 0;
676 0 : if (ai == alen)
677 0 : return 1;
678 0 : return -1;
679 : }
680 :
681 : int
682 6944 : object_cmp(const void *va, const void *vb)
683 : {
684 6944 : const IOSObject *oa = *(const IOSObject * const *)va;
685 6944 : const IOSObject *ob = *(const IOSObject * const *)vb;
686 :
687 6944 : switch (oa->typeidf->value->type) {
688 0 : case booleanvalue:
689 0 : return oa->typeidf->value->u.booleanvalue -
690 0 : ob->typeidf->value->u.booleanvalue;
691 0 : case nullvalue:
692 0 : return 0;
693 0 : case integervalue:
694 0 : return oa->typeidf->value->u.integervalue -
695 0 : ob->typeidf->value->u.integervalue;
696 0 : case stringvalue:
697 0 : return strcmp(oa->typeidf->value->u.stringvalue,
698 0 : ob->typeidf->value->u.stringvalue);
699 6944 : case objectidentifiervalue: {
700 6944 : return objid_cmp(oa->typeidf->value->u.objectidentifiervalue,
701 6944 : ob->typeidf->value->u.objectidentifiervalue);
702 : }
703 0 : default:
704 0 : abort();
705 : return -1;
706 : }
707 : }
708 :
709 : void
710 224 : sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */
711 : Field *typeidfield, /* Field to sort by */
712 : IOSObject ***objectsp, /* Output: array of objects */
713 : size_t *nobjsp) /* Output: count of objects */
714 : {
715 : IOSObject **objects;
716 : IOSObject *o;
717 224 : size_t i, nobjs = 0;
718 :
719 224 : *objectsp = NULL;
720 :
721 2674 : HEIM_TAILQ_FOREACH(o, os->objects, objects) {
722 2450 : ObjectField *typeidobjf = NULL;
723 : ObjectField *of;
724 :
725 8190 : HEIM_TAILQ_FOREACH(of, o->objfields, objfields) {
726 5740 : if (strcmp(of->name, typeidfield->name) == 0)
727 2450 : typeidobjf = of;
728 : }
729 2450 : if (!typeidobjf) {
730 0 : warnx("Ignoring incomplete object specification of %s "
731 : "(missing type ID field)",
732 0 : o->symbol ? o->symbol->name : "<unknown>");
733 0 : continue;
734 : }
735 2450 : o->typeidf = typeidobjf;
736 2450 : nobjs++;
737 : }
738 224 : *nobjsp = nobjs;
739 :
740 224 : if (nobjs == 0)
741 0 : return;
742 :
743 224 : if ((objects = calloc(nobjs, sizeof(*objects))) == NULL)
744 0 : err(1, "Out of memory");
745 224 : *objectsp = objects;
746 :
747 224 : i = 0;
748 2674 : HEIM_TAILQ_FOREACH(o, os->objects, objects) {
749 2450 : ObjectField *typeidobjf = NULL;
750 : ObjectField *of;
751 :
752 8190 : HEIM_TAILQ_FOREACH(of, o->objfields, objfields) {
753 5740 : if (strcmp(of->name, typeidfield->name) == 0)
754 2450 : typeidobjf = of;
755 : }
756 2450 : if (typeidobjf)
757 2450 : objects[i++] = o;
758 : }
759 224 : qsort(objects, nobjs, sizeof(*objects), object_cmp);
760 : }
761 :
762 : static void
763 84 : template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield)
764 : {
765 84 : IOSObject **objects = NULL;
766 : IOSObject *o;
767 : struct tlist *tl;
768 : size_t nobjs, i;
769 :
770 84 : if (os->symbol->emitted_template)
771 14 : return;
772 :
773 70 : sort_object_set(os, typeidfield, &objects, &nobjs);
774 :
775 70 : tl = tlist_new(os->symbol->name);
776 70 : add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", os->symbol->name);
777 784 : for (i = 0; i < nobjs; i++) {
778 714 : ObjectField *typeidobjf = NULL, *opentypeobjf = NULL;
779 : ObjectField *of;
780 714 : char *s = NULL;
781 :
782 714 : o = objects[i];
783 :
784 2422 : HEIM_TAILQ_FOREACH(of, o->objfields, objfields) {
785 1708 : if (strcmp(of->name, typeidfield->name) == 0)
786 714 : typeidobjf = of;
787 994 : else if (strcmp(of->name, opentypefield->name) == 0)
788 714 : opentypeobjf = of;
789 : }
790 714 : if (!typeidobjf)
791 0 : continue; /* We've warned about this one already when sorting */
792 714 : if (!opentypeobjf) {
793 0 : warnx("Ignoring incomplete object specification of %s "
794 : "(missing open type field)",
795 0 : o->symbol ? o->symbol->name : "<unknown>");
796 0 : continue;
797 : }
798 :
799 714 : add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", o->symbol->name);
800 : /*
801 : * Some of this logic could stand to move into sanity checks of object
802 : * definitions in asn1parse.y.
803 : */
804 714 : switch (typeidobjf->value->type) {
805 0 : case integervalue:
806 0 : add_line(&tl->template,
807 : "{ A1_OP_OPENTYPE_ID | A1_OTI_IS_INTEGER, 0, (void *)(uintptr_t)%lld }",
808 0 : (long long)typeidobjf->value->u.integervalue);
809 0 : break;
810 714 : case objectidentifiervalue:
811 714 : if (asprintf(&s, "oid_%s",
812 1428 : typeidobjf->value->s->gen_name) == -1 || !s)
813 0 : err(1, "Out of memory");
814 714 : add_line_pointer_reference(&tl->template, s, "0", "A1_OP_OPENTYPE_ID");
815 714 : free(s);
816 714 : s = NULL;
817 714 : break;
818 0 : default:
819 0 : errx(1, "Only integer and OID types supported "
820 : "for open type type-ID fields");
821 : }
822 :
823 714 : if (asprintf(&s, "sizeof(%s)",
824 1428 : opentypeobjf->type->symbol->gen_name) == -1 || !s)
825 0 : err(1, "Out of memory");
826 1428 : add_line_pointer_reference(&tl->template,
827 714 : opentypeobjf->type->symbol->gen_name, s,
828 : "A1_OP_OPENTYPE");
829 714 : free(s);
830 : }
831 70 : free(objects);
832 :
833 70 : tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nobjs);
834 70 : tlist_print(tl);
835 70 : tlist_add(tl);
836 70 : os->symbol->emitted_template = 1;
837 : }
838 :
839 : static void
840 84 : template_open_type(struct templatehead *temp,
841 : const char *basetype,
842 : const Type *t,
843 : size_t typeididx,
844 : size_t opentypeidx,
845 : Field *typeidfield,
846 : Field *opentypefield,
847 : Member *m,
848 : int is_array_of_open_type)
849 : {
850 84 : char *s = NULL;
851 :
852 84 : if (typeididx >= 1<<10 || opentypeidx >= 1<<10)
853 0 : errx(1, "SET/SEQUENCE with too many members (%s)", basetype);
854 :
855 84 : if (asprintf(&s, "offsetof(%s, _ioschoice_%s)",
856 84 : basetype, m->gen_name) == -1 || !s)
857 0 : err(1, "Out of memory");
858 :
859 84 : template_object_set(t->actual_parameter, typeidfield, opentypefield);
860 84 : add_line_pointer(temp, t->actual_parameter->symbol->gen_name, s,
861 : /*
862 : * We always sort object sets for now as we can't import
863 : * values yet, so they must all be known.
864 : */
865 : "A1_OP_OPENTYPE_OBJSET | A1_OS_IS_SORTED |%s | (%llu << 10) | %llu",
866 : is_array_of_open_type ? "A1_OS_OT_IS_ARRAY" : "0",
867 : (unsigned long long)opentypeidx,
868 : (unsigned long long)typeididx);
869 84 : free(s);
870 84 : }
871 :
872 : static void
873 2660 : template_names(struct templatehead *temp, const char *basetype, const Type *t)
874 : {
875 : Member *m;
876 :
877 2660 : add_line_string(temp, basetype, "0", "A1_OP_NAME");
878 12600 : HEIM_TAILQ_FOREACH(m, t->members, members) {
879 9940 : add_line_string(temp, m->name, "0", "A1_OP_NAME");
880 : }
881 2660 : }
882 :
883 : static void
884 32256 : template_members(struct templatehead *temp,
885 : const char *basetype,
886 : const char *name,
887 : const Type *t,
888 : int optional,
889 : int defaulted,
890 : int implicit,
891 : int isstruct,
892 : int need_offset)
893 : {
894 32256 : char *poffset = NULL;
895 :
896 32256 : if (optional && t->type != TTag && t->type != TType)
897 0 : errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name);
898 :
899 32256 : poffset = partial_offset(basetype, name, need_offset, isstruct);
900 :
901 32256 : switch (t->type) {
902 7420 : case TType:
903 7420 : if (use_extern(t->symbol)) {
904 1064 : add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s%s, %s, &asn1_extern_%s}",
905 : optional ? "|A1_FLAG_OPTIONAL" : "",
906 : defaulted ? "|A1_FLAG_DEFAULT" : "",
907 : implicit ? "|A1_FLAG_IMPLICIT" : "",
908 1064 : poffset, t->symbol->gen_name);
909 : } else {
910 6356 : add_line_pointer(temp, t->symbol->gen_name, poffset,
911 : "A1_OP_TYPE %s%s%s",
912 : optional ? "|A1_FLAG_OPTIONAL" : "",
913 : defaulted ? "|A1_FLAG_DEFAULT" : "",
914 : implicit ? "|A1_FLAG_IMPLICIT" : "");
915 :
916 : }
917 7420 : break;
918 1288 : case TEnumerated:
919 : case TInteger: {
920 1288 : char *varname = NULL;
921 1288 : char *itype = NULL;
922 :
923 1288 : if (t->members)
924 336 : itype = "IMEMBER";
925 952 : else if (t->range == NULL)
926 546 : itype = "HEIM_INTEGER";
927 504 : else if (t->range->min < 0 &&
928 196 : (t->range->min < INT_MIN || t->range->max > INT_MAX))
929 0 : itype = "INTEGER64";
930 406 : else if (t->range->min < 0)
931 98 : itype = "INTEGER";
932 308 : else if (t->range->max > UINT_MAX)
933 0 : itype = "UNSIGNED64";
934 : else
935 308 : itype = "UNSIGNED";
936 :
937 : /*
938 : * If `t->members' then we should generate a template for those
939 : * members.
940 : *
941 : * We don't know the name of this field, and the type may not have a
942 : * name. If it has no name, we should generate a name for it, and if
943 : * it does have a name, use it, to name a template for its members.
944 : *
945 : * Then we could use that in _asn1_print() to pretty-print values of
946 : * enumerations.
947 : */
948 1624 : if (t->members && t->symbol) {
949 : struct tlist *tl;
950 : Member *m;
951 336 : size_t nmemb = 0;
952 :
953 672 : if (asprintf(&varname, "%s_enum_names", t->symbol->gen_name) == -1 ||
954 336 : varname == NULL)
955 0 : err(1, "Out of memory");
956 :
957 336 : tl = tlist_new(varname);
958 : /*
959 : * XXX We're going to assume that t->members is sorted in
960 : * numerically ascending order in the module source. We should
961 : * really sort it here.
962 : */
963 4312 : HEIM_TAILQ_FOREACH(m, t->members, members) {
964 3976 : if (m->val > UINT32_MAX)
965 0 : errx(1, "Cannot handle %s type %s with named bit %s "
966 : "larger than 63",
967 0 : t->type == TEnumerated ? "ENUMERATED" : "INTEGER",
968 : name, m->gen_name);
969 7952 : add_line(&tl->template,
970 3976 : "{ A1_OP_NAME, %d, \"%s\" }", (int)m->val, m->name);
971 3976 : nmemb++;
972 : }
973 336 : tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nmemb);
974 : /* XXX Accidentally O(N^2)? */
975 336 : if (!tlist_find_dup(tl)) {
976 336 : tlist_print(tl);
977 336 : tlist_add(tl);
978 : }
979 336 : add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, asn1_%s }", itype, poffset, varname);
980 : } else {
981 952 : add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset);
982 : }
983 1288 : break;
984 : }
985 182 : case TGeneralString:
986 182 : add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset);
987 182 : break;
988 14 : case TTeletexString:
989 14 : add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset);
990 14 : break;
991 28 : case TPrintableString:
992 28 : add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset);
993 28 : break;
994 1484 : case TOctetString:
995 1484 : add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset);
996 1484 : break;
997 154 : case TIA5String:
998 154 : add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset);
999 154 : break;
1000 42 : case TBMPString:
1001 42 : add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset);
1002 42 : break;
1003 14 : case TUniversalString:
1004 14 : add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset);
1005 14 : break;
1006 28 : case TVisibleString:
1007 28 : add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset);
1008 28 : break;
1009 588 : case TUTF8String:
1010 588 : add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset);
1011 588 : break;
1012 126 : case TGeneralizedTime:
1013 126 : add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset);
1014 126 : break;
1015 14 : case TUTCTime:
1016 14 : add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset);
1017 14 : break;
1018 182 : case TBoolean:
1019 182 : add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset);
1020 182 : break;
1021 462 : case TOID:
1022 462 : add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset);
1023 462 : break;
1024 56 : case TNull:
1025 56 : break;
1026 350 : case TBitString: {
1027 : struct templatehead template;
1028 : struct template *q;
1029 : Member *m;
1030 350 : size_t count = 0, i;
1031 350 : char *bname = NULL;
1032 350 : FILE *f = get_code_file();
1033 : static unsigned long bmember_counter = 0;
1034 :
1035 350 : HEIM_TAILQ_INIT(&template);
1036 :
1037 350 : if (HEIM_TAILQ_EMPTY(t->members)) {
1038 210 : add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset);
1039 210 : break;
1040 : }
1041 :
1042 140 : if (asprintf(&bname, "bmember_%s_%lu", name ? name : "", bmember_counter++) < 0 || bname == NULL)
1043 0 : errx(1, "malloc");
1044 140 : output_name(bname);
1045 :
1046 1372 : HEIM_TAILQ_FOREACH(m, t->members, members) {
1047 1232 : if (m->val > UINT32_MAX)
1048 0 : errx(1, "Cannot handle BIT STRING type %s with named bit %s "
1049 : "larger than 63", name, m->gen_name);
1050 1232 : add_line(&template, "{ 0, %d, \"%s\" }", (int)m->val, m->gen_name);
1051 : }
1052 :
1053 1372 : HEIM_TAILQ_FOREACH(q, &template, members) {
1054 1232 : count++;
1055 : }
1056 :
1057 140 : fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname);
1058 140 : fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)(uintptr_t)%lu) },\n",
1059 140 : rfc1510_bitstring ? "|A1_HBF_RFC1510" : "",
1060 : basetype, (unsigned long)count);
1061 140 : i = 1;
1062 1372 : HEIM_TAILQ_FOREACH(q, &template, members) {
1063 1232 : int last = (HEIM_TAILQ_LAST(&template, templatehead) == q);
1064 1232 : fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
1065 : }
1066 140 : fprintf(f, "};\n");
1067 :
1068 140 : add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname);
1069 :
1070 140 : free(bname);
1071 :
1072 140 : break;
1073 : }
1074 0 : case TSet: {
1075 0 : Member *opentypemember = NULL;
1076 0 : Member *typeidmember = NULL;
1077 0 : Field *opentypefield = NULL;
1078 0 : Field *typeidfield = NULL;
1079 : Member *m;
1080 : struct decoration deco;
1081 0 : ssize_t more_deco = -1;
1082 0 : size_t i = 0, typeididx = 0, opentypeidx = 0;
1083 0 : int is_array_of_open_type = 0;
1084 :
1085 0 : if (isstruct && t->actual_parameter)
1086 0 : get_open_type_defn_fields(t, &typeidmember, &opentypemember,
1087 : &typeidfield, &opentypefield,
1088 : &is_array_of_open_type);
1089 :
1090 0 : fprintf(get_code_file(), "/* tset: members isstruct: %d */\n", isstruct);
1091 :
1092 0 : HEIM_TAILQ_FOREACH(m, t->members, members) {
1093 0 : char *newbasename = NULL;
1094 :
1095 0 : if (m->ellipsis)
1096 0 : continue;
1097 :
1098 0 : if (typeidmember == m) typeididx = i;
1099 0 : if (opentypemember == m) opentypeidx = i;
1100 :
1101 0 : if (name) {
1102 0 : if (asprintf(&newbasename, "%s_%s", basetype, name) < 0)
1103 0 : errx(1, "malloc");
1104 : } else
1105 0 : newbasename = strdup(basetype);
1106 0 : if (newbasename == NULL)
1107 0 : errx(1, "malloc");
1108 :
1109 0 : if (m->defval)
1110 0 : defval(temp, m);
1111 :
1112 0 : template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1);
1113 :
1114 0 : free(newbasename);
1115 0 : i++;
1116 : }
1117 :
1118 0 : if (isstruct && t->actual_parameter)
1119 0 : template_open_type(temp, basetype, t, typeididx, opentypeidx,
1120 : typeidfield, opentypefield, opentypemember,
1121 : is_array_of_open_type);
1122 :
1123 0 : while (decorate_type(basetype, &deco, &more_deco)) {
1124 : char *poffset2;
1125 :
1126 0 : poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct);
1127 :
1128 0 : if (deco.ext) {
1129 0 : char *ptr = NULL;
1130 :
1131 : /* Decorated with external C type */
1132 0 : if (asprintf(&ptr, "&asn1_extern_%s_%s",
1133 0 : basetype, deco.field_name) == -1 || ptr == NULL)
1134 0 : err(1, "out of memory");
1135 0 : add_line_pointer(temp, ptr, poffset2,
1136 : "A1_OP_TYPE_DECORATE_EXTERN %s",
1137 0 : deco.opt ? "|A1_FLAG_OPTIONAL" : "");
1138 0 : free(ptr);
1139 : } else
1140 : /* Decorated with a templated ASN.1 type */
1141 0 : add_line_pointer(temp, deco.field_type, poffset2,
1142 : "A1_OP_TYPE_DECORATE %s",
1143 0 : deco.opt ? "|A1_FLAG_OPTIONAL" : "");
1144 0 : free(poffset2);
1145 0 : free(deco.field_type);
1146 : }
1147 :
1148 0 : if (isstruct)
1149 0 : template_names(temp, basetype, t);
1150 0 : break;
1151 : }
1152 2660 : case TSequence: {
1153 2660 : Member *opentypemember = NULL;
1154 2660 : Member *typeidmember = NULL;
1155 2660 : Field *opentypefield = NULL;
1156 2660 : Field *typeidfield = NULL;
1157 : Member *m;
1158 : struct decoration deco;
1159 2660 : ssize_t more_deco = -1;
1160 2660 : size_t i = 0, typeididx = 0, opentypeidx = 0;
1161 2660 : int is_array_of_open_type = 0;
1162 :
1163 2660 : if (isstruct && t->actual_parameter)
1164 84 : get_open_type_defn_fields(t, &typeidmember, &opentypemember,
1165 : &typeidfield, &opentypefield,
1166 : &is_array_of_open_type);
1167 :
1168 2660 : fprintf(get_code_file(), "/* tsequence: members isstruct: %d */\n", isstruct);
1169 :
1170 12600 : HEIM_TAILQ_FOREACH(m, t->members, members) {
1171 9940 : char *newbasename = NULL;
1172 :
1173 9940 : if (m->ellipsis)
1174 406 : continue;
1175 :
1176 9534 : if (typeidmember == m) typeididx = i;
1177 9534 : if (opentypemember == m) opentypeidx = i;
1178 :
1179 9534 : if (name) {
1180 56 : if (asprintf(&newbasename, "%s_%s", basetype, name) < 0)
1181 0 : errx(1, "malloc");
1182 : } else
1183 9478 : newbasename = strdup(basetype);
1184 9534 : if (newbasename == NULL)
1185 0 : errx(1, "malloc");
1186 :
1187 9534 : if (m->defval)
1188 154 : defval(temp, m);
1189 :
1190 9534 : template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1);
1191 :
1192 9534 : free(newbasename);
1193 9534 : i++;
1194 : }
1195 :
1196 2660 : if (isstruct && t->actual_parameter)
1197 84 : template_open_type(temp, basetype, t, typeididx, opentypeidx,
1198 : typeidfield, opentypefield, opentypemember,
1199 : is_array_of_open_type);
1200 :
1201 5348 : while (decorate_type(basetype, &deco, &more_deco)) {
1202 : char *poffset2;
1203 :
1204 28 : poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct);
1205 :
1206 28 : if (deco.ext) {
1207 14 : char *ptr = NULL;
1208 :
1209 : /* Decorated with external C type */
1210 14 : if (asprintf(&ptr, "&asn1_extern_%s_%s",
1211 14 : basetype, deco.field_name) == -1 || ptr == NULL)
1212 0 : err(1, "out of memory");
1213 14 : add_line_pointer(temp, ptr, poffset2,
1214 : "A1_OP_TYPE_DECORATE_EXTERN %s",
1215 14 : deco.opt ? "|A1_FLAG_OPTIONAL" : "");
1216 14 : free(ptr);
1217 : } else
1218 : /* Decorated with a templated ASN.1 type */
1219 14 : add_line_pointer(temp, deco.field_type, poffset2,
1220 : "A1_OP_TYPE_DECORATE %s",
1221 14 : deco.opt ? "|A1_FLAG_OPTIONAL" : "");
1222 28 : free(poffset2);
1223 28 : free(deco.field_type);
1224 : }
1225 :
1226 2660 : if (isstruct)
1227 2660 : template_names(temp, basetype, t);
1228 2660 : break;
1229 : }
1230 15806 : case TTag: {
1231 15806 : char *tname = NULL, *elname = NULL;
1232 : const char *sename, *dupname;
1233 15806 : int subtype_is_struct = is_struct(t->subtype, isstruct);
1234 : static unsigned long tag_counter = 0;
1235 15806 : int tagimplicit = 0;
1236 38682 : int prim = !(t->tag.tagclass != ASN1_C_UNIV &&
1237 25382 : t->tag.tagenv == TE_EXPLICIT) &&
1238 9576 : is_primitive_type(t->subtype);
1239 :
1240 15806 : if (t->tag.tagenv == TE_IMPLICIT) {
1241 1050 : Type *t2 = t->subtype ? t->subtype : t->symbol->type;
1242 :
1243 2394 : while (t2->type == TType && (t2->subtype || t2->symbol->type))
1244 294 : t2 = t2->subtype ? t2->subtype : t2->symbol->type;
1245 1050 : if (t2->type != TChoice)
1246 1022 : tagimplicit = 1;
1247 : }
1248 :
1249 15806 : fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp");
1250 :
1251 15806 : if (subtype_is_struct)
1252 3640 : sename = basetype;
1253 : else
1254 12166 : sename = symbol_name(basetype, t->subtype);
1255 :
1256 15806 : if (asprintf(&tname, "tag_%s_%lu", name ? name : "", tag_counter++) < 0 || tname == NULL)
1257 0 : errx(1, "malloc");
1258 15806 : output_name(tname);
1259 :
1260 15806 : if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL)
1261 0 : errx(1, "malloc");
1262 :
1263 15806 : generate_template_type(elname, &dupname, NULL, sename, name,
1264 15806 : t->subtype, 0, subtype_is_struct, 0);
1265 :
1266 47418 : add_line_pointer(temp, dupname, poffset,
1267 : "A1_TAG_T(%s,%s,%s)%s%s%s",
1268 15806 : classname(t->tag.tagclass),
1269 : prim ? "PRIM" : "CONS",
1270 15806 : valuename(t->tag.tagclass, t->tag.tagvalue),
1271 : optional ? "|A1_FLAG_OPTIONAL" : "",
1272 : defaulted ? "|A1_FLAG_DEFAULT" : "",
1273 : tagimplicit ? "|A1_FLAG_IMPLICIT" : "");
1274 :
1275 15806 : free(tname);
1276 15806 : free(elname);
1277 :
1278 15806 : break;
1279 : }
1280 1050 : case TSetOf:
1281 : case TSequenceOf: {
1282 1050 : const char *type = NULL, *tname, *dupname;
1283 1050 : char *sename = NULL, *elname = NULL;
1284 1050 : int subtype_is_struct = is_struct(t->subtype, 0);
1285 : static unsigned long seof_counter = 0;
1286 :
1287 1050 : if (name && subtype_is_struct) {
1288 14 : tname = "seofTstruct";
1289 28 : if (asprintf(&sename, "%s_%s_val", basetype, name) < 0)
1290 0 : errx(1, "malloc");
1291 1036 : } else if (subtype_is_struct) {
1292 14 : tname = "seofTstruct";
1293 14 : if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0)
1294 0 : errx(1, "malloc");
1295 : } else {
1296 1022 : if (name)
1297 392 : tname = name;
1298 : else
1299 630 : tname = "seofTstruct";
1300 1022 : sename = strdup(symbol_name(basetype, t->subtype));
1301 : }
1302 1050 : if (sename == NULL)
1303 0 : errx(1, "malloc");
1304 :
1305 1050 : if (t->type == TSetOf) type = "A1_OP_SETOF";
1306 812 : else if (t->type == TSequenceOf) type = "A1_OP_SEQOF";
1307 0 : else abort();
1308 :
1309 1050 : if (asprintf(&elname, "%s_%s_%lu", basetype, tname, seof_counter++) < 0 || elname == NULL)
1310 0 : errx(1, "malloc");
1311 :
1312 1050 : generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype,
1313 : 0, subtype_is_struct, need_offset);
1314 :
1315 1050 : add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname);
1316 1050 : free(sename);
1317 1050 : break;
1318 : }
1319 308 : case TChoice: {
1320 : struct decoration deco;
1321 308 : ssize_t more_deco = -1;
1322 : struct templatehead template;
1323 : struct template *q;
1324 308 : size_t count = 0, i;
1325 308 : char *tname = NULL;
1326 308 : FILE *f = get_code_file();
1327 : Member *m;
1328 308 : int ellipsis = 0;
1329 : char *e;
1330 : static unsigned long choice_counter = 0;
1331 :
1332 308 : HEIM_TAILQ_INIT(&template);
1333 :
1334 308 : if (asprintf(&tname, "asn1_choice_%s_%s%lu",
1335 308 : basetype, name ? name : "", choice_counter++) < 0 || tname == NULL)
1336 0 : errx(1, "malloc");
1337 :
1338 1204 : HEIM_TAILQ_FOREACH(m, t->members, members) {
1339 : const char *dupname;
1340 896 : char *elname = NULL;
1341 896 : char *newbasename = NULL;
1342 : int subtype_is_struct;
1343 :
1344 896 : if (m->ellipsis) {
1345 56 : ellipsis = 1;
1346 56 : continue;
1347 : }
1348 :
1349 840 : subtype_is_struct = is_struct(m->type, 0);
1350 :
1351 840 : if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL)
1352 0 : errx(1, "malloc");
1353 :
1354 840 : if (subtype_is_struct) {
1355 28 : if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0)
1356 0 : errx(1, "malloc");
1357 : } else
1358 812 : newbasename = strdup(basetype);
1359 :
1360 840 : if (newbasename == NULL)
1361 0 : errx(1, "malloc");
1362 :
1363 :
1364 840 : generate_template_type(elname, &dupname, NULL,
1365 840 : symbol_name(newbasename, m->type),
1366 840 : NULL, m->type, 0, subtype_is_struct, 1);
1367 :
1368 840 : add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }",
1369 : m->label, isstruct ? "struct " : "",
1370 : basetype, m->gen_name,
1371 : dupname);
1372 :
1373 840 : free(elname);
1374 840 : free(newbasename);
1375 : }
1376 :
1377 1204 : HEIM_TAILQ_FOREACH(m, t->members, members) {
1378 896 : add_line(&template, "{ 0, 0, \"%s\" }", m->name);
1379 : }
1380 :
1381 308 : e = NULL;
1382 308 : if (ellipsis) {
1383 56 : if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL)
1384 0 : errx(1, "malloc");
1385 : }
1386 :
1387 2044 : HEIM_TAILQ_FOREACH(q, &template, members) {
1388 1736 : count++;
1389 : }
1390 :
1391 308 : fprintf(f, "static const struct asn1_template %s[] = {\n", tname);
1392 616 : fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)(uintptr_t)%lu) },\n",
1393 308 : e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count);
1394 308 : i = 1;
1395 2044 : HEIM_TAILQ_FOREACH(q, &template, members) {
1396 1736 : int last = (HEIM_TAILQ_LAST(&template, templatehead) == q);
1397 1736 : fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
1398 : }
1399 308 : fprintf(f, "};\n");
1400 :
1401 308 : add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname);
1402 :
1403 616 : while (decorate_type(basetype, &deco, &more_deco)) {
1404 : char *poffset2;
1405 :
1406 0 : poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct);
1407 :
1408 0 : if (deco.ext) {
1409 0 : char *ptr = NULL;
1410 :
1411 : /* Decorated with external C type */
1412 0 : if (asprintf(&ptr, "&asn1_extern_%s_%s",
1413 0 : basetype, deco.field_name) == -1 || ptr == NULL)
1414 0 : err(1, "out of memory");
1415 0 : add_line_pointer(temp, ptr, poffset2,
1416 : "A1_OP_TYPE_DECORATE_EXTERN %s",
1417 0 : deco.opt ? "|A1_FLAG_OPTIONAL" : "");
1418 0 : free(ptr);
1419 : } else
1420 : /* Decorated with a templated ASN.1 type */
1421 0 : add_line_pointer(temp, deco.field_type, poffset2,
1422 : "A1_OP_TYPE_DECORATE %s",
1423 0 : deco.opt ? "|A1_FLAG_OPTIONAL" : "");
1424 0 : free(poffset2);
1425 0 : free(deco.field_type);
1426 : }
1427 :
1428 308 : free(e);
1429 308 : free(tname);
1430 308 : break;
1431 : }
1432 0 : default:
1433 0 : abort ();
1434 : }
1435 32256 : if (poffset)
1436 32256 : free(poffset);
1437 32256 : }
1438 :
1439 : static void
1440 616 : gen_extern_stubs(FILE *f, const char *name)
1441 : {
1442 616 : fprintf(f,
1443 : "static const struct asn1_type_func asn1_extern_%s = {\n"
1444 : "\t(asn1_type_encode)encode_%s,\n"
1445 : "\t(asn1_type_decode)decode_%s,\n"
1446 : "\t(asn1_type_length)length_%s,\n"
1447 : "\t(asn1_type_copy)copy_%s,\n"
1448 : "\t(asn1_type_release)free_%s,\n"
1449 : "\t(asn1_type_print)print_%s,\n"
1450 : "\tsizeof(%s)\n"
1451 : "};\n",
1452 : name, name, name, name,
1453 : name, name, name, name);
1454 616 : }
1455 :
1456 : void
1457 784 : gen_template_import(const Symbol *s)
1458 : {
1459 784 : FILE *f = get_code_file();
1460 :
1461 784 : if (template_flag == 0)
1462 168 : return;
1463 :
1464 616 : gen_extern_stubs(f, s->gen_name);
1465 : }
1466 :
1467 : void
1468 6538 : generate_template_type_forward(const char *name)
1469 : {
1470 6538 : fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", name);
1471 6538 : }
1472 :
1473 : void
1474 70 : generate_template_objectset_forwards(const Symbol *s)
1475 : {
1476 70 : if (!template_flag)
1477 0 : return;
1478 70 : fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n",
1479 : s->gen_name);
1480 : }
1481 :
1482 : static void
1483 22722 : generate_template_type(const char *varname,
1484 : const char **dupname,
1485 : const char *symname,
1486 : const char *basetype,
1487 : const char *name,
1488 : Type *type,
1489 : int optional,
1490 : int isstruct,
1491 : int need_offset)
1492 : {
1493 : struct tlist *tl;
1494 : const char *d;
1495 22722 : char *szt = NULL;
1496 22722 : int have_ellipsis = 0;
1497 22722 : int implicit = 0;
1498 : int n;
1499 :
1500 22722 : tl = tlist_new(varname);
1501 :
1502 22722 : if (type->type == TTag && type->tag.tagenv == TE_IMPLICIT) {
1503 378 : Type *t = type->subtype ? type->subtype : type->symbol->type;
1504 :
1505 784 : while (t->type == TType && (t->subtype || t->symbol->type))
1506 28 : t = t->subtype ? t->subtype : t->symbol->type;
1507 378 : if (t->type != TChoice)
1508 364 : implicit = (type->tag.tagenv == TE_IMPLICIT);
1509 : }
1510 :
1511 22722 : template_members(&tl->template, basetype, name, type, optional, 0,
1512 : implicit, isstruct, need_offset);
1513 :
1514 : /* if its a sequence or set type, check if there is a ellipsis */
1515 22722 : if (type->type == TSequence || type->type == TSet) {
1516 : Member *m;
1517 12600 : HEIM_TAILQ_FOREACH(m, type->members, members) {
1518 9940 : if (m->ellipsis)
1519 406 : have_ellipsis = 1;
1520 : }
1521 : }
1522 :
1523 22722 : if (isstruct)
1524 3696 : if (name)
1525 756 : n = asprintf(&szt, "struct %s_%s", basetype, name);
1526 : else
1527 2940 : n = asprintf(&szt, "struct %s", basetype);
1528 : else
1529 19026 : n = asprintf(&szt, "%s", basetype);
1530 22722 : if (n < 0 || szt == NULL)
1531 0 : errx(1, "malloc");
1532 :
1533 22722 : if (HEIM_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull)
1534 0 : errx(1, "Tag %s...%s with no content ?", basetype, name ? name : "");
1535 :
1536 22722 : fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name);
1537 :
1538 22820 : tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)(uintptr_t)%lu) }",
1539 5026 : (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "",
1540 : have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl));
1541 :
1542 22722 : free(szt);
1543 :
1544 : /* XXX Accidentally O(N^2)? */
1545 22722 : d = tlist_find_dup(tl);
1546 22722 : if (d) {
1547 : #if 0
1548 : if (strcmp(d, tl->name) == 0)
1549 : errx(1, "found dup of ourself: %s", d);
1550 : #endif
1551 8722 : *dupname = d;
1552 : } else {
1553 14000 : *dupname = tl->name;
1554 14000 : tlist_print(tl);
1555 14000 : tlist_add(tl);
1556 : }
1557 22722 : }
1558 :
1559 :
1560 : void
1561 5026 : generate_template(const Symbol *s)
1562 : {
1563 5026 : FILE *f = get_code_file();
1564 : const char *dupname;
1565 : struct decoration deco;
1566 5026 : ssize_t more_deco = -1;
1567 :
1568 5026 : if (use_extern(s)) {
1569 0 : gen_extern_stubs(f, s->gen_name);
1570 0 : return;
1571 : }
1572 :
1573 10080 : while (decorate_type(s->gen_name, &deco, &more_deco)) {
1574 28 : if (!deco.ext)
1575 14 : continue;
1576 14 : if (deco.void_star && deco.header_name)
1577 0 : fprintf(f, "#include %s\n", deco.header_name);
1578 42 : fprintf(f,
1579 : "static const struct asn1_type_func asn1_extern_%s_%s = {\n"
1580 : "\t(asn1_type_encode)0,\n"
1581 : "\t(asn1_type_decode)0,\n"
1582 : "\t(asn1_type_length)0,\n"
1583 : "\t(asn1_type_copy)%s,\n"
1584 : "\t(asn1_type_release)%s,\n"
1585 : "\t(asn1_type_print)0,\n"
1586 : "\tsizeof(%s)\n"
1587 : "};\n", s->gen_name, deco.field_name,
1588 14 : deco.copy_function_name && deco.copy_function_name[0] ?
1589 : deco.copy_function_name : "0",
1590 14 : deco.free_function_name && deco.free_function_name[0] ?
1591 : deco.free_function_name : "0",
1592 14 : deco.void_star ? "void *" : deco.field_type);
1593 14 : free(deco.field_type);
1594 : }
1595 :
1596 5026 : generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1);
1597 :
1598 5026 : fprintf(f,
1599 : "\n"
1600 : "int ASN1CALL\n"
1601 : "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n"
1602 : "{\n"
1603 : " memset(data, 0, sizeof(*data));\n"
1604 : " return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n"
1605 : "}\n"
1606 : "\n",
1607 : s->gen_name,
1608 : s->gen_name,
1609 : dupname,
1610 5026 : support_ber ? "A1_PF_ALLOW_BER" : "0");
1611 :
1612 5026 : fprintf(f,
1613 : "\n"
1614 : "int ASN1CALL\n"
1615 : "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n"
1616 : "{\n"
1617 : " return _asn1_encode%s(asn1_%s, p, len, data, size);\n"
1618 : "}\n"
1619 : "\n",
1620 : s->gen_name,
1621 : s->gen_name,
1622 : fuzzer_string,
1623 : dupname);
1624 :
1625 5026 : fprintf(f,
1626 : "\n"
1627 : "size_t ASN1CALL\n"
1628 : "length_%s(const %s *data)\n"
1629 : "{\n"
1630 : " return _asn1_length%s(asn1_%s, data);\n"
1631 : "}\n"
1632 : "\n",
1633 : s->gen_name,
1634 : s->gen_name,
1635 : fuzzer_string,
1636 : dupname);
1637 :
1638 :
1639 5026 : fprintf(f,
1640 : "\n"
1641 : "void ASN1CALL\n"
1642 : "free_%s(%s *data)\n"
1643 : "{\n"
1644 : " _asn1_free_top(asn1_%s, data);\n"
1645 : "}\n"
1646 : "\n",
1647 : s->gen_name,
1648 : s->gen_name,
1649 : dupname);
1650 :
1651 5026 : fprintf(f,
1652 : "\n"
1653 : "int ASN1CALL\n"
1654 : "copy_%s(const %s *from, %s *to)\n"
1655 : "{\n"
1656 : " return _asn1_copy_top(asn1_%s, from, to);\n"
1657 : "}\n"
1658 : "\n",
1659 : s->gen_name,
1660 : s->gen_name,
1661 : s->gen_name,
1662 : dupname);
1663 :
1664 5026 : fprintf(f,
1665 : "\n"
1666 : "char * ASN1CALL\n"
1667 : "print_%s(const %s *data, int flags)\n"
1668 : "{\n"
1669 : " return _asn1_print_top(asn1_%s, flags, data);\n"
1670 : "}\n"
1671 : "\n",
1672 : s->gen_name,
1673 : s->gen_name,
1674 : dupname);
1675 : }
|