xref: /dragonfly/contrib/tcpdump/parsenfsfh.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
1 /*
2  * Copyright (c) 1993, 1994 Jeffrey C. Mogul, Digital Equipment Corporation,
3  * Western Research Laboratory. All rights reserved.
4  * Copyright (c) 2001 Compaq Computer Corporation. All rights reserved.
5  *
6  *  Permission to use, copy, and modify this software and its
7  *  documentation is hereby granted only under the following terms and
8  *  conditions.  Both the above copyright notice and this permission
9  *  notice must appear in all copies of the software, derivative works
10  *  or modified versions, and any portions thereof, and both notices
11  *  must appear in supporting documentation.
12  *
13  *  Redistribution and use in source and binary forms, with or without
14  *  modification, are permitted provided that the following conditions
15  *  are met:
16  *    1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  *    2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in
20  *    the documentation and/or other materials provided with the
21  *    distribution.
22  *
23  *  THE SOFTWARE IS PROVIDED "AS IS" AND COMPAQ COMPUTER CORPORATION
24  *  DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25  *  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.   IN NO
26  *  EVENT SHALL COMPAQ COMPUTER CORPORATION BE LIABLE FOR ANY
27  *  SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
28  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
29  *  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
30  *  OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
31  *  SOFTWARE.
32  */
33 
34 /*
35  * parsenfsfh.c - portable parser for NFS file handles
36  *                            uses all sorts of heuristics
37  *
38  * Jeffrey C. Mogul
39  * Digital Equipment Corporation
40  * Western Research Laboratory
41  */
42 
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif
46 
47 #include "netdissect-stdinc.h"
48 
49 #include <stdio.h>
50 #include <string.h>
51 
52 #include "netdissect-ctype.h"
53 
54 #include "netdissect.h"
55 #include "extract.h"
56 #include "nfsfh.h"
57 
58 /*
59  * This routine attempts to parse a file handle (in network byte order),
60  * using heuristics to guess what kind of format it is in.  See the
61  * file "fhandle_layouts" for a detailed description of the various
62  * patterns we know about.
63  *
64  * The file handle is parsed into our internal representation of a
65  * file-system id, and an internal representation of an inode-number.
66  */
67 
68 #define   FHT_UNKNOWN         0
69 #define   FHT_AUSPEX          1
70 #define   FHT_DECOSF          2
71 #define   FHT_IRIX4 3
72 #define   FHT_IRIX5 4
73 #define   FHT_SUNOS3          5
74 #define   FHT_SUNOS4          6
75 #define   FHT_ULTRIX          7
76 #define   FHT_VMSUCX          8
77 #define   FHT_SUNOS5          9
78 #define   FHT_AIX32 10
79 #define   FHT_HPUX9 11
80 #define   FHT_BSD44 12
81 
82 static int is_UCX(netdissect_options *, const unsigned char *, u_int);
83 
84 void
Parse_fh(netdissect_options * ndo,const unsigned char * fh,u_int len,my_fsid * fsidp,uint32_t * inop,const char ** osnamep,const char ** fsnamep,int ourself)85 Parse_fh(netdissect_options *ndo, const unsigned char *fh, u_int len,
86            my_fsid *fsidp, uint32_t *inop,
87            const char **osnamep, /* if non-NULL, return OS name here */
88            const char **fsnamep, /* if non-NULL, return server fs name here (for VMS) */
89            int ourself)       /* true if file handle was generated on this host */
90 {
91           const unsigned char *fhp = fh;
92           uint32_t temp;
93           int fhtype = FHT_UNKNOWN;
94           u_int i;
95 
96           /*
97            * Require at least 16 bytes of file handle; it's variable-length
98            * in NFSv3.  "len" is in units of 32-bit words, not bytes.
99            */
100           if (len < 16/4)
101                     fhtype = FHT_UNKNOWN;
102           else {
103                     if (ourself) {
104                         /* File handle generated on this host, no need for guessing */
105 #if       defined(IRIX40)
106                         fhtype = FHT_IRIX4;
107 #endif
108 #if       defined(IRIX50)
109                         fhtype = FHT_IRIX5;
110 #endif
111 #if       defined(IRIX51)
112                         fhtype = FHT_IRIX5;
113 #endif
114 #if       defined(SUNOS4)
115                         fhtype = FHT_SUNOS4;
116 #endif
117 #if       defined(SUNOS5)
118                         fhtype = FHT_SUNOS5;
119 #endif
120 #if       defined(ultrix)
121                         fhtype = FHT_ULTRIX;
122 #endif
123 #if       defined(__osf__)
124                         fhtype = FHT_DECOSF;
125 #endif
126 #if       defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
127      || defined(__OpenBSD__)
128                         fhtype = FHT_BSD44;
129 #endif
130                     }
131                     /*
132                      * This is basically a big decision tree
133                      */
134                     else if ((GET_U_1(fhp) == 0) && (GET_U_1(fhp + 1) == 0)) {
135                         /* bytes[0,1] == (0,0); rules out Ultrix, IRIX5, SUNOS5 */
136                         /* probably rules out HP-UX, AIX unless they allow major=0 */
137                         if ((GET_U_1(fhp + 2) == 0) && (GET_U_1(fhp + 3) == 0)) {
138                               /* bytes[2,3] == (0,0); must be Auspex */
139                               /* XXX or could be Ultrix+MASSBUS "hp" disk? */
140                               fhtype = FHT_AUSPEX;
141                         }
142                         else {
143                               /*
144                                * bytes[2,3] != (0,0); rules out Auspex, could be
145                                * DECOSF, SUNOS4, or IRIX4
146                                */
147                               if ((GET_U_1(fhp + 4) != 0) && (GET_U_1(fhp + 5) == 0) &&
148                                         (GET_U_1(fhp + 8) == 12) && (GET_U_1(fhp + 9) == 0)) {
149                                   /* seems to be DECOSF, with minor == 0 */
150                                   fhtype = FHT_DECOSF;
151                               }
152                               else {
153                                   /* could be SUNOS4 or IRIX4 */
154                                   /* XXX the test of fhp[5] == 8 could be wrong */
155                                   if ((GET_U_1(fhp + 4) == 0) && (GET_U_1(fhp + 5) == 8) && (GET_U_1(fhp + 6) == 0) &&
156                                       (GET_U_1(fhp + 7) == 0)) {
157                                         /* looks like a length, not a file system typecode */
158                                         fhtype = FHT_IRIX4;
159                                   }
160                                   else {
161                                         /* by elimination */
162                                         fhtype = FHT_SUNOS4;
163                                   }
164                               }
165                         }
166                     }
167                     else {
168                         /*
169                          * bytes[0,1] != (0,0); rules out Auspex, IRIX4, SUNOS4
170                          * could be IRIX5, DECOSF, UCX, Ultrix, SUNOS5
171                          * could be AIX, HP-UX
172                          */
173                         if ((GET_U_1(fhp + 2) == 0) && (GET_U_1(fhp + 3) == 0)) {
174                               /*
175                                * bytes[2,3] == (0,0); rules out OSF, probably not UCX
176                                * (unless the exported device name is just one letter!),
177                                * could be Ultrix, IRIX5, AIX, or SUNOS5
178                                * might be HP-UX (depends on their values for minor devs)
179                                */
180                               if ((GET_U_1(fhp + 6) == 0) && (GET_U_1(fhp + 7) == 0)) {
181                                   fhtype = FHT_BSD44;
182                               }
183                               /*XXX we probably only need to test of these two bytes */
184                               else if ((len >= 24/4) && (GET_U_1(fhp + 21) == 0) && (GET_U_1(fhp + 23) == 0)) {
185                                   fhtype = FHT_ULTRIX;
186                               }
187                               else {
188                                   /* Could be SUNOS5/IRIX5, maybe AIX */
189                                   /* XXX no obvious difference between SUNOS5 and IRIX5 */
190                                   if (GET_U_1(fhp + 9) == 10)
191                                         fhtype = FHT_SUNOS5;
192                                   /* XXX what about AIX? */
193                               }
194                         }
195                         else {
196                               /*
197                                * bytes[2,3] != (0,0); rules out Ultrix, could be
198                                * DECOSF, SUNOS5, IRIX5, AIX, HP-UX, or UCX
199                                */
200                               if ((GET_U_1(fhp + 8) == 12) && (GET_U_1(fhp + 9) == 0)) {
201                                   fhtype = FHT_DECOSF;
202                               }
203                               else if ((GET_U_1(fhp + 8) == 0) && (GET_U_1(fhp + 9) == 10)) {
204                                   /* could be SUNOS5/IRIX5, AIX, HP-UX */
205                                   if ((GET_U_1(fhp + 7) == 0) && (GET_U_1(fhp + 6) == 0) &&
206                                         (GET_U_1(fhp + 5) == 0) && (GET_U_1(fhp + 4) == 0)) {
207                                         /* XXX is this always true of HP-UX? */
208                                         fhtype = FHT_HPUX9;
209                                   }
210                                   else if (GET_U_1(fhp + 7) == 2) {
211                                         /* This would be MNT_NFS on AIX, which is impossible */
212                                         fhtype = FHT_SUNOS5;          /* or maybe IRIX5 */
213                                   }
214                                   else {
215                                         /*
216                                          * XXX Could be SUNOS5/IRIX5 or AIX.  I don't
217                                          * XXX see any way to disambiguate these, so
218                                          * XXX I'm going with the more likely guess.
219                                          * XXX Sorry, Big Blue.
220                                          */
221                                         fhtype = FHT_SUNOS5;          /* or maybe IRIX5 */
222                                   }
223                             }
224                               else {
225                                   if (is_UCX(ndo, fhp, len)) {
226                                         fhtype = FHT_VMSUCX;
227                                   }
228                                   else {
229                                         fhtype = FHT_UNKNOWN;
230                                   }
231                               }
232                         }
233                     }
234           }
235 
236           /* XXX still needs to handle SUNOS3 */
237 
238           switch (fhtype) {
239           case FHT_AUSPEX:
240               fsidp->Fsid_dev.Minor = GET_U_1(fhp + 7);
241               fsidp->Fsid_dev.Major = GET_U_1(fhp + 6);
242               fsidp->fsid_code = 0;
243 
244               *inop = GET_BE_U_4(fhp + 12);
245 
246               if (osnamep)
247                     *osnamep = "Auspex";
248               break;
249 
250           case FHT_BSD44:
251               fsidp->Fsid_dev.Minor = GET_U_1(fhp);
252               fsidp->Fsid_dev.Major = GET_U_1(fhp + 1);
253               fsidp->fsid_code = 0;
254 
255               *inop = GET_LE_U_4(fhp + 12);
256 
257               if (osnamep)
258                     *osnamep = "BSD 4.4";
259               break;
260 
261           case FHT_DECOSF:
262               fsidp->fsid_code = GET_LE_U_4(fhp + 4);
263                               /* XXX could ignore 3 high-order bytes */
264 
265               temp = GET_LE_U_4(fhp);
266               fsidp->Fsid_dev.Minor = temp & 0xFFFFF;
267               fsidp->Fsid_dev.Major = (temp>>20) & 0xFFF;
268 
269               *inop = GET_LE_U_4(fhp + 12);
270               if (osnamep)
271                     *osnamep = "OSF";
272               break;
273 
274           case FHT_IRIX4:
275               fsidp->Fsid_dev.Minor = GET_U_1(fhp + 3);
276               fsidp->Fsid_dev.Major = GET_U_1(fhp + 2);
277               fsidp->fsid_code = 0;
278 
279               *inop = GET_BE_U_4(fhp + 8);
280 
281               if (osnamep)
282                     *osnamep = "IRIX4";
283               break;
284 
285           case FHT_IRIX5:
286               fsidp->Fsid_dev.Minor = GET_BE_U_2(fhp + 2);
287               fsidp->Fsid_dev.Major = GET_BE_U_2(fhp);
288               fsidp->fsid_code = GET_BE_U_4(fhp + 4);
289 
290               *inop = GET_BE_U_4(fhp + 12);
291 
292               if (osnamep)
293                     *osnamep = "IRIX5";
294               break;
295 
296 #ifdef notdef
297           case FHT_SUNOS3:
298               /*
299                * XXX - none of the heuristics above return this.
300                * Are there any SunOS 3.x systems around to care about?
301                */
302               if (osnamep)
303                     *osnamep = "SUNOS3";
304               break;
305 #endif
306 
307           case FHT_SUNOS4:
308               fsidp->Fsid_dev.Minor = GET_U_1(fhp + 3);
309               fsidp->Fsid_dev.Major = GET_U_1(fhp + 2);
310               fsidp->fsid_code = GET_BE_U_4(fhp + 4);
311 
312               *inop = GET_BE_U_4(fhp + 12);
313 
314               if (osnamep)
315                     *osnamep = "SUNOS4";
316               break;
317 
318           case FHT_SUNOS5:
319               temp = GET_BE_U_2(fhp);
320               fsidp->Fsid_dev.Major = (temp>>2) &  0x3FFF;
321               temp = GET_BE_U_3(fhp + 1);
322               fsidp->Fsid_dev.Minor = temp & 0x3FFFF;
323               fsidp->fsid_code = GET_BE_U_4(fhp + 4);
324 
325               *inop = GET_BE_U_4(fhp + 12);
326 
327               if (osnamep)
328                     *osnamep = "SUNOS5";
329               break;
330 
331           case FHT_ULTRIX:
332               fsidp->fsid_code = 0;
333               fsidp->Fsid_dev.Minor = GET_U_1(fhp);
334               fsidp->Fsid_dev.Major = GET_U_1(fhp + 1);
335 
336               temp = GET_LE_U_4(fhp + 4);
337               *inop = temp;
338               if (osnamep)
339                     *osnamep = "Ultrix";
340               break;
341 
342           case FHT_VMSUCX:
343               /* No numeric file system ID, so hash on the device-name */
344               if (sizeof(*fsidp) >= 14) {
345                     if (sizeof(*fsidp) > 14)
346                         memset((char *)fsidp, 0, sizeof(*fsidp));
347                     /* just use the whole thing */
348                     memcpy((char *)fsidp, (const char *)fh, 14);
349               }
350               else {
351                     uint32_t tempa[4];  /* at least 16 bytes, maybe more */
352 
353                     memset((char *)tempa, 0, sizeof(tempa));
354                     memcpy((char *)tempa, (const char *)fh, 14); /* ensure alignment */
355                     fsidp->Fsid_dev.Minor = tempa[0] + (tempa[1]<<1);
356                     fsidp->Fsid_dev.Major = tempa[2] + (tempa[3]<<1);
357                     fsidp->fsid_code = 0;
358               }
359 
360               /* VMS file ID is: (RVN, FidHi, FidLo) */
361               *inop = (((uint32_t) GET_U_1(fhp + 26)) << 24) |
362                         (((uint32_t) GET_U_1(fhp + 27)) << 16) |
363                         (GET_LE_U_2(fhp + 22) << 0);
364 
365               /* Caller must save (and null-terminate?) this value */
366               if (fsnamep)
367                     *fsnamep = (const char *)(fhp + 1);
368 
369               if (osnamep)
370                     *osnamep = "VMS";
371               break;
372 
373           case FHT_AIX32:
374               fsidp->Fsid_dev.Minor = GET_BE_U_2(fhp + 2);
375               fsidp->Fsid_dev.Major = GET_BE_U_2(fhp);
376               fsidp->fsid_code = GET_BE_U_4(fhp + 4);
377 
378               *inop = GET_BE_U_4(fhp + 12);
379 
380               if (osnamep)
381                     *osnamep = "AIX32";
382               break;
383 
384           case FHT_HPUX9:
385               fsidp->Fsid_dev.Major = GET_U_1(fhp);
386               temp = GET_BE_U_3(fhp + 1);
387               fsidp->Fsid_dev.Minor = temp;
388               fsidp->fsid_code = GET_BE_U_4(fhp + 4);
389 
390               *inop = GET_BE_U_4(fhp + 12);
391 
392               if (osnamep)
393                     *osnamep = "HPUX9";
394               break;
395 
396           case FHT_UNKNOWN:
397 #ifdef DEBUG
398               /* XXX debugging */
399               for (i = 0; i < len*4; i++)
400                     (void)fprintf(stderr, "%x.", GET_U_1(fhp + i));
401               (void)fprintf(stderr, "\n");
402 #endif
403               /* Save the actual handle, so it can be display with -u */
404               for (i = 0; i < len*4 && i*2 < sizeof(fsidp->Opaque_Handle) - 1; i++)
405                     (void)snprintf(&(fsidp->Opaque_Handle[i*2]), 3, "%.2X",
406                                      GET_U_1(fhp + i));
407               fsidp->Opaque_Handle[i*2] = '\0';
408 
409               /* XXX for now, give "bogus" values to aid debugging */
410               fsidp->fsid_code = 0;
411               fsidp->Fsid_dev.Minor = 257;
412               fsidp->Fsid_dev.Major = 257;
413               *inop = 1;
414 
415               /* display will show this string instead of (257,257) */
416               if (fsnamep)
417                     *fsnamep = "Unknown";
418 
419               if (osnamep)
420                     *osnamep = "Unknown";
421               break;
422 
423           }
424 }
425 
426 /*
427  * Is this a VMS UCX file handle?
428  *        Check for:
429  *        (1) leading code byte         [XXX not yet]
430  *        (2) followed by string of printing chars & spaces
431  *        (3) followed by string of nulls
432  */
433 static int
is_UCX(netdissect_options * ndo,const unsigned char * fhp,u_int len)434 is_UCX(netdissect_options *ndo, const unsigned char *fhp, u_int len)
435 {
436           u_int i;
437           int seen_null = 0;
438 
439           /*
440            * Require at least 28 bytes of file handle; it's variable-length
441            * in NFSv3.  "len" is in units of 32-bit words, not bytes.
442            */
443           if (len < 28/4)
444                     return(0);
445 
446           for (i = 1; i < 14; i++) {
447               if (ND_ASCII_ISPRINT(GET_U_1(fhp + i))) {
448                     if (seen_null)
449                        return(0);
450                     else
451                        continue;
452               }
453               else if (GET_U_1(fhp + i) == 0) {
454                     seen_null = 1;
455                     continue;
456               }
457               else
458                     return(0);
459           }
460 
461           return(1);
462 }
463