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 1991-2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/errno.h>
31 #include <sys/tiuser.h>
32 #include <setjmp.h>
33 
34 #include <rpc/types.h>
35 #include <rpc/xdr.h>
36 #include <rpc/auth.h>
37 #include <rpc/clnt.h>
38 #include <rpc/rpc_msg.h>
39 #include <string.h>
40 #include "snoop.h"
41 #include "snoop_nfs.h"
42 
43 #include <sys/stat.h>
44 #include <rpcsvc/nfs_prot.h>
45 
46 static char *perms(int);
47 static char *filetype(int);
48 static char *sum_readdirres(void);
49 static void detail_readdirres(void);
50 static void detail_diroparg(void);
51 static void nfscall2(int);
52 static void nfsreply2(int);
53 static void detail_mode(int);
54 static void detail_sattr(void);
55 static void interpret_nfs2(int, int, int, int, int, char *, int);
56 
57 extern jmp_buf xdr_err;
58 
59 static char *procnames_short[] = {
60 	"NULL2",	/*  0 */
61 	"GETATTR2",	/*  1 */
62 	"SETATTR2",	/*  2 */
63 	"ROOT2",	/*  3 */
64 	"LOOKUP2",	/*  4 */
65 	"READLINK2",	/*  5 */
66 	"READ2",	/*  6 */
67 	"WRITECACHE2",	/*  7 */
68 	"WRITE2",	/*  8 */
69 	"CREATE2",	/*  9 */
70 	"REMOVE2",	/* 10 */
71 	"RENAME2",	/* 11 */
72 	"LINK2",	/* 12 */
73 	"SYMLINK2",	/* 13 */
74 	"MKDIR2",	/* 14 */
75 	"RMDIR2",	/* 15 */
76 	"READDIR2",	/* 16 */
77 	"STATFS2",	/* 17 */
78 };
79 
80 static char *procnames_long[] = {
81 	"Null procedure",		/*  0 */
82 	"Get file attributes",		/*  1 */
83 	"Set file attributes",		/*  2 */
84 	"Get root filehandle",		/*  3 */
85 	"Look up file name",		/*  4 */
86 	"Read from symbolic link",	/*  5 */
87 	"Read from file",		/*  6 */
88 	"Write to cache",		/*  7 */
89 	"Write to file",		/*  8 */
90 	"Create file",			/*  9 */
91 	"Remove file",			/* 10 */
92 	"Rename",			/* 11 */
93 	"Link",				/* 12 */
94 	"Make symbolic link",		/* 13 */
95 	"Make directory",		/* 14 */
96 	"Remove directory",		/* 15 */
97 	"Read from directory",		/* 16 */
98 	"Get filesystem attributes",	/* 17 */
99 };
100 
101 #define	MAXPROC	17
102 
103 /* ARGSUSED */
104 void
105 interpret_nfs(flags, type, xid, vers, proc, data, len)
106 	int flags, type, xid, vers, proc;
107 	char *data;
108 	int len;
109 {
110 
111 	if (vers == 2) {
112 		interpret_nfs2(flags, type, xid, vers, proc, data, len);
113 		return;
114 	}
115 
116 	if (vers == 3) {
117 		interpret_nfs3(flags, type, xid, vers, proc, data, len);
118 		return;
119 	}
120 
121 	if (vers == 4) {
122 		interpret_nfs4(flags, type, xid, vers, proc, data, len);
123 		return;
124 	}
125 }
126 
127 static void
128 interpret_nfs2(flags, type, xid, vers, proc, data, len)
129 	int flags, type, xid, vers, proc;
130 	char *data;
131 	int len;
132 {
133 	char *line;
134 	char buff[NFS_MAXPATHLEN + 1];
135 	int off, sz;
136 	char *fh;
137 
138 	if (proc < 0 || proc > MAXPROC)
139 		return;
140 
141 	if (flags & F_SUM) {
142 		line = get_sum_line();
143 
144 		if (type == CALL) {
145 			(void) sprintf(line,
146 				"NFS C %s",
147 				procnames_short[proc]);
148 			line += strlen(line);
149 			switch (proc) {
150 			case NFSPROC_GETATTR:
151 			case NFSPROC_READLINK:
152 			case NFSPROC_STATFS:
153 			case NFSPROC_SETATTR:
154 				(void) sprintf(line, sum_nfsfh());
155 				break;
156 			case NFSPROC_LOOKUP:
157 			case NFSPROC_REMOVE:
158 			case NFSPROC_RMDIR:
159 			case NFSPROC_CREATE:
160 			case NFSPROC_MKDIR:
161 				fh = sum_nfsfh();
162 				(void) sprintf(line, "%s %s",
163 					fh,
164 					getxdr_string(buff, NFS_MAXNAMLEN));
165 				break;
166 			case NFSPROC_WRITE:
167 				fh = sum_nfsfh();
168 				(void) getxdr_long();	/* beginoff */
169 				off = getxdr_long();
170 				(void) getxdr_long();	/* totalcount */
171 				sz  = getxdr_long();
172 				(void) sprintf(line, "%s at %d for %d",
173 					fh, off, sz);
174 				break;
175 			case NFSPROC_RENAME:
176 				fh = sum_nfsfh();
177 				(void) sprintf(line, "%s %s",
178 					fh,
179 					getxdr_string(buff, NFS_MAXNAMLEN));
180 				line += strlen(line);
181 				fh = sum_nfsfh();
182 				(void) sprintf(line, " to%s %s",
183 					fh,
184 					getxdr_string(buff, NFS_MAXNAMLEN));
185 				break;
186 			case NFSPROC_LINK:
187 				fh = sum_nfsfh();
188 				(void) sprintf(line, "%s", fh);
189 				line += strlen(line);
190 				fh = sum_nfsfh();
191 				(void) sprintf(line, " to%s %s",
192 					fh,
193 					getxdr_string(buff, NFS_MAXNAMLEN));
194 				break;
195 			case NFSPROC_SYMLINK:
196 				fh = sum_nfsfh();
197 				(void) sprintf(line, "%s %s",
198 					fh,
199 					getxdr_string(buff, NFS_MAXNAMLEN));
200 				line += strlen(line);
201 				(void) sprintf(line, " to %s",
202 					getxdr_string(buff, NFS_MAXPATHLEN));
203 				break;
204 			case NFSPROC_READDIR:
205 				fh = sum_nfsfh();
206 				(void) sprintf(line, "%s Cookie=%lu",
207 					fh, getxdr_u_long());
208 				break;
209 			case NFSPROC_READ:
210 				fh = sum_nfsfh();
211 				off = getxdr_long();
212 				sz  = getxdr_long();
213 				(void) sprintf(line, "%s at %d for %d",
214 					fh, off, sz);
215 				break;
216 			default:
217 				break;
218 			}
219 
220 			check_retransmit(line, (ulong_t)xid);
221 		} else {
222 			(void) sprintf(line, "NFS R %s ",
223 				procnames_short[proc]);
224 			line += strlen(line);
225 			switch (proc) {
226 			case NFSPROC_CREATE:
227 			case NFSPROC_MKDIR:
228 			case NFSPROC_LOOKUP:
229 				if (sum_nfsstat(line) == 0) {
230 					line += strlen(line);
231 					(void) sprintf(line, sum_nfsfh());
232 				}
233 				break;
234 			case NFSPROC_READLINK:
235 				if (sum_nfsstat(line) == 0) {
236 					line += strlen(line);
237 					(void) sprintf(line, " (Path=%s)",
238 						getxdr_string(buff,
239 							NFS_MAXPATHLEN));
240 				}
241 				break;
242 			case NFSPROC_GETATTR:
243 			case NFSPROC_SYMLINK:
244 			case NFSPROC_STATFS:
245 			case NFSPROC_SETATTR:
246 			case NFSPROC_REMOVE:
247 			case NFSPROC_RMDIR:
248 			case NFSPROC_WRITE:
249 			case NFSPROC_RENAME:
250 			case NFSPROC_LINK:
251 				(void) sum_nfsstat(line);
252 				break;
253 			case NFSPROC_READDIR:
254 				if (sum_nfsstat(line) == 0) {
255 					line += strlen(line);
256 					(void) strcat(line, sum_readdirres());
257 				}
258 				break;
259 			case NFSPROC_READ:
260 				if (sum_nfsstat(line) == 0) {
261 					line += strlen(line);
262 					xdr_skip(68); /* fattrs */
263 					(void) sprintf(line, " (%ld bytes)",
264 						getxdr_long());
265 				}
266 				break;
267 			default:
268 				break;
269 			}
270 		}
271 	}
272 
273 	if (flags & F_DTAIL) {
274 		show_header("NFS:  ", "Sun NFS", len);
275 		show_space();
276 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
277 			proc, procnames_long[proc]);
278 		if (type == CALL)
279 			nfscall2(proc);
280 		else
281 			nfsreply2(proc);
282 		show_trailer();
283 	}
284 }
285 
286 /*
287  *  Print out version 2 NFS call packets
288  */
289 static void
290 nfscall2(proc)
291 	int proc;
292 {
293 	switch (proc) {
294 	case NFSPROC_GETATTR:
295 	case NFSPROC_READLINK:
296 	case NFSPROC_STATFS:
297 		detail_nfsfh();
298 		break;
299 	case NFSPROC_SETATTR:
300 		detail_nfsfh();
301 		detail_sattr();
302 		break;
303 	case NFSPROC_LOOKUP:
304 	case NFSPROC_REMOVE:
305 	case NFSPROC_RMDIR:
306 		detail_diroparg();
307 		break;
308 	case NFSPROC_MKDIR:
309 	case NFSPROC_CREATE:
310 		detail_diroparg();
311 		detail_sattr();
312 		break;
313 	case NFSPROC_WRITE:
314 		detail_nfsfh();
315 		(void) getxdr_long();	/* begoff */
316 		(void) showxdr_long("Offset = %d");
317 		(void) getxdr_long();	/* totalcount */
318 		(void) showxdr_long("(%d bytes(s) of data)");
319 		break;
320 	case NFSPROC_RENAME:
321 		detail_diroparg();
322 		detail_diroparg();
323 		break;
324 	case NFSPROC_LINK:
325 		detail_nfsfh();
326 		detail_diroparg();
327 		break;
328 	case NFSPROC_SYMLINK:
329 		detail_diroparg();
330 		(void) showxdr_string(NFS_MAXPATHLEN, "Path = %s");
331 		detail_sattr();
332 		break;
333 	case NFSPROC_READDIR:
334 		detail_nfsfh();
335 		(void) showxdr_u_long("Cookie = %lu");
336 		(void) showxdr_long("Count = %d");
337 		break;
338 	case NFSPROC_READ:
339 		detail_nfsfh();
340 		(void) showxdr_long("Offset = %d");
341 		(void) showxdr_long("Count = %d");
342 		break;
343 	default:
344 		break;
345 	}
346 }
347 
348 /*
349  *  Print out version 2 NFS reply packets
350  */
351 static void
352 nfsreply2(proc)
353 	int proc;
354 {
355 	switch (proc) {
356 	    case NFSPROC_GETATTR:
357 	    case NFSPROC_SETATTR:
358 	    case NFSPROC_WRITE:
359 		/* attrstat */
360 		if (detail_nfsstat() == 0) {
361 			detail_fattr();
362 		}
363 		break;
364 	    case NFSPROC_LOOKUP:
365 	    case NFSPROC_CREATE:
366 	    case NFSPROC_MKDIR:
367 		/* diropres */
368 		if (detail_nfsstat() == 0) {
369 			detail_nfsfh();
370 			detail_fattr();
371 		}
372 		break;
373 	    case NFSPROC_READLINK:
374 		/* readlinkres */
375 		if (detail_nfsstat() == 0) {
376 			(void) showxdr_string(NFS_MAXPATHLEN, "Path = %s");
377 		}
378 		break;
379 	    case NFSPROC_READ:
380 		/* readres */
381 		if (detail_nfsstat() == 0) {
382 			detail_fattr();
383 			(void) showxdr_long("(%d byte(s) of data)");
384 		}
385 		break;
386 	    case NFSPROC_REMOVE:
387 	    case NFSPROC_RENAME:
388 	    case NFSPROC_LINK:
389 	    case NFSPROC_SYMLINK:
390 	    case NFSPROC_RMDIR:
391 		/* stat */
392 		detail_nfsstat();
393 		break;
394 	    case NFSPROC_READDIR:
395 		/* readdirres */
396 		if (detail_nfsstat() == 0)
397 			detail_readdirres();
398 		break;
399 	    case NFSPROC_STATFS:
400 		/* statfsres */
401 		if (detail_nfsstat() == 0) {
402 			(void) showxdr_long("Transfer size = %d");
403 			(void) showxdr_long("Block size = %d");
404 			(void) showxdr_long("Total blocks = %d");
405 			(void) showxdr_long("Free blocks = %d");
406 			(void) showxdr_long("Available blocks = %d");
407 		}
408 		break;
409 	    default:
410 		break;
411 	}
412 }
413 
414 static void
415 detail_diroparg()
416 {
417 	detail_nfsfh();
418 	(void) showxdr_string(NFS_MAXPATHLEN, "File name = %s");
419 }
420 
421 /*
422  * V2 NFS protocol was implicitly linked with SunOS errnos.
423  * Some of the errno values changed in SVr4.
424  * Need to map errno value so that SVr4 snoop will interpret
425  * them correctly.
426  */
427 static char *
428 statusmsg(status)
429 	ulong_t status;
430 {
431 	switch (status) {
432 	case NFS_OK: return ("OK");
433 	case NFSERR_PERM: return ("Not owner");
434 	case NFSERR_NOENT: return ("No such file or directory");
435 	case NFSERR_IO: return ("I/O error");
436 	case NFSERR_NXIO: return ("No such device or address");
437 	case NFSERR_ACCES: return ("Permission denied");
438 	case NFSERR_EXIST: return ("File exists");
439 	case NFSERR_XDEV: return ("Cross-device link");
440 	case NFSERR_NODEV: return ("No such device");
441 	case NFSERR_NOTDIR: return ("Not a directory");
442 	case NFSERR_ISDIR: return ("Is a directory");
443 	case NFSERR_INVAL: return ("Invalid argument");
444 	case NFSERR_FBIG: return ("File too large");
445 	case NFSERR_NOSPC: return ("No space left on device");
446 	case NFSERR_ROFS: return ("Read-only file system");
447 	case NFSERR_OPNOTSUPP: return ("Operation not supported");
448 	case NFSERR_NAMETOOLONG: return ("File name too long");
449 	case NFSERR_NOTEMPTY: return ("Directory not empty");
450 	case NFSERR_DQUOT: return ("Disc quota exceeded");
451 	case NFSERR_STALE: return ("Stale NFS file handle");
452 	case NFSERR_REMOTE: return ("Object is remote");
453 	case NFSERR_WFLUSH: return ("write cache flushed");
454 	default: return ("(unknown error)");
455 	}
456 	/* NOTREACHED */
457 }
458 
459 int
460 sum_nfsstat(line)
461 	char *line;
462 {
463 	ulong_t status;
464 
465 	status = getxdr_long();
466 	(void) strcpy(line, statusmsg(status));
467 	return (status);
468 }
469 
470 int
471 detail_nfsstat()
472 {
473 	ulong_t status;
474 	int pos;
475 
476 	pos = getxdr_pos();
477 	status = getxdr_long();
478 	(void) sprintf(get_line(pos, getxdr_pos()),
479 		"Status = %lu (%s)",
480 		status, statusmsg(status));
481 
482 	return ((int)status);
483 }
484 
485 int
486 sum_filehandle(len)
487 	int len;
488 {
489 	int i, l;
490 	int fh = 0;
491 
492 	for (i = 0; i < len; i += 4) {
493 		l = getxdr_long();
494 		fh ^= (l >> 16) ^ l;
495 	}
496 
497 	return (fh);
498 }
499 
500 char *
501 sum_nfsfh()
502 {
503 	int fh;
504 	static char buff[16];
505 
506 	fh = sum_filehandle(NFS_FHSIZE);
507 	(void) sprintf(buff, " FH=%04X", fh & 0xFFFF);
508 	return (buff);
509 }
510 
511 void
512 detail_nfsfh()
513 {
514 	int pos;
515 	int fh;
516 
517 	pos = getxdr_pos();
518 	fh = sum_filehandle(NFS_FHSIZE);
519 	setxdr_pos(pos);
520 	(void) sprintf(get_line(0, 0), "File handle = [%04X]", fh & 0xFFFF);
521 	(void) showxdr_hex(NFS_FHSIZE, " %s");
522 }
523 
524 static void
525 detail_mode(mode)
526 	int mode;
527 {
528 	char *str;
529 
530 	switch (mode & S_IFMT) {
531 	case S_IFDIR: str = "Directory";	break;
532 	case S_IFCHR: str = "Character";	break;
533 	case S_IFBLK: str = "Block";		break;
534 	case S_IFREG: str = "Regular file";	break;
535 	case S_IFLNK: str = "Link";		break;
536 	case S_IFSOCK: str = "Socket";		break;
537 	case S_IFIFO: str = "Fifo";		break;
538 	default: str = "?";			break;
539 	}
540 
541 	(void) sprintf(get_line(0, 0), "Mode = 0%o", mode);
542 	(void) sprintf(get_line(0, 0), " Type = %s", str);
543 	(void) sprintf(get_line(0, 0),
544 		" Setuid = %d, Setgid = %d, Sticky = %d",
545 		(mode & S_ISUID) != 0,
546 		(mode & S_ISGID) != 0,
547 		(mode & S_ISVTX) != 0);
548 	(void) sprintf(get_line(0, 0), " Owner's permissions = %s",
549 		perms(mode >> 6 & 0x7));
550 	(void) sprintf(get_line(0, 0), " Group's permissions = %s",
551 		perms(mode >> 3 & 0x7));
552 	(void) sprintf(get_line(0, 0), " Other's permissions = %s",
553 		perms(mode & 0x7));
554 }
555 
556 void
557 detail_fattr()
558 {
559 	int fltype, mode, nlinks, uid, gid, size, blksz;
560 	int rdev, blocks, fsid, fileid;
561 
562 	fltype = getxdr_long();
563 	mode = getxdr_long();
564 	nlinks = getxdr_long();
565 	uid = getxdr_long();
566 	gid = getxdr_long();
567 	size = getxdr_long();
568 	blksz = getxdr_long();
569 	rdev = getxdr_long();
570 	blocks = getxdr_long();
571 	fsid = getxdr_long();
572 	fileid = getxdr_long();
573 
574 	(void) sprintf(get_line(0, 0),
575 		"File type = %d (%s)",
576 		fltype, filetype(fltype));
577 	detail_mode(mode);
578 	(void) sprintf(get_line(0, 0),
579 		"Link count = %d, UID = %d, GID = %d, Rdev = 0x%x",
580 		nlinks, uid, gid, rdev);
581 	(void) sprintf(get_line(0, 0),
582 		"File size = %d, Block size = %d, No. of blocks = %d",
583 		size, blksz, blocks);
584 	(void) sprintf(get_line(0, 0),
585 		"File system id = %d, File id = %d",
586 		fsid, fileid);
587 	(void) showxdr_date("Access time       = %s");
588 	(void) showxdr_date("Modification time = %s");
589 	(void) showxdr_date("Inode change time = %s");
590 }
591 
592 static void
593 detail_sattr()
594 {
595 	int mode;
596 
597 	mode = getxdr_long();
598 	detail_mode(mode);
599 	(void) showxdr_long("UID = %d");
600 	(void) showxdr_long("GID = %d");
601 	(void) showxdr_long("Size = %d");
602 	(void) showxdr_date("Access time       = %s");
603 	(void) showxdr_date("Modification time = %s");
604 }
605 
606 static char *
607 filetype(n)
608 	int n;
609 {
610 	switch (n) {
611 	    case NFREG: return ("Regular File");
612 	    case NFDIR: return ("Directory");
613 	    case NFBLK: return ("Block special");
614 	    case NFCHR: return ("Character special");
615 	    case NFLNK: return ("Symbolic Link");
616 	    default:	return ("?");
617 	}
618 }
619 
620 static char *
621 perms(n)
622 	int n;
623 {
624 	static char buff[4];
625 
626 	buff[0] = n & 4 ? 'r' : '-';
627 	buff[1] = n & 2 ? 'w' : '-';
628 	buff[2] = n & 1 ? 'x' : '-';
629 	buff[3] = '\0';
630 	return (buff);
631 }
632 
633 static char *
634 sum_readdirres()
635 {
636 	static char buff[NFS_MAXNAMLEN + 1];
637 	int entries = 0;
638 
639 	if (setjmp(xdr_err)) {
640 		(void) sprintf(buff, " %d+ entries (incomplete)", entries);
641 		return (buff);
642 	}
643 	while (getxdr_long()) {
644 		entries++;
645 		(void) getxdr_long();			/* fileid */
646 		(void) getxdr_string(buff, NFS_MAXNAMLEN); /* name */
647 		(void) getxdr_u_long();			/* cookie */
648 	}
649 
650 	(void) sprintf(buff, " %d entries (%s)",
651 		entries,
652 		getxdr_long() ? "No more" : "More");
653 	return (buff);
654 }
655 
656 static void
657 detail_readdirres()
658 {
659 	ulong_t fileid, cookie;
660 	int entries = 0;
661 	char *name;
662 	char buff[NFS_MAXNAMLEN + 1];
663 
664 	(void) sprintf(get_line(0, 0), " File id  Cookie Name");
665 
666 	if (setjmp(xdr_err)) {
667 		(void) sprintf(get_line(0, 0),
668 			"  %d+ entries. (Frame is incomplete)",
669 			entries);
670 		return;
671 	}
672 	while (getxdr_long()) {
673 		entries++;
674 		fileid = getxdr_long();
675 		name = (char *)getxdr_string(buff, NFS_MAXNAMLEN);
676 		cookie = getxdr_u_long();
677 		(void) sprintf(get_line(0, 0),
678 			" %7lu %7lu %s",
679 			fileid, cookie, name);
680 	}
681 
682 	(void) sprintf(get_line(0, 0), "  %d entries", entries);
683 	(void) showxdr_long("EOF = %d");
684 }
685 
686 void
687 skip_fattr()
688 {
689 
690 	xdr_skip(17 * 4);	/* XDR sizeof nfsfattr */
691 }
692