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