xref: /dragonfly/usr.sbin/nscd/nscdcli.c (revision 18cfd87a)
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