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