xref: /illumos-gate/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c (revision d34083bdb88c46438e20789b3e42044428239a21)
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 
43 extern 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  */
48 char *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 
72 static void
73 nfscmd_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 
94 static char *
95 charmap_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 
182 static void
183 nfscmd_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 
230 static void
231 nfscmd_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 
250 void
251 nfscmd_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