xref: /freebsd/contrib/tcpdump/parsenfsfh.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 /*
2  * parsenfsfh.c - portable parser for NFS file handles
3  *			uses all sorts of heuristics
4  *
5  * Jeffrey C. Mogul
6  * Digital Equipment Corporation
7  * Western Research Laboratory
8  */
9 
10 #ifndef lint
11 static const char rcsid[] =
12     "@(#) $Header: parsenfsfh.c,v 1.14 97/06/15 13:20:27 leres Exp $ (LBL)";
13 #endif
14 
15 #include <sys/types.h>
16 #include <sys/time.h>
17 
18 #include <ctype.h>
19 #ifdef HAVE_MEMORY_H
20 #include <memory.h>
21 #endif
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include "interface.h"
26 #include "nfsfh.h"
27 
28 /*
29  * This routine attempts to parse a file handle (in network byte order),
30  * using heuristics to guess what kind of format it is in.  See the
31  * file "fhandle_layouts" for a detailed description of the various
32  * patterns we know about.
33  *
34  * The file handle is parsed into our internal representation of a
35  * file-system id, and an internal representation of an inode-number.
36  */
37 
38 #define	FHT_UNKNOWN	0
39 #define	FHT_AUSPEX	1
40 #define	FHT_DECOSF	2
41 #define	FHT_IRIX4	3
42 #define	FHT_IRIX5	4
43 #define	FHT_SUNOS3	5
44 #define	FHT_SUNOS4	6
45 #define	FHT_ULTRIX	7
46 #define	FHT_VMSUCX	8
47 #define	FHT_SUNOS5	9
48 #define	FHT_AIX32	10
49 #define	FHT_HPUX9	11
50 
51 #ifdef	ultrix
52 /* Nasty hack to keep the Ultrix C compiler from emitting bogus warnings */
53 #define	XFF(x)	((u_int32_t)(x))
54 #else
55 #define	XFF(x)	(x)
56 #endif
57 
58 #define	make_uint32(msb,b,c,lsb)\
59 	(XFF(lsb) + (XFF(c)<<8) + (XFF(b)<<16) + (XFF(msb)<<24))
60 
61 #define	make_uint24(msb,b, lsb)\
62 	(XFF(lsb) + (XFF(b)<<8) + (XFF(msb)<<16))
63 
64 #define	make_uint16(msb,lsb)\
65 	(XFF(lsb) + (XFF(msb)<<8))
66 
67 #ifdef	__alpha
68 	/* or other 64-bit systems */
69 #define	make_uint48(msb,b,c,d,e,lsb)\
70 	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24) + ((b)<<32) + ((msb)<<40))
71 #else
72 	/* on 32-bit systems ignore high-order bits */
73 #define	make_uint48(msb,b,c,d,e,lsb)\
74 	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24))
75 #endif
76 
77 static int is_UCX(unsigned char *);
78 
79 void
80 Parse_fh(fh, len, fsidp, inop, osnamep, fsnamep, ourself)
81 register caddr_t *fh;
82 int len;
83 my_fsid *fsidp;
84 ino_t *inop;
85 char **osnamep;		/* if non-NULL, return OS name here */
86 char **fsnamep;		/* if non-NULL, return server fs name here (for VMS) */
87 int ourself;		/* true if file handle was generated on this host */
88 {
89 	register unsigned char *fhp = (unsigned char *)fh;
90 	u_int32_t temp;
91 	int fhtype = FHT_UNKNOWN;
92 
93 	if (ourself) {
94 	    /* File handle generated on this host, no need for guessing */
95 #if	defined(IRIX40)
96 	    fhtype = FHT_IRIX4;
97 #endif
98 #if	defined(IRIX50)
99 	    fhtype = FHT_IRIX5;
100 #endif
101 #if	defined(IRIX51)
102 	    fhtype = FHT_IRIX5;
103 #endif
104 #if	defined(SUNOS4)
105 	    fhtype = FHT_SUNOS4;
106 #endif
107 #if	defined(SUNOS5)
108 	    fhtype = FHT_SUNOS5;
109 #endif
110 #if	defined(ultrix)
111 	    fhtype = FHT_ULTRIX;
112 #endif
113 #if	defined(__osf__)
114 	    fhtype = FHT_DECOSF;
115 #endif
116 	}
117 	/*
118 	 * This is basically a big decision tree
119 	 */
120 	else if ((fhp[0] == 0) && (fhp[1] == 0)) {
121 	    /* bytes[0,1] == (0,0); rules out Ultrix, IRIX5, SUNOS5 */
122 	    /* probably rules out HP-UX, AIX unless they allow major=0 */
123 	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
124 		/* bytes[2,3] == (0,0); must be Auspex */
125 		/* XXX or could be Ultrix+MASSBUS "hp" disk? */
126 		fhtype = FHT_AUSPEX;
127 	    }
128 	    else {
129 		/*
130 		 * bytes[2,3] != (0,0); rules out Auspex, could be
131 		 * DECOSF, SUNOS4, or IRIX4
132 		 */
133 		if ((fhp[4] != 0) && (fhp[5] == 0) &&
134 			(fhp[8] == 12) && (fhp[9] == 0)) {
135 		    /* seems to be DECOSF, with minor == 0 */
136 		    fhtype = FHT_DECOSF;
137 		}
138 		else {
139 		    /* could be SUNOS4 or IRIX4 */
140 		    /* XXX the test of fhp[5] == 8 could be wrong */
141 		    if ((fhp[4] == 0) && (fhp[5] == 8) && (fhp[6] == 0) &&
142 			(fhp[7] == 0)) {
143 			/* looks like a length, not a file system typecode */
144 			fhtype = FHT_IRIX4;
145 		    }
146 		    else {
147 			/* by elimination */
148 			fhtype = FHT_SUNOS4;
149 		    }
150 		}
151 	    }
152 	}
153 	else {
154 	    /*
155 	     * bytes[0,1] != (0,0); rules out Auspex, IRIX4, SUNOS4
156 	     * could be IRIX5, DECOSF, UCX, Ultrix, SUNOS5
157 	     * could be AIX, HP-UX
158 	     */
159 	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
160 		/*
161 		 * bytes[2,3] == (0,0); rules out OSF, probably not UCX
162 		 * (unless the exported device name is just one letter!),
163 		 * could be Ultrix, IRIX5, AIX, or SUNOS5
164 		 * might be HP-UX (depends on their values for minor devs)
165 		 */
166 		/*XXX we probably only need to test of these two bytes */
167 		if ((fhp[21] == 0) && (fhp[23] == 0)) {
168 		    fhtype = FHT_ULTRIX;
169 		}
170 		else {
171 		    /* Could be SUNOS5/IRIX5, maybe AIX */
172 		    /* XXX no obvious difference between SUNOS5 and IRIX5 */
173 		    if (fhp[9] == 10)
174 			fhtype = FHT_SUNOS5;
175 		    /* XXX what about AIX? */
176 		}
177 	    }
178 	    else {
179 		/*
180 		 * bytes[2,3] != (0,0); rules out Ultrix, could be
181 		 * DECOSF, SUNOS5, IRIX5, AIX, HP-UX, or UCX
182 		 */
183 		if ((fhp[8] == 12) && (fhp[9] == 0)) {
184 		    fhtype = FHT_DECOSF;
185 		}
186 		else if ((fhp[8] == 0) && (fhp[9] == 10)) {
187 		    /* could be SUNOS5/IRIX5, AIX, HP-UX */
188 		    if ((fhp[7] == 0) && (fhp[6] == 0) &&
189 			(fhp[5] == 0) && (fhp[4] == 0)) {
190 			/* XXX is this always true of HP-UX? */
191 			fhtype = FHT_HPUX9;
192 		    }
193 		    else if (fhp[7] == 2) {
194 			/* This would be MNT_NFS on AIX, which is impossible */
195 			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
196 		    }
197 		    else {
198 			/*
199 			 * XXX Could be SUNOS5/IRIX5 or AIX.  I don't
200 			 * XXX see any way to disambiguate these, so
201 			 * XXX I'm going with the more likely guess.
202 			 * XXX Sorry, Big Blue.
203 			 */
204 			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
205 		    }
206 	        }
207 		else {
208 		    if (is_UCX(fhp)) {
209 			fhtype = FHT_VMSUCX;
210 		    }
211 		    else {
212 			fhtype = FHT_UNKNOWN;
213 		    }
214 		}
215 	    }
216 	}
217 
218 	/* XXX still needs to handle SUNOS3 */
219 
220 	switch (fhtype) {
221 	case FHT_AUSPEX:
222 	    fsidp->Fsid_dev.Minor = fhp[7];
223 	    fsidp->Fsid_dev.Major = fhp[6];
224 	    fsidp->fsid_code = 0;
225 
226 	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
227 	    *inop = temp;
228 
229 	    if (osnamep)
230 		*osnamep = "Auspex";
231 	    break;
232 
233 	case FHT_DECOSF:
234 	    fsidp->fsid_code = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
235 			/* XXX could ignore 3 high-order bytes */
236 
237 	    temp = make_uint32(fhp[3], fhp[2], fhp[1], fhp[0]);
238 	    fsidp->Fsid_dev.Minor = temp & 0xFFFFF;
239 	    fsidp->Fsid_dev.Major = (temp>>20) & 0xFFF;
240 
241 	    temp = make_uint32(fhp[15], fhp[14], fhp[13], fhp[12]);
242 	    *inop = temp;
243 	    if (osnamep)
244 		*osnamep = "OSF";
245 	    break;
246 
247 	case FHT_IRIX4:
248 	    fsidp->Fsid_dev.Minor = fhp[3];
249 	    fsidp->Fsid_dev.Major = fhp[2];
250 	    fsidp->fsid_code = 0;
251 
252 	    temp = make_uint32(fhp[8], fhp[9], fhp[10], fhp[11]);
253 	    *inop = temp;
254 
255 	    if (osnamep)
256 		*osnamep = "IRIX4";
257 	    break;
258 
259 	case FHT_IRIX5:
260 	    fsidp->Fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
261 	    fsidp->Fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
262 	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
263 
264 	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
265 	    *inop = temp;
266 
267 	    if (osnamep)
268 		*osnamep = "IRIX5";
269 	    break;
270 
271 	case FHT_SUNOS3:
272 	    if (osnamep)
273 		*osnamep = "SUNOS3";
274 	    break;
275 
276 	case FHT_SUNOS4:
277 	    fsidp->Fsid_dev.Minor = fhp[3];
278 	    fsidp->Fsid_dev.Major = fhp[2];
279 	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
280 
281 	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
282 	    *inop = temp;
283 
284 	    if (osnamep)
285 		*osnamep = "SUNOS4";
286 	    break;
287 
288 	case FHT_SUNOS5:
289 	    temp = make_uint16(fhp[0], fhp[1]);
290 	    fsidp->Fsid_dev.Major = (temp>>2) &  0x3FFF;
291 	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
292 	    fsidp->Fsid_dev.Minor = temp & 0x3FFFF;
293 	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
294 
295 	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
296 	    *inop = temp;
297 
298 	    if (osnamep)
299 		*osnamep = "SUNOS5";
300 	    break;
301 
302 	case FHT_ULTRIX:
303 	    fsidp->fsid_code = 0;
304 	    fsidp->Fsid_dev.Minor = fhp[0];
305 	    fsidp->Fsid_dev.Major = fhp[1];
306 
307 	    temp = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
308 	    *inop = temp;
309 	    if (osnamep)
310 		*osnamep = "Ultrix";
311 	    break;
312 
313 	case FHT_VMSUCX:
314 	    /* No numeric file system ID, so hash on the device-name */
315 	    if (sizeof(*fsidp) >= 14) {
316 		if (sizeof(*fsidp) > 14)
317 		    memset((char *)fsidp, 0, sizeof(*fsidp));
318 		/* just use the whole thing */
319 		memcpy((char *)fsidp, (char *)fh, 14);
320 	    }
321 	    else {
322 		u_int32_t tempa[4];	/* at least 16 bytes, maybe more */
323 
324 		memset((char *)tempa, 0, sizeof(tempa));
325 		memcpy((char *)tempa, (char *)fh, 14); /* ensure alignment */
326 		fsidp->Fsid_dev.Minor = tempa[0] + (tempa[1]<<1);
327 		fsidp->Fsid_dev.Major = tempa[2] + (tempa[3]<<1);
328 		fsidp->fsid_code = 0;
329 	    }
330 
331 	    /* VMS file ID is: (RVN, FidHi, FidLo) */
332 	    *inop = make_uint32(fhp[26], fhp[27], fhp[23], fhp[22]);
333 
334 	    /* Caller must save (and null-terminate?) this value */
335 	    if (fsnamep)
336 		*fsnamep = (char *)&(fhp[1]);
337 
338 	    if (osnamep)
339 		*osnamep = "VMS";
340 	    break;
341 
342 	case FHT_AIX32:
343 	    fsidp->Fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
344 	    fsidp->Fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
345 	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
346 
347 	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
348 	    *inop = temp;
349 
350 	    if (osnamep)
351 		*osnamep = "AIX32";
352 	    break;
353 
354 	case FHT_HPUX9:
355 	    fsidp->Fsid_dev.Major = fhp[0];
356 	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
357 	    fsidp->Fsid_dev.Minor = temp;
358 	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
359 
360 	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
361 	    *inop = temp;
362 
363 	    if (osnamep)
364 		*osnamep = "HPUX9";
365 	    break;
366 
367 	case FHT_UNKNOWN:
368 #ifdef DEBUG
369 	    {
370 		/* XXX debugging */
371 		int i;
372 		for (i = 0; i < 32; i++)
373 			(void)fprintf(stderr, "%x.", fhp[i]);
374 		(void)fprintf(stderr, "\n");
375 	    }
376 #endif
377 	    /* XXX for now, give "bogus" values to aid debugging */
378 	    fsidp->fsid_code = 0;
379 	    fsidp->Fsid_dev.Minor = 257;
380 	    fsidp->Fsid_dev.Major = 257;
381 	    *inop = 1;
382 
383 	    /* display will show this string instead of (257,257) */
384 	    if (fsnamep)
385 		*fsnamep = "Unknown";
386 
387 	    if (osnamep)
388 		*osnamep = "Unknown";
389 	    break;
390 
391 	}
392 }
393 
394 /*
395  * Is this a VMS UCX file handle?
396  *	Check for:
397  *	(1) leading code byte	[XXX not yet]
398  *	(2) followed by string of printing chars & spaces
399  *	(3) followed by string of nulls
400  */
401 static int
402 is_UCX(fhp)
403 unsigned char *fhp;
404 {
405 	register int i;
406 	int seen_null = 0;
407 
408 	for (i = 1; i < 14; i++) {
409 	    if (isprint(fhp[i])) {
410 		if (seen_null)
411 		   return(0);
412 		else
413 		   continue;
414 	    }
415 	    else if (fhp[i] == 0) {
416 		seen_null = 1;
417 		continue;
418 	    }
419 	    else
420 		return(0);
421 	}
422 
423 	return(1);
424 }
425