From: Jonathan McDowell Date: Tue, 7 Jun 2016 11:23:18 +0000 (+0100) Subject: Change config format to a cleaner .ini style X-Git-Tag: onak-0.5.0~30 X-Git-Url: http://the.earth.li/gitweb/?p=onak.git;a=commitdiff_plain;h=d4aa4e6ee07db203ef2a456a2afb9be52da8067c Change config format to a cleaner .ini style onak's config file format grew from the pksd config style. pksd is long obsolete and there are a number of features it would be nice to support in onak which this config format makes hard to support cleanly. Move to a .ini style config file, with [section] and name=value definitions. The old format is still supported and at present an old style config is searched for first to ensure smooth upgrades, but any new config options will only be supported by the new style. Additionally add tests against both old + new config styles for all backends. --- diff --git a/.gitignore b/.gitignore index b313628..5fbef4f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ keyd keydctl maxpath onak-mail.pl -onak.conf +onak.ini sixdegrees splitkeys stripkey diff --git a/Makefile.in b/Makefile.in index 08a06bf..28e93c9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -52,13 +52,13 @@ endif OBJS = stats.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ) -all: .depend $(PROGS) testparse maxpath sixdegrees splitkeys onak.conf \ +all: .depend $(PROGS) testparse maxpath sixdegrees splitkeys onak.ini \ wotsap $(BACKENDS) test: onak $(BACKENDS) @./runtests -install: $(PROGS) onak.conf $(BACKENDS) +install: $(PROGS) onak.ini $(BACKENDS) install -d $(DESTDIR)/@bindir@ install -d $(DESTDIR)/@libdir@/onak/backends install -d $(DESTDIR)/@localstatedir@/lib/onak @@ -142,7 +142,7 @@ onak: onak.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ) $(CORE_OBJS) $(KEYDB_OBJ) $(LIBS) $(PROGS_LDFLAGS_EXTRA) onak-conf.o: onak-conf.c onak-conf.h - $(CC) $(CFLAGS) -DCONFIGFILE=\"@sysconfdir@/onak.conf\" \ + $(CC) $(CFLAGS) -DCONFIGDIR=\"@sysconfdir@\" \ -DDBINIT=keydb_@DBTYPE@_init -c onak-conf.c # HACK: onak-conf.o needs to be able to see keydb_@DBTYPE@_funcs, but @@ -152,7 +152,8 @@ keydctl.o: keydctl.c keyd.h %: %.in sed -e 's:@BINDIR@:@bindir@:g' \ - -e 's:@CONFIG@:@sysconfdir@/onak.conf:g' \ + -e 's:@CONFIG@:@sysconfdir@/onak.ini:g' \ + -e 's:@CONFIGOLD@:@sysconfdir@/onak.conf:g' \ -e 's:@LIBDIR@:@libdir@:g' \ -e 's:@RUNDIR@:@runstatedir@:g' \ -e 's:@SBINDIR@:@sbindir@:g' \ @@ -162,7 +163,7 @@ keydctl.o: keydctl.c keyd.h clean: $(RM) $(PROGS) $(OBJS) Makefile.bak testparse maxpath *.core core \ gpgwww.o add.o lookup.o main.o maxpath.o onak.o sixdegrees \ - sixdegrees.o splitkeys.o stripkey.o onak.conf keyd.o \ + sixdegrees.o splitkeys.o stripkey.o onak.ini keyd.o \ keydctl.o hashquery.o wotsap.o version.h \ TAGS cscope.out cscope.files \ $(foreach be,@BACKENDS@,keydb_$(be).o) *.so diff --git a/README b/README index 420295d..a8e17eb 100644 --- a/README +++ b/README @@ -54,10 +54,10 @@ Once make has completed you'll end up with various binaries: Config: -I've finally added config file support. onak.conf is an example config; -the main thing to change is the db_dir to whereever you want to put your -database files. The configure script allows you to specific where it -should live; by default it'll be PREFIX/etc/onak.conf. +I've finally added config file support. onak.ini is an example config; +the main thing to change is the location in the backend section to +whereever you want to put your database files. The configure script allows +you to specific where it should live; by default it'll be PREFIX/etc/onak.ini. Backends: diff --git a/keyd.8 b/keyd.8 index 5442f43..93cb31f 100644 --- a/keyd.8 +++ b/keyd.8 @@ -32,7 +32,7 @@ Display help text. .nf .\" set tabstop to longest possible filename, plus a wee bit .ta \w'/usr/lib/perl/getopts.pl 'u -\fI/etc/onak.conf\fR default configuration file +\fI/etc/onak.ini\fR default configuration file .SH NOTES This man page could probably do with some more details. .SH "SEE ALSO" diff --git a/keydctl.8 b/keydctl.8 index 425d81e..430da37 100644 --- a/keydctl.8 +++ b/keydctl.8 @@ -40,7 +40,7 @@ of the commands seen. .nf .\" set tabstop to longest possible filename, plus a wee bit .ta \w'/usr/lib/perl/getopts.pl 'u -\fI/etc/onak.conf\fR default configuration file +\fI/etc/onak.ini\fR default configuration file .SH NOTES This man page could probably do with some more details. .SH "SEE ALSO" diff --git a/onak-conf.c b/onak-conf.c index 038ad55..60f2097 100644 --- a/onak-conf.c +++ b/onak-conf.c @@ -58,6 +58,19 @@ struct onak_config config = { .mail_dir = NULL, }; +struct onak_db_config *find_db_backend_config(struct ll *backends, char *name) +{ + struct ll *cur; + + cur = backends; + while (cur != NULL && strcmp(name, + ((struct onak_db_config *) cur->object)->name)) { + cur = cur->next; + } + + return (cur != NULL) ? (struct onak_db_config *) cur->object : NULL; +} + bool parsebool(char *str, bool fallback) { if (!strcasecmp(str, "false") || !strcasecmp(str, "no") || @@ -76,7 +89,10 @@ bool parsebool(char *str, bool fallback) } } -static bool parseconfigline(char *line) +/* + * Parse an old pksd style config line, as used in onak 0.4.6 and earlier. + */ +static bool parseoldconfigline(char *line) { if (line[0] == '#' || line[0] == 0) { /* @@ -162,6 +178,113 @@ static bool parseconfigline(char *line) return true; } +/* + * Parse a new style .ini config line, supporting [sections] and name=value + * format. + */ +static bool parseconfigline(char *line) +{ + /* Yes, this means we're not re-entrant. */ + static char section[32] = ""; + struct onak_db_config *backend; + size_t len; + char *name, *value; + + if (line[0] == '#' || line[0] == ';' || + line[0] == 0) { + /* + * Comment line, ignore. + */ + } else if (line[0] == '[') { + /* Section name */ + len = strlen(line); + if (line[len - 1] != ']') { + logthing(LOGTHING_CRITICAL, + "Malformed section header '%s' in " + "config file.", line); + return false; + } + if (len > sizeof(section)) { + logthing(LOGTHING_CRITICAL, + "Section header '%s' is too long in " + "config file.", line); + return false; + } + line[len - 1] = 0; + strncpy(section, &line[1], len); + } else if ((value = strchr(line, '=')) != NULL) { + name = line; + *value++ = 0; + + /* We can have multiple backend: sections */ + if (!strncmp(section, "backend:", 8)) { + backend = find_db_backend_config( + config.backends, §ion[8]); + if (backend == NULL) { + backend = calloc(1, + sizeof(struct onak_db_config)); + backend->name = strdup(§ion[8]); + config.backends = lladd(config.backends, + backend); + } + + if (!strcmp(name, "type")) { + backend->type = strdup(value); + } else if (!strcmp(name, "location")) { + backend->location = strdup(value); + } else if (!strcmp(name, "hostname")) { + backend->location = strdup(value); + } else if (!strcmp(name, "username")) { + backend->location = strdup(value); + } else if (!strcmp(name, "password")) { + backend->location = strdup(value); + } + +#define MATCH(s, n) !strcmp(section, s) && !strcmp(name, n) + /* [main] section */ + } else if (MATCH("main", "backend")) { + config.db_backend = strdup(value); + } else if (MATCH("main", "backends_dir")) { + config.backends_dir = strdup(value); + } else if (MATCH("main", "logfile")) { + config.logfile = strdup(value); + } else if (MATCH("main", "loglevel")) { + setlogthreshold(atoi(value)); + } else if (MATCH("main", "use_keyd")) { + config.use_keyd = parsebool(value, + config.use_keyd); + } else if (MATCH("main", "sock_dir")) { + config.sock_dir = strdup(value); + } else if (MATCH("main", "max_reply_keys")) { + config.maxkeys = atoi(value); + /* [mail] section */ + } else if (MATCH("mail", "maintainer_email")) { + config.adminemail = strdup(value); + } else if (MATCH("mail", "mail_dir")) { + config.mail_dir = strdup(value); + } else if (MATCH("mail", "mta")) { + config.mta = strdup(value); + } else if (MATCH("mail", "bin_dir")) { + config.bin_dir = strdup(value); + } else if (MATCH("mail", "this_site")) { + config.thissite = strdup(value); + } else if (MATCH("mail", "syncsite")) { + config.syncsites = lladd(config.syncsites, + strdup(value)); + /* [verification] section */ + } else if (MATCH("verification", "check_sighash")) { + config.check_sighash = parsebool(value, + config.check_sighash); + } else { + return false; + } + } else { + return false; + } + + return true; +} + void readconfig(const char *configfile) { FILE *conffile; char curline[1024]; @@ -169,29 +292,69 @@ void readconfig(const char *configfile) { char *dir, *conf; size_t len; struct onak_db_config *backend; + bool oldstyle = false; + bool res; curline[1023] = 0; + + /* + * Try to find a config file to use. If one is explicitly provided, + * use that. Otherwise look in $XDG_CONFIG_HOME, $HOME and finally + * the build in configuration directory. We try an old style onak.conf + * first and then the new style onak.ini if that wasn't found - this + * is to prevent breaking existing installs on upgrade. + */ if (configfile == NULL) { conffile = NULL; if ((dir = getenv("XDG_CONFIG_HOME")) != NULL) { - len = strlen(dir) + 1 + 9 + 1; /* dir + / + onak.conf + NUL */ + /* dir + / + onak.conf + NUL */ + len = strlen(dir) + 1 + 9 + 1; conf = malloc(len); snprintf(conf, len, "%s/onak.conf", dir); conffile = fopen(conf, "r"); + if (conffile == NULL) { + /* Conveniently .ini is shorter than .conf */ + snprintf(conf, len, "%s/onak.ini", dir); + conffile = fopen(conf, "r"); + } else { + oldstyle = true; + } free(conf); } else if ((dir = getenv("HOME")) != NULL) { - len = strlen(dir) + 18 + 1; /* dir + /.config/onak.conf + NUL */ + /* dir + /.config/onak.conf + NUL */ + len = strlen(dir) + 18 + 1; conf = malloc(len); snprintf(conf, len, "%s/.config/onak.conf", dir); conffile = fopen(conf, "r"); + if (conffile == NULL) { + /* Conveniently .ini is shorter than .conf */ + snprintf(conf, len, "%s/onak.ini", dir); + conffile = fopen(conf, "r"); + } else { + oldstyle = true; + } free(conf); } if (conffile == NULL) { - conffile = fopen(CONFIGFILE, "r"); + conffile = fopen(CONFIGDIR "/onak.conf", "r"); + if (conffile == NULL) { + conffile = fopen(CONFIGDIR "/onak.ini", "r"); + } else { + oldstyle = true; + } } } else { + /* + * Explicitly provided config file; if the filename ends .conf + * assume it's old style. + */ + len = strlen(configfile); + if (!strcmp(&configfile[len - 5], ".conf")) { + oldstyle = true; + } conffile = fopen(configfile, "r"); } + if (conffile != NULL) { if (!fgets(curline, 1023, conffile)) { logthing(LOGTHING_CRITICAL, @@ -200,10 +363,12 @@ void readconfig(const char *configfile) { return; } - /* Add a single DB configuration */ - backend = calloc(1, sizeof(*backend)); - config.backend = backend; - config.backends = lladd(NULL, backend); + if (oldstyle) { + /* Add a single DB configuration */ + backend = calloc(1, sizeof(*backend)); + config.backend = backend; + config.backends = lladd(NULL, backend); + } while (!feof(conffile)) { /* Strip any trailing white space */ @@ -219,7 +384,12 @@ void readconfig(const char *configfile) { i++; } - if (!parseconfigline(&curline[i])) { + if (oldstyle) { + res = parseoldconfigline(&curline[i]); + } else { + res = parseconfigline(&curline[i]); + } + if (!res) { logthing(LOGTHING_ERROR, "Unknown config line: %s", curline); } @@ -232,6 +402,19 @@ void readconfig(const char *configfile) { } } fclose(conffile); + + if (config.db_backend == NULL) { + logthing(LOGTHING_CRITICAL, + "No database backend configured."); + } else if (!oldstyle) { + config.backend = find_db_backend_config( + config.backends, config.db_backend); + if (config.backend == NULL) { + logthing(LOGTHING_NOTICE, + "Couldn't find configuration for %s " + "backend.", config.db_backend); + } + } } else { logthing(LOGTHING_NOTICE, "Couldn't open config file; using defaults."); diff --git a/onak-mail.pl.8 b/onak-mail.pl.8 index 5e6c5bd..9183981 100644 --- a/onak-mail.pl.8 +++ b/onak-mail.pl.8 @@ -15,7 +15,7 @@ aliases file, a .forward or via procmail and takes no options. .nf .\" set tabstop to longest possible filename, plus a wee bit .ta \w'/usr/lib/perl/getopts.pl 'u -\fI/etc/onak.conf\fR default configuration file +\fI/etc/onak.ini\fR default configuration file .SH NOTES This man page could probably do with some more details. .SH "SEE ALSO" diff --git a/onak-mail.pl.in b/onak-mail.pl.in index 097404e..68439d2 100644 --- a/onak-mail.pl.in +++ b/onak-mail.pl.in @@ -14,14 +14,14 @@ use IPC::Open3; my %config; # -# readconfig +# readoldconfig # -# Reads in our config file. Ignores any command it doesn't understand rather -# than having to list all the ones that are of no interest to us. +# Read an old pksd-style config file. Currently if both old and new style +# files are present the old style will be preferred in order to ensure smooth +# upgrades. # -sub readconfig { - - open(CONFIG, "@CONFIG@") or +sub readoldconfig { + open(CONFIG, "@CONFIGOLD@") or die "Can't read config file: $!"; while () { @@ -49,6 +49,54 @@ sub readconfig { return; } +# +# readconfig +# +# Reads in our config file. Ignores any command it doesn't understand rather +# than having to list all the ones that are of no interest to us. +# +sub readconfig { + # Prefer the old style config if it exists. + if (-e "@CONFIGOLD@") { + &readoldconfig; + return; + } + + open(CONFIG, "@CONFIG@") or + die "Can't read config file: $!"; + + $section = ""; + while () { + if (/^#/ or /^$/) { + # Ignore; comment line. + } elsif (/^\[(\w+)\]/) { + section = $1; + } elsif ($section == "main") { + if (/^logfile\s*=\s*(.*)/) { + $config{'logfile'} = $1; + } + } elsif ($section == "mail") { + if (/^this_site\s*=\s*(.*)/) { + $config{'thissite'} = $1; + } elsif (/^maintainer_email\s*=\s*(.*)/) { + $config{'adminemail'} = $1; + } elsif (/^mta\s*=\s*(.*)/) { + $config{'mta'} = $1; + } elsif (/^bin_dir\s*=\s*(.*)/) { + $config{'pks_bin_dir'} = $1; + } elsif (/^mail_dir\s*=\s*(.*)/) { + $config{'mail_dir'} = $1; + } elsif (/^syncsite\s*=\s*(.*)/) { + push @{$config{'syncsites'}}, $1; + } + } + } + + close(CONFIG); + + return; +} + # # submitupdate # diff --git a/onak.1 b/onak.1 index bc748dd..0ad015c 100644 --- a/onak.1 +++ b/onak.1 @@ -71,7 +71,7 @@ Export all keys on your gnupg keyring and import them into the keyserver. .nf .\" set tabstop to longest possible filename, plus a wee bit .ta \w'/usr/lib/perl/getopts.pl 'u -\fI/etc/onak.conf\fR default configuration file +\fI/etc/onak.ini\fR default configuration file .SH NOTES This man page could probably do with some more details. .SH AUTHOR diff --git a/onak.conf.in b/onak.conf.in deleted file mode 100644 index 74a3772..0000000 --- a/onak.conf.in +++ /dev/null @@ -1,75 +0,0 @@ -# -# onak configuration file. Taken from pksd.conf as a starting point. -# - -pks_bin_dir @BINDIR@ -db_backend db4 -backends_dir @LIBDIR@/onak/backends -db_dir @STATEDIR@/lib/onak -logfile @STATEDIR@/log/onak.log -# Loglevel : 0 is highest debug, default is 3, nothing is 7+ -loglevel 3 - -# Should we use the keyd backend? -use_keyd false - -### Set www_port to the port on which HTTP requests should be accepted. -### If you do not want to process HTTP requests, set this to 0. - -www_port 11371 -socket_name /community/pgp-keyserver/pksd_socket - -### Specify the envelope sender address as the -f argument to -### sendmail. This is the address which will receive any bounces. -### If you don't use sendmail, then change this to an equivalent command. -### If you do not want to process mail requests, leave this unset. - -mail_delivery_client /usr/sbin/sendmail -t -oi -fmailer-daemon - -### Set this to the address which should be displayed as the From: -### address in all outgoing email, and as the maintainer in the body -### of each message. - -maintainer_email PGP Key Server Administrator -mail_intro_file /community/pgp-keyserver/share/mail_intro -help_dir /community/pgp-keyserver/share -mail_dir @STATEDIR@/spool/onak -sock_dir @RUNDIR@ - -### If you change this, make sure to put a corresponding help file in -### the help_dir named above - -default_language EN - -### This is the email address of this site. It will be inserted in all -### outgoing incremental messages, so it should match whatever the -### downstream sites use as syncsite in their pksd.conf files. - -this_site pgp-public-keys@the.earth.li - -### Include a syncsite line for each site with which you are exchanging -### incremental requests. - -#syncsite pgp-public-keys@keys.nl.pgp.net -#syncsite pgp-public-keys@blackhole.pca.dfn.de -#syncsite pgp-public-keys@pgp.es.net -#syncsite pgp-public-keys@keyserver.linux.it -#syncsite pgp-public-keys@pgp.dtype.org -#syncsite pgp-public-keys@kjsl.com - -### Set this to 0 to disable mailserver LAST requests completely, to a -### positive integer to limit LAST requests to that many days, or -1 -### to allow any argument to LAST. - -max_last 1 - -### Set this to the maximum number of keys to return in the reply to -### an index, verbose index, get, or since reply. Setting it to -1 -### will allow any size reply. - -max_reply_keys 128 - -## -## Verify signature hashes. -## -#check_sighash true diff --git a/onak.ini.in b/onak.ini.in new file mode 100644 index 0000000..12a8701 --- /dev/null +++ b/onak.ini.in @@ -0,0 +1,51 @@ +; +; Configuration for onak, an OpenPGP compatible keyserver +; +[main] +backend=defaultdb4 +backends_dir=@LIBDIR@/onak/backends +logfile=@STATEDIR@/log/onak.log +; Loglevel : 0 is highest debug, default is 3, nothing is 7+ +loglevel=3 +; Should we use the keyd backend? +use_keyd=false +sock_dir=@RUNDIR@ +; Maximum number of keys to return in a reply to an index, verbose index or +; get. Setting it to -1 will allow any size of reply. +max_reply_keys=128 + +; Settings related to key verification options available. +[verification] +; Verify signature hashes - verify that the hash a signature claims to be +; over matches the hash of the data. Does not actually verify the signature. +check_sighash=true + +; Settings related to the email interface to onak. +[mail] +maintainer_email=PGP Key Server Administrator +mail_dir=@STATEDIR@/spool/onak +; Specify the envelope sender address as the -f argument to +; sendmail. This is the address which will receive any bounces. +; If you don't use sendmail, then change this to an equivalent command. +; If you do not want to process mail requests, leave this unset. +mta=/usr/sbin/sendmail -t -oi -fmailer-daemon +; Where the main onak binary lives, so the script that handles incoming +; email knows where to find it. +bin_dir=@BINDIR@ +; Email address outgoing incremental messages will come from. +; Needs to match the syncsite entries others sites have for this site. +this_site=pgp-public-keys@the.earth.li +; Include a syncsite line for each site with which you are exchanging +; incremental requests. +;syncsite=pgp-public-keys@keys.nl.pgp.net +;syncsite=pgp-public-keys@blackhole.pca.dfn.de +;syncsite=pgp-public-keys@pgp.es.net +;syncsite=pgp-public-keys@keyserver.linux.it +;syncsite=pgp-public-keys@pgp.dtype.org +;syncsite=pgp-public-keys@kjsl.com + +; Database backend configurations below here + +[backend:defaultdb4] +type=db4 +location=@STATEDIR@/lib/onak diff --git a/runtests b/runtests index 495e7b5..973aa59 100755 --- a/runtests +++ b/runtests @@ -17,7 +17,7 @@ for t in libkeydb_*.so; do backend=${t##libkeydb_} backend=${backend%%.so} if [ "`echo t/$backend-*`" != "t/$backend-*" ]; then - echo "* testing $backend backend" + echo "* testing $backend backend [conf]" (sed -e "s;DIR;`pwd`;" t/test-in.conf ; \ echo db_backend $backend) > t/test.conf for t in t/$backend-*.t t/all-*.t; do @@ -31,6 +31,22 @@ for t in libkeydb_*.so; do done rm t/test.conf fi + + if [ "`echo t/$backend-*`" != "t/$backend-*" ]; then + echo "* testing $backend backend [ini]" + sed -e "s;DIR;`pwd`;" -e "s;DB;${backend};" t/test-in.ini \ + > t/test.ini + for t in t/$backend-*.t t/all-*.t; do + total=`expr $total + 1` + mkdir t/db/ + if ! $t test.ini $backend; then + echo "test $t failed" >&2 + fail=`expr $fail + 1` + fi + rm -rf t/db/ + done + rm t/test.ini + fi done if [ "$fail" -gt 0 ]; then diff --git a/t/test-in.ini b/t/test-in.ini new file mode 100644 index 0000000..fba8033 --- /dev/null +++ b/t/test-in.ini @@ -0,0 +1,15 @@ +[main] +backend=test-DB +backends_dir=DIR +logfile=onak.log +loglevel=7 +use_keyd=false +max_reply_keys=128 + +[backend:test-DB] +type=DB +location=DIR/t/db/ + +[mail] +bin_dir=DIR +this_site=pgp-public-keys@localhost