Browse Source

first cut at config file parser

for now, one can set the addresses to listen on
OPENBSD_3_6
henning 20 years ago
parent
commit
a241c3837c
6 changed files with 723 additions and 5 deletions
  1. +2
    -2
      src/usr.sbin/ntpd/Makefile
  2. +147
    -0
      src/usr.sbin/ntpd/config.c
  3. +17
    -1
      src/usr.sbin/ntpd/ntp.c
  4. +4
    -1
      src/usr.sbin/ntpd/ntpd.c
  5. +13
    -1
      src/usr.sbin/ntpd/ntpd.h
  6. +540
    -0
      src/usr.sbin/ntpd/parse.y

+ 2
- 2
src/usr.sbin/ntpd/Makefile View File

@ -1,9 +1,9 @@
# $OpenBSD: Makefile,v 1.2 2004/05/31 13:59:55 henning Exp $
# $OpenBSD: Makefile,v 1.3 2004/06/01 21:58:08 henning Exp $
.PATH: ${.CURDIR}/..
PROG= ntpd
SRCS= ntpd.c buffer.c log.c imsg.c ntp.c
SRCS= ntpd.c buffer.c log.c imsg.c ntp.c parse.y config.c
CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations


+ 147
- 0
src/usr.sbin/ntpd/config.c View File

