예제 #1
0
int
main(int argc, char *argv[])
{
	int sflag = 0, s1flag = 0, s2flag = 0, nflag = 0, dflag = 0, eflag = 0;
	char *options, *value;
	extern char *optarg;
	extern int optind;
	int c, d;
	struct rlimit rl;
	int mode = RPC_SVC_MT_AUTO;
	int maxrecsz = RPC_MAXDATASIZE;

	void detachfromtty(void);
	int setmodulus();
	int pk_nodefaultkeys();
	int svc_create_local_service();

	char domainname[MAXNETNAMELEN + 1];

	/*
	 * Set our allowed number of file descriptors to the max
	 * of what the system will allow, limited by FD_SETSIZE.
	 */
	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
		rlim_t limit;

		if ((limit = rl.rlim_max) > FD_SETSIZE)
			limit = FD_SETSIZE;
		rl.rlim_cur = limit;
		(void) setrlimit(RLIMIT_NOFILE, &rl);
		(void) enable_extended_FILE_stdio(-1, -1);
	}

	__key_encryptsession_pk_LOCAL = &__key_encrypt_pk_2_svc;
	__key_decryptsession_pk_LOCAL = &__key_decrypt_pk_2_svc;
	__key_gendes_LOCAL = &__key_gen_1_svc;

	/*
	 * Pre-option initialisation
	 */
	(void) umask(066);	/* paranoia */
	if (geteuid() != 0) {
		(void) fprintf(stderr, "%s must be run as root\n", argv[0]);
		exit(1);
	}
	setmodulus(HEXMODULUS);
	openlog("keyserv", LOG_PID, LOG_DAEMON);

	/*
	 * keyserv will not work with a null domainname.
	 */
	if (getdomainname(domainname, MAXNETNAMELEN+1) ||
	    (domainname[0] == '\0')) {
		syslog(LOG_ERR, "could not get a valid domainname.\n");
		exit(SMF_EXIT_ERR_CONFIG);
	}

	/*
	 * Initialise security mechanisms
	 */
	cache_size = NULL;
	cache_options = NULL;
	if (init_mechs() == -1) {
		disk_caching = 0;
	}

	defaults();

	while ((c = getopt(argc, argv, "ndDet:cs:")) != -1)
		switch (c) {
		case 'n':
			nflag++;
			break;
		case 'd':
			dflag++;
			use_nobody_keys = FALSE;
			break;
		case 'e':
			eflag++;
			use_nobody_keys = TRUE;
			break;
		case 'D':
			debugging = 1;
			break;
		case 't':
			nthreads = atoi(optarg);
			break;
		case 'c':
			disk_caching = 0;
			break;
		case 's':
			if (!disk_caching) {
				fprintf(stderr, "missing configuration file");
				fprintf(stderr, " or -c option specified\n");
				usage();
			}
			sflag++;
			/*
			 * Which version of [-s] do we have...?
			 */
			if (strchr((const char *) optarg, '=') == NULL) {
				/*
				 * -s <size>
				 */
				if (s1flag) {
					fprintf(stderr, "duplicate"
					    " [-s <size>]\n");
					usage();
				}
				s1flag++;
				default_cache = get_cache_size(optarg);
				break;
			}
			/*
			 * -s <mechtype>=<size>[,...]
			 */
			s2flag++;
			options = optarg;
			while (*options != '\0') {
				d = getsubopt(&options, cache_options, &value);
				if (d == -1) {
					/* Ignore unknown mechtype */
					continue;
				}
				if (value == NULL) {
					fprintf(stderr,
					    "missing cache size for "
					    "mechtype %s\n", cache_options[d]);
					usage();
				}
				cache_size[d] = get_cache_size(value);
			}
			break;
		default:
			usage();
			break;
		}


	if (dflag && eflag) {
		(void) fprintf(stderr, "specify only one of -d and -e\n");
		usage();
	}

	if (use_nobody_keys == FALSE) {
		pk_nodefaultkeys();
	}

	if (optind != argc) {
		usage();
	}

	if (!disk_caching && sflag) {
		fprintf(stderr, "missing configuration file");
		fprintf(stderr, " or -c option specified\n");
		usage();
	}

	if (debugging) {
		if (disk_caching) {
			char **cpp = cache_options;
			int *ip = cache_size;
			(void) fprintf(stderr, "default disk cache size: ");
			if (default_cache < 0) {
				(void) fprintf(stderr, "%d entries\n",
				    abs(default_cache));
			} else {
				(void) fprintf(stderr, "%dMB\n", default_cache);
			}

			(void) fprintf(stderr, "supported mechanisms:\n");
			(void) fprintf(stderr, "\talias\t\tdisk cache size\n");
			(void) fprintf(stderr, "\t=====\t\t===============\n");
			while (*cpp != NULL) {
				(void) fprintf(stderr, "\t%s\t\t", *cpp++);
				if (*ip < 0) {
					(void) fprintf(stderr, "%d entries\n",
					    abs(*ip));
				} else {
					(void) fprintf(stderr, "%dMB\n", *ip);
				}
				ip++;
			}
		} else {
			(void) fprintf(stderr,
			    "common key disk caching disabled\n");
		}
	}
	/*
	 * Post-option initialisation
	 */
	if (disk_caching) {
		int i;
		for (i = 0; mechs[i]; i++) {
			if ((AUTH_DES_COMPAT_CHK(mechs[i])) ||
			    (mechs[i]->keylen < 0) || (mechs[i]->algtype < 0))
				continue;
			create_cache_file(mechs[i]->keylen, mechs[i]->algtype,
			    cache_size[i] ? cache_size[i] : default_cache);
		}
	}
	getrootkey(&masterkey, nflag);

	/*
	 * Set MT mode
	 */
	if (nthreads > 0) {
		(void) rpc_control(RPC_SVC_MTMODE_SET, &mode);
		(void) rpc_control(RPC_SVC_THRMAX_SET, &nthreads);
	}

	/*
	 * Enable non-blocking mode and maximum record size checks for
	 * connection oriented transports.
	 */
	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
		syslog(LOG_INFO, "unable to set max RPC record size");
	}

	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS,
	    "netpath", "keyserv") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service for version %d\n",
		    argv[0], KEY_VERS);
		exit(1);
	}

	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS2,
	    "netpath", "keyserv") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service for version %d\n",
		    argv[0], KEY_VERS2);
		exit(1);
	}

	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS3,
	    "netpath", "keyserv") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service for version %d\n",
		    argv[0], KEY_VERS3);
		exit(1);
	}

	if (!debugging) {
		detachfromtty();
	}

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS, "door") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service over doors for version %d\n",
		    argv[0], KEY_VERS);
		exit(1);
	}

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS2, "door") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service over doors for version %d\n",
		    argv[0], KEY_VERS2);
		exit(1);
	}

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS3, "door") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service over doors for version %d\n",
		    argv[0], KEY_VERS3);
		exit(1);
	}

	svc_run();
	abort();
	/* NOTREACHED */
	return (0);
}
예제 #2
0
int
main(int argc, char **argv)
{
	int c;
	pid_t pid;
	extern char *optarg;
	sigset_t mask;
	struct sigaction act;

	(void) setlocale(LC_ALL, "");
#ifndef	TEXT_DOMAIN
#define	TEXT_DOMAIN	"SYS_TEST"
#endif
	(void) textdomain(TEXT_DOMAIN);

	if ((prog = strrchr(argv[0], '/')) == NULL) {
		prog = argv[0];
	} else {
		prog++;
	}

	(void) enable_extended_FILE_stdio(-1, -1);

	/*
	 * process arguments
	 */
	if (argc > 3) {
		usage();
	}
	while ((c = getopt(argc, argv, "d:t:")) != EOF) {
		switch (c) {
		case 'd':
			debug_level = atoi(optarg);
			break;
		case 't':
			idle_timeout = atoi(optarg);
			break;
		case '?':
		default:
			usage();
			/*NOTREACHED*/
		}
	}

	/*
	 * Check permission
	 */
	if (getuid() != 0) {
		(void) fprintf(stderr, gettext("Must be root to run %s\n"),
		    prog);
		exit(EPERM);
	}

	/*
	 * When rcm_daemon is started by a call to librcm, it inherits file
	 * descriptors from the DR initiator making a call. The file
	 * descriptors may correspond to devices that can be removed by DR.
	 * Since keeping them remain opened is problematic, close everything
	 * but stdin/stdout/stderr.
	 */
	closefrom(3);

	/*
	 * When rcm_daemon is started by the caller, it will inherit the
	 * signal block mask.  We unblock all signals to make sure the
	 * signal handling will work normally.
	 */
	(void) sigfillset(&mask);
	(void) thr_sigsetmask(SIG_UNBLOCK, &mask, NULL);

	/*
	 * block SIGUSR1, use it for killing specific threads
	 */
	(void) sigemptyset(&mask);
	(void) sigaddset(&mask, SIGUSR1);
	(void) thr_sigsetmask(SIG_BLOCK, &mask, NULL);

	/*
	 * Setup signal handlers for SIGHUP and SIGUSR1
	 * SIGHUP - causes a "delayed" daemon exit, effectively the same
	 *	as a daemon restart.
	 * SIGUSR1 - causes a thr_exit(). Unblocked in selected threads.
	 */
	act.sa_flags = 0;
	act.sa_handler = catch_sighup;
	(void) sigaction(SIGHUP, &act, NULL);
	act.sa_handler = catch_sigusr1;
	(void) sigaction(SIGUSR1, &act, NULL);

	/*
	 * ignore SIGPIPE so that the rcm daemon does not exit when it
	 * attempts to read or write from a pipe whose corresponding
	 * rcm script process exited.
	 */
	act.sa_handler = SIG_IGN;
	(void) sigaction(SIGPIPE, &act, NULL);

	/*
	 * run in daemon mode
	 */
	if (debug_level < DEBUG_LEVEL_FORK) {
		if (fork()) {
			exit(0);
		}
		detachfromtty();
	}

	/* only one daemon can run at a time */
	if ((pid = enter_daemon_lock()) != getpid()) {
		rcm_log_message(RCM_DEBUG, "%s pid %d already running\n",
		    prog, pid);
		exit(EDEADLK);
	}

	rcm_log_message(RCM_TRACE1, "%s started, debug level = %d\n",
	    prog, debug_level);

	/*
	 * Set daemon state to block RCM requests before rcm_daemon is
	 * fully initialized. See rcmd_thr_incr().
	 */
	rcmd_set_state(RCMD_INIT);

	/*
	 * create rcm_daemon door and set permission to 0400
	 */
	if (create_event_service(RCM_SERVICE_DOOR, event_service) == -1) {
		rcm_log_message(RCM_ERROR,
		    gettext("cannot create door service: %s\n"),
		    strerror(errno));
		rcmd_exit(errno);
	}
	(void) chmod(RCM_SERVICE_DOOR, S_IRUSR);

	init_poll_thread(); /* initialize poll thread related data */

	/*
	 * Initialize database by asking modules to register.
	 */
	rcmd_db_init();

	/*
	 * Initialize locking, including lock recovery in the event of
	 * unexpected daemon failure.
	 */
	rcmd_lock_init();

	/*
	 * Start accepting normal requests
	 */
	rcmd_set_state(RCMD_NORMAL);

	/*
	 * Start cleanup thread
	 */
	rcmd_db_clean();

	/*
	 * Loop within daemon and return after a period of inactivity.
	 */
	rcmd_start_timer(idle_timeout);

	rcmd_cleanup(0);
	return (0);
}
예제 #3
0
파일: cachemgr.c 프로젝트: alhazred/onarm
int
main(int argc, char ** argv)
{
	int			did;
	int			opt;
	int			errflg = 0;
	int			showstats = 0;
	int			doset = 0;
	int			dofg = 0;
	struct stat		buf;
	sigset_t		myset;
	struct sigaction	sighupaction;
	static void		client_killserver();
	int			debug_level = 0;

	/* setup for localization */
	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	openlog("ldap_cachemgr", LOG_PID, LOG_DAEMON);

	if (chdir(NSLDAPDIRECTORY) < 0) {
		(void) fprintf(stderr, gettext("chdir(\"%s\") failed: %s\n"),
		    NSLDAPDIRECTORY, strerror(errno));
		exit(1);
	}

	/*
	 * Correctly set file mode creation mask, so to make the new files
	 * created for door calls being readable by all.
	 */
	(void) umask(0);

	/*
	 *  Special case non-root user here -	he/she/they/it can just print
	 *					stats
	 */

	if (geteuid()) {
		if (argc != 2 || strcmp(argv[1], "-g")) {
			(void) fprintf(stderr,
			    gettext("Must be root to use any option "
			    "other than -g.\n\n"));
			usage(argv[0]);
		}

		if ((__ns_ldap_cache_ping() != SUCCESS) ||
		    (client_getadmin(&current_admin) != 0)) {
			(void) fprintf(stderr,
			    gettext("%s doesn't appear to be running.\n"),
			    argv[0]);
			exit(1);
		}
		(void) client_showstats(&current_admin);
		exit(0);
	}



	/*
	 *  Determine if there is already a daemon running
	 */

	will_become_server = (__ns_ldap_cache_ping() != SUCCESS);

	/*
	 *  load normal config file
	 */

	if (will_become_server) {
		static const ldap_stat_t defaults = {
			0,		/* stat */
			DEFAULTTTL};	/* ttl */

		current_admin.ldap_stat = defaults;
		(void) strcpy(current_admin.logfile, LOGFILE);
	} else {
		if (client_getadmin(&current_admin)) {
			(void) fprintf(stderr, gettext("Cannot contact %s "
			    "properly(?)\n"), argv[0]);
			exit(1);
		}
	}

#ifndef SLP
	while ((opt = getopt(argc, argv, "fKgl:r:d:")) != EOF) {
#else
	while ((opt = getopt(argc, argv, "fKgs:l:r:d:")) != EOF) {
#endif /* SLP */
		ldap_stat_t	*cache;

		switch (opt) {
		case 'K':
			client_killserver();
			exit(0);
			break;
		case 'g':
			showstats++;
			break;
		case 'f':
			dofg++;
			break;
		case 'r':
			doset++;
			cache = getcacheptr("ldap");
			if (!optarg) {
				errflg++;
				break;
			}
			cache->ldap_ttl = atoi(optarg);
			break;
		case 'l':
			doset++;
			(void) strlcpy(current_admin.logfile,
			    optarg, sizeof (current_admin.logfile));
			break;
		case 'd':
			doset++;
			debug_level = atoi(optarg);
			break;
#ifdef SLP
		case 's':	/* undocumented: use dynamic (SLP) config */
			use_slp = 1;
			break;
#endif /* SLP */
		default:
			errflg++;
			break;
		}
	}

	if (errflg)
		usage(argv[0]);

	/*
	 * will not show statistics if no daemon running
	 */
	if (will_become_server && showstats) {
		(void) fprintf(stderr,
		    gettext("%s doesn't appear to be running.\n"),
		    argv[0]);
		exit(1);
	}

	if (!will_become_server) {
		if (showstats) {
			(void) client_showstats(&current_admin);
		}
		if (doset) {
			current_admin.debug_level = debug_level;
			if (client_setadmin(&current_admin) < 0) {
				(void) fprintf(stderr,
				    gettext("Error during admin call\n"));
				exit(1);
			}
		}
		if (!showstats && !doset) {
			(void) fprintf(stderr,
			gettext("%s already running....use '%s "
			    "-K' to stop\n"), argv[0], argv[0]);
		}
		exit(0);
	}

	/*
	 *   daemon from here on
	 */

	if (debug_level) {
		/*
		 * we're debugging...
		 */
		if (strlen(current_admin.logfile) == 0)
			/*
			 * no specified log file
			 */
			(void) strcpy(current_admin.logfile, LOGFILE);
		else
			(void) cachemgr_set_lf(&current_admin,
			    current_admin.logfile);
		/*
		 * validate the range of debug level number
		 * and set the number to current_admin.debug_level
		 */
		if (cachemgr_set_dl(&current_admin, debug_level) < 0) {
				/*
				 * print error messages to the screen
				 * cachemgr_set_dl prints msgs to cachemgr.log
				 * only
				 */
				(void) fprintf(stderr,
				gettext("Incorrect Debug Level: %d\n"
				"It should be between %d and %d\n"),
				    debug_level, DBG_OFF, MAXDEBUG);
			exit(-1);
		}
	} else {
		if (strlen(current_admin.logfile) == 0)
			(void) strcpy(current_admin.logfile, "/dev/null");
			(void) cachemgr_set_lf(&current_admin,
			    current_admin.logfile);
	}

	if (dofg == 0)
		detachfromtty(argv[0]);

	/*
	 * perform some initialization
	 */

	initialize_lookup_clearance();

	if (getldap_init() != 0)
		exit(-1);

	/*
	 * Establish our own server thread pool
	 */

	(void) door_server_create(server_create);
	if (thr_keycreate(&server_key, server_destroy) != 0) {
		logit("thr_keycreate() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_keycreate() call failed"));
		perror("thr_keycreate");
		exit(-1);
	}

	/*
	 * Create a door
	 */

	if ((did = door_create(switcher, LDAP_CACHE_DOOR_COOKIE,
	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
		logit("door_create() call failed\n");
		syslog(LOG_ERR, gettext(
		    "ldap_cachemgr: door_create() call failed"));
		perror("door_create");
		exit(-1);
	}

	/*
	 * bind to file system
	 */

	if (stat(LDAP_CACHE_DOOR, &buf) < 0) {
		int	newfd;

		if ((newfd = creat(LDAP_CACHE_DOOR, 0444)) < 0) {
			logit("Cannot create %s:%s\n",
			    LDAP_CACHE_DOOR,
			    strerror(errno));
			exit(1);
		}
		(void) close(newfd);
	}

	if (fattach(did, LDAP_CACHE_DOOR) < 0) {
		if ((errno != EBUSY) ||
		    (fdetach(LDAP_CACHE_DOOR) <  0) ||
		    (fattach(did, LDAP_CACHE_DOOR) < 0)) {
			logit("fattach() call failed\n");
			syslog(LOG_ERR, gettext(
			    "ldap_cachemgr: fattach() call failed"));
			perror("fattach");
			exit(2);
		}
	}

	/* catch SIGHUP revalid signals */
	sighupaction.sa_handler = getldap_revalidate;
	sighupaction.sa_flags = 0;
	(void) sigemptyset(&sighupaction.sa_mask);
	(void) sigemptyset(&myset);
	(void) sigaddset(&myset, SIGHUP);

	if (sigaction(SIGHUP, &sighupaction, NULL) < 0) {
		logit("sigaction() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: sigaction() call failed"));
		perror("sigaction");
		exit(1);
	}

	if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) {
		logit("thr_sigsetmask() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_sigsetmask() call failed"));
		perror("thr_sigsetmask");
		exit(1);
	}

	/*
	 *  kick off revalidate threads only if ttl != 0
	 */

	if (thr_create(NULL, NULL, (void *(*)(void*))getldap_refresh,
	    0, 0, NULL) != 0) {
		logit("thr_create() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_create() call failed"));
		perror("thr_create");
		exit(1);
	}

	/*
	 *  kick off the thread which refreshes the server info
	 */

	if (thr_create(NULL, NULL, (void *(*)(void*))getldap_serverInfo_refresh,
	    0, 0, NULL) != 0) {
		logit("thr_create() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_create() call failed"));
		perror("thr_create");
		exit(1);
	}

