summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog4
-rw-r--r--debian/copyright5
-rw-r--r--nss_tacplus.c80
3 files changed, 80 insertions, 9 deletions
diff --git a/debian/changelog b/debian/changelog
index 43d371e..cf33b24 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-libnss-tacplus (1.0.2) unstable; urgency=low
+libnss-tacplus (1.0.3-1) unstable; urgency=low
* added config variable "timeout" to limit time attempting to
* added config variable "exclude_users" in /etc/tacplus_nss
to avoid looking up "local" user accounts via TACACS servers. This
@@ -11,6 +11,8 @@ libnss-tacplus (1.0.2) unstable; urgency=low
* Added vrf config variable, so NSS lookups work correctly$
* During login, send remote add IP address in AUTH request
connect to non-responding TACACS server.
+ * configuration files should automatically be reparsed
+ if they change, for long-lived programs and daemons that use NSS.
-- Dave Olson <olson@cumulusnetworks.com> Tue, 07 Mar 2017 12:58:03 -0800
diff --git a/debian/copyright b/debian/copyright
index 9b1b34a..710851e 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -3,8 +3,9 @@ Upstream-Name: libnss-tacplus
Source: http://www.cumulusnetworks.com
Files: *
-Copyright: 2015, 2016 Cumulus Networks, Inc. All rights reserved.,
- 2010 Pawel Krawczyk <pawel.krawczyk@hush.com> and Jeroen Nijhof <jeroen@jeroennijhof.nl>
+Copyright: 2015, 2016, 2017 Cumulus Networks, Inc. All rights reserved.,
+ 2010 Pawel Krawczyk <pawel.krawczyk@hush.com> and
+ Jeroen Nijhof <jeroen@jeroennijhof.nl>
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/nss_tacplus.c b/nss_tacplus.c
index 2d4f193..1cf99c5 100644
--- a/nss_tacplus.c
+++ b/nss_tacplus.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2014, 2015, 2016 Cumulus Networks, Inc. All rights reserved.
+ * Copyright (C) 2014, 2015, 2016, 2017 Cumulus Networks, Inc.
+ * All rights reserved.
* Author: Dave Olson <olson@cumulusnetworks.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -37,6 +38,7 @@
#include <nss.h>
#include <libaudit.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <tacplus/libtac.h>
#include <tacplus/map_tacplus_user.h>
@@ -60,7 +62,7 @@ struct pwbuf {
typedef struct {
struct addrinfo *addr;
- const char *key;
+ char *key;
} tacplus_server_t;
/* set from configuration file parsing */
@@ -77,14 +79,77 @@ static int conf_parsed = 0;
static void get_remote_addr(void);
+#define MAX_INCL 8 /* max config level nesting */
+
+/* reset all config variables when we are going to re-parse */
+static void
+reset_config(void)
+{
+ int i, nservers;
+
+ /* reset the config variables that we use, freeing memory where needed */
+ nservers = tac_srv_no;
+ tac_srv_no = 0;
+ tac_key_no = 0;
+ vrfname[0] = '\0';
+ if(exclude_users[0])
+ (void)free(exclude_users);
+ exclude_users = NULL;
+ debug = 0;
+ use_tachome = 0;
+ tac_timeout = 0;
+ min_uid = ~0U;
+
+ for(i = 0; i < nservers; i++) {
+ if(tac_srv[i].key) {
+ free(tac_srv[i].key);
+ tac_srv[i].key = NULL;
+ }
+ tac_srv[i].addr = NULL;
+ }
+}
+
static int nss_tacplus_config(int *errnop, const char *cfile, int top)
{
FILE *conf;
char lbuf[256];
+ static struct stat lastconf[MAX_INCL];
+ static char *cfilelist[MAX_INCL];
+ struct stat st, *lst;
+
+ if(top > MAX_INCL) {
+ syslog(LOG_NOTICE, "%s: Config file include depth > %d, ignoring %s",
+ nssname, MAX_INCL, cfile);
+ return 1;
+ }
- if(conf_parsed > 1) /* 1: we've tried and thrown errors, 2, OK */
- return 0;
+ lst = &lastconf[top-1];
+ if(conf_parsed && top == 1) {
+ /*
+ * check to see if the config file(s) have changed since last time,
+ * in case we are part of a long-lived daemon. If any changed,
+ * reparse. If not, return the appropriate status (err or OK)
+ * This is somewhat complicated by the include file mechanism.
+ * When we have nested includes, we have to check all the config
+ * files we saw previously, not just the top level config file.
+ */
+ int i;
+ for(i=0; i < MAX_INCL; i++) {
+ struct stat *cst;
+ cst = &lastconf[i];
+ if(!cst->st_ino || !cfilelist[i]) /* end of files */
+ return conf_parsed == 2 ? 0 : 1;
+ if (stat(cfilelist[i], &st) || st.st_ino != cst->st_ino ||
+ st.st_mtime != cst->st_mtime || st.st_ctime != cst->st_ctime)
+ break; /* found removed or different file, so re-parse */
+ }
+ reset_config();
+ syslog(LOG_NOTICE, "%s: Configuration file(s) have changed, re-initializing",
+ nssname);
+ }
+ /* don't check for failures, we'll just skip, don't want to error out */
+ cfilelist[top-1] = strdup(cfile);
conf = fopen(cfile, "r");
if(conf == NULL) {
*errnop = errno;
@@ -93,6 +158,8 @@ static int nss_tacplus_config(int *errnop, const char *cfile, int top)
nssname, cfile);
return 1;
}
+ if (fstat(fileno(conf), lst) != 0)
+ memset(lst, 0, sizeof *lst); /* avoid stale data, no warning */
while(fgets(lbuf, sizeof lbuf, conf)) {
if(*lbuf == '#' || isspace(*lbuf))
@@ -101,9 +168,10 @@ static int nss_tacplus_config(int *errnop, const char *cfile, int top)
if(!strncmp(lbuf, "include=", 8)) {
/*
* allow include files, useful for centralizing tacacs
- * server IP address and secret.
+ * server IP address and secret. When running non-privileged,
+ * may not be able to read one or more config files.
*/
- if(lbuf[8]) /* else treat as empty config, ignoring errors */
+ if(lbuf[8])
(void)nss_tacplus_config(errnop, &lbuf[8], top+1);
}
else if(!strncmp(lbuf, "debug=", 6))