@ -0,0 +1,147 @@
/* $OpenBSD: config.c,v 1.1 2004/06/01 21:58:08 henning Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* 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.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ntpd.h"
int host_v4(const char *, struct sockaddr *, u_int8_t *);
int host_v6(const char *, struct sockaddr *);
int
check_file_secrecy(int fd, const char *fname)
{
struct stat st;
if (fstat(fd, &st)) {
log_warn("cannot stat %s", fname);
return (-1);
}
if (st.st_uid != 0 && st.st_uid != getuid()) {
log_warnx("%s: owner not root or current user", fname);
return (-1);
}
if (st.st_mode & (S_IRWXG | S_IRWXO)) {
log_warnx("%s: group/world readable/writeable", fname);
return (-1);
}
return (0);
}
int
host(const char *s, struct sockaddr *sa, u_int8_t *len)
{
int done = 0;
int mask;
char *p, *q, *ps;
if ((p = strrchr(s, '/')) != NULL) {
errno = 0;
mask = strtol(p+1, &q, 0);
if (errno == ERANGE || !q || *q || mask > 128 || q == (p+1)) {
log_warnx("invalid netmask");
return (0);
}
if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
fatal("host: malloc");
strlcpy(ps, s, strlen(s) - strlen(p) + 1);
} else {
if ((ps = strdup(s)) == NULL)
fatal("host: strdup");
mask = 128;
}
/* IPv4 address? */
if (!done)
done = host_v4(s, sa, len);
/* IPv6 address? */
if (!done) {
done = host_v6(ps, sa);
*len = mask;
}
free(ps);
return (done);
}
int
host_v4(const char *s, struct sockaddr *sa, u_int8_t *len)
{
struct in_addr ina;
struct sockaddr_in *sa_in;
int bits = 32;
bzero(&ina, sizeof(struct in_addr));
if (strrchr(s, '/') != NULL) {
if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
return (0);
} else {
if (inet_pton(AF_INET, s, &ina) != 1)
return (0);
}
sa_in = (struct sockaddr_in *)sa;
sa_in->sin_len = sizeof(struct sockaddr_in);
sa_in->sin_family = AF_INET;
sa_in->sin_addr.s_addr = ina.s_addr;
*len = bits;
return (1);
}
int
host_v6(const char *s, struct sockaddr *sa)
{
struct addrinfo hints, *res;
struct sockaddr_in6 *sa_in6;
sa_in6 = (struct sockaddr_in6 *)sa;
sa_in6->sin6_len = sizeof(struct sockaddr_in6);
bzero(&hints, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(s, "0", &hints, &res) == 0) {
sa_in6->sin6_family = AF_INET6;
memcpy(&sa_in6->sin6_addr,
&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
sizeof(sa_in6->sin6_addr));
sa_in6->sin6_scope_id =
((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
freeaddrinfo(res);
return (1);
}
return (0);
}

+ 17
- 1
src/usr.sbin/ntpd/ntp.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntp.c,v 1.4 2004/06/01 16:27:09 henning Exp $ */
/* $OpenBSD: ntp.c,v 1.5 2004/06/01 21:58:08 henning Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -178,6 +178,22 @@ setup_listeners(struct servent *se, struct ntpd_conf *conf)
}
TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
switch (la->sa.ss_family) {
case AF_INET:
if (((struct sockaddr_in *)&la->sa)->sin_port == 0)
((struct sockaddr_in *)&la->sa)->sin_port =
se->s_port;
break;
case AF_INET6:
if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0)
((struct sockaddr_in6 *)&la->sa)->sin6_port =
se->s_port;
break;
default:
fatalx("king bula sez: af borked");
}
if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1)
fatal("socket");


+ 4
- 1
src/usr.sbin/ntpd/ntpd.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntpd.c,v 1.3 2004/06/01 16:27:09 henning Exp $ */
/* $OpenBSD: ntpd.c,v 1.4 2004/06/01 21:58:08 henning Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -108,6 +108,9 @@ main(int argc, char *argv[])
}
}
if (parse_config(conffile, &conf))
exit(1);
if (geteuid())
errx(1, "need root privileges");


+ 13
- 1
src/usr.sbin/ntpd/ntpd.h View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntpd.h,v 1.2 2004/06/01 16:27:09 henning Exp $ */
/* $OpenBSD: ntpd.h,v 1.3 2004/06/01 21:58:09 henning Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -28,6 +28,9 @@
#define READ_BUF_SIZE 65535
#define NTPD_OPT_VERBOSE 0x0001
#define NTPD_OPT_VERBOSE2 0x0002
struct listen_addr {
TAILQ_ENTRY(listen_addr) entry;
struct sockaddr_storage sa;
@ -36,6 +39,7 @@ struct listen_addr {
struct ntpd_conf {
TAILQ_HEAD(listen_addrs, listen_addr) listen_addrs;
u_int8_t opts;
};
struct buf {
@ -120,3 +124,11 @@ void imsg_free(struct imsg *);
/* ntp.c */
pid_t ntp_main(int[2], struct ntpd_conf *);
/* parse.y */
int parse_config(char *, struct ntpd_conf *);
int cmdline_symset(char *);
/* config.c */
int check_file_secrecy(int, const char *);
int host(const char *, struct sockaddr *, u_int8_t *);

+ 540
- 0
src/usr.sbin/ntpd/parse.y View File

@ -0,0 +1,540 @@
/* $OpenBSD: parse.y,v 1.1 2004/06/01 21:58:09 henning Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
* Copyright (c) 2001 Theo de Raadt. All rights reserved.
*
* 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.
*/
%{
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include "ntpd.h"
static struct ntpd_conf *conf;
static FILE *fin = NULL;
static int lineno = 1;
static int errors = 0;
static int pdebug = 1;
char *infile;
int yyerror(const char *, ...);
int yyparse(void);
int kw_cmp(const void *, const void *);
int lookup(char *);
int lgetc(FILE *);
int lungetc(int);
int findeol(void);
int yylex(void);
TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
struct sym {
TAILQ_ENTRY(sym) entries;
int used;
int persist;
char *nam;
char *val;
};
int symset(const char *, const char *, int);
char *symget(const char *);
int atoul(char *, u_long *);
typedef struct {
union {
u_int32_t number;
char *string;
struct sockaddr_storage ss;
} v;
int lineno;
} YYSTYPE;
%}
%token LISTEN ON
%token ERROR
%token <v.string> STRING
%type <v.number> number
%type <v.string> string
%type <v.ss> address
%%
grammar : /* empty */
| grammar '\n'
| grammar conf_main '\n'
| grammar varset '\n'
| grammar error '\n' { errors++; }
;
number : STRING {
u_long ulval;
if (atoul($1, &ulval) == -1) {
yyerror("\"%s\" is not a number", $1);
free($1);
YYERROR;
} else
$$ = ulval;
free($1);
}
;
string : string STRING {
if (asprintf(&$$, "%s %s", $1, $2) == -1)
fatal("string: asprintf");
free($1);
free($2);
}
| STRING
;
varset : STRING '=' string {
if (conf->opts & NTPD_OPT_VERBOSE)
printf("%s = \"%s\"\n", $1, $3);
if (symset($1, $3, 0) == -1)
fatal("cannot store variable");
free($1);
free($3);
}
;
conf_main : LISTEN ON address {
struct listen_addr *la;
if ((la = calloc(1, sizeof(struct listen_addr))) ==
NULL)
fatal("parse conf_main listen on calloc");
memcpy(&la->sa, &$3, sizeof(struct sockaddr_storage));
TAILQ_INSERT_TAIL(&conf->listen_addrs, la, entry);
}
;
address : STRING {
u_int8_t len;
bzero(&$$, sizeof($$));
if (!host($1, (struct sockaddr *)&$$, &len)) {
yyerror("could not parse address spec \"%s\"",
$1);
free($1);
YYERROR;
}
free($1);
if (($$.ss_family == AF_INET && len != 32) ||
($$.ss_family == AF_INET6 && len != 128)) {
/* unreachable */
yyerror("got prefixlen %u, expected %u",
len, $$.ss_family == AF_INET ? 32 : 128);
YYERROR;
}
}
;
%%
struct keywords {
const char *k_name;
int k_val;
};
int
yyerror(const char *fmt, ...)
{
va_list ap;
char *nfmt;
errors = 1;
va_start(ap, fmt);
if (asprintf(&nfmt, "%s:%d: %s", infile, yylval.lineno, fmt) == -1)
fatalx("yyerror asprintf");
vlog(LOG_CRIT, nfmt, ap);
va_end(ap);
free(nfmt);
return (0);
}
int
kw_cmp(const void *k, const void *e)
{
return (strcmp(k, ((const struct keywords *)e)->k_name));
}
int
lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
{ "listen", LISTEN},
{ "on", ON}
};
const struct keywords *p;
p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
sizeof(keywords[0]), kw_cmp);
if (p) {
if (pdebug > 1)
fprintf(stderr, "%s: %d\n", s, p->k_val);
return (p->k_val);
} else {
if (pdebug > 1)
fprintf(stderr, "string: %s\n", s);
return (STRING);
}
}
#define MAXPUSHBACK 128
char *parsebuf;
int parseindex;
char pushback_buffer[MAXPUSHBACK];
int pushback_index = 0;
int
lgetc(FILE *f)
{
int c, next;
if (parsebuf) {
/* Read character from the parsebuffer instead of input. */
if (parseindex >= 0) {
c = parsebuf[parseindex++];
if (c != '\0')
return (c);
parsebuf = NULL;
} else
parseindex++;
}
if (pushback_index)
return (pushback_buffer[--pushback_index]);
while ((c = getc(f)) == '\\') {
next = getc(f);
if (next != '\n') {
if (isspace(next))
yyerror("whitespace after \\");
ungetc(next, f);
break;
}
yylval.lineno = lineno;
lineno++;
}
if (c == '\t' || c == ' ') {
/* Compress blanks to a single space. */
do {
c = getc(f);
} while (c == '\t' || c == ' ');
ungetc(c, f);
c = ' ';
}
return (c);
}
int
lungetc(int c)
{
if (c == EOF)
return (EOF);
if (parsebuf) {
parseindex--;
if (parseindex >= 0)
return (c);
}
if (pushback_index < MAXPUSHBACK-1)
return (pushback_buffer[pushback_index++] = c);
else
return (EOF);
}
int
findeol(void)
{
int c;
parsebuf = NULL;
pushback_index = 0;
/* skip to either EOF or the first real EOL */
while (1) {
c = lgetc(fin);
if (c == '\n') {
lineno++;
break;
}
if (c == EOF)
break;
}
return (ERROR);
}
int
yylex(void)
{
char buf[8096];
char *p, *val;
int endc, c;
int token;
top:
p = buf;
while ((c = lgetc(fin)) == ' ')
; /* nothing */
yylval.lineno = lineno;
if (c == '#')
while ((c = lgetc(fin)) != '\n' && c != EOF)
; /* nothing */
if (c == '$' && parsebuf == NULL) {
while (1) {
if ((c = lgetc(fin)) == EOF)
return (0);
if (p + 1 >= buf + sizeof(buf) - 1) {
yyerror("string too long");
return (findeol());
}
if (isalnum(c) || c == '_') {
*p++ = (char)c;
continue;
}
*p = '\0';
lungetc(c);
break;
}
val = symget(buf);
if (val == NULL) {
yyerror("macro \"%s\" not defined", buf);
return (findeol());
}
parsebuf = val;
parseindex = 0;
goto top;
}
switch (c) {
case '\'':
case '"':
endc = c;
while (1) {
if ((c = lgetc(fin)) == EOF)
return (0);
if (c == endc) {
*p = '\0';
break;
}
if (c == '\n') {
lineno++;
continue;
}
if (p + 1 >= buf + sizeof(buf) - 1) {
yyerror("string too long");
return (findeol());
}
*p++ = (char)c;
}
yylval.v.string = strdup(buf);
if (yylval.v.string == NULL)
fatal("yylex: strdup");
return (STRING);
}
#define allowed_in_string(x) \
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
x != '{' && x != '}' && x != '<' && x != '>' && \
x != '!' && x != '=' && x != '/' && x != '#' && \
x != ','))
if (isalnum(c) || c == ':' || c == '_' || c == '*') {
do {
*p++ = c;
if ((unsigned)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
lungetc(c);
*p = '\0';
if ((token = lookup(buf)) == STRING)
if ((yylval.v.string = strdup(buf)) == NULL)
fatal("yylex: strdup");
return (token);
}
if (c == '\n') {
yylval.lineno = lineno;
lineno++;
}
if (c == EOF)
return (0);
return (c);
}
int
parse_config(char *filename, struct ntpd_conf *xconf)
{
struct sym *sym, *next;
struct listen_addr *la;
if ((conf = calloc(1, sizeof(struct ntpd_conf))) == NULL)
fatal(NULL);
lineno = 1;
errors = 0;
TAILQ_INIT(&conf->listen_addrs);
if ((fin = fopen(filename, "r")) == NULL) {
log_warn("%s", filename);
free(conf);
return (-1);
}
infile = filename;
yyparse();
fclose(fin);
/* Free macros and check which have not been used. */
for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
next = TAILQ_NEXT(sym, entries);
if ((conf->opts & NTPD_OPT_VERBOSE2) && !sym->used)
fprintf(stderr, "warning: macro \"%s\" not "
"used\n", sym->nam);
if (!sym->persist) {
free(sym->nam);
free(sym->val);
TAILQ_REMOVE(&symhead, sym, entries);
free(sym);
}
}
while ((la = TAILQ_FIRST(&xconf->listen_addrs)) != NULL) {
TAILQ_REMOVE(&xconf->listen_addrs, la, entry);
free(la);
}
while ((la = TAILQ_FIRST(&conf->listen_addrs)) != NULL) {
TAILQ_REMOVE(&conf->listen_addrs, la, entry);
TAILQ_INSERT_TAIL(&xconf->listen_addrs, la, entry);
}
free(conf);
return (errors ? -1 : 0);
}
int
symset(const char *nam, const char *val, int persist)
{
struct sym *sym;
for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
sym = TAILQ_NEXT(sym, entries))
; /* nothing */
if (sym != NULL) {
if (sym->persist == 1)
return (0);
else {
free(sym->nam);
free(sym->val);
TAILQ_REMOVE(&symhead, sym, entries);
free(sym);
}
}
if ((sym = calloc(1, sizeof(*sym))) == NULL)
return (-1);
sym->nam = strdup(nam);
if (sym->nam == NULL) {
free(sym);
return (-1);
}
sym->val = strdup(val);
if (sym->val == NULL) {
free(sym->nam);
free(sym);
return (-1);
}
sym->used = 0;
sym->persist = persist;
TAILQ_INSERT_TAIL(&symhead, sym, entries);
return (0);
}
int
cmdline_symset(char *s)
{
char *sym, *val;
int ret;
size_t len;
if ((val = strrchr(s, '=')) == NULL)
return (-1);
len = strlen(s) - strlen(val) + 1;
if ((sym = malloc(len)) == NULL)
fatal("cmdline_symset: malloc");
strlcpy(sym, s, len);
ret = symset(sym, val + 1, 1);
free(sym);
return (ret);
}
char *
symget(const char *nam)
{
struct sym *sym;
TAILQ_FOREACH(sym, &symhead, entries)
if (strcmp(nam, sym->nam) == 0) {
sym->used = 1;
return (sym->val);
}
return (NULL);
}
int
atoul(char *s, u_long *ulvalp)
{
u_long ulval;
char *ep;
errno = 0;
ulval = strtoul(s, &ep, 0);
if (s[0] == '\0' || *ep != '\0')
return (-1);
if (errno == ERANGE && ulval == ULONG_MAX)
return (-1);
*ulvalp = ulval;
return (0);
}

Loading…
Cancel
Save