1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Simple doors name server cache daemon 30 */ 31 32 #include <stdio.h> 33 #include <signal.h> 34 #include <sys/door.h> 35 #include <sys/types.h> 36 #include <time.h> 37 #include <string.h> 38 #include <sys/stat.h> 39 #include <sys/time.h> 40 #include <sys/wait.h> 41 #include <sys/zone.h> 42 #include <stdlib.h> 43 #include <errno.h> 44 #include <pthread.h> 45 #include <thread.h> 46 #include <stdarg.h> 47 #include <fcntl.h> 48 #include <assert.h> 49 #include <unistd.h> 50 #include <memory.h> 51 #include <sys/socket.h> 52 #include <net/route.h> 53 #include <net/if.h> 54 #include <netinet/in.h> 55 #include <arpa/nameser.h> 56 #include <resolv.h> 57 #include <door.h> 58 #include "getxby_door.h" 59 #include "server_door.h" 60 #include "nscd.h" 61 /* Includes for filenames of databases */ 62 #include <shadow.h> 63 #include <userdefs.h> 64 #include <netdb.h> 65 #include <nss_dbdefs.h> 66 #include <exec_attr.h> 67 #include <prof_attr.h> 68 #include <user_attr.h> 69 #include <ucred.h> 70 #include <priv.h> 71 #include <libscf.h> 72 #include <tsol/label.h> 73 #include <zone.h> 74 75 #define TSOL_NAME_SERVICE_DOOR "/var/tsol/doors/name_service_door" 76 77 extern int optind; 78 extern int opterr; 79 extern int optopt; 80 extern char *optarg; 81 82 static void switcher(void *, char *, size_t, door_desc_t *, uint_t); 83 static void rts_mon(void); 84 static void usage(char *); 85 static int nsc_calllen(nsc_call_t *); 86 static int client_getadmin(admin_t *); 87 static void getadmin(nsc_return_t *, int, nsc_call_t *); 88 static int setadmin(nsc_return_t *, int, nsc_call_t *); 89 static void client_killserver(void); 90 static int client_setadmin(admin_t *); 91 static void client_showstats(admin_t *); 92 static void detachfromtty(void); 93 94 95 admin_t current_admin; 96 static int will_become_server; 97 98 void 99 nsc_reaper(char *tbl_name, hash_t *tbl, nsc_stat_t *admin_ptr, 100 mutex_t *hash_lock) 101 { 102 uint_t count; 103 uint_t interval; 104 105 while (1) { 106 107 if (current_admin.debug_level >= DBG_ALL) { 108 logit("reaper_%s: %d entries in cache\n", 109 tbl_name, admin_ptr->nsc_entries); 110 } 111 if (admin_ptr->nsc_entries > 0) { 112 count = reap_hash(tbl, admin_ptr, hash_lock, 113 admin_ptr->nsc_pos_ttl); 114 if (current_admin.debug_level >= DBG_ALL) { 115 logit("reaper_%s: reaped %d entries\n", 116 tbl_name, count); 117 } 118 } else { 119 /* 120 * We set a minimum wait of 60 before checking again; 121 * we don't want to sleep for no time at all. 122 * We don't clamp it for the reaping itself, that is 123 * done in reap_hash, and with a different minimum. 124 */ 125 interval = admin_ptr->nsc_pos_ttl; 126 if (interval < 60) interval = 60; 127 if (current_admin.debug_level >= DBG_ALL) { 128 logit( 129 "reaper_%s: Nothing to reap, sleep %d\n", 130 tbl_name, interval); 131 } 132 sleep(interval); 133 } 134 } 135 } 136 137 nsc_stat_t * 138 getcacheptr(char *s) 139 { 140 static const char *caches[7] = {"passwd", "group", "hosts", "ipnodes", 141 "exec_attr", "prof_attr", "user_attr" }; 142 143 if (strncmp(caches[0], s, strlen(caches[0])) == 0) 144 return (¤t_admin.passwd); 145 146 if (strncmp(caches[1], s, strlen(caches[1])) == 0) 147 return (¤t_admin.group); 148 149 if (strncmp(caches[2], s, strlen(caches[2])) == 0) 150 return (¤t_admin.host); 151 152 if (strncmp(caches[3], s, strlen(caches[3])) == 0) 153 return (¤t_admin.node); 154 155 if (strncmp(caches[4], s, strlen(caches[4])) == 0) 156 return (¤t_admin.exec); 157 158 if (strncmp(caches[5], s, strlen(caches[5])) == 0) 159 return (¤t_admin.prof); 160 161 if (strncmp(caches[6], s, strlen(caches[6])) == 0) 162 return (¤t_admin.user); 163 164 return (NULL); 165 } 166 167 static char * 168 getcacheopt(char *s) 169 { 170 while (*s && *s != ',') 171 s++; 172 return ((*s == ',') ? (s + 1) : NULL); 173 } 174 175 /* 176 * routine to check if server is already running 177 */ 178 179 static int 180 nsc_ping(void) 181 { 182 nsc_data_t data; 183 nsc_data_t *dptr; 184 int ndata; 185 int adata; 186 187 data.nsc_call.nsc_callnumber = NULLCALL; 188 ndata = sizeof (data); 189 adata = sizeof (data); 190 dptr = &data; 191 return (_nsc_trydoorcall(&dptr, &ndata, &adata)); 192 } 193 194 static void 195 dozip(void) 196 { 197 /* not much here */ 198 } 199 200 static void 201 keep_open_dns_socket(void) 202 { 203 _res.options |= RES_STAYOPEN; /* just keep this udp socket open */ 204 } 205 206 /* 207 * declaring this causes the files backend to use hashing 208 * this is of course an utter hack, but provides a nice 209 * quiet back door to enable this feature for only the nscd. 210 */ 211 void 212 __nss_use_files_hash(void) 213 { 214 215 } 216 /* 217 * 218 * The allocation of resources for cache lookups is an interesting 219 * problem, and one that has caused several bugs in the beta release 220 * of 2.5. In particular, the introduction of a thottle to prevent 221 * the creation of excessive numbers of LWPs in the case of a failed 222 * name service has led to a denial of service problem when the 223 * name service request rate exceeds the name service's ability 224 * to respond. As a result, I'm implementing the following 225 * algorithm: 226 * 227 * 1) We cap the number of total threads. 228 * 2) We save CACHE_THREADS of those for cache lookups only. 229 * 3) We use a common pool of 2/3 of the remain threads that are used first 230 * 4) We save the remainder and allocate 1/3 of it for table specific lookups 231 * 232 * The intent is to prevent the failure of a single name service from 233 * causing denial of service, and to always have threads available for 234 * cached lookups. If a request comes in and the answer isn't in the 235 * cache and we cannot get a thread, we simply return NOSERVER, forcing 236 * the client to lookup the 237 * data itself. This will prevent the types of starvation seen 238 * at UNC due to a single threaded DNS backend, and allows the cache 239 * to eventually become filled. 240 * 241 */ 242 243 /* 7 tables: passwd, group, hosts, ipnodes, exec_attr, prof_attr, user_attr */ 244 #define NSCD_TABLES 7 245 #define TABLE_THREADS 10 246 #define COMMON_THREADS 20 247 #define CACHE_MISS_THREADS (COMMON_THREADS + NSCD_TABLES * TABLE_THREADS) 248 #define CACHE_HIT_THREADS 20 249 #define MAX_SERVER_THREADS (CACHE_HIT_THREADS + CACHE_MISS_THREADS) 250 251 static sema_t common_sema; 252 static sema_t passwd_sema; 253 static sema_t hosts_sema; 254 static sema_t nodes_sema; 255 static sema_t group_sema; 256 static sema_t exec_sema; 257 static sema_t prof_sema; 258 static sema_t user_sema; 259 static thread_key_t lookup_state_key; 260 261 static void 262 initialize_lookup_clearance(void) 263 { 264 thr_keycreate(&lookup_state_key, NULL); 265 (void) sema_init(&common_sema, COMMON_THREADS, USYNC_THREAD, 0); 266 (void) sema_init(&passwd_sema, TABLE_THREADS, USYNC_THREAD, 0); 267 (void) sema_init(&hosts_sema, TABLE_THREADS, USYNC_THREAD, 0); 268 (void) sema_init(&nodes_sema, TABLE_THREADS, USYNC_THREAD, 0); 269 (void) sema_init(&group_sema, TABLE_THREADS, USYNC_THREAD, 0); 270 (void) sema_init(&exec_sema, TABLE_THREADS, USYNC_THREAD, 0); 271 (void) sema_init(&prof_sema, TABLE_THREADS, USYNC_THREAD, 0); 272 (void) sema_init(&user_sema, TABLE_THREADS, USYNC_THREAD, 0); 273 } 274 275 int 276 get_clearance(int callnumber) 277 { 278 sema_t *table_sema = NULL; 279 char *tab; 280 281 if (sema_trywait(&common_sema) == 0) { 282 thr_setspecific(lookup_state_key, NULL); 283 return (0); 284 } 285 286 switch (MASKUPDATEBIT(callnumber)) { 287 288 case GETPWUID: 289 case GETPWNAM: 290 tab = "passwd"; 291 table_sema = &passwd_sema; 292 break; 293 294 case GETGRNAM: 295 case GETGRGID: 296 tab = "group"; 297 table_sema = &group_sema; 298 break; 299 300 case GETHOSTBYNAME: 301 case GETHOSTBYADDR: 302 tab = "hosts"; 303 table_sema = &hosts_sema; 304 break; 305 306 case GETIPNODEBYNAME: 307 case GETIPNODEBYADDR: 308 tab = "ipnodes"; 309 table_sema = &nodes_sema; 310 break; 311 case GETEXECID: 312 tab = "exec_attr"; 313 table_sema = &exec_sema; 314 break; 315 316 case GETPROFNAM: 317 tab = "prof_attr"; 318 table_sema = &prof_sema; 319 break; 320 321 case GETUSERNAM: 322 tab = "user_attr"; 323 table_sema = &user_sema; 324 break; 325 326 } 327 328 if (sema_trywait(table_sema) == 0) { 329 thr_setspecific(lookup_state_key, (void*)1); 330 return (0); 331 } 332 333 if (current_admin.debug_level >= DBG_CANT_FIND) { 334 logit("get_clearance: throttling load for %s table\n", tab); 335 } 336 return (-1); 337 } 338 339 int 340 release_clearance(int callnumber) 341 { 342 int which; 343 344 sema_t *table_sema = NULL; 345 346 thr_getspecific(lookup_state_key, (void**)&which); 347 348 if (which == 0) /* from common pool */ { 349 (void) sema_post(&common_sema); 350 return (0); 351 } 352 353 switch (MASKUPDATEBIT(callnumber)) { 354 355 case GETPWUID: 356 case GETPWNAM: 357 table_sema = &passwd_sema; 358 break; 359 360 case GETGRNAM: 361 case GETGRGID: 362 table_sema = &group_sema; 363 break; 364 365 case GETHOSTBYNAME: 366 case GETHOSTBYADDR: 367 table_sema = &hosts_sema; 368 break; 369 370 case GETIPNODEBYNAME: 371 case GETIPNODEBYADDR: 372 table_sema = &nodes_sema; 373 break; 374 375 case GETEXECID: 376 table_sema = &exec_sema; 377 break; 378 379 case GETPROFNAM: 380 table_sema = &prof_sema; 381 break; 382 383 case GETUSERNAM: 384 table_sema = &user_sema; 385 break; 386 } 387 388 (void) sema_post(table_sema); 389 return (0); 390 } 391 392 393 static mutex_t create_lock; 394 static int nscd_max_servers = MAX_SERVER_THREADS; 395 static int num_servers = 0; 396 static thread_key_t server_key; 397 398 /* 399 * Bind a TSD value to a server thread. This enables the destructor to 400 * be called if/when this thread exits. This would be a programming error, 401 * but better safe than sorry. 402 */ 403 /*ARGSUSED*/ 404 static void * 405 server_tsd_bind(void *arg) 406 { 407 static void *value = 0; 408 409 /* disable cancellation to avoid hangs if server threads disappear */ 410 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 411 thr_setspecific(server_key, value); 412 door_return(NULL, 0, NULL, 0); 413 414 /* make lint happy */ 415 return (NULL); 416 } 417 418 /* 419 * Server threads are created here. 420 */ 421 /*ARGSUSED*/ 422 static void 423 server_create(door_info_t *dip) 424 { 425 (void) mutex_lock(&create_lock); 426 if (++num_servers > nscd_max_servers) { 427 num_servers--; 428 (void) mutex_unlock(&create_lock); 429 return; 430 } 431 (void) mutex_unlock(&create_lock); 432 thr_create(NULL, 0, server_tsd_bind, NULL, THR_BOUND|THR_DETACHED, 433 NULL); 434 } 435 436 /* 437 * Server thread are destroyed here 438 */ 439 /*ARGSUSED*/ 440 static void 441 server_destroy(void *arg) 442 { 443 (void) mutex_lock(&create_lock); 444 num_servers--; 445 (void) mutex_unlock(&create_lock); 446 } 447 448 static char **saved_argv; 449 static char saved_execname[MAXPATHLEN]; 450 451 static void 452 save_execname() 453 { 454 const char *name = getexecname(); 455 456 saved_execname[0] = 0; 457 458 if (name[0] != '/') { /* started w/ relative path */ 459 (void) getcwd(saved_execname, MAXPATHLEN); 460 strlcat(saved_execname, "/", MAXPATHLEN); 461 } 462 strlcat(saved_execname, name, MAXPATHLEN); 463 } 464 465 int 466 main(int argc, char ** argv) 467 { 468 int did; 469 int opt; 470 int errflg = 0; 471 int showstats = 0; 472 int doset = 0; 473 int loaded_config_file = 0; 474 struct stat buf; 475 sigset_t myset; 476 struct sigaction action; 477 478 /* 479 * The admin model for TX is that labeled zones are managed 480 * in global zone where most trusted configuration database 481 * resides. 482 */ 483 if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) { 484 (void) fprintf(stderr, 485 "With Trusted Extensions nscd runs only in " \ 486 "the global zone.\n"); 487 exit(1); 488 } 489 490 /* 491 * Special case non-root user here - he can just print stats 492 */ 493 494 if (geteuid()) { 495 if (argc != 2 || strcmp(argv[1], "-g")) { 496 (void) fprintf(stderr, 497 "Must be root to use any option other than "\ 498 "-g.\n\n"); 499 usage(argv[0]); 500 } 501 502 if ((nsc_ping() != SUCCESS) || 503 (client_getadmin(¤t_admin) != 0)) { 504 (void) fprintf(stderr, 505 "%s doesn't appear to be running.\n", argv[0]); 506 exit(1); 507 } 508 client_showstats(¤t_admin); 509 exit(0); 510 } 511 512 513 514 /* 515 * Determine if there is already a daemon running 516 */ 517 518 will_become_server = (nsc_ping() != SUCCESS); 519 520 /* 521 * process usual options 522 */ 523 524 /* 525 * load normal config file 526 */ 527 528 if (will_become_server) { 529 static const nsc_stat_t defaults = { 530 0, /* stats */ 531 0, /* stats */ 532 0, /* stats */ 533 0, /* stats */ 534 0, /* stats */ 535 0, /* stats */ 536 0, /* stats */ 537 211, /* suggested size */ 538 1, /* enabled */ 539 0, /* invalidate cmd */ 540 600, /* positive ttl */ 541 10, /* netative ttl */ 542 20, /* keep hot */ 543 0, /* old data not ok */ 544 1 }; /* check files */ 545 546 current_admin.passwd = defaults; 547 current_admin.group = defaults; 548 current_admin.host = defaults; 549 current_admin.node = defaults; 550 current_admin.exec = defaults; 551 current_admin.prof = defaults; 552 current_admin.user = defaults; 553 554 current_admin.logfile[0] = '\0'; 555 556 if (access("/etc/nscd.conf", R_OK) == 0) { 557 if (nscd_parse(argv[0], "/etc/nscd.conf") < 0) { 558 exit(1); 559 } 560 loaded_config_file++; 561 } 562 } 563 564 else { 565 if (client_getadmin(¤t_admin)) { 566 (void) fprintf(stderr, 567 "Cannot contact nscd properly(?)\n"); 568 exit(1); 569 } 570 571 current_admin.logfile[0] = '\0'; 572 } 573 574 while ((opt = getopt(argc, argv, 575 "S:Kf:c:ge:p:n:i:l:d:s:h:o:")) != EOF) { 576 nsc_stat_t *cache; 577 char *cacheopt; 578 579 switch (opt) { 580 581 case 'S': /* undocumented feature */ 582 doset++; 583 cache = getcacheptr(optarg); 584 cacheopt = getcacheopt(optarg); 585 if (!cache || !cacheopt) { 586 errflg++; 587 break; 588 } 589 if (strcmp(cacheopt, "yes") == 0) 590 cache->nsc_secure_mode = 1; 591 else if (strcmp(cacheopt, "no") == 0) 592 cache->nsc_secure_mode = 0; 593 else 594 errflg++; 595 break; 596 597 case 'K': /* undocumented feature */ 598 client_killserver(); 599 exit(0); 600 break; 601 602 case 'f': 603 doset++; 604 loaded_config_file++; 605 if (nscd_parse(argv[0], optarg) < 0) { 606 exit(1); 607 } 608 break; 609 610 case 'g': 611 showstats++; 612 break; 613 614 case 'p': 615 doset++; 616 cache = getcacheptr(optarg); 617 cacheopt = getcacheopt(optarg); 618 if (!cache || !cacheopt) { 619 errflg++; 620 break; 621 } 622 cache->nsc_pos_ttl = atoi(cacheopt); 623 break; 624 625 case 'n': 626 doset++; 627 cache = getcacheptr(optarg); 628 cacheopt = getcacheopt(optarg); 629 if (!cache || !cacheopt) { 630 errflg++; 631 break; 632 } 633 cache->nsc_neg_ttl = atoi(cacheopt); 634 break; 635 636 case 'c': 637 doset++; 638 cache = getcacheptr(optarg); 639 cacheopt = getcacheopt(optarg); 640 if (!cache || !cacheopt) { 641 errflg++; 642 break; 643 } 644 645 if (strcmp(cacheopt, "yes") == 0) 646 cache->nsc_check_files = 1; 647 else if (strcmp(cacheopt, "no") == 0) 648 cache->nsc_check_files = 0; 649 else 650 errflg++; 651 break; 652 653 654 case 'i': 655 doset++; 656 cache = getcacheptr(optarg); 657 if (!cache) { 658 errflg++; 659 break; 660 } 661 cache->nsc_invalidate = 1; 662 break; 663 664 case 'l': 665 doset++; 666 (void) strlcpy(current_admin.logfile, optarg, 128); 667 break; 668 669 case 'd': 670 671 doset++; 672 current_admin.debug_level = atoi(optarg); 673 break; 674 675 case 's': 676 doset++; 677 cache = getcacheptr(optarg); 678 cacheopt = getcacheopt(optarg); 679 if (!cache || !cacheopt) { 680 errflg++; 681 break; 682 } 683 684 cache->nsc_suggestedsize = atoi(cacheopt); 685 686 break; 687 688 case 'h': 689 doset++; 690 cache = getcacheptr(optarg); 691 cacheopt = getcacheopt(optarg); 692 if (!cache || !cacheopt) { 693 errflg++; 694 break; 695 } 696 cache->nsc_keephot = atoi(cacheopt); 697 break; 698 699 case 'o': 700 doset++; 701 cache = getcacheptr(optarg); 702 cacheopt = getcacheopt(optarg); 703 if (!cache || !cacheopt) { 704 errflg++; 705 break; 706 } 707 if (strcmp(cacheopt, "yes") == 0) 708 cache->nsc_old_data_ok = 1; 709 else if (strcmp(cacheopt, "no") == 0) 710 cache->nsc_old_data_ok = 0; 711 else 712 errflg++; 713 break; 714 715 case 'e': 716 doset++; 717 cache = getcacheptr(optarg); 718 cacheopt = getcacheopt(optarg); 719 if (!cache || !cacheopt) { 720 errflg++; 721 break; 722 } 723 if (strcmp(cacheopt, "yes") == 0) 724 cache->nsc_enabled = 1; 725 else if (strcmp(cacheopt, "no") == 0) 726 cache->nsc_enabled = 0; 727 else 728 errflg++; 729 break; 730 731 default: 732 errflg++; 733 break; 734 } 735 736 } 737 738 if (errflg) 739 usage(argv[0]); 740 741 if (!will_become_server) { 742 743 if (showstats) { 744 client_showstats(¤t_admin); 745 } 746 747 if (doset) { 748 if (client_setadmin(¤t_admin) < 0) { 749 (void) fprintf(stderr, 750 "Error during admin call\n"); 751 exit(1); 752 } 753 } 754 if (!showstats && !doset) { 755 (void) fprintf(stderr, 756 "%s already running.... no admin specified\n", 757 argv[0]); 758 } 759 exit(0); 760 } 761 762 /* 763 * daemon from here ou 764 */ 765 766 if (!loaded_config_file) { 767 (void) fprintf(stderr, 768 "No configuration file specifed and /etc/nscd.conf" \ 769 "not present\n"); 770 exit(1); 771 } 772 773 saved_argv = argv; 774 save_execname(); 775 776 if (current_admin.debug_level) { 777 /* we're debugging... */ 778 if (strlen(current_admin.logfile) == 0) 779 /* no specified log file */ 780 (void) strcpy(current_admin.logfile, "stderr"); 781 else 782 (void) nscd_set_lf(¤t_admin, 783 current_admin.logfile); 784 } else { 785 if (strlen(current_admin.logfile) == 0) 786 (void) strcpy(current_admin.logfile, "/dev/null"); 787 (void) nscd_set_lf(¤t_admin, current_admin.logfile); 788 detachfromtty(); 789 } 790 791 /* perform some initialization */ 792 initialize_lookup_clearance(); 793 keep_open_dns_socket(); 794 getpw_init(); 795 getgr_init(); 796 gethost_init(); 797 getnode_init(); 798 getexec_init(); 799 getprof_init(); 800 getuser_init(); 801 802 /* Establish our own server thread pool */ 803 804 door_server_create(server_create); 805 if (thr_keycreate(&server_key, server_destroy) != 0) { 806 perror("thr_keycreate"); 807 exit(-1); 808 } 809 810 /* Create a door */ 811 812 if ((did = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, 813 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { 814 perror("door_create"); 815 exit(-1); 816 } 817 818 /* bind to file system */ 819 820 if (is_system_labeled()) { 821 if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) { 822 int newfd; 823 if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) { 824 logit("Cannot create %s:%s\n", 825 TSOL_NAME_SERVICE_DOOR, strerror(errno)); 826 exit(1); 827 } 828 (void) close(newfd); 829 } 830 if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) { 831 if (errno != EEXIST) { 832 logit("Cannot symlink %s:%s\n", 833 NAME_SERVICE_DOOR, strerror(errno)); 834 exit(1); 835 } 836 } 837 } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) { 838 int newfd; 839 if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) { 840 logit("Cannot create %s:%s\n", NAME_SERVICE_DOOR, 841 strerror(errno)); 842 exit(1); 843 } 844 (void) close(newfd); 845 } 846 847 if (fattach(did, NAME_SERVICE_DOOR) < 0) { 848 if ((errno != EBUSY) || 849 (fdetach(NAME_SERVICE_DOOR) < 0) || 850 (fattach(did, NAME_SERVICE_DOOR) < 0)) { 851 perror("door_attach"); 852 exit(2); 853 } 854 } 855 856 action.sa_handler = dozip; 857 action.sa_flags = 0; 858 (void) sigemptyset(&action.sa_mask); 859 (void) sigemptyset(&myset); 860 (void) sigaddset(&myset, SIGHUP); 861 862 if (sigaction(SIGHUP, &action, NULL) < 0) { 863 perror("sigaction"); 864 exit(1); 865 } 866 867 if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) { 868 perror("thr_sigsetmask"); 869 exit(1); 870 } 871 872 873 /* 874 * kick off revalidate threads 875 */ 876 877 if (thr_create(NULL, NULL, 878 (void *(*)(void *))getpw_revalidate, 0, 0, NULL) != 0) { 879 perror("thr_create"); 880 exit(1); 881 } 882 883 if (thr_create(NULL, NULL, 884 (void *(*)(void *))gethost_revalidate, 0, 0, NULL) != 0) { 885 perror("thr_create"); 886 exit(1); 887 } 888 889 if (thr_create(NULL, NULL, 890 (void *(*)(void*))getnode_revalidate, 0, 0, NULL) != 0) { 891 perror("thr_create"); 892 exit(1); 893 } 894 895 if (thr_create(NULL, NULL, 896 (void *(*)(void*))getgr_revalidate, 0, 0, NULL) != 0) { 897 perror("thr_create"); 898 exit(1); 899 } 900 901 if (thr_create(NULL, NULL, 902 (void *(*)(void*))getexec_revalidate, 0, 0, NULL) != 0) { 903 perror("thr_create"); 904 exit(1); 905 } 906 907 if (thr_create(NULL, NULL, 908 (void *(*)(void*))getprof_revalidate, 0, 0, NULL) != 0) { 909 perror("thr_create"); 910 exit(1); 911 } 912 913 if (thr_create(NULL, NULL, 914 (void *(*)(void*))getuser_revalidate, 0, 0, NULL) != 0) { 915 perror("thr_create"); 916 exit(1); 917 } 918 919 /* 920 * kick off reaper threads 921 */ 922 923 if (thr_create(NULL, NULL, 924 (void *(*)(void *))getpw_uid_reaper, 0, 0, NULL) != 0) { 925 perror("thr_create"); 926 exit(1); 927 } 928 929 if (thr_create(NULL, NULL, 930 (void *(*)(void *))getpw_nam_reaper, 0, 0, NULL) != 0) { 931 perror("thr_create"); 932 exit(1); 933 } 934 935 if (thr_create(NULL, NULL, 936 (void *(*)(void *))getgr_uid_reaper, 0, 0, NULL) != 0) { 937 perror("thr_create"); 938 exit(1); 939 } 940 941 if (thr_create(NULL, NULL, 942 (void *(*)(void *))getgr_nam_reaper, 0, 0, NULL) != 0) { 943 perror("thr_create"); 944 exit(1); 945 } 946 947 948 if (thr_create(NULL, NULL, 949 (void *(*)(void *))gethost_nam_reaper, 0, 0, NULL) != 0) { 950 perror("thr_create"); 951 exit(1); 952 } 953 954 if (thr_create(NULL, NULL, 955 (void *(*)(void *))gethost_addr_reaper, 0, 0, NULL) != 0) { 956 perror("thr_create"); 957 exit(1); 958 } 959 960 if (thr_create(NULL, NULL, 961 (void *(*)(void *))getnode_nam_reaper, 0, 0, NULL) != 0) { 962 perror("thr_create"); 963 exit(1); 964 } 965 966 if (thr_create(NULL, NULL, 967 (void *(*)(void *))getnode_addr_reaper, 0, 0, NULL) != 0) { 968 perror("thr_create"); 969 exit(1); 970 } 971 972 if (thr_create(NULL, NULL, 973 (void *(*)(void *))getexec_reaper, 0, 0, NULL) != 0) { 974 perror("thr_create"); 975 exit(1); 976 } 977 978 if (thr_create(NULL, NULL, 979 (void *(*)(void *))getprof_reaper, 0, 0, NULL) != 0) { 980 perror("thr_create"); 981 exit(1); 982 } 983 984 if (thr_create(NULL, NULL, 985 (void *(*)(void *))getuser_reaper, 0, 0, NULL) != 0) { 986 perror("thr_create"); 987 exit(1); 988 } 989 990 /* 991 * kick off routing socket monitor thread 992 */ 993 994 if (thr_create(NULL, NULL, 995 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { 996 perror("thr_create"); 997 exit(1); 998 } 999 1000 if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) { 1001 perror("thr_sigsetmask"); 1002 return (1); 1003 } 1004 1005 for (;;) { 1006 (void) pause(); 1007 logit("Reloading /etc/nscd.conf\n"); 1008 nscd_parse(argv[0], "/etc/nscd.conf"); 1009 } 1010 } 1011 1012 1013 /*ARGSUSED*/ 1014 static void 1015 switcher(void *cookie, char *argp, size_t arg_size, 1016 door_desc_t *dp, uint_t n_desc) 1017 { 1018 union { 1019 nsc_data_t data; 1020 char space[8192]; 1021 } u; 1022 1023 time_t now; 1024 1025 static time_t last_nsswitch_check; 1026 static time_t last_nsswitch_modified; 1027 static time_t last_resolv_modified; 1028 1029 static mutex_t nsswitch_lock; 1030 1031 nsc_call_t *ptr = (nsc_call_t *)argp; 1032 1033 if (argp == DOOR_UNREF_DATA) { 1034 (void) printf("Door Slam... exiting\n"); 1035 exit(0); 1036 } 1037 1038 if (ptr == NULL) { /* empty door call */ 1039 (void) door_return(NULL, 0, 0, 0); /* return the favor */ 1040 } 1041 1042 now = time(NULL); 1043 1044 /* 1045 * just in case check 1046 */ 1047 1048 (void) mutex_lock(&nsswitch_lock); 1049 1050 if (now - last_nsswitch_check > 10) { 1051 struct stat nss_buf; 1052 struct stat res_buf; 1053 1054 last_nsswitch_check = now; 1055 1056 (void) mutex_unlock(&nsswitch_lock); /* let others continue */ 1057 1058 /* 1059 * This code keeps us from statting resolv.conf 1060 * if it doesn't exist, yet prevents us from ignoring 1061 * it if it happens to disappear later on for a bit. 1062 */ 1063 1064 if (last_resolv_modified >= 0) { 1065 if (stat("/etc/resolv.conf", &res_buf) < 0) { 1066 if (last_resolv_modified == 0) 1067 last_resolv_modified = -1; 1068 else 1069 res_buf.st_mtime = last_resolv_modified; 1070 } else if (last_resolv_modified == 0) { 1071 last_resolv_modified = res_buf.st_mtime; 1072 } 1073 } 1074 1075 if (stat("/etc/nsswitch.conf", &nss_buf) < 0) { 1076 1077 /*EMPTY*/; 1078 1079 } else if (last_nsswitch_modified == 0) { 1080 1081 last_nsswitch_modified = nss_buf.st_mtime; 1082 1083 } else if ((last_nsswitch_modified < nss_buf.st_mtime) || 1084 ((last_resolv_modified > 0) && 1085 (last_resolv_modified < res_buf.st_mtime))) { 1086 static mutex_t exit_lock; 1087 char *fmri; 1088 /* 1089 * time for restart 1090 */ 1091 logit("nscd restart due to /etc/nsswitch.conf or "\ 1092 "resolv.conf change\n"); 1093 /* 1094 * try to restart under smf 1095 */ 1096 if ((fmri = getenv("SMF_FMRI")) == NULL) { 1097 /* not running under smf - reexec */ 1098 execv(saved_execname, saved_argv); 1099 exit(1); /* just in case */ 1100 } 1101 1102 mutex_lock(&exit_lock); /* prevent multiple restarts */ 1103 if (smf_restart_instance(fmri) == 0) 1104 sleep(10); /* wait a bit */ 1105 exit(1); /* give up waiting for resurrection */ 1106 } 1107 1108 } else 1109 (void) mutex_unlock(&nsswitch_lock); 1110 1111 switch (ptr->nsc_callnumber) { 1112 1113 case NULLCALL: 1114 u.data.nsc_ret.nsc_return_code = SUCCESS; 1115 u.data.nsc_ret.nsc_bufferbytesused = sizeof (nsc_return_t); 1116 break; 1117 1118 1119 case GETPWNAM: 1120 *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ 1121 case GETPWUID: 1122 getpw_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); 1123 break; 1124 1125 case GETGRNAM: 1126 *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ 1127 case GETGRGID: 1128 getgr_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); 1129 break; 1130 1131 case GETHOSTBYNAME: 1132 *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ 1133 case GETHOSTBYADDR: 1134 gethost_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); 1135 break; 1136 1137 case GETIPNODEBYNAME: 1138 *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ 1139 case GETIPNODEBYADDR: 1140 getnode_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); 1141 break; 1142 1143 case GETEXECID: 1144 *(argp + arg_size - 1) = 0; 1145 getexec_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); 1146 break; 1147 1148 case GETPROFNAM: 1149 *(argp + arg_size - 1) = 0; 1150 getprof_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); 1151 break; 1152 1153 case GETUSERNAM: 1154 *(argp + arg_size - 1) = 0; 1155 getuser_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); 1156 break; 1157 1158 case GETADMIN: 1159 getadmin(&u.data.nsc_ret, sizeof (u), ptr); 1160 break; 1161 1162 case SETADMIN: 1163 case KILLSERVER: { 1164 1165 ucred_t *uc = NULL; 1166 const priv_set_t *eset; 1167 zoneid_t zoneid; 1168 1169 if (door_ucred(&uc) != 0) { 1170 perror("door_ucred"); 1171 u.data.nsc_ret.nsc_return_code = NOTFOUND; 1172 break; 1173 } 1174 1175 eset = ucred_getprivset(uc, PRIV_EFFECTIVE); 1176 zoneid = ucred_getzoneid(uc); 1177 1178 if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || 1179 eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : 1180 ucred_geteuid(uc) != 0) { 1181 logit("SETADMIN call failed(cred): caller pid %d, " 1182 "uid %d, euid %d, zoneid %d\n", ucred_getpid(uc), 1183 ucred_getruid(uc), ucred_geteuid(uc), zoneid); 1184 u.data.nsc_ret.nsc_return_code = NOTFOUND; 1185 ucred_free(uc); 1186 break; 1187 } 1188 1189 if (ptr->nsc_callnumber == KILLSERVER) { 1190 logit("Nscd received KILLSERVER cmd from pid %d, " 1191 "uid %d, euid %d, zoneid %d\n", ucred_getpid(uc), 1192 ucred_getruid(uc), ucred_geteuid(uc), zoneid); 1193 exit(0); 1194 } else { 1195 if (setadmin(&u.data.nsc_ret, sizeof (u), ptr) != 0) 1196 logit("SETADMIN call failed\n"); 1197 } 1198 ucred_free(uc); 1199 break; 1200 } 1201 1202 default: 1203 logit("Unknown name service door call op %d\n", 1204 ptr->nsc_callnumber); 1205 u.data.nsc_ret.nsc_return_code = -1; 1206 u.data.nsc_ret.nsc_bufferbytesused = sizeof (nsc_return_t); 1207 break; 1208 1209 } 1210 door_return((char *)&u.data, u.data.nsc_ret.nsc_bufferbytesused, 1211 NULL, 0); 1212 } 1213 1214 /* 1215 * Monitor the routing socket. Address lists stored in the ipnodes 1216 * cache are sorted based on destination address selection rules, 1217 * so when things change that could affect that sorting (interfaces 1218 * go up or down, flags change, etc.), we clear that cache so the 1219 * list will be re-ordered the next time the hostname is resolved. 1220 */ 1221 static void 1222 rts_mon(void) 1223 { 1224 int rt_sock, rdlen; 1225 union { 1226 struct { 1227 struct rt_msghdr rtm; 1228 struct sockaddr_storage addrs[RTA_NUMBITS]; 1229 } r; 1230 struct if_msghdr ifm; 1231 struct ifa_msghdr ifam; 1232 } mbuf; 1233 struct ifa_msghdr *ifam = &mbuf.ifam; 1234 1235 rt_sock = socket(PF_ROUTE, SOCK_RAW, 0); 1236 if (rt_sock < 0) { 1237 logit("Failed to open routing socket: %s\n", strerror(errno)); 1238 thr_exit(0); 1239 } 1240 1241 for (;;) { 1242 rdlen = read(rt_sock, &mbuf, sizeof (mbuf)); 1243 if (rdlen <= 0) { 1244 if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) { 1245 logit("routing socket read: %s\n", 1246 strerror(errno)); 1247 thr_exit(0); 1248 } 1249 continue; 1250 } 1251 if (ifam->ifam_version != RTM_VERSION) { 1252 logit("rx unknown version (%d) on routing socket.\n", 1253 ifam->ifam_version); 1254 continue; 1255 } 1256 switch (ifam->ifam_type) { 1257 case RTM_NEWADDR: 1258 case RTM_DELADDR: 1259 getnode_name_invalidate(); 1260 break; 1261 case RTM_ADD: 1262 case RTM_DELETE: 1263 case RTM_CHANGE: 1264 case RTM_GET: 1265 case RTM_LOSING: 1266 case RTM_REDIRECT: 1267 case RTM_MISS: 1268 case RTM_LOCK: 1269 case RTM_OLDADD: 1270 case RTM_OLDDEL: 1271 case RTM_RESOLVE: 1272 case RTM_IFINFO: 1273 break; 1274 default: 1275 logit("rx unknown msg type (%d) on routing socket.\n", 1276 ifam->ifam_type); 1277 break; 1278 } 1279 } 1280 } 1281 1282 static void 1283 usage(char *s) 1284 { 1285 (void) fprintf(stderr, 1286 "Usage: %s [-d debug_level] [-l logfilename]\n", s); 1287 (void) fprintf(stderr, 1288 " [-p cachename,positive_time_to_live]\n"); 1289 (void) fprintf(stderr, 1290 " [-n cachename,negative_time_to_live]\n"); 1291 (void) fprintf(stderr, 1292 " [-i cachename] [-s cachename,suggestedsize]\n"); 1293 1294 (void) fprintf(stderr, 1295 " [-h cachename,keep_hot_count] "\ 1296 "[-o cachename,\"yes\"|\"no\"]\n"); 1297 1298 (void) fprintf(stderr, 1299 " [-e cachename,\"yes\"|\"no\"] [-g] " \ 1300 "[-c cachename,\"yes\"|\"no\"]\n"); 1301 1302 (void) fprintf(stderr, 1303 " [-f configfilename] \n"); 1304 1305 (void) fprintf(stderr, 1306 "\n Supported caches: passwd, group, hosts, ipnodes\n"); 1307 1308 (void) fprintf(stderr, 1309 " exec_attr, prof_attr, and user_attr.\n"); 1310 1311 exit(1); 1312 1313 } 1314 1315 1316 static int logfd = 2; 1317 1318 int 1319 nscd_set_lf(admin_t *ptr, char *s) 1320 { 1321 int newlogfd; 1322 1323 /* 1324 * we don't really want to try and open the log file 1325 * /dev/null since that will fail w/ our security fixes 1326 */ 1327 1328 if (*s == 0) { 1329 /* ignore empty log file specs */ 1330 /*EMPTY*/; 1331 } else if (s == NULL || strcmp(s, "/dev/null") == 0) { 1332 (void) strcpy(current_admin.logfile, "/dev/null"); 1333 (void) close(logfd); 1334 logfd = -1; 1335 } else { 1336 /* 1337 * In order to open this file securely, we'll try a few tricks 1338 */ 1339 1340 if ((newlogfd = open(s, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) { 1341 /* 1342 * File already exists... now we need to get cute 1343 * since opening a file in a world-writeable directory 1344 * safely is hard = it could be a hard link or a 1345 * symbolic link to a system file. 1346 */ 1347 struct stat before; 1348 1349 if (lstat(s, &before) < 0) { 1350 logit("Cannot open new logfile \"%s\": %sn", 1351 s, strerror(errno)); 1352 return (-1); 1353 } 1354 1355 if (S_ISREG(before.st_mode) && /* no symbolic links */ 1356 (before.st_nlink == 1) && /* no hard links */ 1357 (before.st_uid == 0)) { /* owned by root */ 1358 if ((newlogfd = 1359 open(s, O_APPEND|O_WRONLY, 0644)) < 0) { 1360 logit("Cannot open new "\ 1361 "logfile \"%s\": %s\n", s, 1362 strerror(errno)); 1363 return (-1); 1364 } 1365 } else { 1366 logit("Cannot use specified logfile \"%s\": "\ 1367 "file is/has links or isn't owned by "\ 1368 "root\n", s); 1369 return (-1); 1370 } 1371 } 1372 1373 (void) strlcpy(ptr->logfile, s, 128); 1374 (void) close(logfd); 1375 logfd = newlogfd; 1376 logit("Start of new logfile %s\n", s); 1377 } 1378 return (0); 1379 } 1380 1381 void 1382 logit(char *format, ...) 1383 { 1384 static mutex_t loglock; 1385 struct timeval tv; 1386 1387 #define LOGBUFLEN 1024 1388 char buffer[LOGBUFLEN]; 1389 1390 va_list ap; 1391 va_start(ap, format); 1392 1393 if (logfd >= 0) { 1394 int safechars, offset; 1395 if (gettimeofday(&tv, NULL) != 0 || 1396 ctime_r(&tv.tv_sec, buffer, LOGBUFLEN) == NULL) { 1397 (void) snprintf(buffer, LOGBUFLEN, 1398 "<time conversion failed>\t"); 1399 } else { 1400 /* 1401 * ctime_r() includes some stuff we don't want; 1402 * adjust length to overwrite " YYYY\n". 1403 */ 1404 offset = strlen(buffer) - 6; 1405 safechars = LOGBUFLEN - (offset - 1); 1406 (void) snprintf(buffer + offset, safechars, ".%.4ld\t", 1407 tv.tv_usec/100); 1408 } 1409 offset = strlen(buffer); 1410 safechars = LOGBUFLEN - (offset - 1); 1411 if (vsnprintf(buffer + offset, safechars, format, ap) > 1412 safechars) { 1413 (void) strncat(buffer, "...\n", LOGBUFLEN); 1414 } 1415 1416 (void) mutex_lock(&loglock); 1417 (void) write(logfd, buffer, strlen(buffer)); 1418 (void) mutex_unlock(&loglock); 1419 } 1420 1421 va_end(ap); 1422 #undef LOGBUFLEN 1423 } 1424 1425 static void 1426 do_update(nsc_call_t *in) 1427 { 1428 union { 1429 nsc_data_t data; 1430 char space[8192]; 1431 } u; 1432 1433 time_t now = time(NULL); 1434 1435 switch (MASKUPDATEBIT(in->nsc_callnumber)) { 1436 1437 case GETPWUID: 1438 case GETPWNAM: 1439 getpw_lookup(&u.data.nsc_ret, sizeof (u), in, now); 1440 break; 1441 1442 case GETGRNAM: 1443 case GETGRGID: 1444 getgr_lookup(&u.data.nsc_ret, sizeof (u), in, now); 1445 break; 1446 1447 case GETHOSTBYNAME: 1448 case GETHOSTBYADDR: 1449 gethost_lookup(&u.data.nsc_ret, sizeof (u), in, now); 1450 break; 1451 1452 case GETIPNODEBYNAME: 1453 case GETIPNODEBYADDR: 1454 getnode_lookup(&u.data.nsc_ret, sizeof (u), in, now); 1455 break; 1456 1457 case GETEXECID: 1458 getexec_lookup(&u.data.nsc_ret, sizeof (u), in, now); 1459 break; 1460 1461 case GETPROFNAM: 1462 getprof_lookup(&u.data.nsc_ret, sizeof (u), in, now); 1463 break; 1464 1465 case GETUSERNAM: 1466 getuser_lookup(&u.data.nsc_ret, sizeof (u), in, now); 1467 break; 1468 1469 default: 1470 assert(0); 1471 break; 1472 } 1473 1474 free(in); 1475 } 1476 1477 int 1478 launch_update(nsc_call_t *in) 1479 { 1480 nsc_call_t *c; 1481 1482 int l = nsc_calllen(in); 1483 1484 in->nsc_callnumber |= UPDATEBIT; 1485 1486 if ((c = malloc(l)) == NULL) { 1487 logit("thread create failed: %s\n", strerror(errno)); 1488 exit(1); 1489 } 1490 (void) memcpy(c, in, l); 1491 1492 if (current_admin.debug_level >= DBG_ALL) { 1493 logit("launching update\n"); 1494 } 1495 1496 if (thr_create(NULL, 1497 NULL, 1498 (void *(*)(void*))do_update, 1499 c, 1500 0|THR_DETACHED, NULL) != 0) { 1501 logit("thread create failed\n"); 1502 exit(1); 1503 } 1504 1505 return (0); 1506 } 1507 1508 static int 1509 nsc_calllen(nsc_call_t *in) 1510 { 1511 switch (MASKUPDATEBIT(in->nsc_callnumber)) { 1512 1513 case GETPWUID: 1514 case GETGRGID: 1515 case NULLCALL: 1516 return (sizeof (*in)); 1517 1518 case GETPWNAM: 1519 case GETGRNAM: 1520 case GETHOSTBYNAME: 1521 return (sizeof (*in) + strlen(in->nsc_u.name)); 1522 case GETIPNODEBYNAME: 1523 return (sizeof (*in) + strlen(in->nsc_u.ipnode.name)); 1524 1525 case GETHOSTBYADDR: 1526 case GETIPNODEBYADDR: 1527 return (sizeof (*in) + in->nsc_u.addr.a_length); 1528 1529 case GETEXECID: 1530 case GETPROFNAM: 1531 case GETUSERNAM: 1532 1533 return (sizeof (*in) + strlen(in->nsc_u.name)); 1534 } 1535 1536 return (0); 1537 } 1538 1539 static int 1540 client_getadmin(admin_t *ptr) 1541 { 1542 union { 1543 nsc_data_t data; 1544 char space[8192]; 1545 } u; 1546 1547 nsc_data_t *dptr; 1548 int ndata; 1549 int adata; 1550 1551 u.data.nsc_call.nsc_callnumber = GETADMIN; 1552 ndata = sizeof (u); 1553 adata = sizeof (u.data); 1554 dptr = &u.data; 1555 1556 if (_nsc_trydoorcall(&dptr, &ndata, &adata) != SUCCESS) { 1557 return (-1); 1558 } 1559 1560 (void) memcpy(ptr, dptr->nsc_ret.nsc_u.buff, sizeof (*ptr)); 1561 return (0); 1562 } 1563 1564 /*ARGSUSED*/ 1565 static void 1566 getadmin(nsc_return_t *out, int size, nsc_call_t *ptr) 1567 { 1568 out->nsc_return_code = SUCCESS; 1569 out->nsc_bufferbytesused = sizeof (current_admin); 1570 (void) memcpy(out->nsc_u.buff, ¤t_admin, sizeof (current_admin)); 1571 } 1572 1573 1574 static int 1575 nscd_set_rbac(admin_t *new_admin, int invalidate) 1576 { 1577 int i; 1578 char *dbname = NULL; 1579 nsc_stat_t *cache = NULL; 1580 nsc_stat_t *new = NULL; 1581 void (*invalidate_func)(void); 1582 1583 1584 for (i = 1; i <= 3; i++) { 1585 /* 1586 * Three of the RBAC databases are cached. 1587 */ 1588 switch (i) { 1589 case 1: 1590 dbname = NSS_DBNAM_EXECATTR; 1591 cache = ¤t_admin.exec; 1592 new = &new_admin->exec; 1593 invalidate_func = getexec_invalidate; 1594 break; 1595 case 2: 1596 dbname = NSS_DBNAM_PROFATTR; 1597 cache = ¤t_admin.prof; 1598 new = &new_admin->prof; 1599 invalidate_func = getprof_invalidate; 1600 break; 1601 case 3: 1602 dbname = NSS_DBNAM_USERATTR; 1603 cache = ¤t_admin.user; 1604 new = &new_admin->user; 1605 invalidate_func = getuser_invalidate; 1606 break; 1607 default: 1608 break; 1609 } 1610 1611 if (invalidate) { 1612 if (new->nsc_invalidate) { 1613 logit("Invalidating %s cache\n", dbname); 1614 (*invalidate_func)(); 1615 } 1616 } else { 1617 if (nscd_set_ttl_positive(cache, dbname, 1618 new->nsc_pos_ttl) < 0 || 1619 nscd_set_ttl_negative(cache, dbname, 1620 new->nsc_neg_ttl) < 0 || 1621 nscd_set_khc(cache, dbname, new->nsc_keephot) < 0 || 1622 nscd_set_odo(cache, dbname, 1623 new->nsc_old_data_ok) < 0 || 1624 nscd_set_ec(cache, dbname, new->nsc_enabled) < 0 || 1625 nscd_set_ss(cache, dbname, 1626 new->nsc_suggestedsize) < 0) 1627 return (-1); 1628 } 1629 } 1630 1631 return (0); 1632 } 1633 1634 /*ARGSUSED*/ 1635 static int 1636 setadmin(nsc_return_t *out, int size, nsc_call_t *ptr) 1637 { 1638 admin_t *new; 1639 1640 out->nsc_return_code = SUCCESS; 1641 out->nsc_bufferbytesused = sizeof (nsc_return_t); 1642 1643 new = (admin_t *)ptr->nsc_u.name; 1644 1645 1646 /* 1647 * global admin stuff 1648 */ 1649 1650 if ((nscd_set_lf(¤t_admin, new->logfile) < 0) || 1651 nscd_set_dl(¤t_admin, new->debug_level) < 0) { 1652 out->nsc_return_code = NOTFOUND; 1653 return (-1); 1654 } 1655 1656 /* 1657 * per cache items 1658 */ 1659 1660 if (new->passwd.nsc_invalidate) { 1661 logit("Invalidating passwd cache\n"); 1662 getpw_invalidate(); 1663 } 1664 1665 if (new->group.nsc_invalidate) { 1666 logit("Invalidating group cache\n"); 1667 getgr_invalidate(); 1668 } 1669 1670 if (new->host.nsc_invalidate) { 1671 logit("Invalidating host cache\n"); 1672 gethost_invalidate(); 1673 } 1674 1675 if (new->node.nsc_invalidate) { 1676 logit("Invalidating ipnodes cache\n"); 1677 getnode_invalidate(); 1678 } 1679 1680 (void) nscd_set_rbac(new, 1); /* invalidate rbac cache */ 1681 1682 if (nscd_set_ttl_positive(¤t_admin.passwd, 1683 "passwd", 1684 new->passwd.nsc_pos_ttl) < 0 || 1685 nscd_set_ttl_negative(¤t_admin.passwd, 1686 "passwd", 1687 new->passwd.nsc_neg_ttl) < 0 || 1688 nscd_set_khc(¤t_admin.passwd, 1689 "passwd", 1690 new->passwd.nsc_keephot) < 0 || 1691 nscd_set_odo(¤t_admin.passwd, 1692 "passwd", 1693 new->passwd.nsc_old_data_ok) < 0 || 1694 nscd_set_ec(¤t_admin.passwd, 1695 "passwd", 1696 new->passwd.nsc_enabled) < 0 || 1697 nscd_set_ss(¤t_admin.passwd, 1698 "passwd", 1699 new->passwd.nsc_suggestedsize) < 0 || 1700 1701 nscd_set_ttl_positive(¤t_admin.group, 1702 "group", 1703 new->group.nsc_pos_ttl) < 0 || 1704 nscd_set_ttl_negative(¤t_admin.group, 1705 "group", 1706 new->group.nsc_neg_ttl) < 0 || 1707 nscd_set_khc(¤t_admin.group, 1708 "group", 1709 new->group.nsc_keephot) < 0 || 1710 nscd_set_odo(¤t_admin.group, 1711 "group", 1712 new->group.nsc_old_data_ok) < 0 || 1713 nscd_set_ec(¤t_admin.group, 1714 "group", 1715 new->group.nsc_enabled) < 0 || 1716 nscd_set_ss(¤t_admin.group, 1717 "group", 1718 new->group.nsc_suggestedsize) < 0 || 1719 1720 nscd_set_ttl_positive(¤t_admin.node, 1721 "ipnodes", 1722 new->node.nsc_pos_ttl) < 0 || 1723 nscd_set_ttl_negative(¤t_admin.node, 1724 "ipnodes", 1725 new->node.nsc_neg_ttl) < 0 || 1726 nscd_set_khc(¤t_admin.node, 1727 "ipnodes", 1728 new->node.nsc_keephot) < 0 || 1729 nscd_set_odo(¤t_admin.node, 1730 "ipnodes", 1731 new->node.nsc_old_data_ok) < 0 || 1732 nscd_set_ec(¤t_admin.node, 1733 "ipnodes", 1734 new->node.nsc_enabled) < 0 || 1735 nscd_set_ss(¤t_admin.node, 1736 "ipnodes", 1737 new->node.nsc_suggestedsize) < 0 || 1738 1739 nscd_set_ttl_positive(¤t_admin.host, 1740 "hosts", 1741 new->host.nsc_pos_ttl) < 0 || 1742 nscd_set_ttl_negative(¤t_admin.host, 1743 "hosts", 1744 new->host.nsc_neg_ttl) < 0 || 1745 nscd_set_khc(¤t_admin.host, 1746 "hosts", 1747 new->host.nsc_keephot) < 0 || 1748 nscd_set_odo(¤t_admin.host, 1749 "hosts", 1750 new->host.nsc_old_data_ok) < 0 || 1751 nscd_set_ec(¤t_admin.host, 1752 "hosts", 1753 new->host.nsc_enabled) < 0 || 1754 nscd_set_ss(¤t_admin.host, 1755 "hosts", 1756 new->host.nsc_suggestedsize) < 0 || 1757 nscd_set_rbac(new, 0) < 0) { 1758 out->nsc_return_code = NOTFOUND; 1759 return (-1); 1760 } 1761 out->nsc_return_code = SUCCESS; 1762 return (0); 1763 } 1764 1765 void 1766 client_killserver(void) 1767 { 1768 union { 1769 nsc_data_t data; 1770 char space[8192]; 1771 } u; 1772 1773 nsc_data_t *dptr; 1774 int ndata; 1775 int adata; 1776 1777 u.data.nsc_call.nsc_callnumber = KILLSERVER; 1778 1779 ndata = sizeof (u); 1780 adata = sizeof (nsc_call_t); 1781 1782 dptr = &u.data; 1783 1784 _nsc_trydoorcall(&dptr, &ndata, &adata); 1785 } 1786 1787 1788 static int 1789 client_setadmin(admin_t *ptr) 1790 { 1791 union { 1792 nsc_data_t data; 1793 char space[8192]; 1794 } u; 1795 1796 nsc_data_t *dptr; 1797 int ndata; 1798 int adata; 1799 1800 u.data.nsc_call.nsc_callnumber = SETADMIN; 1801 1802 (void) memcpy(u.data.nsc_call.nsc_u.name, ptr, sizeof (*ptr)); 1803 1804 ndata = sizeof (u); 1805 adata = sizeof (*ptr); 1806 1807 dptr = &u.data; 1808 1809 if (_nsc_trydoorcall(&dptr, &ndata, &adata) != SUCCESS) { 1810 return (-1); 1811 } 1812 1813 return (0); 1814 } 1815 1816 static void 1817 dump_stat(nsc_stat_t *ptr) 1818 { 1819 double hitrate; 1820 (void) printf("%10s cache is enabled\n", 1821 (ptr->nsc_enabled?"Yes":"No")); 1822 (void) printf("%10d cache hits on positive entries\n", 1823 ptr->nsc_pos_cache_hits); 1824 (void) printf("%10d cache hits on negative entries\n", 1825 ptr->nsc_neg_cache_hits); 1826 (void) printf("%10d cache misses on positive entries\n", 1827 ptr->nsc_pos_cache_misses); 1828 (void) printf("%10d cache misses on negative entries\n", 1829 ptr->nsc_neg_cache_misses); 1830 hitrate = ptr->nsc_pos_cache_misses + ptr->nsc_neg_cache_misses + 1831 ptr->nsc_pos_cache_hits + ptr->nsc_neg_cache_hits; 1832 1833 if (hitrate > 0.0) 1834 hitrate = (100.0 * ((double)ptr->nsc_pos_cache_hits + 1835 (double)ptr->nsc_neg_cache_hits))/hitrate; 1836 1837 (void) printf("%10.1f%% cache hit rate\n", hitrate); 1838 (void) printf("%10d queries deferred\n", ptr->nsc_throttle_count); 1839 (void) printf("%10d total entries\n", ptr->nsc_entries); 1840 (void) printf("%10d complete cache invalidations\n", 1841 ptr->nsc_invalidate_count); 1842 (void) printf("%10d suggested size\n", ptr->nsc_suggestedsize); 1843 (void) printf("%10d seconds time to live for positive entries\n", 1844 ptr->nsc_pos_ttl); 1845 (void) printf("%10d seconds time to live for negative entries\n", 1846 ptr->nsc_neg_ttl); 1847 (void) printf("%10d most active entries to be kept valid\n", 1848 ptr->nsc_keephot); 1849 (void) printf("%10s check /etc/{passwd, group, hosts, inet/ipnodes} " 1850 "file for changes\n", 1851 (ptr->nsc_check_files?"Yes":"No")); 1852 1853 (void) printf("%10s use possibly stale data rather than waiting for " 1854 "refresh\n", 1855 (ptr->nsc_old_data_ok?"Yes":"No")); 1856 } 1857 1858 static void 1859 client_showstats(admin_t *ptr) 1860 { 1861 1862 (void) printf("nscd configuration:\n\n"); 1863 (void) printf("%10d server debug level\n", ptr->debug_level); 1864 (void) printf("\"%s\" is server log file\n", ptr->logfile); 1865 1866 (void) printf("\npasswd cache:\n\n"); 1867 dump_stat(&(ptr->passwd)); 1868 (void) printf("\ngroup cache:\n\n"); 1869 dump_stat(&(ptr->group)); 1870 (void) printf("\nhosts cache:\n\n"); 1871 dump_stat(&(ptr->host)); 1872 (void) printf("\nipnodes cache:\n\n"); 1873 dump_stat(&(ptr->node)); 1874 (void) printf("\nexec_attr cache:\n\n"); 1875 dump_stat(&(ptr->exec)); 1876 (void) printf("\nprof_attr cache:\n\n"); 1877 dump_stat(&(ptr->prof)); 1878 (void) printf("\nuser_attr cache:\n\n"); 1879 dump_stat(&(ptr->user)); 1880 } 1881 1882 1883 1884 /* 1885 * detach from tty 1886 */ 1887 static void 1888 detachfromtty(void) 1889 { 1890 if (logfd > 0) { 1891 int i; 1892 for (i = 0; i < logfd; i++) 1893 (void) close(i); 1894 closefrom(logfd+1); 1895 } else 1896 closefrom(0); 1897 1898 (void) chdir("/"); 1899 1900 switch (fork1()) { 1901 case (pid_t)-1: 1902 exit(1); 1903 break; 1904 case 0: 1905 break; 1906 default: 1907 exit(0); 1908 } 1909 (void) setsid(); 1910 (void) open("/dev/null", O_RDWR, 0); 1911 (void) dup(0); 1912 (void) dup(0); 1913 } 1914