1 /* $OpenBSD: nfs.c,v 1.15 2017/05/08 20:13:46 patrick Exp $ */ 2 /* $NetBSD: nfs.c,v 1.19 1996/10/13 02:29:04 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 John Brezak 6 * All rights reserved. 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. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/time.h> 34 #include <sys/socket.h> 35 #include <sys/stat.h> 36 37 #include <netinet/in.h> 38 39 #include "rpcv2.h" 40 #include "nfsv2.h" 41 42 #include "stand.h" 43 #include "saerrno.h" 44 #include "net.h" 45 #include "netif.h" 46 #include "nfs.h" 47 #include "rpc.h" 48 49 /* Define our own NFS attributes without NQNFS stuff. */ 50 struct nfsv2_fattrs { 51 u_int32_t fa_type; 52 u_int32_t fa_mode; 53 u_int32_t fa_nlink; 54 u_int32_t fa_uid; 55 u_int32_t fa_gid; 56 u_int32_t fa_size; 57 u_int32_t fa_blocksize; 58 u_int32_t fa_rdev; 59 u_int32_t fa_blocks; 60 u_int32_t fa_fsid; 61 u_int32_t fa_fileid; 62 struct nfsv2_time fa_atime; 63 struct nfsv2_time fa_mtime; 64 struct nfsv2_time fa_ctime; 65 }; 66 67 68 struct nfs_read_args { 69 u_char fh[NFS_FHSIZE]; 70 u_int32_t off; 71 u_int32_t len; 72 u_int32_t xxx; /* XXX what's this for? */ 73 }; 74 75 /* Data part of nfs rpc reply (also the largest thing we receive) */ 76 #define NFSREAD_SIZE 1024 77 struct nfs_read_repl { 78 u_int32_t errno; 79 struct nfsv2_fattrs fa; 80 u_int32_t count; 81 u_char data[NFSREAD_SIZE]; 82 }; 83 84 struct nfs_readlnk_repl { 85 u_int32_t errno; 86 u_int32_t len; 87 char path[NFS_MAXPATHLEN]; 88 }; 89 90 struct nfs_iodesc { 91 struct iodesc *iodesc; 92 off_t off; 93 u_char fh[NFS_FHSIZE]; 94 struct nfsv2_fattrs fa; /* all in network order */ 95 }; 96 97 struct nfs_iodesc nfs_root_node; 98 99 100 /* 101 * Fetch the root file handle (call mount daemon) 102 * On error, return non-zero and set errno. 103 */ 104 static int 105 nfs_getrootfh(struct iodesc *d, const char *path, u_char *fhp) 106 { 107 int len; 108 struct args { 109 u_int32_t len; 110 char path[FNAME_SIZE]; 111 } *args; 112 struct repl { 113 u_int32_t errno; 114 u_char fh[NFS_FHSIZE]; 115 } *repl; 116 struct { 117 u_int32_t h[RPC_HEADER_WORDS]; 118 struct args d; 119 } sdata; 120 struct { 121 u_int32_t h[RPC_HEADER_WORDS]; 122 struct repl d; 123 } rdata; 124 ssize_t cc; 125 126 #ifdef NFS_DEBUG 127 if (debug) 128 printf("nfs_getrootfh: %s\n", path); 129 #endif 130 131 args = &sdata.d; 132 repl = &rdata.d; 133 134 bzero(args, sizeof(*args)); 135 len = strlen(path); 136 if (len > sizeof(args->path)) 137 len = sizeof(args->path); 138 args->len = htonl(len); 139 bcopy(path, args->path, len); 140 len = 4 + roundup(len, 4); 141 142 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 143 args, len, repl, sizeof(*repl)); 144 if (cc == -1) { 145 /* errno was set by rpc_call */ 146 return (-1); 147 } 148 if (cc < 4) { 149 errno = EBADRPC; 150 return (-1); 151 } 152 if (repl->errno) { 153 errno = ntohl(repl->errno); 154 return (-1); 155 } 156 bcopy(repl->fh, fhp, sizeof(repl->fh)); 157 return (0); 158 } 159 160 /* 161 * Lookup a file. Store handle and attributes. 162 * Return zero or error number. 163 */ 164 static int 165 nfs_lookupfh(struct nfs_iodesc *d, char *name, struct nfs_iodesc *newfd) 166 { 167 int len, rlen; 168 struct args { 169 u_char fh[NFS_FHSIZE]; 170 u_int32_t len; 171 char name[FNAME_SIZE]; 172 } *args; 173 struct repl { 174 u_int32_t errno; 175 u_char fh[NFS_FHSIZE]; 176 struct nfsv2_fattrs fa; 177 } *repl; 178 struct { 179 u_int32_t h[RPC_HEADER_WORDS]; 180 struct args d; 181 } sdata; 182 struct { 183 u_int32_t h[RPC_HEADER_WORDS]; 184 struct repl d; 185 } rdata; 186 ssize_t cc; 187 188 #ifdef NFS_DEBUG 189 if (debug) 190 printf("lookupfh: called\n"); 191 #endif 192 193 args = &sdata.d; 194 repl = &rdata.d; 195 196 bzero(args, sizeof(*args)); 197 bcopy(d->fh, args->fh, sizeof(args->fh)); 198 len = strlen(name); 199 if (len > sizeof(args->name)) 200 len = sizeof(args->name); 201 bcopy(name, args->name, len); 202 args->len = htonl(len); 203 len = 4 + roundup(len, 4); 204 len += NFS_FHSIZE; 205 206 rlen = sizeof(*repl); 207 208 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 209 args, len, repl, rlen); 210 if (cc == -1) 211 return (errno); /* XXX - from rpc_call */ 212 if (cc < 4) 213 return (EIO); 214 if (repl->errno) { 215 /* saerrno.h now matches NFS error numbers. */ 216 return (ntohl(repl->errno)); 217 } 218 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 219 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 220 return (0); 221 } 222 223 /* 224 * Get the destination of a symbolic link. 225 */ 226 static int 227 nfs_readlink(struct nfs_iodesc *d, char *buf) 228 { 229 struct { 230 u_int32_t h[RPC_HEADER_WORDS]; 231 u_char fh[NFS_FHSIZE]; 232 } sdata; 233 struct { 234 u_int32_t h[RPC_HEADER_WORDS]; 235 struct nfs_readlnk_repl d; 236 } rdata; 237 ssize_t cc; 238 239 #ifdef NFS_DEBUG 240 if (debug) 241 printf("readlink: called\n"); 242 #endif 243 244 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 245 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 246 sdata.fh, NFS_FHSIZE, 247 &rdata.d, sizeof(rdata.d)); 248 if (cc == -1) 249 return (errno); 250 251 if (cc < 4) 252 return (EIO); 253 254 if (rdata.d.errno) 255 return (ntohl(rdata.d.errno)); 256 257 rdata.d.len = ntohl(rdata.d.len); 258 if (rdata.d.len > NFS_MAXPATHLEN) 259 return (ENAMETOOLONG); 260 261 bcopy(rdata.d.path, buf, rdata.d.len); 262 buf[rdata.d.len] = 0; 263 return (0); 264 } 265 266 /* 267 * Read data from a file. 268 * Return transfer count or -1 (and set errno) 269 */ 270 static ssize_t 271 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 272 { 273 struct nfs_read_args *args; 274 struct nfs_read_repl *repl; 275 struct { 276 u_int32_t h[RPC_HEADER_WORDS]; 277 struct nfs_read_args d; 278 } sdata; 279 struct { 280 u_int32_t h[RPC_HEADER_WORDS]; 281 struct nfs_read_repl d; 282 } rdata; 283 ssize_t cc; 284 long x; 285 int hlen, rlen; 286 287 args = &sdata.d; 288 repl = &rdata.d; 289 290 bcopy(d->fh, args->fh, NFS_FHSIZE); 291 args->off = htonl((u_int32_t)off); 292 if (len > NFSREAD_SIZE) 293 len = NFSREAD_SIZE; 294 args->len = htonl((u_int32_t)len); 295 args->xxx = htonl((u_int32_t)0); 296 hlen = sizeof(*repl) - NFSREAD_SIZE; 297 298 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 299 args, sizeof(*args), 300 repl, sizeof(*repl)); 301 if (cc == -1) { 302 /* errno was already set by rpc_call */ 303 return (-1); 304 } 305 if (cc < hlen) { 306 errno = EBADRPC; 307 return (-1); 308 } 309 if (repl->errno) { 310 errno = ntohl(repl->errno); 311 return (-1); 312 } 313 rlen = cc - hlen; 314 x = ntohl(repl->count); 315 if (rlen < x) { 316 printf("nfsread: short packet, %d < %ld\n", rlen, x); 317 errno = EBADRPC; 318 return(-1); 319 } 320 bcopy(repl->data, addr, x); 321 return (x); 322 } 323 324 /* 325 * nfs_mount - mount this nfs filesystem to a host 326 * On error, return non-zero and set errno. 327 */ 328 int 329 nfs_mount(int sock, struct in_addr ip, const char *path) 330 { 331 struct iodesc *desc; 332 struct nfsv2_fattrs *fa; 333 334 if (!(desc = socktodesc(sock))) { 335 errno = EINVAL; 336 return(-1); 337 } 338 339 /* Bind to a reserved port. */ 340 desc->myport = htons(--rpc_port); 341 desc->destip = ip; 342 if (nfs_getrootfh(desc, path, nfs_root_node.fh)) 343 return (-1); 344 nfs_root_node.iodesc = desc; 345 /* Fake up attributes for the root dir. */ 346 fa = &nfs_root_node.fa; 347 fa->fa_type = htonl(NFDIR); 348 fa->fa_mode = htonl(0755); 349 fa->fa_nlink = htonl(2); 350 351 #ifdef NFS_DEBUG 352 if (debug) 353 printf("nfs_mount: got fh for %s\n", path); 354 #endif 355 356 return(0); 357 } 358 359 /* 360 * Open a file. 361 * return zero or error number 362 */ 363 int 364 nfs_open(char *path, struct open_file *f) 365 { 366 struct nfs_iodesc *newfd, *currfd; 367 char namebuf[NFS_MAXPATHLEN + 1], *cp, *ncp; 368 char linkbuf[NFS_MAXPATHLEN + 1]; 369 int nlinks = 0, error = 0, c; 370 371 #ifdef NFS_DEBUG 372 if (debug) 373 printf("nfs_open: %s\n", path); 374 #endif 375 if (nfs_root_node.iodesc == NULL) { 376 printf("nfs_open: must mount first.\n"); 377 return (ENXIO); 378 } 379 380 currfd = &nfs_root_node; 381 newfd = 0; 382 383 cp = path; 384 while (*cp) { 385 /* 386 * Remove extra separators 387 */ 388 while (*cp == '/') 389 cp++; 390 391 if (*cp == '\0') 392 break; 393 /* 394 * Check that current node is a directory. 395 */ 396 if (currfd->fa.fa_type != htonl(NFDIR)) { 397 error = ENOTDIR; 398 goto out; 399 } 400 401 /* allocate file system specific data structure */ 402 newfd = alloc(sizeof(*newfd)); 403 newfd->iodesc = currfd->iodesc; 404 newfd->off = 0; 405 406 /* 407 * Get next component of path name. 408 */ 409 { 410 int len = 0; 411 412 ncp = cp; 413 while ((c = *cp) != '\0' && c != '/') { 414 if (++len > NFS_MAXNAMLEN) { 415 error = ENOENT; 416 goto out; 417 } 418 cp++; 419 } 420 *cp = '\0'; 421 } 422 423 /* lookup a file handle */ 424 error = nfs_lookupfh(currfd, ncp, newfd); 425 *cp = c; 426 if (error) 427 goto out; 428 429 /* 430 * Check for symbolic link 431 */ 432 if (newfd->fa.fa_type == htonl(NFLNK)) { 433 int link_len, len; 434 435 error = nfs_readlink(newfd, linkbuf); 436 if (error) 437 goto out; 438 439 link_len = strlen(linkbuf); 440 len = strlen(cp); 441 442 if (link_len + len > MAXPATHLEN || 443 ++nlinks > MAXSYMLINKS) { 444 error = ENOENT; 445 goto out; 446 } 447 448 bcopy(cp, &namebuf[link_len], len + 1); 449 bcopy(linkbuf, namebuf, link_len); 450 451 /* 452 * If absolute pathname, restart at root. 453 * If relative pathname, restart at parent directory. 454 */ 455 cp = namebuf; 456 if (*cp == '/') { 457 if (currfd != &nfs_root_node) 458 free(currfd, sizeof(*currfd)); 459 currfd = &nfs_root_node; 460 } 461 462 free(newfd, sizeof(*newfd)); 463 newfd = 0; 464 465 continue; 466 } 467 468 if (currfd != &nfs_root_node) 469 free(currfd, sizeof(*currfd)); 470 currfd = newfd; 471 newfd = 0; 472 } 473 474 error = 0; 475 476 out: 477 if (!error) { 478 f->f_fsdata = (void *)currfd; 479 return (0); 480 } 481 482 #ifdef NFS_DEBUG 483 if (debug) 484 printf("nfs_open: %s lookupfh failed: %s\n", 485 path, strerror(error)); 486 #endif 487 if (currfd != &nfs_root_node) 488 free(currfd, sizeof(*currfd)); 489 if (newfd) 490 free(newfd, sizeof(*newfd)); 491 492 return (error); 493 } 494 495 int 496 nfs_close(struct open_file *f) 497 { 498 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 499 500 #ifdef NFS_DEBUG 501 if (debug) 502 printf("nfs_close: fp=%p\n", fp); 503 #endif 504 505 if (fp) 506 free(fp, sizeof(struct nfs_iodesc)); 507 f->f_fsdata = NULL; 508 509 return (0); 510 } 511 512 /* 513 * read a portion of a file 514 */ 515 int 516 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 517 { 518 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 519 ssize_t cc; 520 char *addr = buf; 521 522 #ifdef NFS_DEBUG 523 if (debug) 524 printf("nfs_read: size=%d off=%d\n", size, (int)fp->off); 525 #endif 526 while ((int)size > 0) { 527 twiddle(); 528 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 529 /* XXX maybe should retry on certain errors */ 530 if (cc == -1) { 531 #ifdef NFS_DEBUG 532 if (debug) 533 printf("nfs_read: read: %s", strerror(errno)); 534 #endif 535 return (errno); /* XXX - from nfs_readdata */ 536 } 537 if (cc == 0) { 538 #ifdef NFS_DEBUG 539 if (debug) 540 printf("nfs_read: hit EOF unexpectantly"); 541 #endif 542 goto ret; 543 } 544 fp->off += cc; 545 addr += cc; 546 size -= cc; 547 } 548 ret: 549 if (resid) 550 *resid = size; 551 552 return (0); 553 } 554 555 /* 556 * Not implemented. 557 */ 558 int 559 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 560 { 561 return (EROFS); 562 } 563 564 off_t 565 nfs_seek(struct open_file *f, off_t offset, int where) 566 { 567 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 568 u_int32_t size = ntohl(d->fa.fa_size); 569 570 switch (where) { 571 case SEEK_SET: 572 d->off = offset; 573 break; 574 case SEEK_CUR: 575 d->off += offset; 576 break; 577 case SEEK_END: 578 d->off = size - offset; 579 break; 580 default: 581 return (-1); 582 } 583 584 return (d->off); 585 } 586 587 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 588 const int nfs_stat_types[8] = { 589 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 590 }; 591 592 int 593 nfs_stat(struct open_file *f, struct stat *sb) 594 { 595 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 596 u_int32_t ftype, mode; 597 598 ftype = ntohl(fp->fa.fa_type); 599 mode = ntohl(fp->fa.fa_mode); 600 mode |= nfs_stat_types[ftype & 7]; 601 602 sb->st_mode = mode; 603 sb->st_nlink = ntohl(fp->fa.fa_nlink); 604 sb->st_uid = ntohl(fp->fa.fa_uid); 605 sb->st_gid = ntohl(fp->fa.fa_gid); 606 sb->st_size = ntohl(fp->fa.fa_size); 607 608 return (0); 609 } 610 611 /* 612 * Not implemented. 613 */ 614 #ifndef NO_READDIR 615 int 616 nfs_readdir(struct open_file *f, char *name) 617 { 618 return (EROFS); 619 } 620 #endif 621