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 2007 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 <stdlib.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include <errno.h> 37 #include <stdarg.h> 38 #include <locale.h> 39 #include <sys/stat.h> 40 #include <tsol/label.h> 41 #include <zone.h> 42 #include "cache.h" 43 #include "nscd_log.h" 44 #include "nscd_selfcred.h" 45 #include "nscd_frontend.h" 46 #include "nscd_common.h" 47 #include "nscd_admin.h" 48 #include "nscd_door.h" 49 #include "nscd_switch.h" 50 51 extern int optind; 52 extern int opterr; 53 extern int optopt; 54 extern char *optarg; 55 56 #define NSCDOPT "S:Kf:c:ge:p:n:i:l:d:s:h:o:GFR" 57 58 /* assume this is a single nscd or, if multiple, the main nscd */ 59 int _whoami = NSCD_MAIN; 60 int _doorfd = -1; 61 extern int _logfd; 62 static char *cfgfile = NULL; 63 64 extern nsc_ctx_t *cache_ctx_p[]; 65 66 static void usage(char *); 67 static void detachfromtty(void); 68 69 static char debug_level[32] = { 0 }; 70 static char logfile[128] = { 0 }; 71 static int will_become_server; 72 73 static char * 74 getcacheopt(char *s) 75 { 76 while (*s && *s != ',') 77 s++; 78 return ((*s == ',') ? (s + 1) : NULL); 79 } 80 81 /* 82 * declaring this causes the files backend to use hashing 83 * this is of course an utter hack, but provides a nice 84 * quiet back door to enable this feature for only the nscd. 85 */ 86 void 87 __nss_use_files_hash(void) 88 { 89 } 90 91 static int saved_argc = 0; 92 static char **saved_argv = NULL; 93 static char saved_execname[MAXPATHLEN]; 94 95 static void 96 save_execname() 97 { 98 const char *name = getexecname(); 99 100 saved_execname[0] = 0; 101 102 if (name[0] != '/') { /* started w/ relative path */ 103 (void) getcwd(saved_execname, MAXPATHLEN); 104 (void) strlcat(saved_execname, "/", MAXPATHLEN); 105 } 106 (void) strlcat(saved_execname, name, MAXPATHLEN); 107 } 108 109 int 110 main(int argc, char ** argv) 111 { 112 int opt; 113 int errflg = 0; 114 int showstats = 0; 115 int doset = 0; 116 nscd_rc_t rc; 117 char *me = "main()"; 118 char *ret_locale; 119 char *ret_textdomain; 120 char msg[128]; 121 122 ret_locale = setlocale(LC_ALL, ""); 123 if (ret_locale == NULL) 124 (void) fprintf(stderr, gettext("Unable to set locale\n")); 125 126 ret_textdomain = textdomain(TEXT_DOMAIN); 127 if (ret_textdomain == NULL) 128 (void) fprintf(stderr, gettext("Unable to set textdomain\n")); 129 130 /* 131 * The admin model for TX is that labeled zones are managed 132 * in global zone where most trusted configuration database 133 * resides. However, nscd will run in any labeled zone if 134 * file /var/tsol/doors/nscd_per_label exists. 135 */ 136 if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) { 137 struct stat sbuf; 138 if (stat(TSOL_NSCD_PER_LABEL_FILE, &sbuf) < 0) { 139 (void) fprintf(stderr, 140 gettext("With Trusted Extensions nscd runs only in the " 141 "global zone (if nscd_per_label flag not set)\n")); 142 exit(1); 143 } 144 } 145 146 /* 147 * Special case non-root user here - he can just print stats 148 */ 149 if (geteuid()) { 150 if (argc != 2 || 151 (strcmp(argv[1], "-g") && strcmp(argv[1], "-G"))) { 152 (void) fprintf(stderr, 153 gettext("Must be root to use any option other than -g\n\n")); 154 usage(argv[0]); 155 } 156 157 if (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS) { 158 (void) fprintf(stderr, 159 gettext("%s doesn't appear to be running.\n"), 160 argv[0]); 161 exit(1); 162 } 163 if (_nscd_client_getadmin(argv[1][1]) != 0) { 164 (void) fprintf(stderr, 165 gettext("unable to get configuration and statistics data\n")); 166 exit(1); 167 } 168 169 _nscd_client_showstats(); 170 exit(0); 171 } 172 173 /* 174 * Determine if there is already a daemon (main nscd) running. 175 * If not, will start it. Forker NSCD will always become a 176 * daemon. 177 */ 178 will_become_server = (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS); 179 if (argc >= 2 && strcmp(argv[1], "-F") == 0) { 180 will_become_server = 1; 181 _whoami = NSCD_FORKER; 182 183 /* 184 * allow time for the main nscd to get ready 185 * to receive the IMHERE door request this 186 * process will send later 187 */ 188 (void) usleep(100000); 189 } 190 191 /* 192 * first get the config file path. Also detect 193 * invalid option as soon as possible. 194 */ 195 while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) { 196 switch (opt) { 197 198 case 'f': 199 if ((cfgfile = strdup(optarg)) == NULL) 200 exit(1); 201 break; 202 case 'g': 203 if (will_become_server) { 204 (void) fprintf(stderr, 205 gettext("nscd not running, no statistics to show\n\n")); 206 errflg++; 207 } 208 break; 209 case 'i': 210 if (will_become_server) { 211 (void) fprintf(stderr, 212 gettext("nscd not running, no cache to invalidate\n\n")); 213 errflg++; 214 } 215 break; 216 217 case '?': 218 errflg++; 219 break; 220 } 221 222 } 223 if (errflg) 224 usage(argv[0]); 225 226 /* 227 * perform more initialization and load configuration 228 * if to become server 229 */ 230 if (will_become_server) { 231 232 /* initialize switch engine and config/stats management */ 233 if ((rc = _nscd_init(cfgfile)) != NSCD_SUCCESS) { 234 (void) fprintf(stderr, 235 gettext("initialization of switch failed (rc = %d)\n"), rc); 236 exit(1); 237 } 238 _nscd_get_log_info(debug_level, sizeof (debug_level), 239 logfile, sizeof (logfile)); 240 241 /* 242 * initialize cache store 243 */ 244 if ((rc = init_cache(0)) != NSCD_SUCCESS) { 245 (void) fprintf(stderr, 246 gettext("initialization of cache store failed (rc = %d)\n"), rc); 247 exit(1); 248 } 249 } 250 251 /* 252 * process usual options 253 */ 254 optind = 1; /* this is a rescan */ 255 *msg = '\0'; 256 while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) { 257 258 switch (opt) { 259 260 case 'K': /* undocumented feature */ 261 (void) _nscd_doorcall(NSCD_KILLSERVER); 262 exit(0); 263 break; 264 265 case 'G': 266 case 'g': 267 showstats++; 268 break; 269 270 case 'p': 271 doset++; 272 if (_nscd_add_admin_mod(optarg, 'p', 273 getcacheopt(optarg), 274 msg, sizeof (msg)) == -1) 275 errflg++; 276 break; 277 278 case 'n': 279 doset++; 280 if (_nscd_add_admin_mod(optarg, 'n', 281 getcacheopt(optarg), 282 msg, sizeof (msg)) == -1) 283 errflg++; 284 break; 285 286 case 'c': 287 doset++; 288 if (_nscd_add_admin_mod(optarg, 'c', 289 getcacheopt(optarg), 290 msg, sizeof (msg)) == -1) 291 errflg++; 292 break; 293 294 case 'i': 295 doset++; 296 if (_nscd_add_admin_mod(optarg, 'i', NULL, 297 msg, sizeof (msg)) == -1) 298 errflg++; 299 break; 300 301 case 'l': 302 doset++; 303 (void) strlcpy(logfile, optarg, sizeof (logfile)); 304 break; 305 306 case 'd': 307 doset++; 308 (void) strlcpy(debug_level, optarg, 309 sizeof (debug_level)); 310 break; 311 312 case 'S': 313 /* silently ignore secure-mode */ 314 break; 315 316 case 's': 317 /* silently ignore suggested-size */ 318 break; 319 320 case 'o': 321 /* silently ignore old-data-ok */ 322 break; 323 324 case 'h': 325 doset++; 326 if (_nscd_add_admin_mod(optarg, 'h', 327 getcacheopt(optarg), 328 msg, sizeof (msg)) == -1) 329 errflg++; 330 break; 331 332 case 'e': 333 doset++; 334 if (_nscd_add_admin_mod(optarg, 'e', 335 getcacheopt(optarg), 336 msg, sizeof (msg)) == -1) 337 errflg++; 338 break; 339 340 case 'F': 341 _whoami = NSCD_FORKER; 342 break; 343 344 default: 345 errflg++; 346 break; 347 } 348 349 } 350 351 if (errflg) { 352 if (*msg != '\0') 353 (void) fprintf(stderr, "\n%s: %s\n\n", argv[0], msg); 354 usage(argv[0]); 355 } 356 357 /* 358 * if main nscd already running and not forker nscd, 359 * can only do admin work 360 */ 361 if (_whoami == NSCD_MAIN) { 362 if (!will_become_server) { 363 if (showstats) { 364 if (_nscd_client_getadmin('g')) { 365 (void) fprintf(stderr, 366 gettext("Cannot contact nscd properly(?)\n")); 367 exit(1); 368 } 369 _nscd_client_showstats(); 370 } 371 372 if (doset) { 373 if (_nscd_client_setadmin() < 0) { 374 (void) fprintf(stderr, 375 gettext("Error during admin call\n")); 376 exit(1); 377 } 378 } 379 if (!showstats && !doset) { 380 (void) fprintf(stderr, 381 gettext("%s already running.... no administration option specified\n"), 382 argv[0]); 383 } 384 exit(0); 385 } 386 } 387 388 /* 389 * daemon from here on 390 */ 391 392 if (_whoami == NSCD_MAIN) { 393 394 /* save enough info in case need to restart or fork */ 395 saved_argc = argc; 396 saved_argv = argv; 397 save_execname(); 398 399 /* 400 * if a log file is not specified, set it to 401 * "stderr" or "/dev/null" based on debug level 402 */ 403 if (*logfile == '\0') { 404 if (*debug_level != '\0') 405 /* we're debugging... */ 406 (void) strcpy(logfile, "stderr"); 407 else 408 (void) strcpy(logfile, "/dev/null"); 409 } 410 (void) _nscd_add_admin_mod(NULL, 'l', logfile, 411 msg, sizeof (msg)); 412 (void) _nscd_add_admin_mod(NULL, 'd', debug_level, 413 msg, sizeof (msg)); 414 415 /* activate command options */ 416 if (_nscd_server_setadmin(NULL) != NSCD_SUCCESS) { 417 (void) fprintf(stderr, 418 gettext("unable to set command line options\n")); 419 exit(1); 420 } 421 422 if (*debug_level != '\0') { 423 /* we're debugging, no forking of nscd */ 424 425 /* 426 * forker nscd will be started if self credential 427 * is configured 428 */ 429 _nscd_start_forker(saved_execname, saved_argc, 430 saved_argv); 431 } else { 432 /* 433 * daemonize the nscd (forker nscd will also 434 * be started if self credential is configured) 435 */ 436 detachfromtty(); 437 } 438 } else { /* NSCD_FORKER */ 439 (void) open("/dev/null", O_RDWR, 0); 440 (void) dup(0); 441 if (_logfd != 2) 442 (void) dup(0); 443 } 444 445 /* set up door and establish our own server thread pool */ 446 if ((_doorfd = _nscd_setup_server(saved_execname, saved_argv)) == -1) { 447 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 448 (me, "unable to set up door\n"); 449 exit(1); 450 } 451 452 /* inform the main nscd that this forker is ready */ 453 if (_whoami == NSCD_FORKER) { 454 int ret; 455 456 for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; ) 457 ret = _nscd_doorcall_sendfd(_doorfd, 458 NSCD_IMHERE | (NSCD_FORKER & NSCD_WHOAMI), 459 NULL, 0, NULL); 460 } 461 462 for (;;) { 463 (void) pause(); 464 (void) _nscd_doorcall(NSCD_REFRESH); 465 } 466 467 /* NOTREACHED */ 468 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 469 } 470 471 static void 472 usage(char *s) 473 { 474 (void) fprintf(stderr, 475 "Usage: %s [-d debug_level] [-l logfilename]\n", s); 476 (void) fprintf(stderr, 477 " [-p cachename,positive_time_to_live]\n"); 478 (void) fprintf(stderr, 479 " [-n cachename,negative_time_to_live]\n"); 480 (void) fprintf(stderr, 481 " [-i cachename]\n"); 482 (void) fprintf(stderr, 483 " [-h cachename,keep_hot_count]\n"); 484 (void) fprintf(stderr, 485 " [-e cachename,\"yes\"|\"no\"] [-g] " \ 486 "[-c cachename,\"yes\"|\"no\"]\n"); 487 (void) fprintf(stderr, 488 " [-f configfilename] \n"); 489 (void) fprintf(stderr, 490 "\n Supported caches:\n"); 491 (void) fprintf(stderr, 492 " audit_user, auth_attr, bootparams, ethers\n"); 493 (void) fprintf(stderr, 494 " exec_attr, group, hosts, ipnodes, netmasks\n"); 495 (void) fprintf(stderr, 496 " networks, passwd, printers, prof_attr, project\n"); 497 (void) fprintf(stderr, 498 " protocols, rpc, services, tnrhtp, tnrhdb\n"); 499 (void) fprintf(stderr, 500 " user_attr\n"); 501 exit(1); 502 } 503 504 /* 505 * detach from tty 506 */ 507 static void 508 detachfromtty(void) 509 { 510 nscd_rc_t rc; 511 char *me = "detachfromtty"; 512 513 if (_logfd > 0) { 514 int i; 515 for (i = 0; i < _logfd; i++) 516 (void) close(i); 517 closefrom(_logfd + 1); 518 } else 519 closefrom(0); 520 521 (void) chdir("/"); 522 523 switch (fork1()) { 524 case (pid_t)-1: 525 526 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 527 (me, "unable to fork: pid = %d, %s\n", 528 getpid(), strerror(errno)); 529 530 exit(1); 531 break; 532 case 0: 533 /* start the forker nscd if so configured */ 534 _nscd_start_forker(saved_execname, saved_argc, saved_argv); 535 break; 536 default: 537 exit(0); 538 } 539 (void) setsid(); 540 (void) open("/dev/null", O_RDWR, 0); 541 (void) dup(0); 542 if (_logfd != 2) 543 (void) dup(0); 544 545 /* 546 * start monitoring the states of the name service clients 547 */ 548 rc = _nscd_init_smf_monitor(); 549 if (rc != NSCD_SUCCESS) { 550 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 551 (me, "unable to start the SMF monitor (rc = %d)\n", rc); 552 553 exit(-1); 554 } 555 } 556