1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1610 thurlow * Common Development and Distribution License (the "License"). 6 1610 thurlow * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8695 Rajkumar * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* 27 0 stevel * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 28 0 stevel * All rights reserved. 29 0 stevel * Use is subject to license terms. 30 0 stevel */ 31 0 stevel 32 0 stevel #include <sys/param.h> 33 0 stevel #include <sys/types.h> 34 0 stevel #include <sys/systm.h> 35 0 stevel #include <sys/cred.h> 36 0 stevel #include <sys/proc.h> 37 0 stevel #include <sys/user.h> 38 0 stevel #include <sys/buf.h> 39 0 stevel #include <sys/vfs.h> 40 0 stevel #include <sys/vnode.h> 41 0 stevel #include <sys/pathname.h> 42 0 stevel #include <sys/uio.h> 43 0 stevel #include <sys/file.h> 44 0 stevel #include <sys/stat.h> 45 0 stevel #include <sys/errno.h> 46 0 stevel #include <sys/socket.h> 47 0 stevel #include <sys/sysmacros.h> 48 0 stevel #include <sys/siginfo.h> 49 0 stevel #include <sys/tiuser.h> 50 0 stevel #include <sys/statvfs.h> 51 0 stevel #include <sys/stream.h> 52 0 stevel #include <sys/strsubr.h> 53 0 stevel #include <sys/stropts.h> 54 0 stevel #include <sys/timod.h> 55 0 stevel #include <sys/t_kuser.h> 56 0 stevel #include <sys/kmem.h> 57 0 stevel #include <sys/kstat.h> 58 0 stevel #include <sys/dirent.h> 59 0 stevel #include <sys/cmn_err.h> 60 0 stevel #include <sys/debug.h> 61 0 stevel #include <sys/unistd.h> 62 0 stevel #include <sys/vtrace.h> 63 0 stevel #include <sys/mode.h> 64 0 stevel #include <sys/acl.h> 65 0 stevel #include <sys/sdt.h> 66 0 stevel 67 0 stevel #include <rpc/types.h> 68 0 stevel #include <rpc/auth.h> 69 0 stevel #include <rpc/auth_unix.h> 70 0 stevel #include <rpc/auth_des.h> 71 0 stevel #include <rpc/svc.h> 72 0 stevel #include <rpc/xdr.h> 73 8695 Rajkumar #include <rpc/rpc_rdma.h> 74 0 stevel 75 0 stevel #include <nfs/nfs.h> 76 0 stevel #include <nfs/export.h> 77 0 stevel #include <nfs/nfssys.h> 78 0 stevel #include <nfs/nfs_clnt.h> 79 0 stevel #include <nfs/nfs_acl.h> 80 0 stevel #include <nfs/nfs_log.h> 81 7961 Natalie #include <nfs/nfs_cmd.h> 82 0 stevel #include <nfs/lm.h> 83 74 rg137905 #include <nfs/nfs_dispatch.h> 84 74 rg137905 #include <nfs/nfs4_drc.h> 85 0 stevel 86 0 stevel #include <sys/modctl.h> 87 0 stevel #include <sys/cladm.h> 88 0 stevel #include <sys/clconf.h> 89 9871 Jarrett 90 9871 Jarrett #include <sys/tsol/label.h> 91 0 stevel 92 0 stevel #define MAXHOST 32 93 0 stevel const char *kinet_ntop6(uchar_t *, char *, size_t); 94 0 stevel 95 0 stevel /* 96 0 stevel * Module linkage information. 97 0 stevel */ 98 0 stevel 99 0 stevel static struct modlmisc modlmisc = { 100 0 stevel &mod_miscops, "NFS server module" 101 0 stevel }; 102 0 stevel 103 0 stevel static struct modlinkage modlinkage = { 104 0 stevel MODREV_1, (void *)&modlmisc, NULL 105 0 stevel }; 106 0 stevel 107 0 stevel char _depends_on[] = "misc/klmmod"; 108 2035 calum 109 0 stevel int 110 0 stevel _init(void) 111 0 stevel { 112 0 stevel int status; 113 0 stevel 114 0 stevel if ((status = nfs_srvinit()) != 0) { 115 0 stevel cmn_err(CE_WARN, "_init: nfs_srvinit failed"); 116 0 stevel return (status); 117 0 stevel } 118 0 stevel 119 0 stevel status = mod_install((struct modlinkage *)&modlinkage); 120 0 stevel if (status != 0) { 121 0 stevel /* 122 0 stevel * Could not load module, cleanup previous 123 0 stevel * initialization work. 124 0 stevel */ 125 0 stevel nfs_srvfini(); 126 0 stevel } 127 0 stevel 128 2035 calum /* 129 2035 calum * Initialise some placeholders for nfssys() calls. These have 130 2035 calum * to be declared by the nfs module, since that handles nfssys() 131 2035 calum * calls - also used by NFS clients - but are provided by this 132 2035 calum * nfssrv module. These also then serve as confirmation to the 133 2035 calum * relevant code in nfs that nfssrv has been loaded, as they're 134 2035 calum * initially NULL. 135 2035 calum */ 136 0 stevel nfs_srv_quiesce_func = nfs_srv_quiesce_all; 137 2035 calum nfs_srv_dss_func = rfs4_dss_setpaths; 138 2035 calum 139 2035 calum /* setup DSS paths here; must be done before initial server startup */ 140 2035 calum rfs4_dss_paths = rfs4_dss_oldpaths = NULL; 141 0 stevel 142 0 stevel return (status); 143 0 stevel } 144 0 stevel 145 0 stevel int 146 0 stevel _fini() 147 0 stevel { 148 0 stevel return (EBUSY); 149 0 stevel } 150 0 stevel 151 0 stevel int 152 0 stevel _info(struct modinfo *modinfop) 153 0 stevel { 154 0 stevel return (mod_info(&modlinkage, modinfop)); 155 0 stevel } 156 0 stevel 157 0 stevel /* 158 0 stevel * PUBLICFH_CHECK() checks if the dispatch routine supports 159 0 stevel * RPC_PUBLICFH_OK, if the filesystem is exported public, and if the 160 0 stevel * incoming request is using the public filehandle. The check duplicates 161 0 stevel * the exportmatch() call done in checkexport(), and we should consider 162 0 stevel * modifying those routines to avoid the duplication. For now, we optimize 163 0 stevel * by calling exportmatch() only after checking that the dispatch routine 164 0 stevel * supports RPC_PUBLICFH_OK, and if the filesystem is explicitly exported 165 0 stevel * public (i.e., not the placeholder). 166 0 stevel */ 167 1610 thurlow #define PUBLICFH_CHECK(disp, exi, fsid, xfid) \ 168 0 stevel ((disp->dis_flags & RPC_PUBLICFH_OK) && \ 169 0 stevel ((exi->exi_export.ex_flags & EX_PUBLIC) || \ 170 0 stevel (exi == exi_public && exportmatch(exi_root, \ 171 1610 thurlow fsid, xfid)))) 172 0 stevel 173 0 stevel static void nfs_srv_shutdown_all(int); 174 0 stevel static void rfs4_server_start(int); 175 0 stevel static void nullfree(void); 176 0 stevel static void rfs_dispatch(struct svc_req *, SVCXPRT *); 177 0 stevel static void acl_dispatch(struct svc_req *, SVCXPRT *); 178 0 stevel static void common_dispatch(struct svc_req *, SVCXPRT *, 179 0 stevel rpcvers_t, rpcvers_t, char *, 180 0 stevel struct rpc_disptable *); 181 2035 calum static void hanfsv4_failover(void); 182 0 stevel static int checkauth(struct exportinfo *, struct svc_req *, cred_t *, int, 183 0 stevel bool_t); 184 0 stevel static char *client_name(struct svc_req *req); 185 0 stevel static char *client_addr(struct svc_req *req, char *buf); 186 0 stevel extern int sec_svc_getcred(struct svc_req *, cred_t *cr, char **, int *); 187 0 stevel extern bool_t sec_svc_inrootlist(int, caddr_t, int, caddr_t *); 188 0 stevel 189 0 stevel #define NFSLOG_COPY_NETBUF(exi, xprt, nb) { \ 190 0 stevel (nb)->maxlen = (xprt)->xp_rtaddr.maxlen; \ 191 0 stevel (nb)->len = (xprt)->xp_rtaddr.len; \ 192 0 stevel (nb)->buf = kmem_alloc((nb)->len, KM_SLEEP); \ 193 0 stevel bcopy((xprt)->xp_rtaddr.buf, (nb)->buf, (nb)->len); \ 194 0 stevel } 195 0 stevel 196 0 stevel /* 197 0 stevel * Public Filehandle common nfs routines 198 0 stevel */ 199 0 stevel static int MCLpath(char **); 200 0 stevel static void URLparse(char *); 201 0 stevel 202 0 stevel /* 203 0 stevel * NFS callout table. 204 0 stevel * This table is used by svc_getreq() to dispatch a request with 205 0 stevel * a given prog/vers pair to an appropriate service provider 206 0 stevel * dispatch routine. 207 0 stevel * 208 0 stevel * NOTE: ordering is relied upon below when resetting the version min/max 209 0 stevel * for NFS_PROGRAM. Careful, if this is ever changed. 210 0 stevel */ 211 0 stevel static SVC_CALLOUT __nfs_sc_clts[] = { 212 0 stevel { NFS_PROGRAM, NFS_VERSMIN, NFS_VERSMAX, rfs_dispatch }, 213 0 stevel { NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, acl_dispatch } 214 0 stevel }; 215 0 stevel 216 0 stevel static SVC_CALLOUT_TABLE nfs_sct_clts = { 217 0 stevel sizeof (__nfs_sc_clts) / sizeof (__nfs_sc_clts[0]), FALSE, 218 0 stevel __nfs_sc_clts 219 0 stevel }; 220 0 stevel 221 0 stevel static SVC_CALLOUT __nfs_sc_cots[] = { 222 0 stevel { NFS_PROGRAM, NFS_VERSMIN, NFS_VERSMAX, rfs_dispatch }, 223 0 stevel { NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, acl_dispatch } 224 0 stevel }; 225 0 stevel 226 0 stevel static SVC_CALLOUT_TABLE nfs_sct_cots = { 227 0 stevel sizeof (__nfs_sc_cots) / sizeof (__nfs_sc_cots[0]), FALSE, __nfs_sc_cots 228 0 stevel }; 229 0 stevel 230 0 stevel static SVC_CALLOUT __nfs_sc_rdma[] = { 231 0 stevel { NFS_PROGRAM, NFS_VERSMIN, NFS_VERSMAX, rfs_dispatch }, 232 0 stevel { NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, acl_dispatch } 233 0 stevel }; 234 0 stevel 235 0 stevel static SVC_CALLOUT_TABLE nfs_sct_rdma = { 236 0 stevel sizeof (__nfs_sc_rdma) / sizeof (__nfs_sc_rdma[0]), FALSE, __nfs_sc_rdma 237 0 stevel }; 238 0 stevel rpcvers_t nfs_versmin = NFS_VERSMIN_DEFAULT; 239 0 stevel rpcvers_t nfs_versmax = NFS_VERSMAX_DEFAULT; 240 0 stevel 241 0 stevel /* 242 0 stevel * Used to track the state of the server so that initialization 243 0 stevel * can be done properly. 244 0 stevel */ 245 0 stevel typedef enum { 246 0 stevel NFS_SERVER_STOPPED, /* server state destroyed */ 247 0 stevel NFS_SERVER_STOPPING, /* server state being destroyed */ 248 0 stevel NFS_SERVER_RUNNING, 249 0 stevel NFS_SERVER_QUIESCED, /* server state preserved */ 250 0 stevel NFS_SERVER_OFFLINE /* server pool offline */ 251 0 stevel } nfs_server_running_t; 252 0 stevel 253 0 stevel static nfs_server_running_t nfs_server_upordown; 254 0 stevel static kmutex_t nfs_server_upordown_lock; 255 0 stevel static kcondvar_t nfs_server_upordown_cv; 256 0 stevel 257 2035 calum /* 258 2035 calum * DSS: distributed stable storage 259 2035 calum * lists of all DSS paths: current, and before last warmstart 260 2035 calum */ 261 2035 calum nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths; 262 2035 calum 263 74 rg137905 int rfs4_dispatch(struct rpcdisp *, struct svc_req *, SVCXPRT *, char *); 264 4635 maheshvs bool_t rfs4_minorvers_mismatch(struct svc_req *, SVCXPRT *, void *); 265 74 rg137905 266 0 stevel /* 267 0 stevel * RDMA wait variables. 268 0 stevel */ 269 0 stevel static kcondvar_t rdma_wait_cv; 270 0 stevel static kmutex_t rdma_wait_mutex; 271 0 stevel 272 0 stevel /* 273 0 stevel * Will be called at the point the server pool is being unregistered 274 0 stevel * from the pool list. From that point onwards, the pool is waiting 275 0 stevel * to be drained and as such the server state is stale and pertains 276 0 stevel * to the old instantiation of the NFS server pool. 277 0 stevel */ 278 0 stevel void 279 0 stevel nfs_srv_offline(void) 280 0 stevel { 281 0 stevel mutex_enter(&nfs_server_upordown_lock); 282 0 stevel if (nfs_server_upordown == NFS_SERVER_RUNNING) { 283 0 stevel nfs_server_upordown = NFS_SERVER_OFFLINE; 284 0 stevel } 285 0 stevel mutex_exit(&nfs_server_upordown_lock); 286 0 stevel } 287 0 stevel 288 0 stevel /* 289 0 stevel * Will be called at the point the server pool is being destroyed so 290 0 stevel * all transports have been closed and no service threads are in 291 0 stevel * existence. 292 0 stevel * 293 0 stevel * If we quiesce the server, we're shutting it down without destroying the 294 0 stevel * server state. This allows it to warm start subsequently. 295 0 stevel */ 296 0 stevel void 297 0 stevel nfs_srv_stop_all(void) 298 0 stevel { 299 0 stevel int quiesce = 0; 300 0 stevel nfs_srv_shutdown_all(quiesce); 301 0 stevel } 302 0 stevel 303 0 stevel /* 304 0 stevel * This alternative shutdown routine can be requested via nfssys() 305 0 stevel */ 306 0 stevel void 307 0 stevel nfs_srv_quiesce_all(void) 308 0 stevel { 309 0 stevel int quiesce = 1; 310 0 stevel nfs_srv_shutdown_all(quiesce); 311 0 stevel } 312 0 stevel 313 0 stevel static void 314 0 stevel nfs_srv_shutdown_all(int quiesce) { 315 0 stevel mutex_enter(&nfs_server_upordown_lock); 316 0 stevel if (quiesce) { 317 0 stevel if (nfs_server_upordown == NFS_SERVER_RUNNING || 318 0 stevel nfs_server_upordown == NFS_SERVER_OFFLINE) { 319 0 stevel nfs_server_upordown = NFS_SERVER_QUIESCED; 320 0 stevel cv_signal(&nfs_server_upordown_cv); 321 2035 calum 322 2035 calum /* reset DSS state, for subsequent warm restart */ 323 2035 calum rfs4_dss_numnewpaths = 0; 324 2035 calum rfs4_dss_newpaths = NULL; 325 2035 calum 326 0 stevel cmn_err(CE_NOTE, "nfs_server: server is now quiesced; " 327 0 stevel "NFSv4 state has been preserved"); 328 0 stevel } 329 0 stevel } else { 330 0 stevel if (nfs_server_upordown == NFS_SERVER_OFFLINE) { 331 0 stevel nfs_server_upordown = NFS_SERVER_STOPPING; 332 0 stevel mutex_exit(&nfs_server_upordown_lock); 333 0 stevel rfs4_state_fini(); 334 74 rg137905 rfs4_fini_drc(nfs4_drc); 335 0 stevel mutex_enter(&nfs_server_upordown_lock); 336 0 stevel nfs_server_upordown = NFS_SERVER_STOPPED; 337 0 stevel cv_signal(&nfs_server_upordown_cv); 338 0 stevel } 339 0 stevel } 340 0 stevel mutex_exit(&nfs_server_upordown_lock); 341 0 stevel } 342 0 stevel 343 0 stevel static int 344 0 stevel nfs_srv_set_sc_versions(struct file *fp, SVC_CALLOUT_TABLE **sctpp, 345 0 stevel rpcvers_t versmin, rpcvers_t versmax) 346 0 stevel { 347 0 stevel struct strioctl strioc; 348 0 stevel struct T_info_ack tinfo; 349 0 stevel int error, retval; 350 0 stevel 351 0 stevel /* 352 0 stevel * Find out what type of transport this is. 353 0 stevel */ 354 0 stevel strioc.ic_cmd = TI_GETINFO; 355 0 stevel strioc.ic_timout = -1; 356 0 stevel strioc.ic_len = sizeof (tinfo); 357 0 stevel strioc.ic_dp = (char *)&tinfo; 358 0 stevel tinfo.PRIM_type = T_INFO_REQ; 359 0 stevel 360 0 stevel error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K, 361 0 stevel CRED(), &retval); 362 0 stevel if (error || retval) 363 0 stevel return (error); 364 0 stevel 365 0 stevel /* 366 0 stevel * Based on our query of the transport type... 367 0 stevel * 368 0 stevel * Reset the min/max versions based on the caller's request 369 0 stevel * NOTE: This assumes that NFS_PROGRAM is first in the array!! 370 0 stevel * And the second entry is the NFS_ACL_PROGRAM. 371 0 stevel */ 372 0 stevel switch (tinfo.SERV_type) { 373 0 stevel case T_CLTS: 374 0 stevel if (versmax == NFS_V4) 375 0 stevel return (EINVAL); 376 0 stevel __nfs_sc_clts[0].sc_versmin = versmin; 377 0 stevel __nfs_sc_clts[0].sc_versmax = versmax; 378 0 stevel __nfs_sc_clts[1].sc_versmin = versmin; 379 0 stevel __nfs_sc_clts[1].sc_versmax = versmax; 380 0 stevel *sctpp = &nfs_sct_clts; 381 0 stevel break; 382 0 stevel case T_COTS: 383 0 stevel case T_COTS_ORD: 384 0 stevel __nfs_sc_cots[0].sc_versmin = versmin; 385 0 stevel __nfs_sc_cots[0].sc_versmax = versmax; 386 0 stevel /* For the NFS_ACL program, check the max version */ 387 0 stevel if (versmax > NFS_ACL_VERSMAX) 388 0 stevel versmax = NFS_ACL_VERSMAX; 389 0 stevel __nfs_sc_cots[1].sc_versmin = versmin; 390 0 stevel __nfs_sc_cots[1].sc_versmax = versmax; 391 0 stevel *sctpp = &nfs_sct_cots; 392 0 stevel break; 393 0 stevel default: 394 0 stevel error = EINVAL; 395 0 stevel } 396 0 stevel 397 0 stevel return (error); 398 0 stevel } 399 0 stevel 400 0 stevel /* 401 0 stevel * NFS Server system call. 402 0 stevel * Does all of the work of running a NFS server. 403 0 stevel * uap->fd is the fd of an open transport provider 404 0 stevel */ 405 0 stevel int 406 0 stevel nfs_svc(struct nfs_svc_args *arg, model_t model) 407 0 stevel { 408 0 stevel file_t *fp; 409 0 stevel SVCMASTERXPRT *xprt; 410 0 stevel int error; 411 0 stevel int readsize; 412 0 stevel char buf[KNC_STRSIZE]; 413 0 stevel size_t len; 414 0 stevel STRUCT_HANDLE(nfs_svc_args, uap); 415 0 stevel struct netbuf addrmask; 416 0 stevel SVC_CALLOUT_TABLE *sctp = NULL; 417 0 stevel 418 0 stevel #ifdef lint 419 0 stevel model = model; /* STRUCT macros don't always refer to it */ 420 0 stevel #endif 421 0 stevel 422 0 stevel STRUCT_SET_HANDLE(uap, model, arg); 423 0 stevel 424 0 stevel /* Check privileges in nfssys() */ 425 0 stevel 426 0 stevel if ((fp = getf(STRUCT_FGET(uap, fd))) == NULL) 427 0 stevel return (EBADF); 428 0 stevel 429 0 stevel /* 430 0 stevel * Set read buffer size to rsize 431 0 stevel * and add room for RPC headers. 432 0 stevel */ 433 0 stevel readsize = nfs3tsize() + (RPC_MAXDATASIZE - NFS_MAXDATA); 434 0 stevel if (readsize < RPC_MAXDATASIZE) 435 0 stevel readsize = RPC_MAXDATASIZE; 436 0 stevel 437 0 stevel error = copyinstr((const char *)STRUCT_FGETP(uap, netid), buf, 438 0 stevel KNC_STRSIZE, &len); 439 0 stevel if (error) { 440 0 stevel releasef(STRUCT_FGET(uap, fd)); 441 0 stevel return (error); 442 0 stevel } 443 0 stevel 444 0 stevel addrmask.len = STRUCT_FGET(uap, addrmask.len); 445 0 stevel addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen); 446 0 stevel addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP); 447 0 stevel error = copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf, 448 0 stevel addrmask.len); 449 0 stevel if (error) { 450 0 stevel releasef(STRUCT_FGET(uap, fd)); 451 0 stevel kmem_free(addrmask.buf, addrmask.maxlen); 452 0 stevel return (error); 453 0 stevel } 454 0 stevel 455 0 stevel nfs_versmin = STRUCT_FGET(uap, versmin); 456 0 stevel nfs_versmax = STRUCT_FGET(uap, versmax); 457 0 stevel 458 0 stevel /* Double check the vers min/max ranges */ 459 0 stevel if ((nfs_versmin > nfs_versmax) || 460 7961 Natalie (nfs_versmin < NFS_VERSMIN) || 461 7961 Natalie (nfs_versmax > NFS_VERSMAX)) { 462 0 stevel nfs_versmin = NFS_VERSMIN_DEFAULT; 463 0 stevel nfs_versmax = NFS_VERSMAX_DEFAULT; 464 0 stevel } 465 0 stevel 466 0 stevel if (error = 467 0 stevel nfs_srv_set_sc_versions(fp, &sctp, nfs_versmin, nfs_versmax)) { 468 0 stevel releasef(STRUCT_FGET(uap, fd)); 469 0 stevel kmem_free(addrmask.buf, addrmask.maxlen); 470 0 stevel return (error); 471 0 stevel } 472 0 stevel 473 0 stevel /* Initialize nfsv4 server */ 474 0 stevel if (nfs_versmax == (rpcvers_t)NFS_V4) 475 0 stevel rfs4_server_start(STRUCT_FGET(uap, delegation)); 476 0 stevel 477 0 stevel /* Create a transport handle. */ 478 0 stevel error = svc_tli_kcreate(fp, readsize, buf, &addrmask, &xprt, 479 7961 Natalie sctp, NULL, NFS_SVCPOOL_ID, TRUE); 480 0 stevel 481 0 stevel if (error) 482 0 stevel kmem_free(addrmask.buf, addrmask.maxlen); 483 0 stevel 484 0 stevel releasef(STRUCT_FGET(uap, fd)); 485 0 stevel 486 2035 calum /* HA-NFSv4: save the cluster nodeid */ 487 0 stevel if (cluster_bootflags & CLUSTER_BOOTED) 488 0 stevel lm_global_nlmid = clconf_get_nodeid(); 489 0 stevel 490 0 stevel return (error); 491 0 stevel } 492 0 stevel 493 0 stevel static void 494 0 stevel rfs4_server_start(int nfs4_srv_delegation) 495 0 stevel { 496 0 stevel /* 497 0 stevel * Determine if the server has previously been "started" and 498 0 stevel * if not, do the per instance initialization 499 0 stevel */ 500 0 stevel mutex_enter(&nfs_server_upordown_lock); 501 0 stevel 502 0 stevel if (nfs_server_upordown != NFS_SERVER_RUNNING) { 503 0 stevel /* Do we need to stop and wait on the previous server? */ 504 0 stevel while (nfs_server_upordown == NFS_SERVER_STOPPING || 505 7961 Natalie nfs_server_upordown == NFS_SERVER_OFFLINE) 506 0 stevel cv_wait(&nfs_server_upordown_cv, 507 0 stevel &nfs_server_upordown_lock); 508 0 stevel 509 0 stevel if (nfs_server_upordown != NFS_SERVER_RUNNING) { 510 0 stevel (void) svc_pool_control(NFS_SVCPOOL_ID, 511 0 stevel SVCPSET_UNREGISTER_PROC, (void *)&nfs_srv_offline); 512 0 stevel (void) svc_pool_control(NFS_SVCPOOL_ID, 513 0 stevel SVCPSET_SHUTDOWN_PROC, (void *)&nfs_srv_stop_all); 514 0 stevel 515 0 stevel /* is this an nfsd warm start? */ 516 0 stevel if (nfs_server_upordown == NFS_SERVER_QUIESCED) { 517 0 stevel cmn_err(CE_NOTE, "nfs_server: " 518 0 stevel "server was previously quiesced; " 519 0 stevel "existing NFSv4 state will be re-used"); 520 0 stevel 521 0 stevel /* 522 2035 calum * HA-NFSv4: this is also the signal 523 2035 calum * that a Resource Group failover has 524 2035 calum * occurred. 525 0 stevel */ 526 2390 calum if (cluster_bootflags & CLUSTER_BOOTED) 527 2035 calum hanfsv4_failover(); 528 0 stevel } else { 529 2035 calum /* cold start */ 530 0 stevel rfs4_state_init(); 531 74 rg137905 nfs4_drc = rfs4_init_drc(nfs4_drc_max, 532 7961 Natalie nfs4_drc_hash); 533 0 stevel } 534 0 stevel 535 0 stevel /* 536 0 stevel * Check to see if delegation is to be 537 0 stevel * enabled at the server 538 0 stevel */ 539 0 stevel if (nfs4_srv_delegation != FALSE) 540 0 stevel rfs4_set_deleg_policy(SRV_NORMAL_DELEGATE); 541 0 stevel 542 0 stevel nfs_server_upordown = NFS_SERVER_RUNNING; 543 0 stevel } 544 0 stevel cv_signal(&nfs_server_upordown_cv); 545 0 stevel } 546 0 stevel mutex_exit(&nfs_server_upordown_lock); 547 0 stevel } 548 0 stevel 549 0 stevel /* 550 0 stevel * If RDMA device available, 551 0 stevel * start RDMA listener. 552 0 stevel */ 553 0 stevel int 554 0 stevel rdma_start(struct rdma_svc_args *rsa) 555 0 stevel { 556 0 stevel int error; 557 0 stevel rdma_xprt_group_t started_rdma_xprts; 558 8695 Rajkumar rdma_stat stat; 559 8695 Rajkumar int svc_state = 0; 560 0 stevel 561 0 stevel /* Double check the vers min/max ranges */ 562 0 stevel if ((rsa->nfs_versmin > rsa->nfs_versmax) || 563 7961 Natalie (rsa->nfs_versmin < NFS_VERSMIN) || 564 7961 Natalie (rsa->nfs_versmax > NFS_VERSMAX)) { 565 0 stevel rsa->nfs_versmin = NFS_VERSMIN_DEFAULT; 566 0 stevel rsa->nfs_versmax = NFS_VERSMAX_DEFAULT; 567 0 stevel } 568 0 stevel nfs_versmin = rsa->nfs_versmin; 569 0 stevel nfs_versmax = rsa->nfs_versmax; 570 0 stevel 571 0 stevel /* Set the versions in the callout table */ 572 0 stevel __nfs_sc_rdma[0].sc_versmin = rsa->nfs_versmin; 573 0 stevel __nfs_sc_rdma[0].sc_versmax = rsa->nfs_versmax; 574 0 stevel /* For the NFS_ACL program, check the max version */ 575 0 stevel __nfs_sc_rdma[1].sc_versmin = rsa->nfs_versmin; 576 0 stevel if (rsa->nfs_versmax > NFS_ACL_VERSMAX) 577 0 stevel __nfs_sc_rdma[1].sc_versmax = NFS_ACL_VERSMAX; 578 0 stevel else 579 0 stevel __nfs_sc_rdma[1].sc_versmax = rsa->nfs_versmax; 580 0 stevel 581 0 stevel /* Initialize nfsv4 server */ 582 0 stevel if (rsa->nfs_versmax == (rpcvers_t)NFS_V4) 583 0 stevel rfs4_server_start(rsa->delegation); 584 0 stevel 585 0 stevel started_rdma_xprts.rtg_count = 0; 586 0 stevel started_rdma_xprts.rtg_listhead = NULL; 587 0 stevel started_rdma_xprts.rtg_poolid = rsa->poolid; 588 8695 Rajkumar 589 8695 Rajkumar restart: 590 0 stevel error = svc_rdma_kcreate(rsa->netid, &nfs_sct_rdma, rsa->poolid, 591 0 stevel &started_rdma_xprts); 592 0 stevel 593 8695 Rajkumar svc_state = !error; 594 8695 Rajkumar 595 8695 Rajkumar while (!error) { 596 8695 Rajkumar 597 8695 Rajkumar /* 598 8695 Rajkumar * wait till either interrupted by a signal on 599 8695 Rajkumar * nfs service stop/restart or signalled by a 600 8695 Rajkumar * rdma plugin attach/detatch. 601 8695 Rajkumar */ 602 8695 Rajkumar 603 8695 Rajkumar stat = rdma_kwait(); 604 8695 Rajkumar 605 8695 Rajkumar /* 606 8695 Rajkumar * stop services if running -- either on a HCA detach event 607 8695 Rajkumar * or if the nfs service is stopped/restarted. 608 8695 Rajkumar */ 609 8695 Rajkumar 610 8695 Rajkumar if ((stat == RDMA_HCA_DETACH || stat == RDMA_INTR) && 611 8695 Rajkumar svc_state) { 612 8695 Rajkumar rdma_stop(&started_rdma_xprts); 613 8695 Rajkumar svc_state = 0; 614 0 stevel } 615 8695 Rajkumar 616 8695 Rajkumar /* 617 8695 Rajkumar * nfs service stop/restart, break out of the 618 8695 Rajkumar * wait loop and return; 619 8695 Rajkumar */ 620 8695 Rajkumar if (stat == RDMA_INTR) 621 8695 Rajkumar return (0); 622 8695 Rajkumar 623 8695 Rajkumar /* 624 8695 Rajkumar * restart stopped services on a HCA attach event 625 8695 Rajkumar * (if not already running) 626 8695 Rajkumar */ 627 8695 Rajkumar 628 8695 Rajkumar if ((stat == RDMA_HCA_ATTACH) && (svc_state == 0)) 629 8695 Rajkumar goto restart; 630 8695 Rajkumar 631 8695 Rajkumar /* 632 8695 Rajkumar * loop until a nfs service stop/restart 633 8695 Rajkumar */ 634 0 stevel } 635 0 stevel 636 0 stevel return (error); 637 0 stevel } 638 0 stevel 639 0 stevel /* ARGSUSED */ 640 74 rg137905 void 641 0 stevel rpc_null(caddr_t *argp, caddr_t *resp) 642 0 stevel { 643 0 stevel } 644 0 stevel 645 0 stevel /* ARGSUSED */ 646 5982 ahl void 647 5982 ahl rpc_null_v3(caddr_t *argp, caddr_t *resp, struct exportinfo *exi, 648 5982 ahl struct svc_req *req, cred_t *cr) 649 5982 ahl { 650 5982 ahl DTRACE_NFSV3_3(op__null__start, struct svc_req *, req, 651 5982 ahl cred_t *, cr, vnode_t *, NULL); 652 5982 ahl DTRACE_NFSV3_3(op__null__done, struct svc_req *, req, 653 5982 ahl cred_t *, cr, vnode_t *, NULL); 654 5982 ahl } 655 5982 ahl 656 5982 ahl /* ARGSUSED */ 657 0 stevel static void 658 0 stevel rfs_error(caddr_t *argp, caddr_t *resp) 659 0 stevel { 660 0 stevel /* return (EOPNOTSUPP); */ 661 0 stevel } 662 0 stevel 663 0 stevel static void 664 0 stevel nullfree(void) 665 0 stevel { 666 0 stevel } 667 0 stevel 668 0 stevel static char *rfscallnames_v2[] = { 669 0 stevel "RFS2_NULL", 670 0 stevel "RFS2_GETATTR", 671 0 stevel "RFS2_SETATTR", 672 0 stevel "RFS2_ROOT", 673 0 stevel "RFS2_LOOKUP", 674 0 stevel "RFS2_READLINK", 675 0 stevel "RFS2_READ", 676 0 stevel "RFS2_WRITECACHE", 677 0 stevel "RFS2_WRITE", 678 0 stevel "RFS2_CREATE", 679 0 stevel "RFS2_REMOVE", 680 0 stevel "RFS2_RENAME", 681 0 stevel "RFS2_LINK", 682 0 stevel "RFS2_SYMLINK", 683 0 stevel "RFS2_MKDIR", 684 0 stevel "RFS2_RMDIR", 685 0 stevel "RFS2_READDIR", 686 0 stevel "RFS2_STATFS" 687 0 stevel }; 688 0 stevel 689 0 stevel static struct rpcdisp rfsdisptab_v2[] = { 690 0 stevel /* 691 0 stevel * NFS VERSION 2 692 0 stevel */ 693 0 stevel 694 0 stevel /* RFS_NULL = 0 */ 695 0 stevel {rpc_null, 696 0 stevel xdr_void, NULL_xdrproc_t, 0, 697 0 stevel xdr_void, NULL_xdrproc_t, 0, 698 0 stevel nullfree, RPC_IDEMPOTENT, 699 74 rg137905 0}, 700 0 stevel 701 0 stevel /* RFS_GETATTR = 1 */ 702 0 stevel {rfs_getattr, 703 0 stevel xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t), 704 0 stevel xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat), 705 0 stevel nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP, 706 74 rg137905 rfs_getattr_getfh}, 707 0 stevel 708 0 stevel /* RFS_SETATTR = 2 */ 709 0 stevel {rfs_setattr, 710 0 stevel xdr_saargs, NULL_xdrproc_t, sizeof (struct nfssaargs), 711 0 stevel xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat), 712 0 stevel nullfree, RPC_MAPRESP, 713 74 rg137905 rfs_setattr_getfh}, 714 0 stevel 715 0 stevel /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */ 716 0 stevel {rfs_error, 717 0 stevel xdr_void, NULL_xdrproc_t, 0, 718 0 stevel xdr_void, NULL_xdrproc_t, 0, 719 0 stevel nullfree, RPC_IDEMPOTENT, 720 74 rg137905 0}, 721 0 stevel 722 0 stevel /* RFS_LOOKUP = 4 */ 723 0 stevel {rfs_lookup, 724 0 stevel xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs), 725 0 stevel xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres), 726 0 stevel nullfree, RPC_IDEMPOTENT|RPC_MAPRESP|RPC_PUBLICFH_OK, 727 74 rg137905 rfs_lookup_getfh}, 728 0 stevel 729 0 stevel /* RFS_READLINK = 5 */ 730 0 stevel {rfs_readlink, 731 0 stevel xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t), 732 0 stevel xdr_rdlnres, NULL_xdrproc_t, sizeof (struct nfsrdlnres), 733 0 stevel rfs_rlfree, RPC_IDEMPOTENT, 734 74 rg137905 rfs_readlink_getfh}, 735 0 stevel 736 0 stevel /* RFS_READ = 6 */ 737 0 stevel {rfs_read, 738 0 stevel xdr_readargs, NULL_xdrproc_t, sizeof (struct nfsreadargs), 739 0 stevel xdr_rdresult, NULL_xdrproc_t, sizeof (struct nfsrdresult), 740 0 stevel rfs_rdfree, RPC_IDEMPOTENT, 741 74 rg137905 rfs_read_getfh}, 742 0 stevel 743 0 stevel /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */ 744 0 stevel {rfs_error, 745 0 stevel xdr_void, NULL_xdrproc_t, 0, 746 0 stevel xdr_void, NULL_xdrproc_t, 0, 747 0 stevel nullfree, RPC_IDEMPOTENT, 748 74 rg137905 0}, 749 0 stevel 750 0 stevel /* RFS_WRITE = 8 */ 751 0 stevel {rfs_write, 752 0 stevel xdr_writeargs, NULL_xdrproc_t, sizeof (struct nfswriteargs), 753 0 stevel xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat), 754 0 stevel nullfree, RPC_MAPRESP, 755 74 rg137905 rfs_write_getfh}, 756 0 stevel 757 0 stevel /* RFS_CREATE = 9 */ 758 0 stevel {rfs_create, 759 0 stevel xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs), 760 0 stevel xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres), 761 0 stevel nullfree, RPC_MAPRESP, 762 74 rg137905 rfs_create_getfh}, 763 0 stevel 764 0 stevel /* RFS_REMOVE = 10 */ 765 0 stevel {rfs_remove, 766 0 stevel xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs), 767 0 stevel #ifdef _LITTLE_ENDIAN 768 0 stevel xdr_enum, xdr_fastenum, sizeof (enum nfsstat), 769 0 stevel #else 770 0 stevel xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat), 771 0 stevel #endif 772 0 stevel nullfree, RPC_MAPRESP, 773 74 rg137905 rfs_remove_getfh}, 774 0 stevel 775 0 stevel /* RFS_RENAME = 11 */ 776 0 stevel {rfs_rename, 777 0 stevel xdr_rnmargs, NULL_xdrproc_t, sizeof (struct nfsrnmargs), 778 0 stevel #ifdef _LITTLE_ENDIAN 779 0 stevel xdr_enum, xdr_fastenum, sizeof (enum nfsstat), 780 0 stevel #else 781 0 stevel xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat), 782 0 stevel #endif 783 0 stevel nullfree, RPC_MAPRESP, 784 74 rg137905 rfs_rename_getfh}, 785 0 stevel 786 0 stevel /* RFS_LINK = 12 */ 787 0 stevel {rfs_link, 788 0 stevel xdr_linkargs, NULL_xdrproc_t, sizeof (struct nfslinkargs), 789 0 stevel #ifdef _LITTLE_ENDIAN 790 0 stevel xdr_enum, xdr_fastenum, sizeof (enum nfsstat), 791 0 stevel #else 792 0 stevel xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat), 793 0 stevel #endif 794 0 stevel nullfree, RPC_MAPRESP, 795 74 rg137905 rfs_link_getfh}, 796 0 stevel 797 0 stevel /* RFS_SYMLINK = 13 */ 798 0 stevel {rfs_symlink, 799 0 stevel xdr_slargs, NULL_xdrproc_t, sizeof (struct nfsslargs), 800 0 stevel #ifdef _LITTLE_ENDIAN 801 0 stevel xdr_enum, xdr_fastenum, sizeof (enum nfsstat), 802 0 stevel #else 803 0 stevel xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat), 804 0 stevel #endif 805 0 stevel nullfree, RPC_MAPRESP, 806 74 rg137905 rfs_symlink_getfh}, 807 0 stevel 808 0 stevel /* RFS_MKDIR = 14 */ 809 0 stevel {rfs_mkdir, 810 0 stevel xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs), 811 0 stevel xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres), 812 0 stevel nullfree, RPC_MAPRESP, 813 74 rg137905 rfs_mkdir_getfh}, 814 0 stevel 815 0 stevel /* RFS_RMDIR = 15 */ 816 0 stevel {rfs_rmdir, 817 0 stevel xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs), 818 0 stevel #ifdef _LITTLE_ENDIAN 819 0 stevel xdr_enum, xdr_fastenum, sizeof (enum nfsstat), 820 0 stevel #else 821 0 stevel xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat), 822 0 stevel #endif 823 0 stevel nullfree, RPC_MAPRESP, 824 74 rg137905 rfs_rmdir_getfh}, 825 0 stevel 826 0 stevel /* RFS_READDIR = 16 */ 827 0 stevel {rfs_readdir, 828 0 stevel xdr_rddirargs, NULL_xdrproc_t, sizeof (struct nfsrddirargs), 829 0 stevel xdr_putrddirres, NULL_xdrproc_t, sizeof (struct nfsrddirres), 830 0 stevel rfs_rddirfree, RPC_IDEMPOTENT, 831 74 rg137905 rfs_readdir_getfh}, 832 0 stevel 833 0 stevel /* RFS_STATFS = 17 */ 834 0 stevel {rfs_statfs, 835 0 stevel xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t), 836 0 stevel xdr_statfs, xdr_faststatfs, sizeof (struct nfsstatfs), 837 0 stevel nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP, 838 74 rg137905 rfs_statfs_getfh}, 839 0 stevel }; 840 0 stevel 841 0 stevel static char *rfscallnames_v3[] = { 842 0 stevel "RFS3_NULL", 843 0 stevel "RFS3_GETATTR", 844 0 stevel "RFS3_SETATTR", 845 0 stevel "RFS3_LOOKUP", 846 0 stevel "RFS3_ACCESS", 847 0 stevel "RFS3_READLINK", 848 0 stevel "RFS3_READ", 849 0 stevel "RFS3_WRITE", 850 0 stevel "RFS3_CREATE", 851 0 stevel "RFS3_MKDIR", 852 0 stevel "RFS3_SYMLINK", 853 0 stevel "RFS3_MKNOD", 854 0 stevel "RFS3_REMOVE", 855 0 stevel "RFS3_RMDIR", 856 0 stevel "RFS3_RENAME", 857 0 stevel "RFS3_LINK", 858 0 stevel "RFS3_READDIR", 859 0 stevel "RFS3_READDIRPLUS", 860 0 stevel "RFS3_FSSTAT", 861 0 stevel "RFS3_FSINFO", 862 0 stevel "RFS3_PATHCONF", 863 0 stevel "RFS3_COMMIT" 864 0 stevel }; 865 0 stevel 866 0 stevel static struct rpcdisp rfsdisptab_v3[] = { 867 0 stevel /* 868 0 stevel * NFS VERSION 3 869 0 stevel */ 870 0 stevel 871 0 stevel /* RFS_NULL = 0 */ 872 5982 ahl {rpc_null_v3, 873 0 stevel xdr_void, NULL_xdrproc_t, 0, 874 0 stevel xdr_void, NULL_xdrproc_t, 0, 875 0 stevel nullfree, RPC_IDEMPOTENT, 876 74 rg137905 0}, 877 0 stevel 878 0 stevel /* RFS3_GETATTR = 1 */ 879 0 stevel {rfs3_getattr, 880 1610 thurlow xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (GETATTR3args), 881 0 stevel xdr_GETATTR3res, NULL_xdrproc_t, sizeof (GETATTR3res), 882 0 stevel nullfree, (RPC_IDEMPOTENT | RPC_ALLOWANON), 883 74 rg137905 rfs3_getattr_getfh}, 884 0 stevel 885 0 stevel /* RFS3_SETATTR = 2 */ 886 0 stevel {rfs3_setattr, 887 0 stevel xdr_SETATTR3args, NULL_xdrproc_t, sizeof (SETATTR3args), 888 0 stevel xdr_SETATTR3res, NULL_xdrproc_t, sizeof (SETATTR3res), 889 0 stevel nullfree, 0, 890 74 rg137905 rfs3_setattr_getfh}, 891 0 stevel 892 0 stevel /* RFS3_LOOKUP = 3 */ 893 0 stevel {rfs3_lookup, 894 0 stevel xdr_diropargs3, NULL_xdrproc_t, sizeof (LOOKUP3args), 895 0 stevel xdr_LOOKUP3res, NULL_xdrproc_t, sizeof (LOOKUP3res), 896 0 stevel nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK), 897 74 rg137905 rfs3_lookup_getfh}, 898 0 stevel 899 0 stevel /* RFS3_ACCESS = 4 */ 900 0 stevel {rfs3_access, 901 0 stevel xdr_ACCESS3args, NULL_xdrproc_t, sizeof (ACCESS3args), 902 0 stevel xdr_ACCESS3res, NULL_xdrproc_t, sizeof (ACCESS3res), 903 0 stevel nullfree, RPC_IDEMPOTENT, 904 74 rg137905 rfs3_access_getfh}, 905 0 stevel 906 0 stevel /* RFS3_READLINK = 5 */ 907 0 stevel {rfs3_readlink, 908 1610 thurlow xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (READLINK3args), 909 0 stevel xdr_READLINK3res, NULL_xdrproc_t, sizeof (READLINK3res), 910 0 stevel rfs3_readlink_free, RPC_IDEMPOTENT, 911 74 rg137905 rfs3_readlink_getfh}, 912 0 stevel 913 0 stevel /* RFS3_READ = 6 */ 914 0 stevel {rfs3_read, 915 0 stevel xdr_READ3args, NULL_xdrproc_t, sizeof (READ3args), 916 0 stevel xdr_READ3res, NULL_xdrproc_t, sizeof (READ3res), 917 0 stevel rfs3_read_free, RPC_IDEMPOTENT, 918 74 rg137905 rfs3_read_getfh}, 919 0 stevel 920 0 stevel /* RFS3_WRITE = 7 */ 921 0 stevel {rfs3_write, 922 0 stevel xdr_WRITE3args, NULL_xdrproc_t, sizeof (WRITE3args), 923 0 stevel xdr_WRITE3res, NULL_xdrproc_t, sizeof (WRITE3res), 924 0 stevel nullfree, 0, 925 74 rg137905 rfs3_write_getfh}, 926 0 stevel 927 0 stevel /* RFS3_CREATE = 8 */ 928 0 stevel {rfs3_create, 929 0 stevel xdr_CREATE3args, NULL_xdrproc_t, sizeof (CREATE3args), 930 0 stevel xdr_CREATE3res, NULL_xdrproc_t, sizeof (CREATE3res), 931 0 stevel nullfree, 0, 932 74 rg137905 rfs3_create_getfh}, 933 0 stevel 934 0 stevel /* RFS3_MKDIR = 9 */ 935 0 stevel {rfs3_mkdir, 936 0 stevel xdr_MKDIR3args, NULL_xdrproc_t, sizeof (MKDIR3args), 937 0 stevel xdr_MKDIR3res, NULL_xdrproc_t, sizeof (MKDIR3res), 938 0 stevel nullfree, 0, 939 74 rg137905 rfs3_mkdir_getfh}, 940 0 stevel 941 0 stevel /* RFS3_SYMLINK = 10 */ 942 0 stevel {rfs3_symlink, 943 0 stevel xdr_SYMLINK3args, NULL_xdrproc_t, sizeof (SYMLINK3args), 944 0 stevel xdr_SYMLINK3res, NULL_xdrproc_t, sizeof (SYMLINK3res), 945 0 stevel nullfree, 0, 946 74 rg137905 rfs3_symlink_getfh}, 947 0 stevel 948 0 stevel /* RFS3_MKNOD = 11 */ 949 0 stevel {rfs3_mknod, 950 0 stevel xdr_MKNOD3args, NULL_xdrproc_t, sizeof (MKNOD3args), 951 0 stevel xdr_MKNOD3res, NULL_xdrproc_t, sizeof (MKNOD3res), 952 0 stevel nullfree, 0, 953 74 rg137905 rfs3_mknod_getfh}, 954 0 stevel 955 0 stevel /* RFS3_REMOVE = 12 */ 956 0 stevel {rfs3_remove, 957 0 stevel xdr_diropargs3, NULL_xdrproc_t, sizeof (REMOVE3args), 958 0 stevel xdr_REMOVE3res, NULL_xdrproc_t, sizeof (REMOVE3res), 959 0 stevel nullfree, 0, 960 74 rg137905 rfs3_remove_getfh}, 961 0 stevel 962 0 stevel /* RFS3_RMDIR = 13 */ 963 0 stevel {rfs3_rmdir, 964 0 stevel xdr_diropargs3, NULL_xdrproc_t, sizeof (RMDIR3args), 965 0 stevel xdr_RMDIR3res, NULL_xdrproc_t, sizeof (RMDIR3res), 966 0 stevel nullfree, 0, 967 74 rg137905 rfs3_rmdir_getfh}, 968 0 stevel 969 0 stevel /* RFS3_RENAME = 14 */ 970 0 stevel {rfs3_rename, 971 0 stevel xdr_RENAME3args, NULL_xdrproc_t, sizeof (RENAME3args), 972 0 stevel xdr_RENAME3res, NULL_xdrproc_t, sizeof (RENAME3res), 973 0 stevel nullfree, 0, 974 74 rg137905 rfs3_rename_getfh}, 975 0 stevel 976 0 stevel /* RFS3_LINK = 15 */ 977 0 stevel {rfs3_link, 978 0 stevel xdr_LINK3args, NULL_xdrproc_t, sizeof (LINK3args), 979 0 stevel xdr_LINK3res, NULL_xdrproc_t, sizeof (LINK3res), 980 0 stevel nullfree, 0, 981 74 rg137905 rfs3_link_getfh}, 982 0 stevel 983 0 stevel /* RFS3_READDIR = 16 */ 984 0 stevel {rfs3_readdir, 985 0 stevel xdr_READDIR3args, NULL_xdrproc_t, sizeof (READDIR3args), 986 0 stevel xdr_READDIR3res, NULL_xdrproc_t, sizeof (READDIR3res), 987 0 stevel rfs3_readdir_free, RPC_IDEMPOTENT, 988 74 rg137905 rfs3_readdir_getfh}, 989 0 stevel 990 0 stevel /* RFS3_READDIRPLUS = 17 */ 991 0 stevel {rfs3_readdirplus, 992 0 stevel xdr_READDIRPLUS3args, NULL_xdrproc_t, sizeof (READDIRPLUS3args), 993 0 stevel xdr_READDIRPLUS3res, NULL_xdrproc_t, sizeof (READDIRPLUS3res), 994 0 stevel rfs3_readdirplus_free, RPC_AVOIDWORK, 995 74 rg137905 rfs3_readdirplus_getfh}, 996 0 stevel 997 0 stevel /* RFS3_FSSTAT = 18 */ 998 0 stevel {rfs3_fsstat, 999 1610 thurlow xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSSTAT3args), 1000 0 stevel xdr_FSSTAT3res, NULL_xdrproc_t, sizeof (FSSTAT3res), 1001 0 stevel nullfree, RPC_IDEMPOTENT, 1002 74 rg137905 rfs3_fsstat_getfh}, 1003 0 stevel 1004 0 stevel /* RFS3_FSINFO = 19 */ 1005 0 stevel {rfs3_fsinfo, 1006 1610 thurlow xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSINFO3args), 1007 0 stevel xdr_FSINFO3res, NULL_xdrproc_t, sizeof (FSINFO3res), 1008 0 stevel nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON, 1009 74 rg137905 rfs3_fsinfo_getfh}, 1010 0 stevel 1011 0 stevel /* RFS3_PATHCONF = 20 */ 1012 0 stevel {rfs3_pathconf, 1013 1610 thurlow xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (PATHCONF3args), 1014 0 stevel xdr_PATHCONF3res, NULL_xdrproc_t, sizeof (PATHCONF3res), 1015 0 stevel nullfree, RPC_IDEMPOTENT, 1016 74 rg137905 rfs3_pathconf_getfh}, 1017 0 stevel 1018 0 stevel /* RFS3_COMMIT = 21 */ 1019 0 stevel {rfs3_commit, 1020 0 stevel xdr_COMMIT3args, NULL_xdrproc_t, sizeof (COMMIT3args), 1021 0 stevel xdr_COMMIT3res, NULL_xdrproc_t, sizeof (COMMIT3res), 1022 0 stevel nullfree, RPC_IDEMPOTENT, 1023 74 rg137905 rfs3_commit_getfh}, 1024 0 stevel }; 1025 0 stevel 1026 0 stevel static char *rfscallnames_v4[] = { 1027 0 stevel "RFS4_NULL", 1028 0 stevel "RFS4_COMPOUND", 1029 0 stevel "RFS4_NULL", 1030 0 stevel "RFS4_NULL", 1031 0 stevel "RFS4_NULL", 1032 0 stevel "RFS4_NULL", 1033 0 stevel "RFS4_NULL", 1034 0 stevel "RFS4_NULL", 1035 0 stevel "RFS4_CREATE" 1036 0 stevel }; 1037 0 stevel 1038 0 stevel static struct rpcdisp rfsdisptab_v4[] = { 1039 0 stevel /* 1040 0 stevel * NFS VERSION 4 1041 0 stevel */ 1042 0 stevel 1043 0 stevel /* RFS_NULL = 0 */ 1044 0 stevel {rpc_null, 1045 0 stevel xdr_void, NULL_xdrproc_t, 0, 1046 0 stevel xdr_void, NULL_xdrproc_t, 0, 1047 74 rg137905 nullfree, RPC_IDEMPOTENT, 0}, 1048 0 stevel 1049 0 stevel /* RFS4_compound = 1 */ 1050 0 stevel {rfs4_compound, 1051 806 ek110237 xdr_COMPOUND4args_srv, NULL_xdrproc_t, sizeof (COMPOUND4args), 1052 806 ek110237 xdr_COMPOUND4res_srv, NULL_xdrproc_t, sizeof (COMPOUND4res), 1053 74 rg137905 rfs4_compound_free, 0, 0}, 1054 0 stevel }; 1055 0 stevel 1056 0 stevel union rfs_args { 1057 0 stevel /* 1058 0 stevel * NFS VERSION 2 1059 0 stevel */ 1060 0 stevel 1061 0 stevel /* RFS_NULL = 0 */ 1062 0 stevel 1063 0 stevel /* RFS_GETATTR = 1 */ 1064 0 stevel fhandle_t nfs2_getattr_args; 1065 0 stevel 1066 0 stevel /* RFS_SETATTR = 2 */ 1067 0 stevel struct nfssaargs nfs2_setattr_args; 1068 0 stevel 1069 0 stevel /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */ 1070 0 stevel 1071 0 stevel /* RFS_LOOKUP = 4 */ 1072 0 stevel struct nfsdiropargs nfs2_lookup_args; 1073 0 stevel 1074 0 stevel /* RFS_READLINK = 5 */ 1075 0 stevel fhandle_t nfs2_readlink_args; 1076 0 stevel 1077 0 stevel /* RFS_READ = 6 */ 1078 0 stevel struct nfsreadargs nfs2_read_args; 1079 0 stevel 1080 0 stevel /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */ 1081 0 stevel 1082 0 stevel /* RFS_WRITE = 8 */ 1083 0 stevel struct nfswriteargs nfs2_write_args; 1084 0 stevel 1085 0 stevel /* RFS_CREATE = 9 */ 1086 0 stevel struct nfscreatargs nfs2_create_args; 1087 0 stevel 1088 0 stevel /* RFS_REMOVE = 10 */ 1089 0 stevel struct nfsdiropargs nfs2_remove_args; 1090 0 stevel 1091 0 stevel /* RFS_RENAME = 11 */ 1092 0 stevel struct nfsrnmargs nfs2_rename_args; 1093 0 stevel 1094 0 stevel /* RFS_LINK = 12 */ 1095 0 stevel struct nfslinkargs nfs2_link_args; 1096 0 stevel 1097 0 stevel /* RFS_SYMLINK = 13 */ 1098 0 stevel struct nfsslargs nfs2_symlink_args; 1099 0 stevel 1100 0 stevel /* RFS_MKDIR = 14 */ 1101 0 stevel struct nfscreatargs nfs2_mkdir_args; 1102 0 stevel 1103 0 stevel /* RFS_RMDIR = 15 */ 1104 0 stevel struct nfsdiropargs nfs2_rmdir_args; 1105 0 stevel 1106 0 stevel /* RFS_READDIR = 16 */ 1107 0 stevel struct nfsrddirargs nfs2_readdir_args; 1108 0 stevel 1109 0 stevel /* RFS_STATFS = 17 */ 1110 0 stevel fhandle_t nfs2_statfs_args; 1111 0 stevel 1112 0 stevel /* 1113 0 stevel * NFS VERSION 3 1114 0 stevel */ 1115 0 stevel 1116 0 stevel /* RFS_NULL = 0 */ 1117 0 stevel 1118 0 stevel /* RFS3_GETATTR = 1 */ 1119 0 stevel GETATTR3args nfs3_getattr_args; 1120 0 stevel 1121 0 stevel /* RFS3_SETATTR = 2 */ 1122 0 stevel SETATTR3args nfs3_setattr_args; 1123 0 stevel 1124 0 stevel /* RFS3_LOOKUP = 3 */ 1125 0 stevel LOOKUP3args nfs3_lookup_args; 1126 0 stevel 1127 0 stevel /* RFS3_ACCESS = 4 */ 1128 0 stevel ACCESS3args nfs3_access_args; 1129 0 stevel 1130 0 stevel /* RFS3_READLINK = 5 */ 1131 0 stevel READLINK3args nfs3_readlink_args; 1132 0 stevel 1133 0 stevel /* RFS3_READ = 6 */ 1134 0 stevel READ3args nfs3_read_args; 1135 0 stevel 1136 0 stevel /* RFS3_WRITE = 7 */ 1137 0 stevel WRITE3args nfs3_write_args; 1138 0 stevel 1139 0 stevel /* RFS3_CREATE = 8 */ 1140 0 stevel CREATE3args nfs3_create_args; 1141 0 stevel 1142 0 stevel /* RFS3_MKDIR = 9 */ 1143 0 stevel MKDIR3args nfs3_mkdir_args; 1144 0 stevel 1145 0 stevel /* RFS3_SYMLINK = 10 */ 1146 0 stevel SYMLINK3args nfs3_symlink_args; 1147 0 stevel 1148 0 stevel /* RFS3_MKNOD = 11 */ 1149 0 stevel MKNOD3args nfs3_mknod_args; 1150 0 stevel 1151 0 stevel /* RFS3_REMOVE = 12 */ 1152 0 stevel REMOVE3args nfs3_remove_args; 1153 0 stevel 1154 0 stevel /* RFS3_RMDIR = 13 */ 1155 0 stevel RMDIR3args nfs3_rmdir_args; 1156 0 stevel 1157 0 stevel /* RFS3_RENAME = 14 */ 1158 0 stevel RENAME3args nfs3_rename_args; 1159 0 stevel 1160 0 stevel /* RFS3_LINK = 15 */ 1161 0 stevel LINK3args nfs3_link_args; 1162 0 stevel 1163 0 stevel /* RFS3_READDIR = 16 */ 1164 0 stevel READDIR3args nfs3_readdir_args; 1165 0 stevel 1166 0 stevel /* RFS3_READDIRPLUS = 17 */ 1167 0 stevel READDIRPLUS3args nfs3_readdirplus_args; 1168 0 stevel 1169 0 stevel /* RFS3_FSSTAT = 18 */ 1170 0 stevel FSSTAT3args nfs3_fsstat_args; 1171 0 stevel 1172 0 stevel /* RFS3_FSINFO = 19 */ 1173 0 stevel FSINFO3args nfs3_fsinfo_args; 1174 0 stevel 1175 0 stevel /* RFS3_PATHCONF = 20 */ 1176 0 stevel PATHCONF3args nfs3_pathconf_args; 1177 0 stevel 1178 0 stevel /* RFS3_COMMIT = 21 */ 1179 0 stevel COMMIT3args nfs3_commit_args; 1180 0 stevel 1181 0 stevel /* 1182 0 stevel * NFS VERSION 4 1183 0 stevel */ 1184 0 stevel 1185 0 stevel /* RFS_NULL = 0 */ 1186 0 stevel 1187 0 stevel /* COMPUND = 1 */ 1188 0 stevel COMPOUND4args nfs4_compound_args; 1189 0 stevel }; 1190 0 stevel 1191 0 stevel union rfs_res { 1192 0 stevel /* 1193 0 stevel * NFS VERSION 2 1194 0 stevel */ 1195 0 stevel 1196 0 stevel /* RFS_NULL = 0 */ 1197 0 stevel 1198 0 stevel /* RFS_GETATTR = 1 */ 1199 0 stevel struct nfsattrstat nfs2_getattr_res; 1200 0 stevel 1201 0 stevel /* RFS_SETATTR = 2 */ 1202 0 stevel struct nfsattrstat nfs2_setattr_res; 1203 0 stevel 1204 0 stevel /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */ 1205 0 stevel 1206 0 stevel /* RFS_LOOKUP = 4 */ 1207 0 stevel struct nfsdiropres nfs2_lookup_res; 1208 0 stevel 1209 0 stevel /* RFS_READLINK = 5 */ 1210 0 stevel struct nfsrdlnres nfs2_readlink_res; 1211 0 stevel 1212 0 stevel /* RFS_READ = 6 */ 1213 0 stevel struct nfsrdresult nfs2_read_res; 1214 0 stevel 1215 0 stevel /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */ 1216 0 stevel 1217 0 stevel /* RFS_WRITE = 8 */ 1218 0 stevel struct nfsattrstat nfs2_write_res; 1219 0 stevel 1220 0 stevel /* RFS_CREATE = 9 */ 1221 0 stevel struct nfsdiropres nfs2_create_res; 1222 0 stevel 1223 0 stevel /* RFS_REMOVE = 10 */ 1224 0 stevel enum nfsstat nfs2_remove_res; 1225 0 stevel 1226 0 stevel /* RFS_RENAME = 11 */ 1227 0 stevel enum nfsstat nfs2_rename_res; 1228 0 stevel 1229 0 stevel /* RFS_LINK = 12 */ 1230 0 stevel enum nfsstat nfs2_link_res; 1231 0 stevel 1232 0 stevel /* RFS_SYMLINK = 13 */ 1233 0 stevel enum nfsstat nfs2_symlink_res; 1234 0 stevel 1235 0 stevel /* RFS_MKDIR = 14 */ 1236 0 stevel struct nfsdiropres nfs2_mkdir_res; 1237 0 stevel 1238 0 stevel /* RFS_RMDIR = 15 */ 1239 0 stevel enum nfsstat nfs2_rmdir_res; 1240 0 stevel 1241 0 stevel /* RFS_READDIR = 16 */ 1242 0 stevel struct nfsrddirres nfs2_readdir_res; 1243 0 stevel 1244 0 stevel /* RFS_STATFS = 17 */ 1245 0 stevel struct nfsstatfs nfs2_statfs_res; 1246 0 stevel 1247 0 stevel /* 1248 0 stevel * NFS VERSION 3 1249 0 stevel */ 1250 0 stevel 1251 0 stevel /* RFS_NULL = 0 */ 1252 0 stevel 1253 0 stevel /* RFS3_GETATTR = 1 */ 1254 0 stevel GETATTR3res nfs3_getattr_res; 1255 0 stevel 1256 0 stevel /* RFS3_SETATTR = 2 */ 1257 0 stevel SETATTR3res nfs3_setattr_res; 1258 0 stevel 1259 0 stevel /* RFS3_LOOKUP = 3 */ 1260 0 stevel LOOKUP3res nfs3_lookup_res; 1261 0 stevel 1262 0 stevel /* RFS3_ACCESS = 4 */ 1263 0 stevel ACCESS3res nfs3_access_res; 1264 0 stevel 1265 0 stevel /* RFS3_READLINK = 5 */ 1266 0 stevel READLINK3res nfs3_readlink_res; 1267 0 stevel 1268 0 stevel /* RFS3_READ = 6 */ 1269 0 stevel READ3res nfs3_read_res; 1270 0 stevel 1271 0 stevel /* RFS3_WRITE = 7 */ 1272 0 stevel WRITE3res nfs3_write_res; 1273 0 stevel 1274 0 stevel /* RFS3_CREATE = 8 */ 1275 0 stevel CREATE3res nfs3_create_res; 1276 0 stevel 1277 0 stevel /* RFS3_MKDIR = 9 */ 1278 0 stevel MKDIR3res nfs3_mkdir_res; 1279 0 stevel 1280 0 stevel /* RFS3_SYMLINK = 10 */ 1281 0 stevel SYMLINK3res nfs3_symlink_res; 1282 0 stevel 1283 0 stevel /* RFS3_MKNOD = 11 */ 1284 0 stevel MKNOD3res nfs3_mknod_res; 1285 0 stevel 1286 0 stevel /* RFS3_REMOVE = 12 */ 1287 0 stevel REMOVE3res nfs3_remove_res; 1288 0 stevel 1289 0 stevel /* RFS3_RMDIR = 13 */ 1290 0 stevel RMDIR3res nfs3_rmdir_res; 1291 0 stevel 1292 0 stevel /* RFS3_RENAME = 14 */ 1293 0 stevel RENAME3res nfs3_rename_res; 1294 0 stevel 1295 0 stevel /* RFS3_LINK = 15 */ 1296 0 stevel LINK3res nfs3_link_res; 1297 0 stevel 1298 0 stevel /* RFS3_READDIR = 16 */ 1299 0 stevel READDIR3res nfs3_readdir_res; 1300 0 stevel 1301 0 stevel /* RFS3_READDIRPLUS = 17 */ 1302 0 stevel READDIRPLUS3res nfs3_readdirplus_res; 1303 0 stevel 1304 0 stevel /* RFS3_FSSTAT = 18 */ 1305 0 stevel FSSTAT3res nfs3_fsstat_res; 1306 0 stevel 1307 0 stevel /* RFS3_FSINFO = 19 */ 1308 0 stevel FSINFO3res nfs3_fsinfo_res; 1309 0 stevel 1310 0 stevel /* RFS3_PATHCONF = 20 */ 1311 0 stevel PATHCONF3res nfs3_pathconf_res; 1312 0 stevel 1313 0 stevel /* RFS3_COMMIT = 21 */ 1314 0 stevel COMMIT3res nfs3_commit_res; 1315 0 stevel 1316 0 stevel /* 1317 0 stevel * NFS VERSION 4 1318 0 stevel */ 1319 0 stevel 1320 0 stevel /* RFS_NULL = 0 */ 1321 0 stevel 1322 0 stevel /* RFS4_COMPOUND = 1 */ 1323 0 stevel COMPOUND4res nfs4_compound_res; 1324 0 stevel 1325 0 stevel }; 1326 0 stevel 1327 0 stevel static struct rpc_disptable rfs_disptable[] = { 1328 0 stevel {sizeof (rfsdisptab_v2) / sizeof (rfsdisptab_v2[0]), 1329 0 stevel rfscallnames_v2, 1330 0 stevel &rfsproccnt_v2_ptr, rfsdisptab_v2}, 1331 0 stevel {sizeof (rfsdisptab_v3) / sizeof (rfsdisptab_v3[0]), 1332 0 stevel rfscallnames_v3, 1333 0 stevel &rfsproccnt_v3_ptr, rfsdisptab_v3}, 1334 0 stevel {sizeof (rfsdisptab_v4) / sizeof (rfsdisptab_v4[0]), 1335 0 stevel rfscallnames_v4, 1336 0 stevel &rfsproccnt_v4_ptr, rfsdisptab_v4}, 1337 0 stevel }; 1338 0 stevel 1339 0 stevel /* 1340 0 stevel * If nfs_portmon is set, then clients are required to use privileged 1341 0 stevel * ports (ports < IPPORT_RESERVED) in order to get NFS services. 1342 0 stevel * 1343 0 stevel * N.B.: this attempt to carry forward the already ill-conceived notion 1344 0 stevel * of privileged ports for TCP/UDP is really quite ineffectual. Not only 1345 0 stevel * is it transport-dependent, it's laughably easy to spoof. If you're 1346 0 stevel * really interested in security, you must start with secure RPC instead. 1347 0 stevel */ 1348 0 stevel static int nfs_portmon = 0; 1349 0 stevel 1350 0 stevel #ifdef DEBUG 1351 0 stevel static int cred_hits = 0; 1352 0 stevel static int cred_misses = 0; 1353 0 stevel #endif 1354 0 stevel 1355 0 stevel 1356 0 stevel #ifdef DEBUG 1357 0 stevel /* 1358 0 stevel * Debug code to allow disabling of rfs_dispatch() use of 1359 0 stevel * fastxdrargs() and fastxdrres() calls for testing purposes. 1360 0 stevel */ 1361 0 stevel static int rfs_no_fast_xdrargs = 0; 1362 0 stevel static int rfs_no_fast_xdrres = 0; 1363 0 stevel #endif 1364 0 stevel 1365 0 stevel union acl_args { 1366 0 stevel /* 1367 0 stevel * ACL VERSION 2 1368 0 stevel */ 1369 0 stevel 1370 0 stevel /* ACL2_NULL = 0 */ 1371 0 stevel 1372 0 stevel /* ACL2_GETACL = 1 */ 1373 0 stevel GETACL2args acl2_getacl_args; 1374 0 stevel 1375 0 stevel /* ACL2_SETACL = 2 */ 1376 0 stevel SETACL2args acl2_setacl_args; 1377 0 stevel 1378 0 stevel /* ACL2_GETATTR = 3 */ 1379 0 stevel GETATTR2args acl2_getattr_args; 1380 0 stevel 1381 0 stevel /* ACL2_ACCESS = 4 */ 1382 0 stevel ACCESS2args acl2_access_args; 1383 0 stevel 1384 0 stevel /* ACL2_GETXATTRDIR = 5 */ 1385 0 stevel GETXATTRDIR2args acl2_getxattrdir_args; 1386 0 stevel 1387 0 stevel /* 1388 0 stevel * ACL VERSION 3 1389 0 stevel */ 1390 0 stevel 1391 0 stevel /* ACL3_NULL = 0 */ 1392 0 stevel 1393 0 stevel /* ACL3_GETACL = 1 */ 1394 0 stevel GETACL3args acl3_getacl_args; 1395 0 stevel 1396 0 stevel /* ACL3_SETACL = 2 */ 1397 0 stevel SETACL3args acl3_setacl; 1398 0 stevel 1399 0 stevel /* ACL3_GETXATTRDIR = 3 */ 1400 0 stevel GETXATTRDIR3args acl3_getxattrdir_args; 1401 0 stevel 1402 0 stevel }; 1403 0 stevel 1404 0 stevel union acl_res { 1405 0 stevel /* 1406 0 stevel * ACL VERSION 2 1407 0 stevel */ 1408 0 stevel 1409 0 stevel /* ACL2_NULL = 0 */ 1410 0 stevel 1411 0 stevel /* ACL2_GETACL = 1 */ 1412 0 stevel GETACL2res acl2_getacl_res; 1413 0 stevel 1414 0 stevel /* ACL2_SETACL = 2 */ 1415 0 stevel SETACL2res acl2_setacl_res; 1416 0 stevel 1417 0 stevel /* ACL2_GETATTR = 3 */ 1418 0 stevel GETATTR2res acl2_getattr_res; 1419 0 stevel 1420 0 stevel /* ACL2_ACCESS = 4 */ 1421 0 stevel ACCESS2res acl2_access_res; 1422 0 stevel 1423 0 stevel /* ACL2_GETXATTRDIR = 5 */ 1424 0 stevel GETXATTRDIR2args acl2_getxattrdir_res; 1425 0 stevel 1426 0 stevel /* 1427 0 stevel * ACL VERSION 3 1428 0 stevel */ 1429 0 stevel 1430 0 stevel /* ACL3_NULL = 0 */ 1431 0 stevel 1432 0 stevel /* ACL3_GETACL = 1 */ 1433 0 stevel GETACL3res acl3_getacl_res; 1434 0 stevel 1435 0 stevel /* ACL3_SETACL = 2 */ 1436 0 stevel SETACL3res acl3_setacl_res; 1437 0 stevel 1438 0 stevel /* ACL3_GETXATTRDIR = 3 */ 1439 0 stevel GETXATTRDIR3res acl3_getxattrdir_res; 1440 0 stevel 1441 0 stevel }; 1442 0 stevel 1443 0 stevel static bool_t 1444 0 stevel auth_tooweak(struct svc_req *req, char *res) 1445 0 stevel { 1446 0 stevel 1447 0 stevel if (req->rq_vers == NFS_VERSION && req->rq_proc == RFS_LOOKUP) { 1448 0 stevel struct nfsdiropres *dr = (struct nfsdiropres *)res; 1449 0 stevel if (dr->dr_status == WNFSERR_CLNT_FLAVOR) 1450 0 stevel return (TRUE); 1451 0 stevel } else if (req->rq_vers == NFS_V3 && req->rq_proc == NFSPROC3_LOOKUP) { 1452 0 stevel LOOKUP3res *resp = (LOOKUP3res *)res; 1453 0 stevel if (resp->status == WNFSERR_CLNT_FLAVOR) 1454 0 stevel return (TRUE); 1455 0 stevel } 1456 0 stevel return (FALSE); 1457 0 stevel } 1458 0 stevel 1459 74 rg137905 1460 0 stevel static void 1461 0 stevel common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers, 1462 0 stevel rpcvers_t max_vers, char *pgmname, 1463 0 stevel struct rpc_disptable *disptable) 1464 0 stevel { 1465 0 stevel int which; 1466 0 stevel rpcvers_t vers; 1467 0 stevel char *args; 1468 0 stevel union { 1469 0 stevel union rfs_args ra; 1470 0 stevel union acl_args aa; 1471 0 stevel } args_buf; 1472 0 stevel char *res; 1473 0 stevel union { 1474 0 stevel union rfs_res rr; 1475 0 stevel union acl_res ar; 1476 0 stevel } res_buf; 1477 0 stevel struct rpcdisp *disp = NULL; 1478 0 stevel int dis_flags = 0; 1479 0 stevel cred_t *cr; 1480 0 stevel int error = 0; 1481 0 stevel int anon_ok; 1482 0 stevel struct exportinfo *exi = NULL; 1483 0 stevel unsigned int nfslog_rec_id; 1484 0 stevel int dupstat; 1485 0 stevel struct dupreq *dr; 1486 0 stevel int authres; 1487 0 stevel bool_t publicfh_ok = FALSE; 1488 0 stevel enum_t auth_flavor; 1489 0 stevel bool_t dupcached = FALSE; 1490 0 stevel struct netbuf nb; 1491 0 stevel bool_t logging_enabled = FALSE; 1492 0 stevel struct exportinfo *nfslog_exi = NULL; 1493 1232 robinson char **procnames; 1494 1232 robinson char cbuf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */ 1495 0 stevel 1496 0 stevel vers = req->rq_vers; 1497 0 stevel 1498 0 stevel if (vers < min_vers || vers > max_vers) { 1499 0 stevel svcerr_progvers(req->rq_xprt, min_vers, max_vers); 1500 0 stevel error++; 1501 0 stevel cmn_err(CE_NOTE, "%s: bad version number %u", pgmname, vers); 1502 0 stevel goto done; 1503 0 stevel } 1504 0 stevel vers -= min_vers; 1505 0 stevel 1506 0 stevel which = req->rq_proc; 1507 0 stevel if (which < 0 || which >= disptable[(int)vers].dis_nprocs) { 1508 0 stevel svcerr_noproc(req->rq_xprt); 1509 0 stevel error++; 1510 0 stevel goto done; 1511 0 stevel } 1512 0 stevel 1513 0 stevel (*(disptable[(int)vers].dis_proccntp))[which].value.ui64++; 1514 0 stevel 1515 0 stevel disp = &disptable[(int)vers].dis_table[which]; 1516 1232 robinson procnames = disptable[(int)vers].dis_procnames; 1517 0 stevel 1518 0 stevel auth_flavor = req->rq_cred.oa_flavor; 1519 1232 robinson 1520 0 stevel /* 1521 0 stevel * Deserialize into the args struct. 1522 0 stevel */ 1523 0 stevel args = (char *)&args_buf; 1524 74 rg137905 1525 0 stevel #ifdef DEBUG 1526 0 stevel if (rfs_no_fast_xdrargs || (auth_flavor == RPCSEC_GSS) || 1527 0 stevel disp->dis_fastxdrargs == NULL_xdrproc_t || 1528 1610 thurlow !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args)) 1529 0 stevel #else 1530 0 stevel if ((auth_flavor == RPCSEC_GSS) || 1531 0 stevel disp->dis_fastxdrargs == NULL_xdrproc_t || 1532 1610 thurlow !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args)) 1533 0 stevel #endif 1534 1610 thurlow { 1535 0 stevel bzero(args, disp->dis_argsz); 1536 0 stevel if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) { 1537 4635 maheshvs error++; 1538 4635 maheshvs /* 1539 4635 maheshvs * Check if we are outside our capabilities. 1540 4635 maheshvs */ 1541 4635 maheshvs if (rfs4_minorvers_mismatch(req, xprt, (void *)args)) 1542 4635 maheshvs goto done; 1543 4635 maheshvs 1544 0 stevel svcerr_decode(xprt); 1545 1232 robinson cmn_err(CE_NOTE, 1546 1232 robinson "Failed to decode arguments for %s version %u " 1547 1232 robinson "procedure %s client %s%s", 1548 1232 robinson pgmname, vers + min_vers, procnames[which], 1549 1232 robinson client_name(req), client_addr(req, cbuf)); 1550 0 stevel goto done; 1551 0 stevel } 1552 0 stevel } 1553 0 stevel 1554 0 stevel /* 1555 74 rg137905 * If Version 4 use that specific dispatch function. 1556 0 stevel */ 1557 74 rg137905 if (req->rq_vers == 4) { 1558 74 rg137905 error += rfs4_dispatch(disp, req, xprt, args); 1559 74 rg137905 goto done; 1560 74 rg137905 } 1561 0 stevel 1562 74 rg137905 dis_flags = disp->dis_flags; 1563 0 stevel 1564 0 stevel /* 1565 0 stevel * Find export information and check authentication, 1566 0 stevel * setting the credential if everything is ok. 1567 0 stevel */ 1568 0 stevel if (disp->dis_getfh != NULL) { 1569 1610 thurlow void *fh; 1570 1610 thurlow fsid_t *fsid; 1571 1610 thurlow fid_t *fid, *xfid; 1572 1610 thurlow fhandle_t *fh2; 1573 1610 thurlow nfs_fh3 *fh3; 1574 0 stevel 1575 0 stevel fh = (*disp->dis_getfh)(args); 1576 1610 thurlow switch (req->rq_vers) { 1577 1610 thurlow case NFS_VERSION: 1578 1610 thurlow fh2 = (fhandle_t *)fh; 1579 1610 thurlow fsid = &fh2->fh_fsid; 1580 1610 thurlow fid = (fid_t *)&fh2->fh_len; 1581 1610 thurlow xfid = (fid_t *)&fh2->fh_xlen; 1582 1610 thurlow break; 1583 1610 thurlow case NFS_V3: 1584 1610 thurlow fh3 = (nfs_fh3 *)fh; 1585 1610 thurlow fsid = &fh3->fh3_fsid; 1586 1610 thurlow fid = FH3TOFIDP(fh3); 1587 1610 thurlow xfid = FH3TOXFIDP(fh3); 1588 1610 thurlow break; 1589 1610 thurlow } 1590 0 stevel 1591 0 stevel /* 1592 0 stevel * Fix for bug 1038302 - corbin 1593 0 stevel * There is a problem here if anonymous access is 1594 0 stevel * disallowed. If the current request is part of the 1595 0 stevel * client's mount process for the requested filesystem, 1596 0 stevel * then it will carry root (uid 0) credentials on it, and 1597 0 stevel * will be denied by checkauth if that client does not 1598 0 stevel * have explicit root=0 permission. This will cause the 1599 0 stevel * client's mount operation to fail. As a work-around, 1600 0 stevel * we check here to see if the request is a getattr or 1601 0 stevel * statfs operation on the exported vnode itself, and 1602 0 stevel * pass a flag to checkauth with the result of this test. 1603 0 stevel * 1604 0 stevel * The filehandle refers to the mountpoint itself if 1605 0 stevel * the fh_data and fh_xdata portions of the filehandle 1606 0 stevel * are equal. 1607 0 stevel * 1608 0 stevel * Added anon_ok argument to checkauth(). 1609 0 stevel */ 1610 0 stevel 1611 1610 thurlow if ((dis_flags & RPC_ALLOWANON) && EQFID(fid, xfid)) 1612 0 stevel anon_ok = 1; 1613 0 stevel else 1614 0 stevel anon_ok = 0; 1615 0 stevel 1616 0 stevel cr = xprt->xp_cred; 1617 0 stevel ASSERT(cr != NULL); 1618 0 stevel #ifdef DEBUG 1619 0 stevel if (crgetref(cr) != 1) { 1620 0 stevel crfree(cr); 1621 0 stevel cr = crget(); 1622 0 stevel xprt->xp_cred = cr; 1623 0 stevel cred_misses++; 1624 0 stevel } else 1625 0 stevel cred_hits++; 1626 0 stevel #else 1627 0 stevel if (crgetref(cr) != 1) { 1628 0 stevel crfree(cr); 1629 0 stevel cr = crget(); 1630 0 stevel xprt->xp_cred = cr; 1631 0 stevel } 1632 0 stevel #endif 1633 0 stevel 1634 1610 thurlow exi = checkexport(fsid, xfid); 1635 74 rg137905 1636 0 stevel if (exi != NULL) { 1637 1610 thurlow publicfh_ok = PUBLICFH_CHECK(disp, exi, fsid, xfid); 1638 0 stevel 1639 0 stevel /* 1640 0 stevel * Don't allow non-V4 clients access 1641 0 stevel * to pseudo exports 1642 0 stevel */ 1643 0 stevel if (PSEUDO(exi)) { 1644 0 stevel svcerr_weakauth(xprt); 1645 0 stevel error++; 1646 0 stevel goto done; 1647 0 stevel } 1648 0 stevel 1649 0 stevel authres = checkauth(exi, req, cr, anon_ok, publicfh_ok); 1650 0 stevel /* 1651 0 stevel * authres > 0: authentication OK - proceed 1652 0 stevel * authres == 0: authentication weak - return error 1653 0 stevel * authres < 0: authentication timeout - drop 1654 0 stevel */ 1655 0 stevel if (authres <= 0) { 1656 0 stevel if (authres == 0) { 1657 0 stevel svcerr_weakauth(xprt); 1658 0 stevel error++; 1659 0 stevel } 1660 0 stevel goto done; 1661 0 stevel } 1662 7961 Natalie 1663 7961 Natalie /* check to see if we might need charmap */ 1664 7961 Natalie if (exi->exi_export.ex_flags & EX_CHARMAP) { 1665 7961 Natalie struct sockaddr *ca; 1666 7961 Natalie ca = (struct sockaddr *) 1667 7961 Natalie svc_getrpccaller(req->rq_xprt)->buf; 1668 7961 Natalie (void) nfscmd_charmap(exi, ca); 1669 7961 Natalie } 1670 0 stevel } 1671 0 stevel } else 1672 0 stevel cr = NULL; 1673 0 stevel 1674 0 stevel if ((dis_flags & RPC_MAPRESP) && (auth_flavor != RPCSEC_GSS)) { 1675 0 stevel res = (char *)SVC_GETRES(xprt, disp->dis_ressz); 1676 0 stevel if (res == NULL) 1677 0 stevel res = (char *)&res_buf; 1678 0 stevel } else 1679 0 stevel res = (char *)&res_buf; 1680 0 stevel 1681 0 stevel if (!(dis_flags & RPC_IDEMPOTENT)) { 1682 0 stevel dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr, 1683 7961 Natalie &dupcached); 1684 0 stevel 1685 0 stevel switch (dupstat) { 1686 0 stevel case DUP_ERROR: 1687 0 stevel svcerr_systemerr(xprt); 1688 0 stevel error++; 1689 0 stevel goto done; 1690 0 stevel /* NOTREACHED */ 1691 0 stevel case DUP_INPROGRESS: 1692 0 stevel if (res != (char *)&res_buf) 1693 0 stevel SVC_FREERES(xprt); 1694 0 stevel error++; 1695 0 stevel goto done; 1696 0 stevel /* NOTREACHED */ 1697 0 stevel case DUP_NEW: 1698 0 stevel case DUP_DROP: 1699 0 stevel curthread->t_flag |= T_DONTPEND; 1700 74 rg137905 1701 0 stevel (*disp->dis_proc)(args, res, exi, req, cr); 1702 74 rg137905 1703 0 stevel curthread->t_flag &= ~T_DONTPEND; 1704 0 stevel if (curthread->t_flag & T_WOULDBLOCK) { 1705 0 stevel curthread->t_flag &= ~T_WOULDBLOCK; 1706 0 stevel SVC_DUPDONE_EXT(xprt, dr, res, NULL, 1707 7961 Natalie disp->dis_ressz, DUP_DROP); 1708 0 stevel if (res != (char *)&res_buf) 1709 0 stevel SVC_FREERES(xprt); 1710 0 stevel error++; 1711 0 stevel goto done; 1712 0 stevel } 1713 0 stevel if (dis_flags & RPC_AVOIDWORK) { 1714 0 stevel SVC_DUPDONE_EXT(xprt, dr, res, NULL, 1715 7961 Natalie disp->dis_ressz, DUP_DROP); 1716 0 stevel } else { 1717 0 stevel SVC_DUPDONE_EXT(xprt, dr, res, 1718 7961 Natalie disp->dis_resfree == nullfree ? NULL : 1719 7961 Natalie disp->dis_resfree, 1720 7961 Natalie disp->dis_ressz, DUP_DONE); 1721 0 stevel dupcached = TRUE; 1722 0 stevel } 1723 0 stevel break; 1724 0 stevel case DUP_DONE: 1725 0 stevel break; 1726 0 stevel } 1727 0 stevel 1728 0 stevel } else { 1729 0 stevel curthread->t_flag |= T_DONTPEND; 1730 74 rg137905 1731 0 stevel (*disp->dis_proc)(args, res, exi, req, cr); 1732 74 rg137905 1733 0 stevel curthread->t_flag &= ~T_DONTPEND; 1734 0 stevel if (curthread->t_flag & T_WOULDBLOCK) { 1735 0 stevel curthread->t_flag &= ~T_WOULDBLOCK; 1736 0 stevel if (res != (char *)&res_buf) 1737 0 stevel SVC_FREERES(xprt); 1738 0 stevel error++; 1739 0 stevel goto done; 1740 0 stevel } 1741 0 stevel } 1742 0 stevel 1743 0 stevel if (auth_tooweak(req, res)) { 1744 0 stevel svcerr_weakauth(xprt); 1745 0 stevel error++; 1746 0 stevel goto done; 1747 0 stevel } 1748 0 stevel 1749 0 stevel /* 1750 0 stevel * Check to see if logging has been enabled on the server. 1751 0 stevel * If so, then obtain the export info struct to be used for 1752 0 stevel * the later writing of the log record. This is done for 1753 0 stevel * the case that a lookup is done across a non-logged public 1754 0 stevel * file system. 1755 0 stevel */ 1756 0 stevel if (nfslog_buffer_list != NULL) { 1757 0 stevel nfslog_exi = nfslog_get_exi(exi, req, res, &nfslog_rec_id); 1758 0 stevel /* 1759 0 stevel * Is logging enabled? 1760 0 stevel */ 1761 0 stevel logging_enabled = (nfslog_exi != NULL); 1762 0 stevel 1763 0 stevel /* 1764 0 stevel * Copy the netbuf for logging purposes, before it is 1765 0 stevel * freed by svc_sendreply(). 1766 0 stevel */ 1767 0 stevel if (logging_enabled) { 1768 0 stevel NFSLOG_COPY_NETBUF(nfslog_exi, xprt, &nb); 1769 0 stevel /* 1770 0 stevel * If RPC_MAPRESP flag set (i.e. in V2 ops) the 1771 0 stevel * res gets copied directly into the mbuf and 1772 0 stevel * may be freed soon after the sendreply. So we 1773 0 stevel * must copy it here to a safe place... 1774 0 stevel */ 1775 0 stevel if (res != (char *)&res_buf) { 1776 0 stevel bcopy(res, (char *)&res_buf, disp->dis_ressz); 1777 0 stevel } 1778 0 stevel } 1779 0 stevel } 1780 0 stevel 1781 0 stevel /* 1782 0 stevel * Serialize and send results struct 1783 0 stevel */ 1784 0 stevel #ifdef DEBUG 1785 1610 thurlow if (rfs_no_fast_xdrres == 0 && res != (char *)&res_buf) 1786 0 stevel #else 1787 1610 thurlow if (res != (char *)&res_buf) 1788 0 stevel #endif 1789 1610 thurlow { 1790 0 stevel if (!svc_sendreply(xprt, disp->dis_fastxdrres, res)) { 1791 0 stevel cmn_err(CE_NOTE, "%s: bad sendreply", pgmname); 1792 0 stevel error++; 1793 0 stevel } 1794 0 stevel } else { 1795 0 stevel if (!svc_sendreply(xprt, disp->dis_xdrres, res)) { 1796 0 stevel cmn_err(CE_NOTE, "%s: bad sendreply", pgmname); 1797 0 stevel error++; 1798 0 stevel } 1799 0 stevel } 1800 0 stevel 1801 0 stevel /* 1802 0 stevel * Log if needed 1803 0 stevel */ 1804 0 stevel if (logging_enabled) { 1805 0 stevel nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf, 1806 7961 Natalie cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER); 1807 0 stevel exi_rele(nfslog_exi); 1808 0 stevel kmem_free((&nb)->buf, (&nb)->len); 1809 0 stevel } 1810 0 stevel 1811 0 stevel /* 1812 0 stevel * Free results struct. With the addition of NFS V4 we can 1813 0 stevel * have non-idempotent procedures with functions. 1814 0 stevel */ 1815 0 stevel if (disp->dis_resfree != nullfree && dupcached == FALSE) { 1816 0 stevel (*disp->dis_resfree)(res); 1817 0 stevel } 1818 0 stevel 1819 0 stevel done: 1820 0 stevel /* 1821 0 stevel * Free arguments struct 1822 0 stevel */ 1823 0 stevel if (disp) { 1824 0 stevel if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) { 1825 0 stevel cmn_err(CE_NOTE, "%s: bad freeargs", pgmname); 1826 0 stevel error++; 1827 0 stevel } 1828 0 stevel } else { 1829 0 stevel if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) { 1830 0 stevel cmn_err(CE_NOTE, "%s: bad freeargs", pgmname); 1831 0 stevel error++; 1832 0 stevel } 1833 0 stevel } 1834 0 stevel 1835 0 stevel if (exi != NULL) 1836 0 stevel exi_rele(exi); 1837 0 stevel 1838 0 stevel global_svstat_ptr[req->rq_vers][NFS_BADCALLS].value.ui64 += error; 1839 0 stevel 1840 0 stevel global_svstat_ptr[req->rq_vers][NFS_CALLS].value.ui64++; 1841 0 stevel } 1842 0 stevel 1843 0 stevel static void 1844 0 stevel rfs_dispatch(struct svc_req *req, SVCXPRT *xprt) 1845 0 stevel { 1846 0 stevel common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX, 1847 7961 Natalie "NFS", rfs_disptable); 1848 0 stevel } 1849 0 stevel 1850 0 stevel static char *aclcallnames_v2[] = { 1851 0 stevel "ACL2_NULL", 1852 0 stevel "ACL2_GETACL", 1853 0 stevel "ACL2_SETACL", 1854 0 stevel "ACL2_GETATTR", 1855 0 stevel "ACL2_ACCESS", 1856 0 stevel "ACL2_GETXATTRDIR" 1857 0 stevel }; 1858 0 stevel 1859 0 stevel static struct rpcdisp acldisptab_v2[] = { 1860 0 stevel /* 1861 0 stevel * ACL VERSION 2 1862 0 stevel */ 1863 0 stevel 1864 0 stevel /* ACL2_NULL = 0 */ 1865 0 stevel {rpc_null, 1866 0 stevel xdr_void, NULL_xdrproc_t, 0, 1867 0 stevel xdr_void, NULL_xdrproc_t, 0, 1868 0 stevel nullfree, RPC_IDEMPOTENT, 1869 0 stevel 0}, 1870 0 stevel 1871 0 stevel /* ACL2_GETACL = 1 */ 1872 0 stevel {acl2_getacl, 1873 0 stevel xdr_GETACL2args, xdr_fastGETACL2args, sizeof (GETACL2args), 1874 0 stevel xdr_GETACL2res, NULL_xdrproc_t, sizeof (GETACL2res), 1875 0 stevel acl2_getacl_free, RPC_IDEMPOTENT, 1876 0 stevel acl2_getacl_getfh}, 1877 0 stevel 1878 0 stevel /* ACL2_SETACL = 2 */ 1879 0 stevel {acl2_setacl, 1880 0 stevel xdr_SETACL2args, NULL_xdrproc_t, sizeof (SETACL2args), 1881 0 stevel #ifdef _LITTLE_ENDIAN 1882 0 stevel xdr_SETACL2res, xdr_fastSETACL2res, sizeof (SETACL2res), 1883 0 stevel #else 1884 0 stevel xdr_SETACL2res, NULL_xdrproc_t, sizeof (SETACL2res), 1885 0 stevel #endif 1886 0 stevel nullfree, RPC_MAPRESP, 1887 0 stevel acl2_setacl_getfh}, 1888 0 stevel 1889 0 stevel /* ACL2_GETATTR = 3 */ 1890 0 stevel {acl2_getattr, 1891 0 stevel xdr_GETATTR2args, xdr_fastGETATTR2args, sizeof (GETATTR2args), 1892 0 stevel #ifdef _LITTLE_ENDIAN 1893 0 stevel xdr_GETATTR2res, xdr_fastGETATTR2res, sizeof (GETATTR2res), 1894 0 stevel #else 1895 0 stevel xdr_GETATTR2res, NULL_xdrproc_t, sizeof (GETATTR2res), 1896 0 stevel #endif 1897 0 stevel nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP, 1898 0 stevel acl2_getattr_getfh}, 1899 0 stevel 1900 0 stevel /* ACL2_ACCESS = 4 */ 1901 0 stevel {acl2_access, 1902 0 stevel xdr_ACCESS2args, xdr_fastACCESS2args, sizeof (ACCESS2args), 1903 0 stevel #ifdef _LITTLE_ENDIAN 1904 0 stevel xdr_ACCESS2res, xdr_fastACCESS2res, sizeof (ACCESS2res), 1905 0 stevel #else 1906 0 stevel xdr_ACCESS2res, NULL_xdrproc_t, sizeof (ACCESS2res), 1907 0 stevel #endif 1908 0 stevel nullfree, RPC_IDEMPOTENT|RPC_MAPRESP, 1909 0 stevel acl2_access_getfh}, 1910 0 stevel 1911 0 stevel /* ACL2_GETXATTRDIR = 5 */ 1912 0 stevel {acl2_getxattrdir, 1913 0 stevel xdr_GETXATTRDIR2args, NULL_xdrproc_t, sizeof (GETXATTRDIR2args), 1914 0 stevel xdr_GETXATTRDIR2res, NULL_xdrproc_t, sizeof (GETXATTRDIR2res), 1915 0 stevel nullfree, RPC_IDEMPOTENT, 1916 0 stevel acl2_getxattrdir_getfh}, 1917 0 stevel }; 1918 0 stevel 1919 0 stevel static char *aclcallnames_v3[] = { 1920 0 stevel "ACL3_NULL", 1921 0 stevel "ACL3_GETACL", 1922 0 stevel "ACL3_SETACL", 1923 0 stevel "ACL3_GETXATTRDIR" 1924 0 stevel }; 1925 0 stevel 1926 0 stevel static struct rpcdisp acldisptab_v3[] = { 1927 0 stevel /* 1928 0 stevel * ACL VERSION 3 1929 0 stevel */ 1930 0 stevel 1931 0 stevel /* ACL3_NULL = 0 */ 1932 0 stevel {rpc_null, 1933 0 stevel xdr_void, NULL_xdrproc_t, 0, 1934 0 stevel xdr_void, NULL_xdrproc_t, 0, 1935 0 stevel nullfree, RPC_IDEMPOTENT, 1936 0 stevel 0}, 1937 0 stevel 1938 0 stevel /* ACL3_GETACL = 1 */ 1939 0 stevel {acl3_getacl, 1940 0 stevel xdr_GETACL3args, NULL_xdrproc_t, sizeof (GETACL3args), 1941 0 stevel xdr_GETACL3res, NULL_xdrproc_t, sizeof (GETACL3res), 1942 0 stevel acl3_getacl_free, RPC_IDEMPOTENT, 1943 0 stevel acl3_getacl_getfh}, 1944 0 stevel 1945 0 stevel /* ACL3_SETACL = 2 */ 1946 0 stevel {acl3_setacl, 1947 0 stevel xdr_SETACL3args, NULL_xdrproc_t, sizeof (SETACL3args), 1948 0 stevel xdr_SETACL3res, NULL_xdrproc_t, sizeof (SETACL3res), 1949 0 stevel nullfree, 0, 1950 0 stevel acl3_setacl_getfh}, 1951 0 stevel 1952 0 stevel /* ACL3_GETXATTRDIR = 3 */ 1953 0 stevel {acl3_getxattrdir, 1954 0 stevel xdr_GETXATTRDIR3args, NULL_xdrproc_t, sizeof (GETXATTRDIR3args), 1955 0 stevel xdr_GETXATTRDIR3res, NULL_xdrproc_t, sizeof (GETXATTRDIR3res), 1956 0 stevel nullfree, RPC_IDEMPOTENT, 1957 0 stevel acl3_getxattrdir_getfh}, 1958 0 stevel }; 1959 0 stevel 1960 0 stevel static struct rpc_disptable acl_disptable[] = { 1961 0 stevel {sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]), 1962 0 stevel aclcallnames_v2, 1963 0 stevel &aclproccnt_v2_ptr, acldisptab_v2}, 1964 0 stevel {sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]), 1965 0 stevel aclcallnames_v3, 1966 0 stevel &aclproccnt_v3_ptr, acldisptab_v3}, 1967 0 stevel }; 1968 0 stevel 1969 0 stevel static void 1970 0 stevel acl_dispatch(struct svc_req *req, SVCXPRT *xprt) 1971 0 stevel { 1972 0 stevel common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, 1973 7961 Natalie "ACL", acl_disptable); 1974 0 stevel } 1975 0 stevel 1976 0 stevel int 1977 0 stevel checkwin(int flavor, int window, struct svc_req *req) 1978 0 stevel { 1979 0 stevel struct authdes_cred *adc; 1980 0 stevel 1981 0 stevel switch (flavor) { 1982 0 stevel case AUTH_DES: 1983 0 stevel adc = (struct authdes_cred *)req->rq_clntcred; 1984 0 stevel if (adc->adc_fullname.window > window) 1985 0 stevel return (0); 1986 0 stevel break; 1987 0 stevel 1988 0 stevel default: 1989 0 stevel break; 1990 0 stevel } 1991 0 stevel return (1); 1992 0 stevel } 1993 0 stevel 1994 0 stevel 1995 0 stevel /* 1996 0 stevel * checkauth() will check the access permission against the export 1997 0 stevel * information. Then map root uid/gid to appropriate uid/gid. 1998 0 stevel * 1999 0 stevel * This routine is used by NFS V3 and V2 code. 2000 0 stevel */ 2001 0 stevel static int 2002 0 stevel checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok, 2003 0 stevel bool_t publicfh_ok) 2004 0 stevel { 2005 0 stevel int i, nfsflavor, rpcflavor, stat, access; 2006 0 stevel struct secinfo *secp; 2007 0 stevel caddr_t principal; 2008 0 stevel char buf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */ 2009 0 stevel int anon_res = 0; 2010 0 stevel 2011 0 stevel /* 2012 9987 Thomas * Check for privileged port number 2013 9987 Thomas * N.B.: this assumes that we know the format of a netbuf. 2014 0 stevel */ 2015 0 stevel if (nfs_portmon) { 2016 0 stevel struct sockaddr *ca; 2017 0 stevel ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2018 0 stevel 2019 0 stevel if (ca == NULL) 2020 0 stevel return (0); 2021 0 stevel 2022 0 stevel if ((ca->sa_family == AF_INET && 2023 0 stevel ntohs(((struct sockaddr_in *)ca)->sin_port) >= 2024 0 stevel IPPORT_RESERVED) || 2025 0 stevel (ca->sa_family == AF_INET6 && 2026 0 stevel ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >= 2027 0 stevel IPPORT_RESERVED)) { 2028 0 stevel cmn_err(CE_NOTE, 2029 0 stevel "nfs_server: client %s%ssent NFS request from " 2030 0 stevel "unprivileged port", 2031 0 stevel client_name(req), client_addr(req, buf)); 2032 0 stevel return (0); 2033 0 stevel } 2034 0 stevel } 2035 0 stevel 2036 0 stevel /* 2037 0 stevel * return 1 on success or 0 on failure 2038 0 stevel */ 2039 0 stevel stat = sec_svc_getcred(req, cr, &principal, &nfsflavor); 2040 0 stevel 2041 0 stevel /* 2042 0 stevel * A failed AUTH_UNIX svc_get_cred() implies we couldn't set 2043 0 stevel * the credentials; below we map that to anonymous. 2044 0 stevel */ 2045 0 stevel if (!stat && nfsflavor != AUTH_UNIX) { 2046 0 stevel cmn_err(CE_NOTE, 2047 0 stevel "nfs_server: couldn't get unix cred for %s", 2048 0 stevel client_name(req)); 2049 0 stevel return (0); 2050 0 stevel } 2051 0 stevel 2052 0 stevel /* 2053 0 stevel * Short circuit checkauth() on operations that support the 2054 0 stevel * public filehandle, and if the request for that operation 2055 0 stevel * is using the public filehandle. Note that we must call 2056 0 stevel * sec_svc_getcred() first so that xp_cookie is set to the 2057 0 stevel * right value. Normally xp_cookie is just the RPC flavor 2058 0 stevel * of the the request, but in the case of RPCSEC_GSS it 2059 0 stevel * could be a pseudo flavor. 2060 0 stevel */ 2061 0 stevel if (publicfh_ok) 2062 0 stevel return (1); 2063 0 stevel 2064 0 stevel rpcflavor = req->rq_cred.oa_flavor; 2065 0 stevel /* 2066 0 stevel * Check if the auth flavor is valid for this export 2067 0 stevel */ 2068 0 stevel access = nfsauth_access(exi, req); 2069 0 stevel if (access & NFSAUTH_DROP) 2070 0 stevel return (-1); /* drop the request */ 2071 0 stevel 2072 0 stevel if (access & NFSAUTH_DENIED) { 2073 0 stevel /* 2074 0 stevel * If anon_ok == 1 and we got NFSAUTH_DENIED, it was 2075 0 stevel * probably due to the flavor not matching during the 2076 0 stevel * the mount attempt. So map the flavor to AUTH_NONE 2077 0 stevel * so that the credentials get mapped to the anonymous 2078 0 stevel * user. 2079 0 stevel */ 2080 0 stevel if (anon_ok == 1) 2081 0 stevel rpcflavor = AUTH_NONE; 2082 0 stevel else 2083 0 stevel return (0); /* deny access */ 2084 0 stevel 2085 0 stevel } else if (access & NFSAUTH_MAPNONE) { 2086 0 stevel /* 2087 0 stevel * Access was granted even though the flavor mismatched 2088 0 stevel * because AUTH_NONE was one of the exported flavors. 2089 0 stevel */ 2090 0 stevel rpcflavor = AUTH_NONE; 2091 0 stevel 2092 0 stevel } else if (access & NFSAUTH_WRONGSEC) { 2093 0 stevel /* 2094 8395 Thomas * NFSAUTH_WRONGSEC is used for NFSv4. If we get here, 2095 8395 Thomas * it means a client ignored the list of allowed flavors 2096 8395 Thomas * returned via the MOUNT protocol. So we just disallow it! 2097 0 stevel */ 2098 8395 Thomas return (0); 2099 0 stevel } 2100 0 stevel 2101 0 stevel switch (rpcflavor) { 2102 0 stevel case AUTH_NONE: 2103 0 stevel anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2104 7961 Natalie exi->exi_export.ex_anon); 2105 0 stevel (void) crsetgroups(cr, 0, NULL); 2106 0 stevel break; 2107 0 stevel 2108 0 stevel case AUTH_UNIX: 2109 0 stevel if (!stat || crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) { 2110 0 stevel anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2111 7961 Natalie exi->exi_export.ex_anon); 2112 0 stevel (void) crsetgroups(cr, 0, NULL); 2113 7961 Natalie } else if (!stat || crgetuid(cr) == 0 && 2114 7961 Natalie access & NFSAUTH_ROOT) { 2115 7961 Natalie /* 2116 7961 Natalie * It is root, so apply rootid to get real UID 2117 7961 Natalie * Find the secinfo structure. We should be able 2118 7961 Natalie * to find it by the time we reach here. 2119 7961 Natalie * nfsauth_access() has done the checking. 2120 7961 Natalie */ 2121 7961 Natalie secp = NULL; 2122 7961 Natalie for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 2123 7961 Natalie struct secinfo *sptr; 2124 7961 Natalie sptr = &exi->exi_export.ex_secinfo[i]; 2125 7961 Natalie if (sptr->s_secinfo.sc_nfsnum == nfsflavor) { 2126 7961 Natalie secp = sptr; 2127 7961 Natalie break; 2128 7961 Natalie } 2129 7961 Natalie } 2130 7961 Natalie if (secp != NULL) { 2131 7961 Natalie (void) crsetugid(cr, secp->s_rootid, 2132 7961 Natalie secp->s_rootid); 2133 7961 Natalie (void) crsetgroups(cr, 0, NULL); 2134 7961 Natalie } 2135 0 stevel } 2136 0 stevel break; 2137 0 stevel 2138 0 stevel case AUTH_DES: 2139 0 stevel case RPCSEC_GSS: 2140 0 stevel /* 2141 0 stevel * Find the secinfo structure. We should be able 2142 0 stevel * to find it by the time we reach here. 2143 0 stevel * nfsauth_access() has done the checking. 2144 0 stevel */ 2145 0 stevel secp = NULL; 2146 0 stevel for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 2147 0 stevel if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum == 2148 0 stevel nfsflavor) { 2149 0 stevel secp = &exi->exi_export.ex_secinfo[i]; 2150 0 stevel break; 2151 0 stevel } 2152 0 stevel } 2153 0 stevel 2154 0 stevel if (!secp) { 2155 0 stevel cmn_err(CE_NOTE, "nfs_server: client %s%shad " 2156 0 stevel "no secinfo data for flavor %d", 2157 0 stevel client_name(req), client_addr(req, buf), 2158 0 stevel nfsflavor); 2159 0 stevel return (0); 2160 0 stevel } 2161 0 stevel 2162 0 stevel if (!checkwin(rpcflavor, secp->s_window, req)) { 2163 0 stevel cmn_err(CE_NOTE, 2164 0 stevel "nfs_server: client %s%sused invalid " 2165 0 stevel "auth window value", 2166 0 stevel client_name(req), client_addr(req, buf)); 2167 0 stevel return (0); 2168 0 stevel } 2169 0 stevel 2170 0 stevel /* 2171 0 stevel * Map root principals listed in the share's root= list to root, 2172 0 stevel * and map any others principals that were mapped to root by RPC 2173 0 stevel * to anon. 2174 0 stevel */ 2175 0 stevel if (principal && sec_svc_inrootlist(rpcflavor, principal, 2176 7961 Natalie secp->s_rootcnt, secp->s_rootnames)) { 2177 7961 Natalie if (crgetuid(cr) == 0 && secp->s_rootid == 0) 2178 0 stevel return (1); 2179 0 stevel 2180 7961 Natalie 2181 7961 Natalie (void) crsetugid(cr, secp->s_rootid, secp->s_rootid); 2182 0 stevel 2183 0 stevel /* 2184 0 stevel * NOTE: If and when kernel-land privilege tracing is 2185 0 stevel * added this may have to be replaced with code that 2186 0 stevel * retrieves root's supplementary groups (e.g., using 2187 0 stevel * kgss_get_group_info(). In the meantime principals 2188 0 stevel * mapped to uid 0 get all privileges, so setting cr's 2189 0 stevel * supplementary groups for them does nothing. 2190 0 stevel */ 2191 0 stevel (void) crsetgroups(cr, 0, NULL); 2192 0 stevel 2193 0 stevel return (1); 2194 0 stevel } 2195 0 stevel 2196 0 stevel /* 2197 0 stevel * Not a root princ, or not in root list, map UID 0/nobody to 2198 0 stevel * the anon ID for the share. (RPC sets cr's UIDs and GIDs to 2199 0 stevel * UID_NOBODY and GID_NOBODY, respectively.) 2200 0 stevel */ 2201 0 stevel if (crgetuid(cr) != 0 && 2202 0 stevel (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY)) 2203 0 stevel return (1); 2204 0 stevel 2205 0 stevel anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2206 7961 Natalie exi->exi_export.ex_anon); 2207 0 stevel (void) crsetgroups(cr, 0, NULL); 2208 0 stevel break; 2209 0 stevel default: 2210 0 stevel return (0); 2211 0 stevel } /* switch on rpcflavor */ 2212 0 stevel 2213 0 stevel /* 2214 0 stevel * Even if anon access is disallowed via ex_anon == -1, we allow 2215 0 stevel * this access if anon_ok is set. So set creds to the default 2216 0 stevel * "nobody" id. 2217 0 stevel */ 2218 0 stevel if (anon_res != 0) { 2219 0 stevel if (anon_ok == 0) { 2220 0 stevel cmn_err(CE_NOTE, 2221 0 stevel "nfs_server: client %s%ssent wrong " 2222 0 stevel "authentication for %s", 2223 0 stevel client_name(req), client_addr(req, buf), 2224 0 stevel exi->exi_export.ex_path ? 2225 0 stevel exi->exi_export.ex_path : "?"); 2226 0 stevel return (0); 2227 0 stevel } 2228 0 stevel 2229 0 stevel if (crsetugid(cr, UID_NOBODY, GID_NOBODY) != 0) 2230 0 stevel return (0); 2231 0 stevel } 2232 0 stevel 2233 0 stevel return (1); 2234 0 stevel } 2235 0 stevel 2236 0 stevel /* 2237 0 stevel * returns 0 on failure, -1 on a drop, -2 on wrong security flavor, 2238 0 stevel * and 1 on success 2239 0 stevel */ 2240 0 stevel int 2241 0 stevel checkauth4(struct compound_state *cs, struct svc_req *req) 2242 0 stevel { 2243 0 stevel int i, rpcflavor, access; 2244 0 stevel struct secinfo *secp; 2245 0 stevel char buf[MAXHOST + 1]; 2246 0 stevel int anon_res = 0, nfsflavor; 2247 0 stevel struct exportinfo *exi; 2248 0 stevel cred_t *cr; 2249 0 stevel caddr_t principal; 2250 0 stevel 2251 0 stevel exi = cs->exi; 2252 0 stevel cr = cs->cr; 2253 0 stevel principal = cs->principal; 2254 0 stevel nfsflavor = cs->nfsflavor; 2255 0 stevel 2256 0 stevel ASSERT(cr != NULL); 2257 0 stevel 2258 0 stevel rpcflavor = req->rq_cred.oa_flavor; 2259 0 stevel cs->access &= ~CS_ACCESS_LIMITED; 2260 9987 Thomas 2261 9987 Thomas /* 2262 9987 Thomas * Check for privileged port number 2263 9987 Thomas * N.B.: this assumes that we know the format of a netbuf. 2264 9987 Thomas */ 2265 9987 Thomas if (nfs_portmon) { 2266 9987 Thomas struct sockaddr *ca; 2267 9987 Thomas ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2268 9987 Thomas 2269 9987 Thomas if (ca == NULL) 2270 9987 Thomas return (0); 2271 9987 Thomas 2272 9987 Thomas if ((ca->sa_family == AF_INET && 2273 9987 Thomas ntohs(((struct sockaddr_in *)ca)->sin_port) >= 2274 9987 Thomas IPPORT_RESERVED) || 2275 9987 Thomas (ca->sa_family == AF_INET6 && 2276 9987 Thomas ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >= 2277 9987 Thomas IPPORT_RESERVED)) { 2278 9987 Thomas cmn_err(CE_NOTE, 2279 9987 Thomas "nfs_server: client %s%ssent NFSv4 request from " 2280 9987 Thomas "unprivileged port", 2281 9987 Thomas client_name(req), client_addr(req, buf)); 2282 9987 Thomas return (0); 2283 9987 Thomas } 2284 9987 Thomas } 2285 0 stevel 2286 0 stevel /* 2287 0 stevel * Check the access right per auth flavor on the vnode of 2288 0 stevel * this export for the given request. 2289 0 stevel */ 2290 0 stevel access = nfsauth4_access(cs->exi, cs->vp, req); 2291 0 stevel 2292 0 stevel if (access & NFSAUTH_WRONGSEC) 2293 0 stevel return (-2); /* no access for this security flavor */ 2294 0 stevel 2295 0 stevel if (access & NFSAUTH_DROP) 2296 0 stevel return (-1); /* drop the request */ 2297 0 stevel 2298 0 stevel if (access & NFSAUTH_DENIED) { 2299 0 stevel 2300 0 stevel if (exi->exi_export.ex_seccnt > 0) 2301 0 stevel return (0); /* deny access */ 2302 0 stevel 2303 0 stevel } else if (access & NFSAUTH_LIMITED) { 2304 0 stevel 2305 0 stevel cs->access |= CS_ACCESS_LIMITED; 2306 0 stevel 2307 0 stevel } else if (access & NFSAUTH_MAPNONE) { 2308 0 stevel /* 2309 0 stevel * Access was granted even though the flavor mismatched 2310 0 stevel * because AUTH_NONE was one of the exported flavors. 2311 0 stevel */ 2312 0 stevel rpcflavor = AUTH_NONE; 2313 0 stevel } 2314 0 stevel 2315 0 stevel /* 2316 0 stevel * XXX probably need to redo some of it for nfsv4? 2317 0 stevel * return 1 on success or 0 on failure 2318 0 stevel */ 2319 0 stevel 2320 0 stevel switch (rpcflavor) { 2321 0 stevel case AUTH_NONE: 2322 0 stevel anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2323 7961 Natalie exi->exi_export.ex_anon); 2324 0 stevel (void) crsetgroups(cr, 0, NULL); 2325 0 stevel break; 2326 0 stevel 2327 0 stevel case AUTH_UNIX: 2328 0 stevel if (crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) { 2329 0 stevel anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2330 7961 Natalie exi->exi_export.ex_anon); 2331 0 stevel (void) crsetgroups(cr, 0, NULL); 2332 7961 Natalie } else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) { 2333 7961 Natalie /* 2334 7961 Natalie * It is root, so apply rootid to get real UID 2335 7961 Natalie * Find the secinfo structure. We should be able 2336 7961 Natalie * to find it by the time we reach here. 2337 7961 Natalie * nfsauth_access() has done the checking. 2338 7961 Natalie */ 2339 7961 Natalie secp = NULL; 2340 7961 Natalie for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 2341 7961 Natalie struct secinfo *sptr; 2342 7961 Natalie sptr = &exi->exi_export.ex_secinfo[i]; 2343 7961 Natalie if (sptr->s_secinfo.sc_nfsnum == nfsflavor) { 2344 7961 Natalie secp = &exi->exi_export.ex_secinfo[i]; 2345 7961 Natalie break; 2346 7961 Natalie } 2347 7961 Natalie } 2348 7961 Natalie if (secp != NULL) { 2349 7961 Natalie (void) crsetugid(cr, secp->s_rootid, 2350 7961 Natalie secp->s_rootid); 2351 7961 Natalie (void) crsetgroups(cr, 0, NULL); 2352 7961 Natalie } 2353 0 stevel } 2354 0 stevel break; 2355 0 stevel 2356 0 stevel default: 2357 0 stevel /* 2358 0 stevel * Find the secinfo structure. We should be able 2359 0 stevel * to find it by the time we reach here. 2360 0 stevel * nfsauth_access() has done the checking. 2361 0 stevel */ 2362 0 stevel secp = NULL; 2363 0 stevel for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 2364 0 stevel if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum == 2365 0 stevel nfsflavor) { 2366 0 stevel secp = &exi->exi_export.ex_secinfo[i]; 2367 0 stevel break; 2368 0 stevel } 2369 0 stevel } 2370 0 stevel 2371 0 stevel if (!secp) { 2372 0 stevel cmn_err(CE_NOTE, "nfs_server: client %s%shad " 2373 0 stevel "no secinfo data for flavor %d", 2374 0 stevel client_name(req), client_addr(req, buf), 2375 0 stevel nfsflavor); 2376 0 stevel return (0); 2377 0 stevel } 2378 0 stevel 2379 0 stevel if (!checkwin(rpcflavor, secp->s_window, req)) { 2380 0 stevel cmn_err(CE_NOTE, 2381 0 stevel "nfs_server: client %s%sused invalid " 2382 0 stevel "auth window value", 2383 0 stevel client_name(req), client_addr(req, buf)); 2384 0 stevel return (0); 2385 0 stevel } 2386 0 stevel 2387 0 stevel /* 2388 0 stevel * Map root principals listed in the share's root= list to root, 2389 0 stevel * and map any others principals that were mapped to root by RPC 2390 7961 Natalie * to anon. If not going to anon, set to rootid (root_mapping). 2391 0 stevel */ 2392 0 stevel if (principal && sec_svc_inrootlist(rpcflavor, principal, 2393 7961 Natalie secp->s_rootcnt, secp->s_rootnames)) { 2394 7961 Natalie if (crgetuid(cr) == 0 && secp->s_rootid == 0) 2395 0 stevel return (1); 2396 0 stevel 2397 7961 Natalie (void) crsetugid(cr, secp->s_rootid, secp->s_rootid); 2398 0 stevel 2399 0 stevel /* 2400 0 stevel * NOTE: If and when kernel-land privilege tracing is 2401 0 stevel * added this may have to be replaced with code that 2402 0 stevel * retrieves root's supplementary groups (e.g., using 2403 0 stevel * kgss_get_group_info(). In the meantime principals 2404 0 stevel * mapped to uid 0 get all privileges, so setting cr's 2405 0 stevel * supplementary groups for them does nothing. 2406 0 stevel */ 2407 0 stevel (void) crsetgroups(cr, 0, NULL); 2408 0 stevel 2409 0 stevel return (1); 2410 0 stevel } 2411 0 stevel 2412 0 stevel /* 2413 0 stevel * Not a root princ, or not in root list, map UID 0/nobody to 2414 0 stevel * the anon ID for the share. (RPC sets cr's UIDs and GIDs to 2415 0 stevel * UID_NOBODY and GID_NOBODY, respectively.) 2416 0 stevel */ 2417 0 stevel if (crgetuid(cr) != 0 && 2418 0 stevel (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY)) 2419 0 stevel return (1); 2420 0 stevel 2421 0 stevel anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2422 7961 Natalie exi->exi_export.ex_anon); 2423 0 stevel (void) crsetgroups(cr, 0, NULL); 2424 0 stevel break; 2425 0 stevel } /* switch on rpcflavor */ 2426 0 stevel 2427 0 stevel /* 2428 0 stevel * Even if anon access is disallowed via ex_anon == -1, we allow 2429 0 stevel * this access if anon_ok is set. So set creds to the default 2430 0 stevel * "nobody" id. 2431 0 stevel */ 2432 0 stevel 2433 0 stevel if (anon_res != 0) { 2434 0 stevel cmn_err(CE_NOTE, 2435 7961 Natalie "nfs_server: client %s%ssent wrong " 2436 7961 Natalie "authentication for %s", 2437 7961 Natalie client_name(req), client_addr(req, buf), 2438 7961 Natalie exi->exi_export.ex_path ? 2439 7961 Natalie exi->exi_export.ex_path : "?"); 2440 0 stevel return (0); 2441 0 stevel } 2442 0 stevel 2443 0 stevel return (1); 2444 0 stevel } 2445 0 stevel 2446 0 stevel 2447 0 stevel static char * 2448 0 stevel client_name(struct svc_req *req) 2449 0 stevel { 2450 0 stevel char *hostname = NULL; 2451 0 stevel 2452 0 stevel /* 2453 0 stevel * If it's a Unix cred then use the 2454 0 stevel * hostname from the credential. 2455 0 stevel */ 2456 0 stevel if (req->rq_cred.oa_flavor == AUTH_UNIX) { 2457 0 stevel hostname = ((struct authunix_parms *) 2458 0 stevel req->rq_clntcred)->aup_machname; 2459 0 stevel } 2460 0 stevel if (hostname == NULL) 2461 0 stevel hostname = ""; 2462 0 stevel 2463 0 stevel return (hostname); 2464 0 stevel } 2465 0 stevel 2466 0 stevel static char * 2467 0 stevel client_addr(struct svc_req *req, char *buf) 2468 0 stevel { 2469 0 stevel struct sockaddr *ca; 2470 0 stevel uchar_t *b; 2471 0 stevel char *frontspace = ""; 2472 0 stevel 2473 0 stevel /* 2474 0 stevel * We assume we are called in tandem with client_name and the 2475 0 stevel * format string looks like "...client %s%sblah blah..." 2476 0 stevel * 2477 0 stevel * If it's a Unix cred then client_name returned 2478 0 stevel * a host name, so we need insert a space between host name 2479 0 stevel * and IP address. 2480 0 stevel */ 2481 0 stevel if (req->rq_cred.oa_flavor == AUTH_UNIX) 2482 0 stevel frontspace = " "; 2483 0 stevel 2484 0 stevel /* 2485 0 stevel * Convert the caller's IP address to a dotted string 2486 0 stevel */ 2487 0 stevel ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2488 0 stevel 2489 0 stevel if (ca->sa_family == AF_INET) { 2490 7961 Natalie b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr; 2491 7961 Natalie (void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace, 2492 7961 Natalie b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF); 2493 0 stevel } else if (ca->sa_family == AF_INET6) { 2494 0 stevel struct sockaddr_in6 *sin6; 2495 0 stevel sin6 = (struct sockaddr_in6 *)ca; 2496 0 stevel (void) kinet_ntop6((uchar_t *)&sin6->sin6_addr, 2497 7961 Natalie buf, INET6_ADDRSTRLEN); 2498 0 stevel 2499 0 stevel } else { 2500 0 stevel 2501 0 stevel /* 2502 0 stevel * No IP address to print. If there was a host name 2503 0 stevel * printed, then we print a space. 2504 0 stevel */ 2505 0 stevel (void) sprintf(buf, frontspace); 2506 0 stevel } 2507 0 stevel 2508 0 stevel return (buf); 2509 0 stevel } 2510 0 stevel 2511 0 stevel /* 2512 0 stevel * NFS Server initialization routine. This routine should only be called 2513 0 stevel * once. It performs the following tasks: 2514 0 stevel * - Call sub-initialization routines (localize access to variables) 2515 0 stevel * - Initialize all locks 2516 0 stevel * - initialize the version 3 write verifier 2517 0 stevel */ 2518 0 stevel int 2519 0 stevel nfs_srvinit(void) 2520 0 stevel { 2521 0 stevel int error; 2522 0 stevel 2523 0 stevel error = nfs_exportinit(); 2524 0 stevel if (error != 0) 2525 0 stevel return (error); 2526 0 stevel error = rfs4_srvrinit(); 2527 0 stevel if (error != 0) { 2528 0 stevel nfs_exportfini(); 2529 0 stevel return (error); 2530 0 stevel } 2531 0 stevel rfs_srvrinit(); 2532 0 stevel rfs3_srvrinit(); 2533 0 stevel nfsauth_init(); 2534 0 stevel 2535 0 stevel /* Init the stuff to control start/stop */ 2536 0 stevel nfs_server_upordown = NFS_SERVER_STOPPED; 2537 0 stevel mutex_init(&nfs_server_upordown_lock, NULL, MUTEX_DEFAULT, NULL); 2538 0 stevel cv_init(&nfs_server_upordown_cv, NULL, CV_DEFAULT, NULL); 2539 0 stevel mutex_init(&rdma_wait_mutex, NULL, MUTEX_DEFAULT, NULL); 2540 0 stevel cv_init(&rdma_wait_cv, NULL, CV_DEFAULT, NULL); 2541 0 stevel 2542 0 stevel return (0); 2543 0 stevel } 2544 0 stevel 2545 0 stevel /* 2546 0 stevel * NFS Server finalization routine. This routine is called to cleanup the 2547 0 stevel * initialization work previously performed if the NFS server module could 2548 0 stevel * not be loaded correctly. 2549 0 stevel */ 2550 0 stevel void 2551 0 stevel nfs_srvfini(void) 2552 0 stevel { 2553 0 stevel nfsauth_fini(); 2554 0 stevel rfs3_srvrfini(); 2555 0 stevel rfs_srvrfini(); 2556 0 stevel nfs_exportfini(); 2557 0 stevel 2558 0 stevel mutex_destroy(&nfs_server_upordown_lock); 2559 0 stevel cv_destroy(&nfs_server_upordown_cv); 2560 0 stevel mutex_destroy(&rdma_wait_mutex); 2561 0 stevel cv_destroy(&rdma_wait_cv); 2562 0 stevel } 2563 0 stevel 2564 0 stevel /* 2565 0 stevel * Set up an iovec array of up to cnt pointers. 2566 0 stevel */ 2567 0 stevel 2568 0 stevel void 2569 0 stevel mblk_to_iov(mblk_t *m, int cnt, struct iovec *iovp) 2570 0 stevel { 2571 0 stevel while (m != NULL && cnt-- > 0) { 2572 0 stevel iovp->iov_base = (caddr_t)m->b_rptr; 2573 0 stevel iovp->iov_len = (m->b_wptr - m->b_rptr); 2574 0 stevel iovp++; 2575 0 stevel m = m->b_cont; 2576 0 stevel } 2577 0 stevel } 2578 0 stevel 2579 0 stevel /* 2580 0 stevel * Common code between NFS Version 2 and NFS Version 3 for the public 2581 0 stevel * filehandle multicomponent lookups. 2582 0 stevel */ 2583 0 stevel 2584 0 stevel /* 2585 0 stevel * Public filehandle evaluation of a multi-component lookup, following 2586 0 stevel * symbolic links, if necessary. This may result in a vnode in another 2587 0 stevel * filesystem, which is OK as long as the other filesystem is exported. 2588 0 stevel * 2589 0 stevel * Note that the exi will be set either to NULL or a new reference to the 2590 0 stevel * exportinfo struct that corresponds to the vnode of the multi-component path. 2591 0 stevel * It is the callers responsibility to release this reference. 2592 0 stevel */ 2593 0 stevel int 2594 0 stevel rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp, 2595 0 stevel struct exportinfo **exi, struct sec_ol *sec) 2596 0 stevel { 2597 0 stevel int pathflag; 2598 0 stevel vnode_t *mc_dvp = NULL; 2599 0 stevel vnode_t *realvp; 2600 0 stevel int error; 2601 0 stevel 2602 0 stevel *exi = NULL; 2603 0 stevel 2604 0 stevel /* 2605 0 stevel * check if the given path is a url or native path. Since p is 2606 0 stevel * modified by MCLpath(), it may be empty after returning from 2607 0 stevel * there, and should be checked. 2608 0 stevel */ 2609 0 stevel if ((pathflag = MCLpath(&p)) == -1) 2610 0 stevel return (EIO); 2611 0 stevel 2612 0 stevel /* 2613 0 stevel * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit 2614 0 stevel * on in sec->sec_flags. This bit will later serve as an 2615 0 stevel * indication in makefh_ol() or makefh3_ol() to overload the 2616 0 stevel * filehandle to contain the sec modes used by the server for 2617 0 stevel * the path. 2618 0 stevel */ 2619 0 stevel if (pathflag == SECURITY_QUERY) { 2620 0 stevel if ((sec->sec_index = (uint_t)(*p)) > 0) { 2621 0 stevel sec->sec_flags |= SEC_QUERY; 2622 0 stevel p++; 2623 0 stevel if ((pathflag = MCLpath(&p)) == -1) 2624 0 stevel return (EIO); 2625 0 stevel } else { 2626 0 stevel cmn_err(CE_NOTE, 2627 0 stevel "nfs_server: invalid security index %d, " 2628 0 stevel "violating WebNFS SNEGO protocol.", sec->sec_index); 2629 0 stevel return (EIO); 2630 0 stevel } 2631 0 stevel } 2632 0 stevel 2633 0 stevel if (p[0] == '\0') { 2634 0 stevel error = ENOENT; 2635 0 stevel goto publicfh_done; 2636 0 stevel } 2637 0 stevel 2638 0 stevel error = rfs_pathname(p, &mc_dvp, vpp, dvp, cr, pathflag); 2639 0 stevel 2640 0 stevel /* 2641 0 stevel * If name resolves to "/" we get EINVAL since we asked for 2642 0 stevel * the vnode of the directory that the file is in. Try again 2643 0 stevel * with NULL directory vnode. 2644 0 stevel */ 2645 0 stevel if (error == EINVAL) { 2646 0 stevel error = rfs_pathname(p, NULL, vpp, dvp, cr, pathflag); 2647 0 stevel if (!error) { 2648 0 stevel ASSERT(*vpp != NULL); 2649 0 stevel if ((*vpp)->v_type == VDIR) { 2650 0 stevel VN_HOLD(*vpp); 2651 0 stevel mc_dvp = *vpp; 2652 0 stevel } else { 2653 0 stevel /* 2654 0 stevel * This should not happen, the filesystem is 2655 0 stevel * in an inconsistent state. Fail the lookup 2656 0 stevel * at this point. 2657 0 stevel */ 2658 0 stevel VN_RELE(*vpp); 2659 0 stevel error = EINVAL; 2660 0 stevel } 2661 0 stevel } 2662 0 stevel } 2663 0 stevel 2664 0 stevel if (error) 2665 0 stevel goto publicfh_done; 2666 0 stevel 2667 0 stevel if (*vpp == NULL) { 2668 0 stevel error = ENOENT; 2669 0 stevel goto publicfh_done; 2670 0 stevel } 2671 0 stevel 2672 0 stevel ASSERT(mc_dvp != NULL); 2673 0 stevel ASSERT(*vpp != NULL); 2674 0 stevel 2675 0 stevel if ((*vpp)->v_type == VDIR) { 2676 0 stevel do { 2677 0 stevel /* 2678 0 stevel * *vpp may be an AutoFS node, so we perform 2679 0 stevel * a VOP_ACCESS() to trigger the mount of the intended 2680 0 stevel * filesystem, so we can perform the lookup in the 2681 0 stevel * intended filesystem. 2682 0 stevel */ 2683 5331 amw (void) VOP_ACCESS(*vpp, 0, 0, cr, NULL); 2684 0 stevel 2685 0 stevel /* 2686 0 stevel * If vnode is covered, get the 2687 0 stevel * the topmost vnode. 2688 0 stevel */ 2689 0 stevel if (vn_mountedvfs(*vpp) != NULL) { 2690 0 stevel error = traverse(vpp); 2691 0 stevel if (error) { 2692 0 stevel VN_RELE(*vpp); 2693 0 stevel goto publicfh_done; 2694 0 stevel } 2695 0 stevel } 2696 0 stevel 2697 5331 amw if (VOP_REALVP(*vpp, &realvp, NULL) == 0 && 2698 5331 amw realvp != *vpp) { 2699 0 stevel /* 2700 0 stevel * If realvp is different from *vpp 2701 0 stevel * then release our reference on *vpp, so that 2702 0 stevel * the export access check be performed on the 2703 0 stevel * real filesystem instead. 2704 0 stevel */ 2705 0 stevel VN_HOLD(realvp); 2706 0 stevel VN_RELE(*vpp); 2707 0 stevel *vpp = realvp; 2708 7961 Natalie } else { 2709 7961 Natalie break; 2710 7961 Natalie } 2711 0 stevel /* LINTED */ 2712 0 stevel } while (TRUE); 2713 0 stevel 2714 0 stevel /* 2715 0 stevel * Let nfs_vptexi() figure what the real parent is. 2716 0 stevel */ 2717 0 stevel VN_RELE(mc_dvp); 2718 0 stevel mc_dvp = NULL; 2719 0 stevel 2720 0 stevel } else { 2721 0 stevel /* 2722 0 stevel * If vnode is covered, get the 2723 0 stevel * the topmost vnode. 2724 0 stevel */ 2725 0 stevel if (vn_mountedvfs(mc_dvp) != NULL) { 2726 0 stevel error = traverse(&mc_dvp); 2727 0 stevel if (error) { 2728 7961 Natalie VN_RELE(*vpp); 2729 7961 Natalie goto publicfh_done; 2730 0 stevel } 2731 0 stevel } 2732 0 stevel 2733 5331 amw if (VOP_REALVP(mc_dvp, &realvp, NULL) == 0 && 2734 5331 amw realvp != mc_dvp) { 2735 0 stevel /* 2736 0 stevel * *vpp is a file, obtain realvp of the parent 2737 0 stevel * directory vnode. 2738 0 stevel */ 2739 0 stevel VN_HOLD(realvp); 2740 0 stevel VN_RELE(mc_dvp); 2741 0 stevel mc_dvp = realvp; 2742 0 stevel } 2743 0 stevel } 2744 0 stevel 2745 0 stevel /* 2746 0 stevel * The pathname may take us from the public filesystem to another. 2747 0 stevel * If that's the case then just set the exportinfo to the new export 2748 0 stevel * and build filehandle for it. Thanks to per-access checking there's 2749 0 stevel * no security issues with doing this. If the client is not allowed 2750 0 stevel * access to this new export then it will get an access error when it 2751 0 stevel * tries to use the filehandle 2752 0 stevel */ 2753 0 stevel if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) { 2754 0 stevel VN_RELE(*vpp); 2755 0 stevel goto publicfh_done; 2756 0 stevel } 2757 0 stevel 2758 0 stevel /* 2759 0 stevel * Not allowed access to pseudo exports. 2760 0 stevel */ 2761 0 stevel if (PSEUDO(*exi)) { 2762 0 stevel error = ENOENT; 2763 0 stevel VN_RELE(*vpp); 2764 0 stevel goto publicfh_done; 2765 0 stevel } 2766 0 stevel 2767 0 stevel /* 2768 0 stevel * Do a lookup for the index file. We know the index option doesn't 2769 0 stevel * allow paths through handling in the share command, so mc_dvp will 2770 0 stevel * be the parent for the index file vnode, if its present. Use 2771 0 stevel * temporary pointers to preserve and reuse the vnode pointers of the 2772 0 stevel * original directory in case there's no index file. Note that the 2773 0 stevel * index file is a native path, and should not be interpreted by 2774 0 stevel * the URL parser in rfs_pathname() 2775 0 stevel */ 2776 0 stevel if (((*exi)->exi_export.ex_flags & EX_INDEX) && 2777 0 stevel ((*vpp)->v_type == VDIR) && (pathflag == URLPATH)) { 2778 0 stevel vnode_t *tvp, *tmc_dvp; /* temporary vnode pointers */ 2779 0 stevel 2780 0 stevel tmc_dvp = mc_dvp; 2781 0 stevel mc_dvp = tvp = *vpp; 2782 0 stevel 2783 0 stevel error = rfs_pathname((*exi)->exi_export.ex_index, NULL, vpp, 2784 0 stevel mc_dvp, cr, NATIVEPATH); 2785 0 stevel 2786 0 stevel if (error == ENOENT) { 2787 0 stevel *vpp = tvp; 2788 0 stevel mc_dvp = tmc_dvp; 2789 0 stevel error = 0; 2790 0 stevel } else { /* ok or error other than ENOENT */ 2791 0 stevel if (tmc_dvp) 2792 0 stevel VN_RELE(tmc_dvp); 2793 0 stevel if (error) 2794 0 stevel goto publicfh_done; 2795 0 stevel 2796 0 stevel /* 2797 0 stevel * Found a valid vp for index "filename". Sanity check 2798 0 stevel * for odd case where a directory is provided as index 2799 0 stevel * option argument and leads us to another filesystem 2800 0 stevel */ 2801 0 stevel 2802 0 stevel /* Release the reference on the old exi value */ 2803 0 stevel ASSERT(*exi != NULL); 2804 0 stevel exi_rele(*exi); 2805 0 stevel 2806 0 stevel if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) { 2807 0 stevel VN_RELE(*vpp); 2808 0 stevel goto publicfh_done; 2809 0 stevel } 2810 0 stevel } 2811 0 stevel } 2812 0 stevel 2813 0 stevel publicfh_done: 2814 0 stevel if (mc_dvp) 2815 0 stevel VN_RELE(mc_dvp); 2816 0 stevel 2817 0 stevel return (error); 2818 0 stevel } 2819 0 stevel 2820 0 stevel /* 2821 0 stevel * Evaluate a multi-component path 2822 0 stevel */ 2823 0 stevel int 2824 0 stevel rfs_pathname( 2825 0 stevel char *path, /* pathname to evaluate */ 2826 0 stevel vnode_t **dirvpp, /* ret for ptr to parent dir vnode */ 2827 0 stevel vnode_t **compvpp, /* ret for ptr to component vnode */ 2828 0 stevel vnode_t *startdvp, /* starting vnode */ 2829 0 stevel cred_t *cr, /* user's credential */ 2830 0 stevel int pathflag) /* flag to identify path, e.g. URL */ 2831 0 stevel { 2832 0 stevel char namebuf[TYPICALMAXPATHLEN]; 2833 0 stevel struct pathname pn; 2834 0 stevel int error; 2835 0 stevel 2836 0 stevel /* 2837 0 stevel * If pathname starts with '/', then set startdvp to root. 2838 0 stevel */ 2839 0 stevel if (*path == '/') { 2840 0 stevel while (*path == '/') 2841 0 stevel path++; 2842 0 stevel 2843 0 stevel startdvp = rootdir; 2844 0 stevel } 2845 0 stevel 2846 0 stevel error = pn_get_buf(path, UIO_SYSSPACE, &pn, namebuf, sizeof (namebuf)); 2847 0 stevel if (error == 0) { 2848 0 stevel /* 2849 0 stevel * Call the URL parser for URL paths to modify the original 2850 0 stevel * string to handle any '%' encoded characters that exist. 2851 0 stevel * Done here to avoid an extra bcopy in the lookup. 2852 0 stevel * We need to be careful about pathlen's. We know that 2853 0 stevel * rfs_pathname() is called with a non-empty path. However, 2854 0 stevel * it could be emptied due to the path simply being all /'s, 2855 0 stevel * which is valid to proceed with the lookup, or due to the 2856 0 stevel * URL parser finding an encoded null character at the 2857 0 stevel * beginning of path which should not proceed with the lookup. 2858 0 stevel */ 2859 0 stevel if (pn.pn_pathlen != 0 && pathflag == URLPATH) { 2860 0 stevel URLparse(pn.pn_path); 2861 0 stevel if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) 2862 0 stevel return (ENOENT); 2863 0 stevel } 2864 0 stevel VN_HOLD(startdvp); 2865 0 stevel error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp, 2866 0 stevel rootdir, startdvp, cr); 2867 0 stevel } 2868 0 stevel if (error == ENAMETOOLONG) { 2869 0 stevel /* 2870 0 stevel * This thread used a pathname > TYPICALMAXPATHLEN bytes long. 2871 0 stevel */ 2872 0 stevel if (error = pn_get(path, UIO_SYSSPACE, &pn)) 2873 0 stevel return (error); 2874 0 stevel if (pn.pn_pathlen != 0 && pathflag == URLPATH) { 2875 0 stevel URLparse(pn.pn_path); 2876 0 stevel if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) { 2877 0 stevel pn_free(&pn); 2878 0 stevel return (ENOENT); 2879 0 stevel } 2880 0 stevel } 2881 0 stevel VN_HOLD(startdvp); 2882 0 stevel error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp, 2883 0 stevel rootdir, startdvp, cr); 2884 0 stevel pn_free(&pn); 2885 0 stevel } 2886 0 stevel 2887 0 stevel return (error); 2888 0 stevel } 2889 0 stevel 2890 0 stevel /* 2891 0 stevel * Adapt the multicomponent lookup path depending on the pathtype 2892 0 stevel */ 2893 0 stevel static int 2894 0 stevel MCLpath(char **path) 2895 0 stevel { 2896 0 stevel unsigned char c = (unsigned char)**path; 2897 0 stevel 2898 0 stevel /* 2899 0 stevel * If the MCL path is between 0x20 and 0x7E (graphic printable 2900 0 stevel * character of the US-ASCII coded character set), its a URL path, 2901 0 stevel * per RFC 1738. 2902 0 stevel */ 2903 0 stevel if (c >= 0x20 && c <= 0x7E) 2904 0 stevel return (URLPATH); 2905 0 stevel 2906 0 stevel /* 2907 0 stevel * If the first octet of the MCL path is not an ASCII character 2908 0 stevel * then it must be interpreted as a tag value that describes the 2909 0 stevel * format of the remaining octets of the MCL path. 2910 0 stevel * 2911 0 stevel * If the first octet of the MCL path is 0x81 it is a query 2912 0 stevel * for the security info. 2913 0 stevel */ 2914 0 stevel switch (c) { 2915 0 stevel case 0x80: /* native path, i.e. MCL via mount protocol */ 2916 0 stevel (*path)++; 2917 0 stevel return (NATIVEPATH); 2918 0 stevel case 0x81: /* security query */ 2919 0 stevel (*path)++; 2920 0 stevel return (SECURITY_QUERY); 2921 0 stevel default: 2922 0 stevel return (-1); 2923 0 stevel } 2924 0 stevel } 2925 0 stevel 2926 0 stevel #define fromhex(c) ((c >= '0' && c <= '9') ? (c - '0') : \ 2927 0 stevel ((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\ 2928 0 stevel ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0))) 2929 0 stevel 2930 0 stevel /* 2931 5331 amw * The implementation of URLparse guarantees that the final string will 2932 0 stevel * fit in the original one. Replaces '%' occurrences followed by 2 characters 2933 0 stevel * with its corresponding hexadecimal character. 2934 0 stevel */ 2935 0 stevel static void 2936 0 stevel URLparse(char *str) 2937 0 stevel { 2938 0 stevel char *p, *q; 2939 0 stevel 2940 0 stevel p = q = str; 2941 0 stevel while (*p) { 2942 0 stevel *q = *p; 2943 0 stevel if (*p++ == '%') { 2944 0 stevel if (*p) { 2945 0 stevel *q = fromhex(*p) * 16; 2946 0 stevel p++; 2947 0 stevel if (*p) { 2948 0 stevel *q += fromhex(*p); 2949 0 stevel p++; 2950 0 stevel } 2951 0 stevel } 2952 0 stevel } 2953 0 stevel q++; 2954 0 stevel } 2955 0 stevel *q = '\0'; 2956 0 stevel } 2957 0 stevel 2958 0 stevel 2959 0 stevel /* 2960 0 stevel * Get the export information for the lookup vnode, and verify its 2961 0 stevel * useable. 2962 0 stevel */ 2963 0 stevel int 2964 0 stevel nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr, 2965 0 stevel struct exportinfo **exi) 2966 0 stevel { 2967 0 stevel int walk; 2968 0 stevel int error = 0; 2969 0 stevel 2970 0 stevel *exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE); 2971 0 stevel if (*exi == NULL) 2972 0 stevel error = EACCES; 2973 0 stevel else { 2974 0 stevel /* 2975 0 stevel * If nosub is set for this export then 2976 0 stevel * a lookup relative to the public fh 2977 0 stevel * must not terminate below the 2978 0 stevel * exported directory. 2979 0 stevel */ 2980 0 stevel if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0) 2981 0 stevel error = EACCES; 2982 0 stevel } 2983 0 stevel 2984 0 stevel return (error); 2985 0 stevel } 2986 2035 calum 2987 2035 calum /* 2988 2035 calum * Do the main work of handling HA-NFSv4 Resource Group failover on 2989 2035 calum * Sun Cluster. 2990 2035 calum * We need to detect whether any RG admin paths have been added or removed, 2991 2035 calum * and adjust resources accordingly. 2992 2035 calum * Currently we're using a very inefficient algorithm, ~ 2 * O(n**2). In 2993 2035 calum * order to scale, the list and array of paths need to be held in more 2994 2035 calum * suitable data structures. 2995 2035 calum */ 2996 2035 calum static void 2997 2035 calum hanfsv4_failover(void) 2998 2035 calum { 2999 2035 calum int i, start_grace, numadded_paths = 0; 3000 2035 calum char **added_paths = NULL; 3001 2035 calum rfs4_dss_path_t *dss_path; 3002 2035 calum 3003 2035 calum /* 3004 2390 calum * Note: currently, rfs4_dss_pathlist cannot be NULL, since 3005 2390 calum * it will always include an entry for NFS4_DSS_VAR_DIR. If we 3006 2390 calum * make the latter dynamically specified too, the following will 3007 2390 calum * need to be adjusted. 3008 2390 calum */ 3009 2390 calum 3010 2390 calum /* 3011 2035 calum * First, look for removed paths: RGs that have been failed-over 3012 2035 calum * away from this node. 3013 2035 calum * Walk the "currently-serving" rfs4_dss_pathlist and, for each 3014 2035 calum * path, check if it is on the "passed-in" rfs4_dss_newpaths array 3015 2035 calum * from nfsd. If not, that RG path has been removed. 3016 2035 calum * 3017 2035 calum * Note that nfsd has sorted rfs4_dss_newpaths for us, and removed 3018 2035 calum * any duplicates. 3019 2035 calum */ 3020 2035 calum dss_path = rfs4_dss_pathlist; 3021 2035 calum do { 3022 2035 calum int found = 0; 3023 2035 calum char *path = dss_path->path; 3024 2035 calum 3025 2035 calum /* used only for non-HA so may not be removed */ 3026 2035 calum if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) { 3027 2035 calum dss_path = dss_path->next; 3028 2035 calum continue; 3029 2035 calum } 3030 2035 calum 3031 2035 calum for (i = 0; i < rfs4_dss_numnewpaths; i++) { 3032 2035 calum int cmpret; 3033 2035 calum char *newpath = rfs4_dss_newpaths[i]; 3034 2035 calum 3035 2035 calum /* 3036 2035 calum * Since nfsd has sorted rfs4_dss_newpaths for us, 3037 2390 calum * once the return from strcmp is negative we know 3038 2035 calum * we've passed the point where "path" should be, 3039 2035 calum * and can stop searching: "path" has been removed. 3040 2035 calum */ 3041 2390 calum cmpret = strcmp(path, newpath); 3042 2035 calum if (cmpret < 0) 3043 2035 calum break; 3044 2035 calum if (cmpret == 0) { 3045 2035 calum found = 1; 3046 2035 calum break; 3047 2035 calum } 3048 2035 calum } 3049 2035 calum 3050 2035 calum if (found == 0) { 3051 2035 calum unsigned index = dss_path->index; 3052 2035 calum rfs4_servinst_t *sip = dss_path->sip; 3053 2035 calum rfs4_dss_path_t *path_next = dss_path->next; 3054 2035 calum 3055 2035 calum /* 3056 2035 calum * This path has been removed. 3057 2035 calum * We must clear out the servinst reference to 3058 2035 calum * it, since it's now owned by another 3059 2035 calum * node: we should not attempt to touch it. 3060 2035 calum */ 3061 2035 calum ASSERT(dss_path == sip->dss_paths[index]); 3062 2035 calum sip->dss_paths[index] = NULL; 3063 2035 calum 3064 2035 calum /* remove from "currently-serving" list, and destroy */ 3065 2035 calum remque(dss_path); 3066 2390 calum /* allow for NUL */ 3067 2390 calum kmem_free(dss_path->path, strlen(dss_path->path) + 1); 3068 2035 calum kmem_free(dss_path, sizeof (rfs4_dss_path_t)); 3069 2035 calum 3070 2035 calum dss_path = path_next; 3071 2035 calum } else { 3072 2035 calum /* path was found; not removed */ 3073 2035 calum dss_path = dss_path->next; 3074 2035 calum } 3075 2035 calum } while (dss_path != rfs4_dss_pathlist); 3076 2035 calum 3077 2035 calum /* 3078 2035 calum * Now, look for added paths: RGs that have been failed-over 3079 2035 calum * to this node. 3080 2035 calum * Walk the "passed-in" rfs4_dss_newpaths array from nfsd and, 3081 2035 calum * for each path, check if it is on the "currently-serving" 3082 2035 calum * rfs4_dss_pathlist. If not, that RG path has been added. 3083 2035 calum * 3084 2035 calum * Note: we don't do duplicate detection here; nfsd does that for us. 3085 2035 calum * 3086 2035 calum * Note: numadded_paths <= rfs4_dss_numnewpaths, which gives us 3087 2035 calum * an upper bound for the size needed for added_paths[numadded_paths]. 3088 2035 calum */ 3089 2035 calum 3090 2035 calum /* probably more space than we need, but guaranteed to be enough */ 3091 2035 calum if (rfs4_dss_numnewpaths > 0) { 3092 2035 calum size_t sz = rfs4_dss_numnewpaths * sizeof (char *); 3093 2035 calum added_paths = kmem_zalloc(sz, KM_SLEEP); 3094 2035 calum } 3095 2035 calum 3096 2035 calum /* walk the "passed-in" rfs4_dss_newpaths array from nfsd */ 3097 2035 calum for (i = 0; i < rfs4_dss_numnewpaths; i++) { 3098 2035 calum int found = 0; 3099 2035 calum char *newpath = rfs4_dss_newpaths[i]; 3100 2035 calum 3101 2035 calum dss_path = rfs4_dss_pathlist; 3102 2035 calum do { 3103 2035 calum char *path = dss_path->path; 3104 2035 calum 3105 2035 calum /* used only for non-HA */ 3106 2035 calum if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) { 3107 2035 calum dss_path = dss_path->next; 3108 2035 calum continue; 3109 2035 calum } 3110 2035 calum 3111 2035 calum if (strncmp(path, newpath, strlen(path)) == 0) { 3112 2035 calum found = 1; 3113 2035 calum break; 3114 2035 calum } 3115 2035 calum 3116 2035 calum dss_path = dss_path->next; 3117 2035 calum } while (dss_path != rfs4_dss_pathlist); 3118 2035 calum 3119 2035 calum if (found == 0) { 3120 2035 calum added_paths[numadded_paths] = newpath; 3121 2035 calum numadded_paths++; 3122 2035 calum } 3123 2035 calum } 3124 2035 calum 3125 2035 calum /* did we find any added paths? */ 3126 2035 calum if (numadded_paths > 0) { 3127 2035 calum /* create a new server instance, and start its grace period */ 3128 2035 calum start_grace = 1; 3129 2035 calum rfs4_servinst_create(start_grace, numadded_paths, added_paths); 3130 2035 calum 3131 2035 calum /* read in the stable storage state from these paths */ 3132 2035 calum rfs4_dss_readstate(numadded_paths, added_paths); 3133 2035 calum 3134 2035 calum /* 3135 2035 calum * Multiple failovers during a grace period will cause 3136 2035 calum * clients of the same resource group to be partitioned 3137 2035 calum * into different server instances, with different 3138 2035 calum * grace periods. Since clients of the same resource 3139 2035 calum * group must be subject to the same grace period, 3140 2035 calum * we need to reset all currently active grace periods. 3141 2035 calum */ 3142 2035 calum rfs4_grace_reset_all(); 3143 2035 calum } 3144 2035 calum 3145 2035 calum if (rfs4_dss_numnewpaths > 0) 3146 2035 calum kmem_free(added_paths, rfs4_dss_numnewpaths * sizeof (char *)); 3147 2035 calum } 3148 9871 Jarrett 3149 9871 Jarrett /* 3150 9871 Jarrett * Used by NFSv3 and NFSv4 server to query label of 3151 9871 Jarrett * a pathname component during lookup/access ops. 3152 9871 Jarrett */ 3153 9871 Jarrett ts_label_t * 3154 9871 Jarrett nfs_getflabel(vnode_t *vp, struct exportinfo *exi) 3155 9871 Jarrett { 3156 9871 Jarrett zone_t *zone; 3157 9871 Jarrett ts_label_t *zone_label; 3158 9871 Jarrett char *path; 3159 9871 Jarrett 3160 9871 Jarrett mutex_enter(&vp->v_lock); 3161 9871 Jarrett if (vp->v_path != NULL) { 3162 9871 Jarrett zone = zone_find_by_any_path(vp->v_path, B_FALSE); 3163 9871 Jarrett mutex_exit(&vp->v_lock); 3164 9871 Jarrett } else { 3165 9871 Jarrett /* 3166 9871 Jarrett * v_path not cached. Fall back on pathname of exported 3167 9871 Jarrett * file system as we rely on pathname from which we can 3168 9871 Jarrett * derive a label. The exported file system portion of 3169 9871 Jarrett * path is sufficient to obtain a label. 3170 9871 Jarrett */ 3171 9871 Jarrett path = exi->exi_export.ex_path; 3172 9871 Jarrett if (path == NULL) { 3173 9871 Jarrett mutex_exit(&vp->v_lock); 3174 9871 Jarrett return (NULL); 3175 9871 Jarrett } 3176 9871 Jarrett zone = zone_find_by_any_path(path, B_FALSE); 3177 9871 Jarrett mutex_exit(&vp->v_lock); 3178 9871 Jarrett } 3179 9871 Jarrett /* 3180 9871 Jarrett * Caller has verified that the file is either 3181 9871 Jarrett * exported or visible. So if the path falls in 3182 9871 Jarrett * global zone, admin_low is returned; otherwise 3183 9871 Jarrett * the zone's label is returned. 3184 9871 Jarrett */ 3185 9871 Jarrett zone_label = zone->zone_slabel; 3186 9871 Jarrett label_hold(zone_label); 3187 9871 Jarrett zone_rele(zone); 3188 9871 Jarrett return (zone_label); 3189 9871 Jarrett } 3190 9871 Jarrett 3191 9871 Jarrett /* 3192 9871 Jarrett * TX NFS routine used by NFSv3 and NFSv4 to do label check 3193 9871 Jarrett * on client label and server's file object lable. 3194 9871 Jarrett */ 3195 9871 Jarrett boolean_t 3196 9871 Jarrett do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag, 3197 9871 Jarrett struct exportinfo *exi) 3198 9871 Jarrett { 3199 9871 Jarrett bslabel_t *slabel; 3200 9871 Jarrett ts_label_t *tslabel; 3201 9871 Jarrett boolean_t result; 3202 9871 Jarrett 3203 9871 Jarrett if ((tslabel = nfs_getflabel(vp, exi)) == NULL) { 3204 9871 Jarrett return (B_FALSE); 3205 9871 Jarrett } 3206 9871 Jarrett slabel = label2bslabel(tslabel); 3