106a99fe3SHajimu UMEMOTO /*- 206a99fe3SHajimu UMEMOTO * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 306a99fe3SHajimu UMEMOTO * All rights reserved. 406a99fe3SHajimu UMEMOTO * 506a99fe3SHajimu UMEMOTO * Redistribution and use in source and binary forms, with or without 606a99fe3SHajimu UMEMOTO * modification, are permitted provided that the following conditions 706a99fe3SHajimu UMEMOTO * are met: 806a99fe3SHajimu UMEMOTO * 1. Redistributions of source code must retain the above copyright 906a99fe3SHajimu UMEMOTO * notice, this list of conditions and the following disclaimer. 1006a99fe3SHajimu UMEMOTO * 2. Redistributions in binary form must reproduce the above copyright 1106a99fe3SHajimu UMEMOTO * notice, this list of conditions and the following disclaimer in the 1206a99fe3SHajimu UMEMOTO * documentation and/or other materials provided with the distribution. 1306a99fe3SHajimu UMEMOTO * 1406a99fe3SHajimu UMEMOTO * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1506a99fe3SHajimu UMEMOTO * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1606a99fe3SHajimu UMEMOTO * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1706a99fe3SHajimu UMEMOTO * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1806a99fe3SHajimu UMEMOTO * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1906a99fe3SHajimu UMEMOTO * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2006a99fe3SHajimu UMEMOTO * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2106a99fe3SHajimu UMEMOTO * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2206a99fe3SHajimu UMEMOTO * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2306a99fe3SHajimu UMEMOTO * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2406a99fe3SHajimu UMEMOTO * SUCH DAMAGE. 2506a99fe3SHajimu UMEMOTO * 2606a99fe3SHajimu UMEMOTO */ 2706a99fe3SHajimu UMEMOTO 2806a99fe3SHajimu UMEMOTO #include <sys/cdefs.h> 2906a99fe3SHajimu UMEMOTO __FBSDID("$FreeBSD$"); 3006a99fe3SHajimu UMEMOTO 3106a99fe3SHajimu UMEMOTO #include <sys/types.h> 32a5a5d924SDag-Erling Smørgrav 3306a99fe3SHajimu UMEMOTO #include <sys/event.h> 34a5a5d924SDag-Erling Smørgrav #include <sys/socket.h> 3506a99fe3SHajimu UMEMOTO #include <sys/uio.h> 3606a99fe3SHajimu UMEMOTO #include <sys/un.h> 37a5a5d924SDag-Erling Smørgrav 3806a99fe3SHajimu UMEMOTO #include <assert.h> 3906a99fe3SHajimu UMEMOTO #include <errno.h> 4006a99fe3SHajimu UMEMOTO #include <fcntl.h> 4106a99fe3SHajimu UMEMOTO #include <stdlib.h> 4206a99fe3SHajimu UMEMOTO #include <string.h> 4306a99fe3SHajimu UMEMOTO #include <unistd.h> 4406a99fe3SHajimu UMEMOTO 4506a99fe3SHajimu UMEMOTO #include "debug.h" 46db1bdf2bSMichael Bushkov #include "nscdcli.h" 4706a99fe3SHajimu UMEMOTO #include "protocol.h" 4806a99fe3SHajimu UMEMOTO 49db1bdf2bSMichael Bushkov #define DEFAULT_NSCD_IO_TIMEOUT 4 5006a99fe3SHajimu UMEMOTO 51db1bdf2bSMichael Bushkov static int safe_write(struct nscd_connection_ *, const void *, size_t); 52db1bdf2bSMichael Bushkov static int safe_read(struct nscd_connection_ *, void *, size_t); 53db1bdf2bSMichael Bushkov static int send_credentials(struct nscd_connection_ *, int); 5406a99fe3SHajimu UMEMOTO 5506a99fe3SHajimu UMEMOTO static int 56db1bdf2bSMichael Bushkov safe_write(struct nscd_connection_ *connection, const void *data, 5706a99fe3SHajimu UMEMOTO size_t data_size) 5806a99fe3SHajimu UMEMOTO { 5906a99fe3SHajimu UMEMOTO struct kevent eventlist; 6006a99fe3SHajimu UMEMOTO int nevents; 6106a99fe3SHajimu UMEMOTO size_t result; 6206a99fe3SHajimu UMEMOTO ssize_t s_result; 6306a99fe3SHajimu UMEMOTO struct timespec timeout; 6406a99fe3SHajimu UMEMOTO 6506a99fe3SHajimu UMEMOTO if (data_size == 0) 6606a99fe3SHajimu UMEMOTO return (0); 6706a99fe3SHajimu UMEMOTO 68db1bdf2bSMichael Bushkov timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT; 6906a99fe3SHajimu UMEMOTO timeout.tv_nsec = 0; 7006a99fe3SHajimu UMEMOTO result = 0; 7106a99fe3SHajimu UMEMOTO do { 7206a99fe3SHajimu UMEMOTO nevents = kevent(connection->write_queue, NULL, 0, &eventlist, 7306a99fe3SHajimu UMEMOTO 1, &timeout); 7406a99fe3SHajimu UMEMOTO if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) { 7506a99fe3SHajimu UMEMOTO s_result = write(connection->sockfd, data + result, 7606a99fe3SHajimu UMEMOTO eventlist.data < data_size - result ? 7706a99fe3SHajimu UMEMOTO eventlist.data : data_size - result); 7806a99fe3SHajimu UMEMOTO if (s_result == -1) 7906a99fe3SHajimu UMEMOTO return (-1); 8006a99fe3SHajimu UMEMOTO else 8106a99fe3SHajimu UMEMOTO result += s_result; 8206a99fe3SHajimu UMEMOTO 8306a99fe3SHajimu UMEMOTO if (eventlist.flags & EV_EOF) 8406a99fe3SHajimu UMEMOTO return (result < data_size ? -1 : 0); 8506a99fe3SHajimu UMEMOTO } else 8606a99fe3SHajimu UMEMOTO return (-1); 8706a99fe3SHajimu UMEMOTO } while (result < data_size); 8806a99fe3SHajimu UMEMOTO 8906a99fe3SHajimu UMEMOTO return (0); 9006a99fe3SHajimu UMEMOTO } 9106a99fe3SHajimu UMEMOTO 9206a99fe3SHajimu UMEMOTO static int 93db1bdf2bSMichael Bushkov safe_read(struct nscd_connection_ *connection, void *data, size_t data_size) 9406a99fe3SHajimu UMEMOTO { 9506a99fe3SHajimu UMEMOTO struct kevent eventlist; 9606a99fe3SHajimu UMEMOTO size_t result; 9706a99fe3SHajimu UMEMOTO ssize_t s_result; 9806a99fe3SHajimu UMEMOTO struct timespec timeout; 9906a99fe3SHajimu UMEMOTO int nevents; 10006a99fe3SHajimu UMEMOTO 10106a99fe3SHajimu UMEMOTO if (data_size == 0) 10206a99fe3SHajimu UMEMOTO return (0); 10306a99fe3SHajimu UMEMOTO 104db1bdf2bSMichael Bushkov timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT; 10506a99fe3SHajimu UMEMOTO timeout.tv_nsec = 0; 10606a99fe3SHajimu UMEMOTO result = 0; 10706a99fe3SHajimu UMEMOTO do { 10806a99fe3SHajimu UMEMOTO nevents = kevent(connection->read_queue, NULL, 0, &eventlist, 1, 10906a99fe3SHajimu UMEMOTO &timeout); 11006a99fe3SHajimu UMEMOTO if ((nevents == 1) && (eventlist.filter == EVFILT_READ)) { 11106a99fe3SHajimu UMEMOTO s_result = read(connection->sockfd, data + result, 11206a99fe3SHajimu UMEMOTO eventlist.data <= data_size - result ? eventlist.data : 11306a99fe3SHajimu UMEMOTO data_size - result); 11406a99fe3SHajimu UMEMOTO if (s_result == -1) 11506a99fe3SHajimu UMEMOTO return (-1); 11606a99fe3SHajimu UMEMOTO else 11706a99fe3SHajimu UMEMOTO result += s_result; 11806a99fe3SHajimu UMEMOTO 11906a99fe3SHajimu UMEMOTO if (eventlist.flags & EV_EOF) 12006a99fe3SHajimu UMEMOTO return (result < data_size ? -1 : 0); 12106a99fe3SHajimu UMEMOTO } else 12206a99fe3SHajimu UMEMOTO return (-1); 12306a99fe3SHajimu UMEMOTO } while (result < data_size); 12406a99fe3SHajimu UMEMOTO 12506a99fe3SHajimu UMEMOTO return (0); 12606a99fe3SHajimu UMEMOTO } 12706a99fe3SHajimu UMEMOTO 12806a99fe3SHajimu UMEMOTO static int 129db1bdf2bSMichael Bushkov send_credentials(struct nscd_connection_ *connection, int type) 13006a99fe3SHajimu UMEMOTO { 13106a99fe3SHajimu UMEMOTO struct kevent eventlist; 13206a99fe3SHajimu UMEMOTO int nevents; 13306a99fe3SHajimu UMEMOTO ssize_t result; 13406a99fe3SHajimu UMEMOTO int res; 13506a99fe3SHajimu UMEMOTO 13606a99fe3SHajimu UMEMOTO struct msghdr cred_hdr; 13706a99fe3SHajimu UMEMOTO struct iovec iov; 13806a99fe3SHajimu UMEMOTO 13906a99fe3SHajimu UMEMOTO struct { 14006a99fe3SHajimu UMEMOTO struct cmsghdr hdr; 14106a99fe3SHajimu UMEMOTO struct cmsgcred creds; 14206a99fe3SHajimu UMEMOTO } cmsg; 14306a99fe3SHajimu UMEMOTO 14406a99fe3SHajimu UMEMOTO TRACE_IN(send_credentials); 14506a99fe3SHajimu UMEMOTO memset(&cmsg, 0, sizeof(cmsg)); 14606a99fe3SHajimu UMEMOTO cmsg.hdr.cmsg_len = sizeof(cmsg); 14706a99fe3SHajimu UMEMOTO cmsg.hdr.cmsg_level = SOL_SOCKET; 14806a99fe3SHajimu UMEMOTO cmsg.hdr.cmsg_type = SCM_CREDS; 14906a99fe3SHajimu UMEMOTO 15006a99fe3SHajimu UMEMOTO memset(&cred_hdr, 0, sizeof(struct msghdr)); 15106a99fe3SHajimu UMEMOTO cred_hdr.msg_iov = &iov; 15206a99fe3SHajimu UMEMOTO cred_hdr.msg_iovlen = 1; 15306a99fe3SHajimu UMEMOTO cred_hdr.msg_control = &cmsg; 15406a99fe3SHajimu UMEMOTO cred_hdr.msg_controllen = sizeof(cmsg); 15506a99fe3SHajimu UMEMOTO 15606a99fe3SHajimu UMEMOTO iov.iov_base = &type; 15706a99fe3SHajimu UMEMOTO iov.iov_len = sizeof(int); 15806a99fe3SHajimu UMEMOTO 15906a99fe3SHajimu UMEMOTO EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 16006a99fe3SHajimu UMEMOTO NOTE_LOWAT, sizeof(int), NULL); 16106a99fe3SHajimu UMEMOTO res = kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 16206a99fe3SHajimu UMEMOTO 16306a99fe3SHajimu UMEMOTO nevents = kevent(connection->write_queue, NULL, 0, &eventlist, 1, NULL); 16406a99fe3SHajimu UMEMOTO if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) { 16506a99fe3SHajimu UMEMOTO result = (sendmsg(connection->sockfd, &cred_hdr, 0) == -1) ? -1 16606a99fe3SHajimu UMEMOTO : 0; 16706a99fe3SHajimu UMEMOTO EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 16806a99fe3SHajimu UMEMOTO 0, 0, NULL); 16906a99fe3SHajimu UMEMOTO kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 17006a99fe3SHajimu UMEMOTO TRACE_OUT(send_credentials); 17106a99fe3SHajimu UMEMOTO return (result); 17206a99fe3SHajimu UMEMOTO } else { 17306a99fe3SHajimu UMEMOTO TRACE_OUT(send_credentials); 17406a99fe3SHajimu UMEMOTO return (-1); 17506a99fe3SHajimu UMEMOTO } 17606a99fe3SHajimu UMEMOTO } 17706a99fe3SHajimu UMEMOTO 178db1bdf2bSMichael Bushkov struct nscd_connection_ * 179db1bdf2bSMichael Bushkov open_nscd_connection__(struct nscd_connection_params const *params) 18006a99fe3SHajimu UMEMOTO { 181db1bdf2bSMichael Bushkov struct nscd_connection_ *retval; 18206a99fe3SHajimu UMEMOTO struct kevent eventlist; 18306a99fe3SHajimu UMEMOTO struct sockaddr_un client_address; 18406a99fe3SHajimu UMEMOTO int client_address_len, client_socket; 18506a99fe3SHajimu UMEMOTO int res; 18606a99fe3SHajimu UMEMOTO 187db1bdf2bSMichael Bushkov TRACE_IN(open_nscd_connection); 18806a99fe3SHajimu UMEMOTO assert(params != NULL); 18906a99fe3SHajimu UMEMOTO 19006a99fe3SHajimu UMEMOTO client_socket = socket(PF_LOCAL, SOCK_STREAM, 0); 19106a99fe3SHajimu UMEMOTO client_address.sun_family = PF_LOCAL; 19253cd9740SXin LI strlcpy(client_address.sun_path, params->socket_path, 19306a99fe3SHajimu UMEMOTO sizeof(client_address.sun_path)); 19406a99fe3SHajimu UMEMOTO client_address_len = sizeof(client_address.sun_family) + 19506a99fe3SHajimu UMEMOTO strlen(client_address.sun_path) + 1; 19606a99fe3SHajimu UMEMOTO 19706a99fe3SHajimu UMEMOTO res = connect(client_socket, (struct sockaddr *)&client_address, 19806a99fe3SHajimu UMEMOTO client_address_len); 19906a99fe3SHajimu UMEMOTO if (res == -1) { 20006a99fe3SHajimu UMEMOTO close(client_socket); 201db1bdf2bSMichael Bushkov TRACE_OUT(open_nscd_connection); 20206a99fe3SHajimu UMEMOTO return (NULL); 20306a99fe3SHajimu UMEMOTO } 20406a99fe3SHajimu UMEMOTO fcntl(client_socket, F_SETFL, O_NONBLOCK); 20506a99fe3SHajimu UMEMOTO 2064f7df5c2SXin LI retval = calloc(1, sizeof(struct nscd_connection_)); 20706a99fe3SHajimu UMEMOTO assert(retval != NULL); 20806a99fe3SHajimu UMEMOTO 20906a99fe3SHajimu UMEMOTO retval->sockfd = client_socket; 21006a99fe3SHajimu UMEMOTO 21106a99fe3SHajimu UMEMOTO retval->write_queue = kqueue(); 21206a99fe3SHajimu UMEMOTO assert(retval->write_queue != -1); 21306a99fe3SHajimu UMEMOTO 21406a99fe3SHajimu UMEMOTO EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 21506a99fe3SHajimu UMEMOTO 0, 0, NULL); 21606a99fe3SHajimu UMEMOTO res = kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL); 21706a99fe3SHajimu UMEMOTO 21806a99fe3SHajimu UMEMOTO retval->read_queue = kqueue(); 21906a99fe3SHajimu UMEMOTO assert(retval->read_queue != -1); 22006a99fe3SHajimu UMEMOTO 22106a99fe3SHajimu UMEMOTO EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 22206a99fe3SHajimu UMEMOTO 0, 0, NULL); 22306a99fe3SHajimu UMEMOTO res = kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL); 22406a99fe3SHajimu UMEMOTO 225db1bdf2bSMichael Bushkov TRACE_OUT(open_nscd_connection); 22606a99fe3SHajimu UMEMOTO return (retval); 22706a99fe3SHajimu UMEMOTO } 22806a99fe3SHajimu UMEMOTO 22906a99fe3SHajimu UMEMOTO void 230db1bdf2bSMichael Bushkov close_nscd_connection__(struct nscd_connection_ *connection) 23106a99fe3SHajimu UMEMOTO { 23206a99fe3SHajimu UMEMOTO 233db1bdf2bSMichael Bushkov TRACE_IN(close_nscd_connection); 23406a99fe3SHajimu UMEMOTO assert(connection != NULL); 23506a99fe3SHajimu UMEMOTO 23606a99fe3SHajimu UMEMOTO close(connection->sockfd); 23706a99fe3SHajimu UMEMOTO close(connection->read_queue); 23806a99fe3SHajimu UMEMOTO close(connection->write_queue); 23906a99fe3SHajimu UMEMOTO free(connection); 240db1bdf2bSMichael Bushkov TRACE_OUT(close_nscd_connection); 24106a99fe3SHajimu UMEMOTO } 24206a99fe3SHajimu UMEMOTO 24306a99fe3SHajimu UMEMOTO int 244db1bdf2bSMichael Bushkov nscd_transform__(struct nscd_connection_ *connection, 24506a99fe3SHajimu UMEMOTO const char *entry_name, int transformation_type) 24606a99fe3SHajimu UMEMOTO { 24706a99fe3SHajimu UMEMOTO size_t name_size; 24806a99fe3SHajimu UMEMOTO int error_code; 24906a99fe3SHajimu UMEMOTO int result; 25006a99fe3SHajimu UMEMOTO 251db1bdf2bSMichael Bushkov TRACE_IN(nscd_transform); 25206a99fe3SHajimu UMEMOTO 25306a99fe3SHajimu UMEMOTO error_code = -1; 25406a99fe3SHajimu UMEMOTO result = 0; 25506a99fe3SHajimu UMEMOTO result = send_credentials(connection, CET_TRANSFORM_REQUEST); 25606a99fe3SHajimu UMEMOTO if (result != 0) 25706a99fe3SHajimu UMEMOTO goto fin; 25806a99fe3SHajimu UMEMOTO 25906a99fe3SHajimu UMEMOTO if (entry_name != NULL) 26006a99fe3SHajimu UMEMOTO name_size = strlen(entry_name); 26106a99fe3SHajimu UMEMOTO else 26206a99fe3SHajimu UMEMOTO name_size = 0; 26306a99fe3SHajimu UMEMOTO 26406a99fe3SHajimu UMEMOTO result = safe_write(connection, &name_size, sizeof(size_t)); 26506a99fe3SHajimu UMEMOTO if (result != 0) 26606a99fe3SHajimu UMEMOTO goto fin; 26706a99fe3SHajimu UMEMOTO 26806a99fe3SHajimu UMEMOTO result = safe_write(connection, &transformation_type, sizeof(int)); 26906a99fe3SHajimu UMEMOTO if (result != 0) 27006a99fe3SHajimu UMEMOTO goto fin; 27106a99fe3SHajimu UMEMOTO 27206a99fe3SHajimu UMEMOTO if (entry_name != NULL) { 27306a99fe3SHajimu UMEMOTO result = safe_write(connection, entry_name, name_size); 27406a99fe3SHajimu UMEMOTO if (result != 0) 27506a99fe3SHajimu UMEMOTO goto fin; 27606a99fe3SHajimu UMEMOTO } 27706a99fe3SHajimu UMEMOTO 27806a99fe3SHajimu UMEMOTO result = safe_read(connection, &error_code, sizeof(int)); 27906a99fe3SHajimu UMEMOTO if (result != 0) 28006a99fe3SHajimu UMEMOTO error_code = -1; 28106a99fe3SHajimu UMEMOTO 28206a99fe3SHajimu UMEMOTO fin: 283db1bdf2bSMichael Bushkov TRACE_OUT(nscd_transform); 28406a99fe3SHajimu UMEMOTO return (error_code); 28506a99fe3SHajimu UMEMOTO } 286