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