LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/asn1 - main.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 172 227 75.8 %
Date: 2024-06-13 04:01:37 Functions: 8 10 80.0 %

          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         504 : strcmp4mergesort_r(const void *ap, const void *bp, void *d)
      46             : {
      47         504 :     const char *a = *(const char **)ap;
      48         504 :     const char *b = *(const char **)bp;
      49         504 :     char sep = *(const char *)d;
      50             :     int cmp;
      51             : 
      52         504 :     if (sep) {
      53          14 :         const char *sepa = strchr(a, sep);
      54          14 :         const char *sepb = strchr(b, sep);
      55             :         size_t alen, blen;
      56             : 
      57          14 :         if (sepa == NULL) sepa = a + strlen(a);
      58          14 :         if (sepb == NULL) sepb = b + strlen(b);
      59          14 :         alen = sepa - a;
      60          14 :         blen = sepb - b;
      61          14 :         cmp = strncmp(a, b, alen > blen ? alen : blen);
      62          14 :         if (cmp == 0)
      63           0 :             cmp = alen - blen;
      64             :     } else
      65         490 :         cmp = strcmp(a, b);
      66         504 :     if (cmp == 0)
      67           0 :         return (uintptr_t)ap - (uintptr_t)bp; /* stable sort */
      68         504 :     return cmp;
      69             : }
      70             : 
      71             : static int
      72        6090 : prefix_check(const char *s, const char *p, size_t plen, char sep, int *cmp)
      73             : {
      74        6090 :     if ((*cmp = strncmp(p, s, plen)) == 0 && s[plen] == sep)
      75         168 :         return 1;
      76        5922 :     if (*cmp == 0)
      77         112 :         *cmp = 1;
      78        5922 :     return 0;
      79             : }
      80             : 
      81             : static ssize_t
      82       33572 : bsearch_strings(struct getarg_strings *strs, const char *p,
      83             :                 char sep, ssize_t *more)
      84             : {
      85       33572 :     ssize_t right = (ssize_t)strs->num_strings - 1;
      86       33572 :     ssize_t left = 0;
      87       33572 :     ssize_t plen = 0;
      88             :     int cmp;
      89             : 
      90       33572 :     if (sep)
      91       16282 :         plen = strlen(p);
      92             : 
      93       33572 :     if (strs->num_strings == 0)
      94       18074 :         return -1;
      95             : 
      96       15498 :     if (sep && more && *more > -1) {
      97             :         /* If *more > -1 we're continuing an iteration */
      98         168 :         if (*more > right)
      99         112 :             return -1;
     100          56 :         if (prefix_check(strs->strings[*more], p, plen, sep, &cmp))
     101           0 :             return (*more)++;
     102          56 :         (*more)++;
     103          56 :         return -1;
     104             :     }
     105             : 
     106       54782 :     while (left <= right) {
     107       24766 :         ssize_t mid = left + (right - left) / 2;
     108             : 
     109       24766 :         if (sep) {
     110             :             int cmp2;
     111             : 
     112       11956 :             while (prefix_check(strs->strings[mid], p, plen, sep, &cmp) &&
     113          56 :                    mid > 0 &&
     114          56 :                    prefix_check(strs->strings[mid - 1], p, plen, sep, &cmp2))
     115           0 :                 mid--;
     116             :         } else
     117       18788 :             cmp = strcmp(p, strs->strings[mid]);
     118       24766 :         if (cmp == 0) {
     119         644 :             if (more)
     120         168 :                 *more = mid + 1;
     121         644 :             return mid;
     122             :         }
     123       24122 :         if (cmp < 0)
     124       12978 :             right = mid - 1; /* -1 if `p' is smaller than smallest in strs */
     125             :         else
     126       11144 :             left = mid + 1;
     127             :     }
     128       14686 :     return -1;
     129             : }
     130             : 
     131             : int
     132       11592 : preserve_type(const char *p)
     133             : {
     134       11592 :     return bsearch_strings(&preserve, p, '\0', 0) > -1;
     135             : }
     136             : 
     137             : int
     138        5698 : seq_type(const char *p)
     139             : {
     140        5698 :     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         168 : split_str(const char *s, char sep, char ***fs)
     154             : {
     155             :     size_t i;
     156             : 
     157         168 :     fs[0][0] = estrdup(s);
     158         504 :     for (i = 1; fs[i]; i++) {
     159             :         char *q;
     160             : 
     161         504 :         if ((q = strchr(fs[i-1][0], sep)) == NULL)
     162         168 :             break;
     163         336 :         *(q++) = '\0';
     164         336 :         fs[i][0] = q;
     165             :     }
     166         672 :     for (; fs[i]; i++)
     167         504 :         fs[i][0] = NULL;
     168         168 : }
     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       16282 : decorate_type(const char *p, struct decoration *deco, ssize_t *more)
     178             : {
     179             :     ssize_t i;
     180             :     char **s[7];
     181       16282 :     char *junk = NULL;
     182             :     char *cp;
     183             : 
     184       16282 :     deco->first = *more == -1;
     185       16282 :     deco->decorated = 0;
     186       16282 :     deco->field_type = NULL;
     187       16282 :     if ((i = bsearch_strings(&decorate, p, ':', more)) == -1)
     188       16114 :         return 0;
     189             : 
     190         168 :     deco->decorated = 1;
     191         168 :     deco->opt = deco->ext = deco->ptr = 0;
     192         168 :     deco->void_star = deco->struct_star = 0;
     193         168 :     deco->field_name = deco->copy_function_name = deco->free_function_name =
     194         168 :         deco->header_name = NULL;
     195             : 
     196         168 :     s[0] = &deco->field_type;
     197         168 :     s[1] = &deco->field_name;
     198         168 :     s[2] = &deco->copy_function_name;
     199         168 :     s[3] = &deco->free_function_name;
     200         168 :     s[4] = &deco->header_name;
     201         168 :     s[5] = &junk;
     202         168 :     s[6] = NULL;
     203         168 :     split_str(decorate.strings[i] + strlen(p) + 1, ':', s);
     204             : 
     205         336 :     if (junk || deco->field_type[0] == '\0' || !deco->field_name ||
     206         336 :         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         168 :     if ((cp = strchr(deco->field_name, '?'))) {
     211         112 :         deco->opt = 1;
     212         112 :         *cp = '\0';
     213             :     }
     214         336 :     if (strcmp(deco->field_type, "void*") == 0 ||
     215         168 :         strcmp(deco->field_type, "void *") == 0) {
     216          56 :         deco->ext = deco->ptr = deco->void_star = 1;
     217          56 :         deco->opt = 1;
     218          56 :         deco->header_name = NULL;
     219         112 :     } 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         168 :     if (deco->ptr || deco->copy_function_name)
     223         112 :         deco->ext = 1;
     224         168 :     if (deco->ext && deco->copy_function_name && !deco->copy_function_name[0])
     225          56 :         deco->copy_function_name = NULL;
     226         168 :     if (deco->ext && deco->free_function_name && !deco->free_function_name[0])
     227          56 :         deco->free_function_name = NULL;
     228         168 :     if (deco->header_name && !deco->header_name[0])
     229          56 :         deco->header_name = NULL;
     230         168 :     if (deco->ptr)
     231          56 :         deco->opt = 0;
     232         168 :     return 1;
     233             : }
     234             : 
     235             : static const char *
     236           0 : my_basename(const char *fn)
     237             : {
     238             :     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         224 : main(int argc, char **argv)
     331             : {
     332             :     int ret;
     333             :     const char *file;
     334         224 :     FILE *opt = NULL;
     335         224 :     int optidx = 0;
     336         224 :     char **arg = NULL;
     337         224 :     size_t len = 0;
     338         224 :     size_t sz = 0;
     339             :     int i;
     340             : 
     341         224 :     setprogname(argv[0]);
     342         224 :     if (getarg(args, num_args, argc, argv, &optidx))
     343           0 :         usage(1);
     344         224 :     if (help_flag)
     345           0 :         usage(0);
     346         224 :     if (version_flag) {
     347           0 :         print_version(NULL);
     348           0 :         exit(0);
     349             :     }
     350         224 :     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         224 :         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         224 :         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         224 :         yyin = fopen (file, "r");
     377         224 :         if (yyin == NULL)
     378           0 :             err (1, "open %s", file);
     379         224 :         if (argc == optidx + 1) {
     380             :             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         224 :             name = argv[optidx + 1];
     389             :     }
     390             : 
     391             :     /*
     392             :      * Parse extra options file
     393             :      */
     394         224 :     if (option_file) {
     395             :         char buf[1024];
     396             : 
     397         140 :         if (opt == NULL &&
     398          70 :             (opt = fopen(option_file, "r")) == NULL)
     399           0 :             err(1, "Could not open given option file %s", option_file);
     400             : 
     401          70 :         arg = calloc(2, sizeof(arg[0]));
     402          70 :         if (arg == NULL) {
     403           0 :             perror("calloc");
     404           0 :             exit(1);
     405             :         }
     406          70 :         arg[0] = option_file;
     407          70 :         arg[1] = NULL;
     408          70 :         len = 1;
     409          70 :         sz = 2;
     410             : 
     411         532 :         while (fgets(buf, sizeof(buf), opt) != NULL) {
     412         392 :             buf[strcspn(buf, "\n\r")] = '\0';
     413             : 
     414         392 :             if (len + 1 >= sz) {
     415         126 :                 arg = realloc(arg, (sz + (sz>>1) + 2) * sizeof(arg[0]));
     416         126 :                 if (arg == NULL) {
     417           0 :                     perror("malloc");
     418           0 :                     exit(1);
     419             :                 }
     420         126 :                 sz += (sz>>1) + 2;
     421             :             }
     422         392 :             arg[len] = strdup(buf);
     423         392 :             if (arg[len] == NULL) {
     424           0 :                 perror("strdup");
     425           0 :                 exit(1);
     426             :             }
     427         392 :             arg[len + 1] = NULL;
     428         392 :             len++;
     429             :         }
     430          70 :         fclose(opt);
     431             : 
     432          70 :         optidx = 0;
     433          70 :         if(getarg(args, num_args, len, arg, &optidx))
     434           0 :             usage(1);
     435             : 
     436          70 :         if (len != optidx) {
     437           0 :             fprintf(stderr, "extra args");
     438           0 :             exit(1);
     439             :         }
     440             :     }
     441             : 
     442         224 :     if (fuzzer_flag) {
     443           0 :         if (!template_flag) {
     444           0 :             printf("can't do fuzzer w/o --template");
     445           0 :             exit(1);
     446             :         }
     447             : #ifdef ASN1_FUZZER
     448             :         fuzzer_string = "_fuzzer";
     449             : #endif
     450             :     }
     451             : 
     452         224 :     if (preserve.num_strings)
     453          56 :         mergesort_r(preserve.strings, preserve.num_strings,
     454             :                     sizeof(preserve.strings[0]), strcmp4mergesort_r, "");
     455         224 :     if (seq.num_strings)
     456          70 :         mergesort_r(seq.strings, seq.num_strings, sizeof(seq.strings[0]),
     457             :                     strcmp4mergesort_r, "");
     458         224 :     if (decorate.num_strings)
     459          28 :         mergesort_r(decorate.strings, decorate.num_strings,
     460             :                     sizeof(decorate.strings[0]), strcmp4mergesort_r, ":");
     461             : 
     462         224 :     init_generate(file, name);
     463             : 
     464         224 :     if (one_code_file)
     465         224 :         generate_header_of_codefile(name);
     466             : 
     467         224 :     initsym ();
     468         224 :     ret = yyparse ();
     469         224 :     if(ret != 0 || error_flag != 0)
     470           0 :         exit(1);
     471         224 :     if (!original_order)
     472         224 :         generate_types();
     473         224 :     if (argc != optidx)
     474         224 :         fclose(yyin);
     475             : 
     476         224 :     if (one_code_file)
     477         224 :         close_codefile();
     478         224 :     close_generate();
     479             : 
     480         224 :     if (arg) {
     481         462 :         for (i = 1; i < len; i++)
     482         392 :             free(arg[i]);
     483          70 :         free(arg);
     484             :     }
     485             : 
     486         224 :     return 0;
     487             : }

Generated by: LCOV version 1.13