usr/src/cmd/rad/rad.c
author David Powell <David.Powell@sun.com>
Wed, 16 Dec 2009 19:06:12 -0800
changeset 401 fc1223edbd8d
parent 391 71abce159a62
child 436 c28d8d667ea1
permissions -rw-r--r--
13421 apache: o.o.o.rad.ContainerException: system error: error talking to slave 13426 TLS transport auto-generates readable private keys 13429 file browsing API hard codes incorrect attributes

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/wait.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <locale.h>
#include <libscf.h>
#include <errno.h>
#include <string.h>

#include <libxml/parser.h>

#include "rad_object.h"
#include "rad_module.h"
#include "rad_xport.h"
#include "rad_pam.h"
#include "rad_ticket.h"
#include "rad_control.h"
#include "rad_log.h"
#include "rad_smf.h"
#include "rad_util.h"

#include "api_config.h"

#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN	"SYS_TEST"
#endif

container_t rad_container = CONTAINER_INITIALIZER;
container_t rad_container_unauth = CONTAINER_INITIALIZER;
container_t rad_container_control = CONTAINER_INITIALIZER;

int rad_exit_failure = 1;
int rad_exit_config = 1;
boolean_t rad_isproxy = B_FALSE;
data_t *moduledirs;

const char *
_umem_debug_init()
{
	return ("default");
}

/*
 * rad(1M) Configuration
 * ---------------------
 *
 * rad(1M) configuration can be obtained from two sources.  Firstly, if
 * rad is started from SMF and the -s option is specified, it will obtain
 * configuration from the corresponding service instance.  Secondly,
 * command line arguments can be provided to specify a particular
 * configuration.  If configuration is available from both sources,
 * command line configuration is processed before SMF configuration.
 *
 * There are two things that are configurable in rad(1M).
 *
 * 1) The set of directories to scan for modules:
 *    SMF: config/moduledir astring[]
 *    Command line: '-m <moduledir>' option
 *
 * 2) The set of endpoints to listen on
 *    SMF: <pgname>:xport_<xport type> / *
 *    Command line: '-t <transport>[:opt1[=val1][,opt2[=val2]...]]'
 *
 *    Available transports are 'stdin', 'tcp', 'tls', and 'uds'.
 *    All transports take a 'proto' option, which defaults to 'rad'.
 *    'tcp' and 'tls' require a 'port' option.  'uds' requires a
 *    'path' option.
 */

static int
rad_service_wait()
{
	int status;
	pid_t pid;
	int fds[2];

	if (pipe(fds) == -1)
		rad_log(RL_FATAL, "unable to create pipe: %s", strerror(errno));

	if ((pid = fork()) == -1)
		rad_log(RL_FATAL, "unable to fork daemon: %s", strerror(errno));

	if (pid > 0) {
		pid_t wpid;

		(void) close(fds[1]);
		if (read(fds[0], &status, sizeof (status)) == sizeof (status))
			_exit(status);

		do {
			wpid = waitpid(pid, &status, 0);
		} while (wpid != pid && errno == EINTR);
		if (WIFEXITED(status))
			_exit(WEXITSTATUS(status));
		_exit(SMF_EXIT_ERR_FATAL);
	}

	(void) close(fds[0]);
	return (fds[1]);
}

static void
rad_service_done(int fd)
{
	int status = SMF_EXIT_OK;
	(void) write(fd, &status, sizeof (status));
}

/* -s is for SMF consumption only; not documented */
static const char *usage =
    "Usage: rad [ -d ] [ -S fmri ] [ -m moduledir ] [ -t transport ]\n";

int
main(int argc, char **argv)
{
	int opt, i;
	int nxport = 0, nmoddir = 0;
	const char *xports[argc], *moddirs[argc];
	boolean_t smf_startup = B_FALSE;
	boolean_t smf_config = B_FALSE;
	const char *smf_fmri = NULL;
	sigset_t hupset;
	int svc_fd = -1;

	(void) umask(077);
	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	(void) sigemptyset(&hupset);
	(void) sigaddset(&hupset, SIGHUP);
	(void) sigprocmask(SIG_BLOCK, &hupset, NULL);
	(void) sigignore(SIGPIPE);
	(void) sigignore(SIGCHLD);

	while ((opt = getopt(argc, argv, "dpsS:t:m:")) != EOF) {
		switch (opt) {
		case 't':
			xports[nxport++] = optarg;
			break;
		case 'm':
			moddirs[nmoddir++] = optarg;
			break;
		case 'p':
			rad_isproxy = B_TRUE;
			break;
		case 's':
			smf_startup = B_TRUE;
			smf_config = B_TRUE;
			rad_exit_failure = SMF_EXIT_ERR_FATAL;
			rad_exit_config = SMF_EXIT_ERR_CONFIG;
			break;
		case 'S':
			/* Read config from specified FMRI */
			smf_config = B_TRUE;
			smf_fmri = optarg;
			break;
		case 'd':
			rad_loglevel = RL_ALL;
			break;
		default:
			(void) fprintf(stderr, usage);
			exit(2);
		}
	}

	moduledirs = rad_strarray(moddirs, nmoddir, lt_copy);

	if (smf_config) {
		data_t *config = rad_smf_read_pg_byname(smf_fmri, "config",
		    &t__radconfig);
		if (config == NULL)
			rad_log(RL_CONFIG,
			    "unable to read configuration from service\n");
		data_t *modules = struct_get(config, "moduledir");
		data_t *debug = struct_get(config, "debug");
		if (debug != NULL && debug->d_data.boolean)
			rad_loglevel = RL_ALL;
		moduledirs = array_combine(moduledirs, data_ref(modules));
	}

	/* parent exits, child returns */
	if (smf_startup)
		svc_fd = rad_service_wait();

	xmlInitParser();	/* So libxml consumers are MT safe */
	rad_ticket_init();
	rad_pam_init();
	rad_module_init();
	rad_control_init();

	if (moduledirs->d_rsize == 0)
		rad_log(RL_CONFIG, "No module directories specified.\n");

	for (i = 0; i < moduledirs->d_rsize; i++)
		rad_module_scan(moduledirs->d_data.array[i]->d_data.string);

	for (i = 0; i < nxport; i++)
		rad_xport_parse(xports[i]);

	if (smf_startup) {
		/*
		 * Only process SMF-configured transports when really
		 * run as a service.
		 */
		rad_xport_smf();
		rad_service_done(svc_fd);
	}

	(void) sigprocmask(SIG_UNBLOCK, &hupset, NULL);
	for (;;)
		pause();
}