8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / nscd / server.c
blobb8fe888f54f532ac6dfb2976b3b2fba8c09aff97
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2016 by Delphix. All rights reserved.
27 * Simple doors name server cache daemon
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <locale.h>
37 #include <sys/stat.h>
38 #include <tsol/label.h>
39 #include <zone.h>
40 #include <signal.h>
41 #include <sys/resource.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"
51 extern int optind;
52 extern int opterr;
53 extern int optopt;
54 extern char *optarg;
56 #define NSCDOPT "S:Kf:c:ge:p:n:i:l:d:s:h:o:GFR"
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;
64 extern nsc_ctx_t *cache_ctx_p[];
66 static void usage(char *);
67 static void detachfromtty(void);
69 static char debug_level[32] = { 0 };
70 static char logfile[128] = { 0 };
71 static int will_become_server;
73 static char *
74 getcacheopt(char *s)
76 while (*s && *s != ',')
77 s++;
78 return ((*s == ',') ? (s + 1) : NULL);
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.
86 void
87 __nss_use_files_hash(void)
91 static int saved_argc = 0;
92 static char **saved_argv = NULL;
93 static char saved_execname[MAXPATHLEN];
95 static void
96 save_execname()
98 const char *name = getexecname();
100 saved_execname[0] = 0;
102 if (name[0] != '/') { /* started w/ relative path */
103 (void) getcwd(saved_execname, MAXPATHLEN);
104 (void) strlcat(saved_execname, "/", MAXPATHLEN);
106 (void) strlcat(saved_execname, name, MAXPATHLEN);
110 main(int argc, char ** argv)
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 struct rlimit rl;
123 ret_locale = setlocale(LC_ALL, "");
124 if (ret_locale == NULL)
125 (void) fprintf(stderr, gettext("Unable to set locale\n"));
127 ret_textdomain = textdomain(TEXT_DOMAIN);
128 if (ret_textdomain == NULL)
129 (void) fprintf(stderr, gettext("Unable to set textdomain\n"));
132 * The admin model for TX is that labeled zones are managed
133 * in global zone where most trusted configuration database
134 * resides. However, nscd will run in any labeled zone if
135 * file /var/tsol/doors/nscd_per_label exists.
137 if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) {
138 struct stat sbuf;
139 if (stat(TSOL_NSCD_PER_LABEL_FILE, &sbuf) < 0) {
140 (void) fprintf(stderr,
141 gettext("With Trusted Extensions nscd runs only in the "
142 "global zone (if nscd_per_label flag not set)\n"));
143 exit(1);
148 * Special case non-root user here - they can only print stats
150 if (geteuid()) {
151 if (argc != 2 ||
152 (strcmp(argv[1], "-g") && strcmp(argv[1], "-G"))) {
153 (void) fprintf(stderr,
154 gettext("Must be root to use any option other than -g\n\n"));
155 usage(argv[0]);
158 if (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS) {
159 (void) fprintf(stderr,
160 gettext("%s doesn't appear to be running.\n"),
161 argv[0]);
162 exit(1);
164 if (_nscd_client_getadmin(argv[1][1]) != 0) {
165 (void) fprintf(stderr,
166 gettext("unable to get configuration and statistics data\n"));
167 exit(1);
170 _nscd_client_showstats();
171 exit(0);
175 * Determine if there is already a daemon (main nscd) running.
176 * If not, will start it. Forker NSCD will always become a
177 * daemon.
179 will_become_server = (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS);
180 if (argc >= 2 && strcmp(argv[1], "-F") == 0) {
181 will_become_server = 1;
182 _whoami = NSCD_FORKER;
185 * allow time for the main nscd to get ready
186 * to receive the IMHERE door request this
187 * process will send later
189 (void) usleep(100000);
193 * first get the config file path. Also detect
194 * invalid option as soon as possible.
196 while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) {
197 switch (opt) {
199 case 'f':
200 if ((cfgfile = strdup(optarg)) == NULL)
201 exit(1);
202 break;
203 case 'g':
204 if (will_become_server) {
205 (void) fprintf(stderr,
206 gettext("nscd not running, no statistics to show\n\n"));
207 errflg++;
209 break;
210 case 'i':
211 if (will_become_server) {
212 (void) fprintf(stderr,
213 gettext("nscd not running, no cache to invalidate\n\n"));
214 errflg++;
216 break;
218 case '?':
219 errflg++;
220 break;
224 if (errflg)
225 usage(argv[0]);
228 * perform more initialization and load configuration
229 * if to become server
231 if (will_become_server) {
233 /* initialize switch engine and config/stats management */
234 if ((rc = _nscd_init(cfgfile)) != NSCD_SUCCESS) {
235 (void) fprintf(stderr,
236 gettext("initialization of switch failed (rc = %d)\n"), rc);
237 exit(1);
239 _nscd_get_log_info(debug_level, sizeof (debug_level),
240 logfile, sizeof (logfile));
243 * initialize cache store
245 if ((rc = init_cache(0)) != NSCD_SUCCESS) {
246 (void) fprintf(stderr,
247 gettext("initialization of cache store failed (rc = %d)\n"), rc);
248 exit(1);
253 * process usual options
255 optind = 1; /* this is a rescan */
256 *msg = '\0';
257 while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) {
259 switch (opt) {
261 case 'K': /* undocumented feature */
262 (void) _nscd_doorcall(NSCD_KILLSERVER);
263 exit(0);
264 break;
266 case 'G':
267 case 'g':
268 showstats++;
269 break;
271 case 'p':
272 doset++;
273 if (_nscd_add_admin_mod(optarg, 'p',
274 getcacheopt(optarg),
275 msg, sizeof (msg)) == -1)
276 errflg++;
277 break;
279 case 'n':
280 doset++;
281 if (_nscd_add_admin_mod(optarg, 'n',
282 getcacheopt(optarg),
283 msg, sizeof (msg)) == -1)
284 errflg++;
285 break;
287 case 'c':
288 doset++;
289 if (_nscd_add_admin_mod(optarg, 'c',
290 getcacheopt(optarg),
291 msg, sizeof (msg)) == -1)
292 errflg++;
293 break;
295 case 'i':
296 doset++;
297 if (_nscd_add_admin_mod(optarg, 'i', NULL,
298 msg, sizeof (msg)) == -1)
299 errflg++;
300 break;
302 case 'l':
303 doset++;
304 (void) strlcpy(logfile, optarg, sizeof (logfile));
305 break;
307 case 'd':
308 doset++;
309 (void) strlcpy(debug_level, optarg,
310 sizeof (debug_level));
311 break;
313 case 'S':
314 /* silently ignore secure-mode */
315 break;
317 case 's':
318 /* silently ignore suggested-size */
319 break;
321 case 'o':
322 /* silently ignore old-data-ok */
323 break;
325 case 'h':
326 doset++;
327 if (_nscd_add_admin_mod(optarg, 'h',
328 getcacheopt(optarg),
329 msg, sizeof (msg)) == -1)
330 errflg++;
331 break;
333 case 'e':
334 doset++;
335 if (_nscd_add_admin_mod(optarg, 'e',
336 getcacheopt(optarg),
337 msg, sizeof (msg)) == -1)
338 errflg++;
339 break;
341 case 'F':
342 _whoami = NSCD_FORKER;
343 break;
345 default:
346 errflg++;
347 break;
352 if (errflg) {
353 if (*msg != '\0')
354 (void) fprintf(stderr, "\n%s: %s\n\n", argv[0], msg);
355 usage(argv[0]);
359 * if main nscd already running and not forker nscd,
360 * can only do admin work
362 if (_whoami == NSCD_MAIN) {
363 if (!will_become_server) {
364 if (showstats) {
365 if (_nscd_client_getadmin('g')) {
366 (void) fprintf(stderr,
367 gettext("Cannot contact nscd properly(?)\n"));
368 exit(1);
370 _nscd_client_showstats();
373 if (doset) {
374 if (_nscd_client_setadmin() < 0) {
375 (void) fprintf(stderr,
376 gettext("Error during admin call\n"));
377 exit(1);
380 if (!showstats && !doset) {
381 (void) fprintf(stderr,
382 gettext("%s already running.... no administration option specified\n"),
383 argv[0]);
385 exit(0);
390 * daemon from here on
393 if (_whoami == NSCD_MAIN) {
395 /* save enough info in case need to restart or fork */
396 saved_argc = argc;
397 saved_argv = argv;
398 save_execname();
401 * if a log file is not specified, set it to
402 * "stderr" or "/dev/null" based on debug level
404 if (*logfile == '\0') {
405 if (*debug_level != '\0')
406 /* we're debugging... */
407 (void) strcpy(logfile, "stderr");
408 else
409 (void) strcpy(logfile, "/dev/null");
411 (void) _nscd_add_admin_mod(NULL, 'l', logfile,
412 msg, sizeof (msg));
413 (void) _nscd_add_admin_mod(NULL, 'd', debug_level,
414 msg, sizeof (msg));
416 /* activate command options */
417 if (_nscd_server_setadmin(NULL) != NSCD_SUCCESS) {
418 (void) fprintf(stderr,
419 gettext("unable to set command line options\n"));
420 exit(1);
423 if (*debug_level != '\0') {
424 /* we're debugging, no forking of nscd */
427 * forker nscd will be started if self credential
428 * is configured
430 _nscd_start_forker(saved_execname, saved_argc,
431 saved_argv);
432 } else {
434 * daemonize the nscd (forker nscd will also
435 * be started if self credential is configured)
437 detachfromtty();
439 } else { /* NSCD_FORKER */
441 * To avoid PUN (Per User Nscd) processes from becoming
442 * zombies after they exit, the forking nscd should
443 * ignore the SIGCLD signal so that it does not
444 * need to wait for every child PUN to exit.
446 (void) signal(SIGCLD, SIG_IGN);
447 (void) open("/dev/null", O_RDWR, 0);
448 (void) dup(0);
449 if (_logfd != 2)
450 (void) dup(0);
453 /* set NOFILE to unlimited */
454 rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
455 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
456 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
457 (me, "Cannot set open file limit: %s\n", strerror(errno));
458 exit(1);
461 /* set up door and establish our own server thread pool */
462 if ((_doorfd = _nscd_setup_server(saved_execname, saved_argv)) == -1) {
463 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
464 (me, "unable to set up door\n");
465 exit(1);
468 /* inform the main nscd that this forker is ready */
469 if (_whoami == NSCD_FORKER) {
470 int ret;
472 for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; )
473 ret = _nscd_doorcall_sendfd(_doorfd,
474 NSCD_IMHERE | (NSCD_FORKER & NSCD_WHOAMI),
475 NULL, 0, NULL);
478 for (;;) {
479 (void) pause();
480 (void) _nscd_doorcall(NSCD_REFRESH);
483 /* NOTREACHED */
484 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
487 static void
488 usage(char *s)
490 (void) fprintf(stderr,
491 "Usage: %s [-d debug_level] [-l logfilename]\n", s);
492 (void) fprintf(stderr,
493 " [-p cachename,positive_time_to_live]\n");
494 (void) fprintf(stderr,
495 " [-n cachename,negative_time_to_live]\n");
496 (void) fprintf(stderr,
497 " [-i cachename]\n");
498 (void) fprintf(stderr,
499 " [-h cachename,keep_hot_count]\n");
500 (void) fprintf(stderr,
501 " [-e cachename,\"yes\"|\"no\"] [-g] " \
502 "[-c cachename,\"yes\"|\"no\"]\n");
503 (void) fprintf(stderr,
504 " [-f configfilename] \n");
505 (void) fprintf(stderr,
506 "\n Supported caches:\n");
507 (void) fprintf(stderr,
508 " auth_attr, bootparams, ethers\n");
509 (void) fprintf(stderr,
510 " exec_attr, group, hosts, ipnodes, netmasks\n");
511 (void) fprintf(stderr,
512 " networks, passwd, printers, prof_attr, project\n");
513 (void) fprintf(stderr,
514 " protocols, rpc, services, tnrhtp, tnrhdb\n");
515 (void) fprintf(stderr,
516 " user_attr\n");
517 exit(1);
521 * detach from tty
523 static void
524 detachfromtty(void)
526 nscd_rc_t rc;
527 char *me = "detachfromtty";
529 if (_logfd > 0) {
530 int i;
531 for (i = 0; i < _logfd; i++)
532 (void) close(i);
533 closefrom(_logfd + 1);
534 } else
535 closefrom(0);
537 (void) chdir("/");
539 switch (fork1()) {
540 case (pid_t)-1:
542 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
543 (me, "unable to fork: pid = %d, %s\n",
544 getpid(), strerror(errno));
546 exit(1);
547 break;
548 case 0:
549 /* start the forker nscd if so configured */
550 _nscd_start_forker(saved_execname, saved_argc, saved_argv);
551 break;
552 default:
553 exit(0);
556 (void) setsid();
557 (void) open("/dev/null", O_RDWR, 0);
558 (void) dup(0);
559 if (_logfd != 2)
560 (void) dup(0);
563 * start monitoring the states of the name service clients
565 rc = _nscd_init_smf_monitor();
566 if (rc != NSCD_SUCCESS) {
567 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
568 (me, "unable to start the SMF monitor (rc = %d)\n", rc);
570 exit(-1);