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