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