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