1 /* 2 * Copyright (C) Andrew Tridgell 1995-1999 3 * 4 * This software may be distributed either under the terms of the 5 * BSD-style license that accompanies tcpdump or the GNU GPL version 2 6 * or later 7 */ 8 9 #ifdef HAVE_CONFIG_H 10 #include "config.h" 11 #endif 12 13 #ifndef lint 14 static const char rcsid[] _U_ = 15 "@(#) $Header: /tcpdump/master/tcpdump/smbutil.c,v 1.26.2.2 2003/11/16 08:51:56 guy Exp $"; 16 #endif 17 18 #include <tcpdump-stdinc.h> 19 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "interface.h" 25 #include "extract.h" 26 #include "smb.h" 27 28 extern const u_char *startbuf; 29 30 /* 31 * interpret a 32 bit dos packed date/time to some parameters 32 */ 33 static void 34 interpret_dos_date(u_int32_t date, struct tm *tp) 35 { 36 u_int32_t p0, p1, p2, p3; 37 38 p0 = date & 0xFF; 39 p1 = ((date & 0xFF00) >> 8) & 0xFF; 40 p2 = ((date & 0xFF0000) >> 16) & 0xFF; 41 p3 = ((date & 0xFF000000) >> 24) & 0xFF; 42 43 tp->tm_sec = 2 * (p0 & 0x1F); 44 tp->tm_min = ((p0 >> 5) & 0xFF) + ((p1 & 0x7) << 3); 45 tp->tm_hour = (p1 >> 3) & 0xFF; 46 tp->tm_mday = (p2 & 0x1F); 47 tp->tm_mon = ((p2 >> 5) & 0xFF) + ((p3 & 0x1) << 3) - 1; 48 tp->tm_year = ((p3 >> 1) & 0xFF) + 80; 49 } 50 51 /* 52 * common portion: 53 * create a unix date from a dos date 54 */ 55 static time_t 56 int_unix_date(u_int32_t dos_date) 57 { 58 struct tm t; 59 60 if (dos_date == 0) 61 return(0); 62 63 interpret_dos_date(dos_date, &t); 64 t.tm_wday = 1; 65 t.tm_yday = 1; 66 t.tm_isdst = 0; 67 68 return (mktime(&t)); 69 } 70 71 /* 72 * create a unix date from a dos date 73 * in network byte order 74 */ 75 static time_t 76 make_unix_date(const u_char *date_ptr) 77 { 78 u_int32_t dos_date = 0; 79 80 dos_date = EXTRACT_LE_32BITS(date_ptr); 81 82 return int_unix_date(dos_date); 83 } 84 85 /* 86 * create a unix date from a dos date 87 * in halfword-swapped network byte order! 88 */ 89 static time_t 90 make_unix_date2(const u_char *date_ptr) 91 { 92 u_int32_t x, x2; 93 94 x = EXTRACT_LE_32BITS(date_ptr); 95 x2 = ((x & 0xFFFF) << 16) | ((x & 0xFFFF0000) >> 16); 96 return int_unix_date(x2); 97 } 98 99 /* 100 * interpret an 8 byte "filetime" structure to a time_t 101 * It's originally in "100ns units since jan 1st 1601" 102 */ 103 static time_t 104 interpret_long_date(const u_char *p) 105 { 106 double d; 107 time_t ret; 108 109 TCHECK2(p[4], 4); 110 111 /* this gives us seconds since jan 1st 1601 (approx) */ 112 d = (EXTRACT_LE_32BITS(p + 4) * 256.0 + p[3]) * (1.0e-7 * (1 << 24)); 113 114 /* now adjust by 369 years to make the secs since 1970 */ 115 d -= 369.0 * 365.25 * 24 * 60 * 60; 116 117 /* and a fudge factor as we got it wrong by a few days */ 118 d += (3 * 24 * 60 * 60 + 6 * 60 * 60 + 2); 119 120 if (d < 0) 121 return(0); 122 123 ret = (time_t)d; 124 125 return(ret); 126 trunc: 127 return(0); 128 } 129 130 /* 131 * interpret the weird netbios "name". Return the name type, or -1 if 132 * we run past the end of the buffer 133 */ 134 static int 135 name_interpret(const u_char *in, const u_char *maxbuf, char *out) 136 { 137 int ret; 138 int len; 139 140 if (in >= maxbuf) 141 return(-1); /* name goes past the end of the buffer */ 142 TCHECK2(*in, 1); 143 len = (*in++) / 2; 144 145 *out=0; 146 147 if (len > 30 || len < 1) 148 return(0); 149 150 while (len--) { 151 TCHECK2(*in, 2); 152 if (in + 1 >= maxbuf) 153 return(-1); /* name goes past the end of the buffer */ 154 if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { 155 *out = 0; 156 return(0); 157 } 158 *out = ((in[0] - 'A') << 4) + (in[1] - 'A'); 159 in += 2; 160 out++; 161 } 162 *out = 0; 163 ret = out[-1]; 164 165 return(ret); 166 167 trunc: 168 return(-1); 169 } 170 171 /* 172 * find a pointer to a netbios name 173 */ 174 static const u_char * 175 name_ptr(const u_char *buf, int ofs, const u_char *maxbuf) 176 { 177 const u_char *p; 178 u_char c; 179 180 p = buf + ofs; 181 if (p >= maxbuf) 182 return(NULL); /* name goes past the end of the buffer */ 183 TCHECK2(*p, 1); 184 185 c = *p; 186 187 /* XXX - this should use the same code that the DNS dissector does */ 188 if ((c & 0xC0) == 0xC0) { 189 u_int16_t l = EXTRACT_16BITS(buf + ofs) & 0x3FFF; 190 if (l == 0) { 191 /* We have a pointer that points to itself. */ 192 return(NULL); 193 } 194 p = buf + l; 195 if (p >= maxbuf) 196 return(NULL); /* name goes past the end of the buffer */ 197 TCHECK2(*p, 1); 198 return(buf + l); 199 } else 200 return(buf + ofs); 201 202 trunc: 203 return(NULL); /* name goes past the end of the buffer */ 204 } 205 206 /* 207 * extract a netbios name from a buf 208 */ 209 static int 210 name_extract(const u_char *buf, int ofs, const u_char *maxbuf, char *name) 211 { 212 const u_char *p = name_ptr(buf, ofs, maxbuf); 213 if (p == NULL) 214 return(-1); /* error (probably name going past end of buffer) */ 215 name[0] = '\0'; 216 return(name_interpret(p, maxbuf, name)); 217 } 218 219 220 /* 221 * return the total storage length of a mangled name 222 */ 223 static int 224 name_len(const unsigned char *s, const unsigned char *maxbuf) 225 { 226 const unsigned char *s0 = s; 227 unsigned char c; 228 229 if (s >= maxbuf) 230 return(-1); /* name goes past the end of the buffer */ 231 TCHECK2(*s, 1); 232 c = *s; 233 if ((c & 0xC0) == 0xC0) 234 return(2); 235 while (*s) { 236 if (s >= maxbuf) 237 return(-1); /* name goes past the end of the buffer */ 238 TCHECK2(*s, 1); 239 s += (*s) + 1; 240 } 241 return(PTR_DIFF(s, s0) + 1); 242 243 trunc: 244 return(-1); /* name goes past the end of the buffer */ 245 } 246 247 static void 248 print_asc(const unsigned char *buf, int len) 249 { 250 int i; 251 for (i = 0; i < len; i++) 252 safeputchar(buf[i]); 253 } 254 255 static const char * 256 name_type_str(int name_type) 257 { 258 const char *f = NULL; 259 260 switch (name_type) { 261 case 0: f = "Workstation"; break; 262 case 0x03: f = "Client?"; break; 263 case 0x20: f = "Server"; break; 264 case 0x1d: f = "Master Browser"; break; 265 case 0x1b: f = "Domain Controller"; break; 266 case 0x1e: f = "Browser Server"; break; 267 default: f = "Unknown"; break; 268 } 269 return(f); 270 } 271 272 void 273 print_data(const unsigned char *buf, int len) 274 { 275 int i = 0; 276 277 if (len <= 0) 278 return; 279 printf("[%03X] ", i); 280 for (i = 0; i < len; /*nothing*/) { 281 printf("%02X ", buf[i] & 0xff); 282 i++; 283 if (i%8 == 0) 284 printf(" "); 285 if (i % 16 == 0) { 286 print_asc(&buf[i - 16], 8); 287 printf(" "); 288 print_asc(&buf[i - 8], 8); 289 printf("\n"); 290 if (i < len) 291 printf("[%03X] ", i); 292 } 293 } 294 if (i % 16) { 295 int n; 296 297 n = 16 - (i % 16); 298 printf(" "); 299 if (n>8) 300 printf(" "); 301 while (n--) 302 printf(" "); 303 304 n = SMBMIN(8, i % 16); 305 print_asc(&buf[i - (i % 16)], n); 306 printf(" "); 307 n = (i % 16) - n; 308 if (n > 0) 309 print_asc(&buf[i - n], n); 310 printf("\n"); 311 } 312 } 313 314 315 static void 316 write_bits(unsigned int val, const char *fmt) 317 { 318 const char *p = fmt; 319 int i = 0; 320 321 while ((p = strchr(fmt, '|'))) { 322 size_t l = PTR_DIFF(p, fmt); 323 if (l && (val & (1 << i))) 324 printf("%.*s ", (int)l, fmt); 325 fmt = p + 1; 326 i++; 327 } 328 } 329 330 /* convert a UCS2 string into iso-8859-1 string */ 331 static const char * 332 unistr(const u_char *s, int *len) 333 { 334 static char buf[1000]; 335 int l=0; 336 static int use_unicode = -1; 337 338 if (use_unicode == -1) { 339 char *p = getenv("USE_UNICODE"); 340 if (p && (atoi(p) == 1)) 341 use_unicode = 1; 342 else 343 use_unicode = 0; 344 } 345 346 /* maybe it isn't unicode - a cheap trick */ 347 if (!use_unicode || (s[0] && s[1])) { 348 *len = strlen((const char *)s) + 1; 349 return (const char *)s; 350 } 351 352 *len = 0; 353 354 if (s[0] == 0 && s[1] != 0) { 355 s++; 356 *len = 1; 357 } 358 359 while (l < (int)(sizeof(buf) - 1) && s[0] && s[1] == 0) { 360 buf[l] = s[0]; 361 s += 2; 362 l++; 363 *len += 2; 364 } 365 buf[l] = 0; 366 *len += 2; 367 return buf; 368 } 369 370 static const u_char * 371 smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) 372 { 373 int reverse = 0; 374 const char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|"; 375 int len; 376 377 while (*fmt && buf<maxbuf) { 378 switch (*fmt) { 379 case 'a': 380 write_bits(buf[0], attrib_fmt); 381 buf++; 382 fmt++; 383 break; 384 385 case 'A': 386 write_bits(EXTRACT_LE_16BITS(buf), attrib_fmt); 387 buf += 2; 388 fmt++; 389 break; 390 391 case '{': 392 { 393 char bitfmt[128]; 394 char *p; 395 int l; 396 397 p = strchr(++fmt, '}'); 398 l = PTR_DIFF(p, fmt); 399 400 if ((unsigned int)l > sizeof(bitfmt) - 1) 401 l = sizeof(bitfmt)-1; 402 403 strncpy(bitfmt, fmt, l); 404 bitfmt[l] = '\0'; 405 fmt = p + 1; 406 write_bits(buf[0], bitfmt); 407 buf++; 408 break; 409 } 410 411 case 'P': 412 { 413 int l = atoi(fmt + 1); 414 buf += l; 415 fmt++; 416 while (isdigit((unsigned char)*fmt)) 417 fmt++; 418 break; 419 } 420 case 'r': 421 reverse = !reverse; 422 fmt++; 423 break; 424 case 'D': 425 { 426 unsigned int x; 427 428 TCHECK2(buf[0], 4); 429 x = reverse ? EXTRACT_32BITS(buf) : EXTRACT_LE_32BITS(buf); 430 printf("%d (0x%x)", x, x); 431 buf += 4; 432 fmt++; 433 break; 434 } 435 case 'L': 436 { 437 unsigned int x1, x2; 438 439 TCHECK2(buf[4], 4); 440 x1 = reverse ? EXTRACT_32BITS(buf) : 441 EXTRACT_LE_32BITS(buf); 442 x2 = reverse ? EXTRACT_32BITS(buf + 4) : 443 EXTRACT_LE_32BITS(buf + 4); 444 if (x2) 445 printf("0x%08x:%08x", x2, x1); 446 else 447 printf("%d (0x%08x%08x)", x1, x2, x1); 448 buf += 8; 449 fmt++; 450 break; 451 } 452 case 'd': 453 { 454 unsigned int x; 455 TCHECK2(buf[0], 2); 456 x = reverse ? EXTRACT_16BITS(buf) : 457 EXTRACT_LE_16BITS(buf); 458 printf("%d (0x%x)", x, x); 459 buf += 2; 460 fmt++; 461 break; 462 } 463 case 'W': 464 { 465 unsigned int x; 466 TCHECK2(buf[0], 4); 467 x = reverse ? EXTRACT_32BITS(buf) : 468 EXTRACT_LE_32BITS(buf); 469 printf("0x%X", x); 470 buf += 4; 471 fmt++; 472 break; 473 } 474 case 'w': 475 { 476 unsigned int x; 477 TCHECK2(buf[0], 2); 478 x = reverse ? EXTRACT_16BITS(buf) : 479 EXTRACT_LE_16BITS(buf); 480 printf("0x%X", x); 481 buf += 2; 482 fmt++; 483 break; 484 } 485 case 'B': 486 { 487 unsigned int x; 488 TCHECK(buf[0]); 489 x = buf[0]; 490 printf("0x%X", x); 491 buf += 1; 492 fmt++; 493 break; 494 } 495 case 'b': 496 { 497 unsigned int x; 498 TCHECK(buf[0]); 499 x = buf[0]; 500 printf("%u (0x%x)", x, x); 501 buf += 1; 502 fmt++; 503 break; 504 } 505 case 'S': 506 { 507 /*XXX unistr() */ 508 printf("%.*s", (int)PTR_DIFF(maxbuf, buf), unistr(buf, &len)); 509 buf += len; 510 fmt++; 511 break; 512 } 513 case 'Z': 514 { 515 if (*buf != 4 && *buf != 2) 516 printf("Error! ASCIIZ buffer of type %u (safety=%lu)\n", *buf, 517 (unsigned long)PTR_DIFF(maxbuf, buf)); 518 printf("%.*s", (int)PTR_DIFF(maxbuf, buf + 1), 519 unistr(buf + 1, &len)); 520 buf += len + 1; 521 fmt++; 522 break; 523 } 524 case 's': 525 { 526 int l = atoi(fmt + 1); 527 printf("%-*.*s", l, l, buf); 528 buf += l; 529 fmt++; 530 while (isdigit((unsigned char)*fmt)) 531 fmt++; 532 break; 533 } 534 case 'h': 535 { 536 int l = atoi(fmt + 1); 537 while (l--) 538 printf("%02x", *buf++); 539 fmt++; 540 while (isdigit((unsigned char)*fmt)) 541 fmt++; 542 break; 543 } 544 case 'n': 545 { 546 int t = atoi(fmt+1); 547 char nbuf[255]; 548 int name_type; 549 int len; 550 551 switch (t) { 552 case 1: 553 name_type = name_extract(startbuf, PTR_DIFF(buf, startbuf), 554 maxbuf, nbuf); 555 if (name_type < 0) 556 goto trunc; 557 len = name_len(buf, maxbuf); 558 if (len < 0) 559 goto trunc; 560 buf += len; 561 printf("%-15.15s NameType=0x%02X (%s)", nbuf, name_type, 562 name_type_str(name_type)); 563 break; 564 case 2: 565 name_type = buf[15]; 566 printf("%-15.15s NameType=0x%02X (%s)", buf, name_type, 567 name_type_str(name_type)); 568 buf += 16; 569 break; 570 } 571 fmt++; 572 while (isdigit((unsigned char)*fmt)) 573 fmt++; 574 break; 575 } 576 case 'T': 577 { 578 time_t t; 579 struct tm *lt; 580 const char *tstring; 581 u_int32_t x; 582 x = EXTRACT_LE_32BITS(buf); 583 584 switch (atoi(fmt + 1)) { 585 case 1: 586 if (x == 0 || x == 0xFFFFFFFF) 587 t = 0; 588 else 589 t = make_unix_date(buf); 590 buf += 4; 591 break; 592 case 2: 593 if (x == 0 || x == 0xFFFFFFFF) 594 t = 0; 595 else 596 t = make_unix_date2(buf); 597 buf += 4; 598 break; 599 case 3: 600 t = interpret_long_date(buf); 601 buf += 8; 602 break; 603 } 604 if (t != 0) { 605 lt = localtime(&t); 606 if (lt != NULL) 607 tstring = asctime(lt); 608 else 609 tstring = "(Can't convert time)\n"; 610 } else 611 tstring = "NULL\n"; 612 printf("%s", tstring); 613 fmt++; 614 while (isdigit((unsigned char)*fmt)) 615 fmt++; 616 break; 617 } 618 default: 619 putchar(*fmt); 620 fmt++; 621 break; 622 } 623 } 624 625 if (buf >= maxbuf && *fmt) 626 printf("END OF BUFFER\n"); 627 628 return(buf); 629 630 trunc: 631 printf("\n"); 632 printf("WARNING: Short packet. Try increasing the snap length\n"); 633 return(NULL); 634 } 635 636 const u_char * 637 smb_fdata(const u_char *buf, const char *fmt, const u_char *maxbuf) 638 { 639 static int depth = 0; 640 char s[128]; 641 char *p; 642 643 while (*fmt) { 644 switch (*fmt) { 645 case '*': 646 fmt++; 647 while (buf < maxbuf) { 648 const u_char *buf2; 649 depth++; 650 buf2 = smb_fdata(buf, fmt, maxbuf); 651 depth--; 652 if (buf2 == NULL) 653 return(NULL); 654 if (buf2 == buf) 655 return(buf); 656 buf = buf2; 657 } 658 return(buf); 659 660 case '|': 661 fmt++; 662 if (buf >= maxbuf) 663 return(buf); 664 break; 665 666 case '%': 667 fmt++; 668 buf = maxbuf; 669 break; 670 671 case '#': 672 fmt++; 673 return(buf); 674 break; 675 676 case '[': 677 fmt++; 678 if (buf >= maxbuf) 679 return(buf); 680 memset(s, 0, sizeof(s)); 681 p = strchr(fmt, ']'); 682 if ((size_t)(p - fmt + 1) > sizeof(s)) { 683 /* overrun */ 684 return(buf); 685 } 686 strncpy(s, fmt, p - fmt); 687 s[p - fmt] = '\0'; 688 fmt = p + 1; 689 buf = smb_fdata1(buf, s, maxbuf); 690 if (buf == NULL) 691 return(NULL); 692 break; 693 694 default: 695 putchar(*fmt); 696 fmt++; 697 fflush(stdout); 698 break; 699 } 700 } 701 if (!depth && buf < maxbuf) { 702 size_t len = PTR_DIFF(maxbuf, buf); 703 printf("Data: (%lu bytes)\n", (unsigned long)len); 704 print_data(buf, len); 705 return(buf + len); 706 } 707 return(buf); 708 } 709 710 typedef struct { 711 const char *name; 712 int code; 713 const char *message; 714 } err_code_struct; 715 716 /* Dos Error Messages */ 717 static err_code_struct dos_msgs[] = { 718 { "ERRbadfunc", 1, "Invalid function." }, 719 { "ERRbadfile", 2, "File not found." }, 720 { "ERRbadpath", 3, "Directory invalid." }, 721 { "ERRnofids", 4, "No file descriptors available" }, 722 { "ERRnoaccess", 5, "Access denied." }, 723 { "ERRbadfid", 6, "Invalid file handle." }, 724 { "ERRbadmcb", 7, "Memory control blocks destroyed." }, 725 { "ERRnomem", 8, "Insufficient server memory to perform the requested function." }, 726 { "ERRbadmem", 9, "Invalid memory block address." }, 727 { "ERRbadenv", 10, "Invalid environment." }, 728 { "ERRbadformat", 11, "Invalid format." }, 729 { "ERRbadaccess", 12, "Invalid open mode." }, 730 { "ERRbaddata", 13, "Invalid data." }, 731 { "ERR", 14, "reserved." }, 732 { "ERRbaddrive", 15, "Invalid drive specified." }, 733 { "ERRremcd", 16, "A Delete Directory request attempted to remove the server's current directory." }, 734 { "ERRdiffdevice", 17, "Not same device." }, 735 { "ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria." }, 736 { "ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing FIDs on the file." }, 737 { "ERRlock", 33, "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process." }, 738 { "ERRfilexists", 80, "The file named in a Create Directory, Make New File or Link request already exists." }, 739 { "ERRbadpipe", 230, "Pipe invalid." }, 740 { "ERRpipebusy", 231, "All instances of the requested pipe are busy." }, 741 { "ERRpipeclosing", 232, "Pipe close in progress." }, 742 { "ERRnotconnected", 233, "No process on other end of pipe." }, 743 { "ERRmoredata", 234, "There is more data to be returned." }, 744 { NULL, -1, NULL } 745 }; 746 747 /* Server Error Messages */ 748 err_code_struct server_msgs[] = { 749 { "ERRerror", 1, "Non-specific error code." }, 750 { "ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid." }, 751 { "ERRbadtype", 3, "reserved." }, 752 { "ERRaccess", 4, "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID." }, 753 { "ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid." }, 754 { "ERRinvnetname", 6, "Invalid network name in tree connect." }, 755 { "ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection." }, 756 { "ERRqfull", 49, "Print queue full (files) -- returned by open print file." }, 757 { "ERRqtoobig", 50, "Print queue full -- no space." }, 758 { "ERRqeof", 51, "EOF on print queue dump." }, 759 { "ERRinvpfid", 52, "Invalid print file FID." }, 760 { "ERRsmbcmd", 64, "The server did not recognize the command received." }, 761 { "ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable." }, 762 { "ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid combination of values." }, 763 { "ERRreserved", 68, "reserved." }, 764 { "ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute." }, 765 { "ERRreserved", 70, "reserved." }, 766 { "ERRsetattrmode", 71, "The attribute mode in the Set File Attribute request is invalid." }, 767 { "ERRpaused", 81, "Server is paused." }, 768 { "ERRmsgoff", 82, "Not receiving messages." }, 769 { "ERRnoroom", 83, "No room to buffer message." }, 770 { "ERRrmuns", 87, "Too many remote user names." }, 771 { "ERRtimeout", 88, "Operation timed out." }, 772 { "ERRnoresource", 89, "No resources currently available for request." }, 773 { "ERRtoomanyuids", 90, "Too many UIDs active on this session." }, 774 { "ERRbaduid", 91, "The UID is not known as a valid ID on this session." }, 775 { "ERRusempx", 250, "Temp unable to support Raw, use MPX mode." }, 776 { "ERRusestd", 251, "Temp unable to support Raw, use standard read/write." }, 777 { "ERRcontmpx", 252, "Continue in MPX mode." }, 778 { "ERRreserved", 253, "reserved." }, 779 { "ERRreserved", 254, "reserved." }, 780 { "ERRnosupport", 0xFFFF, "Function not supported." }, 781 { NULL, -1, NULL } 782 }; 783 784 /* Hard Error Messages */ 785 err_code_struct hard_msgs[] = { 786 { "ERRnowrite", 19, "Attempt to write on write-protected diskette." }, 787 { "ERRbadunit", 20, "Unknown unit." }, 788 { "ERRnotready", 21, "Drive not ready." }, 789 { "ERRbadcmd", 22, "Unknown command." }, 790 { "ERRdata", 23, "Data error (CRC)." }, 791 { "ERRbadreq", 24, "Bad request structure length." }, 792 { "ERRseek", 25 , "Seek error." }, 793 { "ERRbadmedia", 26, "Unknown media type." }, 794 { "ERRbadsector", 27, "Sector not found." }, 795 { "ERRnopaper", 28, "Printer out of paper." }, 796 { "ERRwrite", 29, "Write fault." }, 797 { "ERRread", 30, "Read fault." }, 798 { "ERRgeneral", 31, "General failure." }, 799 { "ERRbadshare", 32, "A open conflicts with an existing open." }, 800 { "ERRlock", 33, "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process." }, 801 { "ERRwrongdisk", 34, "The wrong disk was found in a drive." }, 802 { "ERRFCBUnavail", 35, "No FCBs are available to process request." }, 803 { "ERRsharebufexc", 36, "A sharing buffer has been exceeded." }, 804 { NULL, -1, NULL } 805 }; 806 807 static struct { 808 int code; 809 const char *class; 810 err_code_struct *err_msgs; 811 } err_classes[] = { 812 { 0, "SUCCESS", NULL }, 813 { 0x01, "ERRDOS", dos_msgs }, 814 { 0x02, "ERRSRV", server_msgs }, 815 { 0x03, "ERRHRD", hard_msgs }, 816 { 0x04, "ERRXOS", NULL }, 817 { 0xE1, "ERRRMX1", NULL }, 818 { 0xE2, "ERRRMX2", NULL }, 819 { 0xE3, "ERRRMX3", NULL }, 820 { 0xFF, "ERRCMD", NULL }, 821 { -1, NULL, NULL } 822 }; 823 824 /* 825 * return a SMB error string from a SMB buffer 826 */ 827 char * 828 smb_errstr(int class, int num) 829 { 830 static char ret[128]; 831 int i, j; 832 833 ret[0] = 0; 834 835 for (i = 0; err_classes[i].class; i++) 836 if (err_classes[i].code == class) { 837 if (err_classes[i].err_msgs) { 838 err_code_struct *err = err_classes[i].err_msgs; 839 for (j = 0; err[j].name; j++) 840 if (num == err[j].code) { 841 snprintf(ret, sizeof(ret), "%s - %s (%s)", 842 err_classes[i].class, err[j].name, err[j].message); 843 return ret; 844 } 845 } 846 847 snprintf(ret, sizeof(ret), "%s - %d", err_classes[i].class, num); 848 return ret; 849 } 850 851 snprintf(ret, sizeof(ret), "ERROR: Unknown error (%d,%d)", class, num); 852 return(ret); 853 } 854