static int winbind_read_sock(void *buffer, int count) { int fd; int nread = 0; int total_time = 0; fd = winbind_open_pipe_sock(false, false); if (fd == -1) { return -1; } /* Read data from socket */ while(nread < count) { struct pollfd pfd; int ret; /* Catch pipe close on other end by checking if a read() call would not block by calling poll(). */ pfd.fd = fd; pfd.events = POLLIN|POLLHUP; /* Wait for 5 seconds for a reply. May need to parameterise this... */ ret = poll(&pfd, 1, 5000); if (ret == -1) { winbind_close_sock(); return -1; /* poll error */ } if (ret == 0) { /* Not ready for read yet... */ if (total_time >= 30) { /* Timeout */ winbind_close_sock(); return -1; } total_time += 5; continue; } if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) { /* Do the Read */ int result = read(fd, (char *)buffer + nread, count - nread); if ((result == -1) || (result == 0)) { /* Read failed. I think the only useful thing we can do here is just return -1 and fail since the transaction has failed half way through. */ winbind_close_sock(); return -1; } nread += result; } } return nread; }
static int winbind_open_pipe_sock(int recursing, int need_priv) { #ifdef HAVE_UNIXSOCKET static pid_t our_pid; struct winbindd_request request; struct winbindd_response response; ZERO_STRUCT(request); ZERO_STRUCT(response); if (our_pid != getpid()) { winbind_close_sock(); our_pid = getpid(); } if ((need_priv != 0) && (is_privileged == 0)) { winbind_close_sock(); } if (winbindd_fd != -1) { return winbindd_fd; } if (recursing) { return -1; } if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) { return -1; } is_privileged = 0; /* version-check the socket */ request.wb_flags = WBFLAG_RECURSE; if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) { winbind_close_sock(); return -1; } /* try and get priv pipe */ request.wb_flags = WBFLAG_RECURSE; /* Note that response needs to be initialized to avoid * crashing on clean up after WINBINDD_PRIV_PIPE_DIR call failed * as interface version (from the first request) returned as a fstring, * thus response.extra_data.data will not be NULL even though * winbindd response did not write over it due to a failure */ ZERO_STRUCT(response); if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) { int fd; if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) { close(winbindd_fd); winbindd_fd = fd; is_privileged = 1; } } if ((need_priv != 0) && (is_privileged == 0)) { return -1; } SAFE_FREE(response.extra_data.data); return winbindd_fd; #else return -1; #endif /* HAVE_UNIXSOCKET */ }
static int winbind_write_sock(void *buffer, int count, int recursing, int need_priv) { int fd, result, nwritten; /* Open connection to winbind daemon */ restart: fd = winbind_open_pipe_sock(recursing, need_priv); if (fd == -1) { errno = ENOENT; return -1; } /* Write data to socket */ nwritten = 0; while(nwritten < count) { struct pollfd pfd; int ret; /* Catch pipe close on other end by checking if a read() call would not block by calling poll(). */ pfd.fd = fd; pfd.events = POLLIN|POLLOUT|POLLHUP; ret = poll(&pfd, 1, -1); if (ret == -1) { winbind_close_sock(); return -1; /* poll error */ } /* Write should be OK if fd not available for reading */ if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) { /* Pipe has closed on remote end */ winbind_close_sock(); goto restart; } /* Do the write */ result = write(fd, (char *)buffer + nwritten, count - nwritten); if ((result == -1) || (result == 0)) { /* Write failed */ winbind_close_sock(); return -1; } nwritten += result; } return nwritten; }
static int winbind_open_pipe_sock(int recursing, int need_priv) { #ifdef HAVE_UNIXSOCKET static pid_t our_pid; struct winbindd_request request; struct winbindd_response response; ZERO_STRUCT(request); ZERO_STRUCT(response); if (our_pid != getpid()) { winbind_close_sock(); our_pid = getpid(); } if ((need_priv != 0) && (is_privileged == 0)) { winbind_close_sock(); } if (winbindd_fd != -1) { return winbindd_fd; } if (recursing) { return -1; } if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) { return -1; } is_privileged = 0; /* version-check the socket */ request.wb_flags = WBFLAG_RECURSE; if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) { winbind_close_sock(); return -1; } /* try and get priv pipe */ request.wb_flags = WBFLAG_RECURSE; if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) { int fd; if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) { close(winbindd_fd); winbindd_fd = fd; is_privileged = 1; } } if ((need_priv != 0) && (is_privileged == 0)) { return -1; } SAFE_FREE(response.extra_data.data); return winbindd_fd; #else return -1; #endif /* HAVE_UNIXSOCKET */ }