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