nscdcli.c revision 194093
1229997Sken/*- 2229997Sken * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3229997Sken * All rights reserved. 4229997Sken * 5229997Sken * Redistribution and use in source and binary forms, with or without 6229997Sken * modification, are permitted provided that the following conditions 7229997Sken * are met: 8229997Sken * 1. Redistributions of source code must retain the above copyright 9229997Sken * notice, this list of conditions and the following disclaimer. 10229997Sken * 2. Redistributions in binary form must reproduce the above copyright 11229997Sken * notice, this list of conditions and the following disclaimer in the 12229997Sken * documentation and/or other materials provided with the distribution. 13229997Sken * 14229997Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15229997Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16229997Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17229997Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18229997Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22229997Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23229997Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24229997Sken * SUCH DAMAGE. 25229997Sken * 26229997Sken */ 27229997Sken 28229997Sken#include <sys/cdefs.h> 29229997Sken__FBSDID("$FreeBSD: head/usr.sbin/nscd/nscdcli.c 194093 2009-06-13 00:43:56Z des $"); 30229997Sken 31229997Sken#include <sys/types.h> 32229997Sken 33229997Sken#include <sys/event.h> 34229997Sken#include <sys/socket.h> 35229997Sken#include <sys/uio.h> 36229997Sken#include <sys/un.h> 37229997Sken 38229997Sken#include <assert.h> 39229997Sken#include <errno.h> 40229997Sken#include <fcntl.h> 41229997Sken#include <stdlib.h> 42229997Sken#include <string.h> 43229997Sken#include <unistd.h> 44229997Sken 45229997Sken#include "debug.h" 46229997Sken#include "nscdcli.h" 47229997Sken#include "protocol.h" 48229997Sken 49229997Sken#define DEFAULT_NSCD_IO_TIMEOUT 4 50229997Sken 51229997Skenstatic int safe_write(struct nscd_connection_ *, const void *, size_t); 52229997Skenstatic int safe_read(struct nscd_connection_ *, void *, size_t); 53229997Skenstatic int send_credentials(struct nscd_connection_ *, int); 54229997Sken 55229997Skenstatic int 56229997Skensafe_write(struct nscd_connection_ *connection, const void *data, 57229997Sken size_t data_size) 58229997Sken{ 59229997Sken struct kevent eventlist; 60229997Sken int nevents; 61229997Sken size_t result; 62229997Sken ssize_t s_result; 63229997Sken struct timespec timeout; 64229997Sken 65229997Sken if (data_size == 0) 66229997Sken return (0); 67229997Sken 68229997Sken timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT; 69229997Sken timeout.tv_nsec = 0; 70229997Sken result = 0; 71229997Sken do { 72229997Sken nevents = kevent(connection->write_queue, NULL, 0, &eventlist, 73229997Sken 1, &timeout); 74229997Sken if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) { 75229997Sken s_result = write(connection->sockfd, data + result, 76229997Sken eventlist.data < data_size - result ? 77229997Sken eventlist.data : data_size - result); 78229997Sken if (s_result == -1) 79229997Sken return (-1); 80229997Sken else 81229997Sken result += s_result; 82229997Sken 83229997Sken if (eventlist.flags & EV_EOF) 84229997Sken return (result < data_size ? -1 : 0); 85229997Sken } else 86229997Sken return (-1); 87229997Sken } while (result < data_size); 88229997Sken 89229997Sken return (0); 90229997Sken} 91229997Sken 92229997Skenstatic int 93229997Skensafe_read(struct nscd_connection_ *connection, void *data, size_t data_size) 94229997Sken{ 95229997Sken struct kevent eventlist; 96229997Sken size_t result; 97229997Sken ssize_t s_result; 98229997Sken struct timespec timeout; 99229997Sken int nevents; 100229997Sken 101229997Sken if (data_size == 0) 102229997Sken return (0); 103229997Sken 104229997Sken timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT; 105229997Sken timeout.tv_nsec = 0; 106229997Sken result = 0; 107229997Sken do { 108229997Sken nevents = kevent(connection->read_queue, NULL, 0, &eventlist, 1, 109229997Sken &timeout); 110229997Sken if ((nevents == 1) && (eventlist.filter == EVFILT_READ)) { 111229997Sken s_result = read(connection->sockfd, data + result, 112229997Sken eventlist.data <= data_size - result ? eventlist.data : 113229997Sken data_size - result); 114229997Sken if (s_result == -1) 115229997Sken return (-1); 116229997Sken else 117229997Sken result += s_result; 118229997Sken 119229997Sken if (eventlist.flags & EV_EOF) 120229997Sken return (result < data_size ? -1 : 0); 121229997Sken } else 122229997Sken return (-1); 123229997Sken } while (result < data_size); 124229997Sken 125229997Sken return (0); 126229997Sken} 127229997Sken 128229997Skenstatic int 129229997Skensend_credentials(struct nscd_connection_ *connection, int type) 130229997Sken{ 131229997Sken struct kevent eventlist; 132229997Sken int nevents; 133229997Sken ssize_t result; 134229997Sken int res; 135229997Sken 136229997Sken struct msghdr cred_hdr; 137229997Sken struct iovec iov; 138229997Sken 139229997Sken struct { 140229997Sken struct cmsghdr hdr; 141229997Sken struct cmsgcred creds; 142229997Sken } cmsg; 143229997Sken 144229997Sken TRACE_IN(send_credentials); 145229997Sken memset(&cmsg, 0, sizeof(cmsg)); 146229997Sken cmsg.hdr.cmsg_len = sizeof(cmsg); 147229997Sken cmsg.hdr.cmsg_level = SOL_SOCKET; 148229997Sken cmsg.hdr.cmsg_type = SCM_CREDS; 149229997Sken 150229997Sken memset(&cred_hdr, 0, sizeof(struct msghdr)); 151229997Sken cred_hdr.msg_iov = &iov; 152229997Sken cred_hdr.msg_iovlen = 1; 153229997Sken cred_hdr.msg_control = &cmsg; 154229997Sken cred_hdr.msg_controllen = sizeof(cmsg); 155229997Sken 156229997Sken iov.iov_base = &type; 157229997Sken iov.iov_len = sizeof(int); 158229997Sken 159229997Sken EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 160229997Sken NOTE_LOWAT, sizeof(int), NULL); 161229997Sken res = kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 162229997Sken 163229997Sken nevents = kevent(connection->write_queue, NULL, 0, &eventlist, 1, NULL); 164229997Sken if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) { 165229997Sken result = (sendmsg(connection->sockfd, &cred_hdr, 0) == -1) ? -1 166229997Sken : 0; 167229997Sken EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 168229997Sken 0, 0, NULL); 169229997Sken kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 170229997Sken TRACE_OUT(send_credentials); 171229997Sken return (result); 172229997Sken } else { 173229997Sken TRACE_OUT(send_credentials); 174229997Sken return (-1); 175229997Sken } 176229997Sken} 177229997Sken 178229997Skenstruct nscd_connection_ * 179229997Skenopen_nscd_connection__(struct nscd_connection_params const *params) 180229997Sken{ 181229997Sken struct nscd_connection_ *retval; 182229997Sken struct kevent eventlist; 183229997Sken struct sockaddr_un client_address; 184229997Sken int client_address_len, client_socket; 185229997Sken int res; 186229997Sken 187229997Sken TRACE_IN(open_nscd_connection); 188229997Sken assert(params != NULL); 189229997Sken 190229997Sken client_socket = socket(PF_LOCAL, SOCK_STREAM, 0); 191229997Sken client_address.sun_family = PF_LOCAL; 192229997Sken strlcpy(client_address.sun_path, params->socket_path, 193229997Sken sizeof(client_address.sun_path)); 194229997Sken client_address_len = sizeof(client_address.sun_family) + 195229997Sken strlen(client_address.sun_path) + 1; 196229997Sken 197229997Sken res = connect(client_socket, (struct sockaddr *)&client_address, 198229997Sken client_address_len); 199229997Sken if (res == -1) { 200229997Sken close(client_socket); 201229997Sken TRACE_OUT(open_nscd_connection); 202229997Sken return (NULL); 203229997Sken } 204229997Sken fcntl(client_socket, F_SETFL, O_NONBLOCK); 205229997Sken 206229997Sken retval = calloc(1, sizeof(struct nscd_connection_)); 207229997Sken assert(retval != NULL); 208229997Sken 209229997Sken retval->sockfd = client_socket; 210229997Sken 211229997Sken retval->write_queue = kqueue(); 212229997Sken assert(retval->write_queue != -1); 213229997Sken 214229997Sken EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 215229997Sken 0, 0, NULL); 216229997Sken res = kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL); 217229997Sken 218229997Sken retval->read_queue = kqueue(); 219229997Sken assert(retval->read_queue != -1); 220229997Sken 221229997Sken EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 222229997Sken 0, 0, NULL); 223229997Sken res = kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL); 224229997Sken 225229997Sken TRACE_OUT(open_nscd_connection); 226229997Sken return (retval); 227229997Sken} 228 229void 230close_nscd_connection__(struct nscd_connection_ *connection) 231{ 232 233 TRACE_IN(close_nscd_connection); 234 assert(connection != NULL); 235 236 close(connection->sockfd); 237 close(connection->read_queue); 238 close(connection->write_queue); 239 free(connection); 240 TRACE_OUT(close_nscd_connection); 241} 242 243int 244nscd_transform__(struct nscd_connection_ *connection, 245 const char *entry_name, int transformation_type) 246{ 247 size_t name_size; 248 int error_code; 249 int result; 250 251 TRACE_IN(nscd_transform); 252 253 error_code = -1; 254 result = 0; 255 result = send_credentials(connection, CET_TRANSFORM_REQUEST); 256 if (result != 0) 257 goto fin; 258 259 if (entry_name != NULL) 260 name_size = strlen(entry_name); 261 else 262 name_size = 0; 263 264 result = safe_write(connection, &name_size, sizeof(size_t)); 265 if (result != 0) 266 goto fin; 267 268 result = safe_write(connection, &transformation_type, sizeof(int)); 269 if (result != 0) 270 goto fin; 271 272 if (entry_name != NULL) { 273 result = safe_write(connection, entry_name, name_size); 274 if (result != 0) 275 goto fin; 276 } 277 278 result = safe_read(connection, &error_code, sizeof(int)); 279 if (result != 0) 280 error_code = -1; 281 282fin: 283 TRACE_OUT(nscd_transform); 284 return (error_code); 285} 286