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