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