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