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