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
46static char *perms(int);
47static char *filetype(int);
48static char *sum_readdirres(void);
49static void detail_readdirres(void);
50static void detail_diroparg(void);
51static void nfscall2(int);
52static void nfsreply2(int);
53static void detail_mode(int);
54static void detail_sattr(void);
55static void interpret_nfs2(int, int, int, int, int, char *, int);
56
57extern jmp_buf xdr_err;
58
59static 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
80static 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 */
104void
105interpret_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
127static void
128interpret_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 */
289static void
290nfscall2(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 */
351static void
352nfsreply2(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
414static void
415detail_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 */
427static char *
428statusmsg(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
459int
460sum_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
470int
471detail_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
485int
486sum_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
500char *
501sum_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
511void
512detail_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
524static void
525detail_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
556void
557detail_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
592static void
593detail_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
606static char *
607filetype(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
620static char *
621perms(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
633static char *
634sum_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
656static void
657detail_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
686void
687skip_fattr()
688{
689
690	xdr_skip(17 * 4);	/* XDR sizeof nfsfattr */
691}
692