summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen <jeroen@nijhofnet.nl>2011-04-25 22:16:34 +0200
committerJeroen <jeroen@nijhofnet.nl>2011-04-25 22:19:33 +0200
commiteb6cf3c69186698f0d5fcc5a89dd81a823794937 (patch)
tree69b9c3a92af40d8d2e647725c04aad678e6cfd43
parent28ad740550c92826a54cf830946ce907d948d898 (diff)
downloadpam_tacplus-eb6cf3c69186698f0d5fcc5a89dd81a823794937.tar.gz
pam_tacplus-eb6cf3c69186698f0d5fcc5a89dd81a823794937.zip
Removed encrypt option just check if there is a secret (key).
Removed first_hit option because you can get the same behaviour by using only one server. Added multiple secret support, you can now specify different secrets (keys) for different servers. connect.c: improved connection error handling by using getpeername() to check if connection is still valid. This was needed since we are using non-blocking sockets. Properly handle multiple servers when authenticating, patch from Gregg Nemas, thanks!
-rw-r--r--ChangeLog9
-rw-r--r--README49
-rw-r--r--configure.ac2
-rw-r--r--libtac/include/libtac.h4
-rw-r--r--libtac/lib/connect.c39
-rw-r--r--libtac/lib/header.c2
-rw-r--r--pam_tacplus.c19
-rw-r--r--pam_tacplus.h4
-rw-r--r--sample.pam9
-rw-r--r--support.c30
10 files changed, 90 insertions, 77 deletions
diff --git a/ChangeLog b/ChangeLog
index 2d656b4..d83141a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+1.3.4
+* removed encrypt option just check if there is a secret (key).
+* removed first_hit option because you can get the same behaviour by using only one server.
+* added multiple secret support,
+ you can now specify different secrets (keys) for different servers.
+* connect.c: improved connection error handling by using getpeername() to check if connection
+ is still valid. This was needed since we are using non-blocking sockets.
+* properly handle multiple servers when authenticating, patch from Gregg Nemas, thanks!
+
1.3.3
* pam_tacplus.h: changed bitflags to hex, thanks Jason!
* Added gitignore for build stuff
diff --git a/README b/README
index 8805dd9..ea11bf7 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
-pam_tacplus v1.3.3
-Apr 21 2011
+pam_tacplus v1.3.4
+Apr 25 2011
This PAM module support the following functions:
@@ -26,10 +26,8 @@ debug ALL output debugging information via
syslog(3); note, that the debugging
is heavy, including passwords!
-encrypt ALL encrypt TACACS+ packets; you should
- use this always in normal operations
-
-secret=STRING ALL secret key used to encrypt/decrypt
+secret=STRING ALL can be specified more than once;
+ secret key used to encrypt/decrypt
packets sent/received from the server
server=HOSTNAME auth, session can be specified more than once;
@@ -39,11 +37,6 @@ server=IP_ADDR adds a TACACS+ server to the servers
timeout=INT ALL connection timeout in seconds
default is 5 seconds
-first_hit auth if multiple servers are supplied,
- pam_tacplus will try to authenticate
- the user on all servers until it
- succeds or all servers are queried
-
login=STRING auth TACACS+ authentication service,
this can be "pap", "chap" or "login"
at the moment. Default is pap.
@@ -73,14 +66,13 @@ Example configuration:
~~~~~~~~~~~~~~~~~~~~~~
#%PAM-1.0
-auth required /lib/security/pam_tacplus.so debug server=123.123.123.123 secret=SECRET-123 encrypt
-account required /lib/security/pam_tacplus.so debug secret=SECRET-123 encrypt service=ppp protocol=lcp
+auth required /lib/security/pam_tacplus.so debug server=1.1.1.1 secret=SECRET-1
+account required /lib/security/pam_tacplus.so debug secret=SECRET-1 service=ppp protocol=lcp
account sufficient /lib/security/pam_exec.so /usr/local/bin/showenv.sh
password required /lib/security/pam_cracklib.so
password required /lib/security/pam_pwdb.so shadow use_authtok
-session required /lib/security/pam_tacplus.so debug server=123.123.123.123 server=124.124.124.124 secret=SECRET-124 encrypt service=ppp protocol=lcp
+session required /lib/security/pam_tacplus.so debug server=1.1.1.1 server=2.2.2.2 secret=SECRET-1 secret=SECRET-2 service=ppp protocol=lcp
-(note that above are five long lines)
More on server lists:
~~~~~~~~~~~~~~~~~~~~~
@@ -88,28 +80,11 @@ More on server lists:
1. Having more that one TACACS+ server defined for given management group
has following effects on authentication:
- * always, if the first server on the list is unreachable or failing
- pam_tacplus will try to authenticate user on the another one
-
- in case, where there are no modifiers like `first_hit', you
- could think the of the first server on list as primary one,
- and the others as backup/secondary servers
-
- * if the `first_hit' option is specified, if the first server
- on the list will return negative authentication reply, pam_tacplus
- will try to ask another server; this will continue until it
- will get positive reply from one of the servers, or all servers
- are probed with negative replies; then pam_tacplus will return
- with authentication failure
-
- this is useful if you have e.g. dialup server authenticating
- users who have accounts on multiple servers in your network;
- in this case, from host B won't be authenticated by TACACS+ server
- on host A (which is first on the list), but it will be authenticated
- when pam_tacplus will query the server on host B next
+ * if the first server on the list is unreachable or failing
+ pam_tacplus will try to authenticate the user against the other
+ servers until it succeeds
- in this case all the servers can be considered as having equal
- authority in authenticating users
+ * the `first_hit' option has been deprecated
* when the authentication function gets a positive reply from
a server, it saves its address for future use by account
@@ -184,10 +159,8 @@ Limitations:
Many of them for now :)
- * it's still in beta
* only subset of TACACS+ protocol is supported; it's enough for
most need, though
- * only one, common `secret' can be specified
* utilize PAM_SERVICE item obtained from PAM for TACACS+ services
* clean options and configuration code
diff --git a/configure.ac b/configure.ac
index d169d3e..1070dff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,7 +14,7 @@ AC_PREREQ(2.59)
AC_COPYRIGHT([
See the included file: COPYING for copyright information.
])
-AC_INIT(pam_tacplus, 1.3.3, [jeroen@nijhofnet.nl,kravietz@ceti.com.pl])
+AC_INIT(pam_tacplus, 1.3.4, [jeroen@nijhofnet.nl,kravietz@ceti.com.pl])
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([pam_tacplus.c])
diff --git a/libtac/include/libtac.h b/libtac/include/libtac.h
index 023b60d..dfa5ca0 100644
--- a/libtac/include/libtac.h
+++ b/libtac/include/libtac.h
@@ -57,8 +57,8 @@ extern char *tac_login;
/* connect.c */
extern int tac_timeout;
-extern int tac_connect(struct addrinfo **server, int servers);
-extern int tac_connect_single(struct addrinfo *server);
+extern int tac_connect(struct addrinfo **server, char **key, int servers);
+extern int tac_connect_single(struct addrinfo *server, char *key);
extern char *tac_ntop(const struct sockaddr *sa, size_t ai_addrlen);
extern int tac_authen_send(int fd, const char *user, char *pass, char *tty);
diff --git a/libtac/lib/connect.c b/libtac/lib/connect.c
index 7b55645..c65edf8 100644
--- a/libtac/lib/connect.c
+++ b/libtac/lib/connect.c
@@ -39,11 +39,13 @@ int tac_timeout = 5;
to the first available server from list passed
in server table.
*/
-int tac_connect(struct addrinfo **server, int servers) {
+int tac_connect(struct addrinfo **server, char **key, int servers) {
int tries = 0;
int fd, flags, retval;
fd_set readfds, writefds;
struct timeval tv;
+ socklen_t len;
+ struct sockaddr_storage addr;
if(!servers) {
syslog(LOG_ERR, "%s: no TACACS+ servers defined", __FUNCTION__);
@@ -89,17 +91,31 @@ int tac_connect(struct addrinfo **server, int servers) {
tv.tv_sec = tac_timeout;
tv.tv_usec = 0;
- /* check if socket is ready for read or write */
- if(!select(fd+1, &readfds, &writefds, NULL, &tv)) {
+ /* check if socket is ready for read and write */
+ if(select(fd+1, &readfds, &writefds, NULL, &tv) < 1) {
syslog(LOG_WARNING,
- "%s: connection timeout with %s : %m", __FUNCTION__,
+ "%s: connection failed with %s : %m", __FUNCTION__,
tac_ntop(server[tries]->ai_addr, server[tries]->ai_addrlen));
if(fcntl(fd, F_SETFL, flags)) {
syslog(LOG_WARNING, "%s: cannot restore socket flags",
- __FUNCTION__);
+ __FUNCTION__);
}
tries++;
continue;
+ } else {
+ /* check with getpeername if we have a valid connection */
+ len = sizeof addr;
+ if(getpeername(fd, (struct sockaddr*)&addr, &len) == -1) {
+ syslog(LOG_WARNING,
+ "%s: connection failed with %s : %m", __FUNCTION__,
+ tac_ntop(server[tries]->ai_addr, server[tries]->ai_addrlen));
+ if(fcntl(fd, F_SETFL, flags)) {
+ syslog(LOG_WARNING, "%s: cannot restore socket flags",
+ __FUNCTION__);
+ }
+ tries++;
+ continue;
+ }
}
/* connected ok */
@@ -110,19 +126,22 @@ int tac_connect(struct addrinfo **server, int servers) {
TACDEBUG((LOG_DEBUG, "%s: connected to %s", __FUNCTION__, \
tac_ntop(server[tries]->ai_addr, server[tries]->ai_addrlen)));
+ /* set current tac_secret */
+ tac_secret = key[tries];
return(fd);
}
/* all attempts failed */
- syslog(LOG_ERR, "%s: all possible TACACS+ servers failed", __FUNCTION__);
return(-1);
} /* tac_connect */
-int tac_connect_single(struct addrinfo *server) {
- struct addrinfo *temp[1];
- temp[0] = server;
- return(tac_connect(temp, 1));
+int tac_connect_single(struct addrinfo *server, char *key) {
+ struct addrinfo *tmpaddr[1];
+ tmpaddr[0] = server;
+ char *tmpkey[1];
+ tmpkey[0] = key;
+ return(tac_connect(tmpaddr, tmpkey, 1));
} /* tac_connect_single */
diff --git a/libtac/lib/header.c b/libtac/lib/header.c
index eaccd82..5fdd8f2 100644
--- a/libtac/lib/header.c
+++ b/libtac/lib/header.c
@@ -34,7 +34,7 @@ int session_id;
int tac_encryption;
/* Pointer to TACACS+ shared secret string. */
-char *tac_secret;
+char *tac_secret = "";
/* Pointer to TACACS+ shared login string. */
char *tac_login = "pap";
diff --git a/pam_tacplus.c b/pam_tacplus.c
index 4b4e2a6..d917491 100644
--- a/pam_tacplus.c
+++ b/pam_tacplus.c
@@ -58,6 +58,7 @@
/* support.c */
extern struct addrinfo *tac_srv[TAC_MAX_SERVERS];
+extern char *tac_srv_key[TAC_MAX_SERVERS];
extern int tac_srv_no;
extern char *tac_service;
extern char *tac_protocol;
@@ -75,11 +76,11 @@ extern void *_xcalloc (size_t size);
extern u_int32_t magic();
/* libtac */
-extern char *tac_secret;
extern int tac_encryption;
/* address of server discovered by pam_sm_authenticate */
static struct addrinfo *active_server;
+char *active_key;
/* accounting task identifier */
static short int task_id = 0;
@@ -207,7 +208,7 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv, int type) {
status = PAM_SUCCESS;
- tac_fd = tac_connect(tac_srv, tac_srv_no);
+ tac_fd = tac_connect(tac_srv, tac_srv_key, tac_srv_no);
if(tac_fd < 0) {
_pam_log(LOG_ERR, "%s: error sending %s - no servers",
__FUNCTION__, typemsg);
@@ -238,7 +239,7 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv, int type) {
for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
int tac_fd;
- tac_fd = tac_connect_single(tac_srv[srv_i]);
+ tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
if(tac_fd < 0) {
_pam_log(LOG_WARNING, "%s: error sending %s (fd)",
__FUNCTION__, typemsg);
@@ -343,13 +344,14 @@ 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]);
+ tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
if (tac_fd < 0) {
_pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
if (srv_i == tac_srv_no-1) {
_pam_log (LOG_ERR, "no more servers to connect");
return PAM_AUTHINFO_UNAVAIL;
}
+ continue;
}
if (tac_authen_send (tac_fd, user, pass, tty) < 0) {
_pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
@@ -372,6 +374,7 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
accepted us for pam_sm_acct_mgmt and exit the loop */
status = PAM_SUCCESS;
active_server = tac_srv[srv_i];
+ active_key = tac_srv_key[srv_i];
close(tac_fd);
break;
}
@@ -384,16 +387,12 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
accepted us for pam_sm_acct_mgmt and exit the loop */
status = PAM_SUCCESS;
active_server = tac_srv[srv_i];
+ active_key = tac_srv_key[srv_i];
close(tac_fd);
break;
}
}
close(tac_fd);
- /* if we are here, this means that authentication failed
- on current server; break if we are not allowed to probe
- another one, continue otherwise */
- if (!(ctrl & PAM_TAC_FIRSTHIT))
- break;
}
if (ctrl & PAM_TAC_DEBUG)
@@ -497,7 +496,7 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
tac_add_attrib(&attr, "service", tac_service);
tac_add_attrib(&attr, "protocol", tac_protocol);
- tac_fd = tac_connect_single(active_server);
+ tac_fd = tac_connect_single(active_server, active_key);
if(tac_fd < 0) {
_pam_log (LOG_ERR, "TACACS+ server unavailable");
status = PAM_AUTH_ERR;
diff --git a/pam_tacplus.h b/pam_tacplus.h
index 407958c..f06be3c 100644
--- a/pam_tacplus.h
+++ b/pam_tacplus.h
@@ -21,9 +21,7 @@
/* pam_tacplus command line options */
#define PAM_TAC_DEBUG 0x01
-#define PAM_TAC_ENCRYPT 0x02
-#define PAM_TAC_FIRSTHIT 0x04
-#define PAM_TAC_ACCT 0x08 /* account on all specified servers */
+#define PAM_TAC_ACCT 0x02 /* account on all specified servers */
/* how many TACPLUS+ servers can be defined */
#define TAC_MAX_SERVERS 4
diff --git a/sample.pam b/sample.pam
index 9d2114c..24ee86f 100644
--- a/sample.pam
+++ b/sample.pam
@@ -1,4 +1,7 @@
#%PAM-1.0
-auth required /lib/security/pam_tacplus.so debug server=tac1.foo.net server=tac2.baz.net timeout=5 secret=SECRET-1234 encrypt login=pap prompt=Enter_password: first_hit
-account required /lib/security/pam_tacplus.so debug server=tac1.foo.net timeout=5 secret=SECRET-1234 encrypt service=ppp protocol=lcp
-session required /lib/security/pam_tacplus.so debug server=tac1.foo.net timeout=5 secret=SECRET-1234 encrypt service=ppp protocol=lcp
+auth required /lib/security/pam_tacplus.so debug server=1.1.1.1 server=2.2.2.2 secret=SAME-SECRET
+account required /lib/security/pam_tacplus.so debug secret=SAME-SECRET service=ppp protocol=lcp
+account sufficient /lib/security/pam_exec.so /usr/local/bin/showenv.sh
+password required /lib/security/pam_cracklib.so
+password required /lib/security/pam_pwdb.so shadow use_authtok
+session required /lib/security/pam_tacplus.so debug server=1.1.1.1 secret=SECRET-1 server=2.2.2.2 secret=SECRET-2 service=ppp protocol=lcp
diff --git a/support.c b/support.c
index ec98987..094e2bf 100644
--- a/support.c
+++ b/support.c
@@ -35,12 +35,13 @@
struct addrinfo *tac_srv[TAC_MAX_SERVERS];
int tac_srv_no = 0;
+char *tac_srv_key[TAC_MAX_SERVERS];
+int tac_srv_key_no = 0;
char *tac_service = NULL;
char *tac_protocol = NULL;
char *tac_prompt = NULL;
/* libtac */
-extern char *tac_secret;
extern char *tac_login;
extern int tac_encryption;
extern int tac_timeout;
@@ -161,16 +162,12 @@ int _pam_parse (int argc, const char **argv) {
int ctrl = 0;
/* otherwise the list will grow with each call */
- tac_srv_no = 0;
+ tac_srv_no = tac_srv_key_no = 0;
+ tac_encryption = 0;
for (ctrl = 0; argc-- > 0; ++argv) {
if (!strcmp (*argv, "debug")) { /* all */
ctrl |= PAM_TAC_DEBUG;
- } else if (!strcmp (*argv, "encrypt")) {
- ctrl |= PAM_TAC_ENCRYPT;
- tac_encryption = 1;
- } else if (!strcmp (*argv, "first_hit")) { /* authentication */
- ctrl |= PAM_TAC_FIRSTHIT;
} else if (!strncmp (*argv, "service=", 8)) { /* author & acct */
tac_service = (char *) _xcalloc (strlen (*argv + 8) + 1);
strcpy (tac_service, *argv + 8);
@@ -212,8 +209,15 @@ int _pam_parse (int argc, const char **argv) {
TAC_MAX_SERVERS);
}
} else if (!strncmp (*argv, "secret=", 7)) {
- tac_secret = (char *) _xcalloc (strlen (*argv + 7) + 1);
- strcpy (tac_secret, *argv + 7);
+ tac_encryption = 1;
+ if(tac_srv_key_no < TAC_MAX_SERVERS) {
+ tac_srv_key[tac_srv_key_no] = (char *) _xcalloc (strlen (*argv + 7) + 1);
+ strcpy (tac_srv_key[tac_srv_key_no], *argv + 7);
+ tac_srv_key_no++;
+ } else {
+ _pam_log(LOG_ERR, "maximum number of secrets (%d) exceeded, skipping",
+ TAC_MAX_SERVERS);
+ }
} else if (!strncmp (*argv, "timeout=", 8)) {
tac_timeout = atoi(*argv + 8);
} else if (!strncmp (*argv, "login=", 6)) {
@@ -224,6 +228,14 @@ int _pam_parse (int argc, const char **argv) {
}
}
+ if (tac_srv_key_no == 0) {
+ tac_srv_key[0] = "";
+ tac_srv_key_no++;
+ }
+ for (;tac_srv_key_no < tac_srv_no;tac_srv_key_no++) {
+ tac_srv_key[tac_srv_key_no] = tac_srv_key[0];
+ }
+
return ctrl;
} /* _pam_parse */