xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_sys.c (revision fc910014e8a32a65612105835a10995f2c13d942)
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
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
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