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