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 2005 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 1430 vers = req->rq_vers; 1431 1432 if (vers < min_vers || vers > max_vers) { 1433 svcerr_progvers(req->rq_xprt, min_vers, max_vers); 1434 error++; 1435 cmn_err(CE_NOTE, "%s: bad version number %u", pgmname, vers); 1436 goto done; 1437 } 1438 vers -= min_vers; 1439 1440 which = req->rq_proc; 1441 if (which < 0 || which >= disptable[(int)vers].dis_nprocs) { 1442 svcerr_noproc(req->rq_xprt); 1443 error++; 1444 goto done; 1445 } 1446 1447 (*(disptable[(int)vers].dis_proccntp))[which].value.ui64++; 1448 1449 disp = &disptable[(int)vers].dis_table[which]; 1450 1451 auth_flavor = req->rq_cred.oa_flavor; 1452 /* 1453 * Deserialize into the args struct. 1454 */ 1455 1456 args = (char *)&args_buf; 1457 1458 #ifdef DEBUG 1459 if (rfs_no_fast_xdrargs || (auth_flavor == RPCSEC_GSS) || 1460 disp->dis_fastxdrargs == NULL_xdrproc_t || 1461 !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args)) { 1462 #else 1463 if ((auth_flavor == RPCSEC_GSS) || 1464 disp->dis_fastxdrargs == NULL_xdrproc_t || 1465 !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args)) { 1466 #endif 1467 bzero(args, disp->dis_argsz); 1468 if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) { 1469 svcerr_decode(xprt); 1470 error++; 1471 cmn_err(CE_NOTE, "%s: bad getargs for %u/%d", 1472 pgmname, vers + min_vers, which); 1473 goto done; 1474 } 1475 } 1476 1477 /* 1478 * If Version 4 use that specific dispatch function. 1479 */ 1480 if (req->rq_vers == 4) { 1481 error += rfs4_dispatch(disp, req, xprt, args); 1482 goto done; 1483 } 1484 1485 dis_flags = disp->dis_flags; 1486 1487 /* 1488 * Find export information and check authentication, 1489 * setting the credential if everything is ok. 1490 */ 1491 if (disp->dis_getfh != NULL) { 1492 fhandle_t *fh; 1493 1494 fh = (*disp->dis_getfh)(args); 1495 1496 /* 1497 * Fix for bug 1038302 - corbin 1498 * There is a problem here if anonymous access is 1499 * disallowed. If the current request is part of the 1500 * client's mount process for the requested filesystem, 1501 * then it will carry root (uid 0) credentials on it, and 1502 * will be denied by checkauth if that client does not 1503 * have explicit root=0 permission. This will cause the 1504 * client's mount operation to fail. As a work-around, 1505 * we check here to see if the request is a getattr or 1506 * statfs operation on the exported vnode itself, and 1507 * pass a flag to checkauth with the result of this test. 1508 * 1509 * The filehandle refers to the mountpoint itself if 1510 * the fh_data and fh_xdata portions of the filehandle 1511 * are equal. 1512 * 1513 * Added anon_ok argument to checkauth(). 1514 */ 1515 1516 if ((dis_flags & RPC_ALLOWANON) && 1517 EQFID((fid_t *)&fh->fh_len, (fid_t *)&fh->fh_xlen)) 1518 anon_ok = 1; 1519 else 1520 anon_ok = 0; 1521 1522 cr = xprt->xp_cred; 1523 ASSERT(cr != NULL); 1524 #ifdef DEBUG 1525 if (crgetref(cr) != 1) { 1526 crfree(cr); 1527 cr = crget(); 1528 xprt->xp_cred = cr; 1529 cred_misses++; 1530 } else 1531 cred_hits++; 1532 #else 1533 if (crgetref(cr) != 1) { 1534 crfree(cr); 1535 cr = crget(); 1536 xprt->xp_cred = cr; 1537 } 1538 #endif 1539 1540 exi = checkexport(&fh->fh_fsid, (fid_t *)&fh->fh_xlen); 1541 1542 if (exi != NULL) { 1543 publicfh_ok = PUBLICFH_CHECK(disp, exi, fh); 1544 1545 /* 1546 * Don't allow non-V4 clients access 1547 * to pseudo exports 1548 */ 1549 if (PSEUDO(exi)) { 1550 svcerr_weakauth(xprt); 1551 error++; 1552 goto done; 1553 } 1554 1555 authres = checkauth(exi, req, cr, anon_ok, publicfh_ok); 1556 /* 1557 * authres > 0: authentication OK - proceed 1558 * authres == 0: authentication weak - return error 1559 * authres < 0: authentication timeout - drop 1560 */ 1561 if (authres <= 0) { 1562 if (authres == 0) { 1563 svcerr_weakauth(xprt); 1564 error++; 1565 } 1566 goto done; 1567 } 1568 } 1569 } else 1570 cr = NULL; 1571 1572 if ((dis_flags & RPC_MAPRESP) && (auth_flavor != RPCSEC_GSS)) { 1573 res = (char *)SVC_GETRES(xprt, disp->dis_ressz); 1574 if (res == NULL) 1575 res = (char *)&res_buf; 1576 } else 1577 res = (char *)&res_buf; 1578 1579 if (!(dis_flags & RPC_IDEMPOTENT)) { 1580 dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr, 1581 &dupcached); 1582 1583 switch (dupstat) { 1584 case DUP_ERROR: 1585 svcerr_systemerr(xprt); 1586 error++; 1587 goto done; 1588 /* NOTREACHED */ 1589 case DUP_INPROGRESS: 1590 if (res != (char *)&res_buf) 1591 SVC_FREERES(xprt); 1592 error++; 1593 goto done; 1594 /* NOTREACHED */ 1595 case DUP_NEW: 1596 case DUP_DROP: 1597 curthread->t_flag |= T_DONTPEND; 1598 1599 (*disp->dis_proc)(args, res, exi, req, cr); 1600 1601 curthread->t_flag &= ~T_DONTPEND; 1602 if (curthread->t_flag & T_WOULDBLOCK) { 1603 curthread->t_flag &= ~T_WOULDBLOCK; 1604 SVC_DUPDONE_EXT(xprt, dr, res, NULL, 1605 disp->dis_ressz, DUP_DROP); 1606 if (res != (char *)&res_buf) 1607 SVC_FREERES(xprt); 1608 error++; 1609 goto done; 1610 } 1611 if (dis_flags & RPC_AVOIDWORK) { 1612 SVC_DUPDONE_EXT(xprt, dr, res, NULL, 1613 disp->dis_ressz, DUP_DROP); 1614 } else { 1615 SVC_DUPDONE_EXT(xprt, dr, res, 1616 disp->dis_resfree == nullfree ? NULL : 1617 disp->dis_resfree, 1618 disp->dis_ressz, DUP_DONE); 1619 dupcached = TRUE; 1620 } 1621 break; 1622 case DUP_DONE: 1623 break; 1624 } 1625 1626 } else { 1627 curthread->t_flag |= T_DONTPEND; 1628 1629 (*disp->dis_proc)(args, res, exi, req, cr); 1630 1631 curthread->t_flag &= ~T_DONTPEND; 1632 if (curthread->t_flag & T_WOULDBLOCK) { 1633 curthread->t_flag &= ~T_WOULDBLOCK; 1634 if (res != (char *)&res_buf) 1635 SVC_FREERES(xprt); 1636 error++; 1637 goto done; 1638 } 1639 } 1640 1641 if (auth_tooweak(req, res)) { 1642 svcerr_weakauth(xprt); 1643 error++; 1644 goto done; 1645 } 1646 1647 /* 1648 * Check to see if logging has been enabled on the server. 1649 * If so, then obtain the export info struct to be used for 1650 * the later writing of the log record. This is done for 1651 * the case that a lookup is done across a non-logged public 1652 * file system. 1653 */ 1654 if (nfslog_buffer_list != NULL) { 1655 nfslog_exi = nfslog_get_exi(exi, req, res, &nfslog_rec_id); 1656 /* 1657 * Is logging enabled? 1658 */ 1659 logging_enabled = (nfslog_exi != NULL); 1660 1661 /* 1662 * Copy the netbuf for logging purposes, before it is 1663 * freed by svc_sendreply(). 1664 */ 1665 if (logging_enabled) { 1666 NFSLOG_COPY_NETBUF(nfslog_exi, xprt, &nb); 1667 /* 1668 * If RPC_MAPRESP flag set (i.e. in V2 ops) the 1669 * res gets copied directly into the mbuf and 1670 * may be freed soon after the sendreply. So we 1671 * must copy it here to a safe place... 1672 */ 1673 if (res != (char *)&res_buf) { 1674 bcopy(res, (char *)&res_buf, disp->dis_ressz); 1675 } 1676 } 1677 } 1678 1679 /* 1680 * Serialize and send results struct 1681 */ 1682 #ifdef DEBUG 1683 if (rfs_no_fast_xdrres == 0 && res != (char *)&res_buf) { 1684 #else 1685 if (res != (char *)&res_buf) { 1686 #endif 1687 if (!svc_sendreply(xprt, disp->dis_fastxdrres, res)) { 1688 cmn_err(CE_NOTE, "%s: bad sendreply", pgmname); 1689 error++; 1690 } 1691 } else { 1692 if (!svc_sendreply(xprt, disp->dis_xdrres, res)) { 1693 cmn_err(CE_NOTE, "%s: bad sendreply", pgmname); 1694 error++; 1695 } 1696 } 1697 1698 /* 1699 * Log if needed 1700 */ 1701 if (logging_enabled) { 1702 nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf, 1703 cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER); 1704 exi_rele(nfslog_exi); 1705 kmem_free((&nb)->buf, (&nb)->len); 1706 } 1707 1708 /* 1709 * Free results struct. With the addition of NFS V4 we can 1710 * have non-idempotent procedures with functions. 1711 */ 1712 if (disp->dis_resfree != nullfree && dupcached == FALSE) { 1713 (*disp->dis_resfree)(res); 1714 } 1715 1716 done: 1717 /* 1718 * Free arguments struct 1719 */ 1720 if (disp) { 1721 if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) { 1722 cmn_err(CE_NOTE, "%s: bad freeargs", pgmname); 1723 error++; 1724 } 1725 } else { 1726 if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) { 1727 cmn_err(CE_NOTE, "%s: bad freeargs", pgmname); 1728 error++; 1729 } 1730 } 1731 1732 if (exi != NULL) 1733 exi_rele(exi); 1734 1735 global_svstat_ptr[req->rq_vers][NFS_BADCALLS].value.ui64 += error; 1736 1737 global_svstat_ptr[req->rq_vers][NFS_CALLS].value.ui64++; 1738 } 1739 1740 static void 1741 rfs_dispatch(struct svc_req *req, SVCXPRT *xprt) 1742 { 1743 common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX, 1744 "nfs_server", rfs_disptable); 1745 } 1746 1747 static char *aclcallnames_v2[] = { 1748 "ACL2_NULL", 1749 "ACL2_GETACL", 1750 "ACL2_SETACL", 1751 "ACL2_GETATTR", 1752 "ACL2_ACCESS", 1753 "ACL2_GETXATTRDIR" 1754 }; 1755 1756 static struct rpcdisp acldisptab_v2[] = { 1757 /* 1758 * ACL VERSION 2 1759 */ 1760 1761 /* ACL2_NULL = 0 */ 1762 {rpc_null, 1763 xdr_void, NULL_xdrproc_t, 0, 1764 xdr_void, NULL_xdrproc_t, 0, 1765 nullfree, RPC_IDEMPOTENT, 1766 0}, 1767 1768 /* ACL2_GETACL = 1 */ 1769 {acl2_getacl, 1770 xdr_GETACL2args, xdr_fastGETACL2args, sizeof (GETACL2args), 1771 xdr_GETACL2res, NULL_xdrproc_t, sizeof (GETACL2res), 1772 acl2_getacl_free, RPC_IDEMPOTENT, 1773 acl2_getacl_getfh}, 1774 1775 /* ACL2_SETACL = 2 */ 1776 {acl2_setacl, 1777 xdr_SETACL2args, NULL_xdrproc_t, sizeof (SETACL2args), 1778 #ifdef _LITTLE_ENDIAN 1779 xdr_SETACL2res, xdr_fastSETACL2res, sizeof (SETACL2res), 1780 #else 1781 xdr_SETACL2res, NULL_xdrproc_t, sizeof (SETACL2res), 1782 #endif 1783 nullfree, RPC_MAPRESP, 1784 acl2_setacl_getfh}, 1785 1786 /* ACL2_GETATTR = 3 */ 1787 {acl2_getattr, 1788 xdr_GETATTR2args, xdr_fastGETATTR2args, sizeof (GETATTR2args), 1789 #ifdef _LITTLE_ENDIAN 1790 xdr_GETATTR2res, xdr_fastGETATTR2res, sizeof (GETATTR2res), 1791 #else 1792 xdr_GETATTR2res, NULL_xdrproc_t, sizeof (GETATTR2res), 1793 #endif 1794 nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP, 1795 acl2_getattr_getfh}, 1796 1797 /* ACL2_ACCESS = 4 */ 1798 {acl2_access, 1799 xdr_ACCESS2args, xdr_fastACCESS2args, sizeof (ACCESS2args), 1800 #ifdef _LITTLE_ENDIAN 1801 xdr_ACCESS2res, xdr_fastACCESS2res, sizeof (ACCESS2res), 1802 #else 1803 xdr_ACCESS2res, NULL_xdrproc_t, sizeof (ACCESS2res), 1804 #endif 1805 nullfree, RPC_IDEMPOTENT|RPC_MAPRESP, 1806 acl2_access_getfh}, 1807 1808 /* ACL2_GETXATTRDIR = 5 */ 1809 {acl2_getxattrdir, 1810 xdr_GETXATTRDIR2args, NULL_xdrproc_t, sizeof (GETXATTRDIR2args), 1811 xdr_GETXATTRDIR2res, NULL_xdrproc_t, sizeof (GETXATTRDIR2res), 1812 nullfree, RPC_IDEMPOTENT, 1813 acl2_getxattrdir_getfh}, 1814 }; 1815 1816 static char *aclcallnames_v3[] = { 1817 "ACL3_NULL", 1818 "ACL3_GETACL", 1819 "ACL3_SETACL", 1820 "ACL3_GETXATTRDIR" 1821 }; 1822 1823 static struct rpcdisp acldisptab_v3[] = { 1824 /* 1825 * ACL VERSION 3 1826 */ 1827 1828 /* ACL3_NULL = 0 */ 1829 {rpc_null, 1830 xdr_void, NULL_xdrproc_t, 0, 1831 xdr_void, NULL_xdrproc_t, 0, 1832 nullfree, RPC_IDEMPOTENT, 1833 0}, 1834 1835 /* ACL3_GETACL = 1 */ 1836 {acl3_getacl, 1837 xdr_GETACL3args, NULL_xdrproc_t, sizeof (GETACL3args), 1838 xdr_GETACL3res, NULL_xdrproc_t, sizeof (GETACL3res), 1839 acl3_getacl_free, RPC_IDEMPOTENT, 1840 acl3_getacl_getfh}, 1841 1842 /* ACL3_SETACL = 2 */ 1843 {acl3_setacl, 1844 xdr_SETACL3args, NULL_xdrproc_t, sizeof (SETACL3args), 1845 xdr_SETACL3res, NULL_xdrproc_t, sizeof (SETACL3res), 1846 nullfree, 0, 1847 acl3_setacl_getfh}, 1848 1849 /* ACL3_GETXATTRDIR = 3 */ 1850 {acl3_getxattrdir, 1851 xdr_GETXATTRDIR3args, NULL_xdrproc_t, sizeof (GETXATTRDIR3args), 1852 xdr_GETXATTRDIR3res, NULL_xdrproc_t, sizeof (GETXATTRDIR3res), 1853 nullfree, RPC_IDEMPOTENT, 1854 acl3_getxattrdir_getfh}, 1855 }; 1856 1857 static struct rpc_disptable acl_disptable[] = { 1858 {sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]), 1859 aclcallnames_v2, 1860 &aclproccnt_v2_ptr, acldisptab_v2}, 1861 {sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]), 1862 aclcallnames_v3, 1863 &aclproccnt_v3_ptr, acldisptab_v3}, 1864 }; 1865 1866 static void 1867 acl_dispatch(struct svc_req *req, SVCXPRT *xprt) 1868 { 1869 common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, 1870 "acl_server", acl_disptable); 1871 } 1872 1873 int 1874 checkwin(int flavor, int window, struct svc_req *req) 1875 { 1876 struct authdes_cred *adc; 1877 1878 switch (flavor) { 1879 case AUTH_DES: 1880 adc = (struct authdes_cred *)req->rq_clntcred; 1881 if (adc->adc_fullname.window > window) 1882 return (0); 1883 break; 1884 1885 default: 1886 break; 1887 } 1888 return (1); 1889 } 1890 1891 1892 /* 1893 * checkauth() will check the access permission against the export 1894 * information. Then map root uid/gid to appropriate uid/gid. 1895 * 1896 * This routine is used by NFS V3 and V2 code. 1897 */ 1898 static int 1899 checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok, 1900 bool_t publicfh_ok) 1901 { 1902 int i, nfsflavor, rpcflavor, stat, access; 1903 struct secinfo *secp; 1904 caddr_t principal; 1905 char buf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */ 1906 int anon_res = 0; 1907 1908 /* 1909 * Check for privileged port number 1910 * N.B.: this assumes that we know the format of a netbuf. 1911 */ 1912 if (nfs_portmon) { 1913 struct sockaddr *ca; 1914 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1915 1916 if (ca == NULL) 1917 return (0); 1918 1919 if ((ca->sa_family == AF_INET && 1920 ntohs(((struct sockaddr_in *)ca)->sin_port) >= 1921 IPPORT_RESERVED) || 1922 (ca->sa_family == AF_INET6 && 1923 ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >= 1924 IPPORT_RESERVED)) { 1925 cmn_err(CE_NOTE, 1926 "nfs_server: client %s%ssent NFS request from " 1927 "unprivileged port", 1928 client_name(req), client_addr(req, buf)); 1929 return (0); 1930 } 1931 } 1932 1933 /* 1934 * return 1 on success or 0 on failure 1935 */ 1936 stat = sec_svc_getcred(req, cr, &principal, &nfsflavor); 1937 1938 /* 1939 * A failed AUTH_UNIX svc_get_cred() implies we couldn't set 1940 * the credentials; below we map that to anonymous. 1941 */ 1942 if (!stat && nfsflavor != AUTH_UNIX) { 1943 cmn_err(CE_NOTE, 1944 "nfs_server: couldn't get unix cred for %s", 1945 client_name(req)); 1946 return (0); 1947 } 1948 1949 /* 1950 * Short circuit checkauth() on operations that support the 1951 * public filehandle, and if the request for that operation 1952 * is using the public filehandle. Note that we must call 1953 * sec_svc_getcred() first so that xp_cookie is set to the 1954 * right value. Normally xp_cookie is just the RPC flavor 1955 * of the the request, but in the case of RPCSEC_GSS it 1956 * could be a pseudo flavor. 1957 */ 1958 if (publicfh_ok) 1959 return (1); 1960 1961 rpcflavor = req->rq_cred.oa_flavor; 1962 /* 1963 * Check if the auth flavor is valid for this export 1964 */ 1965 access = nfsauth_access(exi, req); 1966 if (access & NFSAUTH_DROP) 1967 return (-1); /* drop the request */ 1968 1969 if (access & NFSAUTH_DENIED) { 1970 /* 1971 * If anon_ok == 1 and we got NFSAUTH_DENIED, it was 1972 * probably due to the flavor not matching during the 1973 * the mount attempt. So map the flavor to AUTH_NONE 1974 * so that the credentials get mapped to the anonymous 1975 * user. 1976 */ 1977 if (anon_ok == 1) 1978 rpcflavor = AUTH_NONE; 1979 else 1980 return (0); /* deny access */ 1981 1982 } else if (access & NFSAUTH_MAPNONE) { 1983 /* 1984 * Access was granted even though the flavor mismatched 1985 * because AUTH_NONE was one of the exported flavors. 1986 */ 1987 rpcflavor = AUTH_NONE; 1988 1989 } else if (access & NFSAUTH_WRONGSEC) { 1990 /* 1991 * NFSAUTH_WRONGSEC is used for NFSv4. Since V2/V3 already 1992 * negotiates the security flavor thru MOUNT protocol, the 1993 * only way it can get NFSAUTH_WRONGSEC here is from 1994 * NFS_ACL for V4. This could be for a limited view, so 1995 * map it to RO access. V4 lookup/readdir will take care 1996 * of the limited view portion. 1997 */ 1998 access |= NFSAUTH_RO; 1999 access &= ~NFSAUTH_WRONGSEC; 2000 } 2001 2002 switch (rpcflavor) { 2003 case AUTH_NONE: 2004 anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2005 exi->exi_export.ex_anon); 2006 (void) crsetgroups(cr, 0, NULL); 2007 break; 2008 2009 case AUTH_UNIX: 2010 if (!stat || crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) { 2011 anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2012 exi->exi_export.ex_anon); 2013 (void) crsetgroups(cr, 0, NULL); 2014 } 2015 break; 2016 2017 case AUTH_DES: 2018 case RPCSEC_GSS: 2019 /* 2020 * Find the secinfo structure. We should be able 2021 * to find it by the time we reach here. 2022 * nfsauth_access() has done the checking. 2023 */ 2024 secp = NULL; 2025 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 2026 if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum == 2027 nfsflavor) { 2028 secp = &exi->exi_export.ex_secinfo[i]; 2029 break; 2030 } 2031 } 2032 2033 if (!secp) { 2034 cmn_err(CE_NOTE, "nfs_server: client %s%shad " 2035 "no secinfo data for flavor %d", 2036 client_name(req), client_addr(req, buf), 2037 nfsflavor); 2038 return (0); 2039 } 2040 2041 if (!checkwin(rpcflavor, secp->s_window, req)) { 2042 cmn_err(CE_NOTE, 2043 "nfs_server: client %s%sused invalid " 2044 "auth window value", 2045 client_name(req), client_addr(req, buf)); 2046 return (0); 2047 } 2048 2049 /* 2050 * Map root principals listed in the share's root= list to root, 2051 * and map any others principals that were mapped to root by RPC 2052 * to anon. 2053 */ 2054 if (principal && sec_svc_inrootlist(rpcflavor, principal, 2055 secp->s_rootcnt, secp->s_rootnames)) { 2056 if (crgetuid(cr) == 0) 2057 return (1); 2058 2059 (void) crsetugid(cr, 0, 0); 2060 2061 /* 2062 * NOTE: If and when kernel-land privilege tracing is 2063 * added this may have to be replaced with code that 2064 * retrieves root's supplementary groups (e.g., using 2065 * kgss_get_group_info(). In the meantime principals 2066 * mapped to uid 0 get all privileges, so setting cr's 2067 * supplementary groups for them does nothing. 2068 */ 2069 (void) crsetgroups(cr, 0, NULL); 2070 2071 return (1); 2072 } 2073 2074 /* 2075 * Not a root princ, or not in root list, map UID 0/nobody to 2076 * the anon ID for the share. (RPC sets cr's UIDs and GIDs to 2077 * UID_NOBODY and GID_NOBODY, respectively.) 2078 */ 2079 if (crgetuid(cr) != 0 && 2080 (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY)) 2081 return (1); 2082 2083 anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2084 exi->exi_export.ex_anon); 2085 (void) crsetgroups(cr, 0, NULL); 2086 break; 2087 default: 2088 return (0); 2089 } /* switch on rpcflavor */ 2090 2091 /* 2092 * Even if anon access is disallowed via ex_anon == -1, we allow 2093 * this access if anon_ok is set. So set creds to the default 2094 * "nobody" id. 2095 */ 2096 if (anon_res != 0) { 2097 if (anon_ok == 0) { 2098 cmn_err(CE_NOTE, 2099 "nfs_server: client %s%ssent wrong " 2100 "authentication for %s", 2101 client_name(req), client_addr(req, buf), 2102 exi->exi_export.ex_path ? 2103 exi->exi_export.ex_path : "?"); 2104 return (0); 2105 } 2106 2107 if (crsetugid(cr, UID_NOBODY, GID_NOBODY) != 0) 2108 return (0); 2109 } 2110 2111 return (1); 2112 } 2113 2114 /* 2115 * returns 0 on failure, -1 on a drop, -2 on wrong security flavor, 2116 * and 1 on success 2117 */ 2118 int 2119 checkauth4(struct compound_state *cs, struct svc_req *req) 2120 { 2121 int i, rpcflavor, access; 2122 struct secinfo *secp; 2123 char buf[MAXHOST + 1]; 2124 int anon_res = 0, nfsflavor; 2125 struct exportinfo *exi; 2126 cred_t *cr; 2127 caddr_t principal; 2128 2129 exi = cs->exi; 2130 cr = cs->cr; 2131 principal = cs->principal; 2132 nfsflavor = cs->nfsflavor; 2133 2134 ASSERT(cr != NULL); 2135 2136 rpcflavor = req->rq_cred.oa_flavor; 2137 cs->access &= ~CS_ACCESS_LIMITED; 2138 2139 /* 2140 * Check the access right per auth flavor on the vnode of 2141 * this export for the given request. 2142 */ 2143 access = nfsauth4_access(cs->exi, cs->vp, req); 2144 2145 if (access & NFSAUTH_WRONGSEC) 2146 return (-2); /* no access for this security flavor */ 2147 2148 if (access & NFSAUTH_DROP) 2149 return (-1); /* drop the request */ 2150 2151 if (access & NFSAUTH_DENIED) { 2152 2153 if (exi->exi_export.ex_seccnt > 0) 2154 return (0); /* deny access */ 2155 2156 } else if (access & NFSAUTH_LIMITED) { 2157 2158 cs->access |= CS_ACCESS_LIMITED; 2159 2160 } else if (access & NFSAUTH_MAPNONE) { 2161 /* 2162 * Access was granted even though the flavor mismatched 2163 * because AUTH_NONE was one of the exported flavors. 2164 */ 2165 rpcflavor = AUTH_NONE; 2166 } 2167 2168 /* 2169 * XXX probably need to redo some of it for nfsv4? 2170 * return 1 on success or 0 on failure 2171 */ 2172 2173 switch (rpcflavor) { 2174 case AUTH_NONE: 2175 anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2176 exi->exi_export.ex_anon); 2177 (void) crsetgroups(cr, 0, NULL); 2178 break; 2179 2180 case AUTH_UNIX: 2181 if (crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) { 2182 anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2183 exi->exi_export.ex_anon); 2184 (void) crsetgroups(cr, 0, NULL); 2185 } 2186 break; 2187 2188 default: 2189 /* 2190 * Find the secinfo structure. We should be able 2191 * to find it by the time we reach here. 2192 * nfsauth_access() has done the checking. 2193 */ 2194 secp = NULL; 2195 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 2196 if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum == 2197 nfsflavor) { 2198 secp = &exi->exi_export.ex_secinfo[i]; 2199 break; 2200 } 2201 } 2202 2203 if (!secp) { 2204 cmn_err(CE_NOTE, "nfs_server: client %s%shad " 2205 "no secinfo data for flavor %d", 2206 client_name(req), client_addr(req, buf), 2207 nfsflavor); 2208 return (0); 2209 } 2210 2211 if (!checkwin(rpcflavor, secp->s_window, req)) { 2212 cmn_err(CE_NOTE, 2213 "nfs_server: client %s%sused invalid " 2214 "auth window value", 2215 client_name(req), client_addr(req, buf)); 2216 return (0); 2217 } 2218 2219 /* 2220 * Map root principals listed in the share's root= list to root, 2221 * and map any others principals that were mapped to root by RPC 2222 * to anon. 2223 */ 2224 if (principal && sec_svc_inrootlist(rpcflavor, principal, 2225 secp->s_rootcnt, secp->s_rootnames)) { 2226 if (crgetuid(cr) == 0) 2227 return (1); 2228 2229 (void) crsetugid(cr, 0, 0); 2230 2231 /* 2232 * NOTE: If and when kernel-land privilege tracing is 2233 * added this may have to be replaced with code that 2234 * retrieves root's supplementary groups (e.g., using 2235 * kgss_get_group_info(). In the meantime principals 2236 * mapped to uid 0 get all privileges, so setting cr's 2237 * supplementary groups for them does nothing. 2238 */ 2239 (void) crsetgroups(cr, 0, NULL); 2240 2241 return (1); 2242 } 2243 2244 /* 2245 * Not a root princ, or not in root list, map UID 0/nobody to 2246 * the anon ID for the share. (RPC sets cr's UIDs and GIDs to 2247 * UID_NOBODY and GID_NOBODY, respectively.) 2248 */ 2249 if (crgetuid(cr) != 0 && 2250 (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY)) 2251 return (1); 2252 2253 anon_res = crsetugid(cr, exi->exi_export.ex_anon, 2254 exi->exi_export.ex_anon); 2255 (void) crsetgroups(cr, 0, NULL); 2256 break; 2257 } /* switch on rpcflavor */ 2258 2259 /* 2260 * Even if anon access is disallowed via ex_anon == -1, we allow 2261 * this access if anon_ok is set. So set creds to the default 2262 * "nobody" id. 2263 */ 2264 2265 if (anon_res != 0) { 2266 cmn_err(CE_NOTE, 2267 "nfs_server: client %s%ssent wrong " 2268 "authentication for %s", 2269 client_name(req), client_addr(req, buf), 2270 exi->exi_export.ex_path ? 2271 exi->exi_export.ex_path : "?"); 2272 return (0); 2273 } 2274 2275 return (1); 2276 } 2277 2278 2279 static char * 2280 client_name(struct svc_req *req) 2281 { 2282 char *hostname = NULL; 2283 2284 /* 2285 * If it's a Unix cred then use the 2286 * hostname from the credential. 2287 */ 2288 if (req->rq_cred.oa_flavor == AUTH_UNIX) { 2289 hostname = ((struct authunix_parms *) 2290 req->rq_clntcred)->aup_machname; 2291 } 2292 if (hostname == NULL) 2293 hostname = ""; 2294 2295 return (hostname); 2296 } 2297 2298 static char * 2299 client_addr(struct svc_req *req, char *buf) 2300 { 2301 struct sockaddr *ca; 2302 uchar_t *b; 2303 char *frontspace = ""; 2304 2305 /* 2306 * We assume we are called in tandem with client_name and the 2307 * format string looks like "...client %s%sblah blah..." 2308 * 2309 * If it's a Unix cred then client_name returned 2310 * a host name, so we need insert a space between host name 2311 * and IP address. 2312 */ 2313 if (req->rq_cred.oa_flavor == AUTH_UNIX) 2314 frontspace = " "; 2315 2316 /* 2317 * Convert the caller's IP address to a dotted string 2318 */ 2319 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2320 2321 if (ca->sa_family == AF_INET) { 2322 b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr; 2323 (void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace, 2324 b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF); 2325 } else if (ca->sa_family == AF_INET6) { 2326 struct sockaddr_in6 *sin6; 2327 sin6 = (struct sockaddr_in6 *)ca; 2328 (void) kinet_ntop6((uchar_t *)&sin6->sin6_addr, 2329 buf, INET6_ADDRSTRLEN); 2330 2331 } else { 2332 2333 /* 2334 * No IP address to print. If there was a host name 2335 * printed, then we print a space. 2336 */ 2337 (void) sprintf(buf, frontspace); 2338 } 2339 2340 return (buf); 2341 } 2342 2343 /* 2344 * NFS Server initialization routine. This routine should only be called 2345 * once. It performs the following tasks: 2346 * - Call sub-initialization routines (localize access to variables) 2347 * - Initialize all locks 2348 * - initialize the version 3 write verifier 2349 */ 2350 int 2351 nfs_srvinit(void) 2352 { 2353 int error; 2354 2355 error = nfs_exportinit(); 2356 if (error != 0) 2357 return (error); 2358 error = rfs4_srvrinit(); 2359 if (error != 0) { 2360 nfs_exportfini(); 2361 return (error); 2362 } 2363 rfs_srvrinit(); 2364 rfs3_srvrinit(); 2365 nfsauth_init(); 2366 2367 /* Init the stuff to control start/stop */ 2368 nfs_server_upordown = NFS_SERVER_STOPPED; 2369 mutex_init(&nfs_server_upordown_lock, NULL, MUTEX_DEFAULT, NULL); 2370 cv_init(&nfs_server_upordown_cv, NULL, CV_DEFAULT, NULL); 2371 mutex_init(&rdma_wait_mutex, NULL, MUTEX_DEFAULT, NULL); 2372 cv_init(&rdma_wait_cv, NULL, CV_DEFAULT, NULL); 2373 2374 return (0); 2375 } 2376 2377 /* 2378 * NFS Server finalization routine. This routine is called to cleanup the 2379 * initialization work previously performed if the NFS server module could 2380 * not be loaded correctly. 2381 */ 2382 void 2383 nfs_srvfini(void) 2384 { 2385 nfsauth_fini(); 2386 rfs3_srvrfini(); 2387 rfs_srvrfini(); 2388 nfs_exportfini(); 2389 2390 mutex_destroy(&nfs_server_upordown_lock); 2391 cv_destroy(&nfs_server_upordown_cv); 2392 mutex_destroy(&rdma_wait_mutex); 2393 cv_destroy(&rdma_wait_cv); 2394 } 2395 2396 /* 2397 * Set up an iovec array of up to cnt pointers. 2398 */ 2399 2400 void 2401 mblk_to_iov(mblk_t *m, int cnt, struct iovec *iovp) 2402 { 2403 while (m != NULL && cnt-- > 0) { 2404 iovp->iov_base = (caddr_t)m->b_rptr; 2405 iovp->iov_len = (m->b_wptr - m->b_rptr); 2406 iovp++; 2407 m = m->b_cont; 2408 } 2409 } 2410 2411 /* 2412 * Common code between NFS Version 2 and NFS Version 3 for the public 2413 * filehandle multicomponent lookups. 2414 */ 2415 2416 /* 2417 * Public filehandle evaluation of a multi-component lookup, following 2418 * symbolic links, if necessary. This may result in a vnode in another 2419 * filesystem, which is OK as long as the other filesystem is exported. 2420 * 2421 * Note that the exi will be set either to NULL or a new reference to the 2422 * exportinfo struct that corresponds to the vnode of the multi-component path. 2423 * It is the callers responsibility to release this reference. 2424 */ 2425 int 2426 rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp, 2427 struct exportinfo **exi, struct sec_ol *sec) 2428 { 2429 int pathflag; 2430 vnode_t *mc_dvp = NULL; 2431 vnode_t *realvp; 2432 int error; 2433 2434 *exi = NULL; 2435 2436 /* 2437 * check if the given path is a url or native path. Since p is 2438 * modified by MCLpath(), it may be empty after returning from 2439 * there, and should be checked. 2440 */ 2441 if ((pathflag = MCLpath(&p)) == -1) 2442 return (EIO); 2443 2444 /* 2445 * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit 2446 * on in sec->sec_flags. This bit will later serve as an 2447 * indication in makefh_ol() or makefh3_ol() to overload the 2448 * filehandle to contain the sec modes used by the server for 2449 * the path. 2450 */ 2451 if (pathflag == SECURITY_QUERY) { 2452 if ((sec->sec_index = (uint_t)(*p)) > 0) { 2453 sec->sec_flags |= SEC_QUERY; 2454 p++; 2455 if ((pathflag = MCLpath(&p)) == -1) 2456 return (EIO); 2457 } else { 2458 cmn_err(CE_NOTE, 2459 "nfs_server: invalid security index %d, " 2460 "violating WebNFS SNEGO protocol.", sec->sec_index); 2461 return (EIO); 2462 } 2463 } 2464 2465 if (p[0] == '\0') { 2466 error = ENOENT; 2467 goto publicfh_done; 2468 } 2469 2470 error = rfs_pathname(p, &mc_dvp, vpp, dvp, cr, pathflag); 2471 2472 /* 2473 * If name resolves to "/" we get EINVAL since we asked for 2474 * the vnode of the directory that the file is in. Try again 2475 * with NULL directory vnode. 2476 */ 2477 if (error == EINVAL) { 2478 error = rfs_pathname(p, NULL, vpp, dvp, cr, pathflag); 2479 if (!error) { 2480 ASSERT(*vpp != NULL); 2481 if ((*vpp)->v_type == VDIR) { 2482 VN_HOLD(*vpp); 2483 mc_dvp = *vpp; 2484 } else { 2485 /* 2486 * This should not happen, the filesystem is 2487 * in an inconsistent state. Fail the lookup 2488 * at this point. 2489 */ 2490 VN_RELE(*vpp); 2491 error = EINVAL; 2492 } 2493 } 2494 } 2495 2496 if (error) 2497 goto publicfh_done; 2498 2499 if (*vpp == NULL) { 2500 error = ENOENT; 2501 goto publicfh_done; 2502 } 2503 2504 ASSERT(mc_dvp != NULL); 2505 ASSERT(*vpp != NULL); 2506 2507 if ((*vpp)->v_type == VDIR) { 2508 do { 2509 /* 2510 * *vpp may be an AutoFS node, so we perform 2511 * a VOP_ACCESS() to trigger the mount of the intended 2512 * filesystem, so we can perform the lookup in the 2513 * intended filesystem. 2514 */ 2515 (void) VOP_ACCESS(*vpp, 0, 0, cr); 2516 2517 /* 2518 * If vnode is covered, get the 2519 * the topmost vnode. 2520 */ 2521 if (vn_mountedvfs(*vpp) != NULL) { 2522 error = traverse(vpp); 2523 if (error) { 2524 VN_RELE(*vpp); 2525 goto publicfh_done; 2526 } 2527 } 2528 2529 if (VOP_REALVP(*vpp, &realvp) == 0 && realvp != *vpp) { 2530 /* 2531 * If realvp is different from *vpp 2532 * then release our reference on *vpp, so that 2533 * the export access check be performed on the 2534 * real filesystem instead. 2535 */ 2536 VN_HOLD(realvp); 2537 VN_RELE(*vpp); 2538 *vpp = realvp; 2539 } else 2540 break; 2541 /* LINTED */ 2542 } while (TRUE); 2543 2544 /* 2545 * Let nfs_vptexi() figure what the real parent is. 2546 */ 2547 VN_RELE(mc_dvp); 2548 mc_dvp = NULL; 2549 2550 } else { 2551 /* 2552 * If vnode is covered, get the 2553 * the topmost vnode. 2554 */ 2555 if (vn_mountedvfs(mc_dvp) != NULL) { 2556 error = traverse(&mc_dvp); 2557 if (error) { 2558 VN_RELE(*vpp); 2559 goto publicfh_done; 2560 } 2561 } 2562 2563 if (VOP_REALVP(mc_dvp, &realvp) == 0 && realvp != mc_dvp) { 2564 /* 2565 * *vpp is a file, obtain realvp of the parent 2566 * directory vnode. 2567 */ 2568 VN_HOLD(realvp); 2569 VN_RELE(mc_dvp); 2570 mc_dvp = realvp; 2571 } 2572 } 2573 2574 /* 2575 * The pathname may take us from the public filesystem to another. 2576 * If that's the case then just set the exportinfo to the new export 2577 * and build filehandle for it. Thanks to per-access checking there's 2578 * no security issues with doing this. If the client is not allowed 2579 * access to this new export then it will get an access error when it 2580 * tries to use the filehandle 2581 */ 2582 if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) { 2583 VN_RELE(*vpp); 2584 goto publicfh_done; 2585 } 2586 2587 /* 2588 * Not allowed access to pseudo exports. 2589 */ 2590 if (PSEUDO(*exi)) { 2591 error = ENOENT; 2592 VN_RELE(*vpp); 2593 goto publicfh_done; 2594 } 2595 2596 /* 2597 * Do a lookup for the index file. We know the index option doesn't 2598 * allow paths through handling in the share command, so mc_dvp will 2599 * be the parent for the index file vnode, if its present. Use 2600 * temporary pointers to preserve and reuse the vnode pointers of the 2601 * original directory in case there's no index file. Note that the 2602 * index file is a native path, and should not be interpreted by 2603 * the URL parser in rfs_pathname() 2604 */ 2605 if (((*exi)->exi_export.ex_flags & EX_INDEX) && 2606 ((*vpp)->v_type == VDIR) && (pathflag == URLPATH)) { 2607 vnode_t *tvp, *tmc_dvp; /* temporary vnode pointers */ 2608 2609 tmc_dvp = mc_dvp; 2610 mc_dvp = tvp = *vpp; 2611 2612 error = rfs_pathname((*exi)->exi_export.ex_index, NULL, vpp, 2613 mc_dvp, cr, NATIVEPATH); 2614 2615 if (error == ENOENT) { 2616 *vpp = tvp; 2617 mc_dvp = tmc_dvp; 2618 error = 0; 2619 } else { /* ok or error other than ENOENT */ 2620 if (tmc_dvp) 2621 VN_RELE(tmc_dvp); 2622 if (error) 2623 goto publicfh_done; 2624 2625 /* 2626 * Found a valid vp for index "filename". Sanity check 2627 * for odd case where a directory is provided as index 2628 * option argument and leads us to another filesystem 2629 */ 2630 2631 /* Release the reference on the old exi value */ 2632 ASSERT(*exi != NULL); 2633 exi_rele(*exi); 2634 2635 if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) { 2636 VN_RELE(*vpp); 2637 goto publicfh_done; 2638 } 2639 } 2640 } 2641 2642 publicfh_done: 2643 if (mc_dvp) 2644 VN_RELE(mc_dvp); 2645 2646 return (error); 2647 } 2648 2649 /* 2650 * Evaluate a multi-component path 2651 */ 2652 int 2653 rfs_pathname( 2654 char *path, /* pathname to evaluate */ 2655 vnode_t **dirvpp, /* ret for ptr to parent dir vnode */ 2656 vnode_t **compvpp, /* ret for ptr to component vnode */ 2657 vnode_t *startdvp, /* starting vnode */ 2658 cred_t *cr, /* user's credential */ 2659 int pathflag) /* flag to identify path, e.g. URL */ 2660 { 2661 char namebuf[TYPICALMAXPATHLEN]; 2662 struct pathname pn; 2663 int error; 2664 2665 /* 2666 * If pathname starts with '/', then set startdvp to root. 2667 */ 2668 if (*path == '/') { 2669 while (*path == '/') 2670 path++; 2671 2672 startdvp = rootdir; 2673 } 2674 2675 error = pn_get_buf(path, UIO_SYSSPACE, &pn, namebuf, sizeof (namebuf)); 2676 if (error == 0) { 2677 /* 2678 * Call the URL parser for URL paths to modify the original 2679 * string to handle any '%' encoded characters that exist. 2680 * Done here to avoid an extra bcopy in the lookup. 2681 * We need to be careful about pathlen's. We know that 2682 * rfs_pathname() is called with a non-empty path. However, 2683 * it could be emptied due to the path simply being all /'s, 2684 * which is valid to proceed with the lookup, or due to the 2685 * URL parser finding an encoded null character at the 2686 * beginning of path which should not proceed with the lookup. 2687 */ 2688 if (pn.pn_pathlen != 0 && pathflag == URLPATH) { 2689 URLparse(pn.pn_path); 2690 if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) 2691 return (ENOENT); 2692 } 2693 VN_HOLD(startdvp); 2694 error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp, 2695 rootdir, startdvp, cr); 2696 } 2697 if (error == ENAMETOOLONG) { 2698 /* 2699 * This thread used a pathname > TYPICALMAXPATHLEN bytes long. 2700 */ 2701 if (error = pn_get(path, UIO_SYSSPACE, &pn)) 2702 return (error); 2703 if (pn.pn_pathlen != 0 && pathflag == URLPATH) { 2704 URLparse(pn.pn_path); 2705 if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) { 2706 pn_free(&pn); 2707 return (ENOENT); 2708 } 2709 } 2710 VN_HOLD(startdvp); 2711 error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp, 2712 rootdir, startdvp, cr); 2713 pn_free(&pn); 2714 } 2715 2716 return (error); 2717 } 2718 2719 /* 2720 * Adapt the multicomponent lookup path depending on the pathtype 2721 */ 2722 static int 2723 MCLpath(char **path) 2724 { 2725 unsigned char c = (unsigned char)**path; 2726 2727 /* 2728 * If the MCL path is between 0x20 and 0x7E (graphic printable 2729 * character of the US-ASCII coded character set), its a URL path, 2730 * per RFC 1738. 2731 */ 2732 if (c >= 0x20 && c <= 0x7E) 2733 return (URLPATH); 2734 2735 /* 2736 * If the first octet of the MCL path is not an ASCII character 2737 * then it must be interpreted as a tag value that describes the 2738 * format of the remaining octets of the MCL path. 2739 * 2740 * If the first octet of the MCL path is 0x81 it is a query 2741 * for the security info. 2742 */ 2743 switch (c) { 2744 case 0x80: /* native path, i.e. MCL via mount protocol */ 2745 (*path)++; 2746 return (NATIVEPATH); 2747 case 0x81: /* security query */ 2748 (*path)++; 2749 return (SECURITY_QUERY); 2750 default: 2751 return (-1); 2752 } 2753 } 2754 2755 #define fromhex(c) ((c >= '0' && c <= '9') ? (c - '0') : \ 2756 ((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\ 2757 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0))) 2758 2759 /* 2760 * The implementation of URLparse gaurantees that the final string will 2761 * fit in the original one. Replaces '%' occurrences followed by 2 characters 2762 * with its corresponding hexadecimal character. 2763 */ 2764 static void 2765 URLparse(char *str) 2766 { 2767 char *p, *q; 2768 2769 p = q = str; 2770 while (*p) { 2771 *q = *p; 2772 if (*p++ == '%') { 2773 if (*p) { 2774 *q = fromhex(*p) * 16; 2775 p++; 2776 if (*p) { 2777 *q += fromhex(*p); 2778 p++; 2779 } 2780 } 2781 } 2782 q++; 2783 } 2784 *q = '\0'; 2785 } 2786 2787 2788 /* 2789 * Get the export information for the lookup vnode, and verify its 2790 * useable. 2791 */ 2792 int 2793 nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr, 2794 struct exportinfo **exi) 2795 { 2796 int walk; 2797 int error = 0; 2798 2799 *exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE); 2800 if (*exi == NULL) 2801 error = EACCES; 2802 else { 2803 /* 2804 * If nosub is set for this export then 2805 * a lookup relative to the public fh 2806 * must not terminate below the 2807 * exported directory. 2808 */ 2809 if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0) 2810 error = EACCES; 2811 } 2812 2813 return (error); 2814 } 2815