1158115Sume/*-
2158115Sume * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3158115Sume * All rights reserved.
4158115Sume *
5158115Sume * Redistribution and use in source and binary forms, with or without
6158115Sume * modification, are permitted provided that the following conditions
7158115Sume * are met:
8158115Sume * 1. Redistributions of source code must retain the above copyright
9158115Sume *    notice, this list of conditions and the following disclaimer.
10158115Sume * 2. Redistributions in binary form must reproduce the above copyright
11158115Sume *    notice, this list of conditions and the following disclaimer in the
12158115Sume *    documentation and/or other materials provided with the distribution.
13158115Sume *
14158115Sume * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15158115Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16158115Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17158115Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18158115Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19158115Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20158115Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21158115Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22158115Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23158115Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24158115Sume * SUCH DAMAGE.
25158115Sume *
26158115Sume */
27158115Sume
28158115Sume#include <sys/cdefs.h>
29158115Sume__FBSDID("$FreeBSD: stable/11/usr.sbin/nscd/query.c 319178 2017-05-30 03:30:53Z cy $");
30158115Sume
31158115Sume#include <sys/types.h>
32194089Sdes#include <sys/event.h>
33158115Sume#include <sys/socket.h>
34158115Sume#include <sys/time.h>
35194089Sdes
36158115Sume#include <assert.h>
37158115Sume#include <errno.h>
38158115Sume#include <nsswitch.h>
39158115Sume#include <stdio.h>
40158115Sume#include <stdlib.h>
41158115Sume#include <string.h>
42194089Sdes#include <unistd.h>
43194089Sdes
44158115Sume#include "config.h"
45158115Sume#include "debug.h"
46158115Sume#include "query.h"
47158115Sume#include "log.h"
48158115Sume#include "mp_ws_query.h"
49158115Sume#include "mp_rs_query.h"
50158115Sume#include "singletons.h"
51158115Sume
52158115Sumestatic const char negative_data[1] = { 0 };
53158115Sume
54158115Sumeextern	void get_time_func(struct timeval *);
55158115Sume
56158115Sumestatic 	void clear_config_entry(struct configuration_entry *);
57158115Sumestatic 	void clear_config_entry_part(struct configuration_entry *,
58158115Sume	const char *, size_t);
59158115Sume
60158115Sumestatic	int on_query_startup(struct query_state *);
61158115Sumestatic	void on_query_destroy(struct query_state *);
62158115Sume
63158115Sumestatic	int on_read_request_read1(struct query_state *);
64158115Sumestatic	int on_read_request_read2(struct query_state *);
65158115Sumestatic	int on_read_request_process(struct query_state *);
66158115Sumestatic	int on_read_response_write1(struct query_state *);
67158115Sumestatic	int on_read_response_write2(struct query_state *);
68158115Sume
69158115Sumestatic	int on_rw_mapper(struct query_state *);
70158115Sume
71158115Sumestatic	int on_transform_request_read1(struct query_state *);
72158115Sumestatic	int on_transform_request_read2(struct query_state *);
73158115Sumestatic	int on_transform_request_process(struct query_state *);
74158115Sumestatic	int on_transform_response_write1(struct query_state *);
75158115Sume
76158115Sumestatic	int on_write_request_read1(struct query_state *);
77158115Sumestatic	int on_write_request_read2(struct query_state *);
78158115Sumestatic	int on_negative_write_request_process(struct query_state *);
79158115Sumestatic	int on_write_request_process(struct query_state *);
80158115Sumestatic	int on_write_response_write1(struct query_state *);
81158115Sume
82158115Sume/*
83158115Sume * Clears the specified configuration entry (clears the cache for positive and
84158115Sume * and negative entries) and also for all multipart entries.
85158115Sume */
86158115Sumestatic void
87158115Sumeclear_config_entry(struct configuration_entry *config_entry)
88158115Sume{
89158115Sume	size_t i;
90158115Sume
91158115Sume	TRACE_IN(clear_config_entry);
92158115Sume	configuration_lock_entry(config_entry, CELT_POSITIVE);
93158115Sume	if (config_entry->positive_cache_entry != NULL)
94158115Sume		transform_cache_entry(
95158115Sume			config_entry->positive_cache_entry,
96158115Sume			CTT_CLEAR);
97158115Sume	configuration_unlock_entry(config_entry, CELT_POSITIVE);
98158115Sume
99158115Sume	configuration_lock_entry(config_entry, CELT_NEGATIVE);
100158115Sume	if (config_entry->negative_cache_entry != NULL)
101158115Sume		transform_cache_entry(
102158115Sume			config_entry->negative_cache_entry,
103158115Sume			CTT_CLEAR);
104158115Sume	configuration_unlock_entry(config_entry, CELT_NEGATIVE);
105158115Sume
106158115Sume	configuration_lock_entry(config_entry, CELT_MULTIPART);
107158115Sume	for (i = 0; i < config_entry->mp_cache_entries_size; ++i)
108158115Sume		transform_cache_entry(
109158115Sume			config_entry->mp_cache_entries[i],
110158115Sume			CTT_CLEAR);
111158115Sume	configuration_unlock_entry(config_entry, CELT_MULTIPART);
112158115Sume
113158115Sume	TRACE_OUT(clear_config_entry);
114158115Sume}
115158115Sume
116158115Sume/*
117158115Sume * Clears the specified configuration entry by deleting only the elements,
118158115Sume * that are owned by the user with specified eid_str.
119158115Sume */
120158115Sumestatic void
121158115Sumeclear_config_entry_part(struct configuration_entry *config_entry,
122158115Sume	const char *eid_str, size_t eid_str_length)
123158115Sume{
124158115Sume	cache_entry *start, *finish, *mp_entry;
125158115Sume	TRACE_IN(clear_config_entry_part);
126158115Sume	configuration_lock_entry(config_entry, CELT_POSITIVE);
127158115Sume	if (config_entry->positive_cache_entry != NULL)
128158115Sume		transform_cache_entry_part(
129158115Sume			config_entry->positive_cache_entry,
130158115Sume			CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
131158115Sume	configuration_unlock_entry(config_entry, CELT_POSITIVE);
132158115Sume
133158115Sume	configuration_lock_entry(config_entry, CELT_NEGATIVE);
134158115Sume	if (config_entry->negative_cache_entry != NULL)
135158115Sume		transform_cache_entry_part(
136158115Sume			config_entry->negative_cache_entry,
137158115Sume			CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
138158115Sume	configuration_unlock_entry(config_entry, CELT_NEGATIVE);
139158115Sume
140158115Sume	configuration_lock_entry(config_entry, CELT_MULTIPART);
141158115Sume	if (configuration_entry_find_mp_cache_entries(config_entry,
142158115Sume		eid_str, &start, &finish) == 0) {
143158115Sume		for (mp_entry = start; mp_entry != finish; ++mp_entry)
144158115Sume			transform_cache_entry(*mp_entry, CTT_CLEAR);
145158115Sume	}
146158115Sume	configuration_unlock_entry(config_entry, CELT_MULTIPART);
147158115Sume
148158115Sume	TRACE_OUT(clear_config_entry_part);
149158115Sume}
150158115Sume
151158115Sume/*
152158115Sume * This function is assigned to the query_state structue on its creation.
153158115Sume * It's main purpose is to receive credentials from the client.
154158115Sume */
155158115Sumestatic int
156158115Sumeon_query_startup(struct query_state *qstate)
157158115Sume{
158158115Sume	struct msghdr	cred_hdr;
159158115Sume	struct iovec	iov;
160158257Sume	struct cmsgcred *cred;
161158115Sume	int elem_type;
162158115Sume
163158115Sume	struct {
164158115Sume		struct cmsghdr	hdr;
165158257Sume		char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
166158115Sume	} cmsg;
167158115Sume
168158115Sume	TRACE_IN(on_query_startup);
169158115Sume	assert(qstate != NULL);
170158115Sume
171158115Sume	memset(&cred_hdr, 0, sizeof(struct msghdr));
172158115Sume	cred_hdr.msg_iov = &iov;
173158115Sume	cred_hdr.msg_iovlen = 1;
174158257Sume	cred_hdr.msg_control = (caddr_t)&cmsg;
175158257Sume	cred_hdr.msg_controllen = CMSG_LEN(sizeof(struct cmsgcred));
176158115Sume
177158115Sume	memset(&iov, 0, sizeof(struct iovec));
178158115Sume	iov.iov_base = &elem_type;
179158115Sume	iov.iov_len = sizeof(int);
180158115Sume
181158115Sume	if (recvmsg(qstate->sockfd, &cred_hdr, 0) == -1) {
182158115Sume		TRACE_OUT(on_query_startup);
183158115Sume		return (-1);
184158115Sume	}
185158115Sume
186158257Sume	if (cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(struct cmsgcred))
187158115Sume		|| cmsg.hdr.cmsg_level != SOL_SOCKET
188158115Sume		|| cmsg.hdr.cmsg_type != SCM_CREDS) {
189158115Sume		TRACE_OUT(on_query_startup);
190158115Sume		return (-1);
191158115Sume	}
192158115Sume
193158257Sume	cred = (struct cmsgcred *)CMSG_DATA(&cmsg);
194158257Sume	qstate->uid = cred->cmcred_uid;
195158257Sume	qstate->gid = cred->cmcred_gid;
196158115Sume
197171795Sbushman#if defined(NS_NSCD_EID_CHECKING) || defined(NS_STRICT_NSCD_EID_CHECKING)
198158115Sume/*
199158115Sume * This check is probably a bit redundant - per-user cache is always separated
200158115Sume * by the euid/egid pair
201158115Sume */
202158115Sume	if (check_query_eids(qstate) != 0) {
203171795Sbushman#ifdef NS_STRICT_NSCD_EID_CHECKING
204158115Sume		TRACE_OUT(on_query_startup);
205158115Sume		return (-1);
206158115Sume#else
207158115Sume		if ((elem_type != CET_READ_REQUEST) &&
208158115Sume			(elem_type != CET_MP_READ_SESSION_REQUEST) &&
209158115Sume			(elem_type != CET_WRITE_REQUEST) &&
210158115Sume			(elem_type != CET_MP_WRITE_SESSION_REQUEST)) {
211158115Sume			TRACE_OUT(on_query_startup);
212158115Sume			return (-1);
213158115Sume		}
214158115Sume#endif
215158115Sume	}
216158115Sume#endif
217158115Sume
218158115Sume	switch (elem_type) {
219158115Sume	case CET_WRITE_REQUEST:
220158115Sume		qstate->process_func = on_write_request_read1;
221158115Sume		break;
222158115Sume	case CET_READ_REQUEST:
223158115Sume		qstate->process_func = on_read_request_read1;
224158115Sume		break;
225158115Sume	case CET_TRANSFORM_REQUEST:
226158115Sume		qstate->process_func = on_transform_request_read1;
227158115Sume		break;
228158115Sume	case CET_MP_WRITE_SESSION_REQUEST:
229158115Sume		qstate->process_func = on_mp_write_session_request_read1;
230158115Sume		break;
231158115Sume	case CET_MP_READ_SESSION_REQUEST:
232158115Sume		qstate->process_func = on_mp_read_session_request_read1;
233158115Sume		break;
234158115Sume	default:
235158115Sume		TRACE_OUT(on_query_startup);
236158115Sume		return (-1);
237158115Sume	}
238158115Sume
239158115Sume	qstate->kevent_watermark = 0;
240158115Sume	TRACE_OUT(on_query_startup);
241158115Sume	return (0);
242158115Sume}
243158115Sume
244158115Sume/*
245158115Sume * on_rw_mapper is used to process multiple read/write requests during
246158115Sume * one connection session. It's never called in the beginning (on query_state
247158115Sume * creation) as it does not process the multipart requests and does not
248158115Sume * receive credentials
249158115Sume */
250158115Sumestatic int
251158115Sumeon_rw_mapper(struct query_state *qstate)
252158115Sume{
253158115Sume	ssize_t	result;
254158115Sume	int	elem_type;
255158115Sume
256158115Sume	TRACE_IN(on_rw_mapper);
257158115Sume	if (qstate->kevent_watermark == 0) {
258158115Sume		qstate->kevent_watermark = sizeof(int);
259158115Sume	} else {
260158115Sume		result = qstate->read_func(qstate, &elem_type, sizeof(int));
261158115Sume		if (result != sizeof(int)) {
262158115Sume			TRACE_OUT(on_rw_mapper);
263158115Sume			return (-1);
264158115Sume		}
265158115Sume
266158115Sume		switch (elem_type) {
267158115Sume		case CET_WRITE_REQUEST:
268158115Sume			qstate->kevent_watermark = sizeof(size_t);
269158115Sume			qstate->process_func = on_write_request_read1;
270158115Sume		break;
271158115Sume		case CET_READ_REQUEST:
272158115Sume			qstate->kevent_watermark = sizeof(size_t);
273158115Sume			qstate->process_func = on_read_request_read1;
274158115Sume		break;
275158115Sume		default:
276158115Sume			TRACE_OUT(on_rw_mapper);
277158115Sume			return (-1);
278158115Sume		break;
279158115Sume		}
280158115Sume	}
281158115Sume	TRACE_OUT(on_rw_mapper);
282158115Sume	return (0);
283158115Sume}
284158115Sume
285158115Sume/*
286158115Sume * The default query_destroy function
287158115Sume */
288158115Sumestatic void
289158115Sumeon_query_destroy(struct query_state *qstate)
290158115Sume{
291158115Sume
292158115Sume	TRACE_IN(on_query_destroy);
293158115Sume	finalize_comm_element(&qstate->response);
294158115Sume	finalize_comm_element(&qstate->request);
295158115Sume	TRACE_OUT(on_query_destroy);
296158115Sume}
297158115Sume
298158115Sume/*
299158115Sume * The functions below are used to process write requests.
300158115Sume * - on_write_request_read1 and on_write_request_read2 read the request itself
301158115Sume * - on_write_request_process processes it (if the client requests to
302158115Sume *    cache the negative result, the on_negative_write_request_process is used)
303158115Sume * - on_write_response_write1 sends the response
304158115Sume */
305158115Sumestatic int
306158115Sumeon_write_request_read1(struct query_state *qstate)
307158115Sume{
308158115Sume	struct cache_write_request	*write_request;
309158115Sume	ssize_t	result;
310158115Sume
311158115Sume	TRACE_IN(on_write_request_read1);
312158115Sume	if (qstate->kevent_watermark == 0)
313158115Sume		qstate->kevent_watermark = sizeof(size_t) * 3;
314158115Sume	else {
315158115Sume		init_comm_element(&qstate->request, CET_WRITE_REQUEST);
316158115Sume		write_request = get_cache_write_request(&qstate->request);
317158115Sume
318158115Sume		result = qstate->read_func(qstate, &write_request->entry_length,
319158115Sume	    		sizeof(size_t));
320158115Sume		result += qstate->read_func(qstate,
321158115Sume	    		&write_request->cache_key_size, sizeof(size_t));
322158115Sume		result += qstate->read_func(qstate,
323158115Sume	    		&write_request->data_size, sizeof(size_t));
324158115Sume
325158115Sume		if (result != sizeof(size_t) * 3) {
326158115Sume			TRACE_OUT(on_write_request_read1);
327158115Sume			return (-1);
328158115Sume		}
329158115Sume
330158115Sume		if (BUFSIZE_INVALID(write_request->entry_length) ||
331158115Sume			BUFSIZE_INVALID(write_request->cache_key_size) ||
332158115Sume			(BUFSIZE_INVALID(write_request->data_size) &&
333158115Sume			(write_request->data_size != 0))) {
334158115Sume			TRACE_OUT(on_write_request_read1);
335158115Sume			return (-1);
336158115Sume		}
337158115Sume
338194104Sdes		write_request->entry = calloc(1,
339158115Sume			write_request->entry_length + 1);
340158115Sume		assert(write_request->entry != NULL);
341158115Sume
342194104Sdes		write_request->cache_key = calloc(1,
343158115Sume			write_request->cache_key_size +
344158115Sume			qstate->eid_str_length);
345158115Sume		assert(write_request->cache_key != NULL);
346158115Sume		memcpy(write_request->cache_key, qstate->eid_str,
347158115Sume			qstate->eid_str_length);
348158115Sume
349158115Sume		if (write_request->data_size != 0) {
350194104Sdes			write_request->data = calloc(1,
351158115Sume				write_request->data_size);
352158115Sume			assert(write_request->data != NULL);
353158115Sume		}
354158115Sume
355158115Sume		qstate->kevent_watermark = write_request->entry_length +
356158115Sume			write_request->cache_key_size +
357158115Sume			write_request->data_size;
358158115Sume		qstate->process_func = on_write_request_read2;
359158115Sume	}
360158115Sume
361158115Sume	TRACE_OUT(on_write_request_read1);
362158115Sume	return (0);
363158115Sume}
364158115Sume
365158115Sumestatic int
366158115Sumeon_write_request_read2(struct query_state *qstate)
367158115Sume{
368158115Sume	struct cache_write_request	*write_request;
369158115Sume	ssize_t	result;
370158115Sume
371158115Sume	TRACE_IN(on_write_request_read2);
372158115Sume	write_request = get_cache_write_request(&qstate->request);
373158115Sume
374158115Sume	result = qstate->read_func(qstate, write_request->entry,
375158115Sume		write_request->entry_length);
376158115Sume	result += qstate->read_func(qstate, write_request->cache_key +
377158115Sume		qstate->eid_str_length, write_request->cache_key_size);
378158115Sume	if (write_request->data_size != 0)
379158115Sume		result += qstate->read_func(qstate, write_request->data,
380158115Sume			write_request->data_size);
381158115Sume
382194096Sdes	if (result != (ssize_t)qstate->kevent_watermark) {
383158115Sume		TRACE_OUT(on_write_request_read2);
384158115Sume		return (-1);
385158115Sume	}
386158115Sume	write_request->cache_key_size += qstate->eid_str_length;
387158115Sume
388158115Sume	qstate->kevent_watermark = 0;
389158115Sume	if (write_request->data_size != 0)
390158115Sume		qstate->process_func = on_write_request_process;
391158115Sume	else
392158115Sume	    	qstate->process_func = on_negative_write_request_process;
393158115Sume	TRACE_OUT(on_write_request_read2);
394158115Sume	return (0);
395158115Sume}
396158115Sume
397158115Sumestatic	int
398158115Sumeon_write_request_process(struct query_state *qstate)
399158115Sume{
400158115Sume	struct cache_write_request	*write_request;
401158115Sume	struct cache_write_response	*write_response;
402158115Sume	cache_entry c_entry;
403158115Sume
404158115Sume	TRACE_IN(on_write_request_process);
405158115Sume	init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
406158115Sume	write_response = get_cache_write_response(&qstate->response);
407158115Sume	write_request = get_cache_write_request(&qstate->request);
408158115Sume
409158115Sume	qstate->config_entry = configuration_find_entry(
410158115Sume		s_configuration, write_request->entry);
411158115Sume
412158115Sume	if (qstate->config_entry == NULL) {
413158115Sume		write_response->error_code = ENOENT;
414158115Sume
415158115Sume		LOG_ERR_2("write_request", "can't find configuration"
416158115Sume		    " entry '%s'. aborting request", write_request->entry);
417158115Sume		goto fin;
418158115Sume	}
419158115Sume
420158115Sume	if (qstate->config_entry->enabled == 0) {
421158115Sume		write_response->error_code = EACCES;
422158115Sume
423158115Sume		LOG_ERR_2("write_request",
424158115Sume			"configuration entry '%s' is disabled",
425158115Sume			write_request->entry);
426158115Sume		goto fin;
427158115Sume	}
428158115Sume
429158115Sume	if (qstate->config_entry->perform_actual_lookups != 0) {
430158115Sume		write_response->error_code = EOPNOTSUPP;
431158115Sume
432158115Sume		LOG_ERR_2("write_request",
433158115Sume			"entry '%s' performs lookups by itself: "
434158115Sume			"can't write to it", write_request->entry);
435158115Sume		goto fin;
436158115Sume	}
437158115Sume
438158115Sume	configuration_lock_rdlock(s_configuration);
439158115Sume	c_entry = find_cache_entry(s_cache,
440194097Sdes		qstate->config_entry->positive_cache_params.cep.entry_name);
441158115Sume	configuration_unlock(s_configuration);
442158115Sume	if (c_entry != NULL) {
443158115Sume		configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
444158115Sume		qstate->config_entry->positive_cache_entry = c_entry;
445158115Sume		write_response->error_code = cache_write(c_entry,
446158115Sume			write_request->cache_key,
447158115Sume	    		write_request->cache_key_size,
448158115Sume	    		write_request->data,
449158115Sume			write_request->data_size);
450158115Sume		configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
451158115Sume
452158115Sume		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
453158115Sume		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
454158115Sume			memcpy(&qstate->timeout,
455158115Sume				&qstate->config_entry->common_query_timeout,
456158115Sume				sizeof(struct timeval));
457158115Sume
458158115Sume	} else
459158115Sume		write_response->error_code = -1;
460158115Sume
461158115Sumefin:
462158115Sume	qstate->kevent_filter = EVFILT_WRITE;
463158115Sume	qstate->kevent_watermark = sizeof(int);
464158115Sume	qstate->process_func = on_write_response_write1;
465158115Sume
466158115Sume	TRACE_OUT(on_write_request_process);
467158115Sume	return (0);
468158115Sume}
469158115Sume
470158115Sumestatic int
471158115Sumeon_negative_write_request_process(struct query_state *qstate)
472158115Sume{
473158115Sume	struct cache_write_request	*write_request;
474158115Sume	struct cache_write_response	*write_response;
475158115Sume	cache_entry c_entry;
476158115Sume
477158115Sume	TRACE_IN(on_negative_write_request_process);
478158115Sume	init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
479158115Sume	write_response = get_cache_write_response(&qstate->response);
480158115Sume	write_request = get_cache_write_request(&qstate->request);
481158115Sume
482158115Sume	qstate->config_entry = configuration_find_entry	(
483158115Sume		s_configuration, write_request->entry);
484158115Sume
485158115Sume	if (qstate->config_entry == NULL) {
486158115Sume		write_response->error_code = ENOENT;
487158115Sume
488158115Sume		LOG_ERR_2("negative_write_request",
489158115Sume			"can't find configuration"
490158115Sume		   	" entry '%s'. aborting request", write_request->entry);
491158115Sume		goto fin;
492158115Sume	}
493158115Sume
494158115Sume	if (qstate->config_entry->enabled == 0) {
495158115Sume		write_response->error_code = EACCES;
496158115Sume
497158115Sume		LOG_ERR_2("negative_write_request",
498158115Sume			"configuration entry '%s' is disabled",
499158115Sume			write_request->entry);
500158115Sume		goto fin;
501158115Sume	}
502158115Sume
503158115Sume	if (qstate->config_entry->perform_actual_lookups != 0) {
504158115Sume		write_response->error_code = EOPNOTSUPP;
505158115Sume
506158115Sume		LOG_ERR_2("negative_write_request",
507158115Sume			"entry '%s' performs lookups by itself: "
508158115Sume			"can't write to it", write_request->entry);
509158115Sume		goto fin;
510158115Sume	} else {
511171795Sbushman#ifdef NS_NSCD_EID_CHECKING
512158115Sume		if (check_query_eids(qstate) != 0) {
513158115Sume			write_response->error_code = EPERM;
514158115Sume			goto fin;
515158115Sume		}
516158115Sume#endif
517158115Sume	}
518158115Sume
519158115Sume	configuration_lock_rdlock(s_configuration);
520158115Sume	c_entry = find_cache_entry(s_cache,
521194097Sdes		qstate->config_entry->negative_cache_params.cep.entry_name);
522158115Sume	configuration_unlock(s_configuration);
523158115Sume	if (c_entry != NULL) {
524158115Sume		configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
525158115Sume		qstate->config_entry->negative_cache_entry = c_entry;
526158115Sume		write_response->error_code = cache_write(c_entry,
527158115Sume			write_request->cache_key,
528158115Sume	    		write_request->cache_key_size,
529158115Sume	    		negative_data,
530158115Sume			sizeof(negative_data));
531158115Sume		configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
532158115Sume
533158115Sume		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
534158115Sume		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
535158115Sume			memcpy(&qstate->timeout,
536158115Sume				&qstate->config_entry->common_query_timeout,
537158115Sume				sizeof(struct timeval));
538158115Sume	} else
539158115Sume		write_response->error_code = -1;
540158115Sume
541158115Sumefin:
542158115Sume	qstate->kevent_filter = EVFILT_WRITE;
543158115Sume	qstate->kevent_watermark = sizeof(int);
544158115Sume	qstate->process_func = on_write_response_write1;
545158115Sume
546158115Sume	TRACE_OUT(on_negative_write_request_process);
547158115Sume	return (0);
548158115Sume}
549158115Sume
550158115Sumestatic int
551158115Sumeon_write_response_write1(struct query_state *qstate)
552158115Sume{
553158115Sume	struct cache_write_response	*write_response;
554158115Sume	ssize_t	result;
555158115Sume
556158115Sume	TRACE_IN(on_write_response_write1);
557158115Sume	write_response = get_cache_write_response(&qstate->response);
558158115Sume	result = qstate->write_func(qstate, &write_response->error_code,
559158115Sume		sizeof(int));
560158115Sume	if (result != sizeof(int)) {
561158115Sume		TRACE_OUT(on_write_response_write1);
562158115Sume		return (-1);
563158115Sume	}
564158115Sume
565158115Sume	finalize_comm_element(&qstate->request);
566158115Sume	finalize_comm_element(&qstate->response);
567158115Sume
568158115Sume	qstate->kevent_watermark = sizeof(int);
569158115Sume	qstate->kevent_filter = EVFILT_READ;
570158115Sume	qstate->process_func = on_rw_mapper;
571158115Sume
572158115Sume	TRACE_OUT(on_write_response_write1);
573158115Sume	return (0);
574158115Sume}
575158115Sume
576158115Sume/*
577158115Sume * The functions below are used to process read requests.
578158115Sume * - on_read_request_read1 and on_read_request_read2 read the request itself
579158115Sume * - on_read_request_process processes it
580158115Sume * - on_read_response_write1 and on_read_response_write2 send the response
581158115Sume */
582158115Sumestatic int
583158115Sumeon_read_request_read1(struct query_state *qstate)
584158115Sume{
585158115Sume	struct cache_read_request *read_request;
586158115Sume	ssize_t	result;
587158115Sume
588158115Sume	TRACE_IN(on_read_request_read1);
589158115Sume	if (qstate->kevent_watermark == 0)
590158115Sume		qstate->kevent_watermark = sizeof(size_t) * 2;
591158115Sume	else {
592158115Sume		init_comm_element(&qstate->request, CET_READ_REQUEST);
593158115Sume		read_request = get_cache_read_request(&qstate->request);
594158115Sume
595158115Sume		result = qstate->read_func(qstate,
596158115Sume	    		&read_request->entry_length, sizeof(size_t));
597158115Sume		result += qstate->read_func(qstate,
598158115Sume	    		&read_request->cache_key_size, sizeof(size_t));
599158115Sume
600158115Sume		if (result != sizeof(size_t) * 2) {
601158115Sume			TRACE_OUT(on_read_request_read1);
602158115Sume			return (-1);
603158115Sume		}
604158115Sume
605158115Sume		if (BUFSIZE_INVALID(read_request->entry_length) ||
606158115Sume			BUFSIZE_INVALID(read_request->cache_key_size)) {
607158115Sume			TRACE_OUT(on_read_request_read1);
608158115Sume			return (-1);
609158115Sume		}
610158115Sume
611194104Sdes		read_request->entry = calloc(1,
612158115Sume			read_request->entry_length + 1);
613158115Sume		assert(read_request->entry != NULL);
614158115Sume
615194104Sdes		read_request->cache_key = calloc(1,
616158115Sume			read_request->cache_key_size +
617158115Sume			qstate->eid_str_length);
618158115Sume		assert(read_request->cache_key != NULL);
619158115Sume		memcpy(read_request->cache_key, qstate->eid_str,
620158115Sume			qstate->eid_str_length);
621158115Sume
622158115Sume		qstate->kevent_watermark = read_request->entry_length +
623158115Sume			read_request->cache_key_size;
624158115Sume		qstate->process_func = on_read_request_read2;
625158115Sume	}
626158115Sume
627158115Sume	TRACE_OUT(on_read_request_read1);
628158115Sume	return (0);
629158115Sume}
630158115Sume
631158115Sumestatic int
632158115Sumeon_read_request_read2(struct query_state *qstate)
633158115Sume{
634158115Sume	struct cache_read_request	*read_request;
635158115Sume	ssize_t	result;
636158115Sume
637158115Sume	TRACE_IN(on_read_request_read2);
638158115Sume	read_request = get_cache_read_request(&qstate->request);
639158115Sume
640158115Sume	result = qstate->read_func(qstate, read_request->entry,
641158115Sume		read_request->entry_length);
642158115Sume	result += qstate->read_func(qstate,
643158115Sume		read_request->cache_key + qstate->eid_str_length,
644158115Sume		read_request->cache_key_size);
645158115Sume
646194096Sdes	if (result != (ssize_t)qstate->kevent_watermark) {
647158115Sume		TRACE_OUT(on_read_request_read2);
648158115Sume		return (-1);
649158115Sume	}
650158115Sume	read_request->cache_key_size += qstate->eid_str_length;
651158115Sume
652158115Sume	qstate->kevent_watermark = 0;
653158115Sume	qstate->process_func = on_read_request_process;
654158115Sume
655158115Sume	TRACE_OUT(on_read_request_read2);
656158115Sume	return (0);
657158115Sume}
658158115Sume
659158115Sumestatic int
660158115Sumeon_read_request_process(struct query_state *qstate)
661158115Sume{
662158115Sume	struct cache_read_request *read_request;
663158115Sume	struct cache_read_response *read_response;
664158115Sume	cache_entry	c_entry, neg_c_entry;
665158115Sume
666158115Sume	struct agent	*lookup_agent;
667158115Sume	struct common_agent *c_agent;
668158115Sume	int res;
669158115Sume
670158115Sume	TRACE_IN(on_read_request_process);
671158115Sume	init_comm_element(&qstate->response, CET_READ_RESPONSE);
672158115Sume	read_response = get_cache_read_response(&qstate->response);
673158115Sume	read_request = get_cache_read_request(&qstate->request);
674158115Sume
675158115Sume	qstate->config_entry = configuration_find_entry(
676158115Sume		s_configuration, read_request->entry);
677158115Sume	if (qstate->config_entry == NULL) {
678158115Sume		read_response->error_code = ENOENT;
679158115Sume
680158115Sume		LOG_ERR_2("read_request",
681158115Sume			"can't find configuration "
682158115Sume	    		"entry '%s'. aborting request", read_request->entry);
683158115Sume	    	goto fin;
684158115Sume	}
685158115Sume
686158115Sume	if (qstate->config_entry->enabled == 0) {
687158115Sume		read_response->error_code = EACCES;
688158115Sume
689158115Sume		LOG_ERR_2("read_request",
690158115Sume			"configuration entry '%s' is disabled",
691158115Sume			read_request->entry);
692158115Sume		goto fin;
693158115Sume	}
694158115Sume
695158115Sume	/*
696158115Sume	 * if we perform lookups by ourselves, then we don't need to separate
697158115Sume	 * cache entries by euid and egid
698158115Sume	 */
699158115Sume	if (qstate->config_entry->perform_actual_lookups != 0)
700158115Sume		memset(read_request->cache_key, 0, qstate->eid_str_length);
701158115Sume	else {
702171795Sbushman#ifdef NS_NSCD_EID_CHECKING
703158115Sume		if (check_query_eids(qstate) != 0) {
704158115Sume		/* if the lookup is not self-performing, we check for clients euid/egid */
705158115Sume			read_response->error_code = EPERM;
706158115Sume			goto fin;
707158115Sume		}
708158115Sume#endif
709158115Sume	}
710158115Sume
711158115Sume	configuration_lock_rdlock(s_configuration);
712158115Sume	c_entry = find_cache_entry(s_cache,
713194097Sdes		qstate->config_entry->positive_cache_params.cep.entry_name);
714158115Sume	neg_c_entry = find_cache_entry(s_cache,
715194097Sdes		qstate->config_entry->negative_cache_params.cep.entry_name);
716158115Sume	configuration_unlock(s_configuration);
717158115Sume	if ((c_entry != NULL) && (neg_c_entry != NULL)) {
718158115Sume		configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
719158115Sume		qstate->config_entry->positive_cache_entry = c_entry;
720158115Sume		read_response->error_code = cache_read(c_entry,
721158115Sume	    		read_request->cache_key,
722158115Sume	    		read_request->cache_key_size, NULL,
723158115Sume	    		&read_response->data_size);
724158115Sume
725158115Sume		if (read_response->error_code == -2) {
726194104Sdes			read_response->data = malloc(
727194104Sdes				read_response->data_size);
728319178Scy			assert(read_response->data != NULL);
729158115Sume			read_response->error_code = cache_read(c_entry,
730158115Sume				read_request->cache_key,
731158115Sume		    		read_request->cache_key_size,
732158115Sume		    		read_response->data,
733158115Sume		    		&read_response->data_size);
734158115Sume		}
735158115Sume		configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
736158115Sume
737158115Sume		configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
738158115Sume		qstate->config_entry->negative_cache_entry = neg_c_entry;
739158115Sume		if (read_response->error_code == -1) {
740158115Sume			read_response->error_code = cache_read(neg_c_entry,
741158115Sume				read_request->cache_key,
742158115Sume				read_request->cache_key_size, NULL,
743158115Sume				&read_response->data_size);
744158115Sume
745158115Sume			if (read_response->error_code == -2) {
746319177Scy				read_response->data = malloc(
747319177Scy					read_response->data_size);
748319178Scy				assert(read_response->data != NULL);
749319177Scy				read_response->error_code = cache_read(neg_c_entry,
750319177Scy					read_request->cache_key,
751319177Scy		    			read_request->cache_key_size,
752319177Scy		    			read_response->data,
753319177Scy		    			&read_response->data_size);
754158115Sume			}
755158115Sume		}
756158115Sume		configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
757158115Sume
758158115Sume		if ((read_response->error_code == -1) &&
759158115Sume			(qstate->config_entry->perform_actual_lookups != 0)) {
760158115Sume			free(read_response->data);
761158115Sume			read_response->data = NULL;
762158115Sume			read_response->data_size = 0;
763158115Sume
764158115Sume			lookup_agent = find_agent(s_agent_table,
765158115Sume				read_request->entry, COMMON_AGENT);
766158115Sume
767158115Sume			if ((lookup_agent != NULL) &&
768158115Sume			(lookup_agent->type == COMMON_AGENT)) {
769158115Sume				c_agent = (struct common_agent *)lookup_agent;
770158115Sume				res = c_agent->lookup_func(
771158115Sume					read_request->cache_key +
772158115Sume						qstate->eid_str_length,
773158115Sume					read_request->cache_key_size -
774158115Sume						qstate->eid_str_length,
775158115Sume					&read_response->data,
776158115Sume					&read_response->data_size);
777158115Sume
778158115Sume				if (res == NS_SUCCESS) {
779158115Sume					read_response->error_code = 0;
780158115Sume					configuration_lock_entry(
781158115Sume						qstate->config_entry,
782158115Sume						CELT_POSITIVE);
783158115Sume					cache_write(c_entry,
784158115Sume						read_request->cache_key,
785158115Sume	    					read_request->cache_key_size,
786158115Sume	    					read_response->data,
787158115Sume						read_response->data_size);
788158115Sume					configuration_unlock_entry(
789158115Sume						qstate->config_entry,
790158115Sume						CELT_POSITIVE);
791158115Sume				} else if ((res == NS_NOTFOUND) ||
792158115Sume					  (res == NS_RETURN)) {
793158115Sume					configuration_lock_entry(
794158115Sume						  qstate->config_entry,
795158115Sume						  CELT_NEGATIVE);
796158115Sume					cache_write(neg_c_entry,
797158115Sume						read_request->cache_key,
798158115Sume						read_request->cache_key_size,
799158115Sume						negative_data,
800158115Sume						sizeof(negative_data));
801158115Sume					configuration_unlock_entry(
802158115Sume						  qstate->config_entry,
803158115Sume						  CELT_NEGATIVE);
804158115Sume
805158115Sume					read_response->error_code = 0;
806158115Sume					read_response->data = NULL;
807158115Sume					read_response->data_size = 0;
808158115Sume				}
809158115Sume			}
810158115Sume		}
811158115Sume
812158115Sume		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
813158115Sume		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
814158115Sume			memcpy(&qstate->timeout,
815158115Sume				&qstate->config_entry->common_query_timeout,
816158115Sume				sizeof(struct timeval));
817158115Sume	} else
818158115Sume		read_response->error_code = -1;
819158115Sume
820158115Sumefin:
821158115Sume	qstate->kevent_filter = EVFILT_WRITE;
822158115Sume	if (read_response->error_code == 0)
823158115Sume		qstate->kevent_watermark = sizeof(int) + sizeof(size_t);
824158115Sume	else
825158115Sume		qstate->kevent_watermark = sizeof(int);
826158115Sume	qstate->process_func = on_read_response_write1;
827158115Sume
828158115Sume	TRACE_OUT(on_read_request_process);
829158115Sume	return (0);
830158115Sume}
831158115Sume
832158115Sumestatic int
833158115Sumeon_read_response_write1(struct query_state *qstate)
834158115Sume{
835158115Sume	struct cache_read_response	*read_response;
836158115Sume	ssize_t	result;
837158115Sume
838158115Sume	TRACE_IN(on_read_response_write1);
839158115Sume	read_response = get_cache_read_response(&qstate->response);
840158115Sume
841158115Sume	result = qstate->write_func(qstate, &read_response->error_code,
842158115Sume		sizeof(int));
843158115Sume
844158115Sume	if (read_response->error_code == 0) {
845158115Sume		result += qstate->write_func(qstate, &read_response->data_size,
846158115Sume			sizeof(size_t));
847194096Sdes		if (result != (ssize_t)qstate->kevent_watermark) {
848158115Sume			TRACE_OUT(on_read_response_write1);
849158115Sume			return (-1);
850158115Sume		}
851158115Sume
852158115Sume		qstate->kevent_watermark = read_response->data_size;
853158115Sume		qstate->process_func = on_read_response_write2;
854158115Sume	} else {
855194096Sdes		if (result != (ssize_t)qstate->kevent_watermark) {
856158115Sume			TRACE_OUT(on_read_response_write1);
857158115Sume			return (-1);
858158115Sume		}
859158115Sume
860158115Sume		qstate->kevent_watermark = 0;
861158115Sume		qstate->process_func = NULL;
862158115Sume	}
863158115Sume
864158115Sume	TRACE_OUT(on_read_response_write1);
865158115Sume	return (0);
866158115Sume}
867158115Sume
868158115Sumestatic int
869158115Sumeon_read_response_write2(struct query_state *qstate)
870158115Sume{
871158115Sume	struct cache_read_response	*read_response;
872158115Sume	ssize_t	result;
873158115Sume
874158115Sume	TRACE_IN(on_read_response_write2);
875158115Sume	read_response = get_cache_read_response(&qstate->response);
876158115Sume	if (read_response->data_size > 0) {
877158115Sume		result = qstate->write_func(qstate, read_response->data,
878158115Sume			read_response->data_size);
879194096Sdes		if (result != (ssize_t)qstate->kevent_watermark) {
880158115Sume			TRACE_OUT(on_read_response_write2);
881158115Sume			return (-1);
882158115Sume		}
883158115Sume	}
884158115Sume
885158115Sume	finalize_comm_element(&qstate->request);
886158115Sume	finalize_comm_element(&qstate->response);
887158115Sume
888158115Sume	qstate->kevent_watermark = sizeof(int);
889158115Sume	qstate->kevent_filter = EVFILT_READ;
890158115Sume	qstate->process_func = on_rw_mapper;
891158115Sume	TRACE_OUT(on_read_response_write2);
892158115Sume	return (0);
893158115Sume}
894158115Sume
895158115Sume/*
896158115Sume * The functions below are used to process write requests.
897158115Sume * - on_transform_request_read1 and on_transform_request_read2 read the
898158115Sume *   request itself
899158115Sume * - on_transform_request_process processes it
900158115Sume * - on_transform_response_write1 sends the response
901158115Sume */
902158115Sumestatic int
903158115Sumeon_transform_request_read1(struct query_state *qstate)
904158115Sume{
905158115Sume	struct cache_transform_request *transform_request;
906158115Sume	ssize_t	result;
907158115Sume
908158115Sume	TRACE_IN(on_transform_request_read1);
909158115Sume	if (qstate->kevent_watermark == 0)
910158115Sume		qstate->kevent_watermark = sizeof(size_t) + sizeof(int);
911158115Sume	else {
912158115Sume		init_comm_element(&qstate->request, CET_TRANSFORM_REQUEST);
913158115Sume		transform_request =
914158115Sume			get_cache_transform_request(&qstate->request);
915158115Sume
916158115Sume		result = qstate->read_func(qstate,
917158115Sume	    		&transform_request->entry_length, sizeof(size_t));
918158115Sume		result += qstate->read_func(qstate,
919158115Sume	    		&transform_request->transformation_type, sizeof(int));
920158115Sume
921158115Sume		if (result != sizeof(size_t) + sizeof(int)) {
922158115Sume			TRACE_OUT(on_transform_request_read1);
923158115Sume			return (-1);
924158115Sume		}
925158115Sume
926158115Sume		if ((transform_request->transformation_type != TT_USER) &&
927158115Sume		    (transform_request->transformation_type != TT_ALL)) {
928158115Sume			TRACE_OUT(on_transform_request_read1);
929158115Sume			return (-1);
930158115Sume		}
931158115Sume
932158115Sume		if (transform_request->entry_length != 0) {
933158115Sume			if (BUFSIZE_INVALID(transform_request->entry_length)) {
934158115Sume				TRACE_OUT(on_transform_request_read1);
935158115Sume				return (-1);
936158115Sume			}
937158115Sume
938194104Sdes			transform_request->entry = calloc(1,
939158115Sume				transform_request->entry_length + 1);
940158115Sume			assert(transform_request->entry != NULL);
941158115Sume
942158115Sume			qstate->process_func = on_transform_request_read2;
943158115Sume		} else
944158115Sume			qstate->process_func = on_transform_request_process;
945158115Sume
946158115Sume		qstate->kevent_watermark = transform_request->entry_length;
947158115Sume	}
948158115Sume
949158115Sume	TRACE_OUT(on_transform_request_read1);
950158115Sume	return (0);
951158115Sume}
952158115Sume
953158115Sumestatic int
954158115Sumeon_transform_request_read2(struct query_state *qstate)
955158115Sume{
956158115Sume	struct cache_transform_request	*transform_request;
957158115Sume	ssize_t	result;
958158115Sume
959158115Sume	TRACE_IN(on_transform_request_read2);
960158115Sume	transform_request = get_cache_transform_request(&qstate->request);
961158115Sume
962158115Sume	result = qstate->read_func(qstate, transform_request->entry,
963158115Sume		transform_request->entry_length);
964158115Sume
965194096Sdes	if (result != (ssize_t)qstate->kevent_watermark) {
966158115Sume		TRACE_OUT(on_transform_request_read2);
967158115Sume		return (-1);
968158115Sume	}
969158115Sume
970158115Sume	qstate->kevent_watermark = 0;
971158115Sume	qstate->process_func = on_transform_request_process;
972158115Sume
973158115Sume	TRACE_OUT(on_transform_request_read2);
974158115Sume	return (0);
975158115Sume}
976158115Sume
977158115Sumestatic int
978158115Sumeon_transform_request_process(struct query_state *qstate)
979158115Sume{
980158115Sume	struct cache_transform_request *transform_request;
981158115Sume	struct cache_transform_response *transform_response;
982158115Sume	struct configuration_entry *config_entry;
983158115Sume	size_t	i, size;
984158115Sume
985158115Sume	TRACE_IN(on_transform_request_process);
986158115Sume	init_comm_element(&qstate->response, CET_TRANSFORM_RESPONSE);
987158115Sume	transform_response = get_cache_transform_response(&qstate->response);
988158115Sume	transform_request = get_cache_transform_request(&qstate->request);
989158115Sume
990158115Sume	switch (transform_request->transformation_type) {
991158115Sume	case TT_USER:
992158115Sume		if (transform_request->entry == NULL) {
993158115Sume			size = configuration_get_entries_size(s_configuration);
994158115Sume			for (i = 0; i < size; ++i) {
995158115Sume			    config_entry = configuration_get_entry(
996158115Sume				s_configuration, i);
997158115Sume
998158115Sume			    if (config_entry->perform_actual_lookups == 0)
999158115Sume			    	clear_config_entry_part(config_entry,
1000158115Sume				    qstate->eid_str, qstate->eid_str_length);
1001158115Sume			}
1002158115Sume		} else {
1003158115Sume			qstate->config_entry = configuration_find_entry(
1004158115Sume				s_configuration, transform_request->entry);
1005158115Sume
1006158115Sume			if (qstate->config_entry == NULL) {
1007158115Sume				LOG_ERR_2("transform_request",
1008158115Sume					"can't find configuration"
1009158115Sume		   			" entry '%s'. aborting request",
1010158115Sume					transform_request->entry);
1011158115Sume				transform_response->error_code = -1;
1012158115Sume				goto fin;
1013158115Sume			}
1014158115Sume
1015158115Sume			if (qstate->config_entry->perform_actual_lookups != 0) {
1016158115Sume				LOG_ERR_2("transform_request",
1017158115Sume					"can't transform the cache entry %s"
1018158115Sume					", because it ised for actual lookups",
1019158115Sume					transform_request->entry);
1020158115Sume				transform_response->error_code = -1;
1021158115Sume				goto fin;
1022158115Sume			}
1023158115Sume
1024158115Sume			clear_config_entry_part(qstate->config_entry,
1025158115Sume				qstate->eid_str, qstate->eid_str_length);
1026158115Sume		}
1027158115Sume		break;
1028158115Sume	case TT_ALL:
1029158115Sume		if (qstate->euid != 0)
1030158115Sume			transform_response->error_code = -1;
1031158115Sume		else {
1032158115Sume			if (transform_request->entry == NULL) {
1033158115Sume				size = configuration_get_entries_size(
1034158115Sume					s_configuration);
1035158115Sume				for (i = 0; i < size; ++i) {
1036158115Sume				    clear_config_entry(
1037158115Sume					configuration_get_entry(
1038158115Sume						s_configuration, i));
1039158115Sume				}
1040158115Sume			} else {
1041158115Sume				qstate->config_entry = configuration_find_entry(
1042158115Sume					s_configuration,
1043158115Sume					transform_request->entry);
1044158115Sume
1045158115Sume				if (qstate->config_entry == NULL) {
1046158115Sume					LOG_ERR_2("transform_request",
1047158115Sume						"can't find configuration"
1048158115Sume		   				" entry '%s'. aborting request",
1049158115Sume						transform_request->entry);
1050158115Sume					transform_response->error_code = -1;
1051158115Sume					goto fin;
1052158115Sume				}
1053158115Sume
1054158115Sume				clear_config_entry(qstate->config_entry);
1055158115Sume			}
1056158115Sume		}
1057158115Sume		break;
1058158115Sume	default:
1059158115Sume		transform_response->error_code = -1;
1060158115Sume	}
1061158115Sume
1062158115Sumefin:
1063158115Sume	qstate->kevent_watermark = 0;
1064158115Sume	qstate->process_func = on_transform_response_write1;
1065158115Sume	TRACE_OUT(on_transform_request_process);
1066158115Sume	return (0);
1067158115Sume}
1068158115Sume
1069158115Sumestatic int
1070158115Sumeon_transform_response_write1(struct query_state *qstate)
1071158115Sume{
1072158115Sume	struct cache_transform_response	*transform_response;
1073158115Sume	ssize_t	result;
1074158115Sume
1075158115Sume	TRACE_IN(on_transform_response_write1);
1076158115Sume	transform_response = get_cache_transform_response(&qstate->response);
1077158115Sume	result = qstate->write_func(qstate, &transform_response->error_code,
1078158115Sume		sizeof(int));
1079158115Sume	if (result != sizeof(int)) {
1080158115Sume		TRACE_OUT(on_transform_response_write1);
1081158115Sume		return (-1);
1082158115Sume	}
1083158115Sume
1084158115Sume	finalize_comm_element(&qstate->request);
1085158115Sume	finalize_comm_element(&qstate->response);
1086158115Sume
1087158115Sume	qstate->kevent_watermark = 0;
1088158115Sume	qstate->process_func = NULL;
1089158115Sume	TRACE_OUT(on_transform_response_write1);
1090158115Sume	return (0);
1091158115Sume}
1092158115Sume
1093158115Sume/*
1094158115Sume * Checks if the client's euid and egid do not differ from its uid and gid.
1095158115Sume * Returns 0 on success.
1096158115Sume */
1097158115Sumeint
1098158115Sumecheck_query_eids(struct query_state *qstate)
1099158115Sume{
1100158115Sume
1101158115Sume	return ((qstate->uid != qstate->euid) || (qstate->gid != qstate->egid) ? -1 : 0);
1102158115Sume}
1103158115Sume
1104158115Sume/*
1105158115Sume * Uses the qstate fields to process an "alternate" read - when the buffer is
1106158115Sume * too large to be received during one socket read operation
1107158115Sume */
1108158115Sumessize_t
1109158115Sumequery_io_buffer_read(struct query_state *qstate, void *buf, size_t nbytes)
1110158115Sume{
1111194096Sdes	size_t remaining;
1112158115Sume	ssize_t	result;
1113158115Sume
1114158115Sume	TRACE_IN(query_io_buffer_read);
1115158115Sume	if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1116158115Sume		return (-1);
1117158115Sume
1118194096Sdes	assert(qstate->io_buffer_p <=
1119194096Sdes		qstate->io_buffer + qstate->io_buffer_size);
1120194096Sdes	remaining = qstate->io_buffer + qstate->io_buffer_size -
1121194096Sdes		qstate->io_buffer_p;
1122194096Sdes	if (nbytes < remaining)
1123158115Sume		result = nbytes;
1124158115Sume	else
1125194096Sdes		result = remaining;
1126158115Sume
1127158115Sume	memcpy(buf, qstate->io_buffer_p, result);
1128158115Sume	qstate->io_buffer_p += result;
1129158115Sume
1130194096Sdes	if (remaining == 0) {
1131158115Sume		free(qstate->io_buffer);
1132158115Sume		qstate->io_buffer = NULL;
1133158115Sume
1134158115Sume		qstate->write_func = query_socket_write;
1135158115Sume		qstate->read_func = query_socket_read;
1136158115Sume	}
1137158115Sume
1138158115Sume	TRACE_OUT(query_io_buffer_read);
1139158115Sume	return (result);
1140158115Sume}
1141158115Sume
1142158115Sume/*
1143158115Sume * Uses the qstate fields to process an "alternate" write - when the buffer is
1144158115Sume * too large to be sent during one socket write operation
1145158115Sume */
1146158115Sumessize_t
1147158115Sumequery_io_buffer_write(struct query_state *qstate, const void *buf,
1148158115Sume	size_t nbytes)
1149158115Sume{
1150194096Sdes	size_t remaining;
1151158115Sume	ssize_t	result;
1152158115Sume
1153158115Sume	TRACE_IN(query_io_buffer_write);
1154158115Sume	if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1155158115Sume		return (-1);
1156158115Sume
1157194096Sdes	assert(qstate->io_buffer_p <=
1158194096Sdes		qstate->io_buffer + qstate->io_buffer_size);
1159194096Sdes	remaining = qstate->io_buffer + qstate->io_buffer_size -
1160194096Sdes		qstate->io_buffer_p;
1161194096Sdes	if (nbytes < remaining)
1162158115Sume		result = nbytes;
1163158115Sume	else
1164194096Sdes		result = remaining;
1165158115Sume
1166158115Sume	memcpy(qstate->io_buffer_p, buf, result);
1167158115Sume	qstate->io_buffer_p += result;
1168158115Sume
1169194096Sdes	if (remaining == 0) {
1170158115Sume		qstate->use_alternate_io = 1;
1171158115Sume		qstate->io_buffer_p = qstate->io_buffer;
1172158115Sume
1173158115Sume		qstate->write_func = query_socket_write;
1174158115Sume		qstate->read_func = query_socket_read;
1175158115Sume	}
1176158115Sume
1177158115Sume	TRACE_OUT(query_io_buffer_write);
1178158115Sume	return (result);
1179158115Sume}
1180158115Sume
1181158115Sume/*
1182158115Sume * The default "read" function, which reads data directly from socket
1183158115Sume */
1184158115Sumessize_t
1185158115Sumequery_socket_read(struct query_state *qstate, void *buf, size_t nbytes)
1186158115Sume{
1187158115Sume	ssize_t	result;
1188158115Sume
1189158115Sume	TRACE_IN(query_socket_read);
1190158115Sume	if (qstate->socket_failed != 0) {
1191158115Sume		TRACE_OUT(query_socket_read);
1192158115Sume		return (-1);
1193158115Sume	}
1194158115Sume
1195158115Sume	result = read(qstate->sockfd, buf, nbytes);
1196194096Sdes	if (result < 0 || (size_t)result < nbytes)
1197158115Sume		qstate->socket_failed = 1;
1198158115Sume
1199158115Sume	TRACE_OUT(query_socket_read);
1200158115Sume	return (result);
1201158115Sume}
1202158115Sume
1203158115Sume/*
1204158115Sume * The default "write" function, which writes data directly to socket
1205158115Sume */
1206158115Sumessize_t
1207158115Sumequery_socket_write(struct query_state *qstate, const void *buf, size_t nbytes)
1208158115Sume{
1209158115Sume	ssize_t	result;
1210158115Sume
1211158115Sume	TRACE_IN(query_socket_write);
1212158115Sume	if (qstate->socket_failed != 0) {
1213158115Sume		TRACE_OUT(query_socket_write);
1214158115Sume		return (-1);
1215158115Sume	}
1216158115Sume
1217158115Sume	result = write(qstate->sockfd, buf, nbytes);
1218194096Sdes	if (result < 0 || (size_t)result < nbytes)
1219158115Sume		qstate->socket_failed = 1;
1220158115Sume
1221158115Sume	TRACE_OUT(query_socket_write);
1222158115Sume	return (result);
1223158115Sume}
1224158115Sume
1225158115Sume/*
1226158115Sume * Initializes the query_state structure by filling it with the default values.
1227158115Sume */
1228158115Sumestruct query_state *
1229158115Sumeinit_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t egid)
1230158115Sume{
1231158115Sume	struct query_state	*retval;
1232158115Sume
1233158115Sume	TRACE_IN(init_query_state);
1234194104Sdes	retval = calloc(1, sizeof(*retval));
1235158115Sume	assert(retval != NULL);
1236158115Sume
1237158115Sume	retval->sockfd = sockfd;
1238158115Sume	retval->kevent_filter = EVFILT_READ;
1239158115Sume	retval->kevent_watermark = kevent_watermark;
1240158115Sume
1241158115Sume	retval->euid = euid;
1242158115Sume	retval->egid = egid;
1243158115Sume	retval->uid = retval->gid = -1;
1244158115Sume
1245158115Sume	if (asprintf(&retval->eid_str, "%d_%d_", retval->euid,
1246158115Sume		retval->egid) == -1) {
1247158115Sume		free(retval);
1248158115Sume		return (NULL);
1249158115Sume	}
1250158115Sume	retval->eid_str_length = strlen(retval->eid_str);
1251158115Sume
1252158115Sume	init_comm_element(&retval->request, CET_UNDEFINED);
1253158115Sume	init_comm_element(&retval->response, CET_UNDEFINED);
1254158115Sume	retval->process_func = on_query_startup;
1255158115Sume	retval->destroy_func = on_query_destroy;
1256158115Sume
1257158115Sume	retval->write_func = query_socket_write;
1258158115Sume	retval->read_func = query_socket_read;
1259158115Sume
1260158115Sume	get_time_func(&retval->creation_time);
1261272668Sjhb	retval->timeout.tv_sec = s_configuration->query_timeout;
1262272668Sjhb	retval->timeout.tv_usec = 0;
1263158115Sume
1264158115Sume	TRACE_OUT(init_query_state);
1265158115Sume	return (retval);
1266158115Sume}
1267158115Sume
1268158115Sumevoid
1269158115Sumedestroy_query_state(struct query_state *qstate)
1270158115Sume{
1271158115Sume
1272158115Sume	TRACE_IN(destroy_query_state);
1273158115Sume	if (qstate->eid_str != NULL)
1274158115Sume	    free(qstate->eid_str);
1275158115Sume
1276158115Sume	if (qstate->io_buffer != NULL)
1277158115Sume		free(qstate->io_buffer);
1278158115Sume
1279158115Sume	qstate->destroy_func(qstate);
1280158115Sume	free(qstate);
1281158115Sume	TRACE_OUT(destroy_query_state);
1282158115Sume}
1283