nata - properly teardown interrupts on ENXIO
[dragonfly.git] / usr.sbin / nscd / query.c
blobf317136ed880910005f5a82a5b52990eb4ac4e43
1 /*-
2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 * $FreeBSD: src/usr.sbin/nscd/query.c,v 1.5 2008/10/12 00:44:27 delphij Exp $
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/time.h>
32 #include <sys/event.h>
33 #include <sys/uio.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <nsswitch.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include "config.h"
41 #include "debug.h"
42 #include "query.h"
43 #include "log.h"
44 #include "mp_ws_query.h"
45 #include "mp_rs_query.h"
46 #include "singletons.h"
48 static const char negative_data[1] = { 0 };
50 extern void get_time_func(struct timeval *);
52 static void clear_config_entry(struct configuration_entry *);
53 static void clear_config_entry_part(struct configuration_entry *,
54 const char *, size_t);
56 static int on_query_startup(struct query_state *);
57 static void on_query_destroy(struct query_state *);
59 static int on_read_request_read1(struct query_state *);
60 static int on_read_request_read2(struct query_state *);
61 static int on_read_request_process(struct query_state *);
62 static int on_read_response_write1(struct query_state *);
63 static int on_read_response_write2(struct query_state *);
65 static int on_rw_mapper(struct query_state *);
67 static int on_transform_request_read1(struct query_state *);
68 static int on_transform_request_read2(struct query_state *);
69 static int on_transform_request_process(struct query_state *);
70 static int on_transform_response_write1(struct query_state *);
72 static int on_write_request_read1(struct query_state *);
73 static int on_write_request_read2(struct query_state *);
74 static int on_negative_write_request_process(struct query_state *);
75 static int on_write_request_process(struct query_state *);
76 static int on_write_response_write1(struct query_state *);
79 * Clears the specified configuration entry (clears the cache for positive and
80 * and negative entries) and also for all multipart entries.
82 static void
83 clear_config_entry(struct configuration_entry *config_entry)
85 size_t i;
87 TRACE_IN(clear_config_entry);
88 configuration_lock_entry(config_entry, CELT_POSITIVE);
89 if (config_entry->positive_cache_entry != NULL)
90 transform_cache_entry(
91 config_entry->positive_cache_entry,
92 CTT_CLEAR);
93 configuration_unlock_entry(config_entry, CELT_POSITIVE);
95 configuration_lock_entry(config_entry, CELT_NEGATIVE);
96 if (config_entry->negative_cache_entry != NULL)
97 transform_cache_entry(
98 config_entry->negative_cache_entry,
99 CTT_CLEAR);
100 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
102 configuration_lock_entry(config_entry, CELT_MULTIPART);
103 for (i = 0; i < config_entry->mp_cache_entries_size; ++i)
104 transform_cache_entry(
105 config_entry->mp_cache_entries[i],
106 CTT_CLEAR);
107 configuration_unlock_entry(config_entry, CELT_MULTIPART);
109 TRACE_OUT(clear_config_entry);
113 * Clears the specified configuration entry by deleting only the elements,
114 * that are owned by the user with specified eid_str.
116 static void
117 clear_config_entry_part(struct configuration_entry *config_entry,
118 const char *eid_str, size_t eid_str_length)
120 cache_entry *start, *finish, *mp_entry;
121 TRACE_IN(clear_config_entry_part);
122 configuration_lock_entry(config_entry, CELT_POSITIVE);
123 if (config_entry->positive_cache_entry != NULL)
124 transform_cache_entry_part(
125 config_entry->positive_cache_entry,
126 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
127 configuration_unlock_entry(config_entry, CELT_POSITIVE);
129 configuration_lock_entry(config_entry, CELT_NEGATIVE);
130 if (config_entry->negative_cache_entry != NULL)
131 transform_cache_entry_part(
132 config_entry->negative_cache_entry,
133 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
134 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
136 configuration_lock_entry(config_entry, CELT_MULTIPART);
137 if (configuration_entry_find_mp_cache_entries(config_entry,
138 eid_str, &start, &finish) == 0) {
139 for (mp_entry = start; mp_entry != finish; ++mp_entry)
140 transform_cache_entry(*mp_entry, CTT_CLEAR);
142 configuration_unlock_entry(config_entry, CELT_MULTIPART);
144 TRACE_OUT(clear_config_entry_part);
148 * This function is assigned to the query_state structue on its creation.
149 * It's main purpose is to receive credentials from the client.
151 static int
152 on_query_startup(struct query_state *qstate)
154 struct msghdr cred_hdr;
155 struct iovec iov;
156 struct cmsgcred *cred;
157 int elem_type;
159 struct {
160 struct cmsghdr hdr;
161 char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
162 } cmsg;
164 TRACE_IN(on_query_startup);
165 assert(qstate != NULL);
167 memset(&cred_hdr, 0, sizeof(struct msghdr));
168 cred_hdr.msg_iov = &iov;
169 cred_hdr.msg_iovlen = 1;
170 cred_hdr.msg_control = (caddr_t)&cmsg;
171 cred_hdr.msg_controllen = CMSG_LEN(sizeof(struct cmsgcred));
173 memset(&iov, 0, sizeof(struct iovec));
174 iov.iov_base = &elem_type;
175 iov.iov_len = sizeof(int);
177 if (recvmsg(qstate->sockfd, &cred_hdr, 0) == -1) {
178 TRACE_OUT(on_query_startup);
179 return (-1);
182 if (cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(struct cmsgcred))
183 || cmsg.hdr.cmsg_level != SOL_SOCKET
184 || cmsg.hdr.cmsg_type != SCM_CREDS) {
185 TRACE_OUT(on_query_startup);
186 return (-1);
189 cred = (struct cmsgcred *)CMSG_DATA(&cmsg);
190 qstate->uid = cred->cmcred_uid;
191 qstate->gid = cred->cmcred_gid;
193 #if defined(NS_NSCD_EID_CHECKING) || defined(NS_STRICT_NSCD_EID_CHECKING)
195 * This check is probably a bit redundant - per-user cache is always separated
196 * by the euid/egid pair
198 if (check_query_eids(qstate) != 0) {
199 #ifdef NS_STRICT_NSCD_EID_CHECKING
200 TRACE_OUT(on_query_startup);
201 return (-1);
202 #else
203 if ((elem_type != CET_READ_REQUEST) &&
204 (elem_type != CET_MP_READ_SESSION_REQUEST) &&
205 (elem_type != CET_WRITE_REQUEST) &&
206 (elem_type != CET_MP_WRITE_SESSION_REQUEST)) {
207 TRACE_OUT(on_query_startup);
208 return (-1);
210 #endif
212 #endif
214 switch (elem_type) {
215 case CET_WRITE_REQUEST:
216 qstate->process_func = on_write_request_read1;
217 break;
218 case CET_READ_REQUEST:
219 qstate->process_func = on_read_request_read1;
220 break;
221 case CET_TRANSFORM_REQUEST:
222 qstate->process_func = on_transform_request_read1;
223 break;
224 case CET_MP_WRITE_SESSION_REQUEST:
225 qstate->process_func = on_mp_write_session_request_read1;
226 break;
227 case CET_MP_READ_SESSION_REQUEST:
228 qstate->process_func = on_mp_read_session_request_read1;
229 break;
230 default:
231 TRACE_OUT(on_query_startup);
232 return (-1);
235 qstate->kevent_watermark = 0;
236 TRACE_OUT(on_query_startup);
237 return (0);
241 * on_rw_mapper is used to process multiple read/write requests during
242 * one connection session. It's never called in the beginning (on query_state
243 * creation) as it does not process the multipart requests and does not
244 * receive credentials
246 static int
247 on_rw_mapper(struct query_state *qstate)
249 ssize_t result;
250 int elem_type;
252 TRACE_IN(on_rw_mapper);
253 if (qstate->kevent_watermark == 0) {
254 qstate->kevent_watermark = sizeof(int);
255 } else {
256 result = qstate->read_func(qstate, &elem_type, sizeof(int));
257 if (result != sizeof(int)) {
258 TRACE_OUT(on_rw_mapper);
259 return (-1);
262 switch (elem_type) {
263 case CET_WRITE_REQUEST:
264 qstate->kevent_watermark = sizeof(size_t);
265 qstate->process_func = on_write_request_read1;
266 break;
267 case CET_READ_REQUEST:
268 qstate->kevent_watermark = sizeof(size_t);
269 qstate->process_func = on_read_request_read1;
270 break;
271 default:
272 TRACE_OUT(on_rw_mapper);
273 return (-1);
274 break;
277 TRACE_OUT(on_rw_mapper);
278 return (0);
282 * The default query_destroy function
284 static void
285 on_query_destroy(struct query_state *qstate)
288 TRACE_IN(on_query_destroy);
289 finalize_comm_element(&qstate->response);
290 finalize_comm_element(&qstate->request);
291 TRACE_OUT(on_query_destroy);
295 * The functions below are used to process write requests.
296 * - on_write_request_read1 and on_write_request_read2 read the request itself
297 * - on_write_request_process processes it (if the client requests to
298 * cache the negative result, the on_negative_write_request_process is used)
299 * - on_write_response_write1 sends the response
301 static int
302 on_write_request_read1(struct query_state *qstate)
304 struct cache_write_request *write_request;
305 ssize_t result;
307 TRACE_IN(on_write_request_read1);
308 if (qstate->kevent_watermark == 0)
309 qstate->kevent_watermark = sizeof(size_t) * 3;
310 else {
311 init_comm_element(&qstate->request, CET_WRITE_REQUEST);
312 write_request = get_cache_write_request(&qstate->request);
314 result = qstate->read_func(qstate, &write_request->entry_length,
315 sizeof(size_t));
316 result += qstate->read_func(qstate,
317 &write_request->cache_key_size, sizeof(size_t));
318 result += qstate->read_func(qstate,
319 &write_request->data_size, sizeof(size_t));
321 if (result != sizeof(size_t) * 3) {
322 TRACE_OUT(on_write_request_read1);
323 return (-1);
326 if (BUFSIZE_INVALID(write_request->entry_length) ||
327 BUFSIZE_INVALID(write_request->cache_key_size) ||
328 (BUFSIZE_INVALID(write_request->data_size) &&
329 (write_request->data_size != 0))) {
330 TRACE_OUT(on_write_request_read1);
331 return (-1);
334 write_request->entry = (char *)calloc(1,
335 write_request->entry_length + 1);
336 assert(write_request->entry != NULL);
338 write_request->cache_key = (char *)calloc(1,
339 write_request->cache_key_size +
340 qstate->eid_str_length);
341 assert(write_request->cache_key != NULL);
342 memcpy(write_request->cache_key, qstate->eid_str,
343 qstate->eid_str_length);
345 if (write_request->data_size != 0) {
346 write_request->data = (char *)calloc(1,
347 write_request->data_size);
348 assert(write_request->data != NULL);
351 qstate->kevent_watermark = write_request->entry_length +
352 write_request->cache_key_size +
353 write_request->data_size;
354 qstate->process_func = on_write_request_read2;
357 TRACE_OUT(on_write_request_read1);
358 return (0);
361 static int
362 on_write_request_read2(struct query_state *qstate)
364 struct cache_write_request *write_request;
365 ssize_t result;
367 TRACE_IN(on_write_request_read2);
368 write_request = get_cache_write_request(&qstate->request);
370 result = qstate->read_func(qstate, write_request->entry,
371 write_request->entry_length);
372 result += qstate->read_func(qstate, write_request->cache_key +
373 qstate->eid_str_length, write_request->cache_key_size);
374 if (write_request->data_size != 0)
375 result += qstate->read_func(qstate, write_request->data,
376 write_request->data_size);
378 if (result != qstate->kevent_watermark) {
379 TRACE_OUT(on_write_request_read2);
380 return (-1);
382 write_request->cache_key_size += qstate->eid_str_length;
384 qstate->kevent_watermark = 0;
385 if (write_request->data_size != 0)
386 qstate->process_func = on_write_request_process;
387 else
388 qstate->process_func = on_negative_write_request_process;
389 TRACE_OUT(on_write_request_read2);
390 return (0);
393 static int
394 on_write_request_process(struct query_state *qstate)
396 struct cache_write_request *write_request;
397 struct cache_write_response *write_response;
398 cache_entry c_entry;
400 TRACE_IN(on_write_request_process);
401 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
402 write_response = get_cache_write_response(&qstate->response);
403 write_request = get_cache_write_request(&qstate->request);
405 qstate->config_entry = configuration_find_entry(
406 s_configuration, write_request->entry);
408 if (qstate->config_entry == NULL) {
409 write_response->error_code = ENOENT;
411 LOG_ERR_2("write_request", "can't find configuration"
412 " entry '%s'. aborting request", write_request->entry);
413 goto fin;
416 if (qstate->config_entry->enabled == 0) {
417 write_response->error_code = EACCES;
419 LOG_ERR_2("write_request",
420 "configuration entry '%s' is disabled",
421 write_request->entry);
422 goto fin;
425 if (qstate->config_entry->perform_actual_lookups != 0) {
426 write_response->error_code = EOPNOTSUPP;
428 LOG_ERR_2("write_request",
429 "entry '%s' performs lookups by itself: "
430 "can't write to it", write_request->entry);
431 goto fin;
434 configuration_lock_rdlock(s_configuration);
435 c_entry = find_cache_entry(s_cache,
436 qstate->config_entry->positive_cache_params.entry_name);
437 configuration_unlock(s_configuration);
438 if (c_entry != NULL) {
439 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
440 qstate->config_entry->positive_cache_entry = c_entry;
441 write_response->error_code = cache_write(c_entry,
442 write_request->cache_key,
443 write_request->cache_key_size,
444 write_request->data,
445 write_request->data_size);
446 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
448 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
449 (qstate->config_entry->common_query_timeout.tv_usec != 0))
450 memcpy(&qstate->timeout,
451 &qstate->config_entry->common_query_timeout,
452 sizeof(struct timeval));
454 } else
455 write_response->error_code = -1;
457 fin:
458 qstate->kevent_filter = EVFILT_WRITE;
459 qstate->kevent_watermark = sizeof(int);
460 qstate->process_func = on_write_response_write1;
462 TRACE_OUT(on_write_request_process);
463 return (0);
466 static int
467 on_negative_write_request_process(struct query_state *qstate)
469 struct cache_write_request *write_request;
470 struct cache_write_response *write_response;
471 cache_entry c_entry;
473 TRACE_IN(on_negative_write_request_process);
474 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
475 write_response = get_cache_write_response(&qstate->response);
476 write_request = get_cache_write_request(&qstate->request);
478 qstate->config_entry = configuration_find_entry(
479 s_configuration, write_request->entry);
481 if (qstate->config_entry == NULL) {
482 write_response->error_code = ENOENT;
484 LOG_ERR_2("negative_write_request",
485 "can't find configuration"
486 " entry '%s'. aborting request", write_request->entry);
487 goto fin;
490 if (qstate->config_entry->enabled == 0) {
491 write_response->error_code = EACCES;
493 LOG_ERR_2("negative_write_request",
494 "configuration entry '%s' is disabled",
495 write_request->entry);
496 goto fin;
499 if (qstate->config_entry->perform_actual_lookups != 0) {
500 write_response->error_code = EOPNOTSUPP;
502 LOG_ERR_2("negative_write_request",
503 "entry '%s' performs lookups by itself: "
504 "can't write to it", write_request->entry);
505 goto fin;
506 } else {
507 #ifdef NS_NSCD_EID_CHECKING
508 if (check_query_eids(qstate) != 0) {
509 write_response->error_code = EPERM;
510 goto fin;
512 #endif
515 configuration_lock_rdlock(s_configuration);
516 c_entry = find_cache_entry(s_cache,
517 qstate->config_entry->negative_cache_params.entry_name);
518 configuration_unlock(s_configuration);
519 if (c_entry != NULL) {
520 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
521 qstate->config_entry->negative_cache_entry = c_entry;
522 write_response->error_code = cache_write(c_entry,
523 write_request->cache_key,
524 write_request->cache_key_size,
525 negative_data,
526 sizeof(negative_data));
527 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
529 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
530 (qstate->config_entry->common_query_timeout.tv_usec != 0))
531 memcpy(&qstate->timeout,
532 &qstate->config_entry->common_query_timeout,
533 sizeof(struct timeval));
534 } else
535 write_response->error_code = -1;
537 fin:
538 qstate->kevent_filter = EVFILT_WRITE;
539 qstate->kevent_watermark = sizeof(int);
540 qstate->process_func = on_write_response_write1;
542 TRACE_OUT(on_negative_write_request_process);
543 return (0);
546 static int
547 on_write_response_write1(struct query_state *qstate)
549 struct cache_write_response *write_response;
550 ssize_t result;
552 TRACE_IN(on_write_response_write1);
553 write_response = get_cache_write_response(&qstate->response);
554 result = qstate->write_func(qstate, &write_response->error_code,
555 sizeof(int));
556 if (result != sizeof(int)) {
557 TRACE_OUT(on_write_response_write1);
558 return (-1);
561 finalize_comm_element(&qstate->request);
562 finalize_comm_element(&qstate->response);
564 qstate->kevent_watermark = sizeof(int);
565 qstate->kevent_filter = EVFILT_READ;
566 qstate->process_func = on_rw_mapper;
568 TRACE_OUT(on_write_response_write1);
569 return (0);
573 * The functions below are used to process read requests.
574 * - on_read_request_read1 and on_read_request_read2 read the request itself
575 * - on_read_request_process processes it
576 * - on_read_response_write1 and on_read_response_write2 send the response
578 static int
579 on_read_request_read1(struct query_state *qstate)
581 struct cache_read_request *read_request;
582 ssize_t result;
584 TRACE_IN(on_read_request_read1);
585 if (qstate->kevent_watermark == 0)
586 qstate->kevent_watermark = sizeof(size_t) * 2;
587 else {
588 init_comm_element(&qstate->request, CET_READ_REQUEST);
589 read_request = get_cache_read_request(&qstate->request);
591 result = qstate->read_func(qstate,
592 &read_request->entry_length, sizeof(size_t));
593 result += qstate->read_func(qstate,
594 &read_request->cache_key_size, sizeof(size_t));
596 if (result != sizeof(size_t) * 2) {
597 TRACE_OUT(on_read_request_read1);
598 return (-1);
601 if (BUFSIZE_INVALID(read_request->entry_length) ||
602 BUFSIZE_INVALID(read_request->cache_key_size)) {
603 TRACE_OUT(on_read_request_read1);
604 return (-1);
607 read_request->entry = (char *)calloc(1,
608 read_request->entry_length + 1);
609 assert(read_request->entry != NULL);
611 read_request->cache_key = (char *)calloc(1,
612 read_request->cache_key_size +
613 qstate->eid_str_length);
614 assert(read_request->cache_key != NULL);
615 memcpy(read_request->cache_key, qstate->eid_str,
616 qstate->eid_str_length);
618 qstate->kevent_watermark = read_request->entry_length +
619 read_request->cache_key_size;
620 qstate->process_func = on_read_request_read2;
623 TRACE_OUT(on_read_request_read1);
624 return (0);
627 static int
628 on_read_request_read2(struct query_state *qstate)
630 struct cache_read_request *read_request;
631 ssize_t result;
633 TRACE_IN(on_read_request_read2);
634 read_request = get_cache_read_request(&qstate->request);
636 result = qstate->read_func(qstate, read_request->entry,
637 read_request->entry_length);
638 result += qstate->read_func(qstate,
639 read_request->cache_key + qstate->eid_str_length,
640 read_request->cache_key_size);
642 if (result != qstate->kevent_watermark) {
643 TRACE_OUT(on_read_request_read2);
644 return (-1);
646 read_request->cache_key_size += qstate->eid_str_length;
648 qstate->kevent_watermark = 0;
649 qstate->process_func = on_read_request_process;
651 TRACE_OUT(on_read_request_read2);
652 return (0);
655 static int
656 on_read_request_process(struct query_state *qstate)
658 struct cache_read_request *read_request;
659 struct cache_read_response *read_response;
660 cache_entry c_entry, neg_c_entry;
662 struct agent *lookup_agent;
663 struct common_agent *c_agent;
664 int res;
666 TRACE_IN(on_read_request_process);
667 init_comm_element(&qstate->response, CET_READ_RESPONSE);
668 read_response = get_cache_read_response(&qstate->response);
669 read_request = get_cache_read_request(&qstate->request);
671 qstate->config_entry = configuration_find_entry(
672 s_configuration, read_request->entry);
673 if (qstate->config_entry == NULL) {
674 read_response->error_code = ENOENT;
676 LOG_ERR_2("read_request",
677 "can't find configuration "
678 "entry '%s'. aborting request", read_request->entry);
679 goto fin;
682 if (qstate->config_entry->enabled == 0) {
683 read_response->error_code = EACCES;
685 LOG_ERR_2("read_request",
686 "configuration entry '%s' is disabled",
687 read_request->entry);
688 goto fin;
692 * if we perform lookups by ourselves, then we don't need to separate
693 * cache entries by euid and egid
695 if (qstate->config_entry->perform_actual_lookups != 0)
696 memset(read_request->cache_key, 0, qstate->eid_str_length);
697 else {
698 #ifdef NS_NSCD_EID_CHECKING
699 if (check_query_eids(qstate) != 0) {
700 /* if the lookup is not self-performing, we check for clients euid/egid */
701 read_response->error_code = EPERM;
702 goto fin;
704 #endif
707 configuration_lock_rdlock(s_configuration);
708 c_entry = find_cache_entry(s_cache,
709 qstate->config_entry->positive_cache_params.entry_name);
710 neg_c_entry = find_cache_entry(s_cache,
711 qstate->config_entry->negative_cache_params.entry_name);
712 configuration_unlock(s_configuration);
713 if ((c_entry != NULL) && (neg_c_entry != NULL)) {
714 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
715 qstate->config_entry->positive_cache_entry = c_entry;
716 read_response->error_code = cache_read(c_entry,
717 read_request->cache_key,
718 read_request->cache_key_size, NULL,
719 &read_response->data_size);
721 if (read_response->error_code == -2) {
722 read_response->data = (char *)malloc(
723 read_response->data_size);
724 assert(read_response != NULL);
725 read_response->error_code = cache_read(c_entry,
726 read_request->cache_key,
727 read_request->cache_key_size,
728 read_response->data,
729 &read_response->data_size);
731 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
733 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
734 qstate->config_entry->negative_cache_entry = neg_c_entry;
735 if (read_response->error_code == -1) {
736 read_response->error_code = cache_read(neg_c_entry,
737 read_request->cache_key,
738 read_request->cache_key_size, NULL,
739 &read_response->data_size);
741 if (read_response->error_code == -2) {
742 read_response->error_code = 0;
743 read_response->data = NULL;
744 read_response->data_size = 0;
747 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
749 if ((read_response->error_code == -1) &&
750 (qstate->config_entry->perform_actual_lookups != 0)) {
751 free(read_response->data);
752 read_response->data = NULL;
753 read_response->data_size = 0;
755 lookup_agent = find_agent(s_agent_table,
756 read_request->entry, COMMON_AGENT);
758 if ((lookup_agent != NULL) &&
759 (lookup_agent->type == COMMON_AGENT)) {
760 c_agent = (struct common_agent *)lookup_agent;
761 res = c_agent->lookup_func(
762 read_request->cache_key +
763 qstate->eid_str_length,
764 read_request->cache_key_size -
765 qstate->eid_str_length,
766 &read_response->data,
767 &read_response->data_size);
769 if (res == NS_SUCCESS) {
770 read_response->error_code = 0;
771 configuration_lock_entry(
772 qstate->config_entry,
773 CELT_POSITIVE);
774 cache_write(c_entry,
775 read_request->cache_key,
776 read_request->cache_key_size,
777 read_response->data,
778 read_response->data_size);
779 configuration_unlock_entry(
780 qstate->config_entry,
781 CELT_POSITIVE);
782 } else if ((res == NS_NOTFOUND) ||
783 (res == NS_RETURN)) {
784 configuration_lock_entry(
785 qstate->config_entry,
786 CELT_NEGATIVE);
787 cache_write(neg_c_entry,
788 read_request->cache_key,
789 read_request->cache_key_size,
790 negative_data,
791 sizeof(negative_data));
792 configuration_unlock_entry(
793 qstate->config_entry,
794 CELT_NEGATIVE);
796 read_response->error_code = 0;
797 read_response->data = NULL;
798 read_response->data_size = 0;
803 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
804 (qstate->config_entry->common_query_timeout.tv_usec != 0))
805 memcpy(&qstate->timeout,
806 &qstate->config_entry->common_query_timeout,
807 sizeof(struct timeval));
808 } else
809 read_response->error_code = -1;
811 fin:
812 qstate->kevent_filter = EVFILT_WRITE;
813 if (read_response->error_code == 0)
814 qstate->kevent_watermark = sizeof(int) + sizeof(size_t);
815 else
816 qstate->kevent_watermark = sizeof(int);
817 qstate->process_func = on_read_response_write1;
819 TRACE_OUT(on_read_request_process);
820 return (0);
823 static int
824 on_read_response_write1(struct query_state *qstate)
826 struct cache_read_response *read_response;
827 ssize_t result;
829 TRACE_IN(on_read_response_write1);
830 read_response = get_cache_read_response(&qstate->response);
832 result = qstate->write_func(qstate, &read_response->error_code,
833 sizeof(int));
835 if (read_response->error_code == 0) {
836 result += qstate->write_func(qstate, &read_response->data_size,
837 sizeof(size_t));
838 if (result != qstate->kevent_watermark) {
839 TRACE_OUT(on_read_response_write1);
840 return (-1);
843 qstate->kevent_watermark = read_response->data_size;
844 qstate->process_func = on_read_response_write2;
845 } else {
846 if (result != qstate->kevent_watermark) {
847 TRACE_OUT(on_read_response_write1);
848 return (-1);
851 qstate->kevent_watermark = 0;
852 qstate->process_func = NULL;
855 TRACE_OUT(on_read_response_write1);
856 return (0);
859 static int
860 on_read_response_write2(struct query_state *qstate)
862 struct cache_read_response *read_response;
863 ssize_t result;
865 TRACE_IN(on_read_response_write2);
866 read_response = get_cache_read_response(&qstate->response);
867 if (read_response->data_size > 0) {
868 result = qstate->write_func(qstate, read_response->data,
869 read_response->data_size);
870 if (result != qstate->kevent_watermark) {
871 TRACE_OUT(on_read_response_write2);
872 return (-1);
876 finalize_comm_element(&qstate->request);
877 finalize_comm_element(&qstate->response);
879 qstate->kevent_watermark = sizeof(int);
880 qstate->kevent_filter = EVFILT_READ;
881 qstate->process_func = on_rw_mapper;
882 TRACE_OUT(on_read_response_write2);
883 return (0);
887 * The functions below are used to process write requests.
888 * - on_transform_request_read1 and on_transform_request_read2 read the
889 * request itself
890 * - on_transform_request_process processes it
891 * - on_transform_response_write1 sends the response
893 static int
894 on_transform_request_read1(struct query_state *qstate)
896 struct cache_transform_request *transform_request;
897 ssize_t result;
899 TRACE_IN(on_transform_request_read1);
900 if (qstate->kevent_watermark == 0)
901 qstate->kevent_watermark = sizeof(size_t) + sizeof(int);
902 else {
903 init_comm_element(&qstate->request, CET_TRANSFORM_REQUEST);
904 transform_request =
905 get_cache_transform_request(&qstate->request);
907 result = qstate->read_func(qstate,
908 &transform_request->entry_length, sizeof(size_t));
909 result += qstate->read_func(qstate,
910 &transform_request->transformation_type, sizeof(int));
912 if (result != sizeof(size_t) + sizeof(int)) {
913 TRACE_OUT(on_transform_request_read1);
914 return (-1);
917 if ((transform_request->transformation_type != TT_USER) &&
918 (transform_request->transformation_type != TT_ALL)) {
919 TRACE_OUT(on_transform_request_read1);
920 return (-1);
923 if (transform_request->entry_length != 0) {
924 if (BUFSIZE_INVALID(transform_request->entry_length)) {
925 TRACE_OUT(on_transform_request_read1);
926 return (-1);
929 transform_request->entry = (char *)calloc(1,
930 transform_request->entry_length + 1);
931 assert(transform_request->entry != NULL);
933 qstate->process_func = on_transform_request_read2;
934 } else
935 qstate->process_func = on_transform_request_process;
937 qstate->kevent_watermark = transform_request->entry_length;
940 TRACE_OUT(on_transform_request_read1);
941 return (0);
944 static int
945 on_transform_request_read2(struct query_state *qstate)
947 struct cache_transform_request *transform_request;
948 ssize_t result;
950 TRACE_IN(on_transform_request_read2);
951 transform_request = get_cache_transform_request(&qstate->request);
953 result = qstate->read_func(qstate, transform_request->entry,
954 transform_request->entry_length);
956 if (result != qstate->kevent_watermark) {
957 TRACE_OUT(on_transform_request_read2);
958 return (-1);
961 qstate->kevent_watermark = 0;
962 qstate->process_func = on_transform_request_process;
964 TRACE_OUT(on_transform_request_read2);
965 return (0);
968 static int
969 on_transform_request_process(struct query_state *qstate)
971 struct cache_transform_request *transform_request;
972 struct cache_transform_response *transform_response;
973 struct configuration_entry *config_entry;
974 size_t i, size;
976 TRACE_IN(on_transform_request_process);
977 init_comm_element(&qstate->response, CET_TRANSFORM_RESPONSE);
978 transform_response = get_cache_transform_response(&qstate->response);
979 transform_request = get_cache_transform_request(&qstate->request);
981 switch (transform_request->transformation_type) {
982 case TT_USER:
983 if (transform_request->entry == NULL) {
984 size = configuration_get_entries_size(s_configuration);
985 for (i = 0; i < size; ++i) {
986 config_entry = configuration_get_entry(
987 s_configuration, i);
989 if (config_entry->perform_actual_lookups == 0)
990 clear_config_entry_part(config_entry,
991 qstate->eid_str, qstate->eid_str_length);
993 } else {
994 qstate->config_entry = configuration_find_entry(
995 s_configuration, transform_request->entry);
997 if (qstate->config_entry == NULL) {
998 LOG_ERR_2("transform_request",
999 "can't find configuration"
1000 " entry '%s'. aborting request",
1001 transform_request->entry);
1002 transform_response->error_code = -1;
1003 goto fin;
1006 if (qstate->config_entry->perform_actual_lookups != 0) {
1007 LOG_ERR_2("transform_request",
1008 "can't transform the cache entry %s"
1009 ", because it ised for actual lookups",
1010 transform_request->entry);
1011 transform_response->error_code = -1;
1012 goto fin;
1015 clear_config_entry_part(qstate->config_entry,
1016 qstate->eid_str, qstate->eid_str_length);
1018 break;
1019 case TT_ALL:
1020 if (qstate->euid != 0)
1021 transform_response->error_code = -1;
1022 else {
1023 if (transform_request->entry == NULL) {
1024 size = configuration_get_entries_size(
1025 s_configuration);
1026 for (i = 0; i < size; ++i) {
1027 clear_config_entry(
1028 configuration_get_entry(
1029 s_configuration, i));
1031 } else {
1032 qstate->config_entry = configuration_find_entry(
1033 s_configuration,
1034 transform_request->entry);
1036 if (qstate->config_entry == NULL) {
1037 LOG_ERR_2("transform_request",
1038 "can't find configuration"
1039 " entry '%s'. aborting request",
1040 transform_request->entry);
1041 transform_response->error_code = -1;
1042 goto fin;
1045 clear_config_entry(qstate->config_entry);
1048 break;
1049 default:
1050 transform_response->error_code = -1;
1053 fin:
1054 qstate->kevent_watermark = 0;
1055 qstate->process_func = on_transform_response_write1;
1056 TRACE_OUT(on_transform_request_process);
1057 return (0);
1060 static int
1061 on_transform_response_write1(struct query_state *qstate)
1063 struct cache_transform_response *transform_response;
1064 ssize_t result;
1066 TRACE_IN(on_transform_response_write1);
1067 transform_response = get_cache_transform_response(&qstate->response);
1068 result = qstate->write_func(qstate, &transform_response->error_code,
1069 sizeof(int));
1070 if (result != sizeof(int)) {
1071 TRACE_OUT(on_transform_response_write1);
1072 return (-1);
1075 finalize_comm_element(&qstate->request);
1076 finalize_comm_element(&qstate->response);
1078 qstate->kevent_watermark = 0;
1079 qstate->process_func = NULL;
1080 TRACE_OUT(on_transform_response_write1);
1081 return (0);
1085 * Checks if the client's euid and egid do not differ from its uid and gid.
1086 * Returns 0 on success.
1089 check_query_eids(struct query_state *qstate)
1092 return ((qstate->uid != qstate->euid) || (qstate->gid != qstate->egid) ? -1 : 0);
1096 * Uses the qstate fields to process an "alternate" read - when the buffer is
1097 * too large to be received during one socket read operation
1099 ssize_t
1100 query_io_buffer_read(struct query_state *qstate, void *buf, size_t nbytes)
1102 ssize_t result;
1104 TRACE_IN(query_io_buffer_read);
1105 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1106 return (-1);
1108 if (nbytes < qstate->io_buffer + qstate->io_buffer_size -
1109 qstate->io_buffer_p)
1110 result = nbytes;
1111 else
1112 result = qstate->io_buffer + qstate->io_buffer_size -
1113 qstate->io_buffer_p;
1115 memcpy(buf, qstate->io_buffer_p, result);
1116 qstate->io_buffer_p += result;
1118 if (qstate->io_buffer_p == qstate->io_buffer + qstate->io_buffer_size) {
1119 free(qstate->io_buffer);
1120 qstate->io_buffer = NULL;
1122 qstate->write_func = query_socket_write;
1123 qstate->read_func = query_socket_read;
1126 TRACE_OUT(query_io_buffer_read);
1127 return (result);
1131 * Uses the qstate fields to process an "alternate" write - when the buffer is
1132 * too large to be sent during one socket write operation
1134 ssize_t
1135 query_io_buffer_write(struct query_state *qstate, const void *buf,
1136 size_t nbytes)
1138 ssize_t result;
1140 TRACE_IN(query_io_buffer_write);
1141 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1142 return (-1);
1144 if (nbytes < qstate->io_buffer + qstate->io_buffer_size -
1145 qstate->io_buffer_p)
1146 result = nbytes;
1147 else
1148 result = qstate->io_buffer + qstate->io_buffer_size -
1149 qstate->io_buffer_p;
1151 memcpy(qstate->io_buffer_p, buf, result);
1152 qstate->io_buffer_p += result;
1154 if (qstate->io_buffer_p == qstate->io_buffer + qstate->io_buffer_size) {
1155 qstate->use_alternate_io = 1;
1156 qstate->io_buffer_p = qstate->io_buffer;
1158 qstate->write_func = query_socket_write;
1159 qstate->read_func = query_socket_read;
1162 TRACE_OUT(query_io_buffer_write);
1163 return (result);
1167 * The default "read" function, which reads data directly from socket
1169 ssize_t
1170 query_socket_read(struct query_state *qstate, void *buf, size_t nbytes)
1172 ssize_t result;
1174 TRACE_IN(query_socket_read);
1175 if (qstate->socket_failed != 0) {
1176 TRACE_OUT(query_socket_read);
1177 return (-1);
1180 result = read(qstate->sockfd, buf, nbytes);
1181 if ((result == -1) || (result < nbytes))
1182 qstate->socket_failed = 1;
1184 TRACE_OUT(query_socket_read);
1185 return (result);
1189 * The default "write" function, which writes data directly to socket
1191 ssize_t
1192 query_socket_write(struct query_state *qstate, const void *buf, size_t nbytes)
1194 ssize_t result;
1196 TRACE_IN(query_socket_write);
1197 if (qstate->socket_failed != 0) {
1198 TRACE_OUT(query_socket_write);
1199 return (-1);
1202 result = write(qstate->sockfd, buf, nbytes);
1203 if ((result == -1) || (result < nbytes))
1204 qstate->socket_failed = 1;
1206 TRACE_OUT(query_socket_write);
1207 return (result);
1211 * Initializes the query_state structure by filling it with the default values.
1213 struct query_state *
1214 init_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t egid)
1216 struct query_state *retval;
1218 TRACE_IN(init_query_state);
1219 retval = (struct query_state *)calloc(1, sizeof(struct query_state));
1220 assert(retval != NULL);
1222 retval->sockfd = sockfd;
1223 retval->kevent_filter = EVFILT_READ;
1224 retval->kevent_watermark = kevent_watermark;
1226 retval->euid = euid;
1227 retval->egid = egid;
1228 retval->uid = retval->gid = -1;
1230 if (asprintf(&retval->eid_str, "%d_%d_", retval->euid,
1231 retval->egid) == -1) {
1232 free(retval);
1233 return (NULL);
1235 retval->eid_str_length = strlen(retval->eid_str);
1237 init_comm_element(&retval->request, CET_UNDEFINED);
1238 init_comm_element(&retval->response, CET_UNDEFINED);
1239 retval->process_func = on_query_startup;
1240 retval->destroy_func = on_query_destroy;
1242 retval->write_func = query_socket_write;
1243 retval->read_func = query_socket_read;
1245 get_time_func(&retval->creation_time);
1246 memcpy(&retval->timeout, &s_configuration->query_timeout,
1247 sizeof(struct timeval));
1249 TRACE_OUT(init_query_state);
1250 return (retval);
1253 void
1254 destroy_query_state(struct query_state *qstate)
1257 TRACE_IN(destroy_query_state);
1258 if (qstate->eid_str != NULL)
1259 free(qstate->eid_str);
1261 if (qstate->io_buffer != NULL)
1262 free(qstate->io_buffer);
1264 qstate->destroy_func(qstate);
1265 free(qstate);
1266 TRACE_OUT(destroy_query_state);