From fcf522db281ce23840f028a2ea44039f92c5e144 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 17 Jul 2015 17:08:43 +0200 Subject: Add implicit support for .d/*.conf file parsing. --- doc/man/pwquality.conf.5 | 4 +++ src/pwquality.h | 5 +++- src/settings.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/doc/man/pwquality.conf.5 b/doc/man/pwquality.conf.5 index 7315e1c..6d9c80e 100644 --- a/doc/man/pwquality.conf.5 +++ b/doc/man/pwquality.conf.5 @@ -9,6 +9,7 @@ pwquality.conf \- configuration for the libpwquality library .SH SYNOPSIS \fB/etc/security/pwquality.conf\fR +\fB/etc/security/pwquality.conf.d/*.conf\fR .SH DESCRIPTION \fBpwquality.conf\fR provides a way to configure the default password quality requirements for the system passwords. This file is read by the @@ -19,6 +20,9 @@ The file has a very simple \fIname = value\fR format with possible comments starting with \fB#\fR character. The whitespace at the beginning of line, end of line, and around the \fB=\fR sign is ignored. +The libpwquality library also first reads all \fB*.conf\fR files from the +\fB/etc/security/pwquality.conf.d\fR directory in ASCII sorted order. The +values of the same settings are overriden in the order the files are parsed. .PD .SH OPTIONS The possible options in the file are: diff --git a/src/pwquality.h b/src/pwquality.h index 2f09e82..32f5f02 100644 --- a/src/pwquality.h +++ b/src/pwquality.h @@ -77,7 +77,10 @@ pwquality_free_settings(pwquality_settings_t *pwq); /* Parse the configuration file (if cfgfile is NULL then the default one). * If auxerror is not NULL it also possibly returns auxiliary error information - * that must be passed into pwquality_strerror() function. */ + * that must be passed into pwquality_strerror() function. + * New in 1.3.0: First tries to parse all *.conf configuration files from + * .d directory if it exists. Order of parsing determines what + values will be in effect - the latest wins. */ int pwquality_read_config(pwquality_settings_t *pwq, const char *cfgfile, void **auxerror); diff --git a/src/settings.c b/src/settings.c index a6d6efa..a5f22be 100644 --- a/src/settings.c +++ b/src/settings.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "pwquality.h" #include "pwqprivate.h" @@ -181,15 +182,83 @@ read_config_file(pwquality_settings_t *pwq, const char *cfgfile, void **auxerror return rv; } +static int +filter_conf(const struct dirent *d) +{ + const char *p; + + if ((p = strstr(d->d_name, ".conf")) == NULL) + return 0; + + if (p[5] != '\0') + return 0; + + return 1; +} + +static int +comp_func(const struct dirent **a, const struct dirent **b) +{ + return strcmp ((*a)->d_name, (*b)->d_name); +} + /* parse the configuration file (if NULL then the default one) */ int pwquality_read_config(pwquality_settings_t *pwq, const char *cfgfile, void **auxerror) { + char *dirname; + struct dirent **namelist; + int n; + int i; + int rv = 0; + if (auxerror) *auxerror = NULL; if (cfgfile == NULL) cfgfile = PWQUALITY_DEFAULT_CFGFILE; + /* read "*.conf" files from ".d" directory first */ + + if (asprintf(&dirname, "%s.d", cfgfile) < 0) + return PWQ_ERROR_MEM_ALLOC; + + /* we do not care about scandir races here so we use scandir */ + n = scandir(dirname, &namelist, filter_conf, comp_func); + + if (n < 0) { + namelist = NULL; + + if (errno == ENOMEM) { + free(dirname); + return PWQ_ERROR_MEM_ALLOC; + } /* other errors are ignored */ + } + + for (i = 0; i < n; i++) { + char *subcfg; + + if (rv) { + free(namelist[i]); + continue; + } + + if (asprintf(&subcfg, "%s/%s", dirname, namelist[i]->d_name) < 0) + rv = PWQ_ERROR_MEM_ALLOC; + else { + rv = read_config_file(pwq, subcfg, auxerror); + if (rv == PWQ_ERROR_CFGFILE_OPEN) + rv = 0; /* ignore, this one does not modify auxerror */ + free(subcfg); + } + + free(namelist[i]); + } + free(dirname); + free(namelist); + + if (rv) + return rv; + return read_config_file(pwq, cfgfile, auxerror); } -- cgit v1.2.1