summaryrefslogtreecommitdiff
path: root/nss_tacplus.c
diff options
context:
space:
mode:
Diffstat (limited to 'nss_tacplus.c')
-rw-r--r--nss_tacplus.c36
1 files changed, 35 insertions, 1 deletions
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 <ctype.h>
#include <nss.h>
#include <libaudit.h>
+#include <sys/socket.h>
#include <tacplus/libtac.h>
#include <tacplus/map_tacplus_user.h>
@@ -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);
+}