Skip to content

Commit

Permalink
Track changes to config files, and reparse if any change
Browse files Browse the repository at this point in the history
This is done to handle the case where nss_tacplus.so is included in
a long-lived daemon.  It's desirable to have long-lived daemons reflect
changes to the configuration, both to enable/disable debugging, and
particularly if the server list or key changes.  Clear all read config
variables to defaults when re-parsing.

This is complicated by nested configuration files via the include
directive.   At top level, we need to check all the previously used
configuration files to see if any have changed.

This also adds a limitation to no more than 8 deep include nesting.  In
practice, > 2 is going to be very rare, so it should be OK.

Log a message when we re-initialize (without using debug qualifier).
  • Loading branch information
Dave Olson committed May 23, 2017
1 parent f9f714b commit dab6c3b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 9 deletions.
4 changes: 3 additions & 1 deletion debian/changelog
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 <[email protected]> Tue, 07 Mar 2017 12:58:03 -0800

Expand Down
5 changes: 3 additions & 2 deletions debian/copyright
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]> and Jeroen Nijhof <[email protected]>
Copyright: 2015, 2016, 2017 Cumulus Networks, Inc. All rights reserved.,
2010 Pawel Krawczyk <[email protected]> and
Jeroen Nijhof <[email protected]>
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
Expand Down
80 changes: 74 additions & 6 deletions nss_tacplus.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -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>
Expand All @@ -60,7 +62,7 @@ struct pwbuf {

typedef struct {
struct addrinfo *addr;
const char *key;
char *key;
} tacplus_server_t;

/* set from configuration file parsing */
Expand All @@ -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;
Expand All @@ -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))
Expand All @@ -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))
Expand Down

0 comments on commit dab6c3b

Please sign in to comment.