1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <alloca.h> 28 #include <signal.h> 29 #include <sys/stat.h> 30 #include <unistd.h> 31 #include <pthread.h> 32 #include <time.h> 33 #include <errno.h> 34 #include <door.h> 35 #include <zone.h> 36 #include <resolv.h> 37 #include <sys/socket.h> 38 #include <net/route.h> 39 #include <string.h> 40 #include <net/if.h> 41 #include <sys/stat.h> 42 #include <fcntl.h> 43 #include "nscd_common.h" 44 #include "nscd_door.h" 45 #include "nscd_config.h" 46 #include "nscd_switch.h" 47 #include "nscd_log.h" 48 #include "nscd_selfcred.h" 49 #include "nscd_frontend.h" 50 #include "nscd_admin.h" 51 52 static void rts_mon(void); 53 static void keep_open_dns_socket(void); 54 55 extern nsc_ctx_t *cache_ctx_p[]; 56 57 /* 58 * Current active Configuration data for the frontend component 59 */ 60 static nscd_cfg_global_frontend_t frontend_cfg_g; 61 static nscd_cfg_frontend_t *frontend_cfg; 62 63 static int max_servers = 0; 64 static int max_servers_set = 0; 65 static int per_user_is_on = 1; 66 67 static char *main_execname; 68 static char **main_argv; 69 extern int _whoami; 70 extern long activity; 71 extern mutex_t activity_lock; 72 73 static sema_t common_sema; 74 75 static thread_key_t lookup_state_key; 76 static mutex_t create_lock = DEFAULTMUTEX; 77 static int num_servers = 0; 78 static thread_key_t server_key; 79 80 /* 81 * Bind a TSD value to a server thread. This enables the destructor to 82 * be called if/when this thread exits. This would be a programming 83 * error, but better safe than sorry. 84 */ 85 /*ARGSUSED*/ 86 static void * 87 server_tsd_bind(void *arg) 88 { 89 static void *value = 0; 90 91 /* disable cancellation to avoid hangs if server threads disappear */ 92 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 93 (void) thr_setspecific(server_key, value); 94 (void) door_return(NULL, 0, NULL, 0); 95 96 /* make lint happy */ 97 return (NULL); 98 } 99 100 /* 101 * Server threads are created here. 102 */ 103 /*ARGSUSED*/ 104 static void 105 server_create(door_info_t *dip) 106 { 107 (void) mutex_lock(&create_lock); 108 if (++num_servers > max_servers) { 109 num_servers--; 110 (void) mutex_unlock(&create_lock); 111 return; 112 } 113 (void) mutex_unlock(&create_lock); 114 (void) thr_create(NULL, 0, server_tsd_bind, NULL, 115 THR_BOUND|THR_DETACHED, NULL); 116 } 117 118 /* 119 * Server thread are destroyed here 120 */ 121 /*ARGSUSED*/ 122 static void 123 server_destroy(void *arg) 124 { 125 (void) mutex_lock(&create_lock); 126 num_servers--; 127 (void) mutex_unlock(&create_lock); 128 } 129 130 /* 131 * get clearance 132 */ 133 int 134 _nscd_get_clearance(sema_t *sema) { 135 if (sema_trywait(&common_sema) == 0) { 136 (void) thr_setspecific(lookup_state_key, NULL); 137 return (0); 138 } 139 140 if (sema_trywait(sema) == 0) { 141 (void) thr_setspecific(lookup_state_key, (void*)1); 142 return (0); 143 } 144 145 return (1); 146 } 147 148 149 /* 150 * release clearance 151 */ 152 int 153 _nscd_release_clearance(sema_t *sema) { 154 int which; 155 156 (void) thr_getspecific(lookup_state_key, (void**)&which); 157 if (which == 0) /* from common pool */ { 158 (void) sema_post(&common_sema); 159 return (0); 160 } 161 162 (void) sema_post(sema); 163 return (1); 164 } 165 166 static void 167 dozip(void) 168 { 169 /* not much here */ 170 } 171 172 /* 173 * _nscd_restart_if_cfgfile_changed() 174 * Restart if modification times of nsswitch.conf or resolv.conf have changed. 175 * 176 * If nsswitch.conf has changed then it is possible that sources for 177 * various backends have changed and therefore the current cached 178 * data may not be consistent with the new data sources. By 179 * restarting the cache will be cleared and the new configuration will 180 * be used. 181 * 182 * The check for resolv.conf is made as only the first call to 183 * res_gethostbyname() or res_getaddrbyname() causes a call to 184 * res_ninit() to occur which in turn parses resolv.conf. Therefore 185 * to benefit from changes to resolv.conf nscd must be restarted when 186 * resolv.conf is updated, removed or created. If res_getXbyY calls 187 * are removed from NSS then this check could be removed. 188 * 189 */ 190 void 191 _nscd_restart_if_cfgfile_changed() 192 { 193 194 static mutex_t nsswitch_lock = DEFAULTMUTEX; 195 static timestruc_t last_nsswitch_check = { 0 }; 196 static timestruc_t last_nsswitch_modified = { 0 }; 197 static timestruc_t last_resolv_modified = { -1, 0 }; 198 static mutex_t restarting_lock = DEFAULTMUTEX; 199 static int restarting = 0; 200 int restart = 0; 201 time_t now = time(NULL); 202 char *me = "_nscd_restart_if_cfgfile_changed"; 203 204 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\ 205 (void) mutex_lock(&restarting_lock);\ 206 if (restarting == 0) {\ 207 restarting = 1;\ 208 restart = 1;\ 209 }\ 210 (void) mutex_unlock(&restarting_lock);\ 211 } 212 213 if (restarting == 1) 214 return; 215 216 if (now - last_nsswitch_check.tv_sec < _NSC_FILE_CHECK_TIME) 217 return; 218 219 (void) mutex_lock(&nsswitch_lock); 220 221 if (now - last_nsswitch_check.tv_sec >= _NSC_FILE_CHECK_TIME) { 222 struct stat nss_buf; 223 struct stat res_buf; 224 225 last_nsswitch_check.tv_sec = now; 226 last_nsswitch_check.tv_nsec = 0; 227 228 (void) mutex_unlock(&nsswitch_lock); /* let others continue */ 229 230 if (stat("/etc/nsswitch.conf", &nss_buf) < 0) { 231 return; 232 } else if (last_nsswitch_modified.tv_sec == 0) { 233 last_nsswitch_modified = nss_buf.st_mtim; 234 } 235 236 if (last_nsswitch_modified.tv_sec < nss_buf.st_mtim.tv_sec || 237 (last_nsswitch_modified.tv_sec == nss_buf.st_mtim.tv_sec && 238 last_nsswitch_modified.tv_nsec < nss_buf.st_mtim.tv_nsec)) { 239 FLAG_RESTART_REQUIRED; 240 } 241 242 if (restart == 0) { 243 if (stat("/etc/resolv.conf", &res_buf) < 0) { 244 /* Unable to stat file, were we previously? */ 245 if (last_resolv_modified.tv_sec > 0) { 246 /* Yes, it must have been removed. */ 247 FLAG_RESTART_REQUIRED; 248 } else if (last_resolv_modified.tv_sec == -1) { 249 /* No, then we've never seen it. */ 250 last_resolv_modified.tv_sec = 0; 251 } 252 } else if (last_resolv_modified.tv_sec == -1) { 253 /* We've just started and file is present. */ 254 last_resolv_modified = res_buf.st_mtim; 255 } else if (last_resolv_modified.tv_sec == 0) { 256 /* Wasn't there at start-up. */ 257 FLAG_RESTART_REQUIRED; 258 } else if (last_resolv_modified.tv_sec < 259 res_buf.st_mtim.tv_sec || 260 (last_resolv_modified.tv_sec == 261 res_buf.st_mtim.tv_sec && 262 last_resolv_modified.tv_nsec < 263 res_buf.st_mtim.tv_nsec)) { 264 FLAG_RESTART_REQUIRED; 265 } 266 } 267 268 if (restart == 1) { 269 char *fmri; 270 271 /* 272 * if in self cred mode, kill the forker and 273 * child nscds 274 */ 275 if (_nscd_is_self_cred_on(0, NULL)) { 276 _nscd_kill_forker(); 277 _nscd_kill_all_children(); 278 } 279 280 /* 281 * time for restart 282 */ 283 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) 284 (me, "nscd restart due to %s or %s change\n", 285 "/etc/nsswitch.conf", "resolv.conf"); 286 /* 287 * try to restart under smf 288 */ 289 if ((fmri = getenv("SMF_FMRI")) == NULL) { 290 /* not running under smf - reexec */ 291 (void) execv(main_execname, main_argv); 292 exit(1); /* just in case */ 293 } 294 295 if (smf_restart_instance(fmri) == 0) 296 (void) sleep(10); /* wait a bit */ 297 exit(1); /* give up waiting for resurrection */ 298 } 299 300 } else 301 (void) mutex_unlock(&nsswitch_lock); 302 } 303 304 uid_t 305 _nscd_get_client_euid() 306 { 307 ucred_t *uc = NULL; 308 uid_t id; 309 char *me = "get_client_euid"; 310 311 if (door_ucred(&uc) != 0) { 312 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 313 (me, "door_ucred: %s\n", strerror(errno)); 314 return ((uid_t)-1); 315 } 316 317 id = ucred_geteuid(uc); 318 ucred_free(uc); 319 return (id); 320 } 321 322 /* 323 * Check to see if the door client's euid is 0 or if it has PRIV_FILE_DAC_READ 324 * privilege. Return 0 if yes, -1 otherwise. 325 */ 326 int 327 _nscd_check_client_read_priv() 328 { 329 int rc = 0; 330 ucred_t *uc = NULL; 331 const priv_set_t *eset; 332 char *me = "_nscd_check_client_read_priv"; 333 334 if (door_ucred(&uc) != 0) { 335 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 336 (me, "door_ucred: %s\n", strerror(errno)); 337 return (-1); 338 } 339 340 if (ucred_geteuid(uc) == 0) { 341 ucred_free(uc); 342 return (0); 343 } 344 345 eset = ucred_getprivset(uc, PRIV_EFFECTIVE); 346 if (!priv_ismember(eset, PRIV_FILE_DAC_READ)) 347 rc = -1; 348 ucred_free(uc); 349 return (rc); 350 } 351 352 static void 353 N2N_check_priv( 354 void *buf, 355 char *dc_str) 356 { 357 nss_pheader_t *phdr = (nss_pheader_t *)buf; 358 ucred_t *uc = NULL; 359 const priv_set_t *eset; 360 zoneid_t zoneid; 361 int errnum; 362 char *me = "N2N_check_priv"; 363 364 if (door_ucred(&uc) != 0) { 365 errnum = errno; 366 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 367 (me, "door_ucred: %s\n", strerror(errno)); 368 369 NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); 370 } 371 372 eset = ucred_getprivset(uc, PRIV_EFFECTIVE); 373 zoneid = ucred_getzoneid(uc); 374 375 if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || 376 eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : 377 ucred_geteuid(uc) != 0) { 378 379 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 380 (me, "%s call failed(cred): caller pid %d, uid %d, " 381 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), 382 ucred_getruid(uc), ucred_geteuid(uc), zoneid); 383 ucred_free(uc); 384 385 NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES); 386 } 387 388 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 389 (me, "nscd received %s cmd from pid %d, uid %d, " 390 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), 391 ucred_getruid(uc), ucred_geteuid(uc), zoneid); 392 393 ucred_free(uc); 394 395 NSCD_RETURN_STATUS_SUCCESS(phdr); 396 } 397 398 void 399 _nscd_APP_check_cred( 400 void *buf, 401 pid_t *pidp, 402 char *dc_str, 403 int log_comp, 404 int log_level) 405 { 406 nss_pheader_t *phdr = (nss_pheader_t *)buf; 407 ucred_t *uc = NULL; 408 uid_t ruid; 409 uid_t euid; 410 pid_t pid; 411 int errnum; 412 char *me = "_nscd_APP_check_cred"; 413 414 if (door_ucred(&uc) != 0) { 415 errnum = errno; 416 _NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR) 417 (me, "door_ucred: %s\n", strerror(errno)); 418 419 NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); 420 } 421 422 NSCD_SET_STATUS_SUCCESS(phdr); 423 pid = ucred_getpid(uc); 424 if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc), 425 euid = ucred_geteuid(uc))) { 426 if (pidp != NULL) { 427 if (*pidp == (pid_t)-1) 428 *pidp = pid; 429 else if (*pidp != pid) { 430 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES); 431 } 432 } 433 } else { 434 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES); 435 } 436 437 ucred_free(uc); 438 439 if (NSCD_STATUS_IS_NOT_OK(phdr)) { 440 _NSCD_LOG(log_comp, log_level) 441 (me, "%s call failed: caller pid %d (input pid = %d), ruid %d, " 442 "euid %d, header ruid %d, header euid %d\n", dc_str, 443 pid, (pidp != NULL) ? *pidp : -1, ruid, euid, 444 ((nss_pheader_t *)(buf))->p_ruid, 445 ((nss_pheader_t *)(buf))->p_euid); 446 } 447 } 448 449 /* log error and return -1 when an invalid packed buffer header is found */ 450 static int 451 pheader_error(nss_pheader_t *phdr, uint32_t call_number) 452 { 453 char *call_num_str; 454 455 switch (call_number) { 456 case NSCD_SEARCH: 457 call_num_str = "NSCD_SEARCH"; 458 break; 459 case NSCD_SETENT: 460 call_num_str = "NSCD_SETENT"; 461 break; 462 case NSCD_GETENT: 463 call_num_str = "NSCD_GETENT"; 464 break; 465 case NSCD_ENDENT: 466 call_num_str = "NSCD_ENDENT"; 467 break; 468 case NSCD_PUT: 469 call_num_str = "NSCD_PUT"; 470 break; 471 case NSCD_GETHINTS: 472 call_num_str = "NSCD_GETHINTS"; 473 break; 474 default: 475 call_num_str = "UNKNOWN"; 476 break; 477 } 478 479 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 480 ("pheader_error", "call number %s: invalid packed buffer header\n", 481 call_num_str); 482 483 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 484 return (-1); 485 } 486 487 /* 488 * Validate the header of a getXbyY or setent/getent/endent request. 489 * Return 0 if good, -1 otherwise. 490 * 491 * A valid header looks like the following (size is arg_size, does 492 * not include the output area): 493 * +----------------------------------+ -- 494 * | nss_pheader_t (header fixed part)| ^ 495 * | | | 496 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t) 497 * | data_off .... | | 498 * | | v 499 * +----------------------------------+ <----- dbd_off 500 * | dbd (database description) | ^ 501 * | nss_dbd_t + up to 3 strings | | 502 * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off 503 * | length of 3 strings + | | 504 * | length of padding | | 505 * | (total length in multiple of 4) | v 506 * +----------------------------------+ <----- key_off 507 * | lookup key | ^ 508 * | nss_XbyY_key_t, content varies, | | 509 * | based on database and lookup op | len = data_off - key_off 510 * | length = data_off - key_off | | 511 * | including padding, multiple of 4 | v 512 * +----------------------------------+ <----- data_off (= arg_size) 513 * | | ^ 514 * | area to hold results | | 515 * | | len = data_len (= pbufsiz - 516 * | | | data_off) 517 * | | v 518 * +----------------------------------+ <----- pbufsiz 519 */ 520 static int 521 validate_pheader( 522 void *argp, 523 size_t arg_size, 524 uint32_t call_number) 525 { 526 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 527 nssuint_t l1, l2; 528 529 /* 530 * current version is NSCD_HEADER_REV, length of the fixed part 531 * of the header must match the size of nss_pheader_t 532 */ 533 if (phdr->p_version != NSCD_HEADER_REV || 534 phdr->dbd_off != sizeof (nss_pheader_t)) 535 return (pheader_error(phdr, call_number)); 536 537 /* 538 * buffer size and offsets must be in multiple of 4 539 */ 540 if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) || 541 (phdr->data_off & 3)) 542 return (pheader_error(phdr, call_number)); 543 544 /* 545 * the input arg_size is the length of the request header 546 * and should be less than NSCD_PHDR_MAXLEN 547 */ 548 if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN) 549 return (pheader_error(phdr, call_number)); 550 551 /* get length of the dbd area */ 552 l1 = phdr->key_off - phdr-> dbd_off; 553 554 /* 555 * dbd area may contain padding, so length of dbd should 556 * not be less than the length of the actual data 557 */ 558 if (l1 < phdr->dbd_len) 559 return (pheader_error(phdr, call_number)); 560 561 /* get length of the key area */ 562 l2 = phdr->data_off - phdr->key_off; 563 564 /* 565 * key area may contain padding, so length of key area should 566 * not be less than the length of the actual data 567 */ 568 if (l2 < phdr->key_len) 569 return (pheader_error(phdr, call_number)); 570 571 /* 572 * length of fixed part + lengths of dbd and key area = length of 573 * the request header 574 */ 575 if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off) 576 return (pheader_error(phdr, call_number)); 577 578 /* header length + data length = buffer length */ 579 if (phdr->data_off + phdr->data_len != phdr->pbufsiz) 580 return (pheader_error(phdr, call_number)); 581 582 return (0); 583 } 584 585 /* log error and return -1 when an invalid nscd to nscd buffer is found */ 586 static int 587 N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number) 588 { 589 char *call_num_str; 590 591 switch (call_number) { 592 case NSCD_PING: 593 call_num_str = "NSCD_PING"; 594 break; 595 596 case NSCD_IMHERE: 597 call_num_str = "NSCD_IMHERE"; 598 break; 599 600 case NSCD_PULSE: 601 call_num_str = "NSCD_PULSE"; 602 break; 603 604 case NSCD_FORK: 605 call_num_str = "NSCD_FORK"; 606 break; 607 608 case NSCD_KILL: 609 call_num_str = "NSCD_KILL"; 610 break; 611 612 case NSCD_REFRESH: 613 call_num_str = "NSCD_REFRESH"; 614 break; 615 616 case NSCD_GETPUADMIN: 617 call_num_str = "NSCD_GETPUADMIN"; 618 break; 619 620 case NSCD_GETADMIN: 621 call_num_str = "NSCD_GETADMIN"; 622 break; 623 624 case NSCD_SETADMIN: 625 call_num_str = "NSCD_SETADMIN"; 626 break; 627 628 case NSCD_KILLSERVER: 629 call_num_str = "NSCD_KILLSERVER"; 630 break; 631 default: 632 call_num_str = "UNKNOWN"; 633 break; 634 } 635 636 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 637 ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str); 638 639 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 640 NSCD_DOOR_BUFFER_CHECK_FAILED); 641 642 return (-1); 643 } 644 645 /* 646 * Validate the buffer of an nscd to nscd request. 647 * Return 0 if good, -1 otherwise. 648 * 649 * A valid buffer looks like the following (size is arg_size): 650 * +----------------------------------+ -- 651 * | nss_pheader_t (header fixed part)| ^ 652 * | | | 653 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t) 654 * | data_off .... | | 655 * | | v 656 * +----------------------------------+ <---dbd_off = key_off = data_off 657 * | | ^ 658 * | input data/output data | | 659 * | OR no data | len = data_len (= pbufsiz - 660 * | | | data_off) 661 * | | | len could be zero 662 * | | v 663 * +----------------------------------+ <--- pbufsiz 664 */ 665 static int 666 validate_N2Nbuf( 667 void *argp, 668 size_t arg_size, 669 uint32_t call_number) 670 { 671 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 672 673 /* 674 * current version is NSCD_HEADER_REV, length of the fixed part 675 * of the header must match the size of nss_pheader_t 676 */ 677 if (phdr->p_version != NSCD_HEADER_REV || 678 phdr->dbd_off != sizeof (nss_pheader_t)) 679 return (N2Nbuf_error(phdr, call_number)); 680 681 /* 682 * There are no dbd and key data, so the dbd, key, data 683 * offsets should be equal 684 */ 685 if (phdr->dbd_off != phdr->key_off || 686 phdr->dbd_off != phdr->data_off) 687 return (N2Nbuf_error(phdr, call_number)); 688 689 /* 690 * the input arg_size is the buffer length and should 691 * be less or equal than NSCD_N2NBUF_MAXLEN 692 */ 693 if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN) 694 return (N2Nbuf_error(phdr, call_number)); 695 696 /* header length + data length = buffer length */ 697 if (phdr->data_off + phdr->data_len != phdr->pbufsiz) 698 return (N2Nbuf_error(phdr, call_number)); 699 700 return (0); 701 } 702 703 static void 704 lookup(char *argp, size_t arg_size) 705 { 706 nsc_lookup_args_t largs; 707 char space[NSCD_LOOKUP_BUFSIZE]; 708 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 709 710 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, 711 sizeof (space)); 712 713 /* 714 * make sure the first couple bytes of the data area is null, 715 * so that bad strings in the packed header stop here 716 */ 717 (void) memset((char *)phdr + phdr->data_off, 0, 16); 718 719 (void) memset(&largs, 0, sizeof (largs)); 720 largs.buffer = argp; 721 largs.bufsize = arg_size; 722 nsc_lookup(&largs, 0); 723 724 /* 725 * only the PUN needs to keep track of the 726 * activity count to determine when to 727 * terminate itself 728 */ 729 if (_whoami == NSCD_CHILD) { 730 (void) mutex_lock(&activity_lock); 731 ++activity; 732 (void) mutex_unlock(&activity_lock); 733 } 734 735 NSCD_SET_RETURN_ARG(phdr, arg_size); 736 (void) door_return(argp, arg_size, NULL, 0); 737 } 738 739 static void 740 getent(char *argp, size_t arg_size) 741 { 742 char space[NSCD_LOOKUP_BUFSIZE]; 743 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 744 745 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, sizeof (space)); 746 747 nss_pgetent(argp, arg_size); 748 749 NSCD_SET_RETURN_ARG(phdr, arg_size); 750 (void) door_return(argp, arg_size, NULL, 0); 751 } 752 753 static int 754 is_db_per_user(void *buf, char *dblist) 755 { 756 nss_pheader_t *phdr = (nss_pheader_t *)buf; 757 nss_dbd_t *pdbd; 758 char *dbname, *dbn; 759 int len; 760 761 /* copy db name into a temp buffer */ 762 pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off)); 763 dbname = (char *)pdbd + pdbd->o_name; 764 len = strlen(dbname); 765 dbn = alloca(len + 2); 766 (void) memcpy(dbn, dbname, len); 767 768 /* check if <dbname> + ',' can be found in the dblist string */ 769 dbn[len] = ','; 770 dbn[len + 1] = '\0'; 771 if (strstr(dblist, dbn) != NULL) 772 return (1); 773 774 /* 775 * check if <dbname> can be found in the last part 776 * of the dblist string 777 */ 778 dbn[len] = '\0'; 779 if (strstr(dblist, dbn) != NULL) 780 return (1); 781 782 return (0); 783 } 784 785 /* 786 * Check to see if all conditions are met for processing per-user 787 * requests. Returns 1 if yes, -1 if backend is not configured, 788 * 0 otherwise. 789 */ 790 static int 791 need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist) 792 { 793 nss_pheader_t *phdr = (nss_pheader_t *)buf; 794 795 NSCD_SET_STATUS_SUCCESS(phdr); 796 797 /* if already a per-user nscd, no need to get per-user door */ 798 if (whoami == NSCD_CHILD) 799 return (0); 800 801 /* forker shouldn't be asked */ 802 if (whoami == NSCD_FORKER) { 803 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 804 return (0); 805 } 806 807 /* if door client is root, no need for a per-user door */ 808 if (uid == 0) 809 return (0); 810 811 /* 812 * if per-user lookup is not configured, no per-user 813 * door available 814 */ 815 if (_nscd_is_self_cred_on(0, dblist) == 0) 816 return (-1); 817 818 /* 819 * if per-user lookup is not configured for the db, 820 * don't bother 821 */ 822 if (is_db_per_user(phdr, *dblist) == 0) 823 return (0); 824 825 return (1); 826 } 827 828 static void 829 if_selfcred_return_per_user_door(char *argp, size_t arg_size, 830 door_desc_t *dp, int whoami) 831 { 832 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); 833 char *dblist; 834 int door = -1; 835 int rc = 0; 836 door_desc_t desc; 837 char *space; 838 int len; 839 840 /* 841 * check to see if self-cred is configured and 842 * need to return an alternate PUN door 843 */ 844 if (per_user_is_on == 1) { 845 rc = need_per_user_door(argp, whoami, 846 _nscd_get_client_euid(), &dblist); 847 if (rc == -1) 848 per_user_is_on = 0; 849 } 850 if (rc <= 0) { 851 /* 852 * self-cred not configured, and no error detected, 853 * return to continue the door call processing 854 */ 855 if (NSCD_STATUS_IS_OK(phdr)) 856 return; 857 else 858 /* 859 * configured but error detected, 860 * stop the door call processing 861 */ 862 (void) door_return(argp, phdr->data_off, NULL, 0); 863 } 864 865 /* get the alternate PUN door */ 866 _nscd_proc_alt_get(argp, &door); 867 if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) { 868 (void) door_return(argp, phdr->data_off, NULL, 0); 869 } 870 871 /* return the alternate door descriptor */ 872 len = strlen(dblist) + 1; 873 space = alloca(arg_size + len); 874 phdr->data_len = len; 875 (void) memcpy(space, phdr, arg_size); 876 (void) strncpy((char *)space + arg_size, dblist, len); 877 dp = &desc; 878 dp->d_attributes = DOOR_DESCRIPTOR; 879 dp->d_data.d_desc.d_descriptor = door; 880 arg_size += len; 881 (void) door_return(space, arg_size, dp, 1); 882 } 883 884 /*ARGSUSED*/ 885 static void 886 switcher(void *cookie, char *argp, size_t arg_size, 887 door_desc_t *dp, uint_t n_desc) 888 { 889 int iam; 890 pid_t ent_pid = -1; 891 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); 892 void *uptr; 893 int len; 894 size_t buflen; 895 int callnum; 896 char *me = "switcher"; 897 898 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 899 (me, "switcher ...\n"); 900 901 if (argp == DOOR_UNREF_DATA) { 902 (void) printf("Door Slam... exiting\n"); 903 exit(0); 904 } 905 906 if (argp == NULL) { /* empty door call */ 907 (void) door_return(NULL, 0, 0, 0); /* return the favor */ 908 } 909 910 /* 911 * need to restart if main nscd and config file(s) changed 912 */ 913 if (_whoami == NSCD_MAIN) 914 _nscd_restart_if_cfgfile_changed(); 915 916 if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) { 917 918 /* make sure the packed buffer header is good */ 919 if (validate_pheader(argp, arg_size, 920 phdr->nsc_callnumber) == -1) 921 (void) door_return(argp, arg_size, NULL, 0); 922 923 switch (phdr->nsc_callnumber) { 924 925 case NSCD_SEARCH: 926 927 /* if a fallback to main nscd, skip per-user setup */ 928 if (phdr->p_status != NSS_ALTRETRY) 929 if_selfcred_return_per_user_door(argp, arg_size, 930 dp, _whoami); 931 lookup(argp, arg_size); 932 933 break; 934 935 case NSCD_SETENT: 936 937 _nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT", 938 NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT); 939 if (NSCD_STATUS_IS_OK(phdr)) { 940 if_selfcred_return_per_user_door(argp, arg_size, 941 dp, _whoami); 942 nss_psetent(argp, arg_size, ent_pid); 943 } 944 break; 945 946 case NSCD_GETENT: 947 948 getent(argp, arg_size); 949 break; 950 951 case NSCD_ENDENT: 952 953 nss_pendent(argp, arg_size); 954 break; 955 956 case NSCD_PUT: 957 958 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 959 (me, "door call NSCD_PUT not supported yet\n"); 960 961 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 962 break; 963 964 case NSCD_GETHINTS: 965 966 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 967 (me, "door call NSCD_GETHINTS not supported yet\n"); 968 969 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 970 break; 971 972 default: 973 974 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 975 (me, "Unknown name service door call op %x\n", 976 phdr->nsc_callnumber); 977 978 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 979 break; 980 } 981 982 (void) door_return(argp, arg_size, NULL, 0); 983 } 984 985 iam = NSCD_MAIN; 986 callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI; 987 if (callnum == NSCD_IMHERE || 988 callnum == NSCD_PULSE || callnum == NSCD_FORK) 989 iam = phdr->nsc_callnumber & NSCD_WHOAMI; 990 else 991 callnum = phdr->nsc_callnumber; 992 993 /* nscd -> nscd v2 calls */ 994 995 /* make sure the buffer is good */ 996 if (validate_N2Nbuf(argp, arg_size, callnum) == -1) 997 (void) door_return(argp, arg_size, NULL, 0); 998 999 switch (callnum) { 1000 1001 case NSCD_PING: 1002 NSCD_SET_STATUS_SUCCESS(phdr); 1003 break; 1004 1005 case NSCD_IMHERE: 1006 _nscd_proc_iamhere(argp, dp, n_desc, iam); 1007 break; 1008 1009 case NSCD_PULSE: 1010 N2N_check_priv(argp, "NSCD_PULSE"); 1011 if (NSCD_STATUS_IS_OK(phdr)) 1012 _nscd_proc_pulse(argp, iam); 1013 break; 1014 1015 case NSCD_FORK: 1016 N2N_check_priv(argp, "NSCD_FORK"); 1017 if (NSCD_STATUS_IS_OK(phdr)) 1018 _nscd_proc_fork(argp, iam); 1019 break; 1020 1021 case NSCD_KILL: 1022 N2N_check_priv(argp, "NSCD_KILL"); 1023 if (NSCD_STATUS_IS_OK(phdr)) 1024 exit(0); 1025 break; 1026 1027 case NSCD_REFRESH: 1028 N2N_check_priv(argp, "NSCD_REFRESH"); 1029 if (NSCD_STATUS_IS_OK(phdr)) { 1030 if (_nscd_refresh() != NSCD_SUCCESS) 1031 exit(1); 1032 NSCD_SET_STATUS_SUCCESS(phdr); 1033 } 1034 break; 1035 1036 case NSCD_GETPUADMIN: 1037 1038 if (_nscd_is_self_cred_on(0, NULL)) { 1039 _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t)); 1040 } else { 1041 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 1042 NSCD_SELF_CRED_NOT_CONFIGURED); 1043 } 1044 break; 1045 1046 case NSCD_GETADMIN: 1047 1048 len = _nscd_door_getadmin((void *)argp); 1049 if (len == 0) 1050 break; 1051 1052 /* size of door buffer not big enough, allocate one */ 1053 NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen); 1054 1055 /* copy packed header */ 1056 *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp); 1057 1058 /* set new buffer size */ 1059 ((nss_pheader_t *)uptr)->pbufsiz = buflen; 1060 1061 /* try one more time */ 1062 (void) _nscd_door_getadmin((void *)uptr); 1063 (void) door_return(uptr, buflen, NULL, 0); 1064 break; 1065 1066 case NSCD_SETADMIN: 1067 N2N_check_priv(argp, "NSCD_SETADMIN"); 1068 if (NSCD_STATUS_IS_OK(phdr)) 1069 _nscd_door_setadmin(argp); 1070 break; 1071 1072 case NSCD_KILLSERVER: 1073 N2N_check_priv(argp, "NSCD_KILLSERVER"); 1074 if (NSCD_STATUS_IS_OK(phdr)) { 1075 /* also kill the forker nscd if one is running */ 1076 _nscd_kill_forker(); 1077 exit(0); 1078 } 1079 break; 1080 1081 default: 1082 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1083 (me, "Unknown name service door call op %d\n", 1084 phdr->nsc_callnumber); 1085 1086 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 1087 1088 (void) door_return(argp, arg_size, NULL, 0); 1089 break; 1090 1091 } 1092 (void) door_return(argp, arg_size, NULL, 0); 1093 } 1094 1095 int 1096 _nscd_setup_server(char *execname, char **argv) 1097 { 1098 1099 int fd; 1100 int errnum; 1101 int bind_failed = 0; 1102 mode_t old_mask; 1103 struct stat buf; 1104 sigset_t myset; 1105 struct sigaction action; 1106 char *me = "_nscd_setup_server"; 1107 1108 main_execname = execname; 1109 main_argv = argv; 1110 1111 /* Any nscd process is to ignore SIGPIPE */ 1112 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 1113 errnum = errno; 1114 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1115 (me, "signal (SIGPIPE): %s\n", strerror(errnum)); 1116 return (-1); 1117 } 1118 1119 keep_open_dns_socket(); 1120 1121 /* 1122 * the max number of server threads should be fixed now, so 1123 * set flag to indicate that no in-flight change is allowed 1124 */ 1125 max_servers_set = 1; 1126 1127 (void) thr_keycreate(&lookup_state_key, NULL); 1128 (void) sema_init(&common_sema, frontend_cfg_g.common_worker_threads, 1129 USYNC_THREAD, 0); 1130 1131 /* Establish server thread pool */ 1132 (void) door_server_create(server_create); 1133 if (thr_keycreate(&server_key, server_destroy) != 0) { 1134 errnum = errno; 1135 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1136 (me, "thr_keycreate (server thread): %s\n", 1137 strerror(errnum)); 1138 return (-1); 1139 } 1140 1141 /* Create a door */ 1142 if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, 1143 DOOR_UNREF | DOOR_NO_CANCEL)) < 0) { 1144 errnum = errno; 1145 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1146 (me, "door_create: %s\n", strerror(errnum)); 1147 return (-1); 1148 } 1149 1150 /* if not main nscd, no more setup to do */ 1151 if (_whoami != NSCD_MAIN) 1152 return (fd); 1153 1154 /* bind to file system */ 1155 if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID)) { 1156 if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) { 1157 int newfd; 1158 1159 /* make sure the door will be readable by all */ 1160 old_mask = umask(0); 1161 if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) { 1162 errnum = errno; 1163 _NSCD_LOG(NSCD_LOG_FRONT_END, 1164 NSCD_LOG_LEVEL_ERROR) 1165 (me, "Cannot create %s: %s\n", 1166 TSOL_NAME_SERVICE_DOOR, 1167 strerror(errnum)); 1168 bind_failed = 1; 1169 } 1170 /* rstore the old file mode creation mask */ 1171 (void) umask(old_mask); 1172 (void) close(newfd); 1173 } 1174 if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) { 1175 if (errno != EEXIST) { 1176 errnum = errno; 1177 _NSCD_LOG(NSCD_LOG_FRONT_END, 1178 NSCD_LOG_LEVEL_ERROR) 1179 (me, "Cannot symlink %s: %s\n", 1180 NAME_SERVICE_DOOR, strerror(errnum)); 1181 bind_failed = 1; 1182 } 1183 } 1184 } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) { 1185 int newfd; 1186 1187 /* make sure the door will be readable by all */ 1188 old_mask = umask(0); 1189 if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) { 1190 errnum = errno; 1191 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1192 (me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR, 1193 strerror(errnum)); 1194 bind_failed = 1; 1195 } 1196 /* rstore the old file mode creation mask */ 1197 (void) umask(old_mask); 1198 (void) close(newfd); 1199 } 1200 1201 if (bind_failed == 1) { 1202 (void) door_revoke(fd); 1203 return (-1); 1204 } 1205 1206 if (fattach(fd, NAME_SERVICE_DOOR) < 0) { 1207 if ((errno != EBUSY) || 1208 (fdetach(NAME_SERVICE_DOOR) < 0) || 1209 (fattach(fd, NAME_SERVICE_DOOR) < 0)) { 1210 errnum = errno; 1211 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1212 (me, "fattach: %s\n", strerror(errnum)); 1213 (void) door_revoke(fd); 1214 return (-1); 1215 } 1216 } 1217 1218 /* 1219 * kick off routing socket monitor thread 1220 */ 1221 if (thr_create(NULL, NULL, 1222 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { 1223 errnum = errno; 1224 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1225 (me, "thr_create (routing socket monitor): %s\n", 1226 strerror(errnum)); 1227 1228 (void) door_revoke(fd); 1229 return (-1); 1230 } 1231 1232 /* 1233 * set up signal handler for SIGHUP 1234 */ 1235 action.sa_handler = dozip; 1236 action.sa_flags = 0; 1237 (void) sigemptyset(&action.sa_mask); 1238 (void) sigemptyset(&myset); 1239 (void) sigaddset(&myset, SIGHUP); 1240 1241 if (sigaction(SIGHUP, &action, NULL) < 0) { 1242 errnum = errno; 1243 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1244 (me, "sigaction (SIGHUP): %s\n", strerror(errnum)); 1245 1246 (void) door_revoke(fd); 1247 return (-1); 1248 } 1249 1250 return (fd); 1251 } 1252 1253 int 1254 _nscd_setup_child_server(int did) 1255 { 1256 1257 int errnum; 1258 int fd; 1259 nscd_rc_t rc; 1260 char *me = "_nscd_setup_child_server"; 1261 1262 /* Re-establish our own server thread pool */ 1263 (void) door_server_create(server_create); 1264 if (thr_keycreate(&server_key, server_destroy) != 0) { 1265 errnum = errno; 1266 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 1267 (me, "thr_keycreate failed: %s", strerror(errnum)); 1268 return (-1); 1269 } 1270 1271 /* 1272 * Create a new door. 1273 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork) 1274 */ 1275 (void) close(did); 1276 if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, 1277 DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) { 1278 errnum = errno; 1279 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 1280 (me, "door_create failed: %s", strerror(errnum)); 1281 return (-1); 1282 } 1283 1284 /* 1285 * kick off routing socket monitor thread 1286 */ 1287 if (thr_create(NULL, NULL, 1288 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { 1289 errnum = errno; 1290 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1291 (me, "thr_create (routing socket monitor): %s\n", 1292 strerror(errnum)); 1293 (void) door_revoke(fd); 1294 return (-1); 1295 } 1296 1297 /* 1298 * start monitoring the states of the name service clients 1299 */ 1300 rc = _nscd_init_smf_monitor(); 1301 if (rc != NSCD_SUCCESS) { 1302 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1303 (me, "unable to start the SMF monitor (rc = %d)\n", rc); 1304 1305 (void) door_revoke(fd); 1306 return (-1); 1307 } 1308 1309 return (fd); 1310 } 1311 1312 nscd_rc_t 1313 _nscd_alloc_frontend_cfg() 1314 { 1315 frontend_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t)); 1316 if (frontend_cfg == NULL) 1317 return (NSCD_NO_MEMORY); 1318 1319 return (NSCD_SUCCESS); 1320 } 1321 1322 1323 /* ARGSUSED */ 1324 nscd_rc_t 1325 _nscd_cfg_frontend_notify( 1326 void *data, 1327 struct nscd_cfg_param_desc *pdesc, 1328 nscd_cfg_id_t *nswdb, 1329 nscd_cfg_flag_t dflag, 1330 nscd_cfg_error_t **errorp, 1331 void *cookie) 1332 { 1333 void *dp; 1334 1335 /* 1336 * At init time, the whole group of config params are received. 1337 * At update time, group or individual parameter value could 1338 * be received. 1339 */ 1340 1341 if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) || 1342 _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { 1343 /* 1344 * group data is received, copy in the 1345 * entire strcture 1346 */ 1347 if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) 1348 frontend_cfg_g = *(nscd_cfg_global_frontend_t *)data; 1349 else 1350 frontend_cfg[nswdb->index] = 1351 *(nscd_cfg_frontend_t *)data; 1352 1353 } else { 1354 /* 1355 * individual paramater is received: copy in the 1356 * parameter value. 1357 */ 1358 if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) 1359 dp = (char *)&frontend_cfg_g + pdesc->p_offset; 1360 else 1361 dp = (char *)&frontend_cfg[nswdb->index] + 1362 pdesc->p_offset; 1363 (void) memcpy(dp, data, pdesc->p_size); 1364 } 1365 1366 return (NSCD_SUCCESS); 1367 } 1368 1369 /* ARGSUSED */ 1370 nscd_rc_t 1371 _nscd_cfg_frontend_verify( 1372 void *data, 1373 struct nscd_cfg_param_desc *pdesc, 1374 nscd_cfg_id_t *nswdb, 1375 nscd_cfg_flag_t dflag, 1376 nscd_cfg_error_t **errorp, 1377 void **cookie) 1378 { 1379 1380 char *me = "_nscd_cfg_frontend_verify"; 1381 1382 /* 1383 * if max. number of server threads is set and in effect, 1384 * don't allow changing of the frontend configuration 1385 */ 1386 if (max_servers_set) { 1387 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) 1388 (me, "changing of the frontend configuration not allowed now"); 1389 1390 return (NSCD_CFG_CHANGE_NOT_ALLOWED); 1391 } 1392 1393 return (NSCD_SUCCESS); 1394 } 1395 1396 /* ARGSUSED */ 1397 nscd_rc_t 1398 _nscd_cfg_frontend_get_stat( 1399 void **stat, 1400 struct nscd_cfg_stat_desc *sdesc, 1401 nscd_cfg_id_t *nswdb, 1402 nscd_cfg_flag_t *dflag, 1403 void (**free_stat)(void *stat), 1404 nscd_cfg_error_t **errorp) 1405 { 1406 return (NSCD_SUCCESS); 1407 } 1408 1409 void 1410 _nscd_init_cache_sema(sema_t *sema, char *cache_name) 1411 { 1412 int i, j; 1413 char *dbn; 1414 1415 if (max_servers == 0) 1416 max_servers = frontend_cfg_g.common_worker_threads + 1417 frontend_cfg_g.cache_hit_threads; 1418 1419 for (i = 0; i < NSCD_NUM_DB; i++) { 1420 1421 dbn = NSCD_NSW_DB_NAME(i); 1422 if (strcasecmp(dbn, cache_name) == 0) { 1423 j = frontend_cfg[i].worker_thread_per_nsw_db; 1424 (void) sema_init(sema, j, USYNC_THREAD, 0); 1425 max_servers += j; 1426 break; 1427 } 1428 } 1429 } 1430 1431 /* 1432 * Monitor the routing socket. Address lists stored in the ipnodes 1433 * cache are sorted based on destination address selection rules, 1434 * so when things change that could affect that sorting (interfaces 1435 * go up or down, flags change, etc.), we clear that cache so the 1436 * list will be re-ordered the next time the hostname is resolved. 1437 */ 1438 static void 1439 rts_mon(void) 1440 { 1441 int rt_sock, rdlen, idx; 1442 union { 1443 struct { 1444 struct rt_msghdr rtm; 1445 struct sockaddr_storage addrs[RTA_NUMBITS]; 1446 } r; 1447 struct if_msghdr ifm; 1448 struct ifa_msghdr ifam; 1449 } mbuf; 1450 struct ifa_msghdr *ifam = &mbuf.ifam; 1451 char *me = "rts_mon"; 1452 1453 rt_sock = socket(PF_ROUTE, SOCK_RAW, 0); 1454 if (rt_sock < 0) { 1455 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1456 (me, "Failed to open routing socket: %s\n", strerror(errno)); 1457 thr_exit(0); 1458 } 1459 1460 for (;;) { 1461 rdlen = read(rt_sock, &mbuf, sizeof (mbuf)); 1462 if (rdlen <= 0) { 1463 if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) { 1464 _NSCD_LOG(NSCD_LOG_FRONT_END, 1465 NSCD_LOG_LEVEL_ERROR) 1466 (me, "routing socket read: %s\n", 1467 strerror(errno)); 1468 thr_exit(0); 1469 } 1470 continue; 1471 } 1472 if (ifam->ifam_version != RTM_VERSION) { 1473 _NSCD_LOG(NSCD_LOG_FRONT_END, 1474 NSCD_LOG_LEVEL_ERROR) 1475 (me, "rx unknown version (%d) on " 1476 "routing socket.\n", 1477 ifam->ifam_version); 1478 continue; 1479 } 1480 switch (ifam->ifam_type) { 1481 case RTM_NEWADDR: 1482 case RTM_DELADDR: 1483 /* if no ipnodes cache, then nothing to do */ 1484 idx = get_cache_idx("ipnodes"); 1485 if (cache_ctx_p[idx] == NULL || 1486 cache_ctx_p[idx]->reaper_on != nscd_true) 1487 break; 1488 nsc_invalidate(cache_ctx_p[idx], NULL, NULL); 1489 break; 1490 case RTM_ADD: 1491 case RTM_DELETE: 1492 case RTM_CHANGE: 1493 case RTM_GET: 1494 case RTM_LOSING: 1495 case RTM_REDIRECT: 1496 case RTM_MISS: 1497 case RTM_LOCK: 1498 case RTM_OLDADD: 1499 case RTM_OLDDEL: 1500 case RTM_RESOLVE: 1501 case RTM_IFINFO: 1502 break; 1503 default: 1504 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1505 (me, "rx unknown msg type (%d) on routing socket.\n", 1506 ifam->ifam_type); 1507 break; 1508 } 1509 } 1510 } 1511 1512 static void 1513 keep_open_dns_socket(void) 1514 { 1515 _res.options |= RES_STAYOPEN; /* just keep this udp socket open */ 1516 } 1517