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
interpret_nfs(flags,type,xid,vers,proc,data,len)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
interpret_nfs2(flags,type,xid,vers,proc,data,len)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
nfscall2(proc)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
nfsreply2(proc)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
detail_diroparg()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 *
statusmsg(status)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
sum_nfsstat(line)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
detail_nfsstat()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
sum_filehandle(len)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 *
sum_nfsfh()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
detail_nfsfh()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
detail_mode(mode)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
detail_fattr()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
detail_sattr()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 *
filetype(n)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 *
perms(n)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 *
sum_readdirres()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
detail_readdirres()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
skip_fattr()685 skip_fattr()
686 {
687
688 xdr_skip(17 * 4); /* XDR sizeof nfsfattr */
689 }
690