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