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>
44 #include "mp_ws_query.h"
45 #include "mp_rs_query.h"
46 #include "singletons.h"
48 static const char negative_data
[1] = { 0 };
50 extern void get_time_func(struct timeval
*);
52 static void clear_config_entry(struct configuration_entry
*);
53 static void clear_config_entry_part(struct configuration_entry
*,
54 const char *, size_t);
56 static int on_query_startup(struct query_state
*);
57 static void on_query_destroy(struct query_state
*);
59 static int on_read_request_read1(struct query_state
*);
60 static int on_read_request_read2(struct query_state
*);
61 static int on_read_request_process(struct query_state
*);
62 static int on_read_response_write1(struct query_state
*);
63 static int on_read_response_write2(struct query_state
*);
65 static int on_rw_mapper(struct query_state
*);
67 static int on_transform_request_read1(struct query_state
*);
68 static int on_transform_request_read2(struct query_state
*);
69 static int on_transform_request_process(struct query_state
*);
70 static int on_transform_response_write1(struct query_state
*);
72 static int on_write_request_read1(struct query_state
*);
73 static int on_write_request_read2(struct query_state
*);
74 static int on_negative_write_request_process(struct query_state
*);
75 static int on_write_request_process(struct query_state
*);
76 static int on_write_response_write1(struct query_state
*);
79 * Clears the specified configuration entry (clears the cache for positive and
80 * and negative entries) and also for all multipart entries.
83 clear_config_entry(struct configuration_entry
*config_entry
)
87 TRACE_IN(clear_config_entry
);
88 configuration_lock_entry(config_entry
, CELT_POSITIVE
);
89 if (config_entry
->positive_cache_entry
!= NULL
)
90 transform_cache_entry(
91 config_entry
->positive_cache_entry
,
93 configuration_unlock_entry(config_entry
, CELT_POSITIVE
);
95 configuration_lock_entry(config_entry
, CELT_NEGATIVE
);
96 if (config_entry
->negative_cache_entry
!= NULL
)
97 transform_cache_entry(
98 config_entry
->negative_cache_entry
,
100 configuration_unlock_entry(config_entry
, CELT_NEGATIVE
);
102 configuration_lock_entry(config_entry
, CELT_MULTIPART
);
103 for (i
= 0; i
< config_entry
->mp_cache_entries_size
; ++i
)
104 transform_cache_entry(
105 config_entry
->mp_cache_entries
[i
],
107 configuration_unlock_entry(config_entry
, CELT_MULTIPART
);
109 TRACE_OUT(clear_config_entry
);
113 * Clears the specified configuration entry by deleting only the elements,
114 * that are owned by the user with specified eid_str.
117 clear_config_entry_part(struct configuration_entry
*config_entry
,
118 const char *eid_str
, size_t eid_str_length
)
120 cache_entry
*start
, *finish
, *mp_entry
;
121 TRACE_IN(clear_config_entry_part
);
122 configuration_lock_entry(config_entry
, CELT_POSITIVE
);
123 if (config_entry
->positive_cache_entry
!= NULL
)
124 transform_cache_entry_part(
125 config_entry
->positive_cache_entry
,
126 CTT_CLEAR
, eid_str
, eid_str_length
, KPPT_LEFT
);
127 configuration_unlock_entry(config_entry
, CELT_POSITIVE
);
129 configuration_lock_entry(config_entry
, CELT_NEGATIVE
);
130 if (config_entry
->negative_cache_entry
!= NULL
)
131 transform_cache_entry_part(
132 config_entry
->negative_cache_entry
,
133 CTT_CLEAR
, eid_str
, eid_str_length
, KPPT_LEFT
);
134 configuration_unlock_entry(config_entry
, CELT_NEGATIVE
);
136 configuration_lock_entry(config_entry
, CELT_MULTIPART
);
137 if (configuration_entry_find_mp_cache_entries(config_entry
,
138 eid_str
, &start
, &finish
) == 0) {
139 for (mp_entry
= start
; mp_entry
!= finish
; ++mp_entry
)
140 transform_cache_entry(*mp_entry
, CTT_CLEAR
);
142 configuration_unlock_entry(config_entry
, CELT_MULTIPART
);
144 TRACE_OUT(clear_config_entry_part
);
148 * This function is assigned to the query_state structue on its creation.
149 * It's main purpose is to receive credentials from the client.
152 on_query_startup(struct query_state
*qstate
)
154 struct msghdr cred_hdr
;
156 struct cmsgcred
*cred
;
161 char cred
[CMSG_SPACE(sizeof(struct cmsgcred
))];
164 TRACE_IN(on_query_startup
);
165 assert(qstate
!= NULL
);
167 memset(&cred_hdr
, 0, sizeof(struct msghdr
));
168 cred_hdr
.msg_iov
= &iov
;
169 cred_hdr
.msg_iovlen
= 1;
170 cred_hdr
.msg_control
= (caddr_t
)&cmsg
;
171 cred_hdr
.msg_controllen
= CMSG_LEN(sizeof(struct cmsgcred
));
173 memset(&iov
, 0, sizeof(struct iovec
));
174 iov
.iov_base
= &elem_type
;
175 iov
.iov_len
= sizeof(int);
177 if (recvmsg(qstate
->sockfd
, &cred_hdr
, 0) == -1) {
178 TRACE_OUT(on_query_startup
);
182 if (cmsg
.hdr
.cmsg_len
< CMSG_LEN(sizeof(struct cmsgcred
))
183 || cmsg
.hdr
.cmsg_level
!= SOL_SOCKET
184 || cmsg
.hdr
.cmsg_type
!= SCM_CREDS
) {
185 TRACE_OUT(on_query_startup
);
189 cred
= (struct cmsgcred
*)CMSG_DATA(&cmsg
);
190 qstate
->uid
= cred
->cmcred_uid
;
191 qstate
->gid
= cred
->cmcred_gid
;
193 #if defined(NS_NSCD_EID_CHECKING) || defined(NS_STRICT_NSCD_EID_CHECKING)
195 * This check is probably a bit redundant - per-user cache is always separated
196 * by the euid/egid pair
198 if (check_query_eids(qstate
) != 0) {
199 #ifdef NS_STRICT_NSCD_EID_CHECKING
200 TRACE_OUT(on_query_startup
);
203 if ((elem_type
!= CET_READ_REQUEST
) &&
204 (elem_type
!= CET_MP_READ_SESSION_REQUEST
) &&
205 (elem_type
!= CET_WRITE_REQUEST
) &&
206 (elem_type
!= CET_MP_WRITE_SESSION_REQUEST
)) {
207 TRACE_OUT(on_query_startup
);
215 case CET_WRITE_REQUEST
:
216 qstate
->process_func
= on_write_request_read1
;
218 case CET_READ_REQUEST
:
219 qstate
->process_func
= on_read_request_read1
;
221 case CET_TRANSFORM_REQUEST
:
222 qstate
->process_func
= on_transform_request_read1
;
224 case CET_MP_WRITE_SESSION_REQUEST
:
225 qstate
->process_func
= on_mp_write_session_request_read1
;
227 case CET_MP_READ_SESSION_REQUEST
:
228 qstate
->process_func
= on_mp_read_session_request_read1
;
231 TRACE_OUT(on_query_startup
);
235 qstate
->kevent_watermark
= 0;
236 TRACE_OUT(on_query_startup
);
241 * on_rw_mapper is used to process multiple read/write requests during
242 * one connection session. It's never called in the beginning (on query_state
243 * creation) as it does not process the multipart requests and does not
244 * receive credentials
247 on_rw_mapper(struct query_state
*qstate
)
252 TRACE_IN(on_rw_mapper
);
253 if (qstate
->kevent_watermark
== 0) {
254 qstate
->kevent_watermark
= sizeof(int);
256 result
= qstate
->read_func(qstate
, &elem_type
, sizeof(int));
257 if (result
!= sizeof(int)) {
258 TRACE_OUT(on_rw_mapper
);
263 case CET_WRITE_REQUEST
:
264 qstate
->kevent_watermark
= sizeof(size_t);
265 qstate
->process_func
= on_write_request_read1
;
267 case CET_READ_REQUEST
:
268 qstate
->kevent_watermark
= sizeof(size_t);
269 qstate
->process_func
= on_read_request_read1
;
272 TRACE_OUT(on_rw_mapper
);
277 TRACE_OUT(on_rw_mapper
);
282 * The default query_destroy function
285 on_query_destroy(struct query_state
*qstate
)
288 TRACE_IN(on_query_destroy
);
289 finalize_comm_element(&qstate
->response
);
290 finalize_comm_element(&qstate
->request
);
291 TRACE_OUT(on_query_destroy
);
295 * The functions below are used to process write requests.
296 * - on_write_request_read1 and on_write_request_read2 read the request itself
297 * - on_write_request_process processes it (if the client requests to
298 * cache the negative result, the on_negative_write_request_process is used)
299 * - on_write_response_write1 sends the response
302 on_write_request_read1(struct query_state
*qstate
)
304 struct cache_write_request
*write_request
;
307 TRACE_IN(on_write_request_read1
);
308 if (qstate
->kevent_watermark
== 0)
309 qstate
->kevent_watermark
= sizeof(size_t) * 3;
311 init_comm_element(&qstate
->request
, CET_WRITE_REQUEST
);
312 write_request
= get_cache_write_request(&qstate
->request
);
314 result
= qstate
->read_func(qstate
, &write_request
->entry_length
,
316 result
+= qstate
->read_func(qstate
,
317 &write_request
->cache_key_size
, sizeof(size_t));
318 result
+= qstate
->read_func(qstate
,
319 &write_request
->data_size
, sizeof(size_t));
321 if (result
!= sizeof(size_t) * 3) {
322 TRACE_OUT(on_write_request_read1
);
326 if (BUFSIZE_INVALID(write_request
->entry_length
) ||
327 BUFSIZE_INVALID(write_request
->cache_key_size
) ||
328 (BUFSIZE_INVALID(write_request
->data_size
) &&
329 (write_request
->data_size
!= 0))) {
330 TRACE_OUT(on_write_request_read1
);
334 write_request
->entry
= (char *)calloc(1,
335 write_request
->entry_length
+ 1);
336 assert(write_request
->entry
!= NULL
);
338 write_request
->cache_key
= (char *)calloc(1,
339 write_request
->cache_key_size
+
340 qstate
->eid_str_length
);
341 assert(write_request
->cache_key
!= NULL
);
342 memcpy(write_request
->cache_key
, qstate
->eid_str
,
343 qstate
->eid_str_length
);
345 if (write_request
->data_size
!= 0) {
346 write_request
->data
= (char *)calloc(1,
347 write_request
->data_size
);
348 assert(write_request
->data
!= NULL
);
351 qstate
->kevent_watermark
= write_request
->entry_length
+
352 write_request
->cache_key_size
+
353 write_request
->data_size
;
354 qstate
->process_func
= on_write_request_read2
;
357 TRACE_OUT(on_write_request_read1
);
362 on_write_request_read2(struct query_state
*qstate
)
364 struct cache_write_request
*write_request
;
367 TRACE_IN(on_write_request_read2
);
368 write_request
= get_cache_write_request(&qstate
->request
);
370 result
= qstate
->read_func(qstate
, write_request
->entry
,
371 write_request
->entry_length
);
372 result
+= qstate
->read_func(qstate
, write_request
->cache_key
+
373 qstate
->eid_str_length
, write_request
->cache_key_size
);
374 if (write_request
->data_size
!= 0)
375 result
+= qstate
->read_func(qstate
, write_request
->data
,
376 write_request
->data_size
);
378 if (result
!= qstate
->kevent_watermark
) {
379 TRACE_OUT(on_write_request_read2
);
382 write_request
->cache_key_size
+= qstate
->eid_str_length
;
384 qstate
->kevent_watermark
= 0;
385 if (write_request
->data_size
!= 0)
386 qstate
->process_func
= on_write_request_process
;
388 qstate
->process_func
= on_negative_write_request_process
;
389 TRACE_OUT(on_write_request_read2
);
394 on_write_request_process(struct query_state
*qstate
)
396 struct cache_write_request
*write_request
;
397 struct cache_write_response
*write_response
;
400 TRACE_IN(on_write_request_process
);
401 init_comm_element(&qstate
->response
, CET_WRITE_RESPONSE
);
402 write_response
= get_cache_write_response(&qstate
->response
);
403 write_request
= get_cache_write_request(&qstate
->request
);
405 qstate
->config_entry
= configuration_find_entry(
406 s_configuration
, write_request
->entry
);
408 if (qstate
->config_entry
== NULL
) {
409 write_response
->error_code
= ENOENT
;
411 LOG_ERR_2("write_request", "can't find configuration"
412 " entry '%s'. aborting request", write_request
->entry
);
416 if (qstate
->config_entry
->enabled
== 0) {
417 write_response
->error_code
= EACCES
;
419 LOG_ERR_2("write_request",
420 "configuration entry '%s' is disabled",
421 write_request
->entry
);
425 if (qstate
->config_entry
->perform_actual_lookups
!= 0) {
426 write_response
->error_code
= EOPNOTSUPP
;
428 LOG_ERR_2("write_request",
429 "entry '%s' performs lookups by itself: "
430 "can't write to it", write_request
->entry
);
434 configuration_lock_rdlock(s_configuration
);
435 c_entry
= find_cache_entry(s_cache
,
436 qstate
->config_entry
->positive_cache_params
.entry_name
);
437 configuration_unlock(s_configuration
);
438 if (c_entry
!= NULL
) {
439 configuration_lock_entry(qstate
->config_entry
, CELT_POSITIVE
);
440 qstate
->config_entry
->positive_cache_entry
= c_entry
;
441 write_response
->error_code
= cache_write(c_entry
,
442 write_request
->cache_key
,
443 write_request
->cache_key_size
,
445 write_request
->data_size
);
446 configuration_unlock_entry(qstate
->config_entry
, CELT_POSITIVE
);
448 if ((qstate
->config_entry
->common_query_timeout
.tv_sec
!= 0) ||
449 (qstate
->config_entry
->common_query_timeout
.tv_usec
!= 0))
450 memcpy(&qstate
->timeout
,
451 &qstate
->config_entry
->common_query_timeout
,
452 sizeof(struct timeval
));
455 write_response
->error_code
= -1;
458 qstate
->kevent_filter
= EVFILT_WRITE
;
459 qstate
->kevent_watermark
= sizeof(int);
460 qstate
->process_func
= on_write_response_write1
;
462 TRACE_OUT(on_write_request_process
);
467 on_negative_write_request_process(struct query_state
*qstate
)
469 struct cache_write_request
*write_request
;
470 struct cache_write_response
*write_response
;
473 TRACE_IN(on_negative_write_request_process
);
474 init_comm_element(&qstate
->response
, CET_WRITE_RESPONSE
);
475 write_response
= get_cache_write_response(&qstate
->response
);
476 write_request
= get_cache_write_request(&qstate
->request
);
478 qstate
->config_entry
= configuration_find_entry(
479 s_configuration
, write_request
->entry
);
481 if (qstate
->config_entry
== NULL
) {
482 write_response
->error_code
= ENOENT
;
484 LOG_ERR_2("negative_write_request",
485 "can't find configuration"
486 " entry '%s'. aborting request", write_request
->entry
);
490 if (qstate
->config_entry
->enabled
== 0) {
491 write_response
->error_code
= EACCES
;
493 LOG_ERR_2("negative_write_request",
494 "configuration entry '%s' is disabled",
495 write_request
->entry
);
499 if (qstate
->config_entry
->perform_actual_lookups
!= 0) {
500 write_response
->error_code
= EOPNOTSUPP
;
502 LOG_ERR_2("negative_write_request",
503 "entry '%s' performs lookups by itself: "
504 "can't write to it", write_request
->entry
);
507 #ifdef NS_NSCD_EID_CHECKING
508 if (check_query_eids(qstate
) != 0) {
509 write_response
->error_code
= EPERM
;
515 configuration_lock_rdlock(s_configuration
);
516 c_entry
= find_cache_entry(s_cache
,
517 qstate
->config_entry
->negative_cache_params
.entry_name
);
518 configuration_unlock(s_configuration
);
519 if (c_entry
!= NULL
) {
520 configuration_lock_entry(qstate
->config_entry
, CELT_NEGATIVE
);
521 qstate
->config_entry
->negative_cache_entry
= c_entry
;
522 write_response
->error_code
= cache_write(c_entry
,
523 write_request
->cache_key
,
524 write_request
->cache_key_size
,
526 sizeof(negative_data
));
527 configuration_unlock_entry(qstate
->config_entry
, CELT_NEGATIVE
);
529 if ((qstate
->config_entry
->common_query_timeout
.tv_sec
!= 0) ||
530 (qstate
->config_entry
->common_query_timeout
.tv_usec
!= 0))
531 memcpy(&qstate
->timeout
,
532 &qstate
->config_entry
->common_query_timeout
,
533 sizeof(struct timeval
));
535 write_response
->error_code
= -1;
538 qstate
->kevent_filter
= EVFILT_WRITE
;
539 qstate
->kevent_watermark
= sizeof(int);
540 qstate
->process_func
= on_write_response_write1
;
542 TRACE_OUT(on_negative_write_request_process
);
547 on_write_response_write1(struct query_state
*qstate
)
549 struct cache_write_response
*write_response
;
552 TRACE_IN(on_write_response_write1
);
553 write_response
= get_cache_write_response(&qstate
->response
);
554 result
= qstate
->write_func(qstate
, &write_response
->error_code
,
556 if (result
!= sizeof(int)) {
557 TRACE_OUT(on_write_response_write1
);
561 finalize_comm_element(&qstate
->request
);
562 finalize_comm_element(&qstate
->response
);
564 qstate
->kevent_watermark
= sizeof(int);
565 qstate
->kevent_filter
= EVFILT_READ
;
566 qstate
->process_func
= on_rw_mapper
;
568 TRACE_OUT(on_write_response_write1
);
573 * The functions below are used to process read requests.
574 * - on_read_request_read1 and on_read_request_read2 read the request itself
575 * - on_read_request_process processes it
576 * - on_read_response_write1 and on_read_response_write2 send the response
579 on_read_request_read1(struct query_state
*qstate
)
581 struct cache_read_request
*read_request
;
584 TRACE_IN(on_read_request_read1
);
585 if (qstate
->kevent_watermark
== 0)
586 qstate
->kevent_watermark
= sizeof(size_t) * 2;
588 init_comm_element(&qstate
->request
, CET_READ_REQUEST
);
589 read_request
= get_cache_read_request(&qstate
->request
);
591 result
= qstate
->read_func(qstate
,
592 &read_request
->entry_length
, sizeof(size_t));
593 result
+= qstate
->read_func(qstate
,
594 &read_request
->cache_key_size
, sizeof(size_t));
596 if (result
!= sizeof(size_t) * 2) {
597 TRACE_OUT(on_read_request_read1
);
601 if (BUFSIZE_INVALID(read_request
->entry_length
) ||
602 BUFSIZE_INVALID(read_request
->cache_key_size
)) {
603 TRACE_OUT(on_read_request_read1
);
607 read_request
->entry
= (char *)calloc(1,
608 read_request
->entry_length
+ 1);
609 assert(read_request
->entry
!= NULL
);
611 read_request
->cache_key
= (char *)calloc(1,
612 read_request
->cache_key_size
+
613 qstate
->eid_str_length
);
614 assert(read_request
->cache_key
!= NULL
);
615 memcpy(read_request
->cache_key
, qstate
->eid_str
,
616 qstate
->eid_str_length
);
618 qstate
->kevent_watermark
= read_request
->entry_length
+
619 read_request
->cache_key_size
;
620 qstate
->process_func
= on_read_request_read2
;
623 TRACE_OUT(on_read_request_read1
);
628 on_read_request_read2(struct query_state
*qstate
)
630 struct cache_read_request
*read_request
;
633 TRACE_IN(on_read_request_read2
);
634 read_request
= get_cache_read_request(&qstate
->request
);
636 result
= qstate
->read_func(qstate
, read_request
->entry
,
637 read_request
->entry_length
);
638 result
+= qstate
->read_func(qstate
,
639 read_request
->cache_key
+ qstate
->eid_str_length
,
640 read_request
->cache_key_size
);
642 if (result
!= qstate
->kevent_watermark
) {
643 TRACE_OUT(on_read_request_read2
);
646 read_request
->cache_key_size
+= qstate
->eid_str_length
;
648 qstate
->kevent_watermark
= 0;
649 qstate
->process_func
= on_read_request_process
;
651 TRACE_OUT(on_read_request_read2
);
656 on_read_request_process(struct query_state
*qstate
)
658 struct cache_read_request
*read_request
;
659 struct cache_read_response
*read_response
;
660 cache_entry c_entry
, neg_c_entry
;
662 struct agent
*lookup_agent
;
663 struct common_agent
*c_agent
;
666 TRACE_IN(on_read_request_process
);
667 init_comm_element(&qstate
->response
, CET_READ_RESPONSE
);
668 read_response
= get_cache_read_response(&qstate
->response
);
669 read_request
= get_cache_read_request(&qstate
->request
);
671 qstate
->config_entry
= configuration_find_entry(
672 s_configuration
, read_request
->entry
);
673 if (qstate
->config_entry
== NULL
) {
674 read_response
->error_code
= ENOENT
;
676 LOG_ERR_2("read_request",
677 "can't find configuration "
678 "entry '%s'. aborting request", read_request
->entry
);
682 if (qstate
->config_entry
->enabled
== 0) {
683 read_response
->error_code
= EACCES
;
685 LOG_ERR_2("read_request",
686 "configuration entry '%s' is disabled",
687 read_request
->entry
);
692 * if we perform lookups by ourselves, then we don't need to separate
693 * cache entries by euid and egid
695 if (qstate
->config_entry
->perform_actual_lookups
!= 0)
696 memset(read_request
->cache_key
, 0, qstate
->eid_str_length
);
698 #ifdef NS_NSCD_EID_CHECKING
699 if (check_query_eids(qstate
) != 0) {
700 /* if the lookup is not self-performing, we check for clients euid/egid */
701 read_response
->error_code
= EPERM
;
707 configuration_lock_rdlock(s_configuration
);
708 c_entry
= find_cache_entry(s_cache
,
709 qstate
->config_entry
->positive_cache_params
.entry_name
);
710 neg_c_entry
= find_cache_entry(s_cache
,
711 qstate
->config_entry
->negative_cache_params
.entry_name
);
712 configuration_unlock(s_configuration
);
713 if ((c_entry
!= NULL
) && (neg_c_entry
!= NULL
)) {
714 configuration_lock_entry(qstate
->config_entry
, CELT_POSITIVE
);
715 qstate
->config_entry
->positive_cache_entry
= c_entry
;
716 read_response
->error_code
= cache_read(c_entry
,
717 read_request
->cache_key
,
718 read_request
->cache_key_size
, NULL
,
719 &read_response
->data_size
);
721 if (read_response
->error_code
== -2) {
722 read_response
->data
= (char *)malloc(
723 read_response
->data_size
);
724 assert(read_response
!= NULL
);
725 read_response
->error_code
= cache_read(c_entry
,
726 read_request
->cache_key
,
727 read_request
->cache_key_size
,
729 &read_response
->data_size
);
731 configuration_unlock_entry(qstate
->config_entry
, CELT_POSITIVE
);
733 configuration_lock_entry(qstate
->config_entry
, CELT_NEGATIVE
);
734 qstate
->config_entry
->negative_cache_entry
= neg_c_entry
;
735 if (read_response
->error_code
== -1) {
736 read_response
->error_code
= cache_read(neg_c_entry
,
737 read_request
->cache_key
,
738 read_request
->cache_key_size
, NULL
,
739 &read_response
->data_size
);
741 if (read_response
->error_code
== -2) {
742 read_response
->error_code
= 0;
743 read_response
->data
= NULL
;
744 read_response
->data_size
= 0;
747 configuration_unlock_entry(qstate
->config_entry
, CELT_NEGATIVE
);
749 if ((read_response
->error_code
== -1) &&
750 (qstate
->config_entry
->perform_actual_lookups
!= 0)) {
751 free(read_response
->data
);
752 read_response
->data
= NULL
;
753 read_response
->data_size
= 0;
755 lookup_agent
= find_agent(s_agent_table
,
756 read_request
->entry
, COMMON_AGENT
);
758 if ((lookup_agent
!= NULL
) &&
759 (lookup_agent
->type
== COMMON_AGENT
)) {
760 c_agent
= (struct common_agent
*)lookup_agent
;
761 res
= c_agent
->lookup_func(
762 read_request
->cache_key
+
763 qstate
->eid_str_length
,
764 read_request
->cache_key_size
-
765 qstate
->eid_str_length
,
766 &read_response
->data
,
767 &read_response
->data_size
);
769 if (res
== NS_SUCCESS
) {
770 read_response
->error_code
= 0;
771 configuration_lock_entry(
772 qstate
->config_entry
,
775 read_request
->cache_key
,
776 read_request
->cache_key_size
,
778 read_response
->data_size
);
779 configuration_unlock_entry(
780 qstate
->config_entry
,
782 } else if ((res
== NS_NOTFOUND
) ||
783 (res
== NS_RETURN
)) {
784 configuration_lock_entry(
785 qstate
->config_entry
,
787 cache_write(neg_c_entry
,
788 read_request
->cache_key
,
789 read_request
->cache_key_size
,
791 sizeof(negative_data
));
792 configuration_unlock_entry(
793 qstate
->config_entry
,
796 read_response
->error_code
= 0;
797 read_response
->data
= NULL
;
798 read_response
->data_size
= 0;
803 if ((qstate
->config_entry
->common_query_timeout
.tv_sec
!= 0) ||
804 (qstate
->config_entry
->common_query_timeout
.tv_usec
!= 0))
805 memcpy(&qstate
->timeout
,
806 &qstate
->config_entry
->common_query_timeout
,
807 sizeof(struct timeval
));
809 read_response
->error_code
= -1;
812 qstate
->kevent_filter
= EVFILT_WRITE
;
813 if (read_response
->error_code
== 0)
814 qstate
->kevent_watermark
= sizeof(int) + sizeof(size_t);
816 qstate
->kevent_watermark
= sizeof(int);
817 qstate
->process_func
= on_read_response_write1
;
819 TRACE_OUT(on_read_request_process
);
824 on_read_response_write1(struct query_state
*qstate
)
826 struct cache_read_response
*read_response
;
829 TRACE_IN(on_read_response_write1
);
830 read_response
= get_cache_read_response(&qstate
->response
);
832 result
= qstate
->write_func(qstate
, &read_response
->error_code
,
835 if (read_response
->error_code
== 0) {
836 result
+= qstate
->write_func(qstate
, &read_response
->data_size
,
838 if (result
!= qstate
->kevent_watermark
) {
839 TRACE_OUT(on_read_response_write1
);
843 qstate
->kevent_watermark
= read_response
->data_size
;
844 qstate
->process_func
= on_read_response_write2
;
846 if (result
!= qstate
->kevent_watermark
) {
847 TRACE_OUT(on_read_response_write1
);
851 qstate
->kevent_watermark
= 0;
852 qstate
->process_func
= NULL
;
855 TRACE_OUT(on_read_response_write1
);
860 on_read_response_write2(struct query_state
*qstate
)
862 struct cache_read_response
*read_response
;
865 TRACE_IN(on_read_response_write2
);
866 read_response
= get_cache_read_response(&qstate
->response
);
867 if (read_response
->data_size
> 0) {
868 result
= qstate
->write_func(qstate
, read_response
->data
,
869 read_response
->data_size
);
870 if (result
!= qstate
->kevent_watermark
) {
871 TRACE_OUT(on_read_response_write2
);
876 finalize_comm_element(&qstate
->request
);
877 finalize_comm_element(&qstate
->response
);
879 qstate
->kevent_watermark
= sizeof(int);
880 qstate
->kevent_filter
= EVFILT_READ
;
881 qstate
->process_func
= on_rw_mapper
;
882 TRACE_OUT(on_read_response_write2
);
887 * The functions below are used to process write requests.
888 * - on_transform_request_read1 and on_transform_request_read2 read the
890 * - on_transform_request_process processes it
891 * - on_transform_response_write1 sends the response
894 on_transform_request_read1(struct query_state
*qstate
)
896 struct cache_transform_request
*transform_request
;
899 TRACE_IN(on_transform_request_read1
);
900 if (qstate
->kevent_watermark
== 0)
901 qstate
->kevent_watermark
= sizeof(size_t) + sizeof(int);
903 init_comm_element(&qstate
->request
, CET_TRANSFORM_REQUEST
);
905 get_cache_transform_request(&qstate
->request
);
907 result
= qstate
->read_func(qstate
,
908 &transform_request
->entry_length
, sizeof(size_t));
909 result
+= qstate
->read_func(qstate
,
910 &transform_request
->transformation_type
, sizeof(int));
912 if (result
!= sizeof(size_t) + sizeof(int)) {
913 TRACE_OUT(on_transform_request_read1
);
917 if ((transform_request
->transformation_type
!= TT_USER
) &&
918 (transform_request
->transformation_type
!= TT_ALL
)) {
919 TRACE_OUT(on_transform_request_read1
);
923 if (transform_request
->entry_length
!= 0) {
924 if (BUFSIZE_INVALID(transform_request
->entry_length
)) {
925 TRACE_OUT(on_transform_request_read1
);
929 transform_request
->entry
= (char *)calloc(1,
930 transform_request
->entry_length
+ 1);
931 assert(transform_request
->entry
!= NULL
);
933 qstate
->process_func
= on_transform_request_read2
;
935 qstate
->process_func
= on_transform_request_process
;
937 qstate
->kevent_watermark
= transform_request
->entry_length
;
940 TRACE_OUT(on_transform_request_read1
);
945 on_transform_request_read2(struct query_state
*qstate
)
947 struct cache_transform_request
*transform_request
;
950 TRACE_IN(on_transform_request_read2
);
951 transform_request
= get_cache_transform_request(&qstate
->request
);
953 result
= qstate
->read_func(qstate
, transform_request
->entry
,
954 transform_request
->entry_length
);
956 if (result
!= qstate
->kevent_watermark
) {
957 TRACE_OUT(on_transform_request_read2
);
961 qstate
->kevent_watermark
= 0;
962 qstate
->process_func
= on_transform_request_process
;
964 TRACE_OUT(on_transform_request_read2
);
969 on_transform_request_process(struct query_state
*qstate
)
971 struct cache_transform_request
*transform_request
;
972 struct cache_transform_response
*transform_response
;
973 struct configuration_entry
*config_entry
;
976 TRACE_IN(on_transform_request_process
);
977 init_comm_element(&qstate
->response
, CET_TRANSFORM_RESPONSE
);
978 transform_response
= get_cache_transform_response(&qstate
->response
);
979 transform_request
= get_cache_transform_request(&qstate
->request
);
981 switch (transform_request
->transformation_type
) {
983 if (transform_request
->entry
== NULL
) {
984 size
= configuration_get_entries_size(s_configuration
);
985 for (i
= 0; i
< size
; ++i
) {
986 config_entry
= configuration_get_entry(
989 if (config_entry
->perform_actual_lookups
== 0)
990 clear_config_entry_part(config_entry
,
991 qstate
->eid_str
, qstate
->eid_str_length
);
994 qstate
->config_entry
= configuration_find_entry(
995 s_configuration
, transform_request
->entry
);
997 if (qstate
->config_entry
== NULL
) {
998 LOG_ERR_2("transform_request",
999 "can't find configuration"
1000 " entry '%s'. aborting request",
1001 transform_request
->entry
);
1002 transform_response
->error_code
= -1;
1006 if (qstate
->config_entry
->perform_actual_lookups
!= 0) {
1007 LOG_ERR_2("transform_request",
1008 "can't transform the cache entry %s"
1009 ", because it ised for actual lookups",
1010 transform_request
->entry
);
1011 transform_response
->error_code
= -1;
1015 clear_config_entry_part(qstate
->config_entry
,
1016 qstate
->eid_str
, qstate
->eid_str_length
);
1020 if (qstate
->euid
!= 0)
1021 transform_response
->error_code
= -1;
1023 if (transform_request
->entry
== NULL
) {
1024 size
= configuration_get_entries_size(
1026 for (i
= 0; i
< size
; ++i
) {
1028 configuration_get_entry(
1029 s_configuration
, i
));
1032 qstate
->config_entry
= configuration_find_entry(
1034 transform_request
->entry
);
1036 if (qstate
->config_entry
== NULL
) {
1037 LOG_ERR_2("transform_request",
1038 "can't find configuration"
1039 " entry '%s'. aborting request",
1040 transform_request
->entry
);
1041 transform_response
->error_code
= -1;
1045 clear_config_entry(qstate
->config_entry
);
1050 transform_response
->error_code
= -1;
1054 qstate
->kevent_watermark
= 0;
1055 qstate
->process_func
= on_transform_response_write1
;
1056 TRACE_OUT(on_transform_request_process
);
1061 on_transform_response_write1(struct query_state
*qstate
)
1063 struct cache_transform_response
*transform_response
;
1066 TRACE_IN(on_transform_response_write1
);
1067 transform_response
= get_cache_transform_response(&qstate
->response
);
1068 result
= qstate
->write_func(qstate
, &transform_response
->error_code
,
1070 if (result
!= sizeof(int)) {
1071 TRACE_OUT(on_transform_response_write1
);
1075 finalize_comm_element(&qstate
->request
);
1076 finalize_comm_element(&qstate
->response
);
1078 qstate
->kevent_watermark
= 0;
1079 qstate
->process_func
= NULL
;
1080 TRACE_OUT(on_transform_response_write1
);
1085 * Checks if the client's euid and egid do not differ from its uid and gid.
1086 * Returns 0 on success.
1089 check_query_eids(struct query_state
*qstate
)
1092 return ((qstate
->uid
!= qstate
->euid
) || (qstate
->gid
!= qstate
->egid
) ? -1 : 0);
1096 * Uses the qstate fields to process an "alternate" read - when the buffer is
1097 * too large to be received during one socket read operation
1100 query_io_buffer_read(struct query_state
*qstate
, void *buf
, size_t nbytes
)
1104 TRACE_IN(query_io_buffer_read
);
1105 if ((qstate
->io_buffer_size
== 0) || (qstate
->io_buffer
== NULL
))
1108 if (nbytes
< qstate
->io_buffer
+ qstate
->io_buffer_size
-
1109 qstate
->io_buffer_p
)
1112 result
= qstate
->io_buffer
+ qstate
->io_buffer_size
-
1113 qstate
->io_buffer_p
;
1115 memcpy(buf
, qstate
->io_buffer_p
, result
);
1116 qstate
->io_buffer_p
+= result
;
1118 if (qstate
->io_buffer_p
== qstate
->io_buffer
+ qstate
->io_buffer_size
) {
1119 free(qstate
->io_buffer
);
1120 qstate
->io_buffer
= NULL
;
1122 qstate
->write_func
= query_socket_write
;
1123 qstate
->read_func
= query_socket_read
;
1126 TRACE_OUT(query_io_buffer_read
);
1131 * Uses the qstate fields to process an "alternate" write - when the buffer is
1132 * too large to be sent during one socket write operation
1135 query_io_buffer_write(struct query_state
*qstate
, const void *buf
,
1140 TRACE_IN(query_io_buffer_write
);
1141 if ((qstate
->io_buffer_size
== 0) || (qstate
->io_buffer
== NULL
))
1144 if (nbytes
< qstate
->io_buffer
+ qstate
->io_buffer_size
-
1145 qstate
->io_buffer_p
)
1148 result
= qstate
->io_buffer
+ qstate
->io_buffer_size
-
1149 qstate
->io_buffer_p
;
1151 memcpy(qstate
->io_buffer_p
, buf
, result
);
1152 qstate
->io_buffer_p
+= result
;
1154 if (qstate
->io_buffer_p
== qstate
->io_buffer
+ qstate
->io_buffer_size
) {
1155 qstate
->use_alternate_io
= 1;
1156 qstate
->io_buffer_p
= qstate
->io_buffer
;
1158 qstate
->write_func
= query_socket_write
;
1159 qstate
->read_func
= query_socket_read
;
1162 TRACE_OUT(query_io_buffer_write
);
1167 * The default "read" function, which reads data directly from socket
1170 query_socket_read(struct query_state
*qstate
, void *buf
, size_t nbytes
)
1174 TRACE_IN(query_socket_read
);
1175 if (qstate
->socket_failed
!= 0) {
1176 TRACE_OUT(query_socket_read
);
1180 result
= read(qstate
->sockfd
, buf
, nbytes
);
1181 if ((result
== -1) || (result
< nbytes
))
1182 qstate
->socket_failed
= 1;
1184 TRACE_OUT(query_socket_read
);
1189 * The default "write" function, which writes data directly to socket
1192 query_socket_write(struct query_state
*qstate
, const void *buf
, size_t nbytes
)
1196 TRACE_IN(query_socket_write
);
1197 if (qstate
->socket_failed
!= 0) {
1198 TRACE_OUT(query_socket_write
);
1202 result
= write(qstate
->sockfd
, buf
, nbytes
);
1203 if ((result
== -1) || (result
< nbytes
))
1204 qstate
->socket_failed
= 1;
1206 TRACE_OUT(query_socket_write
);
1211 * Initializes the query_state structure by filling it with the default values.
1213 struct query_state
*
1214 init_query_state(int sockfd
, size_t kevent_watermark
, uid_t euid
, gid_t egid
)
1216 struct query_state
*retval
;
1218 TRACE_IN(init_query_state
);
1219 retval
= (struct query_state
*)calloc(1, sizeof(struct query_state
));
1220 assert(retval
!= NULL
);
1222 retval
->sockfd
= sockfd
;
1223 retval
->kevent_filter
= EVFILT_READ
;
1224 retval
->kevent_watermark
= kevent_watermark
;
1226 retval
->euid
= euid
;
1227 retval
->egid
= egid
;
1228 retval
->uid
= retval
->gid
= -1;
1230 if (asprintf(&retval
->eid_str
, "%d_%d_", retval
->euid
,
1231 retval
->egid
) == -1) {
1235 retval
->eid_str_length
= strlen(retval
->eid_str
);
1237 init_comm_element(&retval
->request
, CET_UNDEFINED
);
1238 init_comm_element(&retval
->response
, CET_UNDEFINED
);
1239 retval
->process_func
= on_query_startup
;
1240 retval
->destroy_func
= on_query_destroy
;
1242 retval
->write_func
= query_socket_write
;
1243 retval
->read_func
= query_socket_read
;
1245 get_time_func(&retval
->creation_time
);
1246 memcpy(&retval
->timeout
, &s_configuration
->query_timeout
,
1247 sizeof(struct timeval
));
1249 TRACE_OUT(init_query_state
);
1254 destroy_query_state(struct query_state
*qstate
)
1257 TRACE_IN(destroy_query_state
);
1258 if (qstate
->eid_str
!= NULL
)
1259 free(qstate
->eid_str
);
1261 if (qstate
->io_buffer
!= NULL
)
1262 free(qstate
->io_buffer
);
1264 qstate
->destroy_func(qstate
);
1266 TRACE_OUT(destroy_query_state
);