summaryrefslogtreecommitdiffstats
path: root/lib/getdef.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/getdef.c')
-rw-r--r--lib/getdef.c623
1 files changed, 623 insertions, 0 deletions
diff --git a/lib/getdef.c b/lib/getdef.c
new file mode 100644
index 0000000..dcd1fe7
--- /dev/null
+++ b/lib/getdef.c
@@ -0,0 +1,623 @@
+/*
+ * SPDX-FileCopyrightText: 1991 - 1994, Julianne Frances Haugh
+ * SPDX-FileCopyrightText: 1996 - 2000, Marek Michałkiewicz
+ * SPDX-FileCopyrightText: 2002 - 2006, Tomasz Kłoczko
+ * SPDX-FileCopyrightText: 2007 - 2008, Nicolas François
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <config.h>
+
+#ident "$Id$"
+
+#include "prototypes.h"
+#include "defines.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef USE_ECONF
+#include <libeconf.h>
+#endif
+#include "getdef.h"
+#include "shadowlog_internal.h"
+/*
+ * A configuration item definition.
+ */
+struct itemdef {
+ /*@null@*/const char *name; /* name of the item */
+ /*@null@*/char *value; /* value given, or NULL if no value */
+};
+
+#define PAMDEFS \
+ {"CHFN_AUTH", NULL}, \
+ {"CHSH_AUTH", NULL}, \
+ {"CRACKLIB_DICTPATH", NULL}, \
+ {"ENV_HZ", NULL}, \
+ {"ENVIRON_FILE", NULL}, \
+ {"ENV_TZ", NULL}, \
+ {"FAILLOG_ENAB", NULL}, \
+ {"FTMP_FILE", NULL}, \
+ {"HMAC_CRYPTO_ALGO", NULL}, \
+ {"ISSUE_FILE", NULL}, \
+ {"LASTLOG_ENAB", NULL}, \
+ {"LOGIN_STRING", NULL}, \
+ {"MAIL_CHECK_ENAB", NULL}, \
+ {"MOTD_FILE", NULL}, \
+ {"NOLOGINS_FILE", NULL}, \
+ {"OBSCURE_CHECKS_ENAB", NULL}, \
+ {"PASS_ALWAYS_WARN", NULL}, \
+ {"PASS_CHANGE_TRIES", NULL}, \
+ {"PASS_MAX_LEN", NULL}, \
+ {"PASS_MIN_LEN", NULL}, \
+ {"PORTTIME_CHECKS_ENAB", NULL}, \
+ {"QUOTAS_ENAB", NULL}, \
+ {"SU_WHEEL_ONLY", NULL}, \
+ {"ULIMIT", NULL},
+
+/*
+ * Items used in other tools (util-linux, etc.)
+ */
+#define FOREIGNDEFS \
+ {"ALWAYS_SET_PATH", NULL}, \
+ {"ENV_ROOTPATH", NULL}, \
+ {"LOGIN_KEEP_USERNAME", NULL}, \
+ {"LOGIN_PLAIN_PROMPT", NULL}, \
+ {"MOTD_FIRSTONLY", NULL}, \
+
+
+#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
+static struct itemdef def_table[] = {
+ {"CHFN_RESTRICT", NULL},
+ {"CONSOLE_GROUPS", NULL},
+ {"CONSOLE", NULL},
+ {"CREATE_HOME", NULL},
+ {"DEFAULT_HOME", NULL},
+ {"ENCRYPT_METHOD", NULL},
+ {"ENV_PATH", NULL},
+ {"ENV_SUPATH", NULL},
+ {"ERASECHAR", NULL},
+ {"FAIL_DELAY", NULL},
+ {"FAKE_SHELL", NULL},
+ {"GID_MAX", NULL},
+ {"GID_MIN", NULL},
+ {"HOME_MODE", NULL},
+ {"HUSHLOGIN_FILE", NULL},
+ {"KILLCHAR", NULL},
+ {"LASTLOG_UID_MAX", NULL},
+ {"LOGIN_RETRIES", NULL},
+ {"LOGIN_TIMEOUT", NULL},
+ {"LOG_OK_LOGINS", NULL},
+ {"LOG_UNKFAIL_ENAB", NULL},
+ {"MAIL_DIR", NULL},
+ {"MAIL_FILE", NULL},
+ {"MAX_MEMBERS_PER_GROUP", NULL},
+ {"MD5_CRYPT_ENAB", NULL},
+ {"NONEXISTENT", NULL},
+ {"PASS_MAX_DAYS", NULL},
+ {"PASS_MIN_DAYS", NULL},
+ {"PASS_WARN_AGE", NULL},
+#ifdef USE_SHA_CRYPT
+ {"SHA_CRYPT_MAX_ROUNDS", NULL},
+ {"SHA_CRYPT_MIN_ROUNDS", NULL},
+#endif
+#ifdef USE_BCRYPT
+ {"BCRYPT_MAX_ROUNDS", NULL},
+ {"BCRYPT_MIN_ROUNDS", NULL},
+#endif
+#ifdef USE_YESCRYPT
+ {"YESCRYPT_COST_FACTOR", NULL},
+#endif
+ {"SUB_GID_COUNT", NULL},
+ {"SUB_GID_MAX", NULL},
+ {"SUB_GID_MIN", NULL},
+ {"SUB_UID_COUNT", NULL},
+ {"SUB_UID_MAX", NULL},
+ {"SUB_UID_MIN", NULL},
+ {"SULOG_FILE", NULL},
+ {"SU_NAME", NULL},
+ {"SYS_GID_MAX", NULL},
+ {"SYS_GID_MIN", NULL},
+ {"SYS_UID_MAX", NULL},
+ {"SYS_UID_MIN", NULL},
+ {"TTYGROUP", NULL},
+ {"TTYPERM", NULL},
+ {"TTYTYPE_FILE", NULL},
+ {"UID_MAX", NULL},
+ {"UID_MIN", NULL},
+ {"UMASK", NULL},
+ {"USERDEL_CMD", NULL},
+ {"USERGROUPS_ENAB", NULL},
+#ifndef USE_PAM
+ PAMDEFS
+#endif
+#ifdef USE_SYSLOG
+ {"SYSLOG_SG_ENAB", NULL},
+ {"SYSLOG_SU_ENAB", NULL},
+#endif
+#ifdef WITH_TCB
+ {"TCB_AUTH_GROUP", NULL},
+ {"TCB_SYMLINKS", NULL},
+ {"USE_TCB", NULL},
+#endif
+ {"FORCE_SHADOW", NULL},
+ {"GRANT_AUX_GROUP_SUBIDS", NULL},
+ {"PREVENT_NO_AUTH", NULL},
+ {NULL, NULL}
+};
+
+#define NUMKNOWNDEFS (sizeof(knowndef_table)/sizeof(knowndef_table[0]))
+static struct itemdef knowndef_table[] = {
+#ifdef USE_PAM
+ PAMDEFS
+#endif
+ FOREIGNDEFS
+ {NULL, NULL}
+};
+
+#ifdef USE_ECONF
+#ifdef VENDORDIR
+static const char* vendordir = VENDORDIR;
+#else
+static const char* vendordir = NULL;
+#endif
+static const char* sysconfdir = "/etc";
+#else
+#ifndef LOGINDEFS
+#define LOGINDEFS "/etc/login.defs"
+#endif
+
+static const char* def_fname = LOGINDEFS; /* login config defs file */
+#endif
+static bool def_loaded = false; /* are defs already loaded? */
+
+/* local function prototypes */
+static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *);
+static void def_load (void);
+
+
+/*
+ * getdef_str - get string value from table of definitions.
+ *
+ * Return point to static data for specified item, or NULL if item is not
+ * defined. First time invoked, will load definitions from the file.
+ */
+
+/*@observer@*/ /*@null@*/const char *getdef_str (const char *item)
+{
+ struct itemdef *d;
+
+ if (!def_loaded) {
+ def_load ();
+ }
+
+ d = def_find (item);
+ return ((NULL == d)? (const char *) NULL : d->value);
+}
+
+
+/*
+ * getdef_bool - get boolean value from table of definitions.
+ *
+ * Return TRUE if specified item is defined as "yes", else FALSE.
+ */
+
+bool getdef_bool (const char *item)
+{
+ struct itemdef *d;
+
+ if (!def_loaded) {
+ def_load ();
+ }
+
+ d = def_find (item);
+ if ((NULL == d) || (NULL == d->value)) {
+ return false;
+ }
+
+ return (strcasecmp (d->value, "yes") == 0);
+}
+
+
+/*
+ * getdef_num - get numerical value from table of definitions
+ *
+ * Returns numeric value of specified item, else the "dflt" value if
+ * the item is not defined. Octal (leading "0") and hex (leading "0x")
+ * values are handled.
+ */
+
+int getdef_num (const char *item, int dflt)
+{
+ struct itemdef *d;
+ long val;
+
+ if (!def_loaded) {
+ def_load ();
+ }
+
+ d = def_find (item);
+ if ((NULL == d) || (NULL == d->value)) {
+ return dflt;
+ }
+
+ if ( (getlong (d->value, &val) == 0)
+ || (val > INT_MAX)
+ || (val < INT_MIN)) {
+ fprintf (shadow_logfd,
+ _("configuration error - cannot parse %s value: '%s'"),
+ item, d->value);
+ return dflt;
+ }
+
+ return (int) val;
+}
+
+
+/*
+ * getdef_unum - get unsigned numerical value from table of definitions
+ *
+ * Returns numeric value of specified item, else the "dflt" value if
+ * the item is not defined. Octal (leading "0") and hex (leading "0x")
+ * values are handled.
+ */
+
+unsigned int getdef_unum (const char *item, unsigned int dflt)
+{
+ struct itemdef *d;
+ long val;
+
+ if (!def_loaded) {
+ def_load ();
+ }
+
+ d = def_find (item);
+ if ((NULL == d) || (NULL == d->value)) {
+ return dflt;
+ }
+
+ if ( (getlong (d->value, &val) == 0)
+ || (val < 0)
+ || (val > INT_MAX)) {
+ fprintf (shadow_logfd,
+ _("configuration error - cannot parse %s value: '%s'"),
+ item, d->value);
+ return dflt;
+ }
+
+ return (unsigned int) val;
+}
+
+
+/*
+ * getdef_long - get long integer value from table of definitions
+ *
+ * Returns numeric value of specified item, else the "dflt" value if
+ * the item is not defined. Octal (leading "0") and hex (leading "0x")
+ * values are handled.
+ */
+
+long getdef_long (const char *item, long dflt)
+{
+ struct itemdef *d;
+ long val;
+
+ if (!def_loaded) {
+ def_load ();
+ }
+
+ d = def_find (item);
+ if ((NULL == d) || (NULL == d->value)) {
+ return dflt;
+ }
+
+ if (getlong (d->value, &val) == 0) {
+ fprintf (shadow_logfd,
+ _("configuration error - cannot parse %s value: '%s'"),
+ item, d->value);
+ return dflt;
+ }
+
+ return val;
+}
+
+/*
+ * getdef_ulong - get unsigned long numerical value from table of definitions
+ *
+ * Returns numeric value of specified item, else the "dflt" value if
+ * the item is not defined. Octal (leading "0") and hex (leading "0x")
+ * values are handled.
+ */
+
+unsigned long getdef_ulong (const char *item, unsigned long dflt)
+{
+ struct itemdef *d;
+ unsigned long val;
+
+ if (!def_loaded) {
+ def_load ();
+ }
+
+ d = def_find (item);
+ if ((NULL == d) || (NULL == d->value)) {
+ return dflt;
+ }
+
+ if (getulong (d->value, &val) == 0) {
+ fprintf (shadow_logfd,
+ _("configuration error - cannot parse %s value: '%s'"),
+ item, d->value);
+ return dflt;
+ }
+
+ return val;
+}
+
+/*
+ * putdef_str - override the value read from /etc/login.defs
+ * (also used when loading the initial defaults)
+ */
+
+int putdef_str (const char *name, const char *value)
+{
+ struct itemdef *d;
+ char *cp;
+
+ if (!def_loaded) {
+ def_load ();
+ }
+
+ /*
+ * Locate the slot to save the value. If this parameter
+ * is unknown then "def_find" will print an err message.
+ */
+ d = def_find (name);
+ if (NULL == d) {
+ return -1;
+ }
+
+ /*
+ * Save off the value.
+ */
+ cp = strdup (value);
+ if (NULL == cp) {
+ (void) fputs (_("Could not allocate space for config info.\n"),
+ shadow_logfd);
+ SYSLOG ((LOG_ERR, "could not allocate space for config info"));
+ return -1;
+ }
+
+ free (d->value);
+ d->value = cp;
+ return 0;
+}
+
+
+/*
+ * def_find - locate named item in table
+ *
+ * Search through a table of configurable items to locate the
+ * specified configuration option.
+ */
+
+static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
+{
+ struct itemdef *ptr;
+
+ /*
+ * Search into the table.
+ */
+
+ for (ptr = def_table; NULL != ptr->name; ptr++) {
+ if (strcmp (ptr->name, name) == 0) {
+ return ptr;
+ }
+ }
+
+ /*
+ * Item was never found.
+ */
+
+ for (ptr = knowndef_table; NULL != ptr->name; ptr++) {
+ if (strcmp (ptr->name, name) == 0) {
+ goto out;
+ }
+ }
+ fprintf (shadow_logfd,
+ _("configuration error - unknown item '%s' (notify administrator)\n"),
+ name);
+ SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name));
+
+out:
+ return (struct itemdef *) NULL;
+}
+
+/*
+ * setdef_config_file - set the default configuration file path
+ *
+ * must be called prior to any def* calls.
+ */
+
+void setdef_config_file (const char* file)
+{
+#ifdef USE_ECONF
+ size_t len;
+ char* cp;
+
+ len = strlen(file) + strlen(sysconfdir) + 2;
+ cp = malloc(len);
+ if (cp == NULL)
+ exit (13);
+ snprintf(cp, len, "%s/%s", file, sysconfdir);
+ sysconfdir = cp;
+#ifdef VENDORDIR
+ len = strlen(file) + strlen(vendordir) + 2;
+ cp = malloc(len);
+ if (cp == NULL)
+ exit (13);
+ snprintf(cp, len, "%s/%s", file, vendordir);
+ vendordir = cp;
+#endif
+#else
+ def_fname = file;
+#endif
+}
+
+/*
+ * def_load - load configuration table
+ *
+ * Loads the user-configured options from the default configuration file
+ */
+
+static void def_load (void)
+{
+#ifdef USE_ECONF
+ econf_file *defs_file = NULL;
+ econf_err error;
+ char **keys;
+ size_t key_number;
+#else
+ int i;
+ FILE *fp;
+ char buf[1024], *name, *value, *s;
+#endif
+
+ /*
+ * Set the initialized flag.
+ * (do it early to prevent recursion in putdef_str())
+ */
+ def_loaded = true;
+
+#ifdef USE_ECONF
+
+ error = econf_readDirs (&defs_file, vendordir, sysconfdir, "login", "defs", " \t", "#");
+ if (error) {
+ if (error == ECONF_NOFILE)
+ return;
+
+ SYSLOG ((LOG_CRIT, "cannot open login definitions [%s]",
+ econf_errString(error)));
+ exit (EXIT_FAILURE);
+ }
+
+ if ((error = econf_getKeys(defs_file, NULL, &key_number, &keys))) {
+ SYSLOG ((LOG_CRIT, "cannot read login definitions [%s]",
+ econf_errString(error)));
+ exit (EXIT_FAILURE);
+ }
+
+ for (size_t i = 0; i < key_number; i++) {
+ char *value;
+
+ econf_getStringValue(defs_file, NULL, keys[i], &value);
+
+ /*
+ * Store the value in def_table.
+ *
+ * Ignore failures to load the login.defs file.
+ * The error was already reported to the user and to
+ * syslog. The tools will just use their default values.
+ */
+ (void)putdef_str (keys[i], value);
+ }
+
+ econf_free (keys);
+ econf_free (defs_file);
+#else
+ /*
+ * Open the configuration definitions file.
+ */
+ fp = fopen (def_fname, "r");
+ if (NULL == fp) {
+ if (errno == ENOENT)
+ return;
+
+ int err = errno;
+ SYSLOG ((LOG_CRIT, "cannot open login definitions %s [%s]",
+ def_fname, strerror (err)));
+ exit (EXIT_FAILURE);
+ }
+
+ /*
+ * Go through all of the lines in the file.
+ */
+ while (fgets (buf, (int) sizeof (buf), fp) != NULL) {
+
+ /*
+ * Trim trailing whitespace.
+ */
+ for (i = (int) strlen (buf) - 1; i >= 0; --i) {
+ if (!isspace (buf[i])) {
+ break;
+ }
+ }
+ i++;
+ buf[i] = '\0';
+
+ /*
+ * Break the line into two fields.
+ */
+ name = buf + strspn (buf, " \t"); /* first nonwhite */
+ if (*name == '\0' || *name == '#')
+ continue; /* comment or empty */
+
+ s = name + strcspn (name, " \t"); /* end of field */
+ if (*s == '\0')
+ continue; /* only 1 field?? */
+
+ *s++ = '\0';
+ value = s + strspn (s, " \"\t"); /* next nonwhite */
+ *(value + strcspn (value, "\"")) = '\0';
+
+ /*
+ * Store the value in def_table.
+ *
+ * Ignore failures to load the login.defs file.
+ * The error was already reported to the user and to
+ * syslog. The tools will just use their default values.
+ */
+ (void)putdef_str (name, value);
+ }
+
+ if (ferror (fp) != 0) {
+ int err = errno;
+ SYSLOG ((LOG_CRIT, "cannot read login definitions %s [%s]",
+ def_fname, strerror (err)));
+ exit (EXIT_FAILURE);
+ }
+
+ (void) fclose (fp);
+#endif
+}
+
+
+#ifdef CKDEFS
+int main (int argc, char **argv)
+{
+ int i;
+ char *cp;
+ struct itemdef *d;
+
+ def_load ();
+
+ for (i = 0; i < NUMDEFS; ++i) {
+ d = def_find (def_table[i].name);
+ if (NULL == d) {
+ printf ("error - lookup '%s' failed\n",
+ def_table[i].name);
+ } else {
+ printf ("%4d %-24s %s\n", i + 1, d->name, d->value);
+ }
+ }
+ for (i = 1; i < argc; i++) {
+ cp = getdef_str (argv[1]);
+ if (NULL != cp) {
+ printf ("%s `%s'\n", argv[1], cp);
+ } else {
+ printf ("%s not found\n", argv[1]);
+ }
+ }
+ exit (EXIT_SUCCESS);
+}
+#endif