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 : * 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 : #include <getarg.h>
36 : #include "lex.h"
37 :
38 : extern FILE *yyin;
39 :
40 : static getarg_strings preserve;
41 : static getarg_strings seq;
42 : static getarg_strings decorate;
43 :
44 : static int
45 703 : strcmp4mergesort_r(const void *ap, const void *bp, void *d)
46 : {
47 703 : const char *a = *(const char **)ap;
48 703 : const char *b = *(const char **)bp;
49 703 : char sep = *(const char *)d;
50 37 : int cmp;
51 :
52 703 : if (sep) {
53 38 : const char *sepa = strchr(a, sep);
54 38 : const char *sepb = strchr(b, sep);
55 2 : size_t alen, blen;
56 :
57 38 : if (sepa == NULL) sepa = a + strlen(a);
58 38 : if (sepb == NULL) sepb = b + strlen(b);
59 38 : alen = sepa - a;
60 38 : blen = sepb - b;
61 38 : cmp = strncmp(a, b, alen > blen ? alen : blen);
62 38 : if (cmp == 0)
63 19 : cmp = alen - blen;
64 : } else
65 665 : cmp = strcmp(a, b);
66 703 : if (cmp == 0)
67 19 : return (uintptr_t)ap - (uintptr_t)bp; /* stable sort */
68 648 : return cmp;
69 : }
70 :
71 : static int
72 9025 : prefix_check(const char *s, const char *p, size_t plen, char sep, int *cmp)
73 : {
74 8574 : if ((*cmp = strncmp(p, s, plen)) == 0 && s[plen] == sep)
75 288 : return 1;
76 8713 : if (*cmp == 0)
77 152 : *cmp = 1;
78 8262 : return 0;
79 : }
80 :
81 : static ssize_t
82 45201 : bsearch_strings(struct getarg_strings *strs, const char *p,
83 : char sep, ssize_t *more)
84 : {
85 45201 : ssize_t right = (ssize_t)strs->num_strings - 1;
86 45201 : ssize_t left = 0;
87 45201 : ssize_t plen = 0;
88 2379 : int cmp;
89 :
90 45201 : if (sep)
91 22268 : plen = strlen(p);
92 :
93 45201 : if (strs->num_strings == 0)
94 23004 : return -1;
95 :
96 20919 : if (sep && more && *more > -1) {
97 : /* If *more > -1 we're continuing an iteration */
98 304 : if (*more > right)
99 144 : return -1;
100 152 : if (prefix_check(strs->strings[*more], p, plen, sep, &cmp))
101 76 : return (*more)++;
102 76 : (*more)++;
103 76 : return -1;
104 : }
105 :
106 53618 : while (left <= right) {
107 33877 : ssize_t mid = left + (right - left) / 2;
108 :
109 33877 : if (sep) {
110 : int cmp2;
111 :
112 8562 : while (prefix_check(strs->strings[mid], p, plen, sep, &cmp) &&
113 8869 : mid > 0 &&
114 76 : prefix_check(strs->strings[mid - 1], p, plen, sep, &cmp2))
115 0 : mid--;
116 : } else
117 25080 : cmp = strcmp(p, strs->strings[mid]);
118 33877 : if (cmp == 0) {
119 874 : if (more)
120 228 : *more = mid + 1;
121 874 : return mid;
122 : }
123 33003 : if (cmp < 0)
124 17518 : right = mid - 1; /* -1 if `p' is smaller than smallest in strs */
125 : else
126 15485 : left = mid + 1;
127 : }
128 18702 : return -1;
129 : }
130 :
131 : int
132 15162 : preserve_type(const char *p)
133 : {
134 15162 : return bsearch_strings(&preserve, p, '\0', 0) > -1;
135 : }
136 :
137 : int
138 7771 : seq_type(const char *p)
139 : {
140 7771 : return bsearch_strings(&seq, p, '\0', 0) > -1;
141 : }
142 :
143 : /*
144 : * Split `s' on `sep' and fill fs[] with pointers to the substrings.
145 : *
146 : * Only the first substring is to be freed -- the rest share the same
147 : * allocation.
148 : *
149 : * The last element may contain `sep' chars if there are more fields in `s'
150 : * than output locations in `fs[]'.
151 : */
152 : static void
153 304 : split_str(const char *s, char sep, char ***fs)
154 : {
155 16 : size_t i;
156 :
157 304 : fs[0][0] = estrdup(s);
158 1064 : for (i = 1; fs[i]; i++) {
159 56 : char *q;
160 :
161 1064 : if ((q = strchr(fs[i-1][0], sep)) == NULL)
162 288 : break;
163 760 : *(q++) = '\0';
164 760 : fs[i][0] = q;
165 : }
166 1064 : for (; fs[i]; i++)
167 760 : fs[i][0] = NULL;
168 304 : }
169 :
170 : /*
171 : * If `p' is "decorated" with a not-to-be-encoded-or-decoded field,
172 : * output the field's typename and fieldname, whether it's optional, whether
173 : * it's an ASN.1 type or an "external" type, and if external the names of
174 : * functions to copy and free values of that type.
175 : */
176 : int
177 22268 : decorate_type(const char *p, struct decoration *deco, ssize_t *more)
178 : {
179 1172 : ssize_t i;
180 1172 : char **s[7];
181 22268 : char *junk = NULL;
182 1172 : char *cp;
183 :
184 22268 : deco->first = *more == -1;
185 22268 : deco->decorated = 0;
186 22268 : deco->field_type = NULL;
187 22268 : if ((i = bsearch_strings(&decorate, p, ':', more)) == -1)
188 20808 : return 0;
189 :
190 304 : deco->decorated = 1;
191 304 : deco->opt = deco->ext = deco->ptr = 0;
192 304 : deco->void_star = deco->struct_star = 0;
193 304 : deco->field_name = deco->copy_function_name = deco->free_function_name =
194 304 : deco->header_name = NULL;
195 :
196 304 : s[0] = &deco->field_type;
197 304 : s[1] = &deco->field_name;
198 304 : s[2] = &deco->copy_function_name;
199 304 : s[3] = &deco->free_function_name;
200 304 : s[4] = &deco->header_name;
201 304 : s[5] = &junk;
202 304 : s[6] = NULL;
203 304 : split_str(decorate.strings[i] + strlen(p) + 1, ':', s);
204 :
205 304 : if (junk || deco->field_type[0] == '\0' || !deco->field_name ||
206 304 : deco->field_name[0] == '\0' || deco->field_name[0] == '?') {
207 0 : errx(1, "Invalidate type decoration specification: --decorate=\"%s\"",
208 0 : decorate.strings[i]);
209 : }
210 304 : if ((cp = strchr(deco->field_name, '?'))) {
211 152 : deco->opt = 1;
212 152 : *cp = '\0';
213 : }
214 304 : if (strcmp(deco->field_type, "void*") == 0 ||
215 304 : strcmp(deco->field_type, "void *") == 0) {
216 76 : deco->ext = deco->ptr = deco->void_star = 1;
217 76 : deco->opt = 1;
218 76 : deco->header_name = NULL;
219 228 : } else if (strncmp(deco->field_type, "struct ", sizeof("struct ") - 1) == 0 &&
220 0 : deco->field_type[strlen(deco->field_type) - 1] == '*')
221 0 : deco->ptr = deco->struct_star = 1;
222 304 : if (deco->ptr || deco->copy_function_name)
223 228 : deco->ext = 1;
224 304 : if (deco->ext && deco->copy_function_name && !deco->copy_function_name[0])
225 152 : deco->copy_function_name = NULL;
226 304 : if (deco->ext && deco->free_function_name && !deco->free_function_name[0])
227 152 : deco->free_function_name = NULL;
228 304 : if (deco->header_name && !deco->header_name[0])
229 152 : deco->header_name = NULL;
230 304 : if (deco->ptr)
231 76 : deco->opt = 0;
232 288 : return 1;
233 : }
234 :
235 : static const char *
236 0 : my_basename(const char *fn)
237 : {
238 0 : const char *base, *p;
239 :
240 0 : for (p = base = fn; *p; p++) {
241 : #ifdef WIN32
242 : if (*p == '/' || *p == '\\')
243 : base = p + 1;
244 : #else
245 0 : if (*p == '/')
246 0 : base = p + 1;
247 : #endif
248 : }
249 0 : return base;
250 : }
251 :
252 : const char *fuzzer_string = "";
253 : const char *enum_prefix;
254 : const char *name;
255 : int prefix_enum;
256 : int fuzzer_flag;
257 : int support_ber;
258 : int template_flag;
259 : int rfc1510_bitstring;
260 : int one_code_file;
261 : char *option_file;
262 : int parse_units_flag = 1;
263 : char *type_file_string = "krb5-types.h";
264 : int original_order;
265 : int version_flag;
266 : int help_flag;
267 : struct getargs args[] = {
268 : { "fuzzer", 0, arg_flag, &fuzzer_flag, NULL, NULL },
269 : { "template", 0, arg_flag, &template_flag, NULL, NULL },
270 : { "prefix-enum", 0, arg_flag, &prefix_enum,
271 : "prefix C enum labels for ENUMERATED types and INTEGER types with the "
272 : "type's name", NULL },
273 : { "enum-prefix", 0, arg_string, &enum_prefix,
274 : "prefix for C enum labels for ENUMERATED types and INTEGER types with "
275 : "enumerated values", "PREFIX" },
276 : { "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring,
277 : "Use RFC1510 incorrect BIT STRING handling for all BIT STRING types "
278 : "in the module", NULL },
279 : { "decode-dce-ber", 0, arg_flag, &support_ber,
280 : "Allow DCE-style BER on decode", NULL },
281 : { "support-ber", 0, arg_flag, &support_ber, "Allow BER on decode", NULL },
282 : { "preserve-binary", 0, arg_strings, &preserve,
283 : "Names of types for which to generate _save fields, saving original "
284 : "encoding, in containing structures (useful for signature "
285 : "verification)", "TYPE" },
286 : { "sequence", 0, arg_strings, &seq,
287 : "Generate add/remove functions for SEQUENCE OF types", "TYPE" },
288 : { "decorate", 0, arg_strings, &decorate,
289 : "Generate private field for SEQUENCE/SET type", "DECORATION" },
290 : { "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL },
291 : { "gen-name", 0, arg_string, &name,
292 : "Name of generated module", "NAME" },
293 : { "option-file", 0, arg_string, &option_file,
294 : "File with additional compiler CLI options", "FILE" },
295 : { "original-order", 0, arg_flag, &original_order,
296 : "Define C types and functions in the order in which they appear in "
297 : "the ASN.1 module instead of topologically sorting types. This "
298 : "is useful for comparing output to earlier compiler versions.",
299 : NULL },
300 : { "parse-units", 0, arg_negative_flag, &parse_units_flag,
301 : "Do not generate roken-style units", NULL },
302 : { "type-file", 0, arg_string, &type_file_string,
303 : "Name of a C header file to generate includes of for base types",
304 : "FILE" },
305 : { "version", 0, arg_flag, &version_flag, NULL, NULL },
306 : { "help", 0, arg_flag, &help_flag, NULL, NULL }
307 : };
308 : int num_args = sizeof(args) / sizeof(args[0]);
309 :
310 : static void
311 0 : usage(int code)
312 : {
313 0 : if (code)
314 0 : dup2(STDERR_FILENO, STDOUT_FILENO);
315 : else
316 0 : dup2(STDOUT_FILENO, STDERR_FILENO);
317 0 : arg_printusage(args, num_args, NULL, "[asn1-file [name]]");
318 0 : fprintf(stderr,
319 : "\nA DECORATION is one of:\n\n"
320 : "\tTYPE:FTYPE:fname[?]\n"
321 : "\tTYPE:FTYPE:fname[?]:[copy_function]:[free_function]:header\n"
322 : "\tTYPE:void:fname:::\n"
323 : "\nSee the manual page.\n");
324 0 : exit(code);
325 : }
326 :
327 : int error_flag;
328 :
329 : int
330 304 : main(int argc, char **argv)
331 : {
332 16 : int ret;
333 16 : const char *file;
334 304 : FILE *opt = NULL;
335 304 : int optidx = 0;
336 304 : char **arg = NULL;
337 304 : size_t len = 0;
338 304 : size_t sz = 0;
339 16 : int i;
340 :
341 304 : setprogname(argv[0]);
342 304 : if (getarg(args, num_args, argc, argv, &optidx))
343 0 : usage(1);
344 304 : if (help_flag)
345 0 : usage(0);
346 304 : if (version_flag) {
347 0 : print_version(NULL);
348 0 : exit(0);
349 : }
350 304 : if (argc == optidx) {
351 : /* Compile the module on stdin */
352 0 : file = "stdin";
353 0 : name = "stdin";
354 0 : yyin = stdin;
355 : } else {
356 : /* Compile a named module */
357 304 : file = argv[optidx];
358 :
359 : /*
360 : * If the .asn1 stem is not given, then assume it, and also assume
361 : * --option-file was given if the .opt file exists
362 : */
363 304 : if (strchr(file, '.') == NULL) {
364 0 : char *s = NULL;
365 :
366 0 : if (asprintf(&s, "%s.opt", file) == -1 || s == NULL)
367 0 : err(1, "Out of memory");
368 0 : if ((opt = fopen(s, "r")))
369 0 : option_file = s;
370 : else
371 0 : free(s);
372 0 : if (asprintf(&s, "%s.asn1", file) == -1 || s == NULL)
373 0 : err(1, "Out of memory");
374 0 : file = s;
375 : }
376 304 : yyin = fopen (file, "r");
377 304 : if (yyin == NULL)
378 0 : err (1, "open %s", file);
379 304 : if (argc == optidx + 1) {
380 0 : char *p;
381 :
382 : /* C module name substring not given; derive from file name */
383 0 : name = my_basename(estrdup(file));
384 0 : p = strrchr(name, '.');
385 0 : if (p)
386 0 : *p = '\0';
387 : } else
388 304 : name = argv[optidx + 1];
389 : }
390 :
391 : /*
392 : * Parse extra options file
393 : */
394 304 : if (option_file) {
395 5 : char buf[1024];
396 :
397 185 : if (opt == NULL &&
398 95 : (opt = fopen(option_file, "r")) == NULL)
399 0 : err(1, "Could not open given option file %s", option_file);
400 :
401 95 : arg = calloc(2, sizeof(arg[0]));
402 95 : if (arg == NULL) {
403 0 : perror("calloc");
404 0 : exit(1);
405 : }
406 95 : arg[0] = option_file;
407 95 : arg[1] = NULL;
408 95 : len = 1;
409 95 : sz = 2;
410 :
411 703 : while (fgets(buf, sizeof(buf), opt) != NULL) {
412 32 : size_t buflen, ws;
413 :
414 608 : buf[strcspn(buf, "\n\r")] = '\0';
415 :
416 608 : buflen = strlen(buf);
417 608 : if ((ws = strspn(buf, " \t")))
418 0 : memmove(buf, buf + ws, buflen - ws);
419 608 : if (buf[0] == '\0' || buf[0] == '#')
420 57 : continue;
421 :
422 551 : if (len + 1 >= sz) {
423 171 : arg = realloc(arg, (sz + (sz>>1) + 2) * sizeof(arg[0]));
424 171 : if (arg == NULL) {
425 0 : perror("malloc");
426 0 : exit(1);
427 : }
428 162 : sz += (sz>>1) + 2;
429 : }
430 551 : arg[len] = strdup(buf);
431 551 : if (arg[len] == NULL) {
432 0 : perror("strdup");
433 0 : exit(1);
434 : }
435 551 : arg[len + 1] = NULL;
436 551 : len++;
437 : }
438 95 : fclose(opt);
439 :
440 95 : optidx = 0;
441 95 : if(getarg(args, num_args, len, arg, &optidx))
442 0 : usage(1);
443 :
444 95 : if (len != optidx) {
445 0 : fprintf(stderr, "extra args");
446 0 : exit(1);
447 : }
448 : }
449 :
450 304 : if (fuzzer_flag) {
451 0 : if (!template_flag) {
452 0 : printf("can't do fuzzer w/o --template");
453 0 : exit(1);
454 : }
455 : #ifdef ASN1_FUZZER
456 : fuzzer_string = "_fuzzer";
457 : #endif
458 : }
459 :
460 304 : if (preserve.num_strings)
461 76 : mergesort_r(preserve.strings, preserve.num_strings,
462 : sizeof(preserve.strings[0]), strcmp4mergesort_r, "");
463 304 : if (seq.num_strings)
464 95 : mergesort_r(seq.strings, seq.num_strings, sizeof(seq.strings[0]),
465 : strcmp4mergesort_r, "");
466 304 : if (decorate.num_strings)
467 38 : mergesort_r(decorate.strings, decorate.num_strings,
468 : sizeof(decorate.strings[0]), strcmp4mergesort_r, ":");
469 :
470 304 : init_generate(file, name);
471 :
472 304 : if (one_code_file)
473 304 : generate_header_of_codefile(name);
474 :
475 304 : initsym ();
476 304 : ret = yyparse ();
477 304 : if(ret != 0 || error_flag != 0)
478 0 : exit(1);
479 304 : if (!original_order)
480 304 : generate_types();
481 304 : if (argc != optidx)
482 304 : fclose(yyin);
483 :
484 304 : if (one_code_file)
485 304 : close_codefile();
486 304 : close_generate();
487 :
488 304 : if (arg) {
489 646 : for (i = 1; i < len; i++)
490 551 : free(arg[i]);
491 95 : free(arg);
492 : }
493 :
494 304 : return 0;
495 : }
|