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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
29 * All rights reserved.
30 */
31
32 /*
33 * Copyright 2017 Joyent, Inc.
34 * Copyright 2018 Nexenta Systems, Inc.
35 */
36
37 #include <sys/types.h>
38 #include <rpc/types.h>
39 #include <sys/systm.h>
40 #include <sys/vfs.h>
41 #include <sys/errno.h>
42 #include <sys/cred.h>
43 #include <sys/policy.h>
44 #include <sys/siginfo.h>
45 #include <sys/proc.h> /* for exit() declaration */
46 #include <sys/kmem.h>
47 #include <nfs/nfs4.h>
48 #include <nfs/nfssys.h>
49 #include <sys/thread.h>
50 #include <rpc/auth.h>
51 #include <rpc/rpcsys.h>
52 #include <rpc/svc.h>
53
54 /*
55 * This is filled in with an appropriate address for the
56 * function that will traverse the rfs4_client_t table
57 * and mark any matching IP Address as "forced_expire".
58 *
59 * It is the server init() function that plops the
60 * function pointer.
61 */
62 void (*rfs4_client_clrst)(struct nfs4clrst_args *) = NULL;
63
64 /* This filled in by nfssrv:_init() */
65 void (*nfs_srv_quiesce_func)(void) = NULL;
66
67 extern void nfscmd_args(uint_t);
68
69 /*
70 * These will be reset by klmmod:lm_svc(), when lockd starts NLM service,
71 * based on values read by lockd from /etc/default/nfs. Since nfssrv depends on
72 * klmmod, the declarations need to be here (in nfs, on which both depend) so
73 * that nfssrv can see the klmmod changes.
74 * When the dependency of NFSv4 on NLM/lockd is removed, this will need to
75 * be adjusted.
76 */
77 #define RFS4_LEASETIME 90 /* seconds */
78 time_t rfs4_lease_time = RFS4_LEASETIME;
79 time_t rfs4_grace_period = RFS4_LEASETIME;
80
81 /* DSS: distributed stable storage */
82 size_t nfs4_dss_buflen = 0;
83 /* This filled in by nfssrv:_init() */
84 int (*nfs_srv_dss_func)(char *, size_t) = NULL;
85
86 int
87 nfs_export(void *arg)
88 {
89 STRUCT_DECL(exportfs_args, ea);
90
91 STRUCT_INIT(ea, get_udatamodel());
92 if (copyin(arg, STRUCT_BUF(ea), STRUCT_SIZE(ea)))
93 return (set_errno(EFAULT));
94
95 return (exportfs(STRUCT_BUF(ea), get_udatamodel(), CRED()));
96 }
97
98 int
99 nfssys(enum nfssys_op opcode, void *arg)
100 {
101 int error = 0;
102
103 if (!(opcode == NFS_REVAUTH || opcode == NFS4_SVC) &&
104 secpolicy_nfs(CRED()) != 0)
105 return (set_errno(EPERM));
106
107 switch (opcode) {
108 case NFS4_CLR_STATE: { /* Clear NFS4 client state */
109 struct nfs4clrst_args clr;
110 STRUCT_DECL(nfs4clrst_args, u_clr);
111
112 /*
113 * If the server is not loaded then no point in
114 * clearing nothing :-)
115 */
116 if (rfs4_client_clrst == NULL) {
117 break;
118 }
119
120 STRUCT_INIT(u_clr, get_udatamodel());
121
122 if (copyin(arg, STRUCT_BUF(u_clr), STRUCT_SIZE(u_clr)))
123 return (set_errno(EFAULT));
124
125 clr.vers = STRUCT_FGET(u_clr, vers);
126
127 if (clr.vers != NFS4_CLRST_VERSION)
128 return (set_errno(EINVAL));
129
130 clr.addr_type = STRUCT_FGET(u_clr, addr_type);
131 clr.ap = STRUCT_FGETP(u_clr, ap);
132 rfs4_client_clrst(&clr);
133 break;
134 }
135
136 case SVCPOOL_CREATE: { /* setup an RPC server thread pool */
137 struct svcpool_args p;
138
139 if (copyin(arg, &p, sizeof (p)))
140 return (set_errno(EFAULT));
141
142 error = svc_pool_create(&p);
143 break;
144 }
145
146 case SVCPOOL_WAIT: { /* wait in kernel for threads to be needed */
147 int id;
148
149 if (copyin(arg, &id, sizeof (id)))
150 return (set_errno(EFAULT));
151
152 error = svc_wait(id);
153 break;
154 }
155
156 case SVCPOOL_RUN: { /* give work to a runnable thread */
157 int id;
158
159 if (copyin(arg, &id, sizeof (id)))
160 return (set_errno(EFAULT));
161
162 error = svc_do_run(id);
163 break;
164 }
165
166 case RDMA_SVC_INIT: {
167 struct rdma_svc_args rsa;
168 char netstore[20] = "tcp";
169
170 if (get_udatamodel() != DATAMODEL_NATIVE) {
171 STRUCT_DECL(rdma_svc_args, ursa);
172
173 STRUCT_INIT(ursa, get_udatamodel());
174 if (copyin(arg, STRUCT_BUF(ursa), STRUCT_SIZE(ursa)))
175 return (set_errno(EFAULT));
176
177 rsa.poolid = STRUCT_FGET(ursa, poolid);
178 rsa.nfs_versmin = STRUCT_FGET(ursa, nfs_versmin);
179 rsa.nfs_versmax = STRUCT_FGET(ursa, nfs_versmax);
180 rsa.delegation = STRUCT_FGET(ursa, delegation);
181 } else {
182 if (copyin(arg, &rsa, sizeof (rsa)))
183 return (set_errno(EFAULT));
184 }
185 rsa.netid = netstore;
186
187 error = rdma_start(&rsa);
188 break;
189 }
190
191 case NFS_SVC: { /* NFS server daemon */
192 STRUCT_DECL(nfs_svc_args, nsa);
193 STRUCT_INIT(nsa, get_udatamodel());
194
195 if (copyin(arg, STRUCT_BUF(nsa), STRUCT_SIZE(nsa)))
196 return (set_errno(EFAULT));
197
198 error = nfs_svc(STRUCT_BUF(nsa), get_udatamodel());
199 break;
200 }
201
202 case EXPORTFS: { /* export a file system */
203 error = nfs_export(arg);
204 break;
205 }
206
207 case NFS_GETFH: { /* get a file handle */
208 STRUCT_DECL(nfs_getfh_args, nga);
209
210 STRUCT_INIT(nga, get_udatamodel());
211 if (copyin(arg, STRUCT_BUF(nga), STRUCT_SIZE(nga)))
212 return (set_errno(EFAULT));
213
214 error = nfs_getfh(STRUCT_BUF(nga), get_udatamodel(), CRED());
215 break;
216 }
217
218 case NFS_REVAUTH: { /* revoke the cached credentials for the uid */
219 STRUCT_DECL(nfs_revauth_args, nra);
220
221 STRUCT_INIT(nra, get_udatamodel());
222 if (copyin(arg, STRUCT_BUF(nra), STRUCT_SIZE(nra)))
223 return (set_errno(EFAULT));
224
225 /* This call performs its own privilege checking */
226 error = sec_clnt_revoke(STRUCT_FGET(nra, authtype),
227 STRUCT_FGET(nra, uid), CRED(), NULL, get_udatamodel());
228 break;
229 }
230
231 case LM_SVC: { /* LM server daemon */
232 struct lm_svc_args lsa;
233
234 if (get_udatamodel() != DATAMODEL_NATIVE) {
235 STRUCT_DECL(lm_svc_args, ulsa);
236
237 STRUCT_INIT(ulsa, get_udatamodel());
238 if (copyin(arg, STRUCT_BUF(ulsa), STRUCT_SIZE(ulsa)))
239 return (set_errno(EFAULT));
240
241 lsa.version = STRUCT_FGET(ulsa, version);
242 lsa.fd = STRUCT_FGET(ulsa, fd);
243 lsa.n_fmly = STRUCT_FGET(ulsa, n_fmly);
244 lsa.n_proto = STRUCT_FGET(ulsa, n_proto);
245 lsa.n_rdev = expldev(STRUCT_FGET(ulsa, n_rdev));
246 lsa.n_v4_only = STRUCT_FGET(ulsa, n_v4_only);
247 lsa.timout = STRUCT_FGET(ulsa, timout);
248 lsa.grace = STRUCT_FGET(ulsa, grace);
249 lsa.retransmittimeout = STRUCT_FGET(ulsa,
250 retransmittimeout);
251 } else {
252 if (copyin(arg, &lsa, sizeof (lsa)))
253 return (set_errno(EFAULT));
254 }
255
256 error = lm_svc(&lsa);
257 break;
258 }
259
260 case KILL_LOCKMGR: {
261 error = lm_shutdown();
262 break;
263 }
264
265 case LOG_FLUSH: { /* Flush log buffer and possibly rename */
266 STRUCT_DECL(nfsl_flush_args, nfa);
267
268 STRUCT_INIT(nfa, get_udatamodel());
269 if (copyin(arg, STRUCT_BUF(nfa), STRUCT_SIZE(nfa)))
270 return (set_errno(EFAULT));
271
272 error = nfsl_flush(STRUCT_BUF(nfa), get_udatamodel());
273 break;
274 }
275
276 case NFS4_SVC: { /* NFS client callback daemon */
277
278 STRUCT_DECL(nfs4_svc_args, nsa);
279
280 STRUCT_INIT(nsa, get_udatamodel());
281
282 if (copyin(arg, STRUCT_BUF(nsa), STRUCT_SIZE(nsa)))
283 return (set_errno(EFAULT));
284
285 error = nfs4_svc(STRUCT_BUF(nsa), get_udatamodel());
286 break;
287 }
288
289 /* Request that NFSv4 server quiesce on next shutdown */
290 case NFS4_SVC_REQUEST_QUIESCE: {
291 int id;
292
293 /* check that nfssrv module is loaded */
294 if (nfs_srv_quiesce_func == NULL)
295 return (set_errno(ENOTSUP));
296
297 if (copyin(arg, &id, sizeof (id)))
298 return (set_errno(EFAULT));
299
300 error = svc_pool_control(id, SVCPSET_SHUTDOWN_PROC,
301 (void *)nfs_srv_quiesce_func);
302 break;
303 }
304
305 case NFS_IDMAP: {
306 struct nfsidmap_args idm;
307
308 if (copyin(arg, &idm, sizeof (idm)))
309 return (set_errno(EFAULT));
310
311 nfs_idmap_args(&idm);
312 error = 0;
313 break;
314 }
315
316 case NFS4_DSS_SETPATHS_SIZE: {
317 /* crosses ILP32/LP64 boundary */
318 uint32_t nfs4_dss_bufsize = 0;
319
320 if (copyin(arg, &nfs4_dss_bufsize, sizeof (nfs4_dss_bufsize)))
321 return (set_errno(EFAULT));
322 nfs4_dss_buflen = (long)nfs4_dss_bufsize;
323 error = 0;
324 break;
325 }
326
327 case NFS4_DSS_SETPATHS: {
328 char *nfs4_dss_bufp;
329
330 /* check that nfssrv module is loaded */
331 if (nfs_srv_dss_func == NULL)
332 return (set_errno(ENOTSUP));
333
334 /*
335 * NFS4_DSS_SETPATHS_SIZE must be called before
336 * NFS4_DSS_SETPATHS, to tell us how big a buffer we need
337 * to allocate.
338 */
339 if (nfs4_dss_buflen == 0)
340 return (set_errno(EINVAL));
341 nfs4_dss_bufp = kmem_alloc(nfs4_dss_buflen, KM_SLEEP);
342 if (nfs4_dss_bufp == NULL)
343 return (set_errno(ENOMEM));
344
345 if (copyin(arg, nfs4_dss_bufp, nfs4_dss_buflen)) {
346 kmem_free(nfs4_dss_bufp, nfs4_dss_buflen);
347 return (set_errno(EFAULT));
348 }
349
350 /* unpack the buffer and extract the pathnames */
351 error = nfs_srv_dss_func(nfs4_dss_bufp, nfs4_dss_buflen);
352 kmem_free(nfs4_dss_bufp, nfs4_dss_buflen);
353
354 break;
355 }
356
357 case NFS4_EPHEMERAL_MOUNT_TO: {
358 uint_t mount_to;
359
360 /*
361 * Not a very complicated call.
362 */
363 if (copyin(arg, &mount_to, sizeof (mount_to)))
364 return (set_errno(EFAULT));
365 nfs4_ephemeral_set_mount_to(mount_to);
366 error = 0;
367 break;
368 }
369
370 case MOUNTD_ARGS: {
371 uint_t did;
372
373 /*
374 * For now, only passing down the door fd; if we
375 * ever need to pass down more info, we can use
376 * a (properly aligned) struct.
377 */
378 if (copyin(arg, &did, sizeof (did)))
379 return (set_errno(EFAULT));
380 mountd_args(did);
381 error = 0;
382 break;
383 }
384
385 case NFSCMD_ARGS: {
386 uint_t did;
387
388 /*
389 * For now, only passing down the door fd; if we
390 * ever need to pass down more info, we can use
391 * a (properly aligned) struct.
392 */
393 if (copyin(arg, &did, sizeof (did)))
394 return (set_errno(EFAULT));
395 nfscmd_args(did);
396 error = 0;
397 break;
398 }
399
400 default:
401 error = EINVAL;
402 break;
403 }
404
405 return ((error != 0) ? set_errno(error) : 0);
406 }