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 2006 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 79 int 80 nfssys(enum nfssys_op opcode, void *arg) 81 { 82 int error = 0; 83 84 if (!(opcode == NFS_REVAUTH || opcode == NFS4_SVC) && 85 secpolicy_nfs(CRED()) != 0) 86 return (set_errno(EPERM)); 87 88 switch (opcode) { 89 case NFS4_CLR_STATE: { /* Clear NFS4 client state */ 90 struct nfs4clrst_args clr; 91 STRUCT_DECL(nfs4clrst_args, u_clr); 92 93 /* 94 * If the server is not loaded then no point in 95 * clearing nothing :-) 96 */ 97 if (rfs4_client_clrst == NULL) { 98 break; 99 } 100 101 if (!INGLOBALZONE(curproc)) 102 return (set_errno(EPERM)); 103 104 STRUCT_INIT(u_clr, get_udatamodel()); 105 106 if (copyin(arg, STRUCT_BUF(u_clr), STRUCT_SIZE(u_clr))) 107 return (set_errno(EFAULT)); 108 109 clr.vers = STRUCT_FGET(u_clr, vers); 110 111 if (clr.vers != NFS4_CLRST_VERSION) 112 return (set_errno(EINVAL)); 113 114 clr.addr_type = STRUCT_FGET(u_clr, addr_type); 115 clr.ap = STRUCT_FGETP(u_clr, ap); 116 rfs4_client_clrst(&clr); 117 break; 118 } 119 120 case SVCPOOL_CREATE: { /* setup an RPC server thread pool */ 121 struct svcpool_args p; 122 123 if (copyin(arg, &p, sizeof (p))) 124 return (set_errno(EFAULT)); 125 126 error = svc_pool_create(&p); 127 break; 128 } 129 130 case SVCPOOL_WAIT: { /* wait in kernel for threads to be needed */ 131 int id; 132 133 if (copyin(arg, &id, sizeof (id))) 134 return (set_errno(EFAULT)); 135 136 error = svc_wait(id); 137 break; 138 } 139 140 case SVCPOOL_RUN: { /* give work to a runnable thread */ 141 int id; 142 143 if (copyin(arg, &id, sizeof (id))) 144 return (set_errno(EFAULT)); 145 146 error = svc_do_run(id); 147 break; 148 } 149 150 case RDMA_SVC_INIT: { 151 struct rdma_svc_args rsa; 152 char netstore[20] = "tcp"; 153 154 if (!INGLOBALZONE(curproc)) 155 return (set_errno(EPERM)); 156 if (get_udatamodel() != DATAMODEL_NATIVE) { 157 STRUCT_DECL(rdma_svc_args, ursa); 158 159 STRUCT_INIT(ursa, get_udatamodel()); 160 if (copyin(arg, STRUCT_BUF(ursa), STRUCT_SIZE(ursa))) 161 return (set_errno(EFAULT)); 162 163 rsa.poolid = STRUCT_FGET(ursa, poolid); 164 rsa.nfs_versmin = STRUCT_FGET(ursa, nfs_versmin); 165 rsa.nfs_versmax = STRUCT_FGET(ursa, nfs_versmax); 166 rsa.delegation = STRUCT_FGET(ursa, delegation); 167 } else { 168 if (copyin(arg, &rsa, sizeof (rsa))) 169 return (set_errno(EFAULT)); 170 } 171 rsa.netid = netstore; 172 173 error = rdma_start(&rsa); 174 break; 175 } 176 177 case NFS_SVC: { /* NFS server daemon */ 178 STRUCT_DECL(nfs_svc_args, nsa); 179 180 if (!INGLOBALZONE(curproc)) 181 return (set_errno(EPERM)); 182 STRUCT_INIT(nsa, get_udatamodel()); 183 184 if (copyin(arg, STRUCT_BUF(nsa), STRUCT_SIZE(nsa))) 185 return (set_errno(EFAULT)); 186 187 error = nfs_svc(STRUCT_BUF(nsa), get_udatamodel()); 188 break; 189 } 190 191 case EXPORTFS: { /* export a file system */ 192 STRUCT_DECL(exportfs_args, ea); 193 194 if (!INGLOBALZONE(curproc)) 195 return (set_errno(EPERM)); 196 STRUCT_INIT(ea, get_udatamodel()); 197 if (copyin(arg, STRUCT_BUF(ea), STRUCT_SIZE(ea))) 198 return (set_errno(EFAULT)); 199 200 error = exportfs(STRUCT_BUF(ea), get_udatamodel(), CRED()); 201 break; 202 } 203 204 case NFS_GETFH: { /* get a file handle */ 205 STRUCT_DECL(nfs_getfh_args, nga); 206 207 if (!INGLOBALZONE(curproc)) 208 return (set_errno(EPERM)); 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 default: 357 error = EINVAL; 358 break; 359 } 360 361 return ((error != 0) ? set_errno(error) : 0); 362 } 363