2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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>
32 #include <sys/event.h>
43 #include "mp_ws_query.h"
44 #include "mp_rs_query.h"
45 #include "singletons.h"
47 static const char negative_data[1] = { 0 };
49 extern void get_time_func(struct timeval *);
51 static void clear_config_entry(struct configuration_entry *);
52 static void clear_config_entry_part(struct configuration_entry *,
53 const char *, size_t);
55 static int on_query_startup(struct query_state *);
56 static void on_query_destroy(struct query_state *);
58 static int on_read_request_read1(struct query_state *);
59 static int on_read_request_read2(struct query_state *);
60 static int on_read_request_process(struct query_state *);
61 static int on_read_response_write1(struct query_state *);
62 static int on_read_response_write2(struct query_state *);
64 static int on_rw_mapper(struct query_state *);
66 static int on_transform_request_read1(struct query_state *);
67 static int on_transform_request_read2(struct query_state *);
68 static int on_transform_request_process(struct query_state *);
69 static int on_transform_response_write1(struct query_state *);
71 static int on_write_request_read1(struct query_state *);
72 static int on_write_request_read2(struct query_state *);
73 static int on_negative_write_request_process(struct query_state *);
74 static int on_write_request_process(struct query_state *);
75 static int on_write_response_write1(struct query_state *);
78 * Clears the specified configuration entry (clears the cache for positive and
79 * and negative entries) and also for all multipart entries.
82 clear_config_entry(struct configuration_entry *config_entry)
86 TRACE_IN(clear_config_entry);
87 configuration_lock_entry(config_entry, CELT_POSITIVE);
88 if (config_entry->positive_cache_entry != NULL)
89 transform_cache_entry(
90 config_entry->positive_cache_entry,
92 configuration_unlock_entry(config_entry, CELT_POSITIVE);
94 configuration_lock_entry(config_entry, CELT_NEGATIVE);
95 if (config_entry->negative_cache_entry != NULL)
96 transform_cache_entry(
97 config_entry->negative_cache_entry,
99 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
101 configuration_lock_entry(config_entry, CELT_MULTIPART);
102 for (i = 0; i < config_entry->mp_cache_entries_size; ++i)
103 transform_cache_entry(
104 config_entry->mp_cache_entries[i],
106 configuration_unlock_entry(config_entry, CELT_MULTIPART);
108 TRACE_OUT(clear_config_entry);
112 * Clears the specified configuration entry by deleting only the elements,
113 * that are owned by the user with specified eid_str.
116 clear_config_entry_part(struct configuration_entry *config_entry,
117 const char *eid_str, size_t eid_str_length)
119 cache_entry *start, *finish, *mp_entry;
120 TRACE_IN(clear_config_entry_part);
121 configuration_lock_entry(config_entry, CELT_POSITIVE);
122 if (config_entry->positive_cache_entry != NULL)
123 transform_cache_entry_part(
124 config_entry->positive_cache_entry,
125 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
126 configuration_unlock_entry(config_entry, CELT_POSITIVE);
128 configuration_lock_entry(config_entry, CELT_NEGATIVE);
129 if (config_entry->negative_cache_entry != NULL)
130 transform_cache_entry_part(
131 config_entry->negative_cache_entry,
132 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
133 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
135 configuration_lock_entry(config_entry, CELT_MULTIPART);
136 if (configuration_entry_find_mp_cache_entries(config_entry,
137 eid_str, &start, &finish) == 0) {
138 for (mp_entry = start; mp_entry != finish; ++mp_entry)
139 transform_cache_entry(*mp_entry, CTT_CLEAR);
141 configuration_unlock_entry(config_entry, CELT_MULTIPART);
143 TRACE_OUT(clear_config_entry_part);
147 * This function is assigned to the query_state structue on its creation.
148 * It's main purpose is to receive credentials from the client.
151 on_query_startup(struct query_state *qstate)
153 struct msghdr cred_hdr;
155 struct cmsgcred *cred;
160 char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
163 TRACE_IN(on_query_startup);
164 assert(qstate != NULL);
166 memset(&cred_hdr, 0, sizeof(struct msghdr));
167 cred_hdr.msg_iov = &iov;
168 cred_hdr.msg_iovlen = 1;
169 cred_hdr.msg_control = (caddr_t)&cmsg;
170 cred_hdr.msg_controllen = CMSG_LEN(sizeof(struct cmsgcred));
172 memset(&iov, 0, sizeof(struct iovec));
173 iov.iov_base = &elem_type;
174 iov.iov_len = sizeof(int);
176 if (recvmsg(qstate->sockfd, &cred_hdr, 0) == -1) {
177 TRACE_OUT(on_query_startup);
181 if (cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(struct cmsgcred))
182 || cmsg.hdr.cmsg_level != SOL_SOCKET
183 || cmsg.hdr.cmsg_type != SCM_CREDS) {
184 TRACE_OUT(on_query_startup);
188 cred = (struct cmsgcred *)CMSG_DATA(&cmsg);
189 qstate->uid = cred->cmcred_uid;
190 qstate->gid = cred->cmcred_gid;
192 #if defined(NS_NSCD_EID_CHECKING) || defined(NS_STRICT_NSCD_EID_CHECKING)
194 * This check is probably a bit redundant - per-user cache is always separated
195 * by the euid/egid pair
197 if (check_query_eids(qstate) != 0) {
198 #ifdef NS_STRICT_NSCD_EID_CHECKING
199 TRACE_OUT(on_query_startup);
202 if ((elem_type != CET_READ_REQUEST) &&
203 (elem_type != CET_MP_READ_SESSION_REQUEST) &&
204 (elem_type != CET_WRITE_REQUEST) &&
205 (elem_type != CET_MP_WRITE_SESSION_REQUEST)) {
206 TRACE_OUT(on_query_startup);
214 case CET_WRITE_REQUEST:
215 qstate->process_func = on_write_request_read1;
217 case CET_READ_REQUEST:
218 qstate->process_func = on_read_request_read1;
220 case CET_TRANSFORM_REQUEST:
221 qstate->process_func = on_transform_request_read1;
223 case CET_MP_WRITE_SESSION_REQUEST:
224 qstate->process_func = on_mp_write_session_request_read1;
226 case CET_MP_READ_SESSION_REQUEST:
227 qstate->process_func = on_mp_read_session_request_read1;
230 TRACE_OUT(on_query_startup);
234 qstate->kevent_watermark = 0;
235 TRACE_OUT(on_query_startup);
240 * on_rw_mapper is used to process multiple read/write requests during
241 * one connection session. It's never called in the beginning (on query_state
242 * creation) as it does not process the multipart requests and does not
243 * receive credentials
246 on_rw_mapper(struct query_state *qstate)
251 TRACE_IN(on_rw_mapper);
252 if (qstate->kevent_watermark == 0) {
253 qstate->kevent_watermark = sizeof(int);
255 result = qstate->read_func(qstate, &elem_type, sizeof(int));
256 if (result != sizeof(int)) {
257 TRACE_OUT(on_rw_mapper);
262 case CET_WRITE_REQUEST:
263 qstate->kevent_watermark = sizeof(size_t);
264 qstate->process_func = on_write_request_read1;
266 case CET_READ_REQUEST:
267 qstate->kevent_watermark = sizeof(size_t);
268 qstate->process_func = on_read_request_read1;
271 TRACE_OUT(on_rw_mapper);
276 TRACE_OUT(on_rw_mapper);
281 * The default query_destroy function
284 on_query_destroy(struct query_state *qstate)
287 TRACE_IN(on_query_destroy);
288 finalize_comm_element(&qstate->response);
289 finalize_comm_element(&qstate->request);
290 TRACE_OUT(on_query_destroy);
294 * The functions below are used to process write requests.
295 * - on_write_request_read1 and on_write_request_read2 read the request itself
296 * - on_write_request_process processes it (if the client requests to
297 * cache the negative result, the on_negative_write_request_process is used)
298 * - on_write_response_write1 sends the response
301 on_write_request_read1(struct query_state *qstate)
303 struct cache_write_request *write_request;
306 TRACE_IN(on_write_request_read1);
307 if (qstate->kevent_watermark == 0)
308 qstate->kevent_watermark = sizeof(size_t) * 3;
310 init_comm_element(&qstate->request, CET_WRITE_REQUEST);
311 write_request = get_cache_write_request(&qstate->request);
313 result = qstate->read_func(qstate, &write_request->entry_length,
315 result += qstate->read_func(qstate,
316 &write_request->cache_key_size, sizeof(size_t));
317 result += qstate->read_func(qstate,
318 &write_request->data_size, sizeof(size_t));
320 if (result != sizeof(size_t) * 3) {
321 TRACE_OUT(on_write_request_read1);
325 if (BUFSIZE_INVALID(write_request->entry_length) ||
326 BUFSIZE_INVALID(write_request->cache_key_size) ||
327 (BUFSIZE_INVALID(write_request->data_size) &&
328 (write_request->data_size != 0))) {
329 TRACE_OUT(on_write_request_read1);
333 write_request->entry = (char *)calloc(1,
334 write_request->entry_length + 1);
335 assert(write_request->entry != NULL);
337 write_request->cache_key = (char *)calloc(1,
338 write_request->cache_key_size +
339 qstate->eid_str_length);
340 assert(write_request->cache_key != NULL);
341 memcpy(write_request->cache_key, qstate->eid_str,
342 qstate->eid_str_length);
344 if (write_request->data_size != 0) {
345 write_request->data = (char *)calloc(1,
346 write_request->data_size);
347 assert(write_request->data != NULL);
350 qstate->kevent_watermark = write_request->entry_length +
351 write_request->cache_key_size +
352 write_request->data_size;
353 qstate->process_func = on_write_request_read2;
356 TRACE_OUT(on_write_request_read1);
361 on_write_request_read2(struct query_state *qstate)
363 struct cache_write_request *write_request;
366 TRACE_IN(on_write_request_read2);
367 write_request = get_cache_write_request(&qstate->request);
369 result = qstate->read_func(qstate, write_request->entry,
370 write_request->entry_length);
371 result += qstate->read_func(qstate, write_request->cache_key +
372 qstate->eid_str_length, write_request->cache_key_size);
373 if (write_request->data_size != 0)
374 result += qstate->read_func(qstate, write_request->data,
375 write_request->data_size);
377 if (result != qstate->kevent_watermark) {
378 TRACE_OUT(on_write_request_read2);
381 write_request->cache_key_size += qstate->eid_str_length;
383 qstate->kevent_watermark = 0;
384 if (write_request->data_size != 0)
385 qstate->process_func = on_write_request_process;
387 qstate->process_func = on_negative_write_request_process;
388 TRACE_OUT(on_write_request_read2);
393 on_write_request_process(struct query_state *qstate)
395 struct cache_write_request *write_request;
396 struct cache_write_response *write_response;
399 TRACE_IN(on_write_request_process);
400 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
401 write_response = get_cache_write_response(&qstate->response);
402 write_request = get_cache_write_request(&qstate->request);
404 qstate->config_entry = configuration_find_entry(
405 s_configuration, write_request->entry);
407 if (qstate->config_entry == NULL) {
408 write_response->error_code = ENOENT;
410 LOG_ERR_2("write_request", "can't find configuration"
411 " entry '%s'. aborting request", write_request->entry);
415 if (qstate->config_entry->enabled == 0) {
416 write_response->error_code = EACCES;
418 LOG_ERR_2("write_request",
419 "configuration entry '%s' is disabled",
420 write_request->entry);
424 if (qstate->config_entry->perform_actual_lookups != 0) {
425 write_response->error_code = EOPNOTSUPP;
427 LOG_ERR_2("write_request",
428 "entry '%s' performs lookups by itself: "
429 "can't write to it", write_request->entry);
433 configuration_lock_rdlock(s_configuration);
434 c_entry = find_cache_entry(s_cache,
435 qstate->config_entry->positive_cache_params.entry_name);
436 configuration_unlock(s_configuration);
437 if (c_entry != NULL) {
438 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
439 qstate->config_entry->positive_cache_entry = c_entry;
440 write_response->error_code = cache_write(c_entry,
441 write_request->cache_key,
442 write_request->cache_key_size,
444 write_request->data_size);
445 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
447 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
448 (qstate->config_entry->common_query_timeout.tv_usec != 0))
449 memcpy(&qstate->timeout,
450 &qstate->config_entry->common_query_timeout,
451 sizeof(struct timeval));
454 write_response->error_code = -1;
457 qstate->kevent_filter = EVFILT_WRITE;
458 qstate->kevent_watermark = sizeof(int);
459 qstate->process_func = on_write_response_write1;
461 TRACE_OUT(on_write_request_process);
466 on_negative_write_request_process(struct query_state *qstate)
468 struct cache_write_request *write_request;
469 struct cache_write_response *write_response;
472 TRACE_IN(on_negative_write_request_process);
473 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
474 write_response = get_cache_write_response(&qstate->response);
475 write_request = get_cache_write_request(&qstate->request);
477 qstate->config_entry = configuration_find_entry(
478 s_configuration, write_request->entry);
480 if (qstate->config_entry == NULL) {
481 write_response->error_code = ENOENT;
483 LOG_ERR_2("negative_write_request",
484 "can't find configuration"
485 " entry '%s'. aborting request", write_request->entry);
489 if (qstate->config_entry->enabled == 0) {
490 write_response->error_code = EACCES;
492 LOG_ERR_2("negative_write_request",
493 "configuration entry '%s' is disabled",
494 write_request->entry);
498 if (qstate->config_entry->perform_actual_lookups != 0) {
499 write_response->error_code = EOPNOTSUPP;
501 LOG_ERR_2("negative_write_request",
502 "entry '%s' performs lookups by itself: "
503 "can't write to it", write_request->entry);
506 #ifdef NS_NSCD_EID_CHECKING
507 if (check_query_eids(qstate) != 0) {
508 write_response->error_code = EPERM;
514 configuration_lock_rdlock(s_configuration);
515 c_entry = find_cache_entry(s_cache,
516 qstate->config_entry->negative_cache_params.entry_name);
517 configuration_unlock(s_configuration);
518 if (c_entry != NULL) {
519 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
520 qstate->config_entry->negative_cache_entry = c_entry;
521 write_response->error_code = cache_write(c_entry,
522 write_request->cache_key,
523 write_request->cache_key_size,
525 sizeof(negative_data));
526 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
528 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
529 (qstate->config_entry->common_query_timeout.tv_usec != 0))
530 memcpy(&qstate->timeout,
531 &qstate->config_entry->common_query_timeout,
532 sizeof(struct timeval));
534 write_response->error_code = -1;
537 qstate->kevent_filter = EVFILT_WRITE;
538 qstate->kevent_watermark = sizeof(int);
539 qstate->process_func = on_write_response_write1;
541 TRACE_OUT(on_negative_write_request_process);
546 on_write_response_write1(struct query_state *qstate)
548 struct cache_write_response *write_response;
551 TRACE_IN(on_write_response_write1);
552 write_response = get_cache_write_response(&qstate->response);
553 result = qstate->write_func(qstate, &write_response->error_code,
555 if (result != sizeof(int)) {
556 TRACE_OUT(on_write_response_write1);
560 finalize_comm_element(&qstate->request);
561 finalize_comm_element(&qstate->response);
563 qstate->kevent_watermark = sizeof(int);
564 qstate->kevent_filter = EVFILT_READ;
565 qstate->process_func = on_rw_mapper;
567 TRACE_OUT(on_write_response_write1);
572 * The functions below are used to process read requests.
573 * - on_read_request_read1 and on_read_request_read2 read the request itself
574 * - on_read_request_process processes it
575 * - on_read_response_write1 and on_read_response_write2 send the response
578 on_read_request_read1(struct query_state *qstate)
580 struct cache_read_request *read_request;
583 TRACE_IN(on_read_request_read1);
584 if (qstate->kevent_watermark == 0)
585 qstate->kevent_watermark = sizeof(size_t) * 2;
587 init_comm_element(&qstate->request, CET_READ_REQUEST);
588 read_request = get_cache_read_request(&qstate->request);
590 result = qstate->read_func(qstate,
591 &read_request->entry_length, sizeof(size_t));
592 result += qstate->read_func(qstate,
593 &read_request->cache_key_size, sizeof(size_t));
595 if (result != sizeof(size_t) * 2) {
596 TRACE_OUT(on_read_request_read1);
600 if (BUFSIZE_INVALID(read_request->entry_length) ||
601 BUFSIZE_INVALID(read_request->cache_key_size)) {
602 TRACE_OUT(on_read_request_read1);
606 read_request->entry = (char *)calloc(1,
607 read_request->entry_length + 1);
608 assert(read_request->entry != NULL);
610 read_request->cache_key = (char *)calloc(1,
611 read_request->cache_key_size +
612 qstate->eid_str_length);
613 assert(read_request->cache_key != NULL);
614 memcpy(read_request->cache_key, qstate->eid_str,
615 qstate->eid_str_length);
617 qstate->kevent_watermark = read_request->entry_length +
618 read_request->cache_key_size;
619 qstate->process_func = on_read_request_read2;
622 TRACE_OUT(on_read_request_read1);
627 on_read_request_read2(struct query_state *qstate)
629 struct cache_read_request *read_request;
632 TRACE_IN(on_read_request_read2);
633 read_request = get_cache_read_request(&qstate->request);
635 result = qstate->read_func(qstate, read_request->entry,
636 read_request->entry_length);
637 result += qstate->read_func(qstate,
638 read_request->cache_key + qstate->eid_str_length,
639 read_request->cache_key_size);
641 if (result != qstate->kevent_watermark) {
642 TRACE_OUT(on_read_request_read2);
645 read_request->cache_key_size += qstate->eid_str_length;
647 qstate->kevent_watermark = 0;
648 qstate->process_func = on_read_request_process;
650 TRACE_OUT(on_read_request_read2);
655 on_read_request_process(struct query_state *qstate)
657 struct cache_read_request *read_request;
658 struct cache_read_response *read_response;
659 cache_entry c_entry, neg_c_entry;
661 struct agent *lookup_agent;
662 struct common_agent *c_agent;
665 TRACE_IN(on_read_request_process);
666 init_comm_element(&qstate->response, CET_READ_RESPONSE);
667 read_response = get_cache_read_response(&qstate->response);
668 read_request = get_cache_read_request(&qstate->request);
670 qstate->config_entry = configuration_find_entry(
671 s_configuration, read_request->entry);
672 if (qstate->config_entry == NULL) {
673 read_response->error_code = ENOENT;
675 LOG_ERR_2("read_request",
676 "can't find configuration "
677 "entry '%s'. aborting request", read_request->entry);
681 if (qstate->config_entry->enabled == 0) {
682 read_response->error_code = EACCES;
684 LOG_ERR_2("read_request",
685 "configuration entry '%s' is disabled",
686 read_request->entry);
691 * if we perform lookups by ourselves, then we don't need to separate
692 * cache entries by euid and egid
694 if (qstate->config_entry->perform_actual_lookups != 0)
695 memset(read_request->cache_key, 0, qstate->eid_str_length);
697 #ifdef NS_NSCD_EID_CHECKING
698 if (check_query_eids(qstate) != 0) {
699 /* if the lookup is not self-performing, we check for clients euid/egid */
700 read_response->error_code = EPERM;
706 configuration_lock_rdlock(s_configuration);
707 c_entry = find_cache_entry(s_cache,
708 qstate->config_entry->positive_cache_params.entry_name);
709 neg_c_entry = find_cache_entry(s_cache,
710 qstate->config_entry->negative_cache_params.entry_name);
711 configuration_unlock(s_configuration);
712 if ((c_entry != NULL) && (neg_c_entry != NULL)) {
713 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
714 qstate->config_entry->positive_cache_entry = c_entry;
715 read_response->error_code = cache_read(c_entry,
716 read_request->cache_key,
717 read_request->cache_key_size, NULL,
718 &read_response->data_size);
720 if (read_response->error_code == -2) {
721 read_response->data = (char *)malloc(
722 read_response->data_size);
723 assert(read_response != NULL);
724 read_response->error_code = cache_read(c_entry,
725 read_request->cache_key,
726 read_request->cache_key_size,
728 &read_response->data_size);
730 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
732 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
733 qstate->config_entry->negative_cache_entry = neg_c_entry;
734 if (read_response->error_code == -1) {
735 read_response->error_code = cache_read(neg_c_entry,
736 read_request->cache_key,
737 read_request->cache_key_size, NULL,
738 &read_response->data_size);
740 if (read_response->error_code == -2) {
741 read_response->error_code = 0;
742 read_response->data = NULL;
743 read_response->data_size = 0;
746 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
748 if ((read_response->error_code == -1) &&
749 (qstate->config_entry->perform_actual_lookups != 0)) {
750 free(read_response->data);
751 read_response->data = NULL;
752 read_response->data_size = 0;
754 lookup_agent = find_agent(s_agent_table,
755 read_request->entry, COMMON_AGENT);
757 if ((lookup_agent != NULL) &&
758 (lookup_agent->type == COMMON_AGENT)) {
759 c_agent = (struct common_agent *)lookup_agent;
760 res = c_agent->lookup_func(
761 read_request->cache_key +
762 qstate->eid_str_length,
763 read_request->cache_key_size -
764 qstate->eid_str_length,
765 &read_response->data,
766 &read_response->data_size);
768 if (res == NS_SUCCESS) {
769 read_response->error_code = 0;
770 configuration_lock_entry(
771 qstate->config_entry,
774 read_request->cache_key,
775 read_request->cache_key_size,
777 read_response->data_size);
778 configuration_unlock_entry(
779 qstate->config_entry,
781 } else if ((res == NS_NOTFOUND) ||
782 (res == NS_RETURN)) {
783 configuration_lock_entry(
784 qstate->config_entry,
786 cache_write(neg_c_entry,
787 read_request->cache_key,
788 read_request->cache_key_size,
790 sizeof(negative_data));
791 configuration_unlock_entry(
792 qstate->config_entry,
795 read_response->error_code = 0;
796 read_response->data = NULL;
797 read_response->data_size = 0;
802 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
803 (qstate->config_entry->common_query_timeout.tv_usec != 0))
804 memcpy(&qstate->timeout,
805 &qstate->config_entry->common_query_timeout,
806 sizeof(struct timeval));
808 read_response->error_code = -1;
811 qstate->kevent_filter = EVFILT_WRITE;
812 if (read_response->error_code == 0)
813 qstate->kevent_watermark = sizeof(int) + sizeof(size_t);
815 qstate->kevent_watermark = sizeof(int);
816 qstate->process_func = on_read_response_write1;
818 TRACE_OUT(on_read_request_process);
823 on_read_response_write1(struct query_state *qstate)
825 struct cache_read_response *read_response;
828 TRACE_IN(on_read_response_write1);
829 read_response = get_cache_read_response(&qstate->response);
831 result = qstate->write_func(qstate, &read_response->error_code,
834 if (read_response->error_code == 0) {
835 result += qstate->write_func(qstate, &read_response->data_size,
837 if (result != qstate->kevent_watermark) {
838 TRACE_OUT(on_read_response_write1);
842 qstate->kevent_watermark = read_response->data_size;
843 qstate->process_func = on_read_response_write2;
845 if (result != qstate->kevent_watermark) {
846 TRACE_OUT(on_read_response_write1);
850 qstate->kevent_watermark = 0;
851 qstate->process_func = NULL;
854 TRACE_OUT(on_read_response_write1);
859 on_read_response_write2(struct query_state *qstate)
861 struct cache_read_response *read_response;
864 TRACE_IN(on_read_response_write2);
865 read_response = get_cache_read_response(&qstate->response);
866 if (read_response->data_size > 0) {
867 result = qstate->write_func(qstate, read_response->data,
868 read_response->data_size);
869 if (result != qstate->kevent_watermark) {
870 TRACE_OUT(on_read_response_write2);
875 finalize_comm_element(&qstate->request);
876 finalize_comm_element(&qstate->response);
878 qstate->kevent_watermark = sizeof(int);
879 qstate->kevent_filter = EVFILT_READ;
880 qstate->process_func = on_rw_mapper;
881 TRACE_OUT(on_read_response_write2);
886 * The functions below are used to process write requests.
887 * - on_transform_request_read1 and on_transform_request_read2 read the
889 * - on_transform_request_process processes it
890 * - on_transform_response_write1 sends the response
893 on_transform_request_read1(struct query_state *qstate)
895 struct cache_transform_request *transform_request;
898 TRACE_IN(on_transform_request_read1);
899 if (qstate->kevent_watermark == 0)
900 qstate->kevent_watermark = sizeof(size_t) + sizeof(int);
902 init_comm_element(&qstate->request, CET_TRANSFORM_REQUEST);
904 get_cache_transform_request(&qstate->request);
906 result = qstate->read_func(qstate,
907 &transform_request->entry_length, sizeof(size_t));
908 result += qstate->read_func(qstate,
909 &transform_request->transformation_type, sizeof(int));
911 if (result != sizeof(size_t) + sizeof(int)) {
912 TRACE_OUT(on_transform_request_read1);
916 if ((transform_request->transformation_type != TT_USER) &&
917 (transform_request->transformation_type != TT_ALL)) {
918 TRACE_OUT(on_transform_request_read1);
922 if (transform_request->entry_length != 0) {
923 if (BUFSIZE_INVALID(transform_request->entry_length)) {
924 TRACE_OUT(on_transform_request_read1);
928 transform_request->entry = (char *)calloc(1,
929 transform_request->entry_length + 1);
930 assert(transform_request->entry != NULL);
932 qstate->process_func = on_transform_request_read2;
934 qstate->process_func = on_transform_request_process;
936 qstate->kevent_watermark = transform_request->entry_length;
939 TRACE_OUT(on_transform_request_read1);
944 on_transform_request_read2(struct query_state *qstate)
946 struct cache_transform_request *transform_request;
949 TRACE_IN(on_transform_request_read2);
950 transform_request = get_cache_transform_request(&qstate->request);
952 result = qstate->read_func(qstate, transform_request->entry,
953 transform_request->entry_length);
955 if (result != qstate->kevent_watermark) {
956 TRACE_OUT(on_transform_request_read2);
960 qstate->kevent_watermark = 0;
961 qstate->process_func = on_transform_request_process;
963 TRACE_OUT(on_transform_request_read2);
968 on_transform_request_process(struct query_state *qstate)
970 struct cache_transform_request *transform_request;
971 struct cache_transform_response *transform_response;
972 struct configuration_entry *config_entry;
975 TRACE_IN(on_transform_request_process);
976 init_comm_element(&qstate->response, CET_TRANSFORM_RESPONSE);
977 transform_response = get_cache_transform_response(&qstate->response);
978 transform_request = get_cache_transform_request(&qstate->request);
980 switch (transform_request->transformation_type) {
982 if (transform_request->entry == NULL) {
983 size = configuration_get_entries_size(s_configuration);
984 for (i = 0; i < size; ++i) {
985 config_entry = configuration_get_entry(
988 if (config_entry->perform_actual_lookups == 0)
989 clear_config_entry_part(config_entry,
990 qstate->eid_str, qstate->eid_str_length);
993 qstate->config_entry = configuration_find_entry(
994 s_configuration, transform_request->entry);
996 if (qstate->config_entry == NULL) {
997 LOG_ERR_2("transform_request",
998 "can't find configuration"
999 " entry '%s'. aborting request",
1000 transform_request->entry);
1001 transform_response->error_code = -1;
1005 if (qstate->config_entry->perform_actual_lookups != 0) {
1006 LOG_ERR_2("transform_request",
1007 "can't transform the cache entry %s"
1008 ", because it ised for actual lookups",
1009 transform_request->entry);
1010 transform_response->error_code = -1;
1014 clear_config_entry_part(qstate->config_entry,
1015 qstate->eid_str, qstate->eid_str_length);
1019 if (qstate->euid != 0)
1020 transform_response->error_code = -1;
1022 if (transform_request->entry == NULL) {
1023 size = configuration_get_entries_size(
1025 for (i = 0; i < size; ++i) {
1027 configuration_get_entry(
1028 s_configuration, i));
1031 qstate->config_entry = configuration_find_entry(
1033 transform_request->entry);
1035 if (qstate->config_entry == NULL) {
1036 LOG_ERR_2("transform_request",
1037 "can't find configuration"
1038 " entry '%s'. aborting request",
1039 transform_request->entry);
1040 transform_response->error_code = -1;
1044 clear_config_entry(qstate->config_entry);
1049 transform_response->error_code = -1;
1053 qstate->kevent_watermark = 0;
1054 qstate->process_func = on_transform_response_write1;
1055 TRACE_OUT(on_transform_request_process);
1060 on_transform_response_write1(struct query_state *qstate)
1062 struct cache_transform_response *transform_response;
1065 TRACE_IN(on_transform_response_write1);
1066 transform_response = get_cache_transform_response(&qstate->response);
1067 result = qstate->write_func(qstate, &transform_response->error_code,
1069 if (result != sizeof(int)) {
1070 TRACE_OUT(on_transform_response_write1);
1074 finalize_comm_element(&qstate->request);
1075 finalize_comm_element(&qstate->response);
1077 qstate->kevent_watermark = 0;
1078 qstate->process_func = NULL;
1079 TRACE_OUT(on_transform_response_write1);
1084 * Checks if the client's euid and egid do not differ from its uid and gid.
1085 * Returns 0 on success.
1088 check_query_eids(struct query_state *qstate)
1091 return ((qstate->uid != qstate->euid) || (qstate->gid != qstate->egid) ? -1 : 0);
1095 * Uses the qstate fields to process an "alternate" read - when the buffer is
1096 * too large to be received during one socket read operation
1099 query_io_buffer_read(struct query_state *qstate, void *buf, size_t nbytes)
1103 TRACE_IN(query_io_buffer_read);
1104 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1107 if (nbytes < qstate->io_buffer + qstate->io_buffer_size -
1108 qstate->io_buffer_p)
1111 result = qstate->io_buffer + qstate->io_buffer_size -
1112 qstate->io_buffer_p;
1114 memcpy(buf, qstate->io_buffer_p, result);
1115 qstate->io_buffer_p += result;
1117 if (qstate->io_buffer_p == qstate->io_buffer + qstate->io_buffer_size) {
1118 free(qstate->io_buffer);
1119 qstate->io_buffer = NULL;
1121 qstate->write_func = query_socket_write;
1122 qstate->read_func = query_socket_read;
1125 TRACE_OUT(query_io_buffer_read);
1130 * Uses the qstate fields to process an "alternate" write - when the buffer is
1131 * too large to be sent during one socket write operation
1134 query_io_buffer_write(struct query_state *qstate, const void *buf,
1139 TRACE_IN(query_io_buffer_write);
1140 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1143 if (nbytes < qstate->io_buffer + qstate->io_buffer_size -
1144 qstate->io_buffer_p)
1147 result = qstate->io_buffer + qstate->io_buffer_size -
1148 qstate->io_buffer_p;
1150 memcpy(qstate->io_buffer_p, buf, result);
1151 qstate->io_buffer_p += result;
1153 if (qstate->io_buffer_p == qstate->io_buffer + qstate->io_buffer_size) {
1154 qstate->use_alternate_io = 1;
1155 qstate->io_buffer_p = qstate->io_buffer;
1157 qstate->write_func = query_socket_write;
1158 qstate->read_func = query_socket_read;
1161 TRACE_OUT(query_io_buffer_write);
1166 * The default "read" function, which reads data directly from socket
1169 query_socket_read(struct query_state *qstate, void *buf, size_t nbytes)
1173 TRACE_IN(query_socket_read);
1174 if (qstate->socket_failed != 0) {
1175 TRACE_OUT(query_socket_read);
1179 result = read(qstate->sockfd, buf, nbytes);
1180 if ((result == -1) || (result < nbytes))
1181 qstate->socket_failed = 1;
1183 TRACE_OUT(query_socket_read);
1188 * The default "write" function, which writes data directly to socket
1191 query_socket_write(struct query_state *qstate, const void *buf, size_t nbytes)
1195 TRACE_IN(query_socket_write);
1196 if (qstate->socket_failed != 0) {
1197 TRACE_OUT(query_socket_write);
1201 result = write(qstate->sockfd, buf, nbytes);
1202 if ((result == -1) || (result < nbytes))
1203 qstate->socket_failed = 1;
1205 TRACE_OUT(query_socket_write);
1210 * Initializes the query_state structure by filling it with the default values.
1212 struct query_state *
1213 init_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t egid)
1215 struct query_state *retval;
1217 TRACE_IN(init_query_state);
1218 retval = (struct query_state *)calloc(1, sizeof(struct query_state));
1219 assert(retval != NULL);
1221 retval->sockfd = sockfd;
1222 retval->kevent_filter = EVFILT_READ;
1223 retval->kevent_watermark = kevent_watermark;
1225 retval->euid = euid;
1226 retval->egid = egid;
1227 retval->uid = retval->gid = -1;
1229 if (asprintf(&retval->eid_str, "%d_%d_", retval->euid,
1230 retval->egid) == -1) {
1234 retval->eid_str_length = strlen(retval->eid_str);
1236 init_comm_element(&retval->request, CET_UNDEFINED);
1237 init_comm_element(&retval->response, CET_UNDEFINED);
1238 retval->process_func = on_query_startup;
1239 retval->destroy_func = on_query_destroy;
1241 retval->write_func = query_socket_write;
1242 retval->read_func = query_socket_read;
1244 get_time_func(&retval->creation_time);
1245 memcpy(&retval->timeout, &s_configuration->query_timeout,
1246 sizeof(struct timeval));
1248 TRACE_OUT(init_query_state);
1253 destroy_query_state(struct query_state *qstate)
1256 TRACE_IN(destroy_query_state);
1257 if (qstate->eid_str != NULL)
1258 free(qstate->eid_str);
1260 if (qstate->io_buffer != NULL)
1261 free(qstate->io_buffer);
1263 qstate->destroy_func(qstate);
1265 TRACE_OUT(destroy_query_state);