usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
author Pavan Mettu - Oracle Corporation - Menlo Park United States <Pavan.Mettu@Oracle.COM>
Wed, 11 Aug 2010 17:11:30 -0500
changeset 13092 fcc1e406c13f
parent 12393 a4df3ee2f129
permissions -rw-r--r--
6975309 PSARC2007_393 Move /etc/default/{nfs/autofs} parameters to SMF PSARC 2007/393 converting /etc/default/{nfs,autofs} to SMF properties

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

#include <sys/types.h>
#include <rpc/rpc.h>
#include <netconfig.h>
#include <netdir.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <libtsnet.h>
#include <nfs/nfssys.h>
#include <nfs/export.h>
#include <nfs/nfs_cmd.h>
#include <door.h>
#include <syslog.h>
#include <locale.h>
#include <strings.h>
#include <sharefs/share.h>

extern struct share *findentry(char *);
/*
 * The following codesets must match what is in libshare_nfs.c until we can
 * request them from the kernel.
 */
char *charopts[] = {
	"euc-cn",
	"euc-jp",
	"euc-jpms",
	"euc-kr",
	"euc-tw",
	"iso8859-1",
	"iso8859-2",
	"iso8859-5",
	"iso8859-6",
	"iso8859-7",
	"iso8859-8",
	"iso8859-9",
	"iso8859-13",
	"iso8859-15",
	"koi8-r",
	NULL
};

/*
 * nfscmd_err(dp, args, err)
 * Return an error for the door call.
 */

static void
nfscmd_err(door_desc_t *dp, nfscmd_arg_t *args, int err)
{
	nfscmd_res_t res;

	res.version = NFSCMD_VERS_1;
	res.cmd = NFSCMD_ERROR;
	res.error = err;
	(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
	(void) door_return(NULL, 0, NULL, 0);
	/* NOTREACHED */

}

/*
 * charmap_search(netbuf, opts)
 *
 * Check to see if the address in the netbuf is found in
 * a character map spec in the opts option string. Returns the charset
 * name if found.
 */

static char *
charmap_search(struct netbuf *nbuf, char *opts)
{
	char *copts;
	char *next;
	char *name;
	char *result = NULL;
	char *netid;
	struct netconfig *nconf;
	struct nd_hostservlist  *hl = NULL;
	struct sockaddr *sa;

	/* eventually charopts should be dynamically setup */
	if (charopts == NULL) {
		free(copts);
		return (NULL);
	}

	sa = (struct sockaddr *)nbuf->buf;

	switch (sa->sa_family) {
	case AF_INET:
		nconf = getnetconfigent("tcp");
		break;
	case AF_INET6:
		nconf = getnetconfigent("tcp6");
		break;
	default:
		return (NULL);
	}

	if (nconf == NULL) {
		return (NULL);
	}

	/*
	 * Use the this API instead of the netdir_getbyaddr()
	 * to avoid service lookup.
	 */
	if (__netdir_getbyaddr_nosrv(nconf, &hl, nbuf)) {
		syslog(LOG_ERR, "netdir: %s\n", netdir_sperror());
		freenetconfigent(nconf);
		return (NULL);
	}

	copts = strdup(opts);
	if (copts == NULL) {
		freenetconfigent(nconf);
		return (NULL);
	}

	next = copts;
	while (*next != '\0') {
		char *val;
		name = next;
		if (getsubopt(&next, charopts, &val) >= 0) {
			char *cp;
			/*
			 * name will have the whole opt and val the value. Set
			 * the '=' to '\0' and we have the charmap in name and
			 * the access list in val.
			 */
			cp = strchr(name, '=');
			if (cp != NULL)
				*cp = '\0';
			if (in_access_list(NULL, &nbuf, &hl, val)) {
				result = name;
				break;
			}
		}
	}

	if (result != NULL)
		result = strdup(result);

	free(copts);
	freenetconfigent(nconf);

	return (result);
}

/*
 * nfscmd_charmap_lookup(door, args)
 *
 * Check to see if there is a translation requested for the path
 * specified in the request. If there is, return the charset name.
 */

static void
nfscmd_charmap_lookup(door_desc_t *dp, nfscmd_arg_t *args)
{
	nfscmd_res_t res;
	struct netbuf nb;
	struct sockaddr sa;
	struct share *sh = NULL;
	char *opts;
	char *name;

	memset(&res, '\0', sizeof (res));
	res.version = NFSCMD_VERS_1;
	res.cmd = NFSCMD_CHARMAP_LOOKUP;

	sh = findentry(args->arg.charmap.path);

	if (sh != NULL) {
		nb.len = nb.maxlen = sizeof (struct sockaddr);
		nb.buf = (char *)&sa;

		sa = args->arg.charmap.addr;

		name = charmap_search(&nb, sh->sh_opts);
		if (name != NULL) {
			strcpy(res.result.charmap.codeset, name);
			res.result.charmap.apply = B_TRUE;
			res.error = NFSCMD_ERR_SUCCESS;
			free(name);
		} else {
			res.result.charmap.apply = B_FALSE;
			res.error = NFSCMD_ERR_NOTFOUND;
		}
		sharefree(sh);
	} else {
		res.error = NFSCMD_ERR_NOTFOUND;
	}

	(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
	(void) door_return(NULL, 0, NULL, 0);
	/* NOTREACHED */
}

/*
 * nfscmd_ver_1(door, args, size)
 *
 * Version 1 of the door command processor for nfs cmds.
 */

static void
nfscmd_vers_1(door_desc_t *dp, nfscmd_arg_t *args, size_t size)
{
	switch (args->cmd) {
	case NFSCMD_CHARMAP_LOOKUP:
		nfscmd_charmap_lookup(dp, args);
		break;
	default:
		nfscmd_err(dp, args, NFSCMD_ERR_BADCMD);
		break;
	}
}

/*
 * nfscmd_func(cookie, dataptr, size, door, ndesc)
 *
 * The function called by the door thread for processing
 * nfscmd type commands.
 */

void
nfscmd_func(void *cookie, char *dataptr, size_t arg_size,
	door_desc_t *dp, uint_t n_desc)
{
	nfscmd_arg_t	*args;

	args = (nfscmd_arg_t *)dataptr;

	switch (args->version) {
	case NFSCMD_VERS_1:
		nfscmd_vers_1(dp, args, arg_size);
		break;
	default:
		syslog(LOG_ERR, gettext("Invalid nfscmd version"));
		break;
	}

	(void) door_return((caddr_t)args, sizeof (nfscmd_res_t), NULL, 0);
	(void) door_return(NULL, 0, NULL, 0);
	/* NOTREACHED */

}