1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)nfs_subs.c 7.41 (Berkeley) 5/15/91 37 * $Id: nfs_subs.c,v 1.11 1994/03/09 21:24:36 ws Exp $ 38 */ 39 40 /* 41 * These functions support the macros and help fiddle mbuf chains for 42 * the nfs op functions. They do things like create the rpc header and 43 * copy data between mbuf chains and uio lists. 44 */ 45 #include <sys/param.h> 46 #include <sys/proc.h> 47 #include <sys/filedesc.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/mount.h> 51 #include <sys/file.h> 52 #include <sys/vnode.h> 53 #include <sys/namei.h> 54 #include <sys/mbuf.h> 55 #ifdef NFSCLIENT 56 #include <sys/buf.h> 57 #endif 58 59 #include <nfs/rpcv2.h> 60 #include <nfs/nfsv2.h> 61 #include <nfs/nfsnode.h> 62 #include <nfs/nfs.h> 63 #include <nfs/nfsiom.h> 64 #include <nfs/xdr_subs.h> 65 #include <nfs/nfsm_subs.h> 66 #include <nfs/nfscompress.h> 67 68 #define TRUE 1 69 #define FALSE 0 70 71 /* 72 * Data items converted to xdr at startup, since they are constant 73 * This is kinda hokey, but may save a little time doing byte swaps 74 */ 75 u_long nfs_procids[NFS_NPROCS]; 76 u_long nfs_xdrneg1; 77 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 78 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 79 u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 80 /* And other global data */ 81 static u_long *rpc_uidp = (u_long *)0; 82 static u_long nfs_xid = 1; 83 static char *rpc_unixauth; 84 extern long hostid; 85 #ifdef NFSCLIENT 86 extern struct buf nfs_bqueue; 87 #endif 88 89 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 90 extern struct nfsreq nfsreqh; 91 92 /* Function ret types */ 93 static char *nfs_unixauth(); 94 95 /* 96 * Maximum number of groups passed through to NFS server. 97 * According to RFC1057 it should be 16. 98 * For release 3.X systems, the maximum value is 8. 99 * For some other servers, the maximum value is 10. 100 */ 101 int numgrps = 8; 102 103 /* 104 * Create the header for an rpc request packet 105 * The function nfs_unixauth() creates a unix style authorization string 106 * and returns a ptr to it. 107 * The hsiz is the size of the rest of the nfs request header. 108 * (just used to decide if a cluster is a good idea) 109 * nb: Note that the prog, vers and procid args are already in xdr byte order 110 */ 111 struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 112 u_long prog; 113 u_long vers; 114 u_long procid; 115 struct ucred *cred; 116 int hsiz; 117 caddr_t *bpos; 118 struct mbuf **mb; 119 u_long *retxid; 120 { 121 register struct mbuf *mreq, *m; 122 register u_long *tl; 123 struct mbuf *m1; 124 char *ap; 125 int asiz, siz; 126 static char authnull[4*NFSX_UNSIGNED]; 127 128 NFSMGETHDR(mreq); 129 if (cred != NOCRED) { 130 asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps : 131 (cred->cr_ngroups - 1)) << 2); 132 #ifdef FILLINHOST 133 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 134 #else 135 asiz += 9*NFSX_UNSIGNED; 136 #endif 137 } else 138 asiz = 4 * NFSX_UNSIGNED; 139 140 /* If we need a lot, alloc a cluster ?? */ 141 if ((asiz+hsiz+RPC_SIZ) > MHLEN) 142 MCLGET(mreq, M_WAIT); 143 mreq->m_len = NFSMSIZ(mreq); 144 siz = mreq->m_len; 145 m1 = mreq; 146 /* 147 * Alloc enough mbufs 148 * We do it now to avoid all sleeps after the call to nfs_unixauth() 149 */ 150 while ((asiz+RPC_SIZ) > siz) { 151 MGET(m, M_WAIT, MT_DATA); 152 m1->m_next = m; 153 m->m_len = MLEN; 154 siz += MLEN; 155 m1 = m; 156 } 157 tl = mtod(mreq, u_long *); 158 *tl++ = *retxid = txdr_unsigned(++nfs_xid); 159 *tl++ = rpc_call; 160 *tl++ = rpc_vers; 161 *tl++ = prog; 162 *tl++ = vers; 163 *tl++ = procid; 164 165 /* Now we can call nfs_unixauth() and copy it in */ 166 if (cred != NOCRED) 167 ap = nfs_unixauth(cred); 168 else 169 ap = authnull; 170 m = mreq; 171 siz = m->m_len-RPC_SIZ; 172 if (asiz <= siz) { 173 bcopy(ap, (caddr_t)tl, asiz); 174 m->m_len = asiz+RPC_SIZ; 175 } else { 176 bcopy(ap, (caddr_t)tl, siz); 177 ap += siz; 178 asiz -= siz; 179 while (asiz > 0) { 180 siz = (asiz > MLEN) ? MLEN : asiz; 181 m = m->m_next; 182 bcopy(ap, mtod(m, caddr_t), siz); 183 m->m_len = siz; 184 asiz -= siz; 185 ap += siz; 186 } 187 } 188 189 /* Finally, return values */ 190 *mb = m; 191 *bpos = mtod(m, caddr_t)+m->m_len; 192 return (mreq); 193 } 194 195 /* 196 * copies mbuf chain to the uio scatter/gather list 197 */ 198 nfsm_mbuftouio(mrep, uiop, siz, dpos) 199 struct mbuf **mrep; 200 register struct uio *uiop; 201 int siz; 202 caddr_t *dpos; 203 { 204 register char *mbufcp, *uiocp; 205 register int xfer, left, len; 206 register struct mbuf *mp; 207 long uiosiz, rem; 208 int error = 0; 209 210 mp = *mrep; 211 mbufcp = *dpos; 212 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 213 rem = nfsm_rndup(siz)-siz; 214 while (siz > 0) { 215 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 216 return (EFBIG); 217 left = uiop->uio_iov->iov_len; 218 uiocp = uiop->uio_iov->iov_base; 219 if (left > siz) 220 left = siz; 221 uiosiz = left; 222 while (left > 0) { 223 while (len == 0) { 224 mp = mp->m_next; 225 if (mp == NULL) 226 return (EBADRPC); 227 mbufcp = mtod(mp, caddr_t); 228 len = mp->m_len; 229 } 230 xfer = (left > len) ? len : left; 231 #ifdef notdef 232 /* Not Yet.. */ 233 if (uiop->uio_iov->iov_op != NULL) 234 (*(uiop->uio_iov->iov_op)) 235 (mbufcp, uiocp, xfer); 236 else 237 #endif 238 if (uiop->uio_segflg == UIO_SYSSPACE) 239 bcopy(mbufcp, uiocp, xfer); 240 else 241 copyout(mbufcp, uiocp, xfer); 242 left -= xfer; 243 len -= xfer; 244 mbufcp += xfer; 245 uiocp += xfer; 246 uiop->uio_offset += xfer; 247 uiop->uio_resid -= xfer; 248 } 249 if (uiop->uio_iov->iov_len <= siz) { 250 uiop->uio_iovcnt--; 251 uiop->uio_iov++; 252 } else { 253 uiop->uio_iov->iov_base += uiosiz; 254 uiop->uio_iov->iov_len -= uiosiz; 255 } 256 siz -= uiosiz; 257 } 258 *dpos = mbufcp; 259 *mrep = mp; 260 if (rem > 0) { 261 if (len < rem) 262 error = nfs_adv(mrep, dpos, rem, len); 263 else 264 *dpos += rem; 265 } 266 return (error); 267 } 268 269 /* 270 * copies a uio scatter/gather list to an mbuf chain... 271 */ 272 nfsm_uiotombuf(uiop, mq, siz, bpos) 273 register struct uio *uiop; 274 struct mbuf **mq; 275 int siz; 276 caddr_t *bpos; 277 { 278 register char *uiocp; 279 register struct mbuf *mp, *mp2; 280 register int xfer, left, len; 281 int uiosiz, clflg, rem; 282 char *cp; 283 284 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 285 clflg = 1; 286 else 287 clflg = 0; 288 rem = nfsm_rndup(siz)-siz; 289 mp2 = *mq; 290 while (siz > 0) { 291 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 292 return (EINVAL); 293 left = uiop->uio_iov->iov_len; 294 uiocp = uiop->uio_iov->iov_base; 295 if (left > siz) 296 left = siz; 297 uiosiz = left; 298 while (left > 0) { 299 MGET(mp, M_WAIT, MT_DATA); 300 if (clflg) 301 MCLGET(mp, M_WAIT); 302 mp->m_len = NFSMSIZ(mp); 303 mp2->m_next = mp; 304 mp2 = mp; 305 xfer = (left > mp->m_len) ? mp->m_len : left; 306 #ifdef notdef 307 /* Not Yet.. */ 308 if (uiop->uio_iov->iov_op != NULL) 309 (*(uiop->uio_iov->iov_op)) 310 (uiocp, mtod(mp, caddr_t), xfer); 311 else 312 #endif 313 if (uiop->uio_segflg == UIO_SYSSPACE) 314 bcopy(uiocp, mtod(mp, caddr_t), xfer); 315 else 316 copyin(uiocp, mtod(mp, caddr_t), xfer); 317 len = mp->m_len; 318 mp->m_len = xfer; 319 left -= xfer; 320 uiocp += xfer; 321 uiop->uio_offset += xfer; 322 uiop->uio_resid -= xfer; 323 } 324 if (uiop->uio_iov->iov_len <= siz) { 325 uiop->uio_iovcnt--; 326 uiop->uio_iov++; 327 } else { 328 uiop->uio_iov->iov_base += uiosiz; 329 uiop->uio_iov->iov_len -= uiosiz; 330 } 331 siz -= uiosiz; 332 } 333 if (rem > 0) { 334 if (rem > (len-mp->m_len)) { 335 MGET(mp, M_WAIT, MT_DATA); 336 mp->m_len = 0; 337 mp2->m_next = mp; 338 } 339 cp = mtod(mp, caddr_t)+mp->m_len; 340 for (left = 0; left < rem; left++) 341 *cp++ = '\0'; 342 mp->m_len += rem; 343 *bpos = cp; 344 } else 345 *bpos = mtod(mp, caddr_t)+mp->m_len; 346 *mq = mp; 347 return (0); 348 } 349 350 /* 351 * Help break down an mbuf chain by setting the first siz bytes contiguous 352 * pointed to by returned val. 353 * If Updateflg == True we can overwrite the first part of the mbuf data 354 * This is used by the macros nfsm_disect and nfsm_disecton for tough 355 * cases. (The macros use the vars. dpos and dpos2) 356 */ 357 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 358 struct mbuf **mdp; 359 caddr_t *dposp; 360 int siz; 361 int left; 362 int updateflg; 363 caddr_t *cp2; 364 { 365 register struct mbuf *mp, *mp2; 366 register int siz2, xfer; 367 register caddr_t tl; 368 369 mp = *mdp; 370 while (left == 0) { 371 *mdp = mp = mp->m_next; 372 if (mp == NULL) 373 return (EBADRPC); 374 left = mp->m_len; 375 *dposp = mtod(mp, caddr_t); 376 } 377 if (left >= siz) { 378 *cp2 = *dposp; 379 *dposp += siz; 380 } else if (mp->m_next == NULL) { 381 return (EBADRPC); 382 } else if (siz > MHLEN) { 383 panic("nfs S too big"); 384 } else { 385 /* Iff update, you can overwrite, else must alloc new mbuf */ 386 if (updateflg) { 387 NFSMINOFF(mp); 388 } else { 389 MGET(mp2, M_WAIT, MT_DATA); 390 mp2->m_next = mp->m_next; 391 mp->m_next = mp2; 392 mp->m_len -= left; 393 mp = mp2; 394 } 395 *cp2 = tl = mtod(mp, caddr_t); 396 bcopy(*dposp, tl, left); /* Copy what was left */ 397 siz2 = siz-left; 398 tl += left; 399 mp2 = mp->m_next; 400 /* Loop around copying up the siz2 bytes */ 401 while (siz2 > 0) { 402 if (mp2 == NULL) 403 return (EBADRPC); 404 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 405 if (xfer > 0) { 406 bcopy(mtod(mp2, caddr_t), tl, xfer); 407 NFSMADV(mp2, xfer); 408 mp2->m_len -= xfer; 409 tl += xfer; 410 siz2 -= xfer; 411 } 412 if (siz2 > 0) 413 mp2 = mp2->m_next; 414 } 415 mp->m_len = siz; 416 *mdp = mp2; 417 *dposp = mtod(mp2, caddr_t); 418 } 419 return (0); 420 } 421 422 /* 423 * Advance the position in the mbuf chain. 424 */ 425 nfs_adv(mdp, dposp, offs, left) 426 struct mbuf **mdp; 427 caddr_t *dposp; 428 int offs; 429 int left; 430 { 431 register struct mbuf *m; 432 register int s; 433 434 m = *mdp; 435 s = left; 436 while (s < offs) { 437 offs -= s; 438 m = m->m_next; 439 if (m == NULL) 440 return (EBADRPC); 441 s = m->m_len; 442 } 443 *mdp = m; 444 *dposp = mtod(m, caddr_t)+offs; 445 return (0); 446 } 447 448 /* 449 * Copy a string into mbufs for the hard cases... 450 */ 451 nfsm_strtmbuf(mb, bpos, cp, siz) 452 struct mbuf **mb; 453 char **bpos; 454 char *cp; 455 long siz; 456 { 457 register struct mbuf *m1, *m2; 458 long left, xfer, len, tlen; 459 u_long *tl; 460 int putsize; 461 462 putsize = 1; 463 m2 = *mb; 464 left = NFSMSIZ(m2)-m2->m_len; 465 if (left > 0) { 466 tl = ((u_long *)(*bpos)); 467 *tl++ = txdr_unsigned(siz); 468 putsize = 0; 469 left -= NFSX_UNSIGNED; 470 m2->m_len += NFSX_UNSIGNED; 471 if (left > 0) { 472 bcopy(cp, (caddr_t) tl, left); 473 siz -= left; 474 cp += left; 475 m2->m_len += left; 476 left = 0; 477 } 478 } 479 /* Loop arround adding mbufs */ 480 while (siz > 0) { 481 MGET(m1, M_WAIT, MT_DATA); 482 if (siz > MLEN) 483 MCLGET(m1, M_WAIT); 484 m1->m_len = NFSMSIZ(m1); 485 m2->m_next = m1; 486 m2 = m1; 487 tl = mtod(m1, u_long *); 488 tlen = 0; 489 if (putsize) { 490 *tl++ = txdr_unsigned(siz); 491 m1->m_len -= NFSX_UNSIGNED; 492 tlen = NFSX_UNSIGNED; 493 putsize = 0; 494 } 495 if (siz < m1->m_len) { 496 len = nfsm_rndup(siz); 497 xfer = siz; 498 if (xfer < len) 499 *(tl+(xfer>>2)) = 0; 500 } else { 501 xfer = len = m1->m_len; 502 } 503 bcopy(cp, (caddr_t) tl, xfer); 504 m1->m_len = len+tlen; 505 siz -= xfer; 506 cp += xfer; 507 } 508 *mb = m1; 509 *bpos = mtod(m1, caddr_t)+m1->m_len; 510 return (0); 511 } 512 513 /* 514 * Called once to initialize data structures... 515 */ 516 nfs_init() 517 { 518 register int i; 519 520 rpc_vers = txdr_unsigned(RPC_VER2); 521 rpc_call = txdr_unsigned(RPC_CALL); 522 rpc_reply = txdr_unsigned(RPC_REPLY); 523 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 524 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 525 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 526 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 527 nfs_vers = txdr_unsigned(NFS_VER2); 528 nfs_prog = txdr_unsigned(NFS_PROG); 529 nfs_true = txdr_unsigned(TRUE); 530 nfs_false = txdr_unsigned(FALSE); 531 /* Loop thru nfs procids */ 532 for (i = 0; i < NFS_NPROCS; i++) 533 nfs_procids[i] = txdr_unsigned(i); 534 /* Ensure async daemons disabled */ 535 nfs_xdrneg1 = txdr_unsigned(-1); 536 #ifdef NFSCLIENT 537 nfs_bqueue.b_actb = &nfs_bqueue.b_actf; 538 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 539 nfs_iodwant[i] = (struct proc *)0; 540 nfs_nhinit(); /* Init the nfsnode table */ 541 #endif /* NFSCLIENT */ 542 #ifdef NFSSERVER 543 nfsrv_initcache(); /* Init the server request cache */ 544 #endif /*NFSSERVER */ 545 /* 546 * Initialize reply list and start timer 547 */ 548 nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 549 nfs_timer(); 550 } 551 552 /* 553 * Fill in the rest of the rpc_unixauth and return it 554 */ 555 static char *nfs_unixauth(cr) 556 register struct ucred *cr; 557 { 558 register u_long *tl; 559 register int i; 560 int ngr; 561 562 /* Maybe someday there should be a cache of AUTH_SHORT's */ 563 if ((tl = rpc_uidp) == NULL) { 564 #ifdef FILLINHOST 565 i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED); 566 #else 567 i = 25*NFSX_UNSIGNED; 568 #endif 569 MALLOC(tl, u_long *, i, M_TEMP, M_WAITOK); 570 bzero((caddr_t)tl, i); 571 rpc_unixauth = (caddr_t)tl; 572 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 573 tl++; /* Fill in size later */ 574 *tl++ = hostid; 575 #ifdef FILLINHOST 576 *tl++ = txdr_unsigned(hostnamelen); 577 i = nfsm_rndup(hostnamelen); 578 bcopy(hostname, (caddr_t)tl, hostnamelen); 579 tl += (i>>2); 580 #else 581 *tl++ = 0; 582 #endif 583 rpc_uidp = tl; 584 } 585 *tl++ = txdr_unsigned(cr->cr_uid); 586 *tl++ = txdr_unsigned(cr->cr_groups[0]); 587 ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1); 588 *tl++ = txdr_unsigned(ngr); 589 for (i = 1; i <= ngr; i++) 590 *tl++ = txdr_unsigned(cr->cr_groups[i]); 591 /* And add the AUTH_NULL */ 592 *tl++ = 0; 593 *tl = 0; 594 i = (((caddr_t)tl)-rpc_unixauth)-12; 595 tl = (u_long *)(rpc_unixauth+4); 596 *tl = txdr_unsigned(i); 597 return (rpc_unixauth); 598 } 599 600 /* 601 * Set up nameidata for a namei() call and do it 602 */ 603 nfs_namei(ndp, fhp, len, mdp, dposp, p) 604 register struct nameidata *ndp; 605 fhandle_t *fhp; 606 int len; 607 struct mbuf **mdp; 608 caddr_t *dposp; 609 struct proc *p; 610 { 611 register int i, rem; 612 register struct mbuf *md; 613 register char *fromcp, *tocp; 614 struct vnode *dp; 615 int flag; 616 int error; 617 618 flag = ndp->ni_nameiop & OPMASK; 619 MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 620 /* 621 * Copy the name from the mbuf list to ndp->ni_pnbuf 622 * and set the various ndp fields appropriately. 623 */ 624 fromcp = *dposp; 625 tocp = ndp->ni_pnbuf; 626 md = *mdp; 627 rem = mtod(md, caddr_t) + md->m_len - fromcp; 628 for (i = 0; i < len; i++) { 629 while (rem == 0) { 630 md = md->m_next; 631 if (md == NULL) { 632 error = EBADRPC; 633 goto out; 634 } 635 fromcp = mtod(md, caddr_t); 636 rem = md->m_len; 637 } 638 if (*fromcp == '\0' || *fromcp == '/') { 639 error = EINVAL; 640 goto out; 641 } 642 if (*fromcp & 0200) 643 if ((*fromcp&0377) == ('/'|0200) || flag != DELETE) { 644 error = EINVAL; 645 goto out; 646 } 647 *tocp++ = *fromcp++; 648 rem--; 649 } 650 *tocp = '\0'; 651 *mdp = md; 652 *dposp = fromcp; 653 len = nfsm_rndup(len)-len; 654 if (len > 0) { 655 if (rem >= len) 656 *dposp += len; 657 else if (error = nfs_adv(mdp, dposp, len, rem)) 658 goto out; 659 } 660 ndp->ni_pathlen = tocp - ndp->ni_pnbuf; 661 ndp->ni_ptr = ndp->ni_pnbuf; 662 /* 663 * Extract and set starting directory. 664 */ 665 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 666 goto out; 667 if (dp->v_type != VDIR) { 668 vrele(dp); 669 error = ENOTDIR; 670 goto out; 671 } 672 ndp->ni_startdir = dp; 673 ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE); 674 /* 675 * And call lookup() to do the real work 676 */ 677 if (error = lookup(ndp, p)) 678 goto out; 679 /* 680 * Check for encountering a symbolic link 681 */ 682 if (ndp->ni_more) { 683 if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1) 684 vput(ndp->ni_dvp); 685 else 686 vrele(ndp->ni_dvp); 687 vput(ndp->ni_vp); 688 ndp->ni_vp = NULL; 689 error = EINVAL; 690 goto out; 691 } 692 /* 693 * Check for saved name request 694 */ 695 if (ndp->ni_nameiop & (SAVENAME | SAVESTART)) { 696 ndp->ni_nameiop |= HASBUF; 697 return (0); 698 } 699 out: 700 FREE(ndp->ni_pnbuf, M_NAMEI); 701 return (error); 702 } 703 704 /* 705 * A fiddled version of m_adj() that ensures null fill to a long 706 * boundary and only trims off the back end 707 */ 708 nfsm_adj(mp, len, nul) 709 struct mbuf *mp; 710 register int len; 711 int nul; 712 { 713 register struct mbuf *m; 714 register int count, i; 715 register char *cp; 716 717 /* 718 * Trim from tail. Scan the mbuf chain, 719 * calculating its length and finding the last mbuf. 720 * If the adjustment only affects this mbuf, then just 721 * adjust and return. Otherwise, rescan and truncate 722 * after the remaining size. 723 */ 724 count = 0; 725 m = mp; 726 for (;;) { 727 count += m->m_len; 728 if (m->m_next == (struct mbuf *)0) 729 break; 730 m = m->m_next; 731 } 732 if (m->m_len > len) { 733 m->m_len -= len; 734 if (nul > 0) { 735 cp = mtod(m, caddr_t)+m->m_len-nul; 736 for (i = 0; i < nul; i++) 737 *cp++ = '\0'; 738 } 739 return; 740 } 741 count -= len; 742 if (count < 0) 743 count = 0; 744 /* 745 * Correct length for chain is "count". 746 * Find the mbuf with last data, adjust its length, 747 * and toss data from remaining mbufs on chain. 748 */ 749 for (m = mp; m; m = m->m_next) { 750 if (m->m_len >= count) { 751 m->m_len = count; 752 if (nul > 0) { 753 cp = mtod(m, caddr_t)+m->m_len-nul; 754 for (i = 0; i < nul; i++) 755 *cp++ = '\0'; 756 } 757 break; 758 } 759 count -= m->m_len; 760 } 761 while (m = m->m_next) 762 m->m_len = 0; 763 } 764 765 /* 766 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 767 * - look up fsid in mount list (if not found ret error) 768 * - check that it is exported 769 * - get vp by calling VFS_FHTOVP() macro 770 * - if not lockflag unlock it with VOP_UNLOCK() 771 * - if cred->cr_uid == 0 set it to m_exroot 772 */ 773 nfsrv_fhtovp(fhp, lockflag, vpp, cred) 774 fhandle_t *fhp; 775 int lockflag; 776 struct vnode **vpp; 777 struct ucred *cred; 778 { 779 register struct mount *mp; 780 781 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 782 return (ESTALE); 783 if ((mp->mnt_flag & MNT_EXPORTED) == 0) 784 return (EACCES); 785 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 786 return (ESTALE); 787 if (cred->cr_uid == 0) 788 cred->cr_uid = mp->mnt_exroot; 789 if (!lockflag) 790 VOP_UNLOCK(*vpp); 791 return (0); 792 } 793 794 /* 795 * These two functions implement nfs rpc compression. 796 * The algorithm is a trivial run length encoding of '\0' bytes. The high 797 * order nibble of hex "e" is or'd with the number of zeroes - 2 in four 798 * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e" 799 * is byte stuffed. 800 * The compressed data is padded with 0x0 bytes to an even multiple of 801 * 4 bytes in length to avoid any weird long pointer alignments. 802 * If compression/uncompression is unsuccessful, the original mbuf list 803 * is returned. 804 * The first four bytes (the XID) are left uncompressed and the fifth 805 * byte is set to 0x1 for request and 0x2 for reply. 806 * An uncompressed RPC will always have the fifth byte == 0x0. 807 */ 808 struct mbuf * 809 nfs_compress(m0) 810 struct mbuf *m0; 811 { 812 register u_char ch, nextch; 813 register int i, rlelast; 814 register u_char *ip, *op; 815 register int ileft, oleft, noteof; 816 register struct mbuf *m, *om; 817 struct mbuf **mp, *retm; 818 int olen, clget; 819 820 i = rlelast = 0; 821 noteof = 1; 822 m = m0; 823 if (m->m_len < 12) 824 return (m0); 825 if (m->m_pkthdr.len >= MINCLSIZE) 826 clget = 1; 827 else 828 clget = 0; 829 ileft = m->m_len - 9; 830 ip = mtod(m, u_char *); 831 MGETHDR(om, M_WAIT, MT_DATA); 832 if (clget) 833 MCLGET(om, M_WAIT); 834 retm = om; 835 mp = &om->m_next; 836 olen = om->m_len = 5; 837 oleft = M_TRAILINGSPACE(om); 838 op = mtod(om, u_char *); 839 *((u_long *)op) = *((u_long *)ip); 840 ip += 7; 841 op += 4; 842 *op++ = *ip++ + 1; 843 nextch = *ip++; 844 while (noteof) { 845 ch = nextch; 846 if (ileft == 0) { 847 do { 848 m = m->m_next; 849 } while (m && m->m_len == 0); 850 if (m) { 851 ileft = m->m_len; 852 ip = mtod(m, u_char *); 853 } else { 854 noteof = 0; 855 nextch = 0x1; 856 goto doit; 857 } 858 } 859 nextch = *ip++; 860 ileft--; 861 doit: 862 if (ch == '\0') { 863 if (++i == NFSC_MAX || nextch != '\0') { 864 if (i < 2) { 865 nfscput('\0'); 866 } else { 867 if (rlelast == i) { 868 nfscput('\0'); 869 i--; 870 } 871 if (NFSCRLE(i) == (nextch & 0xff)) { 872 i--; 873 if (i < 2) { 874 nfscput('\0'); 875 } else { 876 nfscput(NFSCRLE(i)); 877 } 878 nfscput('\0'); 879 rlelast = 0; 880 } else { 881 nfscput(NFSCRLE(i)); 882 rlelast = i; 883 } 884 } 885 i = 0; 886 } 887 } else { 888 if ((ch & NFSCRL) == NFSCRL) { 889 nfscput(ch); 890 } 891 nfscput(ch); 892 i = rlelast = 0; 893 } 894 } 895 if (olen < m0->m_pkthdr.len) { 896 m_freem(m0); 897 if (i = (olen & 0x3)) { 898 i = 4 - i; 899 while (i-- > 0) { 900 nfscput('\0'); 901 } 902 } 903 retm->m_pkthdr.len = olen; 904 retm->m_pkthdr.rcvif = (struct ifnet *)0; 905 return (retm); 906 } else { 907 m_freem(retm); 908 return (m0); 909 } 910 } 911 912 struct mbuf * 913 nfs_uncompress(m0) 914 struct mbuf *m0; 915 { 916 register u_char cp, nextcp, *ip, *op; 917 register struct mbuf *m, *om; 918 struct mbuf *retm, **mp; 919 int i, j, noteof, clget, ileft, oleft, olen; 920 921 m = m0; 922 i = 0; 923 while (m && i < MINCLSIZE) { 924 i += m->m_len; 925 m = m->m_next; 926 } 927 if (i < 6) 928 return (m0); 929 if (i >= MINCLSIZE) 930 clget = 1; 931 else 932 clget = 0; 933 m = m0; 934 MGET(om, M_WAIT, MT_DATA); 935 if (clget) 936 MCLGET(om, M_WAIT); 937 olen = om->m_len = 8; 938 oleft = M_TRAILINGSPACE(om); 939 op = mtod(om, u_char *); 940 retm = om; 941 mp = &om->m_next; 942 if (m->m_len >= 6) { 943 ileft = m->m_len - 6; 944 ip = mtod(m, u_char *); 945 *((u_long *)op) = *((u_long *)ip); 946 bzero(op + 4, 3); 947 ip += 4; 948 op += 7; 949 if (*ip == '\0') { 950 m_freem(om); 951 return (m0); 952 } 953 *op++ = *ip++ - 1; 954 cp = *ip++; 955 } else { 956 ileft = m->m_len; 957 ip = mtod(m, u_char *); 958 nfscget(*op++); 959 nfscget(*op++); 960 nfscget(*op++); 961 nfscget(*op++); 962 bzero(op, 3); 963 op += 3; 964 nfscget(*op); 965 if (*op == '\0') { 966 m_freem(om); 967 return (m0); 968 } 969 (*op)--; 970 op++; 971 nfscget(cp); 972 } 973 noteof = 1; 974 while (noteof) { 975 if ((cp & NFSCRL) == NFSCRL) { 976 nfscget(nextcp); 977 if (cp == nextcp) { 978 nfscput(cp); 979 goto readit; 980 } else { 981 i = (cp & 0xf) + 2; 982 for (j = 0; j < i; j++) { 983 nfscput('\0'); 984 } 985 cp = nextcp; 986 } 987 } else { 988 nfscput(cp); 989 readit: 990 nfscget(cp); 991 } 992 } 993 m_freem(m0); 994 if (i = (olen & 0x3)) 995 om->m_len -= i; 996 return (retm); 997 } 998