LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/asn1 - main.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 192 247 77.7 %
Date: 2024-04-21 15:09:00 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         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             : }

Generated by: LCOV version 1.14