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