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