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> 3206a99fe3SHajimu UMEMOTO #include <sys/socket.h> 3306a99fe3SHajimu UMEMOTO #include <sys/event.h> 3406a99fe3SHajimu UMEMOTO #include <sys/uio.h> 3506a99fe3SHajimu UMEMOTO #include <sys/un.h> 3606a99fe3SHajimu UMEMOTO #include <assert.h> 3706a99fe3SHajimu UMEMOTO #include <errno.h> 3806a99fe3SHajimu UMEMOTO #include <fcntl.h> 3906a99fe3SHajimu UMEMOTO #include <stdlib.h> 4006a99fe3SHajimu UMEMOTO #include <string.h> 4106a99fe3SHajimu UMEMOTO #include <unistd.h> 4206a99fe3SHajimu UMEMOTO 4306a99fe3SHajimu UMEMOTO #include "debug.h" 44db1bdf2bSMichael Bushkov #include "nscdcli.h" 4506a99fe3SHajimu UMEMOTO #include "protocol.h" 4606a99fe3SHajimu UMEMOTO 47db1bdf2bSMichael Bushkov #define DEFAULT_NSCD_IO_TIMEOUT 4 4806a99fe3SHajimu UMEMOTO 49db1bdf2bSMichael Bushkov static int safe_write(struct nscd_connection_ *, const void *, size_t); 50db1bdf2bSMichael Bushkov static int safe_read(struct nscd_connection_ *, void *, size_t); 51db1bdf2bSMichael Bushkov static int send_credentials(struct nscd_connection_ *, int); 5206a99fe3SHajimu UMEMOTO 5306a99fe3SHajimu UMEMOTO static int 54db1bdf2bSMichael Bushkov safe_write(struct nscd_connection_ *connection, const void *data, 5506a99fe3SHajimu UMEMOTO size_t data_size) 5606a99fe3SHajimu UMEMOTO { 5706a99fe3SHajimu UMEMOTO struct kevent eventlist; 5806a99fe3SHajimu UMEMOTO int nevents; 5906a99fe3SHajimu UMEMOTO size_t result; 6006a99fe3SHajimu UMEMOTO ssize_t s_result; 6106a99fe3SHajimu UMEMOTO struct timespec timeout; 6206a99fe3SHajimu UMEMOTO 6306a99fe3SHajimu UMEMOTO if (data_size == 0) 6406a99fe3SHajimu UMEMOTO return (0); 6506a99fe3SHajimu UMEMOTO 66db1bdf2bSMichael Bushkov timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT; 6706a99fe3SHajimu UMEMOTO timeout.tv_nsec = 0; 6806a99fe3SHajimu UMEMOTO result = 0; 6906a99fe3SHajimu UMEMOTO do { 7006a99fe3SHajimu UMEMOTO nevents = kevent(connection->write_queue, NULL, 0, &eventlist, 7106a99fe3SHajimu UMEMOTO 1, &timeout); 7206a99fe3SHajimu UMEMOTO if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) { 7306a99fe3SHajimu UMEMOTO s_result = write(connection->sockfd, data + result, 7406a99fe3SHajimu UMEMOTO eventlist.data < data_size - result ? 7506a99fe3SHajimu UMEMOTO eventlist.data : data_size - result); 7606a99fe3SHajimu UMEMOTO if (s_result == -1) 7706a99fe3SHajimu UMEMOTO return (-1); 7806a99fe3SHajimu UMEMOTO else 7906a99fe3SHajimu UMEMOTO result += s_result; 8006a99fe3SHajimu UMEMOTO 8106a99fe3SHajimu UMEMOTO if (eventlist.flags & EV_EOF) 8206a99fe3SHajimu UMEMOTO return (result < data_size ? -1 : 0); 8306a99fe3SHajimu UMEMOTO } else 8406a99fe3SHajimu UMEMOTO return (-1); 8506a99fe3SHajimu UMEMOTO } while (result < data_size); 8606a99fe3SHajimu UMEMOTO 8706a99fe3SHajimu UMEMOTO return (0); 8806a99fe3SHajimu UMEMOTO } 8906a99fe3SHajimu UMEMOTO 9006a99fe3SHajimu UMEMOTO static int 91db1bdf2bSMichael Bushkov safe_read(struct nscd_connection_ *connection, void *data, size_t data_size) 9206a99fe3SHajimu UMEMOTO { 9306a99fe3SHajimu UMEMOTO struct kevent eventlist; 9406a99fe3SHajimu UMEMOTO size_t result; 9506a99fe3SHajimu UMEMOTO ssize_t s_result; 9606a99fe3SHajimu UMEMOTO struct timespec timeout; 9706a99fe3SHajimu UMEMOTO int nevents; 9806a99fe3SHajimu UMEMOTO 9906a99fe3SHajimu UMEMOTO if (data_size == 0) 10006a99fe3SHajimu UMEMOTO return (0); 10106a99fe3SHajimu UMEMOTO 102db1bdf2bSMichael Bushkov timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT; 10306a99fe3SHajimu UMEMOTO timeout.tv_nsec = 0; 10406a99fe3SHajimu UMEMOTO result = 0; 10506a99fe3SHajimu UMEMOTO do { 10606a99fe3SHajimu UMEMOTO nevents = kevent(connection->read_queue, NULL, 0, &eventlist, 1, 10706a99fe3SHajimu UMEMOTO &timeout); 10806a99fe3SHajimu UMEMOTO if ((nevents == 1) && (eventlist.filter == EVFILT_READ)) { 10906a99fe3SHajimu UMEMOTO s_result = read(connection->sockfd, data + result, 11006a99fe3SHajimu UMEMOTO eventlist.data <= data_size - result ? eventlist.data : 11106a99fe3SHajimu UMEMOTO data_size - result); 11206a99fe3SHajimu UMEMOTO if (s_result == -1) 11306a99fe3SHajimu UMEMOTO return (-1); 11406a99fe3SHajimu UMEMOTO else 11506a99fe3SHajimu UMEMOTO result += s_result; 11606a99fe3SHajimu UMEMOTO 11706a99fe3SHajimu UMEMOTO if (eventlist.flags & EV_EOF) 11806a99fe3SHajimu UMEMOTO return (result < data_size ? -1 : 0); 11906a99fe3SHajimu UMEMOTO } else 12006a99fe3SHajimu UMEMOTO return (-1); 12106a99fe3SHajimu UMEMOTO } while (result < data_size); 12206a99fe3SHajimu UMEMOTO 12306a99fe3SHajimu UMEMOTO return (0); 12406a99fe3SHajimu UMEMOTO } 12506a99fe3SHajimu UMEMOTO 12606a99fe3SHajimu UMEMOTO static int 127db1bdf2bSMichael Bushkov send_credentials(struct nscd_connection_ *connection, int type) 12806a99fe3SHajimu UMEMOTO { 12906a99fe3SHajimu UMEMOTO struct kevent eventlist; 13006a99fe3SHajimu UMEMOTO int nevents; 13106a99fe3SHajimu UMEMOTO ssize_t result; 13206a99fe3SHajimu UMEMOTO int res; 13306a99fe3SHajimu UMEMOTO 13406a99fe3SHajimu UMEMOTO struct msghdr cred_hdr; 13506a99fe3SHajimu UMEMOTO struct iovec iov; 13606a99fe3SHajimu UMEMOTO 13706a99fe3SHajimu UMEMOTO struct { 13806a99fe3SHajimu UMEMOTO struct cmsghdr hdr; 13906a99fe3SHajimu UMEMOTO struct cmsgcred creds; 14006a99fe3SHajimu UMEMOTO } cmsg; 14106a99fe3SHajimu UMEMOTO 14206a99fe3SHajimu UMEMOTO TRACE_IN(send_credentials); 14306a99fe3SHajimu UMEMOTO memset(&cmsg, 0, sizeof(cmsg)); 14406a99fe3SHajimu UMEMOTO cmsg.hdr.cmsg_len = sizeof(cmsg); 14506a99fe3SHajimu UMEMOTO cmsg.hdr.cmsg_level = SOL_SOCKET; 14606a99fe3SHajimu UMEMOTO cmsg.hdr.cmsg_type = SCM_CREDS; 14706a99fe3SHajimu UMEMOTO 14806a99fe3SHajimu UMEMOTO memset(&cred_hdr, 0, sizeof(struct msghdr)); 14906a99fe3SHajimu UMEMOTO cred_hdr.msg_iov = &iov; 15006a99fe3SHajimu UMEMOTO cred_hdr.msg_iovlen = 1; 15106a99fe3SHajimu UMEMOTO cred_hdr.msg_control = &cmsg; 15206a99fe3SHajimu UMEMOTO cred_hdr.msg_controllen = sizeof(cmsg); 15306a99fe3SHajimu UMEMOTO 15406a99fe3SHajimu UMEMOTO iov.iov_base = &type; 15506a99fe3SHajimu UMEMOTO iov.iov_len = sizeof(int); 15606a99fe3SHajimu UMEMOTO 15706a99fe3SHajimu UMEMOTO EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 15806a99fe3SHajimu UMEMOTO NOTE_LOWAT, sizeof(int), NULL); 15906a99fe3SHajimu UMEMOTO res = kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 16006a99fe3SHajimu UMEMOTO 16106a99fe3SHajimu UMEMOTO nevents = kevent(connection->write_queue, NULL, 0, &eventlist, 1, NULL); 16206a99fe3SHajimu UMEMOTO if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) { 16306a99fe3SHajimu UMEMOTO result = (sendmsg(connection->sockfd, &cred_hdr, 0) == -1) ? -1 16406a99fe3SHajimu UMEMOTO : 0; 16506a99fe3SHajimu UMEMOTO EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 16606a99fe3SHajimu UMEMOTO 0, 0, NULL); 16706a99fe3SHajimu UMEMOTO kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 16806a99fe3SHajimu UMEMOTO TRACE_OUT(send_credentials); 16906a99fe3SHajimu UMEMOTO return (result); 17006a99fe3SHajimu UMEMOTO } else { 17106a99fe3SHajimu UMEMOTO TRACE_OUT(send_credentials); 17206a99fe3SHajimu UMEMOTO return (-1); 17306a99fe3SHajimu UMEMOTO } 17406a99fe3SHajimu UMEMOTO } 17506a99fe3SHajimu UMEMOTO 176db1bdf2bSMichael Bushkov struct nscd_connection_ * 177db1bdf2bSMichael Bushkov open_nscd_connection__(struct nscd_connection_params const *params) 17806a99fe3SHajimu UMEMOTO { 179db1bdf2bSMichael Bushkov struct nscd_connection_ *retval; 18006a99fe3SHajimu UMEMOTO struct kevent eventlist; 18106a99fe3SHajimu UMEMOTO struct sockaddr_un client_address; 18206a99fe3SHajimu UMEMOTO int client_address_len, client_socket; 18306a99fe3SHajimu UMEMOTO int res; 18406a99fe3SHajimu UMEMOTO 185db1bdf2bSMichael Bushkov TRACE_IN(open_nscd_connection); 18606a99fe3SHajimu UMEMOTO assert(params != NULL); 18706a99fe3SHajimu UMEMOTO 18806a99fe3SHajimu UMEMOTO client_socket = socket(PF_LOCAL, SOCK_STREAM, 0); 18906a99fe3SHajimu UMEMOTO client_address.sun_family = PF_LOCAL; 19053cd9740SXin LI strlcpy(client_address.sun_path, params->socket_path, 19106a99fe3SHajimu UMEMOTO sizeof(client_address.sun_path)); 19206a99fe3SHajimu UMEMOTO client_address_len = sizeof(client_address.sun_family) + 19306a99fe3SHajimu UMEMOTO strlen(client_address.sun_path) + 1; 19406a99fe3SHajimu UMEMOTO 19506a99fe3SHajimu UMEMOTO res = connect(client_socket, (struct sockaddr *)&client_address, 19606a99fe3SHajimu UMEMOTO client_address_len); 19706a99fe3SHajimu UMEMOTO if (res == -1) { 19806a99fe3SHajimu UMEMOTO close(client_socket); 199db1bdf2bSMichael Bushkov TRACE_OUT(open_nscd_connection); 20006a99fe3SHajimu UMEMOTO return (NULL); 20106a99fe3SHajimu UMEMOTO } 20206a99fe3SHajimu UMEMOTO fcntl(client_socket, F_SETFL, O_NONBLOCK); 20306a99fe3SHajimu UMEMOTO 2044f7df5c2SXin LI retval = calloc(1, sizeof(struct nscd_connection_)); 20506a99fe3SHajimu UMEMOTO assert(retval != NULL); 20606a99fe3SHajimu UMEMOTO 20706a99fe3SHajimu UMEMOTO retval->sockfd = client_socket; 20806a99fe3SHajimu UMEMOTO 20906a99fe3SHajimu UMEMOTO retval->write_queue = kqueue(); 21006a99fe3SHajimu UMEMOTO assert(retval->write_queue != -1); 21106a99fe3SHajimu UMEMOTO 21206a99fe3SHajimu UMEMOTO EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 21306a99fe3SHajimu UMEMOTO 0, 0, NULL); 21406a99fe3SHajimu UMEMOTO res = kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL); 21506a99fe3SHajimu UMEMOTO 21606a99fe3SHajimu UMEMOTO retval->read_queue = kqueue(); 21706a99fe3SHajimu UMEMOTO assert(retval->read_queue != -1); 21806a99fe3SHajimu UMEMOTO 21906a99fe3SHajimu UMEMOTO EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 22006a99fe3SHajimu UMEMOTO 0, 0, NULL); 22106a99fe3SHajimu UMEMOTO res = kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL); 22206a99fe3SHajimu UMEMOTO 223db1bdf2bSMichael Bushkov TRACE_OUT(open_nscd_connection); 22406a99fe3SHajimu UMEMOTO return (retval); 22506a99fe3SHajimu UMEMOTO } 22606a99fe3SHajimu UMEMOTO 22706a99fe3SHajimu UMEMOTO void 228db1bdf2bSMichael Bushkov close_nscd_connection__(struct nscd_connection_ *connection) 22906a99fe3SHajimu UMEMOTO { 23006a99fe3SHajimu UMEMOTO 231db1bdf2bSMichael Bushkov TRACE_IN(close_nscd_connection); 23206a99fe3SHajimu UMEMOTO assert(connection != NULL); 23306a99fe3SHajimu UMEMOTO 23406a99fe3SHajimu UMEMOTO close(connection->sockfd); 23506a99fe3SHajimu UMEMOTO close(connection->read_queue); 23606a99fe3SHajimu UMEMOTO close(connection->write_queue); 23706a99fe3SHajimu UMEMOTO free(connection); 238db1bdf2bSMichael Bushkov TRACE_OUT(close_nscd_connection); 23906a99fe3SHajimu UMEMOTO } 24006a99fe3SHajimu UMEMOTO 24106a99fe3SHajimu UMEMOTO int 242db1bdf2bSMichael Bushkov nscd_transform__(struct nscd_connection_ *connection, 24306a99fe3SHajimu UMEMOTO const char *entry_name, int transformation_type) 24406a99fe3SHajimu UMEMOTO { 24506a99fe3SHajimu UMEMOTO size_t name_size; 24606a99fe3SHajimu UMEMOTO int error_code; 24706a99fe3SHajimu UMEMOTO int result; 24806a99fe3SHajimu UMEMOTO 249db1bdf2bSMichael Bushkov TRACE_IN(nscd_transform); 25006a99fe3SHajimu UMEMOTO 25106a99fe3SHajimu UMEMOTO error_code = -1; 25206a99fe3SHajimu UMEMOTO result = 0; 25306a99fe3SHajimu UMEMOTO result = send_credentials(connection, CET_TRANSFORM_REQUEST); 25406a99fe3SHajimu UMEMOTO if (result != 0) 25506a99fe3SHajimu UMEMOTO goto fin; 25606a99fe3SHajimu UMEMOTO 25706a99fe3SHajimu UMEMOTO if (entry_name != NULL) 25806a99fe3SHajimu UMEMOTO name_size = strlen(entry_name); 25906a99fe3SHajimu UMEMOTO else 26006a99fe3SHajimu UMEMOTO name_size = 0; 26106a99fe3SHajimu UMEMOTO 26206a99fe3SHajimu UMEMOTO result = safe_write(connection, &name_size, sizeof(size_t)); 26306a99fe3SHajimu UMEMOTO if (result != 0) 26406a99fe3SHajimu UMEMOTO goto fin; 26506a99fe3SHajimu UMEMOTO 26606a99fe3SHajimu UMEMOTO result = safe_write(connection, &transformation_type, sizeof(int)); 26706a99fe3SHajimu UMEMOTO if (result != 0) 26806a99fe3SHajimu UMEMOTO goto fin; 26906a99fe3SHajimu UMEMOTO 27006a99fe3SHajimu UMEMOTO if (entry_name != NULL) { 27106a99fe3SHajimu UMEMOTO result = safe_write(connection, entry_name, name_size); 27206a99fe3SHajimu UMEMOTO if (result != 0) 27306a99fe3SHajimu UMEMOTO goto fin; 27406a99fe3SHajimu UMEMOTO } 27506a99fe3SHajimu UMEMOTO 27606a99fe3SHajimu UMEMOTO result = safe_read(connection, &error_code, sizeof(int)); 27706a99fe3SHajimu UMEMOTO if (result != 0) 27806a99fe3SHajimu UMEMOTO error_code = -1; 27906a99fe3SHajimu UMEMOTO 28006a99fe3SHajimu UMEMOTO fin: 281db1bdf2bSMichael Bushkov TRACE_OUT(nscd_transform); 28206a99fe3SHajimu UMEMOTO return (error_code); 28306a99fe3SHajimu UMEMOTO } 284