diff options
author | Jeroen <jeroen@nijhofnet.nl> | 2011-04-25 22:16:34 +0200 |
---|---|---|
committer | Jeroen <jeroen@nijhofnet.nl> | 2011-04-25 22:19:33 +0200 |
commit | eb6cf3c69186698f0d5fcc5a89dd81a823794937 (patch) | |
tree | 69b9c3a92af40d8d2e647725c04aad678e6cfd43 | |
parent | 28ad740550c92826a54cf830946ce907d948d898 (diff) | |
download | pam_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-- | ChangeLog | 9 | ||||
-rw-r--r-- | README | 49 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | libtac/include/libtac.h | 4 | ||||
-rw-r--r-- | libtac/lib/connect.c | 39 | ||||
-rw-r--r-- | libtac/lib/header.c | 2 | ||||
-rw-r--r-- | pam_tacplus.c | 19 | ||||
-rw-r--r-- | pam_tacplus.h | 4 | ||||
-rw-r--r-- | sample.pam | 9 | ||||
-rw-r--r-- | support.c | 30 |
10 files changed, 90 insertions, 77 deletions
@@ -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 @@ -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 @@ -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 @@ -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 */ |