diff --git a/files/image_config/hostcfgd/common-auth-sonic.j2 b/files/image_config/hostcfgd/common-auth-sonic.j2 index d91a02120f8..e6a51fd6309 100644 --- a/files/image_config/hostcfgd/common-auth-sonic.j2 +++ b/files/image_config/hostcfgd/common-auth-sonic.j2 @@ -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 }} 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 }} {{ '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 }} 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 }} {{ '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 }} 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 }} {{ 'source_ip=%s' % src_ip if src_ip }} try_first_pass {% endfor %} auth [success=1 default=ignore] pam_unix.so nullok try_first_pass diff --git a/files/image_config/hostcfgd/hostcfgd b/files/image_config/hostcfgd/hostcfgd index 837c5351e0e..b5492be50d5 100755 --- a/files/image_config/hostcfgd/hostcfgd +++ b/files/image_config/hostcfgd/hostcfgd @@ -90,6 +90,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: @@ -104,7 +108,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) @@ -127,7 +131,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) diff --git a/files/image_config/hostcfgd/tacplus_nss.conf.j2 b/files/image_config/hostcfgd/tacplus_nss.conf.j2 index 61ab905ecb8..e9229edf095 100644 --- a/files/image_config/hostcfgd/tacplus_nss.conf.j2 +++ b/files/image_config/hostcfgd/tacplus_nss.conf.j2 @@ -1,4 +1,4 @@ -onfiguration for libnss-tacplus +# Configuration for libnss-tacplus # debug - If you want to open debug log, set it on # Default: off @@ -7,6 +7,13 @@ onfiguration for libnss-tacplus debug=on {% endif %} +# src_ip - set source address of TACACS+ protocl 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 diff --git a/src/tacacs/nss/0002-Add-support-for-TACACS-source-address.patch b/src/tacacs/nss/0002-Add-support-for-TACACS-source-address.patch new file mode 100644 index 00000000000..241cd3ec6e3 --- /dev/null +++ b/src/tacacs/nss/0002-Add-support-for-TACACS-source-address.patch @@ -0,0 +1,64 @@ +From a1b2b5193a6b1ce84d3961ecbc9ed16d8c9df44e Mon Sep 17 00:00:00 2001 +From: Liuqu +Date: Wed, 13 Dec 2017 22:50:45 +0800 +Subject: [PATCH] Add support for TACACS+ source address + +--- + nss_tacplus.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/nss_tacplus.c b/nss_tacplus.c +index ecfa0b0..0d78ced 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"; +@@ -258,6 +259,21 @@ 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; ++ ++ memset(&hints, 0, sizeof hints); ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_socktype = SOCK_STREAM; ++ ++ if(source_addr) ++ freeaddrinfo(source_addr); ++ ++ 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", +@@ -278,6 +294,8 @@ static int parse_config(const char *file) + nssname, n, tac_ntop(tac_srv[n].addr->ai_addr), + tac_srv[n].key, 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++) { +@@ -630,7 +648,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); + if(fd >= 0) { + *attr = NULL; /* so tac_add_attr() allocates memory */ +-- +1.9.1 + diff --git a/src/tacacs/nss/Makefile b/src/tacacs/nss/Makefile index 4f1a337b34b..d1e8821b319 100644 --- a/src/tacacs/nss/Makefile +++ b/src/tacacs/nss/Makefile @@ -13,6 +13,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Apply patch git apply ../0001-Modify-user-map-profile.patch + git apply ../0002-Add-support-for-TACACS-source-address.patch dpkg-buildpackage -rfakeroot -b -us -uc popd diff --git a/src/tacacs/pam/0003-Add-support-for-source-ip-address.patch b/src/tacacs/pam/0003-Add-support-for-source-ip-address.patch new file mode 100644 index 00000000000..48353036591 --- /dev/null +++ b/src/tacacs/pam/0003-Add-support-for-source-ip-address.patch @@ -0,0 +1,124 @@ +From 9494f71bc5f04b28b790ab25f1729b480ca18879 Mon Sep 17 00:00:00 2001 +From: Liuqu +Date: Thu, 14 Dec 2017 18:30:46 +0800 +Subject: [PATCH] Add support for source ip address + +--- + 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 2b7d2cd..4369306 100644 +--- a/pam_tacplus.c ++++ b/pam_tacplus.c +@@ -175,7 +175,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); ++ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, tac_source_addr, tac_timeout); + if (tac_fd < 0) { + _pam_log(LOG_WARNING, "%s: error sending %s (fd)", + __FUNCTION__, typemsg); +@@ -274,7 +274,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); ++ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, tac_source_addr, tac_timeout); + if (tac_fd < 0) { + _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i); + continue; +@@ -577,7 +577,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); ++ tac_fd = tac_connect_single(active_server.addr, active_server.key, tac_source_addr, tac_timeout); + if(tac_fd < 0) { + _pam_log (LOG_ERR, "TACACS+ server unavailable"); + if(arep.msg != NULL) +@@ -760,7 +760,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); ++ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, tac_source_addr, tac_timeout); + 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 44efee3..14bfca1 100644 +--- a/support.c ++++ b/support.c +@@ -36,6 +36,8 @@ int tac_srv_no = 0; + char tac_service[64]; + char tac_protocol[64]; + char tac_prompt[64]; ++char tac_source_ip[64]; ++struct addrinfo *tac_source_addr = NULL; + + void _pam_log(int err, const char *format,...) { + char msg[256]; +@@ -271,6 +273,10 @@ int _pam_parse (int argc, const char **argv) { + } else { + tac_readtimeout_enable = 1; + } ++ } 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); + } +@@ -289,8 +295,33 @@ 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; ++ ++ /* check if source address is configured */ ++ if (*tac_source_ip == 0) ++ return; ++ ++ /* set the source ip address for the tacacs packets */ ++ if (tac_source_ip != NULL) { ++ 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 *); +-- +1.9.1 + diff --git a/src/tacacs/pam/Makefile b/src/tacacs/pam/Makefile index 70766879140..832795d6203 100644 --- a/src/tacacs/pam/Makefile +++ b/src/tacacs/pam/Makefile @@ -16,6 +16,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Apply patch git apply ../0001-Don-t-init-declarations-in-a-for-loop.patch git apply ../0002-Fix-libtac2-bin-install-directory-error.patch + git apply ../0003-Add-support-for-source-ip-address.patch dpkg-buildpackage -rfakeroot -b -us -uc popd