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