1*4a50067cSflorian /* $OpenBSD: parse.y,v 1.45 2022/12/15 08:06:13 florian Exp $ */
23943d840Sbenno
33943d840Sbenno /*
43943d840Sbenno * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
53943d840Sbenno * Copyright (c) 2016 Sebastian Benoit <benno@openbsd.org>
63943d840Sbenno * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
73943d840Sbenno * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
83943d840Sbenno * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
93943d840Sbenno * Copyright (c) 2001 Markus Friedl. All rights reserved.
103943d840Sbenno * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
113943d840Sbenno * Copyright (c) 2001 Theo de Raadt. All rights reserved.
123943d840Sbenno *
133943d840Sbenno * Permission to use, copy, modify, and distribute this software for any
143943d840Sbenno * purpose with or without fee is hereby granted, provided that the above
153943d840Sbenno * copyright notice and this permission notice appear in all copies.
163943d840Sbenno *
173943d840Sbenno * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
183943d840Sbenno * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
193943d840Sbenno * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
203943d840Sbenno * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
213943d840Sbenno * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
223943d840Sbenno * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
233943d840Sbenno * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
243943d840Sbenno */
253943d840Sbenno
263943d840Sbenno %{
27f9e1cc5fSbenno #include <sys/types.h>
28f9e1cc5fSbenno #include <sys/queue.h>
29f9e1cc5fSbenno #include <sys/stat.h>
303943d840Sbenno #include <ctype.h>
313943d840Sbenno #include <err.h>
322570ecd0Sflorian #include <errno.h>
333943d840Sbenno #include <limits.h>
343943d840Sbenno #include <stdarg.h>
353943d840Sbenno #include <stdio.h>
363943d840Sbenno #include <stdlib.h>
373943d840Sbenno #include <string.h>
383943d840Sbenno #include <unistd.h>
393943d840Sbenno
403943d840Sbenno #include "parse.h"
413e86e78bSgilles #include "extern.h"
423943d840Sbenno
433943d840Sbenno TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
443943d840Sbenno static struct file {
453943d840Sbenno TAILQ_ENTRY(file) entry;
463943d840Sbenno FILE *stream;
473943d840Sbenno char *name;
48f3e9965dSdenis size_t ungetpos;
49f3e9965dSdenis size_t ungetsize;
50f3e9965dSdenis u_char *ungetbuf;
51f3e9965dSdenis int eof_reached;
523943d840Sbenno int lineno;
533943d840Sbenno int errors;
543943d840Sbenno } *file, *topfile;
553943d840Sbenno struct file *pushfile(const char *);
563943d840Sbenno int popfile(void);
573943d840Sbenno int yyparse(void);
583943d840Sbenno int yylex(void);
593943d840Sbenno int yyerror(const char *, ...)
603943d840Sbenno __attribute__((__format__ (printf, 1, 2)))
613943d840Sbenno __attribute__((__nonnull__ (1)));
623943d840Sbenno int kw_cmp(const void *, const void *);
633943d840Sbenno int lookup(char *);
64f3e9965dSdenis int igetc(void);
653943d840Sbenno int lgetc(int);
66f3e9965dSdenis void lungetc(int);
673943d840Sbenno int findeol(void);
683943d840Sbenno
693943d840Sbenno struct authority_c *conf_new_authority(struct acme_conf *, char *);
703943d840Sbenno struct domain_c *conf_new_domain(struct acme_conf *, char *);
713943d840Sbenno struct keyfile *conf_new_keyfile(struct acme_conf *, char *);
723298b855Sbenno void clear_config(struct acme_conf *);
73bc812290Sflorian const char* kt2txt(enum keytype);
743298b855Sbenno void print_config(struct acme_conf *);
752570ecd0Sflorian int conf_check_file(char *);
763943d840Sbenno
773943d840Sbenno TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
783943d840Sbenno struct sym {
793943d840Sbenno TAILQ_ENTRY(sym) entry;
803943d840Sbenno int used;
813943d840Sbenno int persist;
823943d840Sbenno char *nam;
833943d840Sbenno char *val;
843943d840Sbenno };
853943d840Sbenno int symset(const char *, const char *, int);
863943d840Sbenno char *symget(const char *);
873943d840Sbenno
883943d840Sbenno static struct acme_conf *conf;
893943d840Sbenno static struct authority_c *auth;
903943d840Sbenno static struct domain_c *domain;
913943d840Sbenno static int errors = 0;
923943d840Sbenno
933943d840Sbenno typedef struct {
943943d840Sbenno union {
953943d840Sbenno int64_t number;
963943d840Sbenno char *string;
973943d840Sbenno } v;
983943d840Sbenno int lineno;
993943d840Sbenno } YYSTYPE;
1003943d840Sbenno
1013943d840Sbenno %}
1023943d840Sbenno
1036736ff2bSflorian %token AUTHORITY URL API ACCOUNT CONTACT
104d0ea1cfcSsthen %token DOMAIN ALTERNATIVE NAME NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
1053943d840Sbenno %token YES NO
1063943d840Sbenno %token INCLUDE
1073943d840Sbenno %token ERROR
1083e86e78bSgilles %token RSA ECDSA
1093943d840Sbenno %token <v.string> STRING
1103943d840Sbenno %token <v.number> NUMBER
1113943d840Sbenno %type <v.string> string
11265a104faSflorian %type <v.number> keytype
1133943d840Sbenno
1143943d840Sbenno %%
1153943d840Sbenno
1163943d840Sbenno grammar : /* empty */
1173943d840Sbenno | grammar include '\n'
1183943d840Sbenno | grammar varset '\n'
1193943d840Sbenno | grammar '\n'
1203943d840Sbenno | grammar authority '\n'
1213943d840Sbenno | grammar domain '\n'
1223943d840Sbenno | grammar error '\n' { file->errors++; }
1233943d840Sbenno ;
1243943d840Sbenno
1253943d840Sbenno include : INCLUDE STRING {
1263943d840Sbenno struct file *nfile;
1273943d840Sbenno
1283943d840Sbenno if ((nfile = pushfile($2)) == NULL) {
1293943d840Sbenno yyerror("failed to include file %s", $2);
1303943d840Sbenno free($2);
1313943d840Sbenno YYERROR;
1323943d840Sbenno }
1333943d840Sbenno free($2);
1343943d840Sbenno
1353943d840Sbenno file = nfile;
1363943d840Sbenno lungetc('\n');
1373943d840Sbenno }
1383943d840Sbenno ;
1393943d840Sbenno
1403943d840Sbenno string : string STRING {
1413943d840Sbenno if (asprintf(&$$, "%s %s", $1, $2) == -1) {
1423943d840Sbenno free($1);
1433943d840Sbenno free($2);
1443943d840Sbenno yyerror("string: asprintf");
1453943d840Sbenno YYERROR;
1463943d840Sbenno }
1473943d840Sbenno free($1);
1483943d840Sbenno free($2);
1493943d840Sbenno }
1503943d840Sbenno | STRING
1513943d840Sbenno ;
1523943d840Sbenno
1533943d840Sbenno varset : STRING '=' string {
1543943d840Sbenno char *s = $1;
1553943d840Sbenno if (conf->opts & ACME_OPT_VERBOSE)
1563943d840Sbenno printf("%s = \"%s\"\n", $1, $3);
1573943d840Sbenno while (*s++) {
1583943d840Sbenno if (isspace((unsigned char)*s)) {
1593943d840Sbenno yyerror("macro name cannot contain "
1603943d840Sbenno "whitespace");
16116a0a906Skrw free($1);
16216a0a906Skrw free($3);
1633943d840Sbenno YYERROR;
1643943d840Sbenno }
1653943d840Sbenno }
1663943d840Sbenno if (symset($1, $3, 0) == -1)
1673943d840Sbenno errx(EXIT_FAILURE, "cannot store variable");
1683943d840Sbenno free($1);
1693943d840Sbenno free($3);
1703943d840Sbenno }
1713943d840Sbenno ;
1723943d840Sbenno
1733943d840Sbenno optnl : '\n' optnl
1743943d840Sbenno |
1753943d840Sbenno ;
1763943d840Sbenno
1773943d840Sbenno nl : '\n' optnl /* one newline or more */
1783943d840Sbenno ;
1793943d840Sbenno
180e6cfdc77Sop optcommanl : ',' optnl
181e6cfdc77Sop | optnl
1823943d840Sbenno ;
1833943d840Sbenno
1843943d840Sbenno authority : AUTHORITY STRING {
1853943d840Sbenno char *s;
1863943d840Sbenno if ((s = strdup($2)) == NULL)
1873943d840Sbenno err(EXIT_FAILURE, "strdup");
1883943d840Sbenno if ((auth = conf_new_authority(conf, s)) == NULL) {
1893943d840Sbenno free(s);
1903943d840Sbenno yyerror("authority already defined");
1913943d840Sbenno YYERROR;
1923943d840Sbenno }
1933943d840Sbenno } '{' optnl authorityopts_l '}' {
1941e4d2958Sbenno if (auth->api == NULL) {
1951e4d2958Sbenno yyerror("authority %s: no api URL specified",
1961e4d2958Sbenno auth->name);
1971e4d2958Sbenno YYERROR;
1981e4d2958Sbenno }
1991e4d2958Sbenno if (auth->account == NULL) {
2001e4d2958Sbenno yyerror("authority %s: no account key file "
2011e4d2958Sbenno "specified", auth->name);
2021e4d2958Sbenno YYERROR;
2031e4d2958Sbenno }
2043943d840Sbenno auth = NULL;
2053943d840Sbenno }
2063943d840Sbenno ;
2073943d840Sbenno
2083943d840Sbenno authorityopts_l : authorityopts_l authorityoptsl nl
2093943d840Sbenno | authorityoptsl optnl
2103943d840Sbenno ;
2113943d840Sbenno
212179fe9a6Sflorian authorityoptsl : API URL STRING {
2133943d840Sbenno char *s;
2143943d840Sbenno if (auth->api != NULL) {
2153943d840Sbenno yyerror("duplicate api");
2163943d840Sbenno YYERROR;
2173943d840Sbenno }
2183943d840Sbenno if ((s = strdup($3)) == NULL)
2193943d840Sbenno err(EXIT_FAILURE, "strdup");
2203943d840Sbenno auth->api = s;
2213943d840Sbenno }
2224f8b772fSflorian | ACCOUNT KEY STRING keytype{
2233943d840Sbenno char *s;
2243943d840Sbenno if (auth->account != NULL) {
2253943d840Sbenno yyerror("duplicate account");
2263943d840Sbenno YYERROR;
2273943d840Sbenno }
2283943d840Sbenno if ((s = strdup($3)) == NULL)
2293943d840Sbenno err(EXIT_FAILURE, "strdup");
2303943d840Sbenno auth->account = s;
2314f8b772fSflorian auth->keytype = $4;
2323943d840Sbenno }
2336736ff2bSflorian | CONTACT STRING {
2346736ff2bSflorian char *s;
2356736ff2bSflorian if (auth->contact != NULL) {
2366736ff2bSflorian yyerror("duplicate contact");
2376736ff2bSflorian YYERROR;
2386736ff2bSflorian }
2396736ff2bSflorian if ((s = strdup($2)) == NULL)
2406736ff2bSflorian err(EXIT_FAILURE, "strdup");
2416736ff2bSflorian auth->contact = s;
2426736ff2bSflorian }
2433943d840Sbenno ;
2443943d840Sbenno
2453943d840Sbenno domain : DOMAIN STRING {
2463943d840Sbenno char *s;
2473943d840Sbenno if ((s = strdup($2)) == NULL)
2483943d840Sbenno err(EXIT_FAILURE, "strdup");
2493943d840Sbenno if (!domain_valid(s)) {
2503943d840Sbenno yyerror("%s: bad domain syntax", s);
2519d58ffeeSjsg free(s);
2523943d840Sbenno YYERROR;
2533943d840Sbenno }
2543943d840Sbenno if ((domain = conf_new_domain(conf, s)) == NULL) {
2553943d840Sbenno free(s);
2563943d840Sbenno yyerror("domain already defined");
2573943d840Sbenno YYERROR;
2583943d840Sbenno }
2593943d840Sbenno } '{' optnl domainopts_l '}' {
26087f5451dSbenno if (domain->domain == NULL) {
26187f5451dSbenno if ((domain->domain = strdup(domain->handle))
26287f5451dSbenno == NULL)
26387f5451dSbenno err(EXIT_FAILURE, "strdup");
26487f5451dSbenno }
2651b6b7d02Sflorian /* enforce minimum config here */
2661b6b7d02Sflorian if (domain->key == NULL) {
2671b6b7d02Sflorian yyerror("no domain key file specified for "
2681b6b7d02Sflorian "domain %s", domain->domain);
2691b6b7d02Sflorian YYERROR;
2701b6b7d02Sflorian }
2711b6b7d02Sflorian if (domain->cert == NULL && domain->fullchain == NULL) {
2721b6b7d02Sflorian yyerror("at least certificate file or full "
2731b6b7d02Sflorian "certificate chain file must be specified "
2741b6b7d02Sflorian "for domain %s", domain->domain);
2751b6b7d02Sflorian YYERROR;
2761b6b7d02Sflorian }
2773943d840Sbenno domain = NULL;
2783943d840Sbenno }
2793943d840Sbenno ;
2803943d840Sbenno
28165a104faSflorian keytype : RSA { $$ = KT_RSA; }
28265a104faSflorian | ECDSA { $$ = KT_ECDSA; }
28365a104faSflorian | { $$ = KT_RSA; }
2843e86e78bSgilles ;
2853e86e78bSgilles
2863943d840Sbenno domainopts_l : domainopts_l domainoptsl nl
2873943d840Sbenno | domainoptsl optnl
2883943d840Sbenno ;
2893943d840Sbenno
290e6cfdc77Sop domainoptsl : ALTERNATIVE NAMES '{' optnl altname_l '}'
29187f5451dSbenno | DOMAIN NAME STRING {
29287f5451dSbenno char *s;
29387f5451dSbenno if (domain->domain != NULL) {
29487f5451dSbenno yyerror("duplicate domain name");
29587f5451dSbenno YYERROR;
29687f5451dSbenno }
29787f5451dSbenno if ((s = strdup($3)) == NULL)
29887f5451dSbenno err(EXIT_FAILURE, "strdup");
29987f5451dSbenno domain->domain = s;
30087f5451dSbenno }
3013e86e78bSgilles | DOMAIN KEY STRING keytype {
3023943d840Sbenno char *s;
3033943d840Sbenno if (domain->key != NULL) {
3043943d840Sbenno yyerror("duplicate key");
3053943d840Sbenno YYERROR;
3063943d840Sbenno }
3073943d840Sbenno if ((s = strdup($3)) == NULL)
3083943d840Sbenno err(EXIT_FAILURE, "strdup");
3092570ecd0Sflorian if (!conf_check_file(s)) {
310383e31e9Sbenno free(s);
311383e31e9Sbenno YYERROR;
312383e31e9Sbenno }
31333febeb9Sflorian if ((conf_new_keyfile(conf, s)) == NULL) {
3143943d840Sbenno free(s);
3153943d840Sbenno yyerror("domain key file already used");
3163943d840Sbenno YYERROR;
3173943d840Sbenno }
3183943d840Sbenno domain->key = s;
31965a104faSflorian domain->keytype = $4;
3203943d840Sbenno }
3213943d840Sbenno | DOMAIN CERT STRING {
3223943d840Sbenno char *s;
3233943d840Sbenno if (domain->cert != NULL) {
3243943d840Sbenno yyerror("duplicate cert");
3253943d840Sbenno YYERROR;
3263943d840Sbenno }
3273943d840Sbenno if ((s = strdup($3)) == NULL)
3283943d840Sbenno err(EXIT_FAILURE, "strdup");
3293943d840Sbenno if (s[0] != '/') {
3303943d840Sbenno free(s);
3313943d840Sbenno yyerror("not an absolute path");
3323943d840Sbenno YYERROR;
3333943d840Sbenno }
33433febeb9Sflorian if ((conf_new_keyfile(conf, s)) == NULL) {
3353943d840Sbenno free(s);
3363943d840Sbenno yyerror("domain cert file already used");
3373943d840Sbenno YYERROR;
3383943d840Sbenno }
3393943d840Sbenno domain->cert = s;
3403943d840Sbenno }
34133febeb9Sflorian | DOMAIN CHAIN CERT STRING {
34233febeb9Sflorian char *s;
34333febeb9Sflorian if (domain->chain != NULL) {
34433febeb9Sflorian yyerror("duplicate chain");
34533febeb9Sflorian YYERROR;
34633febeb9Sflorian }
34733febeb9Sflorian if ((s = strdup($4)) == NULL)
34833febeb9Sflorian err(EXIT_FAILURE, "strdup");
34933febeb9Sflorian if ((conf_new_keyfile(conf, s)) == NULL) {
35033febeb9Sflorian free(s);
35133febeb9Sflorian yyerror("domain chain file already used");
35233febeb9Sflorian YYERROR;
35333febeb9Sflorian }
35433febeb9Sflorian domain->chain = s;
35533febeb9Sflorian }
35670bcb874Sbenno | DOMAIN FULL CHAIN CERT STRING {
35770bcb874Sbenno char *s;
35870bcb874Sbenno if (domain->fullchain != NULL) {
3594adf5313Sbenno yyerror("duplicate full chain");
36070bcb874Sbenno YYERROR;
36170bcb874Sbenno }
36270bcb874Sbenno if ((s = strdup($5)) == NULL)
36370bcb874Sbenno err(EXIT_FAILURE, "strdup");
36470bcb874Sbenno if ((conf_new_keyfile(conf, s)) == NULL) {
36570bcb874Sbenno free(s);
36670bcb874Sbenno yyerror("domain full chain file already used");
36770bcb874Sbenno YYERROR;
36870bcb874Sbenno }
36970bcb874Sbenno domain->fullchain = s;
37070bcb874Sbenno }
3713943d840Sbenno | SIGN WITH STRING {
3723943d840Sbenno char *s;
3733943d840Sbenno if (domain->auth != NULL) {
37446203dadSbenno yyerror("duplicate sign with");
3753943d840Sbenno YYERROR;
3763943d840Sbenno }
3773943d840Sbenno if ((s = strdup($3)) == NULL)
3783943d840Sbenno err(EXIT_FAILURE, "strdup");
3793943d840Sbenno if (authority_find(conf, s) == NULL) {
38046203dadSbenno yyerror("sign with: unknown authority");
3819d58ffeeSjsg free(s);
3823943d840Sbenno YYERROR;
3833943d840Sbenno }
3843943d840Sbenno domain->auth = s;
3853943d840Sbenno }
3866c0ff37dSbenno | CHALLENGEDIR STRING {
3876c0ff37dSbenno char *s;
3886c0ff37dSbenno if (domain->challengedir != NULL) {
3896c0ff37dSbenno yyerror("duplicate challengedir");
3906c0ff37dSbenno YYERROR;
3916c0ff37dSbenno }
3926c0ff37dSbenno if ((s = strdup($2)) == NULL)
3936c0ff37dSbenno err(EXIT_FAILURE, "strdup");
3946c0ff37dSbenno domain->challengedir = s;
3956c0ff37dSbenno }
3963943d840Sbenno ;
3973943d840Sbenno
398e6cfdc77Sop altname_l : altname optcommanl altname_l
399e6cfdc77Sop | altname optnl
4003943d840Sbenno ;
4013943d840Sbenno
4023943d840Sbenno altname : STRING {
4033943d840Sbenno char *s;
4043943d840Sbenno struct altname_c *ac;
4053943d840Sbenno if (!domain_valid($1)) {
4063943d840Sbenno yyerror("bad domain syntax");
4073943d840Sbenno YYERROR;
4083943d840Sbenno }
4093943d840Sbenno if ((ac = calloc(1, sizeof(struct altname_c))) == NULL)
4103943d840Sbenno err(EXIT_FAILURE, "calloc");
4113943d840Sbenno if ((s = strdup($1)) == NULL) {
4123943d840Sbenno free(ac);
4133943d840Sbenno err(EXIT_FAILURE, "strdup");
4143943d840Sbenno }
4153943d840Sbenno ac->domain = s;
416221ac2aaSbenno TAILQ_INSERT_TAIL(&domain->altname_list, ac, entry);
417383e31e9Sbenno domain->altname_count++;
4183943d840Sbenno /*
4193943d840Sbenno * XXX we could check if altname is duplicate
4203943d840Sbenno * or identical to domain->domain
4213943d840Sbenno */
4223943d840Sbenno }
4233943d840Sbenno
4243943d840Sbenno %%
4253943d840Sbenno
4263943d840Sbenno struct keywords {
4273943d840Sbenno const char *k_name;
4283943d840Sbenno int k_val;
4293943d840Sbenno };
4303943d840Sbenno
4313943d840Sbenno int
yyerror(const char * fmt,...)4323943d840Sbenno yyerror(const char *fmt, ...)
4333943d840Sbenno {
4343943d840Sbenno va_list ap;
4353943d840Sbenno char *msg;
4363943d840Sbenno
4373943d840Sbenno file->errors++;
4383943d840Sbenno va_start(ap, fmt);
4393943d840Sbenno if (vasprintf(&msg, fmt, ap) == -1)
4403943d840Sbenno err(EXIT_FAILURE, "yyerror vasprintf");
4413943d840Sbenno va_end(ap);
4423943d840Sbenno fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, msg);
4433943d840Sbenno free(msg);
4443943d840Sbenno return (0);
4453943d840Sbenno }
4463943d840Sbenno
4473943d840Sbenno int
kw_cmp(const void * k,const void * e)4483943d840Sbenno kw_cmp(const void *k, const void *e)
4493943d840Sbenno {
4507d83751cSbenno return strcmp(k, ((const struct keywords *)e)->k_name);
4513943d840Sbenno }
4523943d840Sbenno
4533943d840Sbenno int
lookup(char * s)4543943d840Sbenno lookup(char *s)
4553943d840Sbenno {
4563943d840Sbenno /* this has to be sorted always */
4573943d840Sbenno static const struct keywords keywords[] = {
4583943d840Sbenno {"account", ACCOUNT},
4593943d840Sbenno {"alternative", ALTERNATIVE},
4603943d840Sbenno {"api", API},
4613943d840Sbenno {"authority", AUTHORITY},
4623943d840Sbenno {"certificate", CERT},
46333febeb9Sflorian {"chain", CHAIN},
4646c0ff37dSbenno {"challengedir", CHALLENGEDIR},
4656736ff2bSflorian {"contact", CONTACT},
4663943d840Sbenno {"domain", DOMAIN},
4673e86e78bSgilles {"ecdsa", ECDSA},
46870bcb874Sbenno {"full", FULL},
4693943d840Sbenno {"include", INCLUDE},
4703943d840Sbenno {"key", KEY},
471d0ea1cfcSsthen {"name", NAME},
4723943d840Sbenno {"names", NAMES},
4733e86e78bSgilles {"rsa", RSA},
4743943d840Sbenno {"sign", SIGN},
4753943d840Sbenno {"url", URL},
4763943d840Sbenno {"with", WITH},
4773943d840Sbenno };
4783943d840Sbenno const struct keywords *p;
4793943d840Sbenno
4803943d840Sbenno p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
4813943d840Sbenno sizeof(keywords[0]), kw_cmp);
4823943d840Sbenno
4837d83751cSbenno if (p != NULL)
4847d83751cSbenno return p->k_val;
4853943d840Sbenno else
4867d83751cSbenno return STRING;
4873943d840Sbenno }
4883943d840Sbenno
489f3e9965dSdenis #define START_EXPAND 1
490f3e9965dSdenis #define DONE_EXPAND 2
4913943d840Sbenno
492f3e9965dSdenis static int expanding;
493f3e9965dSdenis
494f3e9965dSdenis int
igetc(void)495f3e9965dSdenis igetc(void)
496f3e9965dSdenis {
497f3e9965dSdenis int c;
498f3e9965dSdenis
499f3e9965dSdenis while (1) {
500f3e9965dSdenis if (file->ungetpos > 0)
501f3e9965dSdenis c = file->ungetbuf[--file->ungetpos];
502f3e9965dSdenis else
503f3e9965dSdenis c = getc(file->stream);
504f3e9965dSdenis
505f3e9965dSdenis if (c == START_EXPAND)
506f3e9965dSdenis expanding = 1;
507f3e9965dSdenis else if (c == DONE_EXPAND)
508f3e9965dSdenis expanding = 0;
509f3e9965dSdenis else
510f3e9965dSdenis break;
511f3e9965dSdenis }
5127d83751cSbenno return c;
513f3e9965dSdenis }
5143943d840Sbenno
5153943d840Sbenno int
lgetc(int quotec)5163943d840Sbenno lgetc(int quotec)
5173943d840Sbenno {
5183943d840Sbenno int c, next;
5193943d840Sbenno
5203943d840Sbenno if (quotec) {
521f3e9965dSdenis if ((c = igetc()) == EOF) {
5223943d840Sbenno yyerror("reached end of file while parsing "
5233943d840Sbenno "quoted string");
5243943d840Sbenno if (file == topfile || popfile() == EOF)
5253943d840Sbenno return (EOF);
5267d83751cSbenno return quotec;
5273943d840Sbenno }
5287d83751cSbenno return c;
5293943d840Sbenno }
5303943d840Sbenno
531f3e9965dSdenis while ((c = igetc()) == '\\') {
532f3e9965dSdenis next = igetc();
5333943d840Sbenno if (next != '\n') {
5343943d840Sbenno c = next;
5353943d840Sbenno break;
5363943d840Sbenno }
5373943d840Sbenno yylval.lineno = file->lineno;
5383943d840Sbenno file->lineno++;
5393943d840Sbenno }
5403943d840Sbenno
541f3e9965dSdenis if (c == EOF) {
542f3e9965dSdenis /*
543f3e9965dSdenis * Fake EOL when hit EOF for the first time. This gets line
544f3e9965dSdenis * count right if last line in included file is syntactically
545f3e9965dSdenis * invalid and has no newline.
546f3e9965dSdenis */
547f3e9965dSdenis if (file->eof_reached == 0) {
548f3e9965dSdenis file->eof_reached = 1;
5497d83751cSbenno return '\n';
550f3e9965dSdenis }
5513943d840Sbenno while (c == EOF) {
5523943d840Sbenno if (file == topfile || popfile() == EOF)
5533943d840Sbenno return (EOF);
554f3e9965dSdenis c = igetc();
555f3e9965dSdenis }
5563943d840Sbenno }
5577d83751cSbenno return c;
5583943d840Sbenno }
5593943d840Sbenno
560f3e9965dSdenis void
lungetc(int c)5613943d840Sbenno lungetc(int c)
5623943d840Sbenno {
5633943d840Sbenno if (c == EOF)
564f3e9965dSdenis return;
565f3e9965dSdenis
566f3e9965dSdenis if (file->ungetpos >= file->ungetsize) {
567f3e9965dSdenis void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
568f3e9965dSdenis if (p == NULL)
569a062aa9dSkrw err(1, "%s", __func__);
570f3e9965dSdenis file->ungetbuf = p;
571f3e9965dSdenis file->ungetsize *= 2;
5723943d840Sbenno }
573f3e9965dSdenis file->ungetbuf[file->ungetpos++] = c;
5743943d840Sbenno }
5753943d840Sbenno
5763943d840Sbenno int
findeol(void)5773943d840Sbenno findeol(void)
5783943d840Sbenno {
5793943d840Sbenno int c;
5803943d840Sbenno
5813943d840Sbenno /* skip to either EOF or the first real EOL */
5823943d840Sbenno while (1) {
5833943d840Sbenno c = lgetc(0);
5843943d840Sbenno if (c == '\n') {
5853943d840Sbenno file->lineno++;
5863943d840Sbenno break;
5873943d840Sbenno }
5883943d840Sbenno if (c == EOF)
5893943d840Sbenno break;
5903943d840Sbenno }
5917d83751cSbenno return ERROR;
5923943d840Sbenno }
5933943d840Sbenno
5943943d840Sbenno int
yylex(void)5953943d840Sbenno yylex(void)
5963943d840Sbenno {
59708f6ba19Snaddy char buf[8096];
59808f6ba19Snaddy char *p, *val;
5993943d840Sbenno int quotec, next, c;
6003943d840Sbenno int token;
6013943d840Sbenno
6023943d840Sbenno top:
6033943d840Sbenno p = buf;
6043943d840Sbenno while ((c = lgetc(0)) == ' ' || c == '\t')
6053943d840Sbenno ; /* nothing */
6063943d840Sbenno
6073943d840Sbenno yylval.lineno = file->lineno;
6083943d840Sbenno if (c == '#')
6093943d840Sbenno while ((c = lgetc(0)) != '\n' && c != EOF)
6103943d840Sbenno ; /* nothing */
611f3e9965dSdenis if (c == '$' && !expanding) {
6123943d840Sbenno while (1) {
6133943d840Sbenno if ((c = lgetc(0)) == EOF)
6147d83751cSbenno return 0;
6153943d840Sbenno
6163943d840Sbenno if (p + 1 >= buf + sizeof(buf) - 1) {
6173943d840Sbenno yyerror("string too long");
6187d83751cSbenno return findeol();
6193943d840Sbenno }
6203943d840Sbenno if (isalnum(c) || c == '_') {
6213943d840Sbenno *p++ = c;
6223943d840Sbenno continue;
6233943d840Sbenno }
6243943d840Sbenno *p = '\0';
6253943d840Sbenno lungetc(c);
6263943d840Sbenno break;
6273943d840Sbenno }
6283943d840Sbenno val = symget(buf);
6293943d840Sbenno if (val == NULL) {
6303943d840Sbenno yyerror("macro '%s' not defined", buf);
6317d83751cSbenno return findeol();
6323943d840Sbenno }
633f3e9965dSdenis p = val + strlen(val) - 1;
634f3e9965dSdenis lungetc(DONE_EXPAND);
635f3e9965dSdenis while (p >= val) {
63608f6ba19Snaddy lungetc((unsigned char)*p);
637f3e9965dSdenis p--;
638f3e9965dSdenis }
639f3e9965dSdenis lungetc(START_EXPAND);
6403943d840Sbenno goto top;
6413943d840Sbenno }
6423943d840Sbenno
6433943d840Sbenno switch (c) {
6443943d840Sbenno case '\'':
6453943d840Sbenno case '"':
6463943d840Sbenno quotec = c;
6473943d840Sbenno while (1) {
6483943d840Sbenno if ((c = lgetc(quotec)) == EOF)
6497d83751cSbenno return 0;
6503943d840Sbenno if (c == '\n') {
6513943d840Sbenno file->lineno++;
6523943d840Sbenno continue;
6533943d840Sbenno } else if (c == '\\') {
6543943d840Sbenno if ((next = lgetc(quotec)) == EOF)
6557d83751cSbenno return 0;
656a1533359Ssashan if (next == quotec || next == ' ' ||
657a1533359Ssashan next == '\t')
6583943d840Sbenno c = next;
6593943d840Sbenno else if (next == '\n') {
6603943d840Sbenno file->lineno++;
6613943d840Sbenno continue;
6623943d840Sbenno } else
6633943d840Sbenno lungetc(next);
6643943d840Sbenno } else if (c == quotec) {
6653943d840Sbenno *p = '\0';
6663943d840Sbenno break;
6673943d840Sbenno } else if (c == '\0') {
6683943d840Sbenno yyerror("syntax error");
6697d83751cSbenno return findeol();
6703943d840Sbenno }
6713943d840Sbenno if (p + 1 >= buf + sizeof(buf) - 1) {
6723943d840Sbenno yyerror("string too long");
6737d83751cSbenno return findeol();
6743943d840Sbenno }
6753943d840Sbenno *p++ = c;
6763943d840Sbenno }
6773943d840Sbenno yylval.v.string = strdup(buf);
6783943d840Sbenno if (yylval.v.string == NULL)
679a062aa9dSkrw err(EXIT_FAILURE, "%s", __func__);
6807d83751cSbenno return STRING;
6813943d840Sbenno }
6823943d840Sbenno
6833943d840Sbenno #define allowed_to_end_number(x) \
6843943d840Sbenno (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
6853943d840Sbenno
6863943d840Sbenno if (c == '-' || isdigit(c)) {
6873943d840Sbenno do {
6883943d840Sbenno *p++ = c;
689915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) {
6903943d840Sbenno yyerror("string too long");
6917d83751cSbenno return findeol();
6923943d840Sbenno }
6933943d840Sbenno } while ((c = lgetc(0)) != EOF && isdigit(c));
6943943d840Sbenno lungetc(c);
6953943d840Sbenno if (p == buf + 1 && buf[0] == '-')
6963943d840Sbenno goto nodigits;
6973943d840Sbenno if (c == EOF || allowed_to_end_number(c)) {
6983943d840Sbenno const char *errstr = NULL;
6993943d840Sbenno
7003943d840Sbenno *p = '\0';
7013943d840Sbenno yylval.v.number = strtonum(buf, LLONG_MIN,
7023943d840Sbenno LLONG_MAX, &errstr);
7037d83751cSbenno if (errstr != NULL) {
7043943d840Sbenno yyerror("\"%s\" invalid number: %s",
7053943d840Sbenno buf, errstr);
7063943d840Sbenno return (findeol());
7073943d840Sbenno }
7087d83751cSbenno return NUMBER;
7093943d840Sbenno } else {
7103943d840Sbenno nodigits:
7113943d840Sbenno while (p > buf + 1)
71208f6ba19Snaddy lungetc((unsigned char)*--p);
71308f6ba19Snaddy c = (unsigned char)*--p;
7143943d840Sbenno if (c == '-')
7157d83751cSbenno return c;
7163943d840Sbenno }
7173943d840Sbenno }
7183943d840Sbenno
7193943d840Sbenno #define allowed_in_string(x) \
7203943d840Sbenno (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
7213943d840Sbenno x != '{' && x != '}' && \
7223943d840Sbenno x != '!' && x != '=' && x != '#' && \
7233943d840Sbenno x != ','))
7243943d840Sbenno
725383e31e9Sbenno if (isalnum(c) || c == ':' || c == '_') {
7263943d840Sbenno do {
7273943d840Sbenno *p++ = c;
728915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) {
7293943d840Sbenno yyerror("string too long");
7303943d840Sbenno return (findeol());
7313943d840Sbenno }
7323943d840Sbenno } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
7333943d840Sbenno lungetc(c);
7343943d840Sbenno *p = '\0';
7353943d840Sbenno if ((token = lookup(buf)) == STRING) {
7363943d840Sbenno if ((yylval.v.string = strdup(buf)) == NULL)
737a062aa9dSkrw err(EXIT_FAILURE, "%s", __func__);
7383943d840Sbenno }
7397d83751cSbenno return token;
7403943d840Sbenno }
7413943d840Sbenno if (c == '\n') {
7423943d840Sbenno yylval.lineno = file->lineno;
7433943d840Sbenno file->lineno++;
7443943d840Sbenno }
7453943d840Sbenno if (c == EOF)
7467d83751cSbenno return 0;
7477d83751cSbenno return c;
7483943d840Sbenno }
7493943d840Sbenno
7503943d840Sbenno struct file *
pushfile(const char * name)7513943d840Sbenno pushfile(const char *name)
7523943d840Sbenno {
7533943d840Sbenno struct file *nfile;
7543943d840Sbenno
7553943d840Sbenno if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
7566a3d55f9Skrw warn("%s", __func__);
7577d83751cSbenno return NULL;
7583943d840Sbenno }
7593943d840Sbenno if ((nfile->name = strdup(name)) == NULL) {
7606a3d55f9Skrw warn("%s", __func__);
7613943d840Sbenno free(nfile);
7627d83751cSbenno return NULL;
7633943d840Sbenno }
7643943d840Sbenno if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
7656a3d55f9Skrw warn("%s: %s", __func__, nfile->name);
7663943d840Sbenno free(nfile->name);
7673943d840Sbenno free(nfile);
7687d83751cSbenno return NULL;
7693943d840Sbenno }
770f3e9965dSdenis nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
771f3e9965dSdenis nfile->ungetsize = 16;
772f3e9965dSdenis nfile->ungetbuf = malloc(nfile->ungetsize);
773f3e9965dSdenis if (nfile->ungetbuf == NULL) {
7746a3d55f9Skrw warn("%s", __func__);
775f3e9965dSdenis fclose(nfile->stream);
776f3e9965dSdenis free(nfile->name);
777f3e9965dSdenis free(nfile);
7787d83751cSbenno return NULL;
779f3e9965dSdenis }
7803943d840Sbenno TAILQ_INSERT_TAIL(&files, nfile, entry);
7817d83751cSbenno return nfile;
7823943d840Sbenno }
7833943d840Sbenno
7843943d840Sbenno int
popfile(void)7853943d840Sbenno popfile(void)
7863943d840Sbenno {
7873943d840Sbenno struct file *prev;
7883943d840Sbenno
7893943d840Sbenno if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
7903943d840Sbenno prev->errors += file->errors;
7913943d840Sbenno
7923943d840Sbenno TAILQ_REMOVE(&files, file, entry);
7933943d840Sbenno fclose(file->stream);
7943943d840Sbenno free(file->name);
795f3e9965dSdenis free(file->ungetbuf);
7963943d840Sbenno free(file);
7973943d840Sbenno file = prev;
7983943d840Sbenno return (file ? 0 : EOF);
7993943d840Sbenno }
8003943d840Sbenno
8013943d840Sbenno struct acme_conf *
parse_config(const char * filename,int opts)8023943d840Sbenno parse_config(const char *filename, int opts)
8033943d840Sbenno {
8043943d840Sbenno struct sym *sym, *next;
8053943d840Sbenno
8063943d840Sbenno if ((conf = calloc(1, sizeof(struct acme_conf))) == NULL)
807a062aa9dSkrw err(EXIT_FAILURE, "%s", __func__);
8083943d840Sbenno conf->opts = opts;
8093943d840Sbenno
8103943d840Sbenno if ((file = pushfile(filename)) == NULL) {
8113943d840Sbenno free(conf);
8127d83751cSbenno return NULL;
8133943d840Sbenno }
8143943d840Sbenno topfile = file;
8153943d840Sbenno
816221ac2aaSbenno TAILQ_INIT(&conf->authority_list);
817221ac2aaSbenno TAILQ_INIT(&conf->domain_list);
8183943d840Sbenno
8193943d840Sbenno yyparse();
8203943d840Sbenno errors = file->errors;
8213943d840Sbenno popfile();
8223943d840Sbenno
8233943d840Sbenno /* Free macros and check which have not been used. */
82446bca67bSkrw TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
8253943d840Sbenno if ((conf->opts & ACME_OPT_VERBOSE) && !sym->used)
8263943d840Sbenno fprintf(stderr, "warning: macro '%s' not "
8273943d840Sbenno "used\n", sym->nam);
8283943d840Sbenno if (!sym->persist) {
8293943d840Sbenno free(sym->nam);
8303943d840Sbenno free(sym->val);
8313943d840Sbenno TAILQ_REMOVE(&symhead, sym, entry);
8323943d840Sbenno free(sym);
8333943d840Sbenno }
8343943d840Sbenno }
8353943d840Sbenno
8367d83751cSbenno if (errors != 0) {
8373943d840Sbenno clear_config(conf);
8387d83751cSbenno return NULL;
8393943d840Sbenno }
8403943d840Sbenno
841f142a2feSbenno if (opts & ACME_OPT_CHECK) {
842f142a2feSbenno if (opts & ACME_OPT_VERBOSE)
84309263938Sbenno print_config(conf);
844f142a2feSbenno exit(0);
845f142a2feSbenno }
846f142a2feSbenno
84709263938Sbenno
8487d83751cSbenno return conf;
8493943d840Sbenno }
8503943d840Sbenno
8513943d840Sbenno int
symset(const char * nam,const char * val,int persist)8523943d840Sbenno symset(const char *nam, const char *val, int persist)
8533943d840Sbenno {
8543943d840Sbenno struct sym *sym;
8553943d840Sbenno
85654c95b7aSkrw TAILQ_FOREACH(sym, &symhead, entry) {
85754c95b7aSkrw if (strcmp(nam, sym->nam) == 0)
85854c95b7aSkrw break;
85954c95b7aSkrw }
8603943d840Sbenno
8613943d840Sbenno if (sym != NULL) {
8623943d840Sbenno if (sym->persist == 1)
8633943d840Sbenno return (0);
8643943d840Sbenno else {
8653943d840Sbenno free(sym->nam);
8663943d840Sbenno free(sym->val);
8673943d840Sbenno TAILQ_REMOVE(&symhead, sym, entry);
8683943d840Sbenno free(sym);
8693943d840Sbenno }
8703943d840Sbenno }
8713943d840Sbenno if ((sym = calloc(1, sizeof(*sym))) == NULL)
8727d83751cSbenno return -1;
8733943d840Sbenno
8743943d840Sbenno sym->nam = strdup(nam);
8753943d840Sbenno if (sym->nam == NULL) {
8763943d840Sbenno free(sym);
8777d83751cSbenno return -1;
8783943d840Sbenno }
8793943d840Sbenno sym->val = strdup(val);
8803943d840Sbenno if (sym->val == NULL) {
8813943d840Sbenno free(sym->nam);
8823943d840Sbenno free(sym);
8837d83751cSbenno return -1;
8843943d840Sbenno }
8853943d840Sbenno sym->used = 0;
8863943d840Sbenno sym->persist = persist;
8873943d840Sbenno TAILQ_INSERT_TAIL(&symhead, sym, entry);
8887d83751cSbenno return 0;
8893943d840Sbenno }
8903943d840Sbenno
8913943d840Sbenno int
cmdline_symset(char * s)8923943d840Sbenno cmdline_symset(char *s)
8933943d840Sbenno {
8943943d840Sbenno char *sym, *val;
8953943d840Sbenno int ret;
8963943d840Sbenno
8973943d840Sbenno if ((val = strrchr(s, '=')) == NULL)
8987d83751cSbenno return -1;
899ed1b9eb8Smiko sym = strndup(s, val - s);
900ed1b9eb8Smiko if (sym == NULL)
901ed1b9eb8Smiko errx(EXIT_FAILURE, "%s: strndup", __func__);
9023943d840Sbenno ret = symset(sym, val + 1, 1);
9033943d840Sbenno free(sym);
9043943d840Sbenno
9057d83751cSbenno return ret;
9063943d840Sbenno }
9073943d840Sbenno
9083943d840Sbenno char *
symget(const char * nam)9093943d840Sbenno symget(const char *nam)
9103943d840Sbenno {
9113943d840Sbenno struct sym *sym;
9123943d840Sbenno
91354c95b7aSkrw TAILQ_FOREACH(sym, &symhead, entry) {
9143943d840Sbenno if (strcmp(nam, sym->nam) == 0) {
9153943d840Sbenno sym->used = 1;
9167d83751cSbenno return sym->val;
9173943d840Sbenno }
91854c95b7aSkrw }
9197d83751cSbenno return NULL;
9203943d840Sbenno }
9213943d840Sbenno
9223943d840Sbenno struct authority_c *
conf_new_authority(struct acme_conf * c,char * s)9233943d840Sbenno conf_new_authority(struct acme_conf *c, char *s)
9243943d840Sbenno {
9253943d840Sbenno struct authority_c *a;
9263943d840Sbenno
9273943d840Sbenno a = authority_find(c, s);
9287d83751cSbenno if (a != NULL)
9297d83751cSbenno return NULL;
9303943d840Sbenno if ((a = calloc(1, sizeof(struct authority_c))) == NULL)
931a062aa9dSkrw err(EXIT_FAILURE, "%s", __func__);
932221ac2aaSbenno TAILQ_INSERT_TAIL(&c->authority_list, a, entry);
9333943d840Sbenno
9343943d840Sbenno a->name = s;
9357d83751cSbenno return a;
9363943d840Sbenno }
9373943d840Sbenno
9383943d840Sbenno struct authority_c *
authority_find(struct acme_conf * c,char * s)9393943d840Sbenno authority_find(struct acme_conf *c, char *s)
9403943d840Sbenno {
9413943d840Sbenno struct authority_c *a;
9423943d840Sbenno
943221ac2aaSbenno TAILQ_FOREACH(a, &c->authority_list, entry) {
9443943d840Sbenno if (strncmp(a->name, s, AUTH_MAXLEN) == 0) {
9457d83751cSbenno return a;
9463943d840Sbenno }
9473943d840Sbenno }
9487d83751cSbenno return NULL;
9493943d840Sbenno }
9503943d840Sbenno
9513943d840Sbenno struct authority_c *
authority_find0(struct acme_conf * c)9523943d840Sbenno authority_find0(struct acme_conf *c)
9533943d840Sbenno {
9547d307612Sbenno return (TAILQ_FIRST(&c->authority_list));
9553943d840Sbenno }
9563943d840Sbenno
9573943d840Sbenno struct domain_c *
conf_new_domain(struct acme_conf * c,char * s)9583943d840Sbenno conf_new_domain(struct acme_conf *c, char *s)
9593943d840Sbenno {
9603943d840Sbenno struct domain_c *d;
9613943d840Sbenno
96287f5451dSbenno d = domain_find_handle(c, s);
9637d83751cSbenno if (d != NULL)
9643943d840Sbenno return (NULL);
9653943d840Sbenno if ((d = calloc(1, sizeof(struct domain_c))) == NULL)
966a062aa9dSkrw err(EXIT_FAILURE, "%s", __func__);
967221ac2aaSbenno TAILQ_INSERT_TAIL(&c->domain_list, d, entry);
9683943d840Sbenno
96987f5451dSbenno d->handle = s;
970221ac2aaSbenno TAILQ_INIT(&d->altname_list);
9713943d840Sbenno
9727d83751cSbenno return d;
9733943d840Sbenno }
9743943d840Sbenno
9753943d840Sbenno struct domain_c *
domain_find_handle(struct acme_conf * c,char * s)97687f5451dSbenno domain_find_handle(struct acme_conf *c, char *s)
9773943d840Sbenno {
9783943d840Sbenno struct domain_c *d;
9793943d840Sbenno
980221ac2aaSbenno TAILQ_FOREACH(d, &c->domain_list, entry) {
98187f5451dSbenno if (strncmp(d->handle, s, DOMAIN_MAXLEN) == 0) {
9827d83751cSbenno return d;
9833943d840Sbenno }
9843943d840Sbenno }
9857d83751cSbenno return NULL;
9863943d840Sbenno }
9873943d840Sbenno
9883943d840Sbenno struct keyfile *
conf_new_keyfile(struct acme_conf * c,char * s)9893943d840Sbenno conf_new_keyfile(struct acme_conf *c, char *s)
9903943d840Sbenno {
9913943d840Sbenno struct keyfile *k;
9923943d840Sbenno
9933943d840Sbenno LIST_FOREACH(k, &c->used_key_list, entry) {
9943943d840Sbenno if (strncmp(k->name, s, PATH_MAX) == 0) {
9957d83751cSbenno return NULL;
9963943d840Sbenno }
9973943d840Sbenno }
9983943d840Sbenno
9993943d840Sbenno if ((k = calloc(1, sizeof(struct keyfile))) == NULL)
1000a062aa9dSkrw err(EXIT_FAILURE, "%s", __func__);
10013943d840Sbenno LIST_INSERT_HEAD(&c->used_key_list, k, entry);
10023943d840Sbenno
10033943d840Sbenno k->name = s;
10047d83751cSbenno return k;
10053943d840Sbenno }
10063943d840Sbenno
10073943d840Sbenno void
clear_config(struct acme_conf * xconf)10083943d840Sbenno clear_config(struct acme_conf *xconf)
10093943d840Sbenno {
10103943d840Sbenno struct authority_c *a;
10113943d840Sbenno struct domain_c *d;
10123943d840Sbenno struct altname_c *ac;
10133943d840Sbenno
1014221ac2aaSbenno while ((a = TAILQ_FIRST(&xconf->authority_list)) != NULL) {
1015221ac2aaSbenno TAILQ_REMOVE(&xconf->authority_list, a, entry);
10163943d840Sbenno free(a);
10173943d840Sbenno }
1018221ac2aaSbenno while ((d = TAILQ_FIRST(&xconf->domain_list)) != NULL) {
1019221ac2aaSbenno while ((ac = TAILQ_FIRST(&d->altname_list)) != NULL) {
1020221ac2aaSbenno TAILQ_REMOVE(&d->altname_list, ac, entry);
10213943d840Sbenno free(ac);
10223943d840Sbenno }
1023221ac2aaSbenno TAILQ_REMOVE(&xconf->domain_list, d, entry);
10243943d840Sbenno free(d);
10253943d840Sbenno }
10263943d840Sbenno free(xconf);
10273943d840Sbenno }
10283943d840Sbenno
1029bc812290Sflorian const char*
kt2txt(enum keytype kt)1030bc812290Sflorian kt2txt(enum keytype kt)
1031bc812290Sflorian {
1032bc812290Sflorian switch (kt) {
1033bc812290Sflorian case KT_RSA:
1034bc812290Sflorian return "rsa";
1035bc812290Sflorian case KT_ECDSA:
1036bc812290Sflorian return "ecdsa";
1037bc812290Sflorian default:
1038bc812290Sflorian return "<unknown>";
1039bc812290Sflorian }
1040bc812290Sflorian }
1041bc812290Sflorian
10423298b855Sbenno void
print_config(struct acme_conf * xconf)10433298b855Sbenno print_config(struct acme_conf *xconf)
10443298b855Sbenno {
10453298b855Sbenno struct authority_c *a;
10463298b855Sbenno struct domain_c *d;
10473298b855Sbenno struct altname_c *ac;
10483298b855Sbenno int f;
10493298b855Sbenno
1050221ac2aaSbenno TAILQ_FOREACH(a, &xconf->authority_list, entry) {
10513298b855Sbenno printf("authority %s {\n", a->name);
10523298b855Sbenno if (a->api != NULL)
10533298b855Sbenno printf("\tapi url \"%s\"\n", a->api);
10543298b855Sbenno if (a->account != NULL)
10554f8b772fSflorian printf("\taccount key \"%s\" %s\n", a->account,
10564f8b772fSflorian kt2txt(a->keytype));
10573298b855Sbenno printf("}\n\n");
10583298b855Sbenno }
1059221ac2aaSbenno TAILQ_FOREACH(d, &xconf->domain_list, entry) {
10603298b855Sbenno f = 0;
106187f5451dSbenno printf("domain %s {\n", d->handle);
106287f5451dSbenno if (d->domain != NULL)
106387f5451dSbenno printf("\tdomain name \"%s\"\n", d->domain);
1064221ac2aaSbenno TAILQ_FOREACH(ac, &d->altname_list, entry) {
10653298b855Sbenno if (!f)
10663298b855Sbenno printf("\talternative names {");
10673298b855Sbenno if (ac->domain != NULL) {
10683298b855Sbenno printf("%s%s", f ? ", " : " ", ac->domain);
10693298b855Sbenno f = 1;
10703298b855Sbenno }
10713298b855Sbenno }
10723298b855Sbenno if (f)
10733298b855Sbenno printf(" }\n");
10743298b855Sbenno if (d->key != NULL)
1075bc812290Sflorian printf("\tdomain key \"%s\" %s\n", d->key, kt2txt(
1076bc812290Sflorian d->keytype));
10773298b855Sbenno if (d->cert != NULL)
10783298b855Sbenno printf("\tdomain certificate \"%s\"\n", d->cert);
107933febeb9Sflorian if (d->chain != NULL)
10805c258182Sflorian printf("\tdomain chain certificate \"%s\"\n", d->chain);
108170bcb874Sbenno if (d->fullchain != NULL)
10825c258182Sflorian printf("\tdomain full chain certificate \"%s\"\n",
108370bcb874Sbenno d->fullchain);
10843298b855Sbenno if (d->auth != NULL)
10853298b855Sbenno printf("\tsign with \"%s\"\n", d->auth);
10863298b855Sbenno if (d->challengedir != NULL)
10873298b855Sbenno printf("\tchallengedir \"%s\"\n", d->challengedir);
10883298b855Sbenno printf("}\n\n");
10893298b855Sbenno }
10903298b855Sbenno }
10913298b855Sbenno
10923943d840Sbenno /*
10933943d840Sbenno * This isn't RFC1035 compliant, but does the bare minimum in making
10943943d840Sbenno * sure that we don't get bogus domain names on the command line, which
10953943d840Sbenno * might otherwise screw up our directory structure.
10963943d840Sbenno * Returns zero on failure, non-zero on success.
10973943d840Sbenno */
10983943d840Sbenno int
domain_valid(const char * cp)10993943d840Sbenno domain_valid(const char *cp)
11003943d840Sbenno {
11013943d840Sbenno
11024de82fa3Sderaadt for ( ; *cp != '\0'; cp++)
11034de82fa3Sderaadt if (!(*cp == '.' || *cp == '-' ||
1104*4a50067cSflorian *cp == '_' || isalnum((unsigned char)*cp)))
11057d83751cSbenno return 0;
11067d83751cSbenno return 1;
11073943d840Sbenno }
11083943d840Sbenno
11093943d840Sbenno int
conf_check_file(char * s)11102570ecd0Sflorian conf_check_file(char *s)
11113943d840Sbenno {
11123943d840Sbenno struct stat st;
11133943d840Sbenno
11143943d840Sbenno if (s[0] != '/') {
11153943d840Sbenno warnx("%s: not an absolute path", s);
11167d83751cSbenno return 0;
11173943d840Sbenno }
11183943d840Sbenno if (stat(s, &st)) {
11192570ecd0Sflorian if (errno == ENOENT)
11202570ecd0Sflorian return 1;
11213943d840Sbenno warn("cannot stat %s", s);
11227d83751cSbenno return 0;
11233943d840Sbenno }
11243943d840Sbenno if (st.st_mode & (S_IRWXG | S_IRWXO)) {
11253943d840Sbenno warnx("%s: group read/writable or world read/writable", s);
11267d83751cSbenno return 0;
11273943d840Sbenno }
11287d83751cSbenno return 1;
11293943d840Sbenno }
1130