Home | History | Annotate | Download | only in nfs
      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