2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
4 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
5 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7 * Copyright (c) 2001 Markus Friedl. All rights reserved.
8 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
9 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
48 TAILQ_ENTRY(file) entry;
58 struct file *pushfile(const char *, int);
60 int check_file_secrecy(int, const char *);
63 int yyerror(const char *, ...)
64 __attribute__((__format__ (printf, 1, 2)))
65 __attribute__((__nonnull__ (1)));
66 int kw_cmp(const void *, const void *);
73 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
75 TAILQ_ENTRY(sym) entry;
82 int symset(const char *, const char *, int);
83 char *symget(const char *);
85 void clear_config(struct kd_conf *xconf);
87 static void add_table(const char *, const char *, const char *);
88 static struct table *findtable(const char *name);
89 static void add_cert(const char *, const char *);
90 static void add_key(const char *, const char *);
91 static struct kd_listen_conf *listen_new(void);
93 static uint32_t counter;
94 static struct table *table;
95 static struct kd_listen_conf *listener;
96 static struct kd_conf *conf;
124 %token <v.string> STRING
125 %token <v.number> NUMBER
126 %type <v.number> yesno
127 %type <v.string> string
128 %type <v.table> tableref
132 grammar : /* empty */
133 | grammar include '\n'
137 | grammar listen '\n'
138 | grammar varset '\n'
139 | grammar error '\n' { file->errors++; }
142 include : INCLUDE STRING {
145 if ((nfile = pushfile($2, 0)) == NULL) {
146 yyerror("failed to include file %s", $2);
157 string : string STRING {
158 if (asprintf(&$$, "%s %s", $1, $2) == -1) {
161 yyerror("string: asprintf");
170 yesno : YES { $$ = 1; }
174 optnl : '\n' optnl /* zero or more newlines */
178 nl : '\n' optnl /* one or more newlines */
186 varset : STRING '=' string {
189 printf("%s = \"%s\"\n", $1, $3);
191 if (isspace((unsigned char)*s)) {
192 yyerror("macro name cannot contain "
199 if (symset($1, $3, 0) == -1)
200 fatal("cannot store variable");
206 pki : PKI STRING CERT STRING { add_cert($2, $4); }
207 | PKI STRING KEY STRING { add_key($2, $4); }
210 table_kp : string arrow string optnl {
211 if (table_add(table, $1, $3) == -1)
212 yyerror("can't add to table %s",
220 | table_kp comma table_kps
224 if (table_add(table, $1, NULL) == -1)
225 yyerror("can't add to table %s",
231 string_list : stringel
232 | stringel comma string_list
235 table_vals : table_kps
239 table : TABLE STRING STRING {
242 if ((p = strchr($3, ':')) == NULL) {
243 yyerror("invalid table %s", $2);
248 add_table($2, $3, p+1);
253 add_table($2, "static", NULL);
254 } '{' optnl table_vals '}' {
259 tableref : '<' STRING '>' {
270 listen : LISTEN { listener = listen_new(); }
272 if (listener->auth_table == NULL)
273 yyerror("missing auth table");
274 if (!(listener->flags & L_TLS))
275 yyerror("can't define a non-tls listener");
280 listen_opts : listen_opt
281 | listen_opt listen_opts
284 listen_opt : ON STRING PORT NUMBER {
285 if (*listener->iface != '\0')
286 yyerror("listen address and port already"
288 strlcpy(listener->iface, $2, sizeof(listener->iface));
292 if (*listener->pki != '\0')
293 yyerror("listen tls pki already defined");
294 listener->flags |= L_TLS;
295 strlcpy(listener->pki, $3, sizeof(listener->pki));
298 if (listener->auth_table != NULL)
299 yyerror("listen auth already defined");
300 listener->auth_table = $2;
302 | USERDATA tableref {
303 if (listener->userdata_table != NULL)
304 yyerror("userdata table already defined");
305 listener->userdata_table = $2;
308 if (listener->virtual_table != NULL)
309 yyerror("virtual table already defined");
310 listener->virtual_table = $2;
322 yyerror(const char *fmt, ...)
329 if (vasprintf(&msg, fmt, ap) == -1)
330 fatalx("yyerror vasprintf");
332 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
338 kw_cmp(const void *k, const void *e)
340 return strcmp(k, ((const struct keywords *)e)->k_name);
346 /* This has to be sorted always. */
347 static const struct keywords keywords[] = {
350 {"include", INCLUDE},
359 {"userdata", USERDATA},
360 {"virtual", VIRTUAL},
363 const struct keywords *p;
365 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
366 sizeof(keywords[0]), kw_cmp);
374 #define START_EXPAND 1
375 #define DONE_EXPAND 2
377 static int expanding;
385 if (file->ungetpos > 0)
386 c = file->ungetbuf[--file->ungetpos];
388 c = getc(file->stream);
390 if (c == START_EXPAND)
392 else if (c == DONE_EXPAND)
406 if ((c = igetc()) == EOF) {
407 yyerror("reached end of file while parsing "
409 if (file == topfile || popfile() == EOF)
416 while ((c = igetc()) == '\\') {
422 yylval.lineno = file->lineno;
428 * Fake EOL when hit EOF for the first time. This gets line
429 * count right if last line in included file is syntactically
430 * invalid and has no newline.
432 if (file->eof_reached == 0) {
433 file->eof_reached = 1;
437 if (file == topfile || popfile() == EOF)
451 if (file->ungetpos >= file->ungetsize) {
452 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
456 file->ungetsize *= 2;
458 file->ungetbuf[file->ungetpos++] = c;
466 /* Skip to either EOF or the first real EOL. */
487 switch (x = my_yylex()) {
528 printf("string \"%s\"\n", yylval.v.string);
531 printf("number %"PRIi64"\n", yylval.v.number);
533 printf("character ");
538 printf(" [0x%x]", x);
560 while ((c = lgetc(0)) == ' ' || c == '\t')
563 yylval.lineno = file->lineno;
565 while ((c = lgetc(0)) != '\n' && c != EOF)
567 if (c == '$' && !expanding) {
569 if ((c = lgetc(0)) == EOF)
572 if (p + 1 >= buf + sizeof(buf) - 1) {
573 yyerror("string too long");
576 if (isalnum(c) || c == '_') {
586 yyerror("macro '%s' not defined", buf);
589 p = val + strlen(val) - 1;
590 lungetc(DONE_EXPAND);
592 lungetc((unsigned char)*p);
595 lungetc(START_EXPAND);
604 if ((c = lgetc(quotec)) == EOF)
609 } else if (c == '\\') {
610 if ((next = lgetc(quotec)) == EOF)
612 if (next == quotec || next == ' ' ||
615 else if (next == '\n') {
620 } else if (c == quotec) {
623 } else if (c == '\0') {
624 yyerror("syntax error");
627 if (p + 1 >= buf + sizeof(buf) - 1) {
628 yyerror("string too long");
633 yylval.v.string = strdup(buf);
634 if (yylval.v.string == NULL)
635 err(1, "yylex: strdup");
639 #define allowed_to_end_number(x) \
640 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
642 if (c == '-' || isdigit(c)) {
645 if ((size_t)(p-buf) >= sizeof(buf)) {
646 yyerror("string too long");
649 } while ((c = lgetc(0)) != EOF && isdigit(c));
651 if (p == buf + 1 && buf[0] == '-')
653 if (c == EOF || allowed_to_end_number(c)) {
654 const char *errstr = NULL;
657 yylval.v.number = strtonum(buf, LLONG_MIN,
660 yyerror("\"%s\" invalid number: %s",
668 lungetc((unsigned char)*--p);
669 c = (unsigned char)*--p;
675 #define allowed_in_string(x) \
676 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
677 x != '{' && x != '}' && \
678 x != '!' && x != '=' && x != '#' && \
679 x != ',' && x != '>'))
681 if (isalnum(c) || c == ':' || c == '_') {
684 if ((size_t)(p-buf) >= sizeof(buf)) {
685 yyerror("string too long");
688 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
691 if ((token = lookup(buf)) == STRING)
692 if ((yylval.v.string = strdup(buf)) == NULL)
693 err(1, "yylex: strdup");
697 yylval.lineno = file->lineno;
706 check_file_secrecy(int fd, const char *fname)
710 if (fstat(fd, &st)) {
711 log_warn("cannot stat %s", fname);
714 if (st.st_uid != 0 && st.st_uid != getuid()) {
715 log_warnx("%s: owner not root or current user", fname);
718 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
719 log_warnx("%s: group writable or world read/writable", fname);
726 pushfile(const char *name, int secret)
730 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
734 if ((nfile->name = strdup(name)) == NULL) {
739 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
740 log_warn("%s", nfile->name);
745 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
746 fclose(nfile->stream);
751 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
752 nfile->ungetsize = 16;
753 nfile->ungetbuf = malloc(nfile->ungetsize);
754 if (nfile->ungetbuf == NULL) {
756 fclose(nfile->stream);
761 TAILQ_INSERT_TAIL(&files, nfile, entry);
770 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
771 prev->errors += file->errors;
773 TAILQ_REMOVE(&files, file, entry);
774 fclose(file->stream);
776 free(file->ungetbuf);
779 return file ? 0 : EOF;
783 parse_config(const char *filename)
785 struct sym *sym, *next;
788 conf = config_new_empty();
790 file = pushfile(filename, 0);
798 errors = file->errors;
801 /* Free macros and check which have not been used. */
802 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
803 if (verbose && !sym->used)
804 fprintf(stderr, "warning: macro '%s' not used\n",
809 TAILQ_REMOVE(&symhead, sym, entry);
823 symset(const char *nam, const char *val, int persist)
827 TAILQ_FOREACH(sym, &symhead, entry) {
828 if (strcmp(nam, sym->nam) == 0)
833 if (sym->persist == 1)
838 TAILQ_REMOVE(&symhead, sym, entry);
842 if ((sym = calloc(1, sizeof(*sym))) == NULL)
845 sym->nam = strdup(nam);
846 if (sym->nam == NULL) {
850 sym->val = strdup(val);
851 if (sym->val == NULL) {
857 sym->persist = persist;
858 TAILQ_INSERT_TAIL(&symhead, sym, entry);
863 cmdline_symset(char *s)
868 if ((val = strrchr(s, '=')) == NULL)
870 sym = strndup(s, val - s);
872 errx(1, "%s: strndup", __func__);
873 ret = symset(sym, val + 1, 1);
880 symget(const char *nam)
884 TAILQ_FOREACH(sym, &symhead, entry) {
885 if (strcmp(nam, sym->nam) == 0) {
894 clear_config(struct kd_conf *xconf)
896 struct kd_pki_conf *p;
897 struct kd_tables_conf *t;
898 struct kd_listen_conf *l;
903 while (!STAILQ_EMPTY(&xconf->pki_head)) {
904 p = STAILQ_FIRST(&xconf->pki_head);
905 STAILQ_REMOVE_HEAD(&xconf->pki_head, entry);
908 tls_unload_file(p->cert, p->certlen);
910 tls_unload_file(p->key, p->keylen);
911 if (p->tlsconf != NULL)
912 tls_config_free(p->tlsconf);
916 while (!STAILQ_EMPTY(&xconf->table_head)) {
917 t = STAILQ_FIRST(&xconf->table_head);
918 STAILQ_REMOVE_HEAD(&xconf->table_head, entry);
920 table_close(t->table);
925 while (!STAILQ_EMPTY(&xconf->listen_head)) {
926 l = STAILQ_FIRST(&xconf->listen_head);
927 STAILQ_REMOVE_HEAD(&xconf->listen_head, entry);
943 add_table(const char *name, const char *type, const char *path)
945 if (table_open(conf, name, type, path) == -1)
946 yyerror("can't initialize table %s", name);
947 table = STAILQ_FIRST(&conf->table_head)->table;
950 static struct table *
951 findtable(const char *name)
953 struct kd_tables_conf *i;
955 STAILQ_FOREACH(i, &conf->table_head, entry) {
956 if (!strcmp(i->table->t_name, name))
960 yyerror("unknown table %s", name);
965 add_cert(const char *name, const char *path)
967 struct kd_pki_conf *pki;
969 STAILQ_FOREACH(pki, &conf->pki_head, entry) {
970 if (strcmp(name, pki->name) != 0)
973 if (pki->cert != NULL) {
974 yyerror("duplicate `pki %s cert'", name);
981 pki = xcalloc(1, sizeof(*pki));
982 strlcpy(pki->name, name, sizeof(pki->name));
983 STAILQ_INSERT_HEAD(&conf->pki_head, pki, entry);
986 if ((pki->cert = tls_load_file(path, &pki->certlen, NULL)) == NULL)
987 fatal("can't open %s", path);
991 add_key(const char *name, const char *path)
993 struct kd_pki_conf *pki;
995 STAILQ_FOREACH(pki, &conf->pki_head, entry) {
996 if (strcmp(name, pki->name) != 0)
999 if (pki->key != NULL) {
1000 yyerror("duplicate `pki %s key'", name);
1007 pki = xcalloc(1, sizeof(*pki));
1008 strlcpy(pki->name, name, sizeof(pki->name));
1009 STAILQ_INSERT_HEAD(&conf->pki_head, pki, entry);
1012 if ((pki->key = tls_load_file(path, &pki->keylen, NULL)) == NULL)
1013 fatal("can't open %s", path);
1016 static struct kd_listen_conf *
1019 struct kd_listen_conf *l;
1021 l = xcalloc(1, sizeof(*l));
1025 STAILQ_INSERT_HEAD(&conf->listen_head, l, entry);