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