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