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