diff --git a/files/image_config/hostcfgd/common-auth-sonic.j2 b/files/image_config/hostcfgd/common-auth-sonic.j2 index d91a02120f8..288d19f714d 100644 --- a/files/image_config/hostcfgd/common-auth-sonic.j2 +++ b/files/image_config/hostcfgd/common-auth-sonic.j2 @@ -1,4 +1,4 @@ -# THIS IS AN AUTO-GENERATED FILE +#THIS IS AN AUTO-GENERATED FILE # # /etc/pam.d/common-auth- authentication settings common to all services # This file is included from other service-specific PAM config files, @@ -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 }} {% if server.vrf %} vrf={{ server.vrf }} {% endif %} 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 }} {% if server.vrf %} vrf={{ last_server.vrf }} {% endif %} 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 }} {%if server.vrf %} vrf={{ server.vrf }} {% endif %} try_first_pass {% endfor %} auth [success=1 default=ignore] pam_unix.so nullok try_first_pass diff --git a/files/image_config/hostcfgd/tacplus_nss.conf.j2 b/files/image_config/hostcfgd/tacplus_nss.conf.j2 index 61ab905ecb8..347a9ec3d8c 100644 --- a/files/image_config/hostcfgd/tacplus_nss.conf.j2 +++ b/files/image_config/hostcfgd/tacplus_nss.conf.j2 @@ -11,7 +11,7 @@ debug=on # Default: None (no TACACS+ server) # server=1.1.1.1:49,secret=test,timeout=3 {% for server in servers %} -server={{ server.ip }}:{{ server.tcp_port }},secret={{ server.passkey }},timeout={{ server.timeout }} +server={{ server.ip }}:{{ server.tcp_port }},secret={{ server.passkey }},timeout={{ server.timeout }}{% if server.vrf %},vrf={{ server.vrf }}{% endif %}{{''}} {% endfor %} # user_priv - set the map between TACACS+ user privilege and local user's passwd diff --git a/src/tacacs/nss/0003-management-vrf-support.patch b/src/tacacs/nss/0003-management-vrf-support.patch new file mode 100644 index 00000000000..35e30f0781b --- /dev/null +++ b/src/tacacs/nss/0003-management-vrf-support.patch @@ -0,0 +1,43 @@ +From b20aad31e186e27cc83432b405555420f94c6049 Mon Sep 17 00:00:00 2001 +From: Kannan KVS +Date: Mon, 8 Oct 2018 03:10:55 -0700 +Subject: [PATCH] MANAGEMENT_VRF_TACACS_NSS_CHANGES + +--- + nss_tacplus.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/nss_tacplus.c b/nss_tacplus.c +index 6e4fddd..1e222dd 100644 +--- a/nss_tacplus.c ++++ b/nss_tacplus.c +@@ -76,6 +76,7 @@ static useradd_info_t useradd_grp_list[MAX_TACACS_USER_PRIV + 1]; + + static char *tac_service = "shell"; + static char *tac_protocol = "ssh"; ++static char vrfname[64]; + static bool debug = false; + static bool many_to_one = false; + +@@ -124,6 +125,9 @@ static int parse_tac_server(char *srv_buf) + return -1; + } + } ++ else if(!strncmp(token, "vrf=", 4)){ ++ strncpy(vrfname, token + 4, sizeof(vrfname)); ++ } + else if(!strncmp(token, "secret=", 7)) { + if(tac_srv[tac_srv_no].key) + free(tac_srv[tac_srv_no].key); +@@ -633,7 +637,7 @@ connect_tacacs(struct tac_attrib **attr, int srvr) + return -1; + + fd = tac_connect_single(tac_srv[srvr].addr, tac_srv[srvr].key, NULL, +- tac_srv[srvr].timeout); ++ tac_srv[srvr].timeout, vrfname[0] ? vrfname : NULL); + if(fd >= 0) { + *attr = NULL; /* so tac_add_attr() allocates memory */ + tac_add_attrib(attr, "service", tac_service); +-- +2.7.4 + diff --git a/src/tacacs/nss/Makefile b/src/tacacs/nss/Makefile index 259e9b28138..d9c858bdcb3 100644 --- a/src/tacacs/nss/Makefile +++ b/src/tacacs/nss/Makefile @@ -14,6 +14,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Apply patch git am ../0001-Modify-user-map-profile.patch git am ../0002-Enable-modifying-local-user-permission.patch + git am ../0003-management-vrf-support.patch dpkg-buildpackage -rfakeroot -b -us -uc popd diff --git a/src/tacacs/pam/0004-management-vrf-support.patch b/src/tacacs/pam/0004-management-vrf-support.patch new file mode 100644 index 00000000000..4ff6ecc28dc --- /dev/null +++ b/src/tacacs/pam/0004-management-vrf-support.patch @@ -0,0 +1,240 @@ +From 6005f4a884f250787bdc070235879b14186ade2c Mon Sep 17 00:00:00 2001 +From: Kannan KVS +Date: Mon, 8 Oct 2018 02:58:42 -0700 +Subject: [PATCH] MANAGEMENT_VRF_TACACS_PAM_CHANGES + +--- + libtac/include/libtac.h | 4 ++-- + libtac/lib/connect.c | 21 +++++++++++++++++---- + pam_tacplus.c | 12 +++++++----- + support.c | 3 +++ + tacc.c | 15 ++++++++++----- + 5 files changed, 39 insertions(+), 16 deletions(-) + +diff --git a/libtac/include/libtac.h b/libtac/include/libtac.h +index 6dc42ab..0c9d3d2 100644 +--- a/libtac/include/libtac.h ++++ b/libtac/include/libtac.h +@@ -135,8 +135,8 @@ extern int tac_readtimeout_enable; + /* connect.c */ + extern int tac_timeout; + +-int tac_connect(struct addrinfo **, char **, int); +-int tac_connect_single(const struct addrinfo *, const char *, struct addrinfo *, int); ++int tac_connect(struct addrinfo **, char **, int, char *); ++int tac_connect_single(const struct addrinfo *, const char *, struct addrinfo *, int, char *); + char *tac_ntop(const struct sockaddr *); + + int tac_authen_send(int, const char *, const char *, const char *, +diff --git a/libtac/lib/connect.c b/libtac/lib/connect.c +index 47f598a..5035135 100644 +--- a/libtac/lib/connect.c ++++ b/libtac/lib/connect.c +@@ -42,7 +42,7 @@ int tac_timeout = 5; + * >= 0 : valid fd + * < 0 : error status code, see LIBTAC_STATUS_... + */ +-int tac_connect(struct addrinfo **server, char **key, int servers) { ++int tac_connect(struct addrinfo **server, char **key, int servers, char *iface) { + int tries; + int fd=-1; + +@@ -50,7 +50,7 @@ int tac_connect(struct addrinfo **server, char **key, int servers) { + TACSYSLOG((LOG_ERR, "%s: no TACACS+ servers defined", __FUNCTION__)) + } else { + for ( tries = 0; tries < servers; tries++ ) { +- if((fd=tac_connect_single(server[tries], key[tries], NULL, tac_timeout)) >= 0 ) { ++ if((fd=tac_connect_single(server[tries], key[tries], NULL, tac_timeout, iface)) >= 0 ) { + /* tac_secret was set in tac_connect_single on success */ + break; + } +@@ -66,8 +66,9 @@ int tac_connect(struct addrinfo **server, char **key, int servers) { + /* return value: + * >= 0 : valid fd + * < 0 : error status code, see LIBTAC_STATUS_... ++ * If iface is non-null, try to BIND to that interface, to support specific routing, including VRF. + */ +-int tac_connect_single(const struct addrinfo *server, const char *key, struct addrinfo *srcaddr, int timeout) { ++int tac_connect_single(const struct addrinfo *server, const char *key, struct addrinfo *srcaddr, int timeout, char *iface) { + int retval = LIBTAC_STATUS_CONN_ERR; /* default retval */ + int fd = -1; + int flags, rc; +@@ -91,6 +92,19 @@ int tac_connect_single(const struct addrinfo *server, const char *key, struct ad + return LIBTAC_STATUS_CONN_ERR; + } + ++ if (iface) { ++ /* do not fail if the bind fails, connection may still succeed */ ++ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface, ++ strlen(iface)+1) < 0) { ++ TACSYSLOG((LOG_WARNING, ":%s: Binding socket to device %s failed.", ++ __FUNCTION__, iface)) ++ } else { ++ TACDEBUG((LOG_DEBUG, "%s: Binding socket to device %s succeeded.", ++ __FUNCTION__, iface)) ++ } ++ ++ } ++ + /* get flags for restoration later */ + flags = fcntl(fd, F_GETFL, 0); + +@@ -166,7 +180,6 @@ int tac_connect_single(const struct addrinfo *server, const char *key, struct ad + } + + /* connected ok */ +- TACDEBUG((LOG_DEBUG, "%s: connected to %s", __FUNCTION__, ip)) + retval = fd; + + /* set current tac_secret */ +diff --git a/pam_tacplus.c b/pam_tacplus.c +index 2b7d2cd..38e2a70 100644 +--- a/pam_tacplus.c ++++ b/pam_tacplus.c +@@ -53,6 +53,8 @@ static tacplus_server_t active_server; + /* accounting task identifier */ + static short int task_id = 0; + ++extern char *__vrfname; ++ + + /* Helper functions */ + int _pam_send_account(int tac_fd, int type, const char *user, char *tty, +@@ -175,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); ++ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout, __vrfname); + if (tac_fd < 0) { + _pam_log(LOG_WARNING, "%s: error sending %s (fd)", + __FUNCTION__, typemsg); +@@ -274,9 +276,9 @@ 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, NULL, tac_timeout, __vrfname); + if (tac_fd < 0) { +- _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i); ++ _pam_log(LOG_ERR, "%s: connection to srv %d failed", __FUNCTION__, srv_i); + continue; + } + if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_LOGIN) < 0) { +@@ -577,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); ++ tac_fd = tac_connect_single(active_server.addr, active_server.key, NULL, tac_timeout, __vrfname); + if(tac_fd < 0) { + _pam_log (LOG_ERR, "TACACS+ server unavailable"); + if(arep.msg != NULL) +@@ -760,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); ++ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, 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 44efee3..be0142d 100644 +--- a/support.c ++++ b/support.c +@@ -36,6 +36,7 @@ int tac_srv_no = 0; + char tac_service[64]; + char tac_protocol[64]; + char tac_prompt[64]; ++char *__vrfname=NULL; + + void _pam_log(int err, const char *format,...) { + char msg[256]; +@@ -271,6 +272,8 @@ int _pam_parse (int argc, const char **argv) { + } else { + tac_readtimeout_enable = 1; + } ++ } else if(!strncmp(*argv, "vrf=", 4)) { ++ __vrfname = strdup(*argv + 4); + } else { + _pam_log (LOG_WARNING, "unrecognized option: %s", *argv); + } +diff --git a/tacc.c b/tacc.c +index d7c6e1a..fcc7d8c 100644 +--- a/tacc.c ++++ b/tacc.c +@@ -76,6 +76,7 @@ int tac_encryption = 1; + typedef unsigned char flag; + flag quiet = 0; + char *user = NULL; /* global, because of signal handler */ ++char *iface = NULL; /* -I interface or VRF to use for connection */ + + /* command line options */ + static struct option long_options[] = { +@@ -97,6 +98,7 @@ static struct option long_options[] = { + { "service", required_argument, NULL, 'S' }, + { "protocol", required_argument, NULL, 'P' }, + { "remote", required_argument, NULL, 'r' }, ++ { "interface", required_argument, NULL, 'I' }, + { "login", required_argument, NULL, 'L' }, + + /* modifiers */ +@@ -107,7 +109,7 @@ static struct option long_options[] = { + { 0, 0, 0, 0 } }; + + /* command line letters */ +-char *opt_string = "TRAVhu:p:s:k:c:qr:wnS:P:L:"; ++char *opt_string = "TRAVIhu:p:s:k:c:qr:wnS:P:L:"; + + int main(int argc, char **argv) { + char *pass = NULL; +@@ -168,6 +170,9 @@ int main(int argc, char **argv) { + showversion(argv[0]); + case 'h': + showusage(argv[0]); ++ case 'I': ++ iface = optarg; ++ break; + case 'u': + user = optarg; + break; +@@ -283,7 +288,7 @@ int main(int argc, char **argv) { + tac_add_attrib(&attr, "service", service); + tac_add_attrib(&attr, "protocol", protocol); + +- tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60); ++ tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60, iface); + if (tac_fd < 0) { + if (!quiet) + printf("Error connecting to TACACS+ server: %m\n"); +@@ -321,7 +326,7 @@ int main(int argc, char **argv) { + tac_add_attrib(&attr, "service", service); + tac_add_attrib(&attr, "protocol", protocol); + +- tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60); ++ tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60, iface); + if (tac_fd < 0) { + if (!quiet) + printf("Error connecting to TACACS+ server: %m\n"); +@@ -404,7 +409,7 @@ int main(int argc, char **argv) { + sprintf(buf, "%hu", task_id); + tac_add_attrib(&attr, "task_id", buf); + +- tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60); ++ tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60, iface); + if (tac_fd < 0) { + if (!quiet) + printf("Error connecting to TACACS+ server: %m\n"); +@@ -445,7 +450,7 @@ void authenticate(const struct addrinfo *tac_server, const char *tac_secret, + int ret; + struct areply arep; + +- tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60); ++ tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60, iface); + if (tac_fd < 0) { + if (!quiet) + printf("Error connecting to TACACS+ server: %m\n"); +-- +2.7.4 + diff --git a/src/tacacs/pam/Makefile b/src/tacacs/pam/Makefile index 21d8eeace73..a54f577bc84 100644 --- a/src/tacacs/pam/Makefile +++ b/src/tacacs/pam/Makefile @@ -17,6 +17,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : 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-Obfuscate-key-before-printing-to-syslog.patch + git apply ../0004-management-vrf-support.patch dpkg-buildpackage -rfakeroot -b -us -uc popd