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