summaryrefslogtreecommitdiff
path: root/libtac/lib/connect.c
diff options
context:
space:
mode:
authorJeroen Nijhof <jeroenn@saralt0078.(none)>2010-12-22 11:12:08 +0100
committerJeroen Nijhof <jeroenn@saralt0078.(none)>2010-12-22 11:12:08 +0100
commit4e0f4aa68e082b469663e3ebc8ec83c9400dab4b (patch)
tree08d50b522bc250659704b2dfc73d887979198fd4 /libtac/lib/connect.c
downloadpam_tacplus-4e0f4aa68e082b469663e3ebc8ec83c9400dab4b.tar.gz
pam_tacplus-4e0f4aa68e082b469663e3ebc8ec83c9400dab4b.zip
Initial commit
Diffstat (limited to 'libtac/lib/connect.c')
-rw-r--r--libtac/lib/connect.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/libtac/lib/connect.c b/libtac/lib/connect.c
new file mode 100644
index 0000000..7b55645
--- /dev/null
+++ b/libtac/lib/connect.c
@@ -0,0 +1,144 @@
+/* connect.c - Open connection to server.
+ *
+ * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and
+ * Jeroen Nijhof <jeroen@nijhofnet.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program - see the file COPYING.
+ *
+ * See `CHANGES' file for revision history.
+ */
+
+#include <signal.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef _AIX
+ #include <sys/socket.h>
+#endif
+
+#include "tacplus.h"
+#include "libtac.h"
+
+/* Pointer to TACACS+ connection timeout */
+int tac_timeout = 5;
+
+/* Returns file descriptor of open connection
+ to the first available server from list passed
+ in server table.
+*/
+int tac_connect(struct addrinfo **server, int servers) {
+ int tries = 0;
+ int fd, flags, retval;
+ fd_set readfds, writefds;
+ struct timeval tv;
+
+ if(!servers) {
+ syslog(LOG_ERR, "%s: no TACACS+ servers defined", __FUNCTION__);
+ return(-1);
+ }
+
+ while(tries < servers) {
+ if((fd=socket(server[tries]->ai_family, server[tries]->ai_socktype, server[tries]->ai_protocol)) == -1) {
+ syslog(LOG_WARNING,
+ "%s: socket creation error", __FUNCTION__);
+ tries++;
+ continue;
+ }
+
+ /* put socket in non blocking mode for timeout support */
+ flags = fcntl(fd, F_GETFL, 0);
+ if(fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
+ syslog(LOG_WARNING, "%s: cannot set socket non blocking",
+ __FUNCTION__);
+ tries++;
+ continue;
+ }
+
+ retval = connect(fd, server[tries]->ai_addr, server[tries]->ai_addrlen);
+ if((retval == -1) && (errno != EINPROGRESS)) {
+ syslog(LOG_WARNING,
+ "%s: connection to %s failed: %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;
+ }
+
+ /* set fds for select */
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ writefds = readfds;
+
+ /* set timeout seconds */
+ 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)) {
+ syslog(LOG_WARNING,
+ "%s: connection timeout 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 */
+ if(fcntl(fd, F_SETFL, flags)) {
+ syslog(LOG_WARNING, "%s: cannot restore socket flags",
+ __FUNCTION__);
+ }
+ TACDEBUG((LOG_DEBUG, "%s: connected to %s", __FUNCTION__, \
+ tac_ntop(server[tries]->ai_addr, server[tries]->ai_addrlen)));
+
+ 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));
+} /* tac_connect_single */
+
+
+char *tac_ntop(const struct sockaddr *sa, size_t ai_addrlen) {
+ char *str = (char *) xcalloc(1, ai_addrlen);
+ switch(sa->sa_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
+ str, ai_addrlen);
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
+ str, ai_addrlen);
+ break;
+ default:
+ strncpy(str, "Unknown AF", ai_addrlen);
+ }
+ return str;
+} /* tac_ntop */