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