#ifdef SLP
	if (use_slp) {
		/* kick off SLP discovery thread */
		if (thr_create(NULL, NULL, (void *(*)(void *))discover,
		    (void *)&refresh, 0, NULL) != 0) {
			logit("thr_create() call failed\n");
			syslog(LOG_ERR, gettext("ldap_cachemgr: thr_create() "
			    "call failed"));
			perror("thr_create");
			exit(1);
		}
	}
#endif /* SLP */

	if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) {
		logit("thr_sigsetmask() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: the_sigsetmask() call failed"));
		perror("thr_sigsetmask");
		exit(1);
	}

	/*CONSTCOND*/
	while (1) {
		(void) pause();
	}
	/* NOTREACHED */
	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
}


/*
 * Before calling the alloca() function we have to be sure that we won't get
 * beyond the stack. Since we don't know the precise layout of the stack,
 * the address of an automatic of the function gives us a rough idea, plus/minus
 * a bit. We also need a bit more of stackspace after the call to be able
 * to call further functions. Even something as simple as making a system call
 * from within this function can take ~100 Bytes of stackspace.
 */
#define	SAFETY_BUFFER 32 * 1024 /* 32KB */

static
size_t
get_data_size(LineBuf *config_info, int *err_code)
{
	size_t		configSize = sizeof (ldap_return_t);
	dataunion	*buf = NULL; /* For the 'sizeof' purpose */

	if (config_info->str != NULL &&
	    config_info->len >= sizeof (buf->data.ldap_ret.ldap_u.config)) {
		configSize = sizeof (buf->space) +
		    config_info->len -
		    sizeof (buf->data.ldap_ret.ldap_u.config);

		if (!stack_inbounds((char *)&buf -
		    (configSize + SAFETY_BUFFER))) {
			/*
			 * We do not have enough space on the stack
			 * to accomodate the whole DUAProfile
			 */
			logit("The DUAProfile is too big. There is not enough "
			    "space to process it. Ignoring it.\n");
			syslog(LOG_ERR, gettext("ldap_cachemgr: The DUAProfile "
			    "is too big. There is not enough space "
			    "to process it. Ignoring it."));

			*err_code = SERVERERROR;

			free(config_info->str);
			config_info->str = NULL;
			config_info->len = 0;
			configSize = sizeof (ldap_return_t);
		}
	}

	return (configSize);
}
예제 #4
0
int
main(int argc, char ** argv)
{
	int		opt;
	int		errflg = 0;
	int		showstats = 0;
	int		doset = 0;
	nscd_rc_t	rc;
	char		*me = "main()";
	char		*ret_locale;
	char		*ret_textdomain;
	char		msg[128];
	struct		rlimit rl;

	ret_locale = setlocale(LC_ALL, "");
	if (ret_locale == NULL)
		(void) fprintf(stderr, gettext("Unable to set locale\n"));

	ret_textdomain = textdomain(TEXT_DOMAIN);
	if (ret_textdomain == NULL)
		(void) fprintf(stderr, gettext("Unable to set textdomain\n"));

	/*
	 * The admin model for TX is that labeled zones are managed
	 * in global zone where most trusted configuration database
	 * resides. However, nscd will run in any labeled zone if
	 * file /var/tsol/doors/nscd_per_label exists.
	 */
	if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) {
		struct stat sbuf;
		if (stat(TSOL_NSCD_PER_LABEL_FILE, &sbuf) < 0) {
			(void) fprintf(stderr,
			gettext("With Trusted Extensions nscd runs only in the "
			    "global zone (if nscd_per_label flag not set)\n"));
			exit(1);
		}
	}

	/*
	 *  Special case non-root user here - he can just print stats
	 */
	if (geteuid()) {
		if (argc != 2 ||
		    (strcmp(argv[1], "-g") && strcmp(argv[1], "-G"))) {
			(void) fprintf(stderr,
	gettext("Must be root to use any option other than -g\n\n"));
			usage(argv[0]);
		}

		if (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS) {
			(void) fprintf(stderr,
			gettext("%s doesn't appear to be running.\n"),
			    argv[0]);
			exit(1);
		}
		if (_nscd_client_getadmin(argv[1][1]) != 0) {
			(void) fprintf(stderr,
	gettext("unable to get configuration and statistics data\n"));
			exit(1);
		}

		_nscd_client_showstats();
		exit(0);
	}

	/*
	 *  Determine if there is already a daemon (main nscd) running.
	 *  If not, will start it. Forker NSCD will always become a
	 *  daemon.
	 */
	will_become_server = (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS);
	if (argc >= 2 && strcmp(argv[1], "-F") == 0) {
		will_become_server = 1;
		_whoami = NSCD_FORKER;

		/*
		 * allow time for the main nscd to get ready
		 * to receive the IMHERE door request this
		 * process will send later
		 */
		(void) usleep(100000);
	}

	/*
	 * first get the config file path. Also detect
	 * invalid option as soon as possible.
	 */
	while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) {
		switch (opt) {

		case 'f':
			if ((cfgfile = strdup(optarg)) == NULL)
				exit(1);
			break;
		case 'g':
			if (will_become_server) {
				(void) fprintf(stderr,
		gettext("nscd not running, no statistics to show\n\n"));
				errflg++;
			}
			break;
		case 'i':
			if (will_become_server) {
				(void) fprintf(stderr,
		gettext("nscd not running, no cache to invalidate\n\n"));
				errflg++;
			}
			break;

		case '?':
			errflg++;
			break;
		}

	}
	if (errflg)
		usage(argv[0]);

	/*
	 *  perform more initialization and load configuration
	 * if to become server
	 */
	if (will_become_server) {

		/* initialize switch engine and config/stats management */
		if ((rc = _nscd_init(cfgfile)) != NSCD_SUCCESS) {
			(void) fprintf(stderr,
		gettext("initialization of switch failed (rc = %d)\n"), rc);
			exit(1);
		}
		_nscd_get_log_info(debug_level, sizeof (debug_level),
		    logfile, sizeof (logfile));

		/*
		 * initialize cache store
		 */
		if ((rc = init_cache(0)) != NSCD_SUCCESS) {
			(void) fprintf(stderr,
	gettext("initialization of cache store failed (rc = %d)\n"), rc);
			exit(1);
		}
	}

	/*
	 * process usual options
	 */
	optind = 1; /* this is a rescan */
	*msg = '\0';
	while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) {

		switch (opt) {

		case 'K':		/* undocumented feature */
			(void) _nscd_doorcall(NSCD_KILLSERVER);
			exit(0);
			break;

		case 'G':
		case 'g':
			showstats++;
			break;

		case 'p':
			doset++;
			if (_nscd_add_admin_mod(optarg, 'p',
			    getcacheopt(optarg),
			    msg, sizeof (msg)) == -1)
				errflg++;
			break;

		case 'n':
			doset++;
			if (_nscd_add_admin_mod(optarg, 'n',
			    getcacheopt(optarg),
			    msg, sizeof (msg)) == -1)
				errflg++;
			break;

		case 'c':
			doset++;
			if (_nscd_add_admin_mod(optarg, 'c',
			    getcacheopt(optarg),
			    msg, sizeof (msg)) == -1)
				errflg++;
			break;

		case 'i':
			doset++;
			if (_nscd_add_admin_mod(optarg, 'i', NULL,
			    msg, sizeof (msg)) == -1)
				errflg++;
			break;

		case 'l':
			doset++;
			(void) strlcpy(logfile, optarg, sizeof (logfile));
			break;

		case 'd':
			doset++;
			(void) strlcpy(debug_level, optarg,
			    sizeof (debug_level));
			break;

		case 'S':
			/* silently ignore secure-mode */
			break;

		case 's':
			/* silently ignore suggested-size */
			break;

		case 'o':
			/* silently ignore old-data-ok */
			break;

		case 'h':
			doset++;
			if (_nscd_add_admin_mod(optarg, 'h',
			    getcacheopt(optarg),
			    msg, sizeof (msg)) == -1)
				errflg++;
			break;

		case 'e':
			doset++;
			if (_nscd_add_admin_mod(optarg, 'e',
			    getcacheopt(optarg),
			    msg, sizeof (msg)) == -1)
				errflg++;
			break;

		case 'F':
			_whoami = NSCD_FORKER;
			break;

		default:
			errflg++;
			break;
		}

	}

	if (errflg) {
		if (*msg != '\0')
			(void) fprintf(stderr, "\n%s: %s\n\n", argv[0], msg);
		usage(argv[0]);
	}

	/*
	 * if main nscd already running and not forker nscd,
	 * can only do admin work
	 */
	if (_whoami == NSCD_MAIN) {
		if (!will_become_server) {
			if (showstats) {
				if (_nscd_client_getadmin('g')) {
					(void) fprintf(stderr,
			gettext("Cannot contact nscd properly(?)\n"));
					exit(1);
				}
				_nscd_client_showstats();
			}

			if (doset) {
				if (_nscd_client_setadmin() < 0) {
					(void) fprintf(stderr,
				gettext("Error during admin call\n"));
					exit(1);
				}
			}
			if (!showstats && !doset) {
				(void) fprintf(stderr,
gettext("%s already running.... no administration option specified\n"),
				    argv[0]);
			}
			exit(0);
		}
	}

	/*
	 *   daemon from here on
	 */

	if (_whoami == NSCD_MAIN) {

		/* save enough info in case need to restart or fork */
		saved_argc = argc;
		saved_argv = argv;
		save_execname();

		/*
		 * if a log file is not specified, set it to
		 * "stderr" or "/dev/null" based on debug level
		 */
		if (*logfile == '\0') {
			if (*debug_level != '\0')
				/* we're debugging... */
				(void) strcpy(logfile, "stderr");
			else
				(void) strcpy(logfile, "/dev/null");
		}
		(void) _nscd_add_admin_mod(NULL, 'l', logfile,
		    msg, sizeof (msg));
		(void) _nscd_add_admin_mod(NULL, 'd', debug_level,
		    msg, sizeof (msg));

		/* activate command options */
		if (_nscd_server_setadmin(NULL) != NSCD_SUCCESS) {
			(void) fprintf(stderr,
			gettext("unable to set command line options\n"));
			exit(1);
		}

		if (*debug_level != '\0') {
			/* we're debugging, no forking of nscd */

			/*
			 * forker nscd will be started if self credential
			 * is configured
			 */
			_nscd_start_forker(saved_execname, saved_argc,
			    saved_argv);
		} else {
			/*
			 * daemonize the nscd (forker nscd will also
			 * be started if self credential is configured)
			 */
			detachfromtty();
		}
	} else { /* NSCD_FORKER */
		/*
		 * To avoid PUN (Per User Nscd) processes from becoming
		 * zombies after they exit, the forking nscd should
		 * ignore the SIGCLD signal so that it does not
		 * need to wait for every child PUN to exit.
		 */
		(void) signal(SIGCLD, SIG_IGN);
		(void) open("/dev/null", O_RDWR, 0);
		(void) dup(0);
		if (_logfd != 2)
			(void) dup(0);
	}

	/* set NOFILE to unlimited */
	rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
		(me, "Cannot set open file limit: %s\n", strerror(errno));
		exit(1);
	}

	/* set up door and establish our own server thread pool */
	if ((_doorfd = _nscd_setup_server(saved_execname, saved_argv)) == -1) {
		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
		(me, "unable to set up door\n");
		exit(1);
	}

	/* inform the main nscd that this forker is ready */
	if (_whoami == NSCD_FORKER) {
		int	ret;

		for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; )
			ret = _nscd_doorcall_sendfd(_doorfd,
			    NSCD_IMHERE | (NSCD_FORKER & NSCD_WHOAMI),
			    NULL, 0, NULL);
	}

	for (;;) {
		(void) pause();
		(void) _nscd_doorcall(NSCD_REFRESH);
	}

	/* NOTREACHED */
	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
}
예제 #5
0
int
main(int argc, char *const *argv)
{
	struct sockaddr_in bindaddr;
	socklen_t addrlen;
	const char *isDA;
	const char *proxyReg;
	int connfd;
	int lfd;
	const int on = 1;

	detachfromtty();

	openlog("slpd", LOG_PID, LOG_DAEMON);

	do_args(argc, argv);

	/* If slpd has been configured to run as a DA, start it and exit */
	isDA = SLPGetProperty("net.slp.isDA");
	proxyReg = SLPGetProperty("net.slp.serializedRegURL");
	if ((isDA && (strcasecmp(isDA, "true") == 0)) || proxyReg) {
		run_slpd();
		return (1);
	}

	if ((lfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		syslog(LOG_ERR, "socket failed: %s", strerror(errno));
		cleanup_and_exit(1);
	}

	(void) setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));

	(void) memset((void *)&bindaddr, 0, sizeof (bindaddr));
	bindaddr.sin_family = AF_INET;
	bindaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	bindaddr.sin_port = htons(427);

	if (bind(lfd, (const struct sockaddr *)&bindaddr, sizeof (bindaddr))
	    < 0) {
		syslog(LOG_ERR, "bind failed: %s", strerror(errno));
		cleanup_and_exit(1);
	}

	if (listen(lfd, 1) < 0) {
		syslog(LOG_ERR, "listen failed: %s", strerror(errno));
		cleanup_and_exit(1);
	}

	addrlen = sizeof (bindaddr);
	if ((connfd = accept(lfd, (struct sockaddr *)&bindaddr, &addrlen))
	    < 0) {
		syslog(LOG_ERR, "accept failed: %s", strerror(errno));
		cleanup_and_exit(1);
	}

	(void) close(lfd);

	(void) dup2(connfd, 0);
	(void) close(connfd);
	(void) dup2(0, 1);
	(void) dup2(0, 2);

	run_slpd();

	return (1);
}