2021-01-15 10:17:43 +01:00
|
|
|
%{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2021 Omar Polo <op@omarpolo.com>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2021-06-16 16:43:16 +02:00
|
|
|
#include <ctype.h>
|
2021-02-10 12:53:05 +01:00
|
|
|
#include <errno.h>
|
2021-02-06 18:22:37 +01:00
|
|
|
#include <stdarg.h>
|
2021-01-15 10:17:43 +01:00
|
|
|
#include <stdio.h>
|
2021-06-16 16:43:16 +02:00
|
|
|
#include <stdlib.h>
|
2021-01-28 18:50:22 +01:00
|
|
|
#include <string.h>
|
2021-01-15 10:17:43 +01:00
|
|
|
|
|
|
|
#include "gmid.h"
|
|
|
|
|
2021-06-16 16:43:16 +02:00
|
|
|
FILE *yyfp;
|
|
|
|
|
2021-06-16 16:51:57 +02:00
|
|
|
typedef struct {
|
|
|
|
union {
|
|
|
|
char *str;
|
|
|
|
int num;
|
2021-06-29 13:11:43 +02:00
|
|
|
} v;
|
2021-06-16 16:51:57 +02:00
|
|
|
int lineno;
|
|
|
|
int colno;
|
|
|
|
} yystype;
|
|
|
|
#define YYSTYPE yystype
|
|
|
|
|
2021-01-15 10:17:43 +01:00
|
|
|
/*
|
|
|
|
* #define YYDEBUG 1
|
|
|
|
* int yydebug = 1;
|
|
|
|
*/
|
|
|
|
|
2021-06-29 14:17:40 +02:00
|
|
|
/*
|
|
|
|
* The idea behind this implementation of macros is from rad/parse.y
|
|
|
|
*/
|
|
|
|
TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
|
|
|
|
struct sym {
|
|
|
|
TAILQ_ENTRY(sym) entry;
|
|
|
|
int used;
|
|
|
|
int persist;
|
|
|
|
char *name;
|
|
|
|
char *val;
|
|
|
|
};
|
|
|
|
|
2021-02-04 14:23:15 +01:00
|
|
|
struct vhost *host;
|
|
|
|
struct location *loc;
|
2021-01-24 15:11:40 +01:00
|
|
|
|
2021-06-16 16:43:16 +02:00
|
|
|
static int goterror;
|
2021-01-27 17:45:45 +01:00
|
|
|
|
2021-03-31 18:32:18 +02:00
|
|
|
static struct vhost *new_vhost(void);
|
|
|
|
static struct location *new_location(void);
|
|
|
|
|
2021-02-06 18:22:37 +01:00
|
|
|
void yyerror(const char*, ...);
|
2021-06-16 16:43:16 +02:00
|
|
|
static int yylex(void);
|
2021-01-27 17:45:45 +01:00
|
|
|
int parse_portno(const char*);
|
|
|
|
void parse_conf(const char*);
|
2021-02-01 12:08:57 +01:00
|
|
|
char *ensure_absolute_path(char*);
|
2021-02-06 18:22:37 +01:00
|
|
|
int check_block_code(int);
|
|
|
|
char *check_block_fmt(char*);
|
|
|
|
int check_strip_no(int);
|
2021-02-07 13:05:32 +01:00
|
|
|
int check_prefork_num(int);
|
2021-02-10 17:37:08 +01:00
|
|
|
void advance_loc(void);
|
2021-05-03 18:11:28 +02:00
|
|
|
void only_once(const void*, const char*);
|
2021-05-09 20:23:36 +02:00
|
|
|
void only_oncei(int, const char*);
|
|
|
|
int fastcgi_conf(char *, char *, char *);
|
2021-06-11 17:49:46 +02:00
|
|
|
void add_param(char *, char *, int);
|
2021-06-29 14:17:40 +02:00
|
|
|
int symset(const char *, const char *, int);
|
|
|
|
char *symget(const char *);
|
2021-01-15 10:17:43 +01:00
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
/* for bison: */
|
|
|
|
/* %define parse.error verbose */
|
|
|
|
|
2021-06-29 18:10:40 +02:00
|
|
|
%token TIPV6 TPORT TPROTOCOLS TMIME TDEFAULT TTYPE TCHROOT TUSER TSERVER
|
|
|
|
%token TPREFORK TLOCATION TCERT TKEY TROOT TCGI TENV TLANG TLOG TINDEX TAUTO
|
|
|
|
%token TSTRIP TBLOCK TRETURN TENTRYPOINT TREQUIRE TCLIENT TCA TALIAS TTCP
|
|
|
|
%token TFASTCGI TSPAWN TPARAM
|
2021-04-29 21:13:16 +02:00
|
|
|
|
2021-06-29 18:10:40 +02:00
|
|
|
%token TERR
|
2021-01-15 10:17:43 +01:00
|
|
|
|
2021-06-29 18:10:40 +02:00
|
|
|
%token <v.str> TSTRING
|
|
|
|
%token <v.num> TNUM
|
|
|
|
%token <v.num> TBOOL
|
2021-01-15 10:17:43 +01:00
|
|
|
|
2021-06-29 18:10:40 +02:00
|
|
|
%type <v.str> string
|
2021-06-29 18:10:10 +02:00
|
|
|
|
2021-01-15 10:17:43 +01:00
|
|
|
%%
|
|
|
|
|
2021-06-29 14:42:44 +02:00
|
|
|
conf : /* empty */
|
|
|
|
| conf var
|
|
|
|
| conf option
|
|
|
|
| conf vhost
|
2021-06-29 14:17:40 +02:00
|
|
|
;
|
|
|
|
|
2021-06-29 18:10:10 +02:00
|
|
|
string : string TSTRING {
|
|
|
|
if (asprintf(&$$, "%s%s", $1, $2) == -1) {
|
|
|
|
free($1);
|
|
|
|
free($2);
|
|
|
|
yyerror("string: asprintf: %s", strerror(errno));
|
|
|
|
YYERROR;
|
|
|
|
}
|
|
|
|
free($1);
|
|
|
|
free($2);
|
|
|
|
}
|
|
|
|
| TSTRING
|
|
|
|
;
|
|
|
|
|
|
|
|
var : TSTRING '=' string {
|
2021-06-29 14:17:40 +02:00
|
|
|
char *s = $1;
|
|
|
|
while (*s++) {
|
|
|
|
if (isspace(*s)) {
|
|
|
|
yyerror("macro name cannot contain "
|
|
|
|
"whitespaces");
|
|
|
|
free($1);
|
|
|
|
free($3);
|
|
|
|
YYERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
symset($1, $3, 0);
|
|
|
|
free($1);
|
|
|
|
free($3);
|
|
|
|
}
|
|
|
|
;
|
2021-01-15 10:17:43 +01:00
|
|
|
|
2021-06-29 18:10:10 +02:00
|
|
|
option : TCHROOT string { conf.chroot = $2; }
|
2021-02-09 23:38:10 +01:00
|
|
|
| TIPV6 TBOOL { conf.ipv6 = $2; }
|
2021-06-29 18:10:10 +02:00
|
|
|
| TMIME TSTRING string { add_mime(&conf.mime, $2, $3); }
|
2021-01-15 10:17:43 +01:00
|
|
|
| TPORT TNUM { conf.port = $2; }
|
2021-02-09 23:38:10 +01:00
|
|
|
| TPREFORK TNUM { conf.prefork = check_prefork_num($2); }
|
2021-06-29 18:10:10 +02:00
|
|
|
| TPROTOCOLS string {
|
2021-01-15 19:55:05 +01:00
|
|
|
if (tls_config_parse_protocols(&conf.protos, $2) == -1)
|
2021-02-10 12:53:05 +01:00
|
|
|
yyerror("invalid protocols string \"%s\"", $2);
|
2021-01-15 19:55:05 +01:00
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TUSER string { conf.user = $2; }
|
2021-01-15 10:17:43 +01:00
|
|
|
;
|
|
|
|
|
2021-06-29 18:10:10 +02:00
|
|
|
vhost : TSERVER string {
|
2021-03-31 18:32:18 +02:00
|
|
|
host = new_vhost();
|
|
|
|
TAILQ_INSERT_HEAD(&hosts, host, vhosts);
|
|
|
|
|
|
|
|
loc = new_location();
|
|
|
|
TAILQ_INSERT_HEAD(&host->locations, loc, locations);
|
|
|
|
|
|
|
|
loc->match = xstrdup("*");
|
2021-01-15 10:17:43 +01:00
|
|
|
host->domain = $2;
|
|
|
|
|
2021-01-28 17:27:40 +01:00
|
|
|
if (strstr($2, "xn--") != NULL) {
|
2021-06-16 16:51:57 +02:00
|
|
|
warnx("%s:%d:%d \"%s\" looks like punycode: "
|
2021-01-28 17:33:20 +01:00
|
|
|
"you should use the decoded hostname.",
|
2021-06-16 16:51:57 +02:00
|
|
|
config_path, yylval.lineno+1, yylval.colno,
|
|
|
|
$2);
|
2021-01-28 17:27:40 +01:00
|
|
|
}
|
2021-03-31 18:32:18 +02:00
|
|
|
} '{' servopts locations '}' {
|
2021-01-28 17:27:40 +01:00
|
|
|
|
2021-04-30 19:16:34 +02:00
|
|
|
if (host->cert == NULL || host->key == NULL)
|
2021-02-10 12:53:05 +01:00
|
|
|
yyerror("invalid vhost definition: %s", $2);
|
2021-01-15 10:17:43 +01:00
|
|
|
}
|
|
|
|
| error '}' { yyerror("error in server directive"); }
|
|
|
|
;
|
|
|
|
|
|
|
|
servopts : /* empty */
|
|
|
|
| servopts servopt
|
|
|
|
;
|
|
|
|
|
2021-06-29 18:10:10 +02:00
|
|
|
servopt : TALIAS string {
|
2021-04-29 20:23:35 +02:00
|
|
|
struct alist *a;
|
|
|
|
|
|
|
|
a = xcalloc(1, sizeof(*a));
|
|
|
|
a->alias = $2;
|
|
|
|
if (TAILQ_EMPTY(&host->aliases))
|
|
|
|
TAILQ_INSERT_HEAD(&host->aliases, a, aliases);
|
|
|
|
else
|
|
|
|
TAILQ_INSERT_TAIL(&host->aliases, a, aliases);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TCERT string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(host->cert, "cert");
|
|
|
|
host->cert = ensure_absolute_path($2);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TCGI string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(host->cgi, "cgi");
|
2021-01-15 10:17:43 +01:00
|
|
|
/* drop the starting '/', if any */
|
2021-02-04 21:04:12 +01:00
|
|
|
if (*$2 == '/')
|
|
|
|
memmove($2, $2+1, strlen($2));
|
|
|
|
host->cgi = $2;
|
2021-01-19 11:58:29 +01:00
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TENTRYPOINT string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(host->entrypoint, "entrypoint");
|
2021-02-06 19:28:43 +01:00
|
|
|
while (*$2 == '/')
|
|
|
|
memmove($2, $2+1, strlen($2));
|
|
|
|
host->entrypoint = $2;
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TENV string string {
|
2021-06-11 17:49:46 +02:00
|
|
|
add_param($2, $3, 1);
|
2021-04-28 14:43:17 +02:00
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TKEY string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(host->key, "key");
|
|
|
|
host->key = ensure_absolute_path($2);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TPARAM string string {
|
2021-06-11 17:49:46 +02:00
|
|
|
add_param($2, $3, 0);
|
|
|
|
}
|
2021-01-24 15:11:40 +01:00
|
|
|
| locopt
|
|
|
|
;
|
|
|
|
|
|
|
|
locations : /* empty */
|
|
|
|
| locations location
|
|
|
|
;
|
|
|
|
|
2021-06-29 18:10:10 +02:00
|
|
|
location : TLOCATION { advance_loc(); } string '{' locopts '}' {
|
2021-02-10 17:37:08 +01:00
|
|
|
/* drop the starting '/' if any */
|
|
|
|
if (*$3 == '/')
|
|
|
|
memmove($3, $3+1, strlen($3));
|
|
|
|
loc->match = $3;
|
2021-01-24 15:11:40 +01:00
|
|
|
}
|
|
|
|
| error '}'
|
|
|
|
;
|
|
|
|
|
|
|
|
locopts : /* empty */
|
|
|
|
| locopts locopt
|
|
|
|
;
|
|
|
|
|
2021-02-09 23:38:10 +01:00
|
|
|
locopt : TAUTO TINDEX TBOOL { loc->auto_index = $3 ? 1 : -1; }
|
2021-06-29 18:10:10 +02:00
|
|
|
| TBLOCK TRETURN TNUM string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->block_fmt, "block");
|
2021-02-06 18:22:37 +01:00
|
|
|
loc->block_fmt = check_block_fmt($4);
|
|
|
|
loc->block_code = check_block_code($3);
|
|
|
|
}
|
|
|
|
| TBLOCK TRETURN TNUM {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->block_fmt, "block");
|
2021-02-06 18:22:37 +01:00
|
|
|
loc->block_fmt = xstrdup("temporary failure");
|
|
|
|
loc->block_code = check_block_code($3);
|
|
|
|
if ($3 >= 30 && $3 < 40)
|
|
|
|
yyerror("missing `meta' for block return %d", $3);
|
|
|
|
}
|
|
|
|
| TBLOCK {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->block_fmt, "block");
|
2021-02-06 18:22:37 +01:00
|
|
|
loc->block_fmt = xstrdup("temporary failure");
|
|
|
|
loc->block_code = 40;
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TDEFAULT TTYPE string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->default_mime, "default type");
|
2021-02-09 23:38:10 +01:00
|
|
|
loc->default_mime = $3;
|
|
|
|
}
|
2021-05-24 11:09:10 +02:00
|
|
|
| TFASTCGI fastcgi
|
2021-06-29 18:10:10 +02:00
|
|
|
| TINDEX string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->index, "index");
|
2021-02-09 23:38:10 +01:00
|
|
|
loc->index = $2;
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TLANG string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->lang, "lang");
|
2021-02-09 23:38:10 +01:00
|
|
|
loc->lang = $2;
|
|
|
|
}
|
2021-02-22 09:53:14 +01:00
|
|
|
| TLOG TBOOL { loc->disable_log = !$2; }
|
2021-06-29 18:10:10 +02:00
|
|
|
| TREQUIRE TCLIENT TCA string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->reqca, "require client ca");
|
2021-04-30 18:17:07 +02:00
|
|
|
ensure_absolute_path($4);
|
2021-02-09 23:30:04 +01:00
|
|
|
if ((loc->reqca = load_ca($4)) == NULL)
|
|
|
|
yyerror("couldn't load ca cert: %s", $4);
|
|
|
|
free($4);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TROOT string {
|
2021-05-03 18:11:28 +02:00
|
|
|
only_once(loc->dir, "root");
|
2021-04-30 19:16:34 +02:00
|
|
|
loc->dir = ensure_absolute_path($2);
|
|
|
|
}
|
2021-02-09 23:38:10 +01:00
|
|
|
| TSTRIP TNUM { loc->strip = check_strip_no($2); }
|
2021-01-15 10:17:43 +01:00
|
|
|
;
|
2021-01-27 17:45:45 +01:00
|
|
|
|
2021-06-29 18:10:10 +02:00
|
|
|
fastcgi : TSPAWN string {
|
2021-05-24 11:09:10 +02:00
|
|
|
only_oncei(loc->fcgi, "fastcgi");
|
|
|
|
loc->fcgi = fastcgi_conf(NULL, NULL, $2);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| string {
|
2021-05-24 11:09:10 +02:00
|
|
|
only_oncei(loc->fcgi, "fastcgi");
|
|
|
|
loc->fcgi = fastcgi_conf($1, NULL, NULL);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TTCP string TNUM {
|
2021-05-24 11:09:10 +02:00
|
|
|
char *c;
|
|
|
|
if (asprintf(&c, "%d", $3) == -1)
|
|
|
|
err(1, "asprintf");
|
|
|
|
only_oncei(loc->fcgi, "fastcgi");
|
|
|
|
loc->fcgi = fastcgi_conf($2, c, NULL);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TTCP string {
|
2021-05-24 11:09:10 +02:00
|
|
|
only_oncei(loc->fcgi, "fastcgi");
|
|
|
|
loc->fcgi = fastcgi_conf($2, xstrdup("9000"), NULL);
|
|
|
|
}
|
2021-06-29 18:10:10 +02:00
|
|
|
| TTCP string string {
|
2021-05-24 11:09:10 +02:00
|
|
|
only_oncei(loc->fcgi, "fastcgi");
|
|
|
|
loc->fcgi = fastcgi_conf($2, $3, NULL);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2021-01-27 17:45:45 +01:00
|
|
|
%%
|
|
|
|
|
2021-03-31 18:32:18 +02:00
|
|
|
static struct vhost *
|
|
|
|
new_vhost(void)
|
|
|
|
{
|
|
|
|
return xcalloc(1, sizeof(struct vhost));
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct location *
|
|
|
|
new_location(void)
|
|
|
|
{
|
2021-04-30 19:16:34 +02:00
|
|
|
struct location *l;
|
|
|
|
|
|
|
|
l = xcalloc(1, sizeof(*l));
|
|
|
|
l->dirfd = -1;
|
2021-05-09 20:23:36 +02:00
|
|
|
l->fcgi = -1;
|
2021-04-30 19:16:34 +02:00
|
|
|
return l;
|
2021-03-31 18:32:18 +02:00
|
|
|
}
|
|
|
|
|
2021-01-27 17:45:45 +01:00
|
|
|
void
|
2021-02-06 18:22:37 +01:00
|
|
|
yyerror(const char *msg, ...)
|
2021-01-27 17:45:45 +01:00
|
|
|
{
|
2021-02-06 18:22:37 +01:00
|
|
|
va_list ap;
|
|
|
|
|
2021-01-27 17:45:45 +01:00
|
|
|
goterror = 1;
|
2021-02-06 18:22:37 +01:00
|
|
|
|
|
|
|
va_start(ap, msg);
|
2021-06-16 16:51:57 +02:00
|
|
|
fprintf(stderr, "%s:%d: ", config_path, yylval.lineno);
|
2021-02-06 18:22:37 +01:00
|
|
|
vfprintf(stderr, msg, ap);
|
2021-02-07 19:08:50 +01:00
|
|
|
fprintf(stderr, "\n");
|
2021-02-06 18:22:37 +01:00
|
|
|
va_end(ap);
|
2021-01-27 17:45:45 +01:00
|
|
|
}
|
|
|
|
|
2021-06-16 16:43:16 +02:00
|
|
|
static struct keyword {
|
|
|
|
const char *word;
|
|
|
|
int token;
|
|
|
|
} keywords[] = {
|
|
|
|
{"alias", TALIAS},
|
|
|
|
{"auto", TAUTO},
|
|
|
|
{"block", TBLOCK},
|
|
|
|
{"ca", TCA},
|
|
|
|
{"cert", TCERT},
|
|
|
|
{"cgi", TCGI},
|
|
|
|
{"chroot", TCHROOT},
|
|
|
|
{"client", TCLIENT},
|
|
|
|
{"default", TDEFAULT},
|
|
|
|
{"entrypoint", TENTRYPOINT},
|
|
|
|
{"env", TENV},
|
|
|
|
{"fastcgi", TFASTCGI},
|
|
|
|
{"index", TINDEX},
|
|
|
|
{"ipv6", TIPV6},
|
|
|
|
{"key", TKEY},
|
|
|
|
{"lang", TLANG},
|
|
|
|
{"location", TLOCATION},
|
|
|
|
{"log", TLOG},
|
|
|
|
{"mime", TMIME},
|
|
|
|
{"param", TPARAM},
|
|
|
|
{"port", TPORT},
|
|
|
|
{"prefork", TPREFORK},
|
|
|
|
{"protocols", TPROTOCOLS},
|
|
|
|
{"require", TREQUIRE},
|
|
|
|
{"return", TRETURN},
|
|
|
|
{"root", TROOT},
|
|
|
|
{"server", TSERVER},
|
|
|
|
{"spawn", TSPAWN},
|
|
|
|
{"strip", TSTRIP},
|
|
|
|
{"tcp", TTCP},
|
|
|
|
{"type", TTYPE},
|
|
|
|
{"user", TUSER},
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Taken an adapted from doas' parse.y
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
yylex(void)
|
|
|
|
{
|
2021-06-29 14:17:40 +02:00
|
|
|
char buf[8096], *ebuf, *p, *str, *v, *val;
|
2021-06-16 16:43:16 +02:00
|
|
|
int c, quotes = 0, escape = 0, qpos = -1, nonkw = 0;
|
2021-06-29 14:17:40 +02:00
|
|
|
size_t i, len;
|
2021-06-16 16:43:16 +02:00
|
|
|
|
|
|
|
p = buf;
|
|
|
|
ebuf = buf + sizeof(buf);
|
|
|
|
|
|
|
|
repeat:
|
|
|
|
/* skip whitespace first */
|
|
|
|
for (c = getc(yyfp); isspace(c); c = getc(yyfp)) {
|
2021-06-16 16:51:57 +02:00
|
|
|
yylval.colno++;
|
2021-06-16 16:43:16 +02:00
|
|
|
if (c == '\n') {
|
2021-06-16 16:51:57 +02:00
|
|
|
yylval.lineno++;
|
|
|
|
yylval.colno = 0;
|
2021-06-16 16:43:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for special one-character constructions */
|
|
|
|
switch (c) {
|
|
|
|
case '{':
|
|
|
|
case '}':
|
|
|
|
return c;
|
|
|
|
case '#':
|
|
|
|
/* skip comments; NUL is allowed; no continuation */
|
|
|
|
while ((c = getc(yyfp)) != '\n')
|
|
|
|
if (c == EOF)
|
|
|
|
goto eof;
|
2021-06-16 16:51:57 +02:00
|
|
|
yylval.colno = 0;
|
|
|
|
yylval.lineno++;
|
2021-06-16 16:43:16 +02:00
|
|
|
goto repeat;
|
2021-06-29 14:17:40 +02:00
|
|
|
case '=':
|
|
|
|
return c;
|
2021-06-16 16:43:16 +02:00
|
|
|
case EOF:
|
|
|
|
goto eof;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parsing next word */
|
2021-06-16 16:51:57 +02:00
|
|
|
for (;; c = getc(yyfp), yylval.colno++) {
|
2021-06-16 16:43:16 +02:00
|
|
|
switch (c) {
|
|
|
|
case '\0':
|
|
|
|
yyerror("unallowed character NULL in column %d",
|
2021-06-16 16:51:57 +02:00
|
|
|
yylval.colno+1);
|
2021-06-16 16:43:16 +02:00
|
|
|
escape = 0;
|
|
|
|
continue;
|
|
|
|
case '\\':
|
|
|
|
escape = !escape;
|
|
|
|
if (escape)
|
|
|
|
continue;
|
|
|
|
break;
|
2021-06-29 14:17:40 +02:00
|
|
|
|
|
|
|
/* expand macros in-place */
|
|
|
|
case '$':
|
2021-06-29 18:35:06 +02:00
|
|
|
if (!escape && !quotes) {
|
2021-06-29 14:17:40 +02:00
|
|
|
v = p;
|
|
|
|
while (1) {
|
|
|
|
if ((c = getc(yyfp)) == EOF) {
|
|
|
|
yyerror("EOF during macro expansion");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (p + 1 >= ebuf - 1) {
|
|
|
|
yyerror("string too long");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (isalnum(c) || c == '_') {
|
|
|
|
*p++ = c;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p = v;
|
|
|
|
if ((val = symget(p)) == NULL) {
|
|
|
|
yyerror("macro '%s' not defined", v);
|
2021-06-29 18:35:06 +02:00
|
|
|
return TERR;
|
2021-06-29 14:17:40 +02:00
|
|
|
}
|
|
|
|
len = strlen(val);
|
|
|
|
if (p + len >= ebuf - 1) {
|
|
|
|
yyerror("after macro-expansion, "
|
|
|
|
"string too long");
|
2021-06-29 18:35:06 +02:00
|
|
|
return TERR;
|
2021-06-29 14:17:40 +02:00
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
strlcat(p, val, ebuf - p);
|
|
|
|
p += len;
|
2021-06-29 18:35:06 +02:00
|
|
|
nonkw = 1;
|
|
|
|
goto eow;
|
2021-06-29 14:17:40 +02:00
|
|
|
}
|
|
|
|
break;
|
2021-06-16 16:43:16 +02:00
|
|
|
case '\n':
|
|
|
|
if (quotes)
|
|
|
|
yyerror("unterminated quotes in column %d",
|
2021-06-16 16:51:57 +02:00
|
|
|
yylval.colno+1);
|
2021-06-16 16:43:16 +02:00
|
|
|
if (escape) {
|
|
|
|
nonkw = 1;
|
|
|
|
escape = 0;
|
2021-06-16 16:51:57 +02:00
|
|
|
yylval.colno = 0;
|
|
|
|
yylval.lineno++;
|
2021-06-16 16:43:16 +02:00
|
|
|
}
|
|
|
|
goto eow;
|
|
|
|
case EOF:
|
|
|
|
if (escape)
|
|
|
|
yyerror("unterminated escape in column %d",
|
2021-06-16 16:51:57 +02:00
|
|
|
yylval.colno);
|
2021-06-16 16:43:16 +02:00
|
|
|
if (quotes)
|
|
|
|
yyerror("unterminated quotes in column %d",
|
|
|
|
qpos+1);
|
|
|
|
goto eow;
|
|
|
|
case '{':
|
|
|
|
case '}':
|
|
|
|
case '#':
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
if (!escape && !quotes)
|
|
|
|
goto eow;
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
if (!escape) {
|
|
|
|
quotes = !quotes;
|
|
|
|
if (quotes) {
|
|
|
|
nonkw = 1;
|
2021-06-16 16:51:57 +02:00
|
|
|
qpos = yylval.colno;
|
2021-06-16 16:43:16 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*p++ = c;
|
|
|
|
if (p == ebuf) {
|
|
|
|
yyerror("line too long");
|
|
|
|
p = buf;
|
|
|
|
}
|
|
|
|
escape = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
eow:
|
|
|
|
*p = 0;
|
|
|
|
if (c != EOF)
|
|
|
|
ungetc(c, yyfp);
|
|
|
|
if (p == buf) {
|
|
|
|
/*
|
|
|
|
* There could be a number of reason for empty buffer,
|
|
|
|
* and we handle all of them here, to avoid cluttering
|
|
|
|
* the main loop.
|
|
|
|
*/
|
|
|
|
if (c == EOF)
|
|
|
|
goto eof;
|
|
|
|
else if (qpos == -1) /* accept, e.g., empty args: cmd foo args "" */
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
if (!nonkw) {
|
|
|
|
for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); ++i) {
|
|
|
|
if (!strcmp(buf, keywords[i].word))
|
|
|
|
return keywords[i].token;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c = *buf;
|
|
|
|
if (!nonkw && (c == '-' || isdigit(c))) {
|
2021-06-29 13:11:43 +02:00
|
|
|
yylval.v.num = parse_portno(buf);
|
2021-06-16 16:43:16 +02:00
|
|
|
return TNUM;
|
|
|
|
}
|
|
|
|
if (!nonkw && !strcmp(buf, "on")) {
|
2021-06-29 13:11:43 +02:00
|
|
|
yylval.v.num = 1;
|
2021-06-16 16:43:16 +02:00
|
|
|
return TBOOL;
|
|
|
|
}
|
|
|
|
if (!nonkw && !strcmp(buf, "off")) {
|
2021-06-29 13:11:43 +02:00
|
|
|
yylval.v.num = 0;
|
2021-06-16 16:43:16 +02:00
|
|
|
return TBOOL;
|
|
|
|
}
|
|
|
|
if ((str = strdup(buf)) == NULL)
|
|
|
|
err(1, "%s", __func__);
|
2021-06-29 13:11:43 +02:00
|
|
|
yylval.v.str = str;
|
2021-06-16 16:43:16 +02:00
|
|
|
return TSTRING;
|
|
|
|
|
|
|
|
eof:
|
|
|
|
if (ferror(yyfp))
|
|
|
|
yyerror("input error reading config");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-27 17:45:45 +01:00
|
|
|
int
|
|
|
|
parse_portno(const char *p)
|
|
|
|
{
|
|
|
|
const char *errstr;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = strtonum(p, 0, UINT16_MAX, &errstr);
|
|
|
|
if (errstr != NULL)
|
2021-02-10 14:13:17 +01:00
|
|
|
yyerror("port number is %s: %s", errstr, p);
|
2021-01-27 17:45:45 +01:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
parse_conf(const char *path)
|
|
|
|
{
|
2021-06-29 14:17:40 +02:00
|
|
|
struct sym *sym, *next;
|
|
|
|
|
2021-01-27 17:45:45 +01:00
|
|
|
config_path = path;
|
2021-06-16 16:43:16 +02:00
|
|
|
if ((yyfp = fopen(path, "r")) == NULL)
|
2021-04-28 14:43:17 +02:00
|
|
|
err(1, "cannot open config: %s", path);
|
2021-01-27 17:45:45 +01:00
|
|
|
yyparse();
|
2021-06-16 16:43:16 +02:00
|
|
|
fclose(yyfp);
|
2021-01-27 17:45:45 +01:00
|
|
|
|
|
|
|
if (goterror)
|
|
|
|
exit(1);
|
2021-03-31 18:32:18 +02:00
|
|
|
|
|
|
|
if (TAILQ_FIRST(&hosts)->domain == NULL)
|
2021-04-28 14:43:17 +02:00
|
|
|
errx(1, "no vhost defined in %s", path);
|
2021-06-29 14:17:40 +02:00
|
|
|
|
|
|
|
/* free unused macros */
|
|
|
|
TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
|
|
|
|
/* TODO: warn if !sym->used */
|
|
|
|
if (!sym->persist) {
|
|
|
|
free(sym->name);
|
|
|
|
free(sym->val);
|
|
|
|
TAILQ_REMOVE(&symhead, sym, entry);
|
|
|
|
free(sym);
|
|
|
|
}
|
|
|
|
}
|
2021-01-27 17:45:45 +01:00
|
|
|
}
|
2021-02-01 12:08:57 +01:00
|
|
|
|
|
|
|
char *
|
|
|
|
ensure_absolute_path(char *path)
|
|
|
|
{
|
|
|
|
if (path == NULL || *path != '/')
|
2021-04-30 18:17:07 +02:00
|
|
|
yyerror("not an absolute path: %s", path);
|
2021-02-01 12:08:57 +01:00
|
|
|
return path;
|
|
|
|
}
|
2021-02-06 18:22:37 +01:00
|
|
|
|
|
|
|
int
|
|
|
|
check_block_code(int n)
|
|
|
|
{
|
|
|
|
if (n < 10 || n >= 70 || (n >= 20 && n <= 29))
|
|
|
|
yyerror("invalid block code %d", n);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
check_block_fmt(char *fmt)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
for (s = fmt; *s; ++s) {
|
|
|
|
if (*s != '%')
|
|
|
|
continue;
|
|
|
|
switch (*++s) {
|
|
|
|
case '%':
|
|
|
|
case 'p':
|
|
|
|
case 'q':
|
|
|
|
case 'P':
|
|
|
|
case 'N':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
yyerror("invalid format specifier %%%c", *s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
check_strip_no(int n)
|
|
|
|
{
|
|
|
|
if (n <= 0)
|
|
|
|
yyerror("invalid strip number %d", n);
|
|
|
|
return n;
|
|
|
|
}
|
2021-02-07 13:05:32 +01:00
|
|
|
|
|
|
|
int
|
|
|
|
check_prefork_num(int n)
|
|
|
|
{
|
2021-03-03 18:22:01 +01:00
|
|
|
if (n <= 0 || n >= PROC_MAX)
|
2021-02-07 13:05:32 +01:00
|
|
|
yyerror("invalid prefork number %d", n);
|
|
|
|
return n;
|
|
|
|
}
|
2021-02-10 17:37:08 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
advance_loc(void)
|
|
|
|
{
|
2021-03-31 18:32:18 +02:00
|
|
|
loc = new_location();
|
|
|
|
TAILQ_INSERT_TAIL(&host->locations, loc, locations);
|
2021-02-10 17:37:08 +01:00
|
|
|
}
|
2021-05-03 18:11:28 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
only_once(const void *ptr, const char *name)
|
|
|
|
{
|
|
|
|
if (ptr != NULL)
|
|
|
|
yyerror("`%s' specified more than once", name);
|
|
|
|
}
|
2021-05-09 20:23:36 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
only_oncei(int i, const char *name)
|
|
|
|
{
|
|
|
|
if (i != -1)
|
|
|
|
yyerror("`%s' specified more than once", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fastcgi_conf(char *path, char *port, char *prog)
|
|
|
|
{
|
|
|
|
struct fcgi *f;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < FCGI_MAX; ++i) {
|
|
|
|
f = &fcgi[i];
|
2021-06-29 13:21:32 +02:00
|
|
|
|
2021-05-09 20:23:36 +02:00
|
|
|
if (f->path == NULL) {
|
|
|
|
f->id = i;
|
|
|
|
f->path = path;
|
|
|
|
f->port = port;
|
|
|
|
f->prog = prog;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: what to do with prog? */
|
|
|
|
if (!strcmp(f->path, path) &&
|
|
|
|
((port == NULL && f->port == NULL) ||
|
|
|
|
!strcmp(f->port, port))) {
|
|
|
|
free(path);
|
|
|
|
free(port);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
yyerror("too much `fastcgi' rules defined.");
|
|
|
|
return -1;
|
|
|
|
}
|
2021-06-11 17:49:46 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
add_param(char *name, char *val, int env)
|
|
|
|
{
|
|
|
|
struct envlist *e;
|
|
|
|
struct envhead *h;
|
|
|
|
|
|
|
|
if (env)
|
|
|
|
h = &host->env;
|
|
|
|
else
|
|
|
|
h = &host->params;
|
|
|
|
|
|
|
|
e = xcalloc(1, sizeof(*e));
|
|
|
|
e->name = name;
|
|
|
|
e->value = val;
|
|
|
|
if (TAILQ_EMPTY(h))
|
|
|
|
TAILQ_INSERT_HEAD(h, e, envs);
|
|
|
|
else
|
|
|
|
TAILQ_INSERT_TAIL(h, e, envs);
|
|
|
|
}
|
2021-06-29 14:17:40 +02:00
|
|
|
|
|
|
|
int
|
|
|
|
symset(const char *name, const char *val, int persist)
|
|
|
|
{
|
|
|
|
struct sym *sym;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(sym, &symhead, entry) {
|
|
|
|
if (!strcmp(name, sym->name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym != NULL) {
|
|
|
|
if (sym->persist)
|
|
|
|
return 0;
|
|
|
|
else {
|
|
|
|
free(sym->name);
|
|
|
|
free(sym->val);
|
|
|
|
TAILQ_REMOVE(&symhead, sym, entry);
|
|
|
|
free(sym);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sym = xcalloc(1, sizeof(*sym));
|
|
|
|
sym->name = xstrdup(name);
|
|
|
|
sym->val = xstrdup(val);
|
|
|
|
sym->used = 0;
|
|
|
|
sym->persist = persist;
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&symhead, sym, entry);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
cmdline_symset(char *s)
|
|
|
|
{
|
|
|
|
char *sym, *val;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((val = strrchr(s, '=')) == NULL)
|
|
|
|
return -1;
|
|
|
|
sym = xcalloc(1, val - s + 1);
|
|
|
|
memcpy(sym, s, val - s);
|
|
|
|
ret = symset(sym, val + 1, 1);
|
|
|
|
free(sym);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
symget(const char *name)
|
|
|
|
{
|
|
|
|
struct sym *sym;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(sym, &symhead, entry) {
|
|
|
|
if (!strcmp(name, sym->name)) {
|
|
|
|
sym->used = 1;
|
|
|
|
return sym->val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|