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