From f9f714b3b7b9f77c0165c0850bd816cac0d46292 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Thu, 30 Mar 2017 09:42:45 -0700 Subject: During login from ssh, send remote host IP address in AUTH request The hack is to run getpeername on fd 0, because during ssh connections, it is a socket from the remote host. This is a bit fragile... Normally fd 0 interactively will be a pty or tty, so getpeername() will fail. There may be some daemons where fd0 is a socket, and returns a local or some other remote IP address, and if so, it could lead to some confusion, but it shouldn't ever break anything. I ran with tshark watching the packet exchange, and verified that the remote address field is set for ssh sessions at the start of the ssh session, and not when run in other uses. The customer ran a 3.2.1 package with this change, and it resolved their issue. --- debian/changelog | 3 ++- nss_tacplus.c | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index fefa524..43d371e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,5 @@ libnss-tacplus (1.0.2) unstable; urgency=low * added config variable "timeout" to limit time attempting to - connect to non-responding TACACS server. * added config variable "exclude_users" in /etc/tacplus_nss to avoid looking up "local" user accounts via TACACS servers. This improves overall system performance for local users, and avoids significant @@ -10,6 +9,8 @@ libnss-tacplus (1.0.2) unstable; urgency=low * Improved debugging messages. * Minor corrections to Copyright and licensing * 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. -- Dave Olson Tue, 07 Mar 2017 12:58:03 -0800 diff --git a/nss_tacplus.c b/nss_tacplus.c index 4fa652e..2d4f193 100644 --- a/nss_tacplus.c +++ b/nss_tacplus.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -67,12 +68,15 @@ static tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS]; static int tac_srv_no, tac_key_no; static char tac_service[] = "shell"; static char tac_protocol[] = "ssh"; +static char tac_rhost[INET6_ADDRSTRLEN]; static char vrfname[64]; static char *exclude_users; static uid_t min_uid = ~0U; /* largest possible */ static int debug; static int conf_parsed = 0; +static void get_remote_addr(void); + static int nss_tacplus_config(int *errnop, const char *cfile, int top) { FILE *conf; @@ -531,7 +535,7 @@ lookup_tacacs_user(struct pwbuf *pb) tac_ntop(tac_srv[srvr].addr->ai_addr) : "unknown", tac_fd); continue; } - ret = tac_author_send(tac_fd, pb->name, "", "", attr); + ret = tac_author_send(tac_fd, pb->name, "", tac_rhost, attr); if(ret < 0) { if(debug) syslog(LOG_WARNING, "%s: TACACS+ server %s send failed (%d) for" @@ -621,6 +625,8 @@ enum nss_status _nss_tacplus_getpwnam_r(const char *name, struct passwd *pw, result = nss_tacplus_config(errnop, config_file, 1); conf_parsed = result == 0 ? 2 : 1; + get_remote_addr(); + if(result) { /* no config file, no servers, etc. */ /* this is a debug because privileges may not allow access */ if(debug) @@ -730,3 +736,31 @@ enum nss_status _nss_tacplus_getpwuid_r(uid_t uid, struct passwd *pw, status = NSS_STATUS_SUCCESS; return status; } + +static void get_remote_addr(void) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof addr; + char ipstr[INET6_ADDRSTRLEN]; + + /* This is so we can fill in the rhost field when we talk to the + * TACACS+ server, when it's an ssh connection, so sites that refuse + * authorization unless from specific IP addresses will get that + * information. It's pretty much of a hack, but it works. + */ + if (getpeername(0, (struct sockaddr*)&addr, &len) == -1) + return; + + *ipstr = 0; + if (addr.ss_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); + } else { + struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; + inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr); + } + + snprintf(tac_rhost, sizeof tac_rhost, "%s", ipstr); + if(debug > 1 && tac_rhost[0]) + syslog(LOG_DEBUG, "%s: rhost=%s", nssname, tac_rhost); +} -- cgit v1.2.3