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/*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <sys/types.h>
27#include <rpc/rpc.h>
28#include <netconfig.h>
29#include <netdir.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <netdb.h>
33#include <libtsnet.h>
34#include <nfs/nfssys.h>
35#include <nfs/export.h>
36#include <nfs/nfs_cmd.h>
37#include <door.h>
38#include <syslog.h>
39#include <locale.h>
40#include <strings.h>
41#include <sharefs/share.h>
42
43extern struct share *findentry(char *);
44/*
45 * The following codesets must match what is in libshare_nfs.c until we can
46 * request them from the kernel.
47 */
48char *charopts[] = {
49	"euc-cn",
50	"euc-jp",
51	"euc-jpms",
52	"euc-kr",
53	"euc-tw",
54	"iso8859-1",
55	"iso8859-2",
56	"iso8859-5",
57	"iso8859-6",
58	"iso8859-7",
59	"iso8859-8",
60	"iso8859-9",
61	"iso8859-13",
62	"iso8859-15",
63	"koi8-r",
64	NULL
65};
66
67/*
68 * nfscmd_err(dp, args, err)
69 * Return an error for the door call.
70 */
71
72static void
73nfscmd_err(door_desc_t *dp, nfscmd_arg_t *args, int err)
74{
75	nfscmd_res_t res;
76
77	res.version = NFSCMD_VERS_1;
78	res.cmd = NFSCMD_ERROR;
79	res.error = err;
80	(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
81	(void) door_return(NULL, 0, NULL, 0);
82	/* NOTREACHED */
83
84}
85
86/*
87 * charmap_search(netbuf, opts)
88 *
89 * Check to see if the address in the netbuf is found in
90 * a character map spec in the opts option string. Returns the charset
91 * name if found.
92 */
93
94static char *
95charmap_search(struct netbuf *nbuf, char *opts)
96{
97	char *copts;
98	char *next;
99	char *name;
100	char *result = NULL;
101	char *netid;
102	struct netconfig *nconf;
103	struct nd_hostservlist  *hl = NULL;
104	struct sockaddr *sa;
105
106	/* eventually charopts should be dynamically setup */
107	if (charopts == NULL) {
108		free(copts);
109		return (NULL);
110	}
111
112	sa = (struct sockaddr *)nbuf->buf;
113
114	switch (sa->sa_family) {
115	case AF_INET:
116		nconf = getnetconfigent("tcp");
117		break;
118	case AF_INET6:
119		nconf = getnetconfigent("tcp6");
120		break;
121	default:
122		return (NULL);
123	}
124
125	if (nconf == NULL) {
126		return (NULL);
127	}
128
129	/*
130	 * Use the this API instead of the netdir_getbyaddr()
131	 * to avoid service lookup.
132	 */
133	if (__netdir_getbyaddr_nosrv(nconf, &hl, nbuf)) {
134		syslog(LOG_ERR, "netdir: %s\n", netdir_sperror());
135		freenetconfigent(nconf);
136		return (NULL);
137	}
138
139	copts = strdup(opts);
140	if (copts == NULL) {
141		freenetconfigent(nconf);
142		return (NULL);
143	}
144
145	next = copts;
146	while (*next != '\0') {
147		char *val;
148		name = next;
149		if (getsubopt(&next, charopts, &val) >= 0) {
150			char *cp;
151			/*
152			 * name will have the whole opt and val the value. Set
153			 * the '=' to '\0' and we have the charmap in name and
154			 * the access list in val.
155			 */
156			cp = strchr(name, '=');
157			if (cp != NULL)
158				*cp = '\0';
159			if (in_access_list(NULL, &nbuf, &hl, val)) {
160				result = name;
161				break;
162			}
163		}
164	}
165
166	if (result != NULL)
167		result = strdup(result);
168
169	free(copts);
170	freenetconfigent(nconf);
171
172	return (result);
173}
174
175/*
176 * nfscmd_charmap_lookup(door, args)
177 *
178 * Check to see if there is a translation requested for the path
179 * specified in the request. If there is, return the charset name.
180 */
181
182static void
183nfscmd_charmap_lookup(door_desc_t *dp, nfscmd_arg_t *args)
184{
185	nfscmd_res_t res;
186	struct netbuf nb;
187	struct sockaddr sa;
188	struct share *sh = NULL;
189	char *opts;
190	char *name;
191
192	memset(&res, '\0', sizeof (res));
193	res.version = NFSCMD_VERS_1;
194	res.cmd = NFSCMD_CHARMAP_LOOKUP;
195
196	sh = findentry(args->arg.charmap.path);
197
198	if (sh != NULL) {
199		nb.len = nb.maxlen = sizeof (struct sockaddr);
200		nb.buf = (char *)&sa;
201
202		sa = args->arg.charmap.addr;
203
204		name = charmap_search(&nb, sh->sh_opts);
205		if (name != NULL) {
206			strcpy(res.result.charmap.codeset, name);
207			res.result.charmap.apply = B_TRUE;
208			res.error = NFSCMD_ERR_SUCCESS;
209			free(name);
210		} else {
211			res.result.charmap.apply = B_FALSE;
212			res.error = NFSCMD_ERR_NOTFOUND;
213		}
214		sharefree(sh);
215	} else {
216		res.error = NFSCMD_ERR_NOTFOUND;
217	}
218
219	(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
220	(void) door_return(NULL, 0, NULL, 0);
221	/* NOTREACHED */
222}
223
224/*
225 * nfscmd_ver_1(door, args, size)
226 *
227 * Version 1 of the door command processor for nfs cmds.
228 */
229
230static void
231nfscmd_vers_1(door_desc_t *dp, nfscmd_arg_t *args, size_t size)
232{
233	switch (args->cmd) {
234	case NFSCMD_CHARMAP_LOOKUP:
235		nfscmd_charmap_lookup(dp, args);
236		break;
237	default:
238		nfscmd_err(dp, args, NFSCMD_ERR_BADCMD);
239		break;
240	}
241}
242
243/*
244 * nfscmd_func(cookie, dataptr, size, door, ndesc)
245 *
246 * The function called by the door thread for processing
247 * nfscmd type commands.
248 */
249
250void
251nfscmd_func(void *cookie, char *dataptr, size_t arg_size,
252	door_desc_t *dp, uint_t n_desc)
253{
254	nfscmd_arg_t	*args;
255
256	args = (nfscmd_arg_t *)dataptr;
257
258	switch (args->version) {
259	case NFSCMD_VERS_1:
260		nfscmd_vers_1(dp, args, arg_size);
261		break;
262	default:
263		syslog(LOG_ERR, gettext("Invalid nfscmd version"));
264		break;
265	}
266
267	(void) door_return((caddr_t)args, sizeof (nfscmd_res_t), NULL, 0);
268	(void) door_return(NULL, 0, NULL, 0);
269	/* NOTREACHED */
270
271}
272