1 /*- 2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <sys/time.h> 34 #include <sys/event.h> 35 #include <assert.h> 36 #include <errno.h> 37 #include <nsswitch.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include "config.h" 42 #include "debug.h" 43 #include "query.h" 44 #include "log.h" 45 #include "mp_ws_query.h" 46 #include "mp_rs_query.h" 47 #include "singletons.h" 48 49 static const char negative_data[1] = { 0 }; 50 51 extern void get_time_func(struct timeval *); 52 53 static void clear_config_entry(struct configuration_entry *); 54 static void clear_config_entry_part(struct configuration_entry *, 55 const char *, size_t); 56 57 static int on_query_startup(struct query_state *); 58 static void on_query_destroy(struct query_state *); 59 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 *); 65 66 static int on_rw_mapper(struct query_state *); 67 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 *); 72 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 *); 78 79 /* 80 * Clears the specified configuration entry (clears the cache for positive and 81 * and negative entries) and also for all multipart entries. 82 */ 83 static void 84 clear_config_entry(struct configuration_entry *config_entry) 85 { 86 size_t i; 87 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, 93 CTT_CLEAR); 94 configuration_unlock_entry(config_entry, CELT_POSITIVE); 95 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, 100 CTT_CLEAR); 101 configuration_unlock_entry(config_entry, CELT_NEGATIVE); 102 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], 107 CTT_CLEAR); 108 configuration_unlock_entry(config_entry, CELT_MULTIPART); 109 110 TRACE_OUT(clear_config_entry); 111 } 112 113 /* 114 * Clears the specified configuration entry by deleting only the elements, 115 * that are owned by the user with specified eid_str. 116 */ 117 static void 118 clear_config_entry_part(struct configuration_entry *config_entry, 119 const char *eid_str, size_t eid_str_length) 120 { 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); 129 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); 136 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); 142 } 143 configuration_unlock_entry(config_entry, CELT_MULTIPART); 144 145 TRACE_OUT(clear_config_entry_part); 146 } 147 148 /* 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. 151 */ 152 static int 153 on_query_startup(struct query_state *qstate) 154 { 155 struct msghdr cred_hdr; 156 struct iovec iov; 157 struct cmsgcred *cred; 158 int elem_type; 159 160 struct { 161 struct cmsghdr hdr; 162 char cred[CMSG_SPACE(sizeof(struct cmsgcred))]; 163 } cmsg; 164 165 TRACE_IN(on_query_startup); 166 assert(qstate != NULL); 167 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)); 173 174 memset(&iov, 0, sizeof(struct iovec)); 175 iov.iov_base = &elem_type; 176 iov.iov_len = sizeof(int); 177 178 if (recvmsg(qstate->sockfd, &cred_hdr, 0) == -1) { 179 TRACE_OUT(on_query_startup); 180 return (-1); 181 } 182 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); 187 return (-1); 188 } 189 190 cred = (struct cmsgcred *)CMSG_DATA(&cmsg); 191 qstate->uid = cred->cmcred_uid; 192 qstate->gid = cred->cmcred_gid; 193 194 #if defined(NS_NSCD_EID_CHECKING) || defined(NS_STRICT_NSCD_EID_CHECKING) 195 /* 196 * This check is probably a bit redundant - per-user cache is always separated 197 * by the euid/egid pair 198 */ 199 if (check_query_eids(qstate) != 0) { 200 #ifdef NS_STRICT_NSCD_EID_CHECKING 201 TRACE_OUT(on_query_startup); 202 return (-1); 203 #else 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); 209 return (-1); 210 } 211 #endif 212 } 213 #endif 214 215 switch (elem_type) { 216 case CET_WRITE_REQUEST: 217 qstate->process_func = on_write_request_read1; 218 break; 219 case CET_READ_REQUEST: 220 qstate->process_func = on_read_request_read1; 221 break; 222 case CET_TRANSFORM_REQUEST: 223 qstate->process_func = on_transform_request_read1; 224 break; 225 case CET_MP_WRITE_SESSION_REQUEST: 226 qstate->process_func = on_mp_write_session_request_read1; 227 break; 228 case CET_MP_READ_SESSION_REQUEST: 229 qstate->process_func = on_mp_read_session_request_read1; 230 break; 231 default: 232 TRACE_OUT(on_query_startup); 233 return (-1); 234 } 235 236 qstate->kevent_watermark = 0; 237 TRACE_OUT(on_query_startup); 238 return (0); 239 } 240 241 /* 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 246 */ 247 static int 248 on_rw_mapper(struct query_state *qstate) 249 { 250 ssize_t result; 251 int elem_type; 252 253 TRACE_IN(on_rw_mapper); 254 if (qstate->kevent_watermark == 0) { 255 qstate->kevent_watermark = sizeof(int); 256 } else { 257 result = qstate->read_func(qstate, &elem_type, sizeof(int)); 258 if (result != sizeof(int)) { 259 TRACE_OUT(on_rw_mapper); 260 return (-1); 261 } 262 263 switch (elem_type) { 264 case CET_WRITE_REQUEST: 265 qstate->kevent_watermark = sizeof(size_t); 266 qstate->process_func = on_write_request_read1; 267 break; 268 case CET_READ_REQUEST: 269 qstate->kevent_watermark = sizeof(size_t); 270 qstate->process_func = on_read_request_read1; 271 break; 272 default: 273 TRACE_OUT(on_rw_mapper); 274 return (-1); 275 break; 276 } 277 } 278 TRACE_OUT(on_rw_mapper); 279 return (0); 280 } 281 282 /* 283 * The default query_destroy function 284 */ 285 static void 286 on_query_destroy(struct query_state *qstate) 287 { 288 289 TRACE_IN(on_query_destroy); 290 finalize_comm_element(&qstate->response); 291 finalize_comm_element(&qstate->request); 292 TRACE_OUT(on_query_destroy); 293 } 294 295 /* 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 301 */ 302 static int 303 on_write_request_read1(struct query_state *qstate) 304 { 305 struct cache_write_request *write_request; 306 ssize_t result; 307 308 TRACE_IN(on_write_request_read1); 309 if (qstate->kevent_watermark == 0) 310 qstate->kevent_watermark = sizeof(size_t) * 3; 311 else { 312 init_comm_element(&qstate->request, CET_WRITE_REQUEST); 313 write_request = get_cache_write_request(&qstate->request); 314 315 result = qstate->read_func(qstate, &write_request->entry_length, 316 sizeof(size_t)); 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)); 321 322 if (result != sizeof(size_t) * 3) { 323 TRACE_OUT(on_write_request_read1); 324 return (-1); 325 } 326 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); 332 return (-1); 333 } 334 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); 340 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); 349 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); 356 } 357 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; 362 } 363 364 TRACE_OUT(on_write_request_read1); 365 return (0); 366 } 367 368 static int 369 on_write_request_read2(struct query_state *qstate) 370 { 371 struct cache_write_request *write_request; 372 ssize_t result; 373 374 TRACE_IN(on_write_request_read2); 375 write_request = get_cache_write_request(&qstate->request); 376 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); 384 385 if (result != qstate->kevent_watermark) { 386 TRACE_OUT(on_write_request_read2); 387 return (-1); 388 } 389 write_request->cache_key_size += qstate->eid_str_length; 390 391 qstate->kevent_watermark = 0; 392 if (write_request->data_size != 0) 393 qstate->process_func = on_write_request_process; 394 else 395 qstate->process_func = on_negative_write_request_process; 396 TRACE_OUT(on_write_request_read2); 397 return (0); 398 } 399 400 static int 401 on_write_request_process(struct query_state *qstate) 402 { 403 struct cache_write_request *write_request; 404 struct cache_write_response *write_response; 405 cache_entry c_entry; 406 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); 411 412 qstate->config_entry = configuration_find_entry( 413 s_configuration, write_request->entry); 414 415 if (qstate->config_entry == NULL) { 416 write_response->error_code = ENOENT; 417 418 LOG_ERR_2("write_request", "can't find configuration" 419 " entry '%s'. aborting request", write_request->entry); 420 goto fin; 421 } 422 423 if (qstate->config_entry->enabled == 0) { 424 write_response->error_code = EACCES; 425 426 LOG_ERR_2("write_request", 427 "configuration entry '%s' is disabled", 428 write_request->entry); 429 goto fin; 430 } 431 432 if (qstate->config_entry->perform_actual_lookups != 0) { 433 write_response->error_code = EOPNOTSUPP; 434 435 LOG_ERR_2("write_request", 436 "entry '%s' performs lookups by itself: " 437 "can't write to it", write_request->entry); 438 goto fin; 439 } 440 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, 451 write_request->data, 452 write_request->data_size); 453 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE); 454 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)); 460 461 } else 462 write_response->error_code = -1; 463 464 fin: 465 qstate->kevent_filter = EVFILT_WRITE; 466 qstate->kevent_watermark = sizeof(int); 467 qstate->process_func = on_write_response_write1; 468 469 TRACE_OUT(on_write_request_process); 470 return (0); 471 } 472 473 static int 474 on_negative_write_request_process(struct query_state *qstate) 475 { 476 struct cache_write_request *write_request; 477 struct cache_write_response *write_response; 478 cache_entry c_entry; 479 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); 484 485 qstate->config_entry = configuration_find_entry ( 486 s_configuration, write_request->entry); 487 488 if (qstate->config_entry == NULL) { 489 write_response->error_code = ENOENT; 490 491 LOG_ERR_2("negative_write_request", 492 "can't find configuration" 493 " entry '%s'. aborting request", write_request->entry); 494 goto fin; 495 } 496 497 if (qstate->config_entry->enabled == 0) { 498 write_response->error_code = EACCES; 499 500 LOG_ERR_2("negative_write_request", 501 "configuration entry '%s' is disabled", 502 write_request->entry); 503 goto fin; 504 } 505 506 if (qstate->config_entry->perform_actual_lookups != 0) { 507 write_response->error_code = EOPNOTSUPP; 508 509 LOG_ERR_2("negative_write_request", 510 "entry '%s' performs lookups by itself: " 511 "can't write to it", write_request->entry); 512 goto fin; 513 } else { 514 #ifdef NS_NSCD_EID_CHECKING 515 if (check_query_eids(qstate) != 0) { 516 write_response->error_code = EPERM; 517 goto fin; 518 } 519 #endif 520 } 521 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, 532 negative_data, 533 sizeof(negative_data)); 534 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE); 535 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)); 541 } else 542 write_response->error_code = -1; 543 544 fin: 545 qstate->kevent_filter = EVFILT_WRITE; 546 qstate->kevent_watermark = sizeof(int); 547 qstate->process_func = on_write_response_write1; 548 549 TRACE_OUT(on_negative_write_request_process); 550 return (0); 551 } 552 553 static int 554 on_write_response_write1(struct query_state *qstate) 555 { 556 struct cache_write_response *write_response; 557 ssize_t result; 558 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, 562 sizeof(int)); 563 if (result != sizeof(int)) { 564 TRACE_OUT(on_write_response_write1); 565 return (-1); 566 } 567 568 finalize_comm_element(&qstate->request); 569 finalize_comm_element(&qstate->response); 570 571 qstate->kevent_watermark = sizeof(int); 572 qstate->kevent_filter = EVFILT_READ; 573 qstate->process_func = on_rw_mapper; 574 575 TRACE_OUT(on_write_response_write1); 576 return (0); 577 } 578 579 /* 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 584 */ 585 static int 586 on_read_request_read1(struct query_state *qstate) 587 { 588 struct cache_read_request *read_request; 589 ssize_t result; 590 591 TRACE_IN(on_read_request_read1); 592 if (qstate->kevent_watermark == 0) 593 qstate->kevent_watermark = sizeof(size_t) * 2; 594 else { 595 init_comm_element(&qstate->request, CET_READ_REQUEST); 596 read_request = get_cache_read_request(&qstate->request); 597 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)); 602 603 if (result != sizeof(size_t) * 2) { 604 TRACE_OUT(on_read_request_read1); 605 return (-1); 606 } 607 608 if (BUFSIZE_INVALID(read_request->entry_length) || 609 BUFSIZE_INVALID(read_request->cache_key_size)) { 610 TRACE_OUT(on_read_request_read1); 611 return (-1); 612 } 613 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); 618 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); 627 628 qstate->kevent_watermark = read_request->entry_length + 629 read_request->cache_key_size; 630 qstate->process_func = on_read_request_read2; 631 } 632 633 TRACE_OUT(on_read_request_read1); 634 return (0); 635 } 636 637 static int 638 on_read_request_read2(struct query_state *qstate) 639 { 640 struct cache_read_request *read_request; 641 ssize_t result; 642 643 TRACE_IN(on_read_request_read2); 644 read_request = get_cache_read_request(&qstate->request); 645 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); 651 652 if (result != qstate->kevent_watermark) { 653 TRACE_OUT(on_read_request_read2); 654 return (-1); 655 } 656 read_request->cache_key_size += qstate->eid_str_length; 657 658 qstate->kevent_watermark = 0; 659 qstate->process_func = on_read_request_process; 660 661 TRACE_OUT(on_read_request_read2); 662 return (0); 663 } 664 665 static int 666 on_read_request_process(struct query_state *qstate) 667 { 668 struct cache_read_request *read_request; 669 struct cache_read_response *read_response; 670 cache_entry c_entry, neg_c_entry; 671 672 struct agent *lookup_agent; 673 struct common_agent *c_agent; 674 int res; 675 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); 680 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; 685 686 LOG_ERR_2("read_request", 687 "can't find configuration " 688 "entry '%s'. aborting request", read_request->entry); 689 goto fin; 690 } 691 692 if (qstate->config_entry->enabled == 0) { 693 read_response->error_code = EACCES; 694 695 LOG_ERR_2("read_request", 696 "configuration entry '%s' is disabled", 697 read_request->entry); 698 goto fin; 699 } 700 701 /* 702 * if we perform lookups by ourselves, then we don't need to separate 703 * cache entries by euid and egid 704 */ 705 if (qstate->config_entry->perform_actual_lookups != 0) 706 memset(read_request->cache_key, 0, qstate->eid_str_length); 707 else { 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; 712 goto fin; 713 } 714 #endif 715 } 716 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); 730 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, 738 read_response->data, 739 &read_response->data_size); 740 } 741 configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE); 742 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); 750 751 if (read_response->error_code == -2) { 752 read_response->error_code = 0; 753 read_response->data = NULL; 754 read_response->data_size = 0; 755 } 756 } 757 configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE); 758 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; 764 765 lookup_agent = find_agent(s_agent_table, 766 read_request->entry, COMMON_AGENT); 767 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); 778 779 if (res == NS_SUCCESS) { 780 read_response->error_code = 0; 781 configuration_lock_entry( 782 qstate->config_entry, 783 CELT_POSITIVE); 784 cache_write(c_entry, 785 read_request->cache_key, 786 read_request->cache_key_size, 787 read_response->data, 788 read_response->data_size); 789 configuration_unlock_entry( 790 qstate->config_entry, 791 CELT_POSITIVE); 792 } else if ((res == NS_NOTFOUND) || 793 (res == NS_RETURN)) { 794 configuration_lock_entry( 795 qstate->config_entry, 796 CELT_NEGATIVE); 797 cache_write(neg_c_entry, 798 read_request->cache_key, 799 read_request->cache_key_size, 800 negative_data, 801 sizeof(negative_data)); 802 configuration_unlock_entry( 803 qstate->config_entry, 804 CELT_NEGATIVE); 805 806 read_response->error_code = 0; 807 read_response->data = NULL; 808 read_response->data_size = 0; 809 } 810 } 811 } 812 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)); 818 } else 819 read_response->error_code = -1; 820 821 fin: 822 qstate->kevent_filter = EVFILT_WRITE; 823 if (read_response->error_code == 0) 824 qstate->kevent_watermark = sizeof(int) + sizeof(size_t); 825 else 826 qstate->kevent_watermark = sizeof(int); 827 qstate->process_func = on_read_response_write1; 828 829 TRACE_OUT(on_read_request_process); 830 return (0); 831 } 832 833 static int 834 on_read_response_write1(struct query_state *qstate) 835 { 836 struct cache_read_response *read_response; 837 ssize_t result; 838 839 TRACE_IN(on_read_response_write1); 840 read_response = get_cache_read_response(&qstate->response); 841 842 result = qstate->write_func(qstate, &read_response->error_code, 843 sizeof(int)); 844 845 if (read_response->error_code == 0) { 846 result += qstate->write_func(qstate, &read_response->data_size, 847 sizeof(size_t)); 848 if (result != qstate->kevent_watermark) { 849 TRACE_OUT(on_read_response_write1); 850 return (-1); 851 } 852 853 qstate->kevent_watermark = read_response->data_size; 854 qstate->process_func = on_read_response_write2; 855 } else { 856 if (result != qstate->kevent_watermark) { 857 TRACE_OUT(on_read_response_write1); 858 return (-1); 859 } 860 861 qstate->kevent_watermark = 0; 862 qstate->process_func = NULL; 863 } 864 865 TRACE_OUT(on_read_response_write1); 866 return (0); 867 } 868 869 static int 870 on_read_response_write2(struct query_state *qstate) 871 { 872 struct cache_read_response *read_response; 873 ssize_t result; 874 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); 882 return (-1); 883 } 884 } 885 886 finalize_comm_element(&qstate->request); 887 finalize_comm_element(&qstate->response); 888 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); 893 return (0); 894 } 895 896 /* 897 * The functions below are used to process write requests. 898 * - on_transform_request_read1 and on_transform_request_read2 read the 899 * request itself 900 * - on_transform_request_process processes it 901 * - on_transform_response_write1 sends the response 902 */ 903 static int 904 on_transform_request_read1(struct query_state *qstate) 905 { 906 struct cache_transform_request *transform_request; 907 ssize_t result; 908 909 TRACE_IN(on_transform_request_read1); 910 if (qstate->kevent_watermark == 0) 911 qstate->kevent_watermark = sizeof(size_t) + sizeof(int); 912 else { 913 init_comm_element(&qstate->request, CET_TRANSFORM_REQUEST); 914 transform_request = 915 get_cache_transform_request(&qstate->request); 916 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)); 921 922 if (result != sizeof(size_t) + sizeof(int)) { 923 TRACE_OUT(on_transform_request_read1); 924 return (-1); 925 } 926 927 if ((transform_request->transformation_type != TT_USER) && 928 (transform_request->transformation_type != TT_ALL)) { 929 TRACE_OUT(on_transform_request_read1); 930 return (-1); 931 } 932 933 if (transform_request->entry_length != 0) { 934 if (BUFSIZE_INVALID(transform_request->entry_length)) { 935 TRACE_OUT(on_transform_request_read1); 936 return (-1); 937 } 938 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); 944 945 qstate->process_func = on_transform_request_read2; 946 } else 947 qstate->process_func = on_transform_request_process; 948 949 qstate->kevent_watermark = transform_request->entry_length; 950 } 951 952 TRACE_OUT(on_transform_request_read1); 953 return (0); 954 } 955 956 static int 957 on_transform_request_read2(struct query_state *qstate) 958 { 959 struct cache_transform_request *transform_request; 960 ssize_t result; 961 962 TRACE_IN(on_transform_request_read2); 963 transform_request = get_cache_transform_request(&qstate->request); 964 965 result = qstate->read_func(qstate, transform_request->entry, 966 transform_request->entry_length); 967 968 if (result != qstate->kevent_watermark) { 969 TRACE_OUT(on_transform_request_read2); 970 return (-1); 971 } 972 973 qstate->kevent_watermark = 0; 974 qstate->process_func = on_transform_request_process; 975 976 TRACE_OUT(on_transform_request_read2); 977 return (0); 978 } 979 980 static int 981 on_transform_request_process(struct query_state *qstate) 982 { 983 struct cache_transform_request *transform_request; 984 struct cache_transform_response *transform_response; 985 struct configuration_entry *config_entry; 986 size_t i, size; 987 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); 992 993 switch (transform_request->transformation_type) { 994 case TT_USER: 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( 999 s_configuration, i); 1000 1001 if (config_entry->perform_actual_lookups == 0) 1002 clear_config_entry_part(config_entry, 1003 qstate->eid_str, qstate->eid_str_length); 1004 } 1005 } else { 1006 qstate->config_entry = configuration_find_entry( 1007 s_configuration, transform_request->entry); 1008 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; 1015 goto fin; 1016 } 1017 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; 1024 goto fin; 1025 } 1026 1027 clear_config_entry_part(qstate->config_entry, 1028 qstate->eid_str, qstate->eid_str_length); 1029 } 1030 break; 1031 case TT_ALL: 1032 if (qstate->euid != 0) 1033 transform_response->error_code = -1; 1034 else { 1035 if (transform_request->entry == NULL) { 1036 size = configuration_get_entries_size( 1037 s_configuration); 1038 for (i = 0; i < size; ++i) { 1039 clear_config_entry( 1040 configuration_get_entry( 1041 s_configuration, i)); 1042 } 1043 } else { 1044 qstate->config_entry = configuration_find_entry( 1045 s_configuration, 1046 transform_request->entry); 1047 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; 1054 goto fin; 1055 } 1056 1057 clear_config_entry(qstate->config_entry); 1058 } 1059 } 1060 break; 1061 default: 1062 transform_response->error_code = -1; 1063 } 1064 1065 fin: 1066 qstate->kevent_watermark = 0; 1067 qstate->process_func = on_transform_response_write1; 1068 TRACE_OUT(on_transform_request_process); 1069 return (0); 1070 } 1071 1072 static int 1073 on_transform_response_write1(struct query_state *qstate) 1074 { 1075 struct cache_transform_response *transform_response; 1076 ssize_t result; 1077 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, 1081 sizeof(int)); 1082 if (result != sizeof(int)) { 1083 TRACE_OUT(on_transform_response_write1); 1084 return (-1); 1085 } 1086 1087 finalize_comm_element(&qstate->request); 1088 finalize_comm_element(&qstate->response); 1089 1090 qstate->kevent_watermark = 0; 1091 qstate->process_func = NULL; 1092 TRACE_OUT(on_transform_response_write1); 1093 return (0); 1094 } 1095 1096 /* 1097 * Checks if the client's euid and egid do not differ from its uid and gid. 1098 * Returns 0 on success. 1099 */ 1100 int 1101 check_query_eids(struct query_state *qstate) 1102 { 1103 1104 return ((qstate->uid != qstate->euid) || (qstate->gid != qstate->egid) ? -1 : 0); 1105 } 1106 1107 /* 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 1110 */ 1111 ssize_t 1112 query_io_buffer_read(struct query_state *qstate, void *buf, size_t nbytes) 1113 { 1114 ssize_t result; 1115 1116 TRACE_IN(query_io_buffer_read); 1117 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL)) 1118 return (-1); 1119 1120 if (nbytes < qstate->io_buffer + qstate->io_buffer_size - 1121 qstate->io_buffer_p) 1122 result = nbytes; 1123 else 1124 result = qstate->io_buffer + qstate->io_buffer_size - 1125 qstate->io_buffer_p; 1126 1127 memcpy(buf, qstate->io_buffer_p, result); 1128 qstate->io_buffer_p += result; 1129 1130 if (qstate->io_buffer_p == qstate->io_buffer + qstate->io_buffer_size) { 1131 free(qstate->io_buffer); 1132 qstate->io_buffer = NULL; 1133 1134 qstate->write_func = query_socket_write; 1135 qstate->read_func = query_socket_read; 1136 } 1137 1138 TRACE_OUT(query_io_buffer_read); 1139 return (result); 1140 } 1141 1142 /* 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 1145 */ 1146 ssize_t 1147 query_io_buffer_write(struct query_state *qstate, const void *buf, 1148 size_t nbytes) 1149 { 1150 ssize_t result; 1151 1152 TRACE_IN(query_io_buffer_write); 1153 if ((qstate->io_buffer_size == 0) || (qstate->io_buffer == NULL)) 1154 return (-1); 1155 1156 if (nbytes < qstate->io_buffer + qstate->io_buffer_size - 1157 qstate->io_buffer_p) 1158 result = nbytes; 1159 else 1160 result = qstate->io_buffer + qstate->io_buffer_size - 1161 qstate->io_buffer_p; 1162 1163 memcpy(qstate->io_buffer_p, buf, result); 1164 qstate->io_buffer_p += result; 1165 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; 1169 1170 qstate->write_func = query_socket_write; 1171 qstate->read_func = query_socket_read; 1172 } 1173 1174 TRACE_OUT(query_io_buffer_write); 1175 return (result); 1176 } 1177 1178 /* 1179 * The default "read" function, which reads data directly from socket 1180 */ 1181 ssize_t 1182 query_socket_read(struct query_state *qstate, void *buf, size_t nbytes) 1183 { 1184 ssize_t result; 1185 1186 TRACE_IN(query_socket_read); 1187 if (qstate->socket_failed != 0) { 1188 TRACE_OUT(query_socket_read); 1189 return (-1); 1190 } 1191 1192 result = read(qstate->sockfd, buf, nbytes); 1193 if ((result == -1) || (result < nbytes)) 1194 qstate->socket_failed = 1; 1195 1196 TRACE_OUT(query_socket_read); 1197 return (result); 1198 } 1199 1200 /* 1201 * The default "write" function, which writes data directly to socket 1202 */ 1203 ssize_t 1204 query_socket_write(struct query_state *qstate, const void *buf, size_t nbytes) 1205 { 1206 ssize_t result; 1207 1208 TRACE_IN(query_socket_write); 1209 if (qstate->socket_failed != 0) { 1210 TRACE_OUT(query_socket_write); 1211 return (-1); 1212 } 1213 1214 result = write(qstate->sockfd, buf, nbytes); 1215 if ((result == -1) || (result < nbytes)) 1216 qstate->socket_failed = 1; 1217 1218 TRACE_OUT(query_socket_write); 1219 return (result); 1220 } 1221 1222 /* 1223 * Initializes the query_state structure by filling it with the default values. 1224 */ 1225 struct query_state * 1226 init_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t egid) 1227 { 1228 struct query_state *retval; 1229 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)); 1234 1235 retval->sockfd = sockfd; 1236 retval->kevent_filter = EVFILT_READ; 1237 retval->kevent_watermark = kevent_watermark; 1238 1239 retval->euid = euid; 1240 retval->egid = egid; 1241 retval->uid = retval->gid = -1; 1242 1243 if (asprintf(&retval->eid_str, "%d_%d_", retval->euid, 1244 retval->egid) == -1) { 1245 free(retval); 1246 return (NULL); 1247 } 1248 retval->eid_str_length = strlen(retval->eid_str); 1249 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; 1254 1255 retval->write_func = query_socket_write; 1256 retval->read_func = query_socket_read; 1257 1258 get_time_func(&retval->creation_time); 1259 memcpy(&retval->timeout, &s_configuration->query_timeout, 1260 sizeof(struct timeval)); 1261 1262 TRACE_OUT(init_query_state); 1263 return (retval); 1264 } 1265 1266 void 1267 destroy_query_state(struct query_state *qstate) 1268 { 1269 1270 TRACE_IN(destroy_query_state); 1271 if (qstate->eid_str != NULL) 1272 free(qstate->eid_str); 1273 1274 if (qstate->io_buffer != NULL) 1275 free(qstate->io_buffer); 1276 1277 qstate->destroy_func(qstate); 1278 free(qstate); 1279 TRACE_OUT(destroy_query_state); 1280 } 1281