diff options
author | Hakan Olsson <ho@cvs.openbsd.org> | 2005-04-03 17:19:27 +0000 |
---|---|---|
committer | Hakan Olsson <ho@cvs.openbsd.org> | 2005-04-03 17:19:27 +0000 |
commit | 3edfba4e92c860e5173084d804678f462b212ef9 (patch) | |
tree | 8cadf19e0fd19b62709715d9dcbafa22567bb094 | |
parent | 587064c5ab03932c985fba57939042fee76aeef8 (diff) |
yacc parser
-rw-r--r-- | usr.sbin/sasyncd/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/sasyncd/conf.c | 280 | ||||
-rw-r--r-- | usr.sbin/sasyncd/conf.y | 340 | ||||
-rw-r--r-- | usr.sbin/sasyncd/sasyncd.h | 4 |
4 files changed, 348 insertions, 283 deletions
diff --git a/usr.sbin/sasyncd/Makefile b/usr.sbin/sasyncd/Makefile index 617d4c14740..5f7a8af1d14 100644 --- a/usr.sbin/sasyncd/Makefile +++ b/usr.sbin/sasyncd/Makefile @@ -1,10 +1,13 @@ -# $Id: Makefile,v 1.1 2005/03/30 18:44:49 ho Exp $ +# $Id: Makefile,v 1.2 2005/04/03 17:19:26 ho Exp $ PROG= sasyncd -SRCS= sasyncd.c carp.c conf.c log.c net.c net_ctl.c net_ssl.c \ +SRCS= sasyncd.c carp.c conf.y log.c net.c net_ctl.c net_ssl.c \ pfkey.c timer.c MAN= sasyncd.8 sasyncd.conf.5 +CFLAGS+= -I${.CURDIR} +CLEANFILES= y.tab.h + # ElectricFence #LDADD+= -L/usr/local/lib -lefence diff --git a/usr.sbin/sasyncd/conf.c b/usr.sbin/sasyncd/conf.c deleted file mode 100644 index 921569d8b3e..00000000000 --- a/usr.sbin/sasyncd/conf.c +++ /dev/null @@ -1,280 +0,0 @@ -/* $OpenBSD: conf.c,v 1.2 2005/03/30 18:56:19 ho Exp $ */ - -/* - * Copyright (c) 2005 Håkan Olsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This code was written under funding by Multicom Security AB. - */ - - -#include <sys/types.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "sasyncd.h" -#include "net.h" - -/* Global configuration context. */ -struct cfgstate cfgstate; - -static int -conf_parse_file(char *cfgfile) -{ - struct syncpeer *peer; - FILE *fp = fopen(cfgfile, "r"); - int lineno = 0, dup; - char linebuf[1024], name[1024], *p; - - if (!fp) { - log_err("failed to open \"%s\"", cfgfile); - return 1; - } - - while(fgets(linebuf, sizeof linebuf, fp)) { - lineno++; - - /* Strip comments and remove \n. */ - for (p = linebuf; *p; p++) - if (*p == '\n' || *p == '#') { - *p = 0; - break; - } - - if (*linebuf == 0) - continue; - - if (sscanf(linebuf, "listen on %1023s", name) == 1) { - if (cfgstate.listen_on) - free(cfgstate.listen_on); - cfgstate.listen_on = strdup(name); - if (!cfgstate.listen_on) { - log_err("config: strdup() failed"); - goto bad; - } - log_msg(2, "config(line %02d): listen on %s", lineno, - cfgstate.listen_on); - continue; - } - - if (sscanf(linebuf, "listen port %1023s", name) == 1) { - cfgstate.listen_port = atoi(name); - if (cfgstate.listen_port < 1 || - cfgstate.listen_port > 65534) { - cfgstate.listen_port = SASYNCD_DEFAULT_PORT; - log_msg(0, "config: bad value line %d, " - "listen-port reset to %u", lineno, - SASYNCD_DEFAULT_PORT); - } else - log_msg(2, "config(line %02d): listen port %u", - cfgstate.listen_port); - continue; - } - - if (sscanf(linebuf, "peer %1023s", name) == 1) { - dup = 0; - for (peer = LIST_FIRST(&cfgstate.peerlist); peer; - peer = LIST_NEXT(peer, link)) - if (strcmp(name, peer->name) == 0) { - dup++; - break; - } - if (dup) - continue; - peer = (struct syncpeer *)calloc(1, sizeof *peer); - if (!peer) { - log_err("config: calloc(1, %lu) failed", - sizeof *peer); - goto bad; - } - peer->name = strdup(name); - if (!peer->name) { - log_err("config: strdup() failed"); - goto bad; - } - LIST_INSERT_HEAD(&cfgstate.peerlist, peer, link); - log_msg(2, "config(line %02d): add peer %s", lineno, - peer->name); - continue; - } - - if (sscanf(linebuf, "carp interface %1023s", name) == 1) { - if (cfgstate.carp_ifname) - free(cfgstate.carp_ifname); - cfgstate.carp_ifname = strdup(name); - if (!cfgstate.carp_ifname) { - log_err("config: strdup failed"); - goto bad; - } - log_msg(2, "config(line %02d): carp interface %s", - lineno, cfgstate.carp_ifname); - continue; - } - - if (sscanf(linebuf, "carp interval %1023s", name) == 1) { - cfgstate.carp_check_interval = atoi(name); - if (cfgstate.carp_check_interval < 1) { - cfgstate.carp_check_interval = - CARP_DEFAULT_INTERVAL; - log_msg(0, "config: bad value line %d, " - "carp-interval reset to %d", lineno, - CARP_DEFAULT_INTERVAL); - } else - log_msg(2, "config(line %02d): carp interval " - "%d", lineno, - cfgstate.carp_check_interval); - continue; - } - - if (sscanf(linebuf, "CAcertificate file %1023s", name) == 1) { - if (cfgstate.cafile) - free(cfgstate.cafile); - cfgstate.cafile = strdup(name); - if (!cfgstate.cafile) { - log_err("config: strdup failed"); - goto bad; - } - log_msg(2, "config(line %02d): CAcertificate file $s", - lineno, cfgstate.cafile); - continue; - } - - if (sscanf(linebuf, "certificate file %1023s", name) == 1) { - if (cfgstate.certfile) - free(cfgstate.certfile); - cfgstate.certfile = strdup(name); - if (!cfgstate.certfile) { - log_err("config: strdup failed"); - goto bad; - } - log_msg(2, "config(line %02d): certificate file $s", - lineno, cfgstate.certfile); - continue; - } - - if (sscanf(linebuf, "private key file %1023s", name) == 1) { - if (cfgstate.privkeyfile) - free(cfgstate.privkeyfile); - cfgstate.privkeyfile = strdup(name); - if (!cfgstate.privkeyfile) { - log_err("config: strdup failed"); - goto bad; - } - log_msg(2, "config(line %02d): private key file $s", - lineno, cfgstate.privkeyfile); - continue; - } - - if (sscanf(linebuf, "run as %1023s", name) == 1) { - if (strcasecmp(name, "SLAVE") == 0) - cfgstate.lockedstate = SLAVE; - else if (strcasecmp(name, "MASTER") == 0) - cfgstate.lockedstate = MASTER; - else { - log_msg(0, "config(line %02d): unknown state " - "%s", lineno, name); - goto bad; - } - log_msg(2, "config(line %02d): runstate locked to %s", - lineno, cfgstate.lockedstate == MASTER ? "MASTER" : - "SLAVE"); - continue; - } - } - - /* Sanity checks. */ - if (LIST_EMPTY(&cfgstate.peerlist)) { - log_msg(0, "config: no peers defined"); - goto bad; - } - - if (!cfgstate.carp_ifname && cfgstate.lockedstate == INIT) { - log_msg(0, "config: no carp interface or runstate defined"); - goto bad; - } - - /* Success. */ - fclose(fp); - return 0; - - bad: - fclose(fp); - return 1; -} - -int -conf_init(int argc, char **argv) -{ - char *cfgfile = 0; - int ch; - - memset(&cfgstate, 0, sizeof cfgstate); - cfgstate.runstate = INIT; - LIST_INIT(&cfgstate.peerlist); - - cfgstate.carp_check_interval = CARP_DEFAULT_INTERVAL; - cfgstate.listen_port = SASYNCD_DEFAULT_PORT; - - while ((ch = getopt(argc, argv, "c:dv")) != -1) { - switch (ch) { - case 'c': - if (cfgfile) - return 2; - cfgfile = optarg; - break; - case 'd': - cfgstate.debug++; - break; - case 'v': - cfgstate.verboselevel++; - break; - default: - return 2; - } - } - argc -= optind; - argv += optind; - - if (argc > 0) - return 2; - - if (!cfgfile) - cfgfile = SASYNCD_CFGFILE; - - if (conf_parse_file(cfgfile) == 0) { - if (!cfgstate.certfile) - cfgstate.certfile = SASYNCD_CERTFILE; - if (!cfgstate.privkeyfile) - cfgstate.privkeyfile = SASYNCD_PRIVKEY; - if (!cfgstate.cafile) - cfgstate.cafile = SASYNCD_CAFILE; - return 0; - } else - return 1; -} diff --git a/usr.sbin/sasyncd/conf.y b/usr.sbin/sasyncd/conf.y new file mode 100644 index 00000000000..419e928c4af --- /dev/null +++ b/usr.sbin/sasyncd/conf.y @@ -0,0 +1,340 @@ +/* $OpenBSD: conf.y,v 1.1 2005/04/03 17:19:26 ho Exp $ */ + +/* + * Copyright (c) 2005 Håkan Olsson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Definitions */ +%{ +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include "sasyncd.h" +#include "net.h" + +/* Global configuration context. */ +struct cfgstate cfgstate; + +struct syncpeer *peer; +int conflen = 0; +char *confbuf, *confptr; + +int yyparse(void); +int yylex(void); +void yyerror(const char *); +%} + +%union { + char *string; + int val; +} + +%token MODE CARP INTERFACE INTERVAL LISTEN ON PORT PEER SHAREDKEY +%token Y_SLAVE Y_MASTER +%token <string> STRING +%token <val> VALUE + +%% +/* Rules */ + +settings : /* empty */ + | settings setting + ; + +setting : CARP INTERFACE STRING + { + if (cfgstate.carp_ifname) + free(cfgstate.carp_ifname); + cfgstate.carp_ifname = $3; + log_msg(2, "config: carp interface %s", $3); + } + | CARP INTERVAL VALUE + { + cfgstate.carp_check_interval = $3; + log_msg(2, "config: carp interval %d", $3); + } + | PEER STRING + { + int dup = 0; + for (peer = LIST_FIRST(&cfgstate.peerlist); peer; + peer = LIST_NEXT(peer, link)) + if (strcmp($2, peer->name) == 0) { + dup++; + break; + } + if (dup) + free($2); + else { + peer = (struct syncpeer *)calloc(1, + sizeof *peer); + if (!peer) { + log_err("config: calloc(1, %lu) " + "failed", sizeof *peer); + YYERROR; + } + peer->name = $2; + } + LIST_INSERT_HEAD(&cfgstate.peerlist, peer, link); + log_msg(2, "config: add peer %s", peer->name); + } + | LISTEN ON STRING + { + if (cfgstate.listen_on) + free(cfgstate.listen_on); + cfgstate.listen_on = $3; + log_msg(2, "config: listen on %s", cfgstate.listen_on); + } + | LISTEN PORT VALUE + { + cfgstate.listen_port = $3; + if (cfgstate.listen_port < 1 || + cfgstate.listen_port > 65534) { + cfgstate.listen_port = SASYNCD_DEFAULT_PORT; + log_msg(0, "config: bad port, listen-port " + "reset to %u", SASYNCD_DEFAULT_PORT); + } else + log_msg(2, "config: listen port %u", + cfgstate.listen_port); + } + | MODE Y_MASTER + { + cfgstate.lockedstate = MASTER; + log_msg(2, "config: mode set to MASTER"); + } + | MODE Y_SLAVE + { + cfgstate.lockedstate = SLAVE; + log_msg(2, "config: mode set to SLAVE"); + } + | SHAREDKEY STRING + { + if (cfgstate.sharedkey) + free(cfgstate.sharedkey); + cfgstate.sharedkey = $2; + log_msg(2, "config: shared key set"); + } + ; + +%% +/* Program */ + +struct keyword { + char *name; + int value; +}; + +static int +match_cmp(const void *a, const void *b) +{ + return strcmp(a, ((const struct keyword *)b)->name); +} + +static int +match(char *token) +{ + /* Sorted */ + static const struct keyword keywords[] = { + { "carp", CARP }, + { "interface", INTERFACE }, + { "interval", INTERVAL }, + { "listen", LISTEN }, + { "master", Y_MASTER }, + { "mode", MODE }, + { "on", ON }, + { "peer", PEER }, + { "port", PORT }, + { "sharedkey", SHAREDKEY }, + { "slave", Y_SLAVE }, + }; + + const struct keyword *k; + + k = bsearch(token, keywords, sizeof keywords / sizeof keywords[0], + sizeof keywords[0], match_cmp); + + return k ? k->value : STRING; +} + +int +yylex(void) +{ + char *p; + int v; + + /* Locate next token */ + if (!confptr) + confptr = confbuf; + else { + for (p = confptr; *p && p < confbuf + conflen; p++) + ; + *p++; + if (!*p) + return 0; + confptr = p; + } + + /* Numerical token? */ + if (isdigit(*confptr)) { + for (p = confptr; *p; p++) + if (*p == '.') /* IP-address, or bad input */ + goto is_string; + v = (int)strtol(confptr, (char **)NULL, 10); + yylval.val = v; + return VALUE; + } + + is_string: + v = match(confptr); + if (v == STRING) { + yylval.string = strdup(confptr); + if (!yylval.string) { + log_err("yylex: strdup()"); + exit(1); + } + } + return v; +} + +static int +conf_parse_file(char *cfgfile) +{ + struct stat st; + int fd, r; + char *buf, *s, *d; + + if (stat(cfgfile, &st) != 0) + goto bad; + + fd = open(cfgfile, O_RDONLY, 0); + if (fd < 0) + goto bad; + + conflen = st.st_size; + buf = (char *)malloc(conflen + 1); + if (!buf) { + log_err("malloc(%d) failed", conflen + 1); + close(fd); + return 1; + } + + if (read(fd, buf, conflen) != conflen) { + log_err("read() failed"); + free(buf); + close(fd); + return 1; + } + close(fd); + + /* Prepare the buffer somewhat in the way of strsep() */ + buf[conflen] = (char)0; + for (s = buf, d = s; *s && s < buf + conflen; s++) { + if (isspace(*s) && isspace(*(s+1))) + continue; + if (*s == '#') { + while (*s != '\n' && s < buf + conflen) + s++; + continue; + } + if (d == buf && isspace(*s)) + continue; + *d++ = *s; + } + *d = (char)0; + for (s = buf; s <= d; s++) + if (isspace(*s)) + *s = (char)0; + + confbuf = buf; + confptr = NULL; + r = yyparse(); + free(buf); + + return r; + + bad: + log_err("failed to open \"%s\"", cfgfile); + return 1; +} + +int +conf_init(int argc, char **argv) +{ + char *cfgfile = 0; + int ch; + + memset(&cfgstate, 0, sizeof cfgstate); + cfgstate.runstate = INIT; + LIST_INIT(&cfgstate.peerlist); + + cfgstate.carp_check_interval = CARP_DEFAULT_INTERVAL; + cfgstate.listen_port = SASYNCD_DEFAULT_PORT; + + while ((ch = getopt(argc, argv, "c:dv")) != -1) { + switch (ch) { + case 'c': + if (cfgfile) + return 2; + cfgfile = optarg; + break; + case 'd': + cfgstate.debug++; + break; + case 'v': + cfgstate.verboselevel++; + break; + default: + return 2; + } + } + argc -= optind; + argv += optind; + + if (argc > 0) + return 2; + + if (!cfgfile) + cfgfile = SASYNCD_CFGFILE; + + if (conf_parse_file(cfgfile) == 0) { + if (!cfgstate.certfile) + cfgstate.certfile = SASYNCD_CERTFILE; + if (!cfgstate.privkeyfile) + cfgstate.privkeyfile = SASYNCD_PRIVKEY; + if (!cfgstate.cafile) + cfgstate.cafile = SASYNCD_CAFILE; + return 0; + } + + return 1; +} + +void +yyerror(const char *s) +{ + fprintf(stderr, "config: %s\n", s); +} diff --git a/usr.sbin/sasyncd/sasyncd.h b/usr.sbin/sasyncd/sasyncd.h index aa37ff3c161..f1d6c8f3ef6 100644 --- a/usr.sbin/sasyncd/sasyncd.h +++ b/usr.sbin/sasyncd/sasyncd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sasyncd.h,v 1.1 2005/03/30 18:44:49 ho Exp $ */ +/* $OpenBSD: sasyncd.h,v 1.2 2005/04/03 17:19:26 ho Exp $ */ /* * Copyright (c) 2005 Håkan Olsson. All rights reserved. @@ -51,6 +51,8 @@ struct cfgstate { char *certfile; char *privkeyfile; + char *sharedkey; + int pfkey_socket; char *listen_on; |