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