[TACACS+]: Add support to specify source address for TACACS+ (#4610)
This pull request was cherry picked from "#1238" to resolve the conflicts. - Why I did it Add support to specify source address for TACACS+ - How I did it Add patches for libpam-tacplus and libnss-tacplus. The patches parse the new option 'src_ip' and store the converted addrinfo. Then the addrinfo is used for TACACS+ connection. Add a attribute 'src_ip' for table "TACPLUS|global" in configDB Add some code to adapt to the attribute 'src_ip'. - How to verify it Config command for source address PR in sonic-utilities config tacacs src_ip <ip_address> - Description for the changelog Add patches to specify source address for the TACACS+ outgoing packets. - A picture of a cute animal (not mandatory but encouraged) **UT logs: ** UT_tacacs_source_intf.txt
This commit is contained in:
parent
1dcf8ec04f
commit
7d003c3518
@ -15,16 +15,16 @@ auth [success=1 default=ignore] pam_unix.so nullok try_first_pass
|
||||
{% elif auth['login'] == 'local,tacacs+' %}
|
||||
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_unix.so nullok try_first_pass
|
||||
{% for server in servers | sub(0, -1) %}
|
||||
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_tacplus.so server={{ server.ip }}:{{ server.tcp_port }} secret={{ server.passkey }} login={{ server.auth_type }} timeout={{ server.timeout }} {% if server.vrf %} vrf={{ server.vrf }} {% endif %} try_first_pass
|
||||
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_tacplus.so server={{ server.ip }}:{{ server.tcp_port }} secret={{ server.passkey }} login={{ server.auth_type }} timeout={{ server.timeout }} {% if server.vrf %} vrf={{ server.vrf }} {% endif %} {{ 'source_ip=%s' % src_ip if src_ip }} try_first_pass
|
||||
{% endfor %}
|
||||
{% if servers | count %}
|
||||
{% set last_server = servers | last %}
|
||||
auth [success=1 default=ignore] pam_tacplus.so server={{ last_server.ip }}:{{ last_server.tcp_port }} secret={{ last_server.passkey }} login={{ last_server.auth_type }} timeout={{ last_server.timeout }} {% if last_server.vrf %} vrf={{ last_server.vrf }} {% endif %} try_first_pass
|
||||
auth [success=1 default=ignore] pam_tacplus.so server={{ last_server.ip }}:{{ last_server.tcp_port }} secret={{ last_server.passkey }} login={{ last_server.auth_type }} timeout={{ last_server.timeout }} {% if last_server.vrf %} vrf={{ last_server.vrf }} {% endif %} {{ 'source_ip=%s' % src_ip if src_ip }} try_first_pass
|
||||
|
||||
{% endif %}
|
||||
{% elif auth['login'] == 'tacacs+' or auth['login'] == 'tacacs+,local' %}
|
||||
{% for server in servers %}
|
||||
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_tacplus.so server={{ server.ip }}:{{ server.tcp_port }} secret={{ server.passkey }} login={{ server.auth_type }} timeout={{ server.timeout }} {%if server.vrf %} vrf={{ server.vrf }} {% endif %} try_first_pass
|
||||
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_tacplus.so server={{ server.ip }}:{{ server.tcp_port }} secret={{ server.passkey }} login={{ server.auth_type }} timeout={{ server.timeout }} {%if server.vrf %} vrf={{ server.vrf }} {% endif %} {{ 'source_ip=%s' % src_ip if src_ip }} try_first_pass
|
||||
{% endfor %}
|
||||
auth [success=1 default=ignore] pam_unix.so nullok try_first_pass
|
||||
|
||||
|
@ -212,6 +212,10 @@ class AaaCfg(object):
|
||||
auth.update(self.auth)
|
||||
tacplus_global = self.tacplus_global_default.copy()
|
||||
tacplus_global.update(self.tacplus_global)
|
||||
if 'src_ip' in tacplus_global:
|
||||
src_ip = tacplus_global['src_ip']
|
||||
else:
|
||||
src_ip = None
|
||||
|
||||
servers_conf = []
|
||||
if self.tacplus_servers:
|
||||
@ -226,7 +230,7 @@ class AaaCfg(object):
|
||||
env = jinja2.Environment(loader=jinja2.FileSystemLoader('/'), trim_blocks=True)
|
||||
env.filters['sub'] = sub
|
||||
template = env.get_template(template_file)
|
||||
pam_conf = template.render(auth=auth, servers=servers_conf)
|
||||
pam_conf = template.render(auth=auth, src_ip=src_ip, servers=servers_conf)
|
||||
with open(PAM_AUTH_CONF, 'w') as f:
|
||||
f.write(pam_conf)
|
||||
|
||||
@ -249,7 +253,7 @@ class AaaCfg(object):
|
||||
# Set tacacs+ server in nss-tacplus conf
|
||||
template_file = os.path.abspath(NSS_TACPLUS_CONF_TEMPLATE)
|
||||
template = env.get_template(template_file)
|
||||
nss_tacplus_conf = template.render(debug=self.debug, servers=servers_conf)
|
||||
nss_tacplus_conf = template.render(debug=self.debug, src_ip=src_ip, servers=servers_conf)
|
||||
with open(NSS_TACPLUS_CONF, 'w') as f:
|
||||
f.write(nss_tacplus_conf)
|
||||
|
||||
|
@ -7,6 +7,13 @@
|
||||
debug=on
|
||||
{% endif %}
|
||||
|
||||
# src_ip - set source address of TACACS+ protocol packets
|
||||
# Default: None (auto source ip address)
|
||||
# src_ip=2.2.2.2
|
||||
{% if src_ip %}
|
||||
src_ip={{ src_ip }}
|
||||
{% endif %}
|
||||
|
||||
# server - set ip address, tcp port, secret string and timeout for TACACS+ servers
|
||||
# Default: None (no TACACS+ server)
|
||||
# server=1.1.1.1:49,secret=test,timeout=3
|
||||
|
@ -0,0 +1,77 @@
|
||||
From 61e951efe54085fe427a32d0e7db8ef08c02fa95 Mon Sep 17 00:00:00 2001
|
||||
From: Venkatesan Mahalingam <venkatesan_mahalinga@dell.com>
|
||||
Date: Mon, 6 Jul 2020 12:14:26 -0700
|
||||
Subject: [PATCH] Add support for TACACS+ source address.
|
||||
|
||||
Signed-off-by: Venkatesan Mahalingam <venkatesan_mahalinga@dell.com>
|
||||
---
|
||||
nss_tacplus.c | 25 ++++++++++++++++++++++++-
|
||||
1 file changed, 24 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/nss_tacplus.c b/nss_tacplus.c
|
||||
index 64a9328..bf6b934 100644
|
||||
--- a/nss_tacplus.c
|
||||
+++ b/nss_tacplus.c
|
||||
@@ -73,6 +73,7 @@ typedef struct {
|
||||
static tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS];
|
||||
static int tac_srv_no;
|
||||
static useradd_info_t useradd_grp_list[MAX_TACACS_USER_PRIV + 1];
|
||||
+static struct addrinfo *source_addr;
|
||||
|
||||
static char *tac_service = "shell";
|
||||
static char *tac_protocol = "ssh";
|
||||
@@ -247,6 +248,10 @@ static int parse_config(const char *file)
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
+ if(source_addr) {
|
||||
+ freeaddrinfo(source_addr);
|
||||
+ source_addr = NULL;
|
||||
+ }
|
||||
debug = false;
|
||||
tac_srv_no = 0;
|
||||
while(fgets(buf, sizeof buf, fp)) {
|
||||
@@ -262,6 +267,22 @@ static int parse_config(const char *file)
|
||||
else if(!strncmp(buf, "user_priv=", 10)) {
|
||||
parse_user_priv(buf);
|
||||
}
|
||||
+ else if(!strncmp(buf, "src_ip=", 7)) {
|
||||
+ struct addrinfo hints;
|
||||
+ char *ip = buf + 7, *new_line;
|
||||
+
|
||||
+ // Remove the new line character as getaddrinfo is not working for IPv6 address with '\n'.
|
||||
+ if ((new_line = strchr(buf, '\n')) != NULL) {
|
||||
+ *new_line = '\0';
|
||||
+ }
|
||||
+ memset(&hints, 0, sizeof hints);
|
||||
+ hints.ai_family = AF_UNSPEC;
|
||||
+ hints.ai_socktype = SOCK_STREAM;
|
||||
+
|
||||
+ if(0 != getaddrinfo(ip, NULL, &hints, &source_addr))
|
||||
+ syslog(LOG_ERR, "%s: error setting the source ip information",
|
||||
+ nssname);
|
||||
+ }
|
||||
else if(!strncmp(buf, "server=", 7)) {
|
||||
if(TAC_PLUS_MAXSERVERS <= tac_srv_no) {
|
||||
syslog(LOG_ERR, "%s: tac server num is more than %d",
|
||||
@@ -282,6 +303,8 @@ static int parse_config(const char *file)
|
||||
nssname, n, tac_ntop(tac_srv[n].addr->ai_addr),
|
||||
tac_srv[n].key[0], tac_srv[n].timeout);
|
||||
}
|
||||
+ syslog(LOG_DEBUG, "%s: src_ip=%s", nssname, NULL == source_addr
|
||||
+ ? "NULL" : tac_ntop(source_addr->ai_addr));
|
||||
syslog(LOG_DEBUG, "%s: many_to_one %s", nssname, 1 == many_to_one
|
||||
? "enable" : "disable");
|
||||
for(n = MIN_TACACS_USER_PRIV; n <= MAX_TACACS_USER_PRIV; n++) {
|
||||
@@ -690,7 +713,7 @@ connect_tacacs(struct tac_attrib **attr, int srvr)
|
||||
if(!*tac_service) /* reported at config file processing */
|
||||
return -1;
|
||||
|
||||
- fd = tac_connect_single(tac_srv[srvr].addr, tac_srv[srvr].key, NULL,
|
||||
+ fd = tac_connect_single(tac_srv[srvr].addr, tac_srv[srvr].key, source_addr,
|
||||
tac_srv[srvr].timeout, vrfname[0] ? vrfname : NULL);
|
||||
if(fd >= 0) {
|
||||
*attr = NULL; /* so tac_add_attr() allocates memory */
|
||||
--
|
||||
2.7.4
|
||||
|
@ -24,6 +24,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
|
||||
git $(GIT_APPLY) ../0004-Skip-accessing-tacacs-servers-for-local-non-tacacs-u.patch
|
||||
git $(GIT_APPLY) ../0005-libnss-Modify-parsing-of-IP-addr-and-port-number-str.patch
|
||||
git $(GIT_APPLY) ../0006-fix-compiling-warning-about-token-dereference.patch
|
||||
git $(GIT_APPLY) ../0007-Add-support-for-TACACS-source-address.patch
|
||||
|
||||
dpkg-buildpackage -rfakeroot -b -us -uc
|
||||
popd
|
||||
|
131
src/tacacs/pam/0006-Add-support-for-source-ip-address.patch
Normal file
131
src/tacacs/pam/0006-Add-support-for-source-ip-address.patch
Normal file
@ -0,0 +1,131 @@
|
||||
From 9c26e734cf9e5cec950dc8b8f474f89d87833bcd Mon Sep 17 00:00:00 2001
|
||||
From: Venkatesan Mahalingam <venkatesan_mahalinga@dell.com>
|
||||
Date: Wed, 1 Jul 2020 18:57:28 -0700
|
||||
Subject: [PATCH] Add support to specify source address for TACACS+
|
||||
|
||||
---
|
||||
pam_tacplus.c | 8 ++++----
|
||||
support.c | 31 +++++++++++++++++++++++++++++++
|
||||
support.h | 1 +
|
||||
3 files changed, 36 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/pam_tacplus.c b/pam_tacplus.c
|
||||
index 38e2a70..ec8ea27 100644
|
||||
--- a/pam_tacplus.c
|
||||
+++ b/pam_tacplus.c
|
||||
@@ -177,7 +177,7 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
|
||||
|
||||
status = PAM_SESSION_ERR;
|
||||
for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
|
||||
- tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout, __vrfname);
|
||||
+ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, tac_source_addr, tac_timeout, __vrfname);
|
||||
if (tac_fd < 0) {
|
||||
_pam_log(LOG_WARNING, "%s: error sending %s (fd)",
|
||||
__FUNCTION__, typemsg);
|
||||
@@ -276,7 +276,7 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
|
||||
if (ctrl & PAM_TAC_DEBUG)
|
||||
syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );
|
||||
|
||||
- tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout, __vrfname);
|
||||
+ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, tac_source_addr, tac_timeout, __vrfname);
|
||||
if (tac_fd < 0) {
|
||||
_pam_log(LOG_ERR, "%s: connection to srv %d failed", __FUNCTION__, srv_i);
|
||||
continue;
|
||||
@@ -579,7 +579,7 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
|
||||
if(tac_protocol[0] != '\0')
|
||||
tac_add_attrib(&attr, "protocol", tac_protocol);
|
||||
|
||||
- tac_fd = tac_connect_single(active_server.addr, active_server.key, NULL, tac_timeout, __vrfname);
|
||||
+ tac_fd = tac_connect_single(active_server.addr, active_server.key, tac_source_addr, tac_timeout, __vrfname);
|
||||
if(tac_fd < 0) {
|
||||
_pam_log (LOG_ERR, "TACACS+ server unavailable");
|
||||
if(arep.msg != NULL)
|
||||
@@ -762,7 +762,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
|
||||
if (ctrl & PAM_TAC_DEBUG)
|
||||
syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );
|
||||
|
||||
- tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout, __vrfname);
|
||||
+ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, tac_source_addr, tac_timeout, __vrfname);
|
||||
if (tac_fd < 0) {
|
||||
_pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
|
||||
continue;
|
||||
diff --git a/support.c b/support.c
|
||||
index 7c00618..3e55e2f 100644
|
||||
--- a/support.c
|
||||
+++ b/support.c
|
||||
@@ -37,6 +37,8 @@ char tac_service[64];
|
||||
char tac_protocol[64];
|
||||
char tac_prompt[64];
|
||||
char *__vrfname=NULL;
|
||||
+char tac_source_ip[64];
|
||||
+struct addrinfo *tac_source_addr = NULL;
|
||||
|
||||
void _pam_log(int err, const char *format,...) {
|
||||
char msg[256];
|
||||
@@ -183,6 +185,12 @@ int _pam_parse (int argc, const char **argv) {
|
||||
tac_protocol[0] = 0;
|
||||
tac_prompt[0] = 0;
|
||||
tac_login[0] = 0;
|
||||
+ tac_source_ip[0] = 0;
|
||||
+
|
||||
+ if (tac_source_addr != NULL) {
|
||||
+ freeaddrinfo(tac_source_addr);
|
||||
+ tac_source_addr = NULL;
|
||||
+ }
|
||||
|
||||
for (ctrl = 0; argc-- > 0; ++argv) {
|
||||
if (!strcmp (*argv, "debug")) { /* all */
|
||||
@@ -274,6 +282,10 @@ int _pam_parse (int argc, const char **argv) {
|
||||
}
|
||||
} else if(!strncmp(*argv, "vrf=", 4)) {
|
||||
__vrfname = strdup(*argv + 4);
|
||||
+ } else if (!strncmp (*argv, "source_ip=", strlen("source_ip="))) {
|
||||
+ /* source ip for the packets */
|
||||
+ strncpy (tac_source_ip, *argv + strlen("source_ip="), sizeof(tac_source_ip));
|
||||
+ set_source_ip (tac_source_ip, &tac_source_addr);
|
||||
} else {
|
||||
_pam_log (LOG_WARNING, "unrecognized option: %s", *argv);
|
||||
}
|
||||
@@ -292,8 +304,27 @@ int _pam_parse (int argc, const char **argv) {
|
||||
_pam_log(LOG_DEBUG, "tac_protocol='%s'", tac_protocol);
|
||||
_pam_log(LOG_DEBUG, "tac_prompt='%s'", tac_prompt);
|
||||
_pam_log(LOG_DEBUG, "tac_login='%s'", tac_login);
|
||||
+ _pam_log(LOG_DEBUG, "tac_source_ip='%s'", tac_source_ip);
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
} /* _pam_parse */
|
||||
|
||||
+/* set source ip address for the outgoing tacacs packets */
|
||||
+void set_source_ip(const char *tac_source_ip,
|
||||
+ struct addrinfo **source_address) {
|
||||
+
|
||||
+ struct addrinfo hints;
|
||||
+ int rv;
|
||||
+
|
||||
+ /* set the source ip address for the tacacs packets */
|
||||
+ memset(&hints, 0, sizeof(hints));
|
||||
+ hints.ai_family = AF_UNSPEC;
|
||||
+ hints.ai_socktype = SOCK_STREAM;
|
||||
+ if ((rv = getaddrinfo(tac_source_ip, NULL, &hints,
|
||||
+ source_address)) != 0) {
|
||||
+ _pam_log(LOG_ERR, "error setting the source ip information");
|
||||
+ } else {
|
||||
+ _pam_log(LOG_DEBUG, "source ip is set");
|
||||
+ }
|
||||
+}
|
||||
diff --git a/support.h b/support.h
|
||||
index 9cbd040..09b8a85 100644
|
||||
--- a/support.h
|
||||
+++ b/support.h
|
||||
@@ -37,6 +37,7 @@ extern int tac_srv_no;
|
||||
extern char tac_service[64];
|
||||
extern char tac_protocol[64];
|
||||
extern char tac_prompt[64];
|
||||
+extern struct addrinfo *tac_source_addr;
|
||||
|
||||
int _pam_parse (int, const char **);
|
||||
unsigned long _resolve_name (char *);
|
||||
--
|
||||
2.7.4
|
||||
|
@ -19,6 +19,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
|
||||
git apply ../0003-Obfuscate-key-before-printing-to-syslog.patch
|
||||
git apply ../0004-management-vrf-support.patch
|
||||
git apply ../0005-pam-Modify-parsing-of-IP-address-and-port-number-to-.patch
|
||||
git apply ../0006-Add-support-for-source-ip-address.patch
|
||||
|
||||
dpkg-buildpackage -rfakeroot -b -us -uc
|
||||
popd
|
||||
|
Reference in New Issue
Block a user