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