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/socket.h>
34 #include <sys/event.h>
45 #include "mp_ws_query.h"
46 #include "mp_rs_query.h"
47 #include "singletons.h"
49 static const char negative_data[1] = { 0 };
51 extern void get_time_func(struct timeval *);
53 static void clear_config_entry(struct configuration_entry *);
54 static void clear_config_entry_part(struct configuration_entry *,
55 const char *, size_t);
57 static int on_query_startup(struct query_state *);
58 static void on_query_destroy(struct query_state *);
60 static int on_read_request_read1(struct query_state *);
61 static int on_read_request_read2(struct query_state *);
62 static int on_read_request_process(struct query_state *);
63 static int on_read_response_write1(struct query_state *);
64 static int on_read_response_write2(struct query_state *);
66 static int on_rw_mapper(struct query_state *);
68 static int on_transform_request_read1(struct query_state *);
69 static int on_transform_request_read2(struct query_state *);
70 static int on_transform_request_process(struct query_state *);
71 static int on_transform_response_write1(struct query_state *);
73 static int on_write_request_read1(struct query_state *);
74 static int on_write_request_read2(struct query_state *);
75 static int on_negative_write_request_process(struct query_state *);
76 static int on_write_request_process(struct query_state *);
77 static int on_write_response_write1(struct query_state *);
80 * Clears the specified configuration entry (clears the cache for positive and
81 * and negative entries) and also for all multipart entries.
84 clear_config_entry(struct configuration_entry *config_entry)
88 TRACE_IN(clear_config_entry);
89 configuration_lock_entry(config_entry, CELT_POSITIVE);
90 if (config_entry->positive_cache_entry != NULL)
91 transform_cache_entry(
92 config_entry->positive_cache_entry,
94 configuration_unlock_entry(config_entry, CELT_POSITIVE);
96 configuration_lock_entry(config_entry, CELT_NEGATIVE);
97 if (config_entry->negative_cache_entry != NULL)
98 transform_cache_entry(
99 config_entry->negative_cache_entry,
101 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
103 configuration_lock_entry(config_entry, CELT_MULTIPART);
104 for (i = 0; i < config_entry->mp_cache_entries_size; ++i)
105 transform_cache_entry(
106 config_entry->mp_cache_entries[i],
108 configuration_unlock_entry(config_entry, CELT_MULTIPART);
110 TRACE_OUT(clear_config_entry);
114 * Clears the specified configuration entry by deleting only the elements,
115 * that are owned by the user with specified eid_str.
118 clear_config_entry_part(struct configuration_entry *config_entry,
119 const char *eid_str, size_t eid_str_length)
121 cache_entry *start, *finish, *mp_entry;
122 TRACE_IN(clear_config_entry_part);
123 configuration_lock_entry(config_entry, CELT_POSITIVE);
124 if (config_entry->positive_cache_entry != NULL)
125 transform_cache_entry_part(
126 config_entry->positive_cache_entry,
127 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
128 configuration_unlock_entry(config_entry, CELT_POSITIVE);
130 configuration_lock_entry(config_entry, CELT_NEGATIVE);
131 if (config_entry->negative_cache_entry != NULL)
132 transform_cache_entry_part(
133 config_entry->negative_cache_entry,
134 CTT_CLEAR, eid_str, eid_str_length, KPPT_LEFT);
135 configuration_unlock_entry(config_entry, CELT_NEGATIVE);
137 configuration_lock_entry(config_entry, CELT_MULTIPART);
138 if (configuration_entry_find_mp_cache_entries(config_entry,
139 eid_str, &start, &finish) == 0) {
140 for (mp_entry = start; mp_entry != finish; ++mp_entry)
141 transform_cache_entry(*mp_entry, CTT_CLEAR);
143 configuration_unlock_entry(config_entry, CELT_MULTIPART);
145 TRACE_OUT(clear_config_entry_part);
149 * This function is assigned to the query_state structue on its creation.
150 * It's main purpose is to receive credentials from the client.
153 on_query_startup(struct query_state *qstate)
155 struct msghdr cred_hdr;
157 struct cmsgcred *cred;
162 char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
165 TRACE_IN(on_query_startup);
166 assert(qstate != NULL);
168 memset(&cred_hdr, 0, sizeof(struct msghdr));
169 cred_hdr.msg_iov = &iov;
170 cred_hdr.msg_iovlen = 1;
171 cred_hdr.msg_control = (caddr_t)&cmsg;
172 cred_hdr.msg_controllen = CMSG_LEN(sizeof(struct cmsgcred));
174 memset(&iov, 0, sizeof(struct iovec));
175 iov.iov_base = &elem_type;
176 iov.iov_len = sizeof(int);
178 if (recvmsg(qstate->sockfd, &cred_hdr, 0) == -1) {
179 TRACE_OUT(on_query_startup);
183 if (cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(struct cmsgcred))
184 || cmsg.hdr.cmsg_level != SOL_SOCKET
185 || cmsg.hdr.cmsg_type != SCM_CREDS) {
186 TRACE_OUT(on_query_startup);
190 cred = (struct cmsgcred *)CMSG_DATA(&cmsg);
191 qstate->uid = cred->cmcred_uid;
192 qstate->gid = cred->cmcred_gid;
194 #if defined(NS_NSCD_EID_CHECKING) || defined(NS_STRICT_NSCD_EID_CHECKING)
196 * This check is probably a bit redundant - per-user cache is always separated
197 * by the euid/egid pair
199 if (check_query_eids(qstate) != 0) {
200 #ifdef NS_STRICT_NSCD_EID_CHECKING
201 TRACE_OUT(on_query_startup);
204 if ((elem_type != CET_READ_REQUEST) &&
205 (elem_type != CET_MP_READ_SESSION_REQUEST) &&
206 (elem_type != CET_WRITE_REQUEST) &&
207 (elem_type != CET_MP_WRITE_SESSION_REQUEST)) {
208 TRACE_OUT(on_query_startup);
216 case CET_WRITE_REQUEST:
217 qstate->process_func = on_write_request_read1;
219 case CET_READ_REQUEST:
220 qstate->process_func = on_read_request_read1;
222 case CET_TRANSFORM_REQUEST:
223 qstate->process_func = on_transform_request_read1;
225 case CET_MP_WRITE_SESSION_REQUEST:
226 qstate->process_func = on_mp_write_session_request_read1;
228 case CET_MP_READ_SESSION_REQUEST:
229 qstate->process_func = on_mp_read_session_request_read1;
232 TRACE_OUT(on_query_startup);
236 qstate->kevent_watermark = 0;
237 TRACE_OUT(on_query_startup);
242 * on_rw_mapper is used to process multiple read/write requests during
243 * one connection session. It's never called in the beginning (on query_state
244 * creation) as it does not process the multipart requests and does not
245 * receive credentials
248 on_rw_mapper(struct query_state *qstate)
253 TRACE_IN(on_rw_mapper);
254 if (qstate->kevent_watermark == 0) {
255 qstate->kevent_watermark = sizeof(int);
257 result = qstate->read_func(qstate, &elem_type, sizeof(int));
258 if (result != sizeof(int)) {
259 TRACE_OUT(on_rw_mapper);
264 case CET_WRITE_REQUEST:
265 qstate->kevent_watermark = sizeof(size_t);
266 qstate->process_func = on_write_request_read1;
268 case CET_READ_REQUEST:
269 qstate->kevent_watermark = sizeof(size_t);
270 qstate->process_func = on_read_request_read1;
273 TRACE_OUT(on_rw_mapper);
278 TRACE_OUT(on_rw_mapper);
283 * The default query_destroy function
286 on_query_destroy(struct query_state *qstate)
289 TRACE_IN(on_query_destroy);
290 finalize_comm_element(&qstate->response);
291 finalize_comm_element(&qstate->request);
292 TRACE_OUT(on_query_destroy);
296 * The functions below are used to process write requests.
297 * - on_write_request_read1 and on_write_request_read2 read the request itself
298 * - on_write_request_process processes it (if the client requests to
299 * cache the negative result, the on_negative_write_request_process is used)
300 * - on_write_response_write1 sends the response
303 on_write_request_read1(struct query_state *qstate)
305 struct cache_write_request *write_request;
308 TRACE_IN(on_write_request_read1);
309 if (qstate->kevent_watermark == 0)
310 qstate->kevent_watermark = sizeof(size_t) * 3;
312 init_comm_element(&qstate->request, CET_WRITE_REQUEST);
313 write_request = get_cache_write_request(&qstate->request);
315 result = qstate->read_func(qstate, &write_request->entry_length,
317 result += qstate->read_func(qstate,
318 &write_request->cache_key_size, sizeof(size_t));
319 result += qstate->read_func(qstate,
320 &write_request->data_size, sizeof(size_t));
322 if (result != sizeof(size_t) * 3) {
323 TRACE_OUT(on_write_request_read1);
327 if (BUFSIZE_INVALID(write_request->entry_length) ||
328 BUFSIZE_INVALID(write_request->cache_key_size) ||
329 (BUFSIZE_INVALID(write_request->data_size) &&
330 (write_request->data_size != 0))) {
331 TRACE_OUT(on_write_request_read1);
335 write_request->entry = (char *)malloc(
336 write_request->entry_length + 1);
337 assert(write_request->entry != NULL);
338 memset(write_request->entry, 0,
339 write_request->entry_length + 1);
341 write_request->cache_key = (char *)malloc(
342 write_request->cache_key_size +
343 qstate->eid_str_length);
344 assert(write_request->cache_key != NULL);
345 memcpy(write_request->cache_key, qstate->eid_str,
346 qstate->eid_str_length);
347 memset(write_request->cache_key + qstate->eid_str_length, 0,
348 write_request->cache_key_size);
350 if (write_request->data_size != 0) {
351 write_request->data = (char *)malloc(
352 write_request->data_size);
353 assert(write_request->data != NULL);
354 memset(write_request->data, 0,
355 write_request->data_size);
358 qstate->kevent_watermark = write_request->entry_length +
359 write_request->cache_key_size +
360 write_request->data_size;
361 qstate->process_func = on_write_request_read2;
364 TRACE_OUT(on_write_request_read1);
369 on_write_request_read2(struct query_state *qstate)
371 struct cache_write_request *write_request;
374 TRACE_IN(on_write_request_read2);
375 write_request = get_cache_write_request(&qstate->request);
377 result = qstate->read_func(qstate, write_request->entry,
378 write_request->entry_length);
379 result += qstate->read_func(qstate, write_request->cache_key +
380 qstate->eid_str_length, write_request->cache_key_size);
381 if (write_request->data_size != 0)
382 result += qstate->read_func(qstate, write_request->data,
383 write_request->data_size);
385 if (result != qstate->kevent_watermark) {
386 TRACE_OUT(on_write_request_read2);
389 write_request->cache_key_size += qstate->eid_str_length;
391 qstate->kevent_watermark = 0;
392 if (write_request->data_size != 0)
393 qstate->process_func = on_write_request_process;
395 qstate->process_func = on_negative_write_request_process;
396 TRACE_OUT(on_write_request_read2);
401 on_write_request_process(struct query_state *qstate)
403 struct cache_write_request *write_request;
404 struct cache_write_response *write_response;
407 TRACE_IN(on_write_request_process);
408 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
409 write_response = get_cache_write_response(&qstate->response);
410 write_request = get_cache_write_request(&qstate->request);
412 qstate->config_entry = configuration_find_entry(
413 s_configuration, write_request->entry);
415 if (qstate->config_entry == NULL) {
416 write_response->error_code = ENOENT;
418 LOG_ERR_2("write_request", "can't find configuration"
419 " entry '%s'. aborting request", write_request->entry);
423 if (qstate->config_entry->enabled == 0) {
424 write_response->error_code = EACCES;
426 LOG_ERR_2("write_request",
427 "configuration entry '%s' is disabled",
428 write_request->entry);
432 if (qstate->config_entry->perform_actual_lookups != 0) {
433 write_response->error_code = EOPNOTSUPP;
435 LOG_ERR_2("write_request",
436 "entry '%s' performs lookups by itself: "
437 "can't write to it", write_request->entry);
441 configuration_lock_rdlock(s_configuration);
442 c_entry = find_cache_entry(s_cache,
443 qstate->config_entry->positive_cache_params.entry_name);
444 configuration_unlock(s_configuration);
445 if (c_entry != NULL) {
446 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
447 qstate->config_entry->positive_cache_entry = c_entry;
448 write_response->error_code = cache_write(c_entry,
449 write_request->cache_key,
450 write_request->cache_key_size,
452 write_request->data_size);
453 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
455 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
456 (qstate->config_entry->common_query_timeout.tv_usec != 0))
457 memcpy(&qstate->timeout,
458 &qstate->config_entry->common_query_timeout,
459 sizeof(struct timeval));
462 write_response->error_code = -1;
465 qstate->kevent_filter = EVFILT_WRITE;
466 qstate->kevent_watermark = sizeof(int);
467 qstate->process_func = on_write_response_write1;
469 TRACE_OUT(on_write_request_process);
474 on_negative_write_request_process(struct query_state *qstate)
476 struct cache_write_request *write_request;
477 struct cache_write_response *write_response;
480 TRACE_IN(on_negative_write_request_process);
481 init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
482 write_response = get_cache_write_response(&qstate->response);
483 write_request = get_cache_write_request(&qstate->request);
485 qstate->config_entry = configuration_find_entry (
486 s_configuration, write_request->entry);
488 if (qstate->config_entry == NULL) {
489 write_response->error_code = ENOENT;
491 LOG_ERR_2("negative_write_request",
492 "can't find configuration"
493 " entry '%s'. aborting request", write_request->entry);
497 if (qstate->config_entry->enabled == 0) {
498 write_response->error_code = EACCES;
500 LOG_ERR_2("negative_write_request",
501 "configuration entry '%s' is disabled",
502 write_request->entry);
506 if (qstate->config_entry->perform_actual_lookups != 0) {
507 write_response->error_code = EOPNOTSUPP;
509 LOG_ERR_2("negative_write_request",
510 "entry '%s' performs lookups by itself: "
511 "can't write to it", write_request->entry);
514 #ifdef NS_NSCD_EID_CHECKING
515 if (check_query_eids(qstate) != 0) {
516 write_response->error_code = EPERM;
522 configuration_lock_rdlock(s_configuration);
523 c_entry = find_cache_entry(s_cache,
524 qstate->config_entry->negative_cache_params.entry_name);
525 configuration_unlock(s_configuration);
526 if (c_entry != NULL) {
527 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
528 qstate->config_entry->negative_cache_entry = c_entry;
529 write_response->error_code = cache_write(c_entry,
530 write_request->cache_key,
531 write_request->cache_key_size,
533 sizeof(negative_data));
534 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);
536 if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
537 (qstate->config_entry->common_query_timeout.tv_usec != 0))
538 memcpy(&qstate->timeout,
539 &qstate->config_entry->common_query_timeout,
540 sizeof(struct timeval));
542 write_response->error_code = -1;
545 qstate->kevent_filter = EVFILT_WRITE;
546 qstate->kevent_watermark = sizeof(int);
547 qstate->process_func = on_write_response_write1;
549 TRACE_OUT(on_negative_write_request_process);
554 on_write_response_write1(struct query_state *qstate)
556 struct cache_write_response *write_response;
559 TRACE_IN(on_write_response_write1);
560 write_response = get_cache_write_response(&qstate->response);
561 result = qstate->write_func(qstate, &write_response->error_code,
563 if (result != sizeof(int)) {
564 TRACE_OUT(on_write_response_write1);
568 finalize_comm_element(&qstate->request);
569 finalize_comm_element(&qstate->response);
571 qstate->kevent_watermark = sizeof(int);
572 qstate->kevent_filter = EVFILT_READ;
573 qstate->process_func = on_rw_mapper;
575 TRACE_OUT(on_write_response_write1);
580 * The functions below are used to process read requests.
581 * - on_read_request_read1 and on_read_request_read2 read the request itself
582 * - on_read_request_process processes it
583 * - on_read_response_write1 and on_read_response_write2 send the response
586 on_read_request_read1(struct query_state *qstate)
588 struct cache_read_request *read_request;
591 TRACE_IN(on_read_request_read1);
592 if (qstate->kevent_watermark == 0)
593 qstate->kevent_watermark = sizeof(size_t) * 2;
595 init_comm_element(&qstate->request, CET_READ_REQUEST);
596 read_request = get_cache_read_request(&qstate->request);
598 result = qstate->read_func(qstate,
599 &read_request->entry_length, sizeof(size_t));
600 result += qstate->read_func(qstate,
601 &read_request->cache_key_size, sizeof(size_t));
603 if (result != sizeof(size_t) * 2) {
604 TRACE_OUT(on_read_request_read1);
608 if (BUFSIZE_INVALID(read_request->entry_length) ||
609 BUFSIZE_INVALID(read_request->cache_key_size)) {
610 TRACE_OUT(on_read_request_read1);
614 read_request->entry = (char *)malloc(
615 read_request->entry_length + 1);
616 assert(read_request->entry != NULL);
617 memset(read_request->entry, 0, read_request->entry_length + 1);
619 read_request->cache_key = (char *)malloc(
620 read_request->cache_key_size +
621 qstate->eid_str_length);
622 assert(read_request->cache_key != NULL);
623 memcpy(read_request->cache_key, qstate->eid_str,
624 qstate->eid_str_length);
625 memset(read_request->cache_key + qstate->eid_str_length, 0,
626 read_request->cache_key_size);
628 qstate->kevent_watermark = read_request->entry_length +
629 read_request->cache_key_size;
630 qstate->process_func = on_read_request_read2;
633 TRACE_OUT(on_read_request_read1);
638 on_read_request_read2(struct query_state *qstate)
640 struct cache_read_request *read_request;
643 TRACE_IN(on_read_request_read2);
644 read_request = get_cache_read_request(&qstate->request);
646 result = qstate->read_func(qstate, read_request->entry,
647 read_request->entry_length);
648 result += qstate->read_func(qstate,
649 read_request->cache_key + qstate->eid_str_length,
650 read_request->cache_key_size);
652 if (result != qstate->kevent_watermark) {
653 TRACE_OUT(on_read_request_read2);
656 read_request->cache_key_size += qstate->eid_str_length;
658 qstate->kevent_watermark = 0;
659 qstate->process_func = on_read_request_process;
661 TRACE_OUT(on_read_request_read2);
666 on_read_request_process(struct query_state *qstate)
668 struct cache_read_request *read_request;
669 struct cache_read_response *read_response;
670 cache_entry c_entry, neg_c_entry;
672 struct agent *lookup_agent;
673 struct common_agent *c_agent;
676 TRACE_IN(on_read_request_process);
677 init_comm_element(&qstate->response, CET_READ_RESPONSE);
678 read_response = get_cache_read_response(&qstate->response);
679 read_request = get_cache_read_request(&qstate->request);
681 qstate->config_entry = configuration_find_entry(
682 s_configuration, read_request->entry);
683 if (qstate->config_entry == NULL) {
684 read_response->error_code = ENOENT;
686 LOG_ERR_2("read_request",
687 "can't find configuration "
688 "entry '%s'. aborting request", read_request->entry);
692 if (qstate->config_entry->enabled == 0) {
693 read_response->error_code = EACCES;
695 LOG_ERR_2("read_request",
696 "configuration entry '%s' is disabled",
697 read_request->entry);
702 * if we perform lookups by ourselves, then we don't need to separate
703 * cache entries by euid and egid
705 if (qstate->config_entry->perform_actual_lookups != 0)
706 memset(read_request->cache_key, 0, qstate->eid_str_length);
708 #ifdef NS_NSCD_EID_CHECKING
709 if (check_query_eids(qstate) != 0) {
710 /* if the lookup is not self-performing, we check for clients euid/egid */
711 read_response->error_code = EPERM;
717 configuration_lock_rdlock(s_configuration);
718 c_entry = find_cache_entry(s_cache,
719 qstate->config_entry->positive_cache_params.entry_name);
720 neg_c_entry = find_cache_entry(s_cache,
721 qstate->config_entry->negative_cache_params.entry_name);
722 configuration_unlock(s_configuration);
723 if ((c_entry != NULL) && (neg_c_entry != NULL)) {
724 configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
725 qstate->config_entry->positive_cache_entry = c_entry;
726 read_response->error_code = cache_read(c_entry,
727 read_request->cache_key,
728 read_request->cache_key_size, NULL,
729 &read_response->data_size);
731 if (read_response->error_code == -2) {
732 read_response->data = (char *)malloc(
733 read_response->data_size);
734 assert(read_response != NULL);
735 read_response->error_code = cache_read(c_entry,
736 read_request->cache_key,
737 read_request->cache_key_size,
739 &read_response->data_size);
741 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);
743 configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
744 qstate->config_entry->negative_cache_entry = neg_c_entry;
745 if (read_response->error_code == -1) {
746 read_response->error_code = cache_read(neg_c_entry,
747 read_request->cache_key,
748 read_request->cache_key_size, NULL,
749 &read_response->data_size);
751 if (read_response->error_code == -2) {
752 read_response->error_code = 0;
753 read_response->data = NULL;
754 read_response->data_size = 0;
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 != 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 != 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 != 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 = (char *)malloc(
940 transform_request->entry_length + 1);
941 assert(transform_request->entry != NULL);
942 memset(transform_request->entry, 0,
943 transform_request->entry_length + 1);
945 qstate->process_func = on_transform_request_read2;
947 qstate->process_func = on_transform_request_process;
949 qstate->kevent_watermark = transform_request->entry_length;
952 TRACE_OUT(on_transform_request_read1);
957 on_transform_request_read2(struct query_state *qstate)
959 struct cache_transform_request *transform_request;
962 TRACE_IN(on_transform_request_read2);
963 transform_request = get_cache_transform_request(&qstate->request);
965 result = qstate->read_func(qstate, transform_request->entry,
966 transform_request->entry_length);
968 if (result != qstate->kevent_watermark) {
969 TRACE_OUT(on_transform_request_read2);
973 qstate->kevent_watermark = 0;
974 qstate->process_func = on_transform_request_process;
976 TRACE_OUT(on_transform_request_read2);
981 on_transform_request_process(struct query_state *qstate)
983 struct cache_transform_request *transform_request;
984 struct cache_transform_response *transform_response;
985 struct configuration_entry *config_entry;
988 TRACE_IN(on_transform_request_process);
989 init_comm_element(&qstate->response, CET_TRANSFORM_RESPONSE);
990 transform_response = get_cache_transform_response(&qstate->response);
991 transform_request = get_cache_transform_request(&qstate->request);
993 switch (transform_request->transformation_type) {
995 if (transform_request->entry == NULL) {
996 size = configuration_get_entries_size(s_configuration);
997 for (i = 0; i < size; ++i) {
998 config_entry = configuration_get_entry(
1001 if (config_entry->perform_actual_lookups == 0)
1002 clear_config_entry_part(config_entry,
1003 qstate->eid_str, qstate->eid_str_length);
1006 qstate->config_entry = configuration_find_entry(
1007 s_configuration, transform_request->entry);
1009 if (qstate->config_entry == NULL) {
1010 LOG_ERR_2("transform_request",
1011 "can't find configuration"
1012 " entry '%s'. aborting request",
1013 transform_request->entry);
1014 transform_response->error_code = -1;
1018 if (qstate->config_entry->perform_actual_lookups != 0) {
1019 LOG_ERR_2("transform_request",
1020 "can't transform the cache entry %s"
1021 ", because it ised for actual lookups",
1022 transform_request->entry);
1023 transform_response->error_code = -1;
1027 clear_config_entry_part(qstate->config_entry,
1028 qstate->eid_str, qstate->eid_str_length);
1032 if (qstate->euid != 0)
1033 transform_response->error_code = -1;
1035 if (transform_request->entry == NULL) {
1036 size = configuration_get_entries_size(
1038 for (i = 0; i < size; ++i) {
1040 configuration_get_entry(
1041 s_configuration, i));
1044 qstate->config_entry = configuration_find_entry(
1046 transform_request->entry);
1048 if (qstate->config_entry == NULL) {
1049 LOG_ERR_2("transform_request",
1050 "can't find configuration"
1051 " entry '%s'. aborting request",
1052 transform_request->entry);
1053 transform_response->error_code = -1;
1057 clear_config_entry(qstate->config_entry);
1062 transform_response->error_code = -1;
1066 qstate->kevent_watermark = 0;
1067 qstate->process_func = on_transform_response_write1;
1068 TRACE_OUT(on_transform_request_process);
1073 on_transform_response_write1(struct query_state *qstate)
1075 struct cache_transform_response *transform_response;
1078 TRACE_IN(on_transform_response_write1);
1079 transform_response = get_cache_transform_response(&qstate->response);
1080 result = qstate->write_func(qstate, &transform_response->error_code,
1082 if (result != sizeof(int)) {
1083 TRACE_OUT(on_transform_response_write1);
1087 finalize_comm_element(&qstate->request);
1088 finalize_comm_element(&qstate->response);
1090 qstate->kevent_watermark = 0;
1091 qstate->process_func = NULL;
1092 TRACE_OUT(on_transform_response_write1);
1097 * Checks if the client's euid and egid do not differ from its uid and gid.
1098 * Returns 0 on success.
1101 check_query_eids(struct query_state *qstate)
1104 return ((qstate->uid != qstate->euid) || (qstate->gid != qstate->egid) ? -1 : 0);
1108 * Uses the qstate fields to process an "alternate" read - when the buffer is
1109 * too large to be received during one socket read operation
1112 query_io_buffer_read(struct query_state *qstate, void *buf, size_t nbytes)
1116 TRACE_IN(query_io_buffer_read);
1117 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1120 if (nbytes < qstate->io_buffer + qstate->io_buffer_size -
1121 qstate->io_buffer_p)
1124 result = qstate->io_buffer + qstate->io_buffer_size -
1125 qstate->io_buffer_p;
1127 memcpy(buf, qstate->io_buffer_p, result);
1128 qstate->io_buffer_p += result;
1130 if (qstate->io_buffer_p == qstate->io_buffer + qstate->io_buffer_size) {
1131 free(qstate->io_buffer);
1132 qstate->io_buffer = NULL;
1134 qstate->write_func = query_socket_write;
1135 qstate->read_func = query_socket_read;
1138 TRACE_OUT(query_io_buffer_read);
1143 * Uses the qstate fields to process an "alternate" write - when the buffer is
1144 * too large to be sent during one socket write operation
1147 query_io_buffer_write(struct query_state *qstate, const void *buf,
1152 TRACE_IN(query_io_buffer_write);
1153 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL))
1156 if (nbytes < qstate->io_buffer + qstate->io_buffer_size -
1157 qstate->io_buffer_p)
1160 result = qstate->io_buffer + qstate->io_buffer_size -
1161 qstate->io_buffer_p;
1163 memcpy(qstate->io_buffer_p, buf, result);
1164 qstate->io_buffer_p += result;
1166 if (qstate->io_buffer_p == qstate->io_buffer + qstate->io_buffer_size) {
1167 qstate->use_alternate_io = 1;
1168 qstate->io_buffer_p = qstate->io_buffer;
1170 qstate->write_func = query_socket_write;
1171 qstate->read_func = query_socket_read;
1174 TRACE_OUT(query_io_buffer_write);
1179 * The default "read" function, which reads data directly from socket
1182 query_socket_read(struct query_state *qstate, void *buf, size_t nbytes)
1186 TRACE_IN(query_socket_read);
1187 if (qstate->socket_failed != 0) {
1188 TRACE_OUT(query_socket_read);
1192 result = read(qstate->sockfd, buf, nbytes);
1193 if ((result == -1) || (result < nbytes))
1194 qstate->socket_failed = 1;
1196 TRACE_OUT(query_socket_read);
1201 * The default "write" function, which writes data directly to socket
1204 query_socket_write(struct query_state *qstate, const void *buf, size_t nbytes)
1208 TRACE_IN(query_socket_write);
1209 if (qstate->socket_failed != 0) {
1210 TRACE_OUT(query_socket_write);
1214 result = write(qstate->sockfd, buf, nbytes);
1215 if ((result == -1) || (result < nbytes))
1216 qstate->socket_failed = 1;
1218 TRACE_OUT(query_socket_write);
1223 * Initializes the query_state structure by filling it with the default values.
1225 struct query_state *
1226 init_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t egid)
1228 struct query_state *retval;
1230 TRACE_IN(init_query_state);
1231 retval = (struct query_state *)malloc(sizeof(struct query_state));
1232 assert(retval != NULL);
1233 memset(retval, 0, sizeof(struct query_state));
1235 retval->sockfd = sockfd;
1236 retval->kevent_filter = EVFILT_READ;
1237 retval->kevent_watermark = kevent_watermark;
1239 retval->euid = euid;
1240 retval->egid = egid;
1241 retval->uid = retval->gid = -1;
1243 if (asprintf(&retval->eid_str, "%d_%d_", retval->euid,
1244 retval->egid) == -1) {
1248 retval->eid_str_length = strlen(retval->eid_str);
1250 init_comm_element(&retval->request, CET_UNDEFINED);
1251 init_comm_element(&retval->response, CET_UNDEFINED);
1252 retval->process_func = on_query_startup;
1253 retval->destroy_func = on_query_destroy;
1255 retval->write_func = query_socket_write;
1256 retval->read_func = query_socket_read;
1258 get_time_func(&retval->creation_time);
1259 memcpy(&retval->timeout, &s_configuration->query_timeout,
1260 sizeof(struct timeval));
1262 TRACE_OUT(init_query_state);
1267 destroy_query_state(struct query_state *qstate)
1270 TRACE_IN(destroy_query_state);
1271 if (qstate->eid_str != NULL)
1272 free(qstate->eid_str);
1274 if (qstate->io_buffer != NULL)
1275 free(qstate->io_buffer);
1277 qstate->destroy_func(qstate);
1279 TRACE_OUT(destroy_query_state);