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