xref: /titanic_44/usr/src/cmd/nscd/server.c (revision fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bb)
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