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