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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/types.h>
32 #include <sys/event.h>
33 #include <sys/socket.h>
48 #include "mp_ws_query.h"
49 #include "mp_rs_query.h"
50 #include "singletons.h"
52 static const char negative_data[1] = { 0 };
54 extern void get_time_func(struct timeval *);
56 static void clear_config_entry(struct configuration_entry *);
57 static void clear_config_entry_part(struct configuration_entry *,
58 const char *, size_t);
60 static int on_query_startup(struct query_state *);
61 static void on_query_destroy(struct query_state *);
63 static int on_read_request_read1(struct query_state *);
64 static int on_read_request_read2(struct query_state *);
65 static int on_read_request_process(struct query_state *);
66 static int on_read_response_write1(struct query_state *);
67 static int on_read_response_write2(struct query_state *);
69 static int on_rw_mapper(struct query_state *);
71 static int on_transform_request_read1(struct query_state *);
72 static int on_transform_request_read2(struct query_state *);
73 static int on_transform_request_process(struct query_state *);
74 static int on_transform_response_write1(struct query_state *);
76 static int on_write_request_read1(struct query_state *);
77 static int on_write_request_read2(struct query_state *);
78 static int on_negative_write_request_process(struct query_state *);
79 static int on_write_request_process(struct query_state *);
80 static int on_write_response_write1(struct query_state *);
83 * Clears the specified configuration entry (clears the cache for positive and
84 * and negative entries) and also for all multipart entries.
87 clear_config_entry(struct configuration_entry *config_entry)
91 TRACE_IN(clear_config_entry);
92 configuration_lock_entry(config_entry, CELT_POSITIVE);
93 if (config_entry->positive_cache_entry != NULL)
94 transform_cache_entry(
95 config_entry->positive_cache_entry,
97 configuration_unlock_entry(config_entry, CELT_POSITIVE);
99 configuration_lock_entry(config_entry, CELT_NEGATIVE);
100 if (config_entry->negative_cache_entry != NULL)
101 transform_cache_entry(
102 config_entry->negative_cache_entry,
104 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
106 configuration_lock_entry(config_entry, CELT_MULTIPART);
107 for (i = 0; i < config_entry->mp_cache_entries_size; ++i)
108 transform_cache_entry(
109 config_entry->mp_cache_entries[i],
111 configuration_unlock_entry(config_entry, CELT_MULTIPART);
113 TRACE_OUT(clear_config_entry);
117 * Clears the specified configuration entry by deleting only the elements,
118 * that are owned by the user with specified eid_str.
121 clear_config_entry_part(struct configuration_entry *config_entry,
122 const char *eid_str, size_t eid_str_length)
124 cache_entry *start, *finish, *mp_entry;
125 TRACE_IN(clear_config_entry_part);
126 configuration_lock_entry(config_entry, CELT_POSITIVE);
127 if (config_entry->positive_cache_entry != NULL)
128 transform_cache_entry_part(
129 config_entry->positive_cache_entry,
130 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
131 configuration_unlock_entry(config_entry, CELT_POSITIVE);
133 configuration_lock_entry(config_entry, CELT_NEGATIVE);
134 if (config_entry->negative_cache_entry != NULL)
135 transform_cache_entry_part(
136 config_entry->negative_cache_entry,
137 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
138 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
140 configuration_lock_entry(config_entry, CELT_MULTIPART);
141 if (configuration_entry_find_mp_cache_entries(config_entry,
142 eid_str, &start, &finish) == 0) {
143 for (mp_entry = start; mp_entry != finish; ++mp_entry)
144 transform_cache_entry(*mp_entry, CTT_CLEAR);
146 configuration_unlock_entry(config_entry, CELT_MULTIPART);
148 TRACE_OUT(clear_config_entry_part);
152 * This function is assigned to the query_state structue on its creation.
153 * It's main purpose is to receive credentials from the client.
156 on_query_startup(struct query_state *qstate)
158 struct msghdr cred_hdr;
160 struct cmsgcred *cred;
165 char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
168 TRACE_IN(on_query_startup);
169 assert(qstate != NULL);
171 memset(&cred_hdr, 0, sizeof(struct msghdr));
172 cred_hdr.msg_iov = &iov;
173 cred_hdr.msg_iovlen = 1;
174 cred_hdr.msg_control = &cmsg;
175 cred_hdr.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
177 memset(&iov, 0, sizeof(struct iovec));
178 iov.iov_base = &elem_type;
179 iov.iov_len = sizeof(int);
181 if (recvmsg(qstate->sockfd, &cred_hdr, 0) == -1) {
182 TRACE_OUT(on_query_startup);
186 if (cred_hdr.msg_controllen < CMSG_LEN(sizeof(struct cmsgcred))
187 || cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(struct cmsgcred))
188 || cmsg.hdr.cmsg_level != SOL_SOCKET
189 || cmsg.hdr.cmsg_type != SCM_CREDS) {
190 TRACE_OUT(on_query_startup);
194 cred = (struct cmsgcred *)CMSG_DATA(&cmsg);
195 qstate->uid = cred->cmcred_uid;
196 qstate->gid = cred->cmcred_gid;
198 #if defined(NS_NSCD_EID_CHECKING) || defined(NS_STRICT_NSCD_EID_CHECKING)
200 * This check is probably a bit redundant - per-user cache is always separated
201 * by the euid/egid pair
203 if (check_query_eids(qstate) != 0) {
204 #ifdef NS_STRICT_NSCD_EID_CHECKING
205 TRACE_OUT(on_query_startup);
208 if ((elem_type != CET_READ_REQUEST) &&
209 (elem_type != CET_MP_READ_SESSION_REQUEST) &&
210 (elem_type != CET_WRITE_REQUEST) &&
211 (elem_type != CET_MP_WRITE_SESSION_REQUEST)) {
212 TRACE_OUT(on_query_startup);
220 case CET_WRITE_REQUEST:
221 qstate->process_func = on_write_request_read1;
223 case CET_READ_REQUEST:
224 qstate->process_func = on_read_request_read1;
226 case CET_TRANSFORM_REQUEST:
227 qstate->process_func = on_transform_request_read1;
229 case CET_MP_WRITE_SESSION_REQUEST:
230 qstate->process_func = on_mp_write_session_request_read1;
232 case CET_MP_READ_SESSION_REQUEST:
233 qstate->process_func = on_mp_read_session_request_read1;
236 TRACE_OUT(on_query_startup);
240 qstate->kevent_watermark = 0;
241 TRACE_OUT(on_query_startup);
246 * on_rw_mapper is used to process multiple read/write requests during
247 * one connection session. It's never called in the beginning (on query_state
248 * creation) as it does not process the multipart requests and does not
249 * receive credentials
252 on_rw_mapper(struct query_state *qstate)
257 TRACE_IN(on_rw_mapper);
258 if (qstate->kevent_watermark == 0) {
259 qstate->kevent_watermark = sizeof(int);
261 result = qstate->read_func(qstate, &elem_type, sizeof(int));
262 if (result != sizeof(int)) {
263 TRACE_OUT(on_rw_mapper);
268 case CET_WRITE_REQUEST:
269 qstate->kevent_watermark = sizeof(size_t);
270 qstate->process_func = on_write_request_read1;
272 case CET_READ_REQUEST:
273 qstate->kevent_watermark = sizeof(size_t);
274 qstate->process_func = on_read_request_read1;
277 TRACE_OUT(on_rw_mapper);
282 TRACE_OUT(on_rw_mapper);
287 * The default query_destroy function
290 on_query_destroy(struct query_state *qstate)
293 TRACE_IN(on_query_destroy);
294 finalize_comm_element(&qstate->response);
295 finalize_comm_element(&qstate->request);
296 TRACE_OUT(on_query_destroy);
300 * The functions below are used to process write requests.
301 * - on_write_request_read1 and on_write_request_read2 read the request itself
302 * - on_write_request_process processes it (if the client requests to
303 * cache the negative result, the on_negative_write_request_process is used)
304 * - on_write_response_write1 sends the response
307 on_write_request_read1(struct query_state *qstate)
309 struct cache_write_request *write_request;
312 TRACE_IN(on_write_request_read1);
313 if (qstate->kevent_watermark == 0)
314 qstate->kevent_watermark = sizeof(size_t) * 3;
316 init_comm_element(&qstate->request, CET_WRITE_REQUEST);
317 write_request = get_cache_write_request(&qstate->request);
319 result = qstate->read_func(qstate, &write_request->entry_length,
321 result += qstate->read_func(qstate,
322 &write_request->cache_key_size, sizeof(size_t));
323 result += qstate->read_func(qstate,
324 &write_request->data_size, sizeof(size_t));
326 if (result != sizeof(size_t) * 3) {
327 TRACE_OUT(on_write_request_read1);
331 if (BUFSIZE_INVALID(write_request->entry_length) ||
332 BUFSIZE_INVALID(write_request->cache_key_size) ||
333 (BUFSIZE_INVALID(write_request->data_size) &&
334 (write_request->data_size != 0))) {
335 TRACE_OUT(on_write_request_read1);
339 write_request->entry = calloc(1,
340 write_request->entry_length + 1);
341 assert(write_request->entry != NULL);
343 write_request->cache_key = calloc(1,
344 write_request->cache_key_size +
345 qstate->eid_str_length);
346 assert(write_request->cache_key != NULL);
347 memcpy(write_request->cache_key, qstate->eid_str,
348 qstate->eid_str_length);
350 if (write_request->data_size != 0) {
351 write_request->data = calloc(1,
352 write_request->data_size);
353 assert(write_request->data != NULL);
356 qstate->kevent_watermark = write_request->entry_length +
357 write_request->cache_key_size +
358 write_request->data_size;
359 qstate->process_func = on_write_request_read2;
362 TRACE_OUT(on_write_request_read1);
367 on_write_request_read2(struct query_state *qstate)
369 struct cache_write_request *write_request;
372 TRACE_IN(on_write_request_read2);
373 write_request = get_cache_write_request(&qstate->request);
375 result = qstate->read_func(qstate, write_request->entry,
376 write_request->entry_length);
377 result += qstate->read_func(qstate, write_request->cache_key +
378 qstate->eid_str_length, write_request->cache_key_size);
379 if (write_request->data_size != 0)
380 result += qstate->read_func(qstate, write_request->data,
381 write_request->data_size);
383 if (result != (ssize_t)qstate->kevent_watermark) {
384 TRACE_OUT(on_write_request_read2);
387 write_request->cache_key_size += qstate->eid_str_length;
389 qstate->kevent_watermark = 0;
390 if (write_request->data_size != 0)
391 qstate->process_func = on_write_request_process;
393 qstate->process_func = on_negative_write_request_process;
394 TRACE_OUT(on_write_request_read2);
399 on_write_request_process(struct query_state *qstate)
401 struct cache_write_request *write_request;
402 struct cache_write_response *write_response;
405 TRACE_IN(on_write_request_process);
406 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
407 write_response = get_cache_write_response(&qstate->response);
408 write_request = get_cache_write_request(&qstate->request);
410 qstate->config_entry = configuration_find_entry(
411 s_configuration, write_request->entry);
413 if (qstate->config_entry == NULL) {
414 write_response->error_code = ENOENT;
416 LOG_ERR_2("write_request", "can't find configuration"
417 " entry '%s'. aborting request", write_request->entry);
421 if (qstate->config_entry->enabled == 0) {
422 write_response->error_code = EACCES;
424 LOG_ERR_2("write_request",
425 "configuration entry '%s' is disabled",
426 write_request->entry);
430 if (qstate->config_entry->perform_actual_lookups != 0) {
431 write_response->error_code = EOPNOTSUPP;
433 LOG_ERR_2("write_request",
434 "entry '%s' performs lookups by itself: "
435 "can't write to it", write_request->entry);
439 configuration_lock_rdlock(s_configuration);
440 c_entry = find_cache_entry(s_cache,
441 qstate->config_entry->positive_cache_params.cep.entry_name);
442 configuration_unlock(s_configuration);
443 if (c_entry != NULL) {
444 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
445 qstate->config_entry->positive_cache_entry = c_entry;
446 write_response->error_code = cache_write(c_entry,
447 write_request->cache_key,
448 write_request->cache_key_size,
450 write_request->data_size);
451 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
453 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
454 (qstate->config_entry->common_query_timeout.tv_usec != 0))
455 memcpy(&qstate->timeout,
456 &qstate->config_entry->common_query_timeout,
457 sizeof(struct timeval));
460 write_response->error_code = -1;
463 qstate->kevent_filter = EVFILT_WRITE;
464 qstate->kevent_watermark = sizeof(int);
465 qstate->process_func = on_write_response_write1;
467 TRACE_OUT(on_write_request_process);
472 on_negative_write_request_process(struct query_state *qstate)
474 struct cache_write_request *write_request;
475 struct cache_write_response *write_response;
478 TRACE_IN(on_negative_write_request_process);
479 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
480 write_response = get_cache_write_response(&qstate->response);
481 write_request = get_cache_write_request(&qstate->request);
483 qstate->config_entry = configuration_find_entry (
484 s_configuration, write_request->entry);
486 if (qstate->config_entry == NULL) {
487 write_response->error_code = ENOENT;
489 LOG_ERR_2("negative_write_request",
490 "can't find configuration"
491 " entry '%s'. aborting request", write_request->entry);
495 if (qstate->config_entry->enabled == 0) {
496 write_response->error_code = EACCES;
498 LOG_ERR_2("negative_write_request",
499 "configuration entry '%s' is disabled",
500 write_request->entry);
504 if (qstate->config_entry->perform_actual_lookups != 0) {
505 write_response->error_code = EOPNOTSUPP;
507 LOG_ERR_2("negative_write_request",
508 "entry '%s' performs lookups by itself: "
509 "can't write to it", write_request->entry);
512 #ifdef NS_NSCD_EID_CHECKING
513 if (check_query_eids(qstate) != 0) {
514 write_response->error_code = EPERM;
520 configuration_lock_rdlock(s_configuration);
521 c_entry = find_cache_entry(s_cache,
522 qstate->config_entry->negative_cache_params.cep.entry_name);
523 configuration_unlock(s_configuration);
524 if (c_entry != NULL) {
525 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
526 qstate->config_entry->negative_cache_entry = c_entry;
527 write_response->error_code = cache_write(c_entry,
528 write_request->cache_key,
529 write_request->cache_key_size,
531 sizeof(negative_data));
532 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
534 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
535 (qstate->config_entry->common_query_timeout.tv_usec != 0))
536 memcpy(&qstate->timeout,
537 &qstate->config_entry->common_query_timeout,
538 sizeof(struct timeval));
540 write_response->error_code = -1;
543 qstate->kevent_filter = EVFILT_WRITE;
544 qstate->kevent_watermark = sizeof(int);
545 qstate->process_func = on_write_response_write1;
547 TRACE_OUT(on_negative_write_request_process);
552 on_write_response_write1(struct query_state *qstate)
554 struct cache_write_response *write_response;
557 TRACE_IN(on_write_response_write1);
558 write_response = get_cache_write_response(&qstate->response);
559 result = qstate->write_func(qstate, &write_response->error_code,
561 if (result != sizeof(int)) {
562 TRACE_OUT(on_write_response_write1);
566 finalize_comm_element(&qstate->request);
567 finalize_comm_element(&qstate->response);
569 qstate->kevent_watermark = sizeof(int);
570 qstate->kevent_filter = EVFILT_READ;
571 qstate->process_func = on_rw_mapper;
573 TRACE_OUT(on_write_response_write1);
578 * The functions below are used to process read requests.
579 * - on_read_request_read1 and on_read_request_read2 read the request itself
580 * - on_read_request_process processes it
581 * - on_read_response_write1 and on_read_response_write2 send the response
584 on_read_request_read1(struct query_state *qstate)
586 struct cache_read_request *read_request;
589 TRACE_IN(on_read_request_read1);
590 if (qstate->kevent_watermark == 0)
591 qstate->kevent_watermark = sizeof(size_t) * 2;
593 init_comm_element(&qstate->request, CET_READ_REQUEST);
594 read_request = get_cache_read_request(&qstate->request);
596 result = qstate->read_func(qstate,
597 &read_request->entry_length, sizeof(size_t));
598 result += qstate->read_func(qstate,
599 &read_request->cache_key_size, sizeof(size_t));
601 if (result != sizeof(size_t) * 2) {
602 TRACE_OUT(on_read_request_read1);
606 if (BUFSIZE_INVALID(read_request->entry_length) ||
607 BUFSIZE_INVALID(read_request->cache_key_size)) {
608 TRACE_OUT(on_read_request_read1);
612 read_request->entry = calloc(1,
613 read_request->entry_length + 1);
614 assert(read_request->entry != NULL);
616 read_request->cache_key = calloc(1,
617 read_request->cache_key_size +
618 qstate->eid_str_length);
619 assert(read_request->cache_key != NULL);
620 memcpy(read_request->cache_key, qstate->eid_str,
621 qstate->eid_str_length);
623 qstate->kevent_watermark = read_request->entry_length +
624 read_request->cache_key_size;
625 qstate->process_func = on_read_request_read2;
628 TRACE_OUT(on_read_request_read1);
633 on_read_request_read2(struct query_state *qstate)
635 struct cache_read_request *read_request;
638 TRACE_IN(on_read_request_read2);
639 read_request = get_cache_read_request(&qstate->request);
641 result = qstate->read_func(qstate, read_request->entry,
642 read_request->entry_length);
643 result += qstate->read_func(qstate,
644 read_request->cache_key + qstate->eid_str_length,
645 read_request->cache_key_size);
647 if (result != (ssize_t)qstate->kevent_watermark) {
648 TRACE_OUT(on_read_request_read2);
651 read_request->cache_key_size += qstate->eid_str_length;
653 qstate->kevent_watermark = 0;
654 qstate->process_func = on_read_request_process;
656 TRACE_OUT(on_read_request_read2);
661 on_read_request_process(struct query_state *qstate)
663 struct cache_read_request *read_request;
664 struct cache_read_response *read_response;
665 cache_entry c_entry, neg_c_entry;
667 struct agent *lookup_agent;
668 struct common_agent *c_agent;
671 TRACE_IN(on_read_request_process);
672 init_comm_element(&qstate->response, CET_READ_RESPONSE);
673 read_response = get_cache_read_response(&qstate->response);
674 read_request = get_cache_read_request(&qstate->request);
676 qstate->config_entry = configuration_find_entry(
677 s_configuration, read_request->entry);
678 if (qstate->config_entry == NULL) {
679 read_response->error_code = ENOENT;
681 LOG_ERR_2("read_request",
682 "can't find configuration "
683 "entry '%s'. aborting request", read_request->entry);
687 if (qstate->config_entry->enabled == 0) {
688 read_response->error_code = EACCES;
690 LOG_ERR_2("read_request",
691 "configuration entry '%s' is disabled",
692 read_request->entry);
697 * if we perform lookups by ourselves, then we don't need to separate
698 * cache entries by euid and egid
700 if (qstate->config_entry->perform_actual_lookups != 0)
701 memset(read_request->cache_key, 0, qstate->eid_str_length);
703 #ifdef NS_NSCD_EID_CHECKING
704 if (check_query_eids(qstate) != 0) {
705 /* if the lookup is not self-performing, we check for clients euid/egid */
706 read_response->error_code = EPERM;
712 configuration_lock_rdlock(s_configuration);
713 c_entry = find_cache_entry(s_cache,
714 qstate->config_entry->positive_cache_params.cep.entry_name);
715 neg_c_entry = find_cache_entry(s_cache,
716 qstate->config_entry->negative_cache_params.cep.entry_name);
717 configuration_unlock(s_configuration);
718 if ((c_entry != NULL) && (neg_c_entry != NULL)) {
719 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
720 qstate->config_entry->positive_cache_entry = c_entry;
721 read_response->error_code = cache_read(c_entry,
722 read_request->cache_key,
723 read_request->cache_key_size, NULL,
724 &read_response->data_size);
726 if (read_response->error_code == -2) {
727 read_response->data = malloc(
728 read_response->data_size);
729 assert(read_response->data != NULL);
730 read_response->error_code = cache_read(c_entry,
731 read_request->cache_key,
732 read_request->cache_key_size,
734 &read_response->data_size);
736 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
738 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
739 qstate->config_entry->negative_cache_entry = neg_c_entry;
740 if (read_response->error_code == -1) {
741 read_response->error_code = cache_read(neg_c_entry,
742 read_request->cache_key,
743 read_request->cache_key_size, NULL,
744 &read_response->data_size);
746 if (read_response->error_code == -2) {
747 read_response->data = malloc(
748 read_response->data_size);
749 assert(read_response->data != NULL);
750 read_response->error_code = cache_read(neg_c_entry,
751 read_request->cache_key,
752 read_request->cache_key_size,
754 &read_response->data_size);
757 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
759 if ((read_response->error_code == -1) &&
760 (qstate->config_entry->perform_actual_lookups != 0)) {
761 free(read_response->data);
762 read_response->data = NULL;
763 read_response->data_size = 0;
765 lookup_agent = find_agent(s_agent_table,
766 read_request->entry, COMMON_AGENT);
768 if ((lookup_agent != NULL) &&
769 (lookup_agent->type == COMMON_AGENT)) {
770 c_agent = (struct common_agent *)lookup_agent;
771 res = c_agent->lookup_func(
772 read_request->cache_key +
773 qstate->eid_str_length,
774 read_request->cache_key_size -
775 qstate->eid_str_length,
776 &read_response->data,
777 &read_response->data_size);
779 if (res == NS_SUCCESS) {
780 read_response->error_code = 0;
781 configuration_lock_entry(
782 qstate->config_entry,
785 read_request->cache_key,
786 read_request->cache_key_size,
788 read_response->data_size);
789 configuration_unlock_entry(
790 qstate->config_entry,
792 } else if ((res == NS_NOTFOUND) ||
793 (res == NS_RETURN)) {
794 configuration_lock_entry(
795 qstate->config_entry,
797 cache_write(neg_c_entry,
798 read_request->cache_key,
799 read_request->cache_key_size,
801 sizeof(negative_data));
802 configuration_unlock_entry(
803 qstate->config_entry,
806 read_response->error_code = 0;
807 read_response->data = NULL;
808 read_response->data_size = 0;
813 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
814 (qstate->config_entry->common_query_timeout.tv_usec != 0))
815 memcpy(&qstate->timeout,
816 &qstate->config_entry->common_query_timeout,
817 sizeof(struct timeval));
819 read_response->error_code = -1;
822 qstate->kevent_filter = EVFILT_WRITE;
823 if (read_response->error_code == 0)
824 qstate->kevent_watermark = sizeof(int) + sizeof(size_t);
826 qstate->kevent_watermark = sizeof(int);
827 qstate->process_func = on_read_response_write1;
829 TRACE_OUT(on_read_request_process);
834 on_read_response_write1(struct query_state *qstate)
836 struct cache_read_response *read_response;
839 TRACE_IN(on_read_response_write1);
840 read_response = get_cache_read_response(&qstate->response);
842 result = qstate->write_func(qstate, &read_response->error_code,
845 if (read_response->error_code == 0) {
846 result += qstate->write_func(qstate, &read_response->data_size,
848 if (result != (ssize_t)qstate->kevent_watermark) {
849 TRACE_OUT(on_read_response_write1);
853 qstate->kevent_watermark = read_response->data_size;
854 qstate->process_func = on_read_response_write2;
856 if (result != (ssize_t)qstate->kevent_watermark) {
857 TRACE_OUT(on_read_response_write1);
861 qstate->kevent_watermark = 0;
862 qstate->process_func = NULL;
865 TRACE_OUT(on_read_response_write1);
870 on_read_response_write2(struct query_state *qstate)
872 struct cache_read_response *read_response;
875 TRACE_IN(on_read_response_write2);
876 read_response = get_cache_read_response(&qstate->response);
877 if (read_response->data_size > 0) {
878 result = qstate->write_func(qstate, read_response->data,
879 read_response->data_size);
880 if (result != (ssize_t)qstate->kevent_watermark) {
881 TRACE_OUT(on_read_response_write2);
886 finalize_comm_element(&qstate->request);
887 finalize_comm_element(&qstate->response);
889 qstate->kevent_watermark = sizeof(int);
890 qstate->kevent_filter = EVFILT_READ;
891 qstate->process_func = on_rw_mapper;
892 TRACE_OUT(on_read_response_write2);
897 * The functions below are used to process write requests.
898 * - on_transform_request_read1 and on_transform_request_read2 read the
900 * - on_transform_request_process processes it
901 * - on_transform_response_write1 sends the response
904 on_transform_request_read1(struct query_state *qstate)
906 struct cache_transform_request *transform_request;
909 TRACE_IN(on_transform_request_read1);
910 if (qstate->kevent_watermark == 0)
911 qstate->kevent_watermark = sizeof(size_t) + sizeof(int);
913 init_comm_element(&qstate->request, CET_TRANSFORM_REQUEST);
915 get_cache_transform_request(&qstate->request);
917 result = qstate->read_func(qstate,
918 &transform_request->entry_length, sizeof(size_t));
919 result += qstate->read_func(qstate,
920 &transform_request->transformation_type, sizeof(int));
922 if (result != sizeof(size_t) + sizeof(int)) {
923 TRACE_OUT(on_transform_request_read1);
927 if ((transform_request->transformation_type != TT_USER) &&
928 (transform_request->transformation_type != TT_ALL)) {
929 TRACE_OUT(on_transform_request_read1);
933 if (transform_request->entry_length != 0) {
934 if (BUFSIZE_INVALID(transform_request->entry_length)) {
935 TRACE_OUT(on_transform_request_read1);
939 transform_request->entry = calloc(1,
940 transform_request->entry_length + 1);
941 assert(transform_request->entry != NULL);
943 qstate->process_func = on_transform_request_read2;
945 qstate->process_func = on_transform_request_process;
947 qstate->kevent_watermark = transform_request->entry_length;
950 TRACE_OUT(on_transform_request_read1);
955 on_transform_request_read2(struct query_state *qstate)
957 struct cache_transform_request *transform_request;
960 TRACE_IN(on_transform_request_read2);
961 transform_request = get_cache_transform_request(&qstate->request);
963 result = qstate->read_func(qstate, transform_request->entry,
964 transform_request->entry_length);
966 if (result != (ssize_t)qstate->kevent_watermark) {
967 TRACE_OUT(on_transform_request_read2);
971 qstate->kevent_watermark = 0;
972 qstate->process_func = on_transform_request_process;
974 TRACE_OUT(on_transform_request_read2);
979 on_transform_request_process(struct query_state *qstate)
981 struct cache_transform_request *transform_request;
982 struct cache_transform_response *transform_response;
983 struct configuration_entry *config_entry;
986 TRACE_IN(on_transform_request_process);
987 init_comm_element(&qstate->response, CET_TRANSFORM_RESPONSE);
988 transform_response = get_cache_transform_response(&qstate->response);
989 transform_request = get_cache_transform_request(&qstate->request);
991 switch (transform_request->transformation_type) {
993 if (transform_request->entry == NULL) {
994 size = configuration_get_entries_size(s_configuration);
995 for (i = 0; i < size; ++i) {
996 config_entry = configuration_get_entry(
999 if (config_entry->perform_actual_lookups == 0)
1000 clear_config_entry_part(config_entry,
1001 qstate->eid_str, qstate->eid_str_length);
1004 qstate->config_entry = configuration_find_entry(
1005 s_configuration, transform_request->entry);
1007 if (qstate->config_entry == NULL) {
1008 LOG_ERR_2("transform_request",
1009 "can't find configuration"
1010 " entry '%s'. aborting request",
1011 transform_request->entry);
1012 transform_response->error_code = -1;
1016 if (qstate->config_entry->perform_actual_lookups != 0) {
1017 LOG_ERR_2("transform_request",
1018 "can't transform the cache entry %s"
1019 ", because it ised for actual lookups",
1020 transform_request->entry);
1021 transform_response->error_code = -1;
1025 clear_config_entry_part(qstate->config_entry,
1026 qstate->eid_str, qstate->eid_str_length);
1030 if (qstate->euid != 0)
1031 transform_response->error_code = -1;
1033 if (transform_request->entry == NULL) {
1034 size = configuration_get_entries_size(
1036 for (i = 0; i < size; ++i) {
1038 configuration_get_entry(
1039 s_configuration, i));
1042 qstate->config_entry = configuration_find_entry(
1044 transform_request->entry);
1046 if (qstate->config_entry == NULL) {
1047 LOG_ERR_2("transform_request",
1048 "can't find configuration"
1049 " entry '%s'. aborting request",
1050 transform_request->entry);
1051 transform_response->error_code = -1;
1055 clear_config_entry(qstate->config_entry);
1060 transform_response->error_code = -1;
1064 qstate->kevent_watermark = 0;
1065 qstate->process_func = on_transform_response_write1;
1066 TRACE_OUT(on_transform_request_process);
1071 on_transform_response_write1(struct query_state *qstate)
1073 struct cache_transform_response *transform_response;
1076 TRACE_IN(on_transform_response_write1);
1077 transform_response = get_cache_transform_response(&qstate->response);
1078 result = qstate->write_func(qstate, &transform_response->error_code,
1080 if (result != sizeof(int)) {
1081 TRACE_OUT(on_transform_response_write1);
1085 finalize_comm_element(&qstate->request);
1086 finalize_comm_element(&qstate->response);
1088 qstate->kevent_watermark = 0;
1089 qstate->process_func = NULL;
1090 TRACE_OUT(on_transform_response_write1);
1095 * Checks if the client's euid and egid do not differ from its uid and gid.
1096 * Returns 0 on success.
1099 check_query_eids(struct query_state *qstate)
1102 return ((qstate->uid != qstate->euid) || (qstate->gid != qstate->egid) ? -1 : 0);
1106 * Uses the qstate fields to process an "alternate" read - when the buffer is
1107 * too large to be received during one socket read operation
1110 query_io_buffer_read(struct query_state *qstate, void *buf, size_t nbytes)
1115 TRACE_IN(query_io_buffer_read);
1116 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1119 assert(qstate->io_buffer_p <=
1120 qstate->io_buffer + qstate->io_buffer_size);
1121 remaining = qstate->io_buffer + qstate->io_buffer_size -
1122 qstate->io_buffer_p;
1123 if (nbytes < remaining)
1128 memcpy(buf, qstate->io_buffer_p, result);
1129 qstate->io_buffer_p += result;
1131 if (remaining == 0) {
1132 free(qstate->io_buffer);
1133 qstate->io_buffer = NULL;
1135 qstate->write_func = query_socket_write;
1136 qstate->read_func = query_socket_read;
1139 TRACE_OUT(query_io_buffer_read);
1144 * Uses the qstate fields to process an "alternate" write - when the buffer is
1145 * too large to be sent during one socket write operation
1148 query_io_buffer_write(struct query_state *qstate, const void *buf,
1154 TRACE_IN(query_io_buffer_write);
1155 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1158 assert(qstate->io_buffer_p <=
1159 qstate->io_buffer + qstate->io_buffer_size);
1160 remaining = qstate->io_buffer + qstate->io_buffer_size -
1161 qstate->io_buffer_p;
1162 if (nbytes < remaining)
1167 memcpy(qstate->io_buffer_p, buf, result);
1168 qstate->io_buffer_p += result;
1170 if (remaining == 0) {
1171 qstate->use_alternate_io = 1;
1172 qstate->io_buffer_p = qstate->io_buffer;
1174 qstate->write_func = query_socket_write;
1175 qstate->read_func = query_socket_read;
1178 TRACE_OUT(query_io_buffer_write);
1183 * The default "read" function, which reads data directly from socket
1186 query_socket_read(struct query_state *qstate, void *buf, size_t nbytes)
1190 TRACE_IN(query_socket_read);
1191 if (qstate->socket_failed != 0) {
1192 TRACE_OUT(query_socket_read);
1196 result = read(qstate->sockfd, buf, nbytes);
1197 if (result < 0 || (size_t)result < nbytes)
1198 qstate->socket_failed = 1;
1200 TRACE_OUT(query_socket_read);
1205 * The default "write" function, which writes data directly to socket
1208 query_socket_write(struct query_state *qstate, const void *buf, size_t nbytes)
1212 TRACE_IN(query_socket_write);
1213 if (qstate->socket_failed != 0) {
1214 TRACE_OUT(query_socket_write);
1218 result = write(qstate->sockfd, buf, nbytes);
1219 if (result < 0 || (size_t)result < nbytes)
1220 qstate->socket_failed = 1;
1222 TRACE_OUT(query_socket_write);
1227 * Initializes the query_state structure by filling it with the default values.
1229 struct query_state *
1230 init_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t egid)
1232 struct query_state *retval;
1234 TRACE_IN(init_query_state);
1235 retval = calloc(1, sizeof(*retval));
1236 assert(retval != NULL);
1238 retval->sockfd = sockfd;
1239 retval->kevent_filter = EVFILT_READ;
1240 retval->kevent_watermark = kevent_watermark;
1242 retval->euid = euid;
1243 retval->egid = egid;
1244 retval->uid = retval->gid = -1;
1246 if (asprintf(&retval->eid_str, "%d_%d_", retval->euid,
1247 retval->egid) == -1) {
1251 retval->eid_str_length = strlen(retval->eid_str);
1253 init_comm_element(&retval->request, CET_UNDEFINED);
1254 init_comm_element(&retval->response, CET_UNDEFINED);
1255 retval->process_func = on_query_startup;
1256 retval->destroy_func = on_query_destroy;
1258 retval->write_func = query_socket_write;
1259 retval->read_func = query_socket_read;
1261 get_time_func(&retval->creation_time);
1262 retval->timeout.tv_sec = s_configuration->query_timeout;
1263 retval->timeout.tv_usec = 0;
1265 TRACE_OUT(init_query_state);
1270 destroy_query_state(struct query_state *qstate)
1273 TRACE_IN(destroy_query_state);
1274 if (qstate->eid_str != NULL)
1275 free(qstate->eid_str);
1277 if (qstate->io_buffer != NULL)
1278 free(qstate->io_buffer);
1280 qstate->destroy_func(qstate);
1282 TRACE_OUT(destroy_query_state);