1ed5d5720SPeter Avalos /*-
2ed5d5720SPeter Avalos * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3ed5d5720SPeter Avalos * All rights reserved.
4ed5d5720SPeter Avalos *
5ed5d5720SPeter Avalos * Redistribution and use in source and binary forms, with or without
6ed5d5720SPeter Avalos * modification, are permitted provided that the following conditions
7ed5d5720SPeter Avalos * are met:
8ed5d5720SPeter Avalos * 1. Redistributions of source code must retain the above copyright
9ed5d5720SPeter Avalos * notice, this list of conditions and the following disclaimer.
10ed5d5720SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
11ed5d5720SPeter Avalos * notice, this list of conditions and the following disclaimer in the
12ed5d5720SPeter Avalos * documentation and/or other materials provided with the distribution.
13ed5d5720SPeter Avalos *
14ed5d5720SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ed5d5720SPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ed5d5720SPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ed5d5720SPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ed5d5720SPeter Avalos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ed5d5720SPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ed5d5720SPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ed5d5720SPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ed5d5720SPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ed5d5720SPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ed5d5720SPeter Avalos * SUCH DAMAGE.
25ed5d5720SPeter Avalos *
26ed5d5720SPeter Avalos * $FreeBSD: src/usr.sbin/nscd/nscdcli.c,v 1.5 2008/10/23 00:28:21 delphij Exp $
27ed5d5720SPeter Avalos */
28ed5d5720SPeter Avalos
29ed5d5720SPeter Avalos #include <sys/types.h>
30ed5d5720SPeter Avalos #include <sys/socket.h>
31ed5d5720SPeter Avalos #include <sys/event.h>
32ed5d5720SPeter Avalos #include <sys/uio.h>
33ed5d5720SPeter Avalos #include <sys/un.h>
34ed5d5720SPeter Avalos #include <assert.h>
35ed5d5720SPeter Avalos #include <errno.h>
36ed5d5720SPeter Avalos #include <fcntl.h>
37ed5d5720SPeter Avalos #include <stdlib.h>
38ed5d5720SPeter Avalos #include <string.h>
39*18cfd87aSzrj #include <time.h>
40ed5d5720SPeter Avalos #include <unistd.h>
41ed5d5720SPeter Avalos
42ed5d5720SPeter Avalos #include "debug.h"
43ed5d5720SPeter Avalos #include "nscdcli.h"
44ed5d5720SPeter Avalos #include "protocol.h"
45ed5d5720SPeter Avalos
46ed5d5720SPeter Avalos #define DEFAULT_NSCD_IO_TIMEOUT 4
47ed5d5720SPeter Avalos
48ed5d5720SPeter Avalos static int safe_write(struct nscd_connection_ *, const void *, size_t);
49ed5d5720SPeter Avalos static int safe_read(struct nscd_connection_ *, void *, size_t);
50ed5d5720SPeter Avalos static int send_credentials(struct nscd_connection_ *, int);
51ed5d5720SPeter Avalos
52ed5d5720SPeter Avalos static int
safe_write(struct nscd_connection_ * connection,const void * data,size_t data_size)53ed5d5720SPeter Avalos safe_write(struct nscd_connection_ *connection, const void *data,
54ed5d5720SPeter Avalos size_t data_size)
55ed5d5720SPeter Avalos {
56ed5d5720SPeter Avalos struct kevent eventlist;
57ed5d5720SPeter Avalos int nevents;
58ed5d5720SPeter Avalos size_t result;
59ed5d5720SPeter Avalos ssize_t s_result;
60ed5d5720SPeter Avalos struct timespec timeout;
61ed5d5720SPeter Avalos
62ed5d5720SPeter Avalos if (data_size == 0)
63ed5d5720SPeter Avalos return (0);
64ed5d5720SPeter Avalos
65ed5d5720SPeter Avalos timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT;
66ed5d5720SPeter Avalos timeout.tv_nsec = 0;
67ed5d5720SPeter Avalos result = 0;
68ed5d5720SPeter Avalos do {
69ed5d5720SPeter Avalos nevents = kevent(connection->write_queue, NULL, 0, &eventlist,
70ed5d5720SPeter Avalos 1, &timeout);
71ed5d5720SPeter Avalos if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) {
72ed5d5720SPeter Avalos s_result = write(connection->sockfd, data + result,
73ed5d5720SPeter Avalos eventlist.data < data_size - result ?
74ed5d5720SPeter Avalos eventlist.data : data_size - result);
75ed5d5720SPeter Avalos if (s_result == -1)
76ed5d5720SPeter Avalos return (-1);
77ed5d5720SPeter Avalos else
78ed5d5720SPeter Avalos result += s_result;
79ed5d5720SPeter Avalos
80ed5d5720SPeter Avalos if (eventlist.flags & EV_EOF)
81ed5d5720SPeter Avalos return (result < data_size ? -1 : 0);
82ed5d5720SPeter Avalos } else
83ed5d5720SPeter Avalos return (-1);
84ed5d5720SPeter Avalos } while (result < data_size);
85ed5d5720SPeter Avalos
86ed5d5720SPeter Avalos return (0);
87ed5d5720SPeter Avalos }
88ed5d5720SPeter Avalos
89ed5d5720SPeter Avalos static int
safe_read(struct nscd_connection_ * connection,void * data,size_t data_size)90ed5d5720SPeter Avalos safe_read(struct nscd_connection_ *connection, void *data, size_t data_size)
91ed5d5720SPeter Avalos {
92ed5d5720SPeter Avalos struct kevent eventlist;
93ed5d5720SPeter Avalos size_t result;
94ed5d5720SPeter Avalos ssize_t s_result;
95ed5d5720SPeter Avalos struct timespec timeout;
96ed5d5720SPeter Avalos int nevents;
97ed5d5720SPeter Avalos
98ed5d5720SPeter Avalos if (data_size == 0)
99ed5d5720SPeter Avalos return (0);
100ed5d5720SPeter Avalos
101ed5d5720SPeter Avalos timeout.tv_sec = DEFAULT_NSCD_IO_TIMEOUT;
102ed5d5720SPeter Avalos timeout.tv_nsec = 0;
103ed5d5720SPeter Avalos result = 0;
104ed5d5720SPeter Avalos do {
105ed5d5720SPeter Avalos nevents = kevent(connection->read_queue, NULL, 0, &eventlist, 1,
106ed5d5720SPeter Avalos &timeout);
107ed5d5720SPeter Avalos if ((nevents == 1) && (eventlist.filter == EVFILT_READ)) {
108ed5d5720SPeter Avalos s_result = read(connection->sockfd, data + result,
109ed5d5720SPeter Avalos eventlist.data <= data_size - result ? eventlist.data :
110ed5d5720SPeter Avalos data_size - result);
111ed5d5720SPeter Avalos if (s_result == -1)
112ed5d5720SPeter Avalos return (-1);
113ed5d5720SPeter Avalos else
114ed5d5720SPeter Avalos result += s_result;
115ed5d5720SPeter Avalos
116ed5d5720SPeter Avalos if (eventlist.flags & EV_EOF)
117ed5d5720SPeter Avalos return (result < data_size ? -1 : 0);
118ed5d5720SPeter Avalos } else
119ed5d5720SPeter Avalos return (-1);
120ed5d5720SPeter Avalos } while (result < data_size);
121ed5d5720SPeter Avalos
122ed5d5720SPeter Avalos return (0);
123ed5d5720SPeter Avalos }
124ed5d5720SPeter Avalos
125ed5d5720SPeter Avalos static int
send_credentials(struct nscd_connection_ * connection,int type)126ed5d5720SPeter Avalos send_credentials(struct nscd_connection_ *connection, int type)
127ed5d5720SPeter Avalos {
128ed5d5720SPeter Avalos struct kevent eventlist;
129ed5d5720SPeter Avalos int nevents;
130ed5d5720SPeter Avalos ssize_t result;
131ed5d5720SPeter Avalos int res;
132ed5d5720SPeter Avalos
133ed5d5720SPeter Avalos struct msghdr cred_hdr;
134ed5d5720SPeter Avalos struct iovec iov;
135ed5d5720SPeter Avalos
136ed5d5720SPeter Avalos struct {
137ed5d5720SPeter Avalos struct cmsghdr hdr;
138ed5d5720SPeter Avalos struct cmsgcred creds;
139ed5d5720SPeter Avalos } cmsg;
140ed5d5720SPeter Avalos
141ed5d5720SPeter Avalos TRACE_IN(send_credentials);
142ed5d5720SPeter Avalos memset(&cmsg, 0, sizeof(cmsg));
143ed5d5720SPeter Avalos cmsg.hdr.cmsg_len = sizeof(cmsg);
144ed5d5720SPeter Avalos cmsg.hdr.cmsg_level = SOL_SOCKET;
145ed5d5720SPeter Avalos cmsg.hdr.cmsg_type = SCM_CREDS;
146ed5d5720SPeter Avalos
147ed5d5720SPeter Avalos memset(&cred_hdr, 0, sizeof(struct msghdr));
148ed5d5720SPeter Avalos cred_hdr.msg_iov = &iov;
149ed5d5720SPeter Avalos cred_hdr.msg_iovlen = 1;
150ed5d5720SPeter Avalos cred_hdr.msg_control = &cmsg;
151ed5d5720SPeter Avalos cred_hdr.msg_controllen = sizeof(cmsg);
152ed5d5720SPeter Avalos
153ed5d5720SPeter Avalos iov.iov_base = &type;
154ed5d5720SPeter Avalos iov.iov_len = sizeof(int);
155ed5d5720SPeter Avalos
156ed5d5720SPeter Avalos EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
157ed5d5720SPeter Avalos NOTE_LOWAT, sizeof(int), NULL);
158ed5d5720SPeter Avalos res = kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
159ed5d5720SPeter Avalos
160ed5d5720SPeter Avalos nevents = kevent(connection->write_queue, NULL, 0, &eventlist, 1, NULL);
161ed5d5720SPeter Avalos if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) {
162ed5d5720SPeter Avalos result = (sendmsg(connection->sockfd, &cred_hdr, 0) == -1) ? -1
163ed5d5720SPeter Avalos : 0;
164ed5d5720SPeter Avalos EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
165ed5d5720SPeter Avalos 0, 0, NULL);
166ed5d5720SPeter Avalos kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
167ed5d5720SPeter Avalos TRACE_OUT(send_credentials);
168ed5d5720SPeter Avalos return (result);
169ed5d5720SPeter Avalos } else {
170ed5d5720SPeter Avalos TRACE_OUT(send_credentials);
171ed5d5720SPeter Avalos return (-1);
172ed5d5720SPeter Avalos }
173ed5d5720SPeter Avalos }
174ed5d5720SPeter Avalos
175ed5d5720SPeter Avalos struct nscd_connection_ *
open_nscd_connection__(struct nscd_connection_params const * params)176ed5d5720SPeter Avalos open_nscd_connection__(struct nscd_connection_params const *params)
177ed5d5720SPeter Avalos {
178ed5d5720SPeter Avalos struct nscd_connection_ *retval;
179ed5d5720SPeter Avalos struct kevent eventlist;
180ed5d5720SPeter Avalos struct sockaddr_un client_address;
181ed5d5720SPeter Avalos int client_address_len, client_socket;
182ed5d5720SPeter Avalos int res;
183ed5d5720SPeter Avalos
184ed5d5720SPeter Avalos TRACE_IN(open_nscd_connection);
185ed5d5720SPeter Avalos assert(params != NULL);
186ed5d5720SPeter Avalos
187ed5d5720SPeter Avalos client_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
188ed5d5720SPeter Avalos client_address.sun_family = PF_LOCAL;
189ed5d5720SPeter Avalos strlcpy(client_address.sun_path, params->socket_path,
190ed5d5720SPeter Avalos sizeof(client_address.sun_path));
191ed5d5720SPeter Avalos client_address_len = sizeof(client_address.sun_family) +
192ed5d5720SPeter Avalos strlen(client_address.sun_path) + 1;
193ed5d5720SPeter Avalos
194ed5d5720SPeter Avalos res = connect(client_socket, (struct sockaddr *)&client_address,
195ed5d5720SPeter Avalos client_address_len);
196ed5d5720SPeter Avalos if (res == -1) {
197ed5d5720SPeter Avalos close(client_socket);
198ed5d5720SPeter Avalos TRACE_OUT(open_nscd_connection);
199ed5d5720SPeter Avalos return (NULL);
200ed5d5720SPeter Avalos }
201ed5d5720SPeter Avalos fcntl(client_socket, F_SETFL, O_NONBLOCK);
202ed5d5720SPeter Avalos
203ed5d5720SPeter Avalos retval = calloc(1, sizeof(struct nscd_connection_));
204ed5d5720SPeter Avalos assert(retval != NULL);
205ed5d5720SPeter Avalos
206ed5d5720SPeter Avalos retval->sockfd = client_socket;
207ed5d5720SPeter Avalos
208ed5d5720SPeter Avalos retval->write_queue = kqueue();
209ed5d5720SPeter Avalos assert(retval->write_queue != -1);
210ed5d5720SPeter Avalos
211ed5d5720SPeter Avalos EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD,
212ed5d5720SPeter Avalos 0, 0, NULL);
213ed5d5720SPeter Avalos res = kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL);
214ed5d5720SPeter Avalos
215ed5d5720SPeter Avalos retval->read_queue = kqueue();
216ed5d5720SPeter Avalos assert(retval->read_queue != -1);
217ed5d5720SPeter Avalos
218ed5d5720SPeter Avalos EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD,
219ed5d5720SPeter Avalos 0, 0, NULL);
220ed5d5720SPeter Avalos res = kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL);
221ed5d5720SPeter Avalos
222ed5d5720SPeter Avalos TRACE_OUT(open_nscd_connection);
223ed5d5720SPeter Avalos return (retval);
224ed5d5720SPeter Avalos }
225ed5d5720SPeter Avalos
226ed5d5720SPeter Avalos void
close_nscd_connection__(struct nscd_connection_ * connection)227ed5d5720SPeter Avalos close_nscd_connection__(struct nscd_connection_ *connection)
228ed5d5720SPeter Avalos {
229ed5d5720SPeter Avalos
230ed5d5720SPeter Avalos TRACE_IN(close_nscd_connection);
231ed5d5720SPeter Avalos assert(connection != NULL);
232ed5d5720SPeter Avalos
233ed5d5720SPeter Avalos close(connection->sockfd);
234ed5d5720SPeter Avalos close(connection->read_queue);
235ed5d5720SPeter Avalos close(connection->write_queue);
236ed5d5720SPeter Avalos free(connection);
237ed5d5720SPeter Avalos TRACE_OUT(close_nscd_connection);
238ed5d5720SPeter Avalos }
239ed5d5720SPeter Avalos
240ed5d5720SPeter Avalos int
nscd_transform__(struct nscd_connection_ * connection,const char * entry_name,int transformation_type)241ed5d5720SPeter Avalos nscd_transform__(struct nscd_connection_ *connection,
242ed5d5720SPeter Avalos const char *entry_name, int transformation_type)
243ed5d5720SPeter Avalos {
244ed5d5720SPeter Avalos size_t name_size;
245ed5d5720SPeter Avalos int error_code;
246ed5d5720SPeter Avalos int result;
247ed5d5720SPeter Avalos
248ed5d5720SPeter Avalos TRACE_IN(nscd_transform);
249ed5d5720SPeter Avalos
250ed5d5720SPeter Avalos error_code = -1;
251ed5d5720SPeter Avalos result = 0;
252ed5d5720SPeter Avalos result = send_credentials(connection, CET_TRANSFORM_REQUEST);
253ed5d5720SPeter Avalos if (result != 0)
254ed5d5720SPeter Avalos goto fin;
255ed5d5720SPeter Avalos
256ed5d5720SPeter Avalos if (entry_name != NULL)
257ed5d5720SPeter Avalos name_size = strlen(entry_name);
258ed5d5720SPeter Avalos else
259ed5d5720SPeter Avalos name_size = 0;
260ed5d5720SPeter Avalos
261ed5d5720SPeter Avalos result = safe_write(connection, &name_size, sizeof(size_t));
262ed5d5720SPeter Avalos if (result != 0)
263ed5d5720SPeter Avalos goto fin;
264ed5d5720SPeter Avalos
265ed5d5720SPeter Avalos result = safe_write(connection, &transformation_type, sizeof(int));
266ed5d5720SPeter Avalos if (result != 0)
267ed5d5720SPeter Avalos goto fin;
268ed5d5720SPeter Avalos
269ed5d5720SPeter Avalos if (entry_name != NULL) {
270ed5d5720SPeter Avalos result = safe_write(connection, entry_name, name_size);
271ed5d5720SPeter Avalos if (result != 0)
272ed5d5720SPeter Avalos goto fin;
273ed5d5720SPeter Avalos }
274ed5d5720SPeter Avalos
275ed5d5720SPeter Avalos result = safe_read(connection, &error_code, sizeof(int));
276ed5d5720SPeter Avalos if (result != 0)
277ed5d5720SPeter Avalos error_code = -1;
278ed5d5720SPeter Avalos
279ed5d5720SPeter Avalos fin:
280ed5d5720SPeter Avalos TRACE_OUT(nscd_transform);
281ed5d5720SPeter Avalos return (error_code);
282ed5d5720SPeter Avalos }
283