summaryrefslogtreecommitdiff
path: root/source3/nsswitch/wb_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nsswitch/wb_common.c')
-rw-r--r--source3/nsswitch/wb_common.c96
1 files changed, 94 insertions, 2 deletions
diff --git a/source3/nsswitch/wb_common.c b/source3/nsswitch/wb_common.c
index 40221b69fe..ef8fc3e40f 100644
--- a/source3/nsswitch/wb_common.c
+++ b/source3/nsswitch/wb_common.c
@@ -70,6 +70,10 @@ void close_sock(void)
}
}
+#define CONNECT_TIMEOUT 30
+#define WRITE_TIMEOUT CONNECT_TIMEOUT
+#define READ_TIMEOUT CONNECT_TIMEOUT
+
/* Make sure socket handle isn't stdin, stdout or stderr */
#define RECURSION_LIMIT 3
@@ -105,6 +109,14 @@ static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
return fd;
}
+/****************************************************************************
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+ Set close on exec also.
+****************************************************************************/
+
static int make_safe_fd(int fd)
{
int result, flags;
@@ -113,8 +125,32 @@ static int make_safe_fd(int fd)
close(fd);
return -1;
}
+
+ /* Socket should be nonblocking. */
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
+ close(new_fd);
+ return -1;
+ }
+
+ flags |= FLAG_TO_SET;
+ if (fcntl(new_fd, F_SETFL, flags) == -1) {
+ close(new_fd);
+ return -1;
+ }
+
+#undef FLAG_TO_SET
+
/* Socket should be closed on exec() */
-
#ifdef FD_CLOEXEC
result = flags = fcntl(new_fd, F_GETFD, 0);
if (flags >= 0) {
@@ -137,6 +173,8 @@ static int winbind_named_pipe_sock(const char *dir)
struct stat st;
pstring path;
int fd;
+ int wait_time;
+ int slept;
/* Check permissions on unix socket directory */
@@ -185,10 +223,64 @@ static int winbind_named_pipe_sock(const char *dir)
return -1;
}
+ /* Set socket non-blocking and close on exec. */
+
if ((fd = make_safe_fd( fd)) == -1) {
return fd;
}
-
+
+ for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
+ wait_time += slept) {
+ struct timeval tv;
+ fd_set w_fds;
+ int ret;
+ int connect_errno = 0, errnosize;
+
+ if (wait_time >= CONNECT_TIMEOUT)
+ goto error_out;
+
+ switch (errno) {
+ case EINPROGRESS:
+ FD_ZERO(&w_fds);
+ FD_SET(fd, &w_fds);
+ tv.tv_sec = CONNECT_TIMEOUT - wait_time;
+ tv.tv_usec = 0;
+
+ ret = select(fd + 1, NULL, &w_fds, NULL, &tv);
+
+ if (ret > 0) {
+ errnosize = sizeof(connect_errno);
+
+ ret = getsockopt(fd, SOL_SOCKET,
+ SO_ERROR, &connect_errno, &errnosize);
+
+ if (ret >= 0 && connect_errno == 0) {
+ /* Connect succeed */
+ goto out;
+ }
+ }
+
+ slept = CONNECT_TIMEOUT;
+ break;
+ case EAGAIN:
+ slept = rand() % 3 + 1;
+ sleep(slept);
+ break;
+ default:
+ goto error_out;
+ }
+
+ }
+
+ out:
+
+ return fd;
+
+ error_out:
+
+ close(fd);
+ return -1;
+
if (connect(fd, (struct sockaddr *)&sunaddr,
sizeof(sunaddr)) == -1) {
close(fd);