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