1 /* $OpenBSD: smbutil.c,v 1.7 2009/10/27 23:59:57 deraadt 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/param.h> 15 #include <sys/time.h> 16 #include <sys/types.h> 17 #include <sys/socket.h> 18 19 20 #include <netinet/in.h> 21 22 #include <ctype.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <time.h> 27 28 #include "interface.h" 29 #include "smb.h" 30 31 extern const uchar *startbuf; 32 33 /******************************************************************* 34 interpret a 32 bit dos packed date/time to some parameters 35 ********************************************************************/ 36 static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second) 37 { 38 uint32 p0,p1,p2,p3; 39 40 p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; 41 p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF; 42 43 *second = 2*(p0 & 0x1F); 44 *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3); 45 *hour = (p1>>3)&0xFF; 46 *day = (p2&0x1F); 47 *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1; 48 *year = ((p3>>1)&0xFF) + 80; 49 } 50 51 /******************************************************************* 52 create a unix date from a dos date 53 ********************************************************************/ 54 static time_t make_unix_date(const void *date_ptr) 55 { 56 uint32 dos_date=0; 57 struct tm t; 58 59 dos_date = IVAL(date_ptr,0); 60 61 if (dos_date == 0) return(0); 62 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(*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 int l = PTR_DIFF(p,fmt); 327 strlcpy(bitfmt,fmt,sizeof(bitfmt)); 328 fmt = p+1; 329 write_bits(CVAL(buf,0),bitfmt); 330 buf++; 331 break; 332 } 333 334 case 'P': 335 { 336 int l = atoi(fmt+1); 337 buf += l; 338 fmt++; 339 while (isdigit(*fmt)) fmt++; 340 break; 341 } 342 case 'r': 343 reverse = !reverse; 344 fmt++; 345 break; 346 case 'D': 347 { 348 unsigned int x = reverse?RIVAL(buf,0):IVAL(buf,0); 349 printf("%d (0x%x)",x, x); 350 buf += 4; 351 fmt++; 352 break; 353 } 354 case 'L': 355 { 356 unsigned int x1 = reverse?RIVAL(buf,0):IVAL(buf,0); 357 unsigned int x2 = reverse?RIVAL(buf,4):IVAL(buf,4); 358 if (x2) { 359 printf("0x%08x:%08x",x2, x1); 360 } else { 361 printf("%d (0x%08x%08x)",x1, x2, x1); 362 } 363 buf += 8; 364 fmt++; 365 break; 366 } 367 case 'd': 368 { 369 unsigned int x = reverse?RSVAL(buf,0):SVAL(buf,0); 370 printf("%d",x); 371 buf += 2; 372 fmt++; 373 break; 374 } 375 case 'W': 376 { 377 unsigned int x = reverse?RIVAL(buf,0):IVAL(buf,0); 378 printf("0x%X",x); 379 buf += 4; 380 fmt++; 381 break; 382 } 383 case 'w': 384 { 385 unsigned int x = reverse?RSVAL(buf,0):SVAL(buf,0); 386 printf("0x%X",x); 387 buf += 2; 388 fmt++; 389 break; 390 } 391 case 'B': 392 { 393 unsigned int x = CVAL(buf,0); 394 printf("0x%X",x); 395 buf += 1; 396 fmt++; 397 break; 398 } 399 case 'b': 400 { 401 unsigned int x = CVAL(buf,0); 402 printf("%d",x); /* EMF - jesus, use B if you want hex */ 403 buf += 1; 404 fmt++; 405 break; 406 } 407 case 'S': 408 { 409 printf("%.*s",(int)PTR_DIFF(maxbuf,buf),unistr(buf, &len)); 410 buf += len; 411 fmt++; 412 break; 413 } 414 case 'Z': 415 { 416 if (*buf != 4 && *buf != 2) 417 printf("Error! ASCIIZ buffer of type %d (safety=%d) ", 418 *buf,(int)PTR_DIFF(maxbuf,buf)); 419 printf("%.*s",(int)PTR_DIFF(maxbuf,buf+1),unistr(buf+1, &len)); 420 buf += len+1; 421 fmt++; 422 break; 423 } 424 case 's': 425 { 426 int l = atoi(fmt+1); 427 printf("%-*.*s",l,l,buf); 428 buf += l; 429 fmt++; while (isdigit(*fmt)) fmt++; 430 break; 431 } 432 case 'h': 433 { 434 int l = atoi(fmt+1); 435 while (l--) printf("%02x",*buf++); 436 fmt++; while (isdigit(*fmt)) fmt++; 437 break; 438 } 439 case 'n': 440 { 441 int t = atoi(fmt+1); 442 char nbuf[255]; 443 int name_type; 444 int len; 445 switch (t) { 446 case 1: 447 name_type = name_extract(startbuf,PTR_DIFF(buf,startbuf),maxbuf, 448 nbuf); 449 if (name_type < 0) 450 goto trunc; 451 len = name_len(buf,maxbuf); 452 if (len < 0) 453 goto trunc; 454 buf += len; 455 printf("%.15s type 0x%02X (%s)", 456 nbuf,name_type,name_type_str(name_type)); 457 break; 458 case 2: 459 name_type = buf[15]; 460 printf("%.15s type 0x%02X (%s)", 461 buf,name_type,name_type_str(name_type)); 462 buf += 16; 463 break; 464 } 465 fmt++; while (isdigit(*fmt)) fmt++; 466 break; 467 } 468 case 'T': 469 { 470 time_t t; 471 int x = IVAL(buf,0); 472 switch (atoi(fmt+1)) { 473 case 1: 474 if (x==0 || x==-1 || x==0xFFFFFFFF) 475 t = 0; 476 else 477 t = make_unix_date(buf); 478 buf+=4; 479 break; 480 case 2: 481 if (x==0 || x==-1 || x==0xFFFFFFFF) 482 t = 0; 483 else 484 t = make_unix_date2(buf); 485 buf+=4; 486 break; 487 case 3: 488 t = interpret_long_date(buf); 489 buf+=8; 490 break; 491 default: 492 error("fdata1: invalid fmt: %s", fmt); 493 } 494 printf("%s",t?asctime(localtime(&t)):"NULL "); 495 fmt++; while (isdigit(*fmt)) fmt++; 496 break; 497 } 498 default: 499 putchar(*fmt); 500 fmt++; 501 break; 502 } 503 } 504 505 if (buf>=maxbuf && *fmt) 506 printf("END OF BUFFER "); 507 508 return(buf); 509 510 trunc: 511 printf("WARNING: Short packet. Try increasing the snap length "); 512 return(NULL); 513 } 514 515 const uchar *fdata(const uchar *buf, const char *fmt, const uchar *maxbuf) 516 { 517 static int depth=0; 518 char s[128]; 519 char *p; 520 521 while (*fmt) { 522 switch (*fmt) { 523 case '*': 524 fmt++; 525 while (buf < maxbuf) { 526 const uchar *buf2; 527 depth++; 528 buf2 = fdata(buf,fmt,maxbuf); 529 depth--; 530 if (buf2 == buf) return(buf); 531 buf = buf2; 532 } 533 break; 534 535 case '|': 536 fmt++; 537 if (buf>=maxbuf) return(buf); 538 break; 539 540 case '%': 541 fmt++; 542 buf=maxbuf; 543 break; 544 545 case '#': 546 fmt++; 547 return(buf); 548 break; 549 550 case '[': 551 fmt++; 552 if (buf>=maxbuf) return(buf); 553 memset(s, 0, sizeof(s)); 554 p = strchr(fmt,']'); 555 strncpy(s,fmt,p-fmt); /* XXX? */ 556 fmt = p+1; 557 buf = fdata1(buf,s,maxbuf); 558 if (buf == NULL) 559 return(NULL); 560 break; 561 562 default: 563 putchar(*fmt); fmt++; 564 fflush(stdout); 565 break; 566 } 567 } 568 if (!depth && buf<maxbuf) { 569 int len = PTR_DIFF(maxbuf,buf); 570 printf("(%d data bytes)",len); 571 /* EMF - use -X flag if you want this verbosity 572 * print_data(buf,len); 573 */ 574 return(buf+len); 575 } 576 return(buf); 577 } 578 579 typedef struct 580 { 581 char *name; 582 int code; 583 char *message; 584 } err_code_struct; 585 586 /* Dos Error Messages */ 587 static err_code_struct dos_msgs[] = { 588 {"ERRbadfunc",1,"Invalid function."}, 589 {"ERRbadfile",2,"File not found."}, 590 {"ERRbadpath",3,"Directory invalid."}, 591 {"ERRnofids",4,"No file descriptors available"}, 592 {"ERRnoaccess",5,"Access denied."}, 593 {"ERRbadfid",6,"Invalid file handle."}, 594 {"ERRbadmcb",7,"Memory control blocks destroyed."}, 595 {"ERRnomem",8,"Insufficient server memory to perform the requested function."}, 596 {"ERRbadmem",9,"Invalid memory block address."}, 597 {"ERRbadenv",10,"Invalid environment."}, 598 {"ERRbadformat",11,"Invalid format."}, 599 {"ERRbadaccess",12,"Invalid open mode."}, 600 {"ERRbaddata",13,"Invalid data."}, 601 {"ERR",14,"reserved."}, 602 {"ERRbaddrive",15,"Invalid drive specified."}, 603 {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."}, 604 {"ERRdiffdevice",17,"Not same device."}, 605 {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."}, 606 {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."}, 607 {"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."}, 608 {"ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."}, 609 {"ERRbadpipe",230,"Pipe invalid."}, 610 {"ERRpipebusy",231,"All instances of the requested pipe are busy."}, 611 {"ERRpipeclosing",232,"Pipe close in progress."}, 612 {"ERRnotconnected",233,"No process on other end of pipe."}, 613 {"ERRmoredata",234,"There is more data to be returned."}, 614 {NULL,-1,NULL}}; 615 616 /* Server Error Messages */ 617 err_code_struct server_msgs[] = { 618 {"ERRerror",1,"Non-specific error code."}, 619 {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, 620 {"ERRbadtype",3,"reserved."}, 621 {"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."}, 622 {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."}, 623 {"ERRinvnetname",6,"Invalid network name in tree connect."}, 624 {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, 625 {"ERRqfull",49,"Print queue full (files) -- returned by open print file."}, 626 {"ERRqtoobig",50,"Print queue full -- no space."}, 627 {"ERRqeof",51,"EOF on print queue dump."}, 628 {"ERRinvpfid",52,"Invalid print file FID."}, 629 {"ERRsmbcmd",64,"The server did not recognize the command received."}, 630 {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."}, 631 {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."}, 632 {"ERRreserved",68,"reserved."}, 633 {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, 634 {"ERRreserved",70,"reserved."}, 635 {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."}, 636 {"ERRpaused",81,"Server is paused."}, 637 {"ERRmsgoff",82,"Not receiving messages."}, 638 {"ERRnoroom",83,"No room to buffer message."}, 639 {"ERRrmuns",87,"Too many remote user names."}, 640 {"ERRtimeout",88,"Operation timed out."}, 641 {"ERRnoresource",89,"No resources currently available for request."}, 642 {"ERRtoomanyuids",90,"Too many UIDs active on this session."}, 643 {"ERRbaduid",91,"The UID is not known as a valid ID on this session."}, 644 {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."}, 645 {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."}, 646 {"ERRcontmpx",252,"Continue in MPX mode."}, 647 {"ERRreserved",253,"reserved."}, 648 {"ERRreserved",254,"reserved."}, 649 {"ERRnosupport",0xFFFF,"Function not supported."}, 650 {NULL,-1,NULL}}; 651 652 /* Hard Error Messages */ 653 err_code_struct hard_msgs[] = { 654 {"ERRnowrite",19,"Attempt to write on write-protected diskette."}, 655 {"ERRbadunit",20,"Unknown unit."}, 656 {"ERRnotready",21,"Drive not ready."}, 657 {"ERRbadcmd",22,"Unknown command."}, 658 {"ERRdata",23,"Data error (CRC)."}, 659 {"ERRbadreq",24,"Bad request structure length."}, 660 {"ERRseek",25 ,"Seek error."}, 661 {"ERRbadmedia",26,"Unknown media type."}, 662 {"ERRbadsector",27,"Sector not found."}, 663 {"ERRnopaper",28,"Printer out of paper."}, 664 {"ERRwrite",29,"Write fault."}, 665 {"ERRread",30,"Read fault."}, 666 {"ERRgeneral",31,"General failure."}, 667 {"ERRbadshare",32,"A open conflicts with an existing open."}, 668 {"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."}, 669 {"ERRwrongdisk",34,"The wrong disk was found in a drive."}, 670 {"ERRFCBUnavail",35,"No FCBs are available to process request."}, 671 {"ERRsharebufexc",36,"A sharing buffer has been exceeded."}, 672 {NULL,-1,NULL}}; 673 674 675 static struct 676 { 677 int code; 678 char *class; 679 err_code_struct *err_msgs; 680 } err_classes[] = { 681 {0,"SUCCESS",NULL}, 682 {0x01,"ERRDOS",dos_msgs}, 683 {0x02,"ERRSRV",server_msgs}, 684 {0x03,"ERRHRD",hard_msgs}, 685 {0x04,"ERRXOS",NULL}, 686 {0xE1,"ERRRMX1",NULL}, 687 {0xE2,"ERRRMX2",NULL}, 688 {0xE3,"ERRRMX3",NULL}, 689 {0xFF,"ERRCMD",NULL}, 690 {-1,NULL,NULL}}; 691 692 693 /**************************************************************************** 694 return a SMB error string from a SMB buffer 695 ****************************************************************************/ 696 char *smb_errstr(int class,int num) 697 { 698 static char ret[128]; 699 int i,j; 700 701 ret[0]=0; 702 703 for (i=0;err_classes[i].class;i++) 704 if (err_classes[i].code == class) 705 { 706 if (err_classes[i].err_msgs) 707 { 708 err_code_struct *err = err_classes[i].err_msgs; 709 for (j=0;err[j].name;j++) 710 if (num == err[j].code) 711 { 712 snprintf(ret, sizeof(ret), "%s - %s (%s)", 713 err_classes[i].class, 714 err[j].name,err[j].message); 715 return ret; 716 } 717 } 718 719 snprintf(ret,sizeof(ret),"%s - %d",err_classes[i].class,num); 720 return ret; 721 } 722 723 snprintf(ret,sizeof(ret),"ERROR: Unknown error (%d,%d)",class,num); 724 return(ret); 725 } 726