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