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