usr/src/cmd/rad/mod/xport_tcp/mod_tcp.c
author Stephen Talley <stephen.talley@oracle.com>
Fri, 18 May 2012 11:08:12 -0400
changeset 862 f20f2afa6263
parent 852 usr/src/cmd/rad/mod/xport_tcp/mod_xport_tcp.c@bcfb754700ce
permissions -rw-r--r--
mod_xport -> mod

/*
 * 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 (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <bsm/adt_event.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#include <rad/adr_stream.h>
#include "rad_object.h"
#include "rad_modapi.h"
#include "rad_modapi_xport.h"
#include "rad_connection.h"
#include "rad_xport.h"
#include "../rad_listen.h"

#include "api_tcp.h"

static char *pam_service = "rad-tcp";

static void
tcp_run(void *arg)
{
	radmod_connection_t *conn = arg;
	rad_proto_handle(conn);
	rad_conn_free(conn);
}

static rad_moderr_t
tcp_listen(rad_thread_t *arg)
{
	int fd;
	data_t *d, *data = rad_thread_arg(arg);

	int port = data_to_integer(struct_get(data, "port"));
	d = struct_get(data, "proto");
	const char *protostr = d != NULL ? data_to_string(d) : "rad";
	d = struct_get(data, "localonly");
	boolean_t local = d != NULL ? data_to_boolean(d) : B_TRUE;
	d = struct_get(data, "noauth");
	boolean_t noauth = d != NULL ? data_to_boolean(d) : B_FALSE;
	d = struct_get(data, "pam_service");
	if (d != NULL) {
		pam_service = (char *)data_to_string(d);
	}

	rad_subject_t *subject = NULL;

	rad_protocol_t *proto = rad_proto_find(protostr);
	if (proto == NULL) {
		rad_log(RL_ERROR, "unable to find protocol '%s'", protostr);
		return (rm_config);
	}

	if (noauth) {
		ucred_t *uc = ucred_get(P_MYID);
		if (uc == NULL ||
		    (subject = rad_subject_create_ucred(uc, B_FALSE,
		    pam_service)) == NULL) {
			rad_log(RL_ERROR, "failed to allocate subject");
			return (rm_system);
		}
		rad_log(RL_WARN, "AUTHORIZING ANONYMOUS TCP CONNECTIONS");
	}

	if ((fd = listen_on_port(port, local)) < 0) {
		rad_log(RL_ERROR, "error starting server on port %d", port);
		return (rm_system);
	}

	rad_thread_ack(arg, rm_ok);
	for (;;) {
		int afd;

		rad_log(RL_DEBUG, "Waiting for connection");
		if ((afd = accept(fd, 0, 0)) == -1) {
			rad_log(RL_ERROR, "error in accept(): %s\n",
			    strerror(errno));
			continue;
		}
		rad_log(RL_DEBUG, "Connection accepted");

		adr_stream_t *stream = adr_stream_create_fd(afd);
		if (stream == NULL)
			continue;

		radmod_connection_t *conn = rad_conn_create_fd(afd, B_TRUE);
		if (conn == NULL) {
			adr_stream_close(stream);
			adr_stream_free(stream);
			rad_log(RL_WARN, "failed to allocate connection");
			continue;
		}
		conn->rm_conn_xport = stream;
		conn->rm_conn_proto_ops = proto;
		conn->rm_conn_pam_service = pam_service;

		if (noauth) {
			assert(subject != NULL);
			rad_subject_ref(subject);
			if (!rad_conn_setsubject(conn, subject)) {
				rad_log(RL_WARN,
				    "failed to set connection subject");
				rad_conn_close(conn);
				rad_conn_free(conn);
				continue;
			}
		}

		if (rad_thread_create_async(tcp_run, conn) != rm_ok) {
			rad_conn_close(conn);
			rad_conn_free(conn);
		}
	}
}

static rad_moderr_t
starter(data_t *data)
{
	/*
	 * Validate parameters
	 */
	data_t *port = struct_get(data, "port");
	if (port == NULL) {
		rad_log(RL_ERROR, "Port required\n");
		return (rm_config);
	}

	return (rad_thread_create(tcp_listen, data));
}

static rad_modinfo_t modinfo = { "xport_tcp", "TCP transport module" };

int
_rad_init(void *handle)
{
	if (rad_module_register(handle, RAD_MODVERSION, &modinfo) == -1)
		return (-1);

	rad_xport_register("tcp", &t__tcp, starter);
	return (0);
}