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 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <sys/types.h> 32 #include <rpc/types.h> 33 #include <sys/systm.h> 34 #include <sys/vfs.h> 35 #include <sys/errno.h> 36 #include <sys/cred.h> 37 #include <sys/policy.h> 38 #include <sys/siginfo.h> 39 #include <sys/proc.h> /* for exit() declaration */ 40 #include <sys/kmem.h> 41 #include <nfs/nfs4.h> 42 #include <nfs/nfssys.h> 43 #include <sys/thread.h> 44 #include <rpc/auth.h> 45 #include <rpc/rpcsys.h> 46 #include <rpc/svc.h> 47 48 /* 49 * This is filled in with an appropriate address for the 50 * function that will traverse the rfs4_client_t table 51 * and mark any matching IP Address as "forced_expire". 52 * 53 * It is the server init() function that plops the 54 * function pointer. 55 */ 56 void (*rfs4_client_clrst)(struct nfs4clrst_args *) = NULL; 57 58 /* This filled in by nfssrv:_init() */ 59 void (*nfs_srv_quiesce_func)(void) = NULL; 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 default: 390 error = EINVAL; 391 break; 392 } 393 394 return ((error != 0) ? set_errno(error) : 0); 395 } 396