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 2006 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 static void 175 restart_if_cfgfile_changed() 176 { 177 178 static mutex_t nsswitch_lock = DEFAULTMUTEX; 179 static time_t last_nsswitch_check = 0; 180 static time_t last_nsswitch_modified = 0; 181 static time_t last_resolv_modified = 0; 182 time_t now = time(NULL); 183 char *me = "restart_if_cfgfile_changed"; 184 185 if (now - last_nsswitch_check <= _NSC_FILE_CHECK_TIME) 186 return; 187 188 (void) mutex_lock(&nsswitch_lock); 189 190 if (now - last_nsswitch_check > _NSC_FILE_CHECK_TIME) { 191 struct stat nss_buf; 192 struct stat res_buf; 193 194 last_nsswitch_check = now; 195 196 (void) mutex_unlock(&nsswitch_lock); /* let others continue */ 197 198 /* 199 * This code keeps us from statting resolv.conf 200 * if it doesn't exist, yet prevents us from ignoring 201 * it if it happens to disappear later on for a bit. 202 */ 203 204 if (last_resolv_modified >= 0) { 205 if (stat("/etc/resolv.conf", &res_buf) < 0) { 206 if (last_resolv_modified == 0) 207 last_resolv_modified = -1; 208 else 209 res_buf.st_mtime = last_resolv_modified; 210 } else if (last_resolv_modified == 0) { 211 last_resolv_modified = res_buf.st_mtime; 212 } 213 } 214 215 if (stat("/etc/nsswitch.conf", &nss_buf) < 0) { 216 217 /*EMPTY*/; 218 219 } else if (last_nsswitch_modified == 0) { 220 221 last_nsswitch_modified = nss_buf.st_mtime; 222 223 } else if ((last_nsswitch_modified < nss_buf.st_mtime) || 224 ((last_resolv_modified > 0) && 225 (last_resolv_modified < res_buf.st_mtime))) { 226 static mutex_t exit_lock = DEFAULTMUTEX; 227 char *fmri; 228 229 /* 230 * if in self cred mode, kill the forker and 231 * child nscds 232 */ 233 if (_nscd_is_self_cred_on(0, NULL)) { 234 _nscd_kill_forker(); 235 _nscd_kill_all_children(); 236 } 237 238 /* 239 * time for restart 240 */ 241 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) 242 (me, "nscd restart due to %s or %s change\n", 243 "/etc/nsswitch.conf", "resolv.conf"); 244 /* 245 * try to restart under smf 246 */ 247 if ((fmri = getenv("SMF_FMRI")) == NULL) { 248 /* not running under smf - reexec */ 249 (void) execv(main_execname, main_argv); 250 exit(1); /* just in case */ 251 } 252 253 /* prevent multiple restarts */ 254 (void) mutex_lock(&exit_lock); 255 256 if (smf_restart_instance(fmri) == 0) 257 (void) sleep(10); /* wait a bit */ 258 exit(1); /* give up waiting for resurrection */ 259 } 260 261 } else 262 (void) mutex_unlock(&nsswitch_lock); 263 } 264 265 uid_t 266 _nscd_get_client_euid() 267 { 268 ucred_t *uc = NULL; 269 uid_t id; 270 char *me = "get_client_euid"; 271 272 if (door_ucred(&uc) != 0) { 273 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 274 (me, "door_ucred: %s\n", strerror(errno)); 275 return ((uid_t)-1); 276 } 277 278 id = ucred_geteuid(uc); 279 ucred_free(uc); 280 return (id); 281 } 282 283 static void 284 N2N_check_priv( 285 void *buf, 286 char *dc_str) 287 { 288 nss_pheader_t *phdr = (nss_pheader_t *)buf; 289 ucred_t *uc = NULL; 290 const priv_set_t *eset; 291 zoneid_t zoneid; 292 int errnum; 293 char *me = "N2N_check_priv"; 294 295 if (door_ucred(&uc) != 0) { 296 errnum = errno; 297 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 298 (me, "door_ucred: %s\n", strerror(errno)); 299 300 NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); 301 } 302 303 eset = ucred_getprivset(uc, PRIV_EFFECTIVE); 304 zoneid = ucred_getzoneid(uc); 305 306 if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || 307 eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : 308 ucred_geteuid(uc) != 0) { 309 310 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 311 (me, "%s call failed(cred): caller pid %d, uid %d, " 312 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), 313 ucred_getruid(uc), ucred_geteuid(uc), zoneid); 314 ucred_free(uc); 315 316 NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES); 317 } 318 319 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 320 (me, "nscd received %s cmd from pid %d, uid %d, " 321 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), 322 ucred_getruid(uc), ucred_geteuid(uc), zoneid); 323 324 ucred_free(uc); 325 326 NSCD_RETURN_STATUS_SUCCESS(phdr); 327 } 328 329 static void 330 APP_check_cred( 331 void *buf, 332 pid_t *pidp, 333 char *dc_str) 334 { 335 nss_pheader_t *phdr = (nss_pheader_t *)buf; 336 ucred_t *uc = NULL; 337 uid_t ruid; 338 uid_t euid; 339 int errnum; 340 char *me = "APP_check_cred"; 341 342 if (door_ucred(&uc) != 0) { 343 errnum = errno; 344 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 345 (me, "door_ucred: %s\n", strerror(errno)); 346 347 NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); 348 } 349 350 if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc), 351 euid = ucred_geteuid(uc))) { 352 if (pidp != NULL) 353 *pidp = ucred_getpid(uc); 354 ucred_free(uc); 355 356 NSCD_RETURN_STATUS_SUCCESS(phdr); 357 } 358 359 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 360 (me, "%s call failed: caller pid %d, ruid %d, " 361 "euid %d, header ruid %d, header euid %d\n", dc_str, 362 (pidp != NULL) ? *pidp : -1, ruid, euid, 363 ((nss_pheader_t *)(buf))->p_ruid, ((nss_pheader_t *)(buf))->p_euid); 364 365 366 ucred_free(uc); 367 368 NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES); 369 } 370 371 static void 372 lookup(char *argp, size_t arg_size) 373 { 374 nsc_lookup_args_t largs; 375 char space[NSCD_LOOKUP_BUFSIZE]; 376 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 377 378 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, 379 sizeof (space)); 380 381 (void) memset(&largs, 0, sizeof (largs)); 382 largs.buffer = argp; 383 largs.bufsize = arg_size; 384 nsc_lookup(&largs, 0); 385 386 /* 387 * only the PUN needs to keep track of the 388 * activity count to determine when to 389 * terminate itself 390 */ 391 if (_whoami == NSCD_CHILD) { 392 (void) mutex_lock(&activity_lock); 393 ++activity; 394 (void) mutex_unlock(&activity_lock); 395 } 396 397 NSCD_SET_RETURN_ARG(phdr, arg_size); 398 (void) door_return(argp, arg_size, NULL, 0); 399 } 400 401 static void 402 getent(char *argp, size_t arg_size) 403 { 404 char space[NSCD_LOOKUP_BUFSIZE]; 405 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 406 407 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, 408 space, sizeof (space)); 409 410 nss_pgetent(argp, arg_size); 411 412 NSCD_SET_RETURN_ARG(phdr, arg_size); 413 (void) door_return(argp, arg_size, NULL, 0); 414 } 415 416 static int 417 is_db_per_user(void *buf, char *dblist) 418 { 419 nss_pheader_t *phdr = (nss_pheader_t *)buf; 420 nss_dbd_t *pdbd; 421 char *dbname, *dbn; 422 int len; 423 424 /* copy db name into a temp buffer */ 425 pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off)); 426 dbname = (char *)pdbd + pdbd->o_name; 427 len = strlen(dbname); 428 dbn = alloca(len + 2); 429 (void) memcpy(dbn, dbname, len); 430 431 /* check if <dbname> + ',' can be found in the dblist string */ 432 dbn[len] = ','; 433 dbn[len + 1] = '\0'; 434 if (strstr(dblist, dbn) != NULL) 435 return (1); 436 437 /* 438 * check if <dbname> can be found in the last part 439 * of the dblist string 440 */ 441 dbn[len] = '\0'; 442 if (strstr(dblist, dbn) != NULL) 443 return (1); 444 445 return (0); 446 } 447 448 /* 449 * Check to see if all conditions are met for processing per-user 450 * requests. Returns 1 if yes, -1 if backend is not configured, 451 * 0 otherwise. 452 */ 453 static int 454 need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist) 455 { 456 nss_pheader_t *phdr = (nss_pheader_t *)buf; 457 458 NSCD_SET_STATUS_SUCCESS(phdr); 459 460 /* if already a per-user nscd, no need to get per-user door */ 461 if (whoami == NSCD_CHILD) 462 return (0); 463 464 /* forker shouldn't be asked */ 465 if (whoami == NSCD_FORKER) { 466 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 467 return (0); 468 } 469 470 /* if door client is root, no need for a per-user door */ 471 if (uid == 0) 472 return (0); 473 474 /* 475 * if per-user lookup is not configured, no per-user 476 * door available 477 */ 478 if (_nscd_is_self_cred_on(0, dblist) == 0) 479 return (-1); 480 481 /* 482 * if per-user lookup is not configured for the db, 483 * don't bother 484 */ 485 if (is_db_per_user(phdr, *dblist) == 0) 486 return (0); 487 488 return (1); 489 } 490 491 static void 492 if_selfcred_return_per_user_door(char *argp, size_t arg_size, 493 door_desc_t *dp, int whoami) 494 { 495 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); 496 char *dblist; 497 int door = -1; 498 int rc = 0; 499 door_desc_t desc; 500 char space[1024*4]; 501 502 /* 503 * check to see if self-cred is configured and 504 * need to return an alternate PUN door 505 */ 506 if (per_user_is_on == 1) { 507 rc = need_per_user_door(argp, whoami, 508 _nscd_get_client_euid(), &dblist); 509 if (rc == -1) 510 per_user_is_on = 0; 511 } 512 if (rc <= 0) { 513 /* 514 * self-cred not configured, and no error detected, 515 * return to continue the door call processing 516 */ 517 if (NSCD_STATUS_IS_OK(phdr)) 518 return; 519 else 520 /* 521 * configured but error detected, 522 * stop the door call processing 523 */ 524 (void) door_return(argp, phdr->data_off, NULL, 0); 525 } 526 527 /* get the alternate PUN door */ 528 _nscd_proc_alt_get(argp, &door); 529 if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) { 530 (void) door_return(argp, phdr->data_off, NULL, 0); 531 } 532 533 /* return the alternate door descriptor */ 534 (void) memcpy(space, phdr, NSCD_PHDR_LEN(phdr)); 535 argp = space; 536 phdr = (nss_pheader_t *)(void *)space; 537 dp = &desc; 538 dp->d_attributes = DOOR_DESCRIPTOR; 539 dp->d_data.d_desc.d_descriptor = door; 540 phdr->data_len = strlen(dblist) + 1; 541 (void) strcpy(((char *)phdr) + NSCD_PHDR_LEN(phdr), dblist); 542 543 arg_size = NSCD_PHDR_LEN(phdr) + NSCD_DATA_LEN(phdr); 544 (void) door_return(argp, arg_size, dp, 1); 545 } 546 547 /*ARGSUSED*/ 548 static void 549 switcher(void *cookie, char *argp, size_t arg_size, 550 door_desc_t *dp, uint_t n_desc) 551 { 552 int iam; 553 pid_t ent_pid = -1; 554 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); 555 void *uptr; 556 int buflen, len; 557 int callnum; 558 char *me = "switcher"; 559 560 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 561 (me, "switcher ...\n"); 562 563 if (argp == DOOR_UNREF_DATA) { 564 (void) printf("Door Slam... exiting\n"); 565 exit(0); 566 } 567 568 if (argp == NULL) { /* empty door call */ 569 (void) door_return(NULL, 0, 0, 0); /* return the favor */ 570 } 571 572 /* 573 * need to restart if main nscd and config file(s) changed 574 */ 575 if (_whoami == NSCD_MAIN) 576 restart_if_cfgfile_changed(); 577 578 if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) { 579 switch (phdr->nsc_callnumber) { 580 case NSCD_SEARCH: 581 582 /* if a fallback to main nscd, skip per-user setup */ 583 if (phdr->p_status != NSS_ALTRETRY) 584 if_selfcred_return_per_user_door(argp, arg_size, 585 dp, _whoami); 586 lookup(argp, arg_size); 587 588 break; 589 590 case NSCD_SETENT: 591 592 APP_check_cred(argp, &ent_pid, "NSCD_SETENT"); 593 if (NSCD_STATUS_IS_OK(phdr)) { 594 if_selfcred_return_per_user_door(argp, arg_size, 595 dp, _whoami); 596 nss_psetent(argp, arg_size, ent_pid); 597 } 598 break; 599 600 case NSCD_GETENT: 601 602 getent(argp, arg_size); 603 break; 604 605 case NSCD_ENDENT: 606 607 nss_pendent(argp, arg_size); 608 break; 609 610 case NSCD_PUT: 611 612 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 613 (me, "door call NSCD_PUT not supported yet\n"); 614 615 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 616 break; 617 618 case NSCD_GETHINTS: 619 620 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 621 (me, "door call NSCD_GETHINTS not supported yet\n"); 622 623 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 624 break; 625 626 default: 627 628 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 629 (me, "Unknown name service door call op %x\n", 630 phdr->nsc_callnumber); 631 632 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 633 break; 634 } 635 636 (void) door_return(argp, arg_size, NULL, 0); 637 } 638 639 iam = NSCD_MAIN; 640 callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI; 641 if (callnum == NSCD_IMHERE || 642 callnum == NSCD_PULSE || callnum == NSCD_FORK) 643 iam = phdr->nsc_callnumber & NSCD_WHOAMI; 644 else 645 callnum = phdr->nsc_callnumber; 646 647 /* nscd -> nscd v2 calls */ 648 switch (callnum) { 649 650 case NSCD_PING: 651 NSCD_SET_STATUS_SUCCESS(phdr); 652 break; 653 654 case NSCD_IMHERE: 655 _nscd_proc_iamhere(argp, dp, n_desc, iam); 656 break; 657 658 case NSCD_PULSE: 659 N2N_check_priv(argp, "NSCD_PULSE"); 660 if (NSCD_STATUS_IS_OK(phdr)) 661 _nscd_proc_pulse(argp, iam); 662 break; 663 664 case NSCD_FORK: 665 N2N_check_priv(argp, "NSCD_FORK"); 666 if (NSCD_STATUS_IS_OK(phdr)) 667 _nscd_proc_fork(argp, iam); 668 break; 669 670 case NSCD_KILL: 671 N2N_check_priv(argp, "NSCD_KILL"); 672 if (NSCD_STATUS_IS_OK(phdr)) 673 exit(0); 674 break; 675 676 case NSCD_REFRESH: 677 if (_nscd_refresh() != NSCD_SUCCESS) 678 exit(1); 679 NSCD_SET_STATUS_SUCCESS(phdr); 680 break; 681 682 case NSCD_GETPUADMIN: 683 684 if (_nscd_is_self_cred_on(0, NULL)) { 685 _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t)); 686 } else { 687 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 688 NSCD_SELF_CRED_NOT_CONFIGURED); 689 } 690 break; 691 692 case NSCD_GETADMIN: 693 694 len = _nscd_door_getadmin((void *)argp); 695 if (len == 0) 696 break; 697 698 /* size of door buffer not big enough, allocate one */ 699 NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen); 700 701 /* copy packed header */ 702 *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp); 703 704 /* set new buffer size */ 705 ((nss_pheader_t *)uptr)->pbufsiz = buflen; 706 707 /* try one more time */ 708 (void) _nscd_door_getadmin((void *)uptr); 709 (void) door_return(uptr, buflen, NULL, 0); 710 break; 711 712 case NSCD_SETADMIN: 713 N2N_check_priv(argp, "NSCD_SETADMIN"); 714 if (NSCD_STATUS_IS_OK(phdr)) 715 _nscd_door_setadmin(argp); 716 break; 717 718 case NSCD_KILLSERVER: 719 N2N_check_priv(argp, "NSCD_KILLSERVER"); 720 if (NSCD_STATUS_IS_OK(phdr)) { 721 /* also kill the forker nscd if one is running */ 722 _nscd_kill_forker(); 723 exit(0); 724 } 725 break; 726 727 default: 728 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 729 (me, "Unknown name service door call op %d\n", 730 phdr->nsc_callnumber); 731 732 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 733 734 (void) door_return(argp, arg_size, NULL, 0); 735 break; 736 737 } 738 (void) door_return(argp, arg_size, NULL, 0); 739 } 740 741 int 742 _nscd_setup_server(char *execname, char **argv) 743 { 744 745 int fd; 746 int errnum; 747 int bind_failed = 0; 748 struct stat buf; 749 sigset_t myset; 750 struct sigaction action; 751 char *me = "_nscd_setup_server"; 752 753 main_execname = execname; 754 main_argv = argv; 755 756 keep_open_dns_socket(); 757 758 /* 759 * the max number of server threads should be fixed now, so 760 * set flag to indicate that no in-flight change is allowed 761 */ 762 max_servers_set = 1; 763 764 (void) thr_keycreate(&lookup_state_key, NULL); 765 (void) sema_init(&common_sema, 766 frontend_cfg_g.common_worker_threads, 767 USYNC_THREAD, 0); 768 769 /* Establish server thread pool */ 770 (void) door_server_create(server_create); 771 if (thr_keycreate(&server_key, server_destroy) != 0) { 772 errnum = errno; 773 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 774 (me, "thr_keycreate (server thread): %s\n", 775 strerror(errnum)); 776 return (-1); 777 } 778 779 /* Create a door */ 780 if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, 781 DOOR_UNREF | DOOR_NO_CANCEL)) < 0) { 782 errnum = errno; 783 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 784 (me, "door_create: %s\n", strerror(errnum)); 785 return (-1); 786 } 787 788 /* if not main nscd, no more setup to do */ 789 if (_whoami != NSCD_MAIN) 790 return (fd); 791 792 /* bind to file system */ 793 if (is_system_labeled()) { 794 if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) { 795 int newfd; 796 if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) { 797 errnum = errno; 798 _NSCD_LOG(NSCD_LOG_FRONT_END, 799 NSCD_LOG_LEVEL_ERROR) 800 (me, "Cannot create %s: %s\n", 801 TSOL_NAME_SERVICE_DOOR, 802 strerror(errnum)); 803 bind_failed = 1; 804 } 805 (void) close(newfd); 806 } 807 if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) { 808 if (errno != EEXIST) { 809 errnum = errno; 810 _NSCD_LOG(NSCD_LOG_FRONT_END, 811 NSCD_LOG_LEVEL_ERROR) 812 (me, "Cannot symlink %s: %s\n", 813 NAME_SERVICE_DOOR, 814 strerror(errnum)); 815 bind_failed = 1; 816 } 817 } 818 } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) { 819 int newfd; 820 if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) { 821 errnum = errno; 822 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 823 (me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR, 824 strerror(errnum)); 825 bind_failed = 1; 826 } 827 (void) close(newfd); 828 } 829 830 if (bind_failed == 1) { 831 (void) door_revoke(fd); 832 return (-1); 833 } 834 835 if (fattach(fd, NAME_SERVICE_DOOR) < 0) { 836 if ((errno != EBUSY) || 837 (fdetach(NAME_SERVICE_DOOR) < 0) || 838 (fattach(fd, NAME_SERVICE_DOOR) < 0)) { 839 errnum = errno; 840 _NSCD_LOG(NSCD_LOG_FRONT_END, 841 NSCD_LOG_LEVEL_ERROR) 842 (me, "fattach: %s\n", strerror(errnum)); 843 (void) door_revoke(fd); 844 return (-1); 845 } 846 } 847 848 /* 849 * kick off routing socket monitor thread 850 */ 851 if (thr_create(NULL, NULL, 852 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { 853 errnum = errno; 854 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 855 (me, "thr_create (routing socket monitor): %s\n", 856 strerror(errnum)); 857 858 (void) door_revoke(fd); 859 return (-1); 860 } 861 862 /* 863 * set up signal handler for SIGHUP 864 */ 865 action.sa_handler = dozip; 866 action.sa_flags = 0; 867 (void) sigemptyset(&action.sa_mask); 868 (void) sigemptyset(&myset); 869 (void) sigaddset(&myset, SIGHUP); 870 871 if (sigaction(SIGHUP, &action, NULL) < 0) { 872 errnum = errno; 873 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 874 (me, "sigaction (SIGHUP): %s\n", strerror(errnum)); 875 876 (void) door_revoke(fd); 877 return (-1); 878 } 879 880 return (fd); 881 } 882 883 int 884 _nscd_setup_child_server(int did) 885 { 886 887 int errnum; 888 int fd; 889 nscd_rc_t rc; 890 char *me = "_nscd_setup_child_server"; 891 892 /* Re-establish our own server thread pool */ 893 (void) door_server_create(server_create); 894 if (thr_keycreate(&server_key, server_destroy) != 0) { 895 errnum = errno; 896 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 897 (me, "thr_keycreate failed: %s", strerror(errnum)); 898 return (-1); 899 } 900 901 /* 902 * Create a new door. 903 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork) 904 */ 905 (void) close(did); 906 if ((fd = door_create(switcher, 907 NAME_SERVICE_DOOR_COOKIE, 908 DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) { 909 errnum = errno; 910 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 911 (me, "door_create failed: %s", strerror(errnum)); 912 return (-1); 913 } 914 915 /* 916 * kick off routing socket monitor thread 917 */ 918 if (thr_create(NULL, NULL, 919 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { 920 errnum = errno; 921 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 922 (me, "thr_create (routing socket monitor): %s\n", 923 strerror(errnum)); 924 (void) door_revoke(fd); 925 return (-1); 926 } 927 928 /* 929 * start monitoring the states of the name service clients 930 */ 931 rc = _nscd_init_smf_monitor(); 932 if (rc != NSCD_SUCCESS) { 933 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 934 (me, "unable to start the SMF monitor (rc = %d)\n", rc); 935 936 (void) door_revoke(fd); 937 return (-1); 938 } 939 940 return (fd); 941 } 942 943 nscd_rc_t 944 _nscd_alloc_frontend_cfg() 945 { 946 frontend_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t)); 947 if (frontend_cfg == NULL) 948 return (NSCD_NO_MEMORY); 949 950 return (NSCD_SUCCESS); 951 } 952 953 954 /* ARGSUSED */ 955 nscd_rc_t 956 _nscd_cfg_frontend_notify( 957 void *data, 958 struct nscd_cfg_param_desc *pdesc, 959 nscd_cfg_id_t *nswdb, 960 nscd_cfg_flag_t dflag, 961 nscd_cfg_error_t **errorp, 962 void *cookie) 963 { 964 void *dp; 965 966 /* 967 * At init time, the whole group of config params are received. 968 * At update time, group or individual parameter value could 969 * be received. 970 */ 971 972 if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) || 973 _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { 974 /* 975 * group data is received, copy in the 976 * entire strcture 977 */ 978 if (_nscd_cfg_flag_is_set(pdesc->pflag, 979 NSCD_CFG_PFLAG_GLOBAL)) 980 frontend_cfg_g = 981 *(nscd_cfg_global_frontend_t *)data; 982 else 983 frontend_cfg[nswdb->index] = 984 *(nscd_cfg_frontend_t *)data; 985 986 } else { 987 /* 988 * individual paramater is received: copy in the 989 * parameter value. 990 */ 991 if (_nscd_cfg_flag_is_set(pdesc->pflag, 992 NSCD_CFG_PFLAG_GLOBAL)) 993 dp = (char *)&frontend_cfg_g + pdesc->p_offset; 994 else 995 dp = (char *)&frontend_cfg[nswdb->index] + 996 pdesc->p_offset; 997 (void) memcpy(dp, data, pdesc->p_size); 998 } 999 1000 return (NSCD_SUCCESS); 1001 } 1002 1003 /* ARGSUSED */ 1004 nscd_rc_t 1005 _nscd_cfg_frontend_verify( 1006 void *data, 1007 struct nscd_cfg_param_desc *pdesc, 1008 nscd_cfg_id_t *nswdb, 1009 nscd_cfg_flag_t dflag, 1010 nscd_cfg_error_t **errorp, 1011 void **cookie) 1012 { 1013 1014 char *me = "_nscd_cfg_frontend_verify"; 1015 1016 /* 1017 * if max. number of server threads is set and in effect, 1018 * don't allow changing of the frontend configuration 1019 */ 1020 if (max_servers_set) { 1021 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) 1022 (me, "changing of the frontend configuration not allowed now"); 1023 1024 return (NSCD_CFG_CHANGE_NOT_ALLOWED); 1025 } 1026 1027 return (NSCD_SUCCESS); 1028 } 1029 1030 /* ARGSUSED */ 1031 nscd_rc_t 1032 _nscd_cfg_frontend_get_stat( 1033 void **stat, 1034 struct nscd_cfg_stat_desc *sdesc, 1035 nscd_cfg_id_t *nswdb, 1036 nscd_cfg_flag_t *dflag, 1037 void (**free_stat)(void *stat), 1038 nscd_cfg_error_t **errorp) 1039 { 1040 return (NSCD_SUCCESS); 1041 } 1042 1043 void 1044 _nscd_init_cache_sema(sema_t *sema, char *cache_name) 1045 { 1046 int i, j; 1047 char *dbn; 1048 1049 if (max_servers == 0) 1050 max_servers = frontend_cfg_g.common_worker_threads + 1051 frontend_cfg_g.cache_hit_threads; 1052 1053 for (i = 0; i < NSCD_NUM_DB; i++) { 1054 1055 dbn = NSCD_NSW_DB_NAME(i); 1056 if (strcasecmp(dbn, cache_name) == 0) { 1057 j = frontend_cfg[i].worker_thread_per_nsw_db; 1058 (void) sema_init(sema, j, USYNC_THREAD, 0); 1059 max_servers += j; 1060 break; 1061 } 1062 } 1063 } 1064 1065 /* 1066 * Monitor the routing socket. Address lists stored in the ipnodes 1067 * cache are sorted based on destination address selection rules, 1068 * so when things change that could affect that sorting (interfaces 1069 * go up or down, flags change, etc.), we clear that cache so the 1070 * list will be re-ordered the next time the hostname is resolved. 1071 */ 1072 static void 1073 rts_mon(void) 1074 { 1075 int rt_sock, rdlen, idx; 1076 union { 1077 struct { 1078 struct rt_msghdr rtm; 1079 struct sockaddr_storage addrs[RTA_NUMBITS]; 1080 } r; 1081 struct if_msghdr ifm; 1082 struct ifa_msghdr ifam; 1083 } mbuf; 1084 struct ifa_msghdr *ifam = &mbuf.ifam; 1085 char *me = "rts_mon"; 1086 1087 rt_sock = socket(PF_ROUTE, SOCK_RAW, 0); 1088 if (rt_sock < 0) { 1089 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1090 (me, "Failed to open routing socket: %s\n", strerror(errno)); 1091 thr_exit(0); 1092 } 1093 1094 for (;;) { 1095 rdlen = read(rt_sock, &mbuf, sizeof (mbuf)); 1096 if (rdlen <= 0) { 1097 if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) { 1098 _NSCD_LOG(NSCD_LOG_FRONT_END, 1099 NSCD_LOG_LEVEL_ERROR) 1100 (me, "routing socket read: %s\n", 1101 strerror(errno)); 1102 thr_exit(0); 1103 } 1104 continue; 1105 } 1106 if (ifam->ifam_version != RTM_VERSION) { 1107 _NSCD_LOG(NSCD_LOG_FRONT_END, 1108 NSCD_LOG_LEVEL_ERROR) 1109 (me, "rx unknown version (%d) on " 1110 "routing socket.\n", 1111 ifam->ifam_version); 1112 continue; 1113 } 1114 switch (ifam->ifam_type) { 1115 case RTM_NEWADDR: 1116 case RTM_DELADDR: 1117 /* if no ipnodes cache, then nothing to do */ 1118 idx = get_cache_idx("ipnodes"); 1119 if (cache_ctx_p[idx] == NULL || 1120 cache_ctx_p[idx]->reaper_on != nscd_true) 1121 break; 1122 nsc_invalidate(cache_ctx_p[idx], NULL, NULL); 1123 break; 1124 case RTM_ADD: 1125 case RTM_DELETE: 1126 case RTM_CHANGE: 1127 case RTM_GET: 1128 case RTM_LOSING: 1129 case RTM_REDIRECT: 1130 case RTM_MISS: 1131 case RTM_LOCK: 1132 case RTM_OLDADD: 1133 case RTM_OLDDEL: 1134 case RTM_RESOLVE: 1135 case RTM_IFINFO: 1136 break; 1137 default: 1138 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1139 (me, "rx unknown msg type (%d) on routing socket.\n", 1140 ifam->ifam_type); 1141 break; 1142 } 1143 } 1144 } 1145 1146 static void 1147 keep_open_dns_socket(void) 1148 { 1149 _res.options |= RES_STAYOPEN; /* just keep this udp socket open */ 1150 } 1151