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
nfscmd_err(door_desc_t * dp,nfscmd_arg_t * args,int err)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 *
charmap_search(struct netbuf * nbuf,char * opts)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
nfscmd_charmap_lookup(door_desc_t * dp,nfscmd_arg_t * args)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
nfscmd_vers_1(door_desc_t * dp,nfscmd_arg_t * args,size_t size)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
nfscmd_func(void * cookie,char * dataptr,size_t arg_size,door_desc_t * dp,uint_t n_desc)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