summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libtac/include/libtac.h63
-rw-r--r--libtac/lib/acct_s.c2
-rw-r--r--libtac/lib/authen_s.c10
-rw-r--r--libtac/lib/connect.c37
-rw-r--r--libtac/lib/header.c7
-rw-r--r--libtac/lib/magic.c29
-rw-r--r--libtac/lib/xalloc.c31
-rw-r--r--libtac/lib/xalloc.h2
-rw-r--r--pam_tacplus.c123
-rw-r--r--pam_tacplus.h17
-rw-r--r--support.c110
-rw-r--r--support.h46
12 files changed, 260 insertions, 217 deletions
diff --git a/libtac/include/libtac.h b/libtac/include/libtac.h
index 6ede892..aad4cbf 100644
--- a/libtac/include/libtac.h
+++ b/libtac/include/libtac.h
@@ -79,7 +79,7 @@ struct areply {
};
#ifndef TAC_PLUS_MAXSERVERS
-#define TAC_PLUS_MAXSERVERS 4
+#define TAC_PLUS_MAXSERVERS 8
#endif
#ifndef TAC_PLUS_PORT
@@ -113,8 +113,8 @@ extern int tac_ver_patch;
/* header.c */
extern int session_id;
extern int tac_encryption;
-extern char *tac_secret;
-extern char *tac_login;
+extern const char *tac_secret;
+extern char tac_login[64];
extern int tac_priv_lvl;
extern int tac_authen_method;
extern int tac_authen_service;
@@ -124,32 +124,37 @@ extern int tac_readtimeout_enable;
/* connect.c */
extern int tac_timeout;
-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,
- char *r_addr);
-extern int tac_authen_read(int fd);
-extern int tac_cont_send(int fd, char *pass);
-extern HDR *_tac_req_header(u_char type, int cont_session);
-extern void _tac_crypt(u_char *buf, HDR *th, int length);
-extern u_char *_tac_md5_pad(int len, HDR *hdr);
-extern void tac_add_attrib(struct tac_attrib **attr, char *name, char *value);
-extern void tac_free_attrib(struct tac_attrib **attr);
-extern char *tac_acct_flag2str(int flag);
-extern int tac_acct_send(int fd, int type, const char *user, char *tty, char *r_addr,
- struct tac_attrib *attr);
-extern int tac_acct_read(int fd, struct areply *arep);
-extern void *xcalloc(size_t nmemb, size_t size);
-extern void *xrealloc(void *ptr, size_t size);
-extern char *_tac_check_header(HDR *th, int type);
-extern int tac_author_send(int fd, const char *user, char *tty, char *r_addr,
- struct tac_attrib *attr);
-extern int tac_author_read(int fd, struct areply *arep);
-extern void tac_add_attrib_pair(struct tac_attrib **attr, char *name, char sep,
- char *value);
-extern int tac_read_wait(int fd, int timeout, int size, int *time_left);
+
+int tac_connect(struct addrinfo **, char **, int);
+int tac_connect_single(struct addrinfo *, const char *);
+char *tac_ntop(const struct sockaddr *);
+
+int tac_authen_send(int, const char *, char *, char *,
+ char *);
+int tac_authen_read(int);
+int tac_cont_send(int, char *);
+HDR *_tac_req_header(u_char, int);
+void _tac_crypt(u_char *, HDR *, int);
+u_char *_tac_md5_pad(int, HDR *);
+void tac_add_attrib(struct tac_attrib **, char *, char *);
+void tac_free_attrib(struct tac_attrib **);
+char *tac_acct_flag2str(int);
+int tac_acct_send(int, int, const char *, char *, char *,
+ struct tac_attrib *);
+int tac_acct_read(int, struct areply *);
+void *xcalloc(size_t, size_t);
+void *xrealloc(void *, size_t);
+char *xstrcpy(char *, const char *, size_t);
+char *_tac_check_header(HDR *, int);
+int tac_author_send(int, const char *, char *, char *,
+ struct tac_attrib *);
+int tac_author_read(int, struct areply *);
+void tac_add_attrib_pair(struct tac_attrib **, char *, char,
+ char *);
+int tac_read_wait(int, int, int, int *);
+
+/* magic.c */
+u_int32_t magic(void);
#ifdef __cplusplus
}
diff --git a/libtac/lib/acct_s.c b/libtac/lib/acct_s.c
index 200dd62..929378a 100644
--- a/libtac/lib/acct_s.c
+++ b/libtac/lib/acct_s.c
@@ -78,7 +78,7 @@ int tac_acct_send(int fd, int type, const char *user, char *tty,
tb.flags=(u_char) type;
tb.authen_method=tac_authen_method;
tb.priv_lvl=tac_priv_lvl;
- if (tac_login == NULL) {
+ if (tac_login == NULL || !*tac_login) {
/* default to PAP */
tb.authen_type = TAC_PLUS_AUTHEN_TYPE_PAP;
} else {
diff --git a/libtac/lib/authen_s.c b/libtac/lib/authen_s.c
index 8cb7cb9..87dcb74 100644
--- a/libtac/lib/authen_s.c
+++ b/libtac/lib/authen_s.c
@@ -51,7 +51,7 @@ int tac_authen_send(int fd, const char *user, char *pass, char *tty,
th=_tac_req_header(TAC_PLUS_AUTHEN, 0);
/* set some header options */
- if ((tac_login != NULL) && (strcmp(tac_login,"login") == 0)) {
+ if (tac_login != NULL && !strcmp(tac_login,"login")) {
th->version = TAC_PLUS_VER_0;
} else {
th->version = TAC_PLUS_VER_1;
@@ -62,7 +62,7 @@ int tac_authen_send(int fd, const char *user, char *pass, char *tty,
__FUNCTION__, user, tty, r_addr, \
(tac_encryption) ? "yes" : "no"))
- if ((tac_login != NULL) && (strcmp(tac_login,"chap") == 0)) {
+ if (tac_login != NULL && !strcmp(tac_login,"chap")) {
chal_len = strlen(chal);
mdp_len = sizeof(u_char) + strlen(pass) + chal_len;
mdp = (u_char *) xcalloc(1, mdp_len);
@@ -90,13 +90,13 @@ int tac_authen_send(int fd, const char *user, char *pass, char *tty,
/* fill the body of message */
tb.action = TAC_PLUS_AUTHEN_LOGIN;
tb.priv_lvl = tac_priv_lvl;
- if (tac_login == NULL) {
+ if (tac_login == NULL || !*tac_login) {
/* default to PAP */
tb.authen_type = TAC_PLUS_AUTHEN_TYPE_PAP;
} else {
- if (strcmp(tac_login,"chap") == 0) {
+ if (!strcmp(tac_login,"chap")) {
tb.authen_type = TAC_PLUS_AUTHEN_TYPE_CHAP;
- } else if (strcmp(tac_login,"login") == 0) {
+ } else if (!strcmp(tac_login,"login")) {
tb.authen_type = TAC_PLUS_AUTHEN_TYPE_ASCII;
} else {
tb.authen_type = TAC_PLUS_AUTHEN_TYPE_PAP;
diff --git a/libtac/lib/connect.c b/libtac/lib/connect.c
index 1844381..1226797 100644
--- a/libtac/lib/connect.c
+++ b/libtac/lib/connect.c
@@ -67,7 +67,7 @@ int tac_connect(struct addrinfo **server, char **key, int servers) {
* >= 0 : valid fd
* < 0 : error status code, see LIBTAC_STATUS_...
*/
-int tac_connect_single(struct addrinfo *server, char *key) {
+int tac_connect_single(struct addrinfo *server, const char *key) {
int retval = LIBTAC_STATUS_CONN_ERR; /* default retval */
int fd = -1;
int flags, rc;
@@ -75,7 +75,7 @@ int tac_connect_single(struct addrinfo *server, char *key) {
struct timeval tv;
socklen_t len;
struct sockaddr_storage addr;
- char *ip = NULL;
+ char *ip;
if(server == NULL) {
TACSYSLOG((LOG_ERR, "%s: no TACACS+ server defined", __FUNCTION__))
@@ -83,7 +83,7 @@ int tac_connect_single(struct addrinfo *server, char *key) {
}
/* format server address into a string for use in messages */
- ip = tac_ntop(server->ai_addr, 0);
+ ip = tac_ntop(server->ai_addr);
if((fd=socket(server->ai_family, server->ai_socktype, server->ai_protocol)) < 0) {
TACSYSLOG((LOG_ERR,"%s: socket creation error", __FUNCTION__))
@@ -159,8 +159,6 @@ int tac_connect_single(struct addrinfo *server, char *key) {
tac_secret = key;
}
- free(ip);
-
/* if valid fd, but error experienced after open, close fd */
if ( fd >= 0 && retval < 0 ) {
close(fd);
@@ -174,29 +172,32 @@ int tac_connect_single(struct addrinfo *server, char *key) {
/* return value:
* ptr to char* with format IP address
- * must be freed by caller
+ * warning: returns a static buffer
+ * (which some ppl don't like, but it's robust and at last no more memory leaks)
*/
-char *tac_ntop(const struct sockaddr *sa, size_t unused) {
- char portstr[7];
- char *str = (char *) xcalloc(1, INET6_ADDRSTRLEN+sizeof(portstr));
+char *tac_ntop(const struct sockaddr *sa) {
+ static char server_address[INET6_ADDRSTRLEN+16];
switch(sa->sa_family) {
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
- str, INET_ADDRSTRLEN);
- snprintf(portstr, sizeof(portstr), ":%hu",
- htons(((struct sockaddr_in *)sa)->sin_port));
- strcat(str, portstr);
+ server_address, INET_ADDRSTRLEN);
+
+ snprintf(server_address + strlen(server_address), 14, ":%hu",
+ htons(((struct sockaddr_in *)sa)->sin_port));
break;
+
case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
- str, INET6_ADDRSTRLEN);
- snprintf(portstr, sizeof(portstr), ":%hu",
+ server_address, INET6_ADDRSTRLEN);
+
+ snprintf(server_address + strlen(server_address), 14, ":%hu",
htons(((struct sockaddr_in6 *)sa)->sin6_port));
- strcat(str, portstr);
break;
+
default:
- strncpy(str, "Unknown AF", INET6_ADDRSTRLEN);
+ strcpy(server_address, "Unknown AF");
}
- return str;
+ return server_address;
} /* tac_ntop */
+
diff --git a/libtac/lib/header.c b/libtac/lib/header.c
index f361225..73c4f13 100644
--- a/libtac/lib/header.c
+++ b/libtac/lib/header.c
@@ -33,10 +33,11 @@ int session_id;
int tac_encryption = 0;
/* Pointer to TACACS+ shared secret string. */
-char *tac_secret = NULL;
+/* note: tac_secret will point to tacplus_server[i].key */
+const char *tac_secret = NULL;
-/* Pointer to TACACS+ shared login string. */
-char *tac_login = NULL; /* default is PAP */
+/* TACACS+ shared login string. */
+char tac_login[64]; /* default is PAP */
/* priv_lvl */
int tac_priv_lvl = TAC_PLUS_PRIV_LVL_MIN;
diff --git a/libtac/lib/magic.c b/libtac/lib/magic.c
index e813afc..6af5bb6 100644
--- a/libtac/lib/magic.c
+++ b/libtac/lib/magic.c
@@ -36,9 +36,10 @@ extern void srand48 __P((long));
/* on Linux we use /dev/urandom as random numbers source
I find it really cool :) */
int rfd = -1; /* /dev/urandom */
-int magic_inited = 0;
#endif
+static int magic_inited = 0;
+
/*
* magic_init - Initialize the magic number generator.
*
@@ -52,8 +53,11 @@ magic_init()
long seed;
struct timeval t;
+ if (magic_inited)
+ return;
+
+/* FIXME this should be ifdef HAVE_DEV_URANDOM + test for /dev/urandom in configure */
#ifdef __linux__
- magic_inited = 1;
rfd = open("/dev/urandom", O_RDONLY);
if(rfd != -1)
return;
@@ -62,6 +66,8 @@ magic_init()
gettimeofday(&t, NULL);
seed = gethostid() ^ t.tv_sec ^ t.tv_usec ^ getpid();
srand48(seed);
+
+ magic_inited = 1;
}
/*
@@ -70,21 +76,20 @@ magic_init()
u_int32_t
magic()
{
+ magic_init();
+
#ifdef __linux__
u_int32_t ret = 0;
- if (magic_inited == 0 )
- magic_init();
-
- if(rfd > -1) {
- read(rfd, &ret, sizeof(ret));
- return ret;
- }
- else
+ if(rfd > -1) {
+ if (read(rfd, &ret, sizeof(ret)) < sizeof(ret)) {
+ /* on read() error, fallback to other method */
return (u_int32_t) mrand48();
-#else
- return (u_int32_t) mrand48();
+ }
+ return ret;
+ }
#endif
+ return (u_int32_t) mrand48();
}
#ifdef NO_DRAND48
diff --git a/libtac/lib/xalloc.c b/libtac/lib/xalloc.c
index ce34c44..3fddcfb 100644
--- a/libtac/lib/xalloc.c
+++ b/libtac/lib/xalloc.c
@@ -23,7 +23,7 @@
#include "xalloc.h"
void *xcalloc(size_t nmemb, size_t size) {
- register void *val = calloc(nmemb, size);
+ void *val = calloc(nmemb, size);
if(val == 0) {
TACSYSLOG((LOG_ERR, "%s: calloc(%u,%u) failed", __FUNCTION__,\
(unsigned) nmemb, (unsigned) size))
@@ -33,7 +33,7 @@ void *xcalloc(size_t nmemb, size_t size) {
}
void *xrealloc(void *ptr, size_t size) {
- register void *val = realloc(ptr, size);
+ void *val = realloc(ptr, size);
if(val == 0) {
TACSYSLOG((LOG_ERR, "%s: realloc(%u) failed", __FUNCTION__, (unsigned) size))
exit(1);
@@ -41,7 +41,7 @@ void *xrealloc(void *ptr, size_t size) {
return val;
}
-char *xstrdup(char *s) {
+char *xstrdup(const char *s) {
char *p;
if (s == NULL) return NULL;
@@ -51,3 +51,28 @@ char *xstrdup(char *s) {
}
return p;
}
+
+
+/*
+ safe string copy that aborts when destination buffer is too small
+*/
+char *xstrcpy(char *dst, const char *src, size_t dst_size) {
+ if (dst == NULL) {
+ TACSYSLOG((LOG_ERR, "xstrcpy(): dst == NULL"));
+ abort();
+ }
+ if (src == NULL) {
+ TACSYSLOG((LOG_ERR, "xstrcpy(): src == NULL"));
+ abort();
+ }
+ if (!dst_size)
+ return NULL;
+
+ if (strlen(src) >= dst_size) {
+ TACSYSLOG((LOG_ERR, "xstrcpy(): argument too long, aborting"));
+ abort();
+ }
+
+ return strcpy(dst, src);
+}
+
diff --git a/libtac/lib/xalloc.h b/libtac/lib/xalloc.h
index 70bc666..196cc9f 100644
--- a/libtac/lib/xalloc.h
+++ b/libtac/lib/xalloc.h
@@ -27,7 +27,7 @@
__BEGIN_DECLS
extern void *xcalloc(size_t nmemb, size_t size);
extern void *xrealloc(void *ptr, size_t size);
-extern char *xstrdup(char *s);
+extern char *xstrdup(const char *s);
__END_DECLS
#endif
diff --git a/pam_tacplus.c b/pam_tacplus.c
index 9644bc4..635c11d 100644
--- a/pam_tacplus.c
+++ b/pam_tacplus.c
@@ -19,6 +19,9 @@
* See `CHANGES' file for revision history.
*/
+#include "pam_tacplus.h"
+#include "support.h"
+
#include <stdlib.h> /* malloc */
#include <stdio.h>
#include <syslog.h>
@@ -32,51 +35,15 @@
#include <ctype.h>
#include <time.h>
#include <unistd.h>
-
-#ifndef __linux__
- #include <strings.h>
-#endif
-
-#include "libtac.h"
-#include "pam_tacplus.h"
-#include "support.h"
-
-#define PAM_SM_AUTH
-#define PAM_SM_ACCOUNT
-#define PAM_SM_SESSION
-/* #define PAM_SM_PASSWORD */
-
-#ifndef __linux__
- #include <security/pam_appl.h>
-#endif
-#include <security/pam_modules.h>
+#include <strings.h>
#ifdef HAVE_CONFIG_H
- #include "config.h"
+ #include "config.h"
#endif
-/* support.c */
-extern struct addrinfo *tac_srv[TAC_PLUS_MAXSERVERS];
-extern char *tac_srv_key[TAC_PLUS_MAXSERVERS];
-extern int tac_srv_no;
-extern char *tac_service;
-extern char *tac_protocol;
-extern int _pam_parse (int argc, const char **argv);
-extern unsigned long _getserveraddr (char *serv);
-extern int tacacs_get_password (pam_handle_t * pamh, int flags
- ,int ctrl, char **password);
-extern int converse (pam_handle_t * pamh, int nargs
- ,struct pam_message **message
- ,struct pam_response **response);
-extern void _pam_log (int err, const char *format,...);
-extern void *_xcalloc (size_t size);
-
-/* magic.c */
-extern u_int32_t magic();
-
/* address of server discovered by pam_sm_authenticate */
-static struct addrinfo *active_server;
-char *active_key;
+static tacplus_server_t *active_server = NULL;
+
/* accounting task identifier */
static short int task_id = 0;
@@ -85,17 +52,13 @@ static short int task_id = 0;
int _pam_send_account(int tac_fd, int type, const char *user, char *tty,
char *r_addr, char *cmd) {
- char buf[40];
+ char buf[64];
struct tac_attrib *attr;
int retval;
-
- attr=(struct tac_attrib *)_xcalloc(sizeof(struct tac_attrib));
-
-#ifdef _AIX
- sprintf(buf, "%d", time(0));
-#else
- sprintf(buf, "%lu", (long unsigned int)time(0));
-#endif
+
+ attr=(struct tac_attrib *)xcalloc(1, sizeof(struct tac_attrib));
+
+ sprintf(buf, "%lu", (unsigned long)time(NULL));
if (type == TAC_PLUS_ACCT_FLAG_START) {
tac_add_attrib(&attr, "start_time", buf);
@@ -130,12 +93,17 @@ int _pam_send_account(int tac_fd, int type, const char *user, char *tty,
__FUNCTION__,
tac_acct_flag2str(type),
task_id);
- if(re.msg != NULL) free(re.msg);
+
+ if(re.msg != NULL)
+ free(re.msg);
+
close(tac_fd);
return -1;
}
- if(re.msg != NULL) free(re.msg);
+ if(re.msg != NULL)
+ free(re.msg);
+
close(tac_fd);
return 0;
}
@@ -206,7 +174,7 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
while ((status == PAM_SESSION_ERR) && (srv_i < tac_srv_no)) {
int tac_fd;
- tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
+ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
if(tac_fd < 0) {
_pam_log(LOG_WARNING, "%s: error sending %s (fd)",
__FUNCTION__, typemsg);
@@ -241,7 +209,7 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
int tac_fd;
- tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
+ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
if(tac_fd < 0) {
_pam_log(LOG_WARNING, "%s: error sending %s (fd)",
__FUNCTION__, typemsg);
@@ -297,6 +265,7 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
int status = PAM_AUTH_ERR;
user = pass = tty = r_addr = NULL;
+ active_server = NULL;
ctrl = _pam_parse (argc, argv);
@@ -342,7 +311,7 @@ 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_srv_key[srv_i]);
+ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
if (tac_fd < 0) {
_pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
if (srv_i == tac_srv_no-1) {
@@ -372,9 +341,12 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
/* OK, we got authenticated; save the server that
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];
+ active_server = &tac_srv[srv_i];
close(tac_fd);
+
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog (LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i );
+
break;
}
}
@@ -385,9 +357,12 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
/* OK, we got authenticated; save the server that
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];
+ active_server = &tac_srv[srv_i];
close(tac_fd);
+
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog (LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i );
+
break;
}
}
@@ -454,7 +429,7 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: username obtained [%s]", __FUNCTION__, user);
-
+
tty = _pam_get_terminal(pamh);
if(!strncmp(tty, "/dev/", 5))
tty += 5;
@@ -469,21 +444,21 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
by TACACS+; we cannot solely authorize user if it hasn't
been authenticated or has been authenticated by method other
than TACACS+ */
- if(!active_server) {
+ if(active_server == NULL) {
_pam_log (LOG_ERR, "user not authenticated by TACACS+");
return PAM_AUTH_ERR;
}
if (ctrl & PAM_TAC_DEBUG)
syslog (LOG_DEBUG, "%s: active server is [%s]", __FUNCTION__,
- tac_ntop(active_server->ai_addr, active_server->ai_addrlen));
+ tac_ntop(active_server->addr->ai_addr));
/* checks for specific data required by TACACS+, which should
be supplied in command line */
- if(tac_service == NULL || *tac_service == '\0') {
+ if(tac_service == NULL || !*tac_service) {
_pam_log (LOG_ERR, "TACACS+ service type not configured");
return PAM_AUTH_ERR;
}
- if(tac_protocol == NULL || *tac_protocol == '\0') {
+ if(tac_protocol == NULL || !*tac_protocol) {
_pam_log (LOG_ERR, "TACACS+ protocol type not configured");
return PAM_AUTH_ERR;
}
@@ -491,10 +466,12 @@ 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, active_key);
+ tac_fd = tac_connect_single(active_server->addr, active_server->key);
if(tac_fd < 0) {
_pam_log (LOG_ERR, "TACACS+ server unavailable");
- if(arep.msg != NULL) free (arep.msg);
+ if(arep.msg != NULL)
+ free (arep.msg);
+
close(tac_fd);
return PAM_AUTH_ERR;
}
@@ -505,7 +482,9 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
if(retval < 0) {
_pam_log (LOG_ERR, "error getting authorization");
- if(arep.msg != NULL) free (arep.msg);
+ if(arep.msg != NULL)
+ free (arep.msg);
+
close(tac_fd);
return PAM_AUTH_ERR;
}
@@ -519,7 +498,9 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
arep.status != AUTHOR_STATUS_PASS_REPL) {
_pam_log (LOG_ERR, "TACACS+ authorisation failed for [%s]", user);
- if(arep.msg != NULL) free (arep.msg);
+ if(arep.msg != NULL)
+ free (arep.msg);
+
close(tac_fd);
return PAM_PERM_DENIED;
}
@@ -565,8 +546,12 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
}
/* free returned attributes */
- if(arep.attr != NULL) tac_free_attrib(&arep.attr);
- if(arep.msg != NULL) free (arep.msg);
+ if(arep.attr != NULL)
+ tac_free_attrib(&arep.attr);
+
+ if(arep.msg != NULL)
+ free (arep.msg);
+
close(tac_fd);
return status;
diff --git a/pam_tacplus.h b/pam_tacplus.h
index c65212d..b2f2b3c 100644
--- a/pam_tacplus.h
+++ b/pam_tacplus.h
@@ -19,6 +19,18 @@
* See `CHANGES' file for revision history.
*/
+#ifndef PAM_TACPLUS_H
+#define PAM_TACPLUS_H
+
+/* define these before including PAM headers */
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+/* #define PAM_SM_PASSWORD */
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
/* pam_tacplus command line options */
#define PAM_TAC_DEBUG 0x01
#define PAM_TAC_ACCT 0x02 /* account on all specified servers */
@@ -31,5 +43,8 @@
#define PAM_TAC_VPAT 8
#ifndef PAM_EXTERN
- #define PAM_EXTERN extern
+ #define PAM_EXTERN extern
#endif
+
+#endif /* PAM_TACPLUS_H */
+
diff --git a/support.c b/support.c
index 23b01e5..3210a37 100644
--- a/support.c
+++ b/support.c
@@ -24,41 +24,18 @@
#define PAM_SM_SESSION
/* #define PAM_SM_PASSWORD */
-#ifndef __linux__
- #include <security/pam_appl.h>
-#endif
-#include <security/pam_modules.h>
-
+#include "support.h"
#include "pam_tacplus.h"
-#include "libtac.h"
-struct addrinfo *tac_srv[TAC_PLUS_MAXSERVERS];
+#include <stdlib.h>
+#include <string.h>
+
+tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS];
int tac_srv_no = 0;
-char *tac_srv_key[TAC_PLUS_MAXSERVERS];
-int tac_srv_key_no = 0;
-char *tac_service = NULL;
-char *tac_protocol = NULL;
-char *tac_prompt = NULL;
-
-/* libtac */
-extern char *tac_login;
-extern int tac_timeout;
-
-/*
- FIXME using xcalloc() leaks memory for long-running programs that authenticate multiple times
-*/
-#ifndef xcalloc
-void *_xcalloc (size_t size) {
- register void *val = calloc (1, size);
- if (val == 0) {
- syslog (LOG_ERR, "xcalloc: calloc(1,%u) failed", (unsigned) size);
- abort();
- }
- return val;
-}
-#else
-#define _xcalloc xcalloc
-#endif
+
+char tac_service[64];
+char tac_protocol[64];
+char tac_prompt[64];
void _pam_log(int err, const char *format,...) {
char msg[256];
@@ -195,9 +172,16 @@ int tacacs_get_password (pam_handle_t * pamh, int flags
int _pam_parse (int argc, const char **argv) {
int ctrl = 0;
+ const char *current_secret = NULL;
/* otherwise the list will grow with each call */
- tac_srv_no = tac_srv_key_no = 0;
+ memset(tac_srv, 0, sizeof(tacplus_server_t) * TAC_PLUS_MAXSERVERS);
+ tac_srv_no = 0;
+
+ tac_service[0] = 0;
+ tac_protocol[0] = 0;
+ tac_prompt[0] = 0;
+ tac_login[0] = 0;
for (ctrl = 0; argc-- > 0; ++argv) {
if (!strcmp (*argv, "debug")) { /* all */
@@ -207,14 +191,11 @@ int _pam_parse (int argc, const char **argv) {
} else if (!strcmp (*argv, "try_first_pass")) {
ctrl |= PAM_TAC_TRY_FIRST_PASS;
} else if (!strncmp (*argv, "service=", 8)) { /* author & acct */
- tac_service = (char *) _xcalloc (strlen (*argv + 8) + 1);
- strcpy (tac_service, *argv + 8);
+ xstrcpy (tac_service, *argv + 8, sizeof(tac_service));
} else if (!strncmp (*argv, "protocol=", 9)) { /* author & acct */
- tac_protocol = (char *) _xcalloc (strlen (*argv + 9) + 1);
- strcpy (tac_protocol, *argv + 9);
+ xstrcpy (tac_protocol, *argv + 9, sizeof(tac_protocol));
} else if (!strncmp (*argv, "prompt=", 7)) { /* authentication */
- tac_prompt = (char *) _xcalloc (strlen (*argv + 7) + 1);
- strcpy (tac_prompt, *argv + 7);
+ xstrcpy (tac_prompt, *argv + 7, sizeof(tac_prompt));
/* Replace _ with space */
int chr;
for (chr = 0; chr < strlen(tac_prompt); chr++) {
@@ -222,6 +203,8 @@ int _pam_parse (int argc, const char **argv) {
tac_prompt[chr] = ' ';
}
}
+ } else if (!strncmp (*argv, "login=", 6)) {
+ xstrcpy (tac_login, *argv + 6, sizeof(tac_login));
} else if (!strcmp (*argv, "acct_all")) {
ctrl |= PAM_TAC_ACCT;
} else if (!strncmp (*argv, "server=", 7)) { /* authen & acct */
@@ -247,7 +230,8 @@ int _pam_parse (int argc, const char **argv) {
}
if ((rv = getaddrinfo(server_buf, (port == NULL) ? "49" : port, &hints, &servers)) == 0) {
for(server = servers; server != NULL && tac_srv_no < TAC_PLUS_MAXSERVERS; server = server->ai_next) {
- tac_srv[tac_srv_no] = server;
+ tac_srv[tac_srv_no].addr = server;
+ tac_srv[tac_srv_no].key = current_secret;
tac_srv_no++;
}
} else {
@@ -260,33 +244,41 @@ int _pam_parse (int argc, const char **argv) {
TAC_PLUS_MAXSERVERS);
}
} else if (!strncmp (*argv, "secret=", 7)) {
- if(tac_srv_key_no < TAC_PLUS_MAXSERVERS) {
- 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_PLUS_MAXSERVERS);
+ int i;
+
+ current_secret = *argv + 7; /* points right into argv (which is const) */
+
+ /* if 'secret=' was given after a 'server=' parameter, fill in the current secret */
+ for(i = tac_srv_no-1; i >= 0; i--) {
+ if (tac_srv[i].key != NULL)
+ break;
+
+ tac_srv[i].key = current_secret;
}
} else if (!strncmp (*argv, "timeout=", 8)) {
+ /* FIXME atoi() doesn't handle invalid numeric strings well */
tac_timeout = atoi(*argv + 8);
- } else if (!strncmp (*argv, "login=", 6)) {
- tac_login = (char *) _xcalloc (strlen (*argv + 6) + 1);
- strcpy (tac_login, *argv + 6);
+
+ if (tac_timeout < 0)
+ tac_timeout = 0;
} else {
_pam_log (LOG_WARNING, "unrecognized option: %s", *argv);
}
}
- if (tac_srv_key_no == 0) {
- /* FIXME this should really be NULL
- but watch out with breaking other code
- */
- 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];
+ if (ctrl & PAM_TAC_DEBUG) {
+ int n;
+
+ _pam_log(LOG_DEBUG, "%d servers defined", tac_srv_no);
+
+ for(n = 0; n < tac_srv_no; n++) {
+ _pam_log(LOG_DEBUG, "server[%d] { addr=%s, key='%s' }", n, tac_ntop(tac_srv[n].addr->ai_addr), tac_srv[n].key);
+ }
+
+ _pam_log(LOG_DEBUG, "tac_service='%s'", tac_service);
+ _pam_log(LOG_DEBUG, "tac_protocol='%s'", tac_protocol);
+ _pam_log(LOG_DEBUG, "tac_prompt='%s'", tac_prompt);
+ _pam_log(LOG_DEBUG, "tac_login='%s'", tac_login);
}
return ctrl;
diff --git a/support.h b/support.h
index 300c7ce..9cbd040 100644
--- a/support.h
+++ b/support.h
@@ -19,21 +19,35 @@
* See `CHANGES' file for revision history.
*/
-#ifndef __linux__
- #include <security/pam_appl.h>
-#endif
+#ifndef PAM_TACPLUS_SUPPORT_H
+#define PAM_TACPLUS_SUPPORT_H
+
+#include "libtac.h"
+
#include <security/pam_modules.h>
-/* support.c */
-extern int _pam_parse (int argc, const char **argv);
-extern unsigned long _resolve_name (char *serv);
-extern int tacacs_get_password (pam_handle_t * pamh, int flags
- ,int ctrl, char **password);
-extern int converse (pam_handle_t * pamh, int nargs
- ,struct pam_message **message
- ,struct pam_response **response);
-extern void _pam_log (int err, const char *format,...);
-extern void *_xcalloc (size_t size);
-extern char *_pam_get_user(pam_handle_t *pamh);
-extern char *_pam_get_terminal(pam_handle_t *pamh);
-extern char *_pam_get_rhost(pam_handle_t *pamh);
+typedef struct {
+ struct addrinfo *addr;
+ const char *key;
+} tacplus_server_t;
+
+extern tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS];
+extern int tac_srv_no;
+
+extern char tac_service[64];
+extern char tac_protocol[64];
+extern char tac_prompt[64];
+
+int _pam_parse (int, const char **);
+unsigned long _resolve_name (char *);
+unsigned long _getserveraddr (char *serv);
+int tacacs_get_password (pam_handle_t *, int, int, char **);
+int converse (pam_handle_t *, int, const struct pam_message *, struct pam_response **);
+void _pam_log (int, const char *, ...);
+void *_xcalloc (size_t);
+char *_pam_get_user(pam_handle_t *);
+char *_pam_get_terminal(pam_handle_t *);
+char *_pam_get_rhost(pam_handle_t *);
+
+#endif /* PAM_TACPLUS_SUPPORT_H */
+