1 /* $OpenBSD: smbutil.c,v 1.8 2013/04/16 18:10:24 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 memset(&t, 0, sizeof t); 64 interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon, 65 &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); 66 t.tm_wday = 1; 67 t.tm_yday = 1; 68 t.tm_isdst = 0; 69 70 return (mktime(&t)); 71 } 72 73 /******************************************************************* 74 create a unix date from a dos date 75 ********************************************************************/ 76 static time_t make_unix_date2(const void *date_ptr) 77 { 78 uint32 x,x2; 79 80 x = IVAL(date_ptr,0); 81 x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); 82 SIVAL(&x,0,x2); 83 84 return(make_unix_date((void *)&x)); 85 } 86 87 /**************************************************************************** 88 interpret an 8 byte "filetime" structure to a time_t 89 It's originally in "100ns units since jan 1st 1601" 90 ****************************************************************************/ 91 static time_t interpret_long_date(const char *p) 92 { 93 double d; 94 time_t ret; 95 96 /* this gives us seconds since jan 1st 1601 (approx) */ 97 d = (IVAL(p,4)*256.0 + CVAL(p,3)) * (1.0e-7 * (1<<24)); 98 99 /* now adjust by 369 years to make the secs since 1970 */ 100 d -= 369.0*365.25*24*60*60; 101 102 /* and a fudge factor as we got it wrong by a few days */ 103 d += (3*24*60*60 + 6*60*60 + 2); 104 105 if (d<0) 106 return(0); 107 108 ret = (time_t)d; 109 110 return(ret); 111 } 112 113 114 /**************************************************************************** 115 interpret the weird netbios "name". Return the name type, or -1 if 116 we run past the end of the buffer 117 ****************************************************************************/ 118 static int name_interpret(const uchar *in,const uchar *maxbuf,char *out) 119 { 120 char *ob = out; 121 int ret; 122 int len; 123 124 if (in >= maxbuf) 125 return(-1); /* name goes past the end of the buffer */ 126 TCHECK2(*in, 1); 127 len = (*in++) / 2; 128 129 *out=0; 130 131 if (len > 30 || len<1) return(0); 132 133 while (len--) 134 { 135 if (in + 1 >= maxbuf) 136 return(-1); /* name goes past the end of the buffer */ 137 TCHECK2(*in, 2); 138 if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { 139 *out++ = 0; 140 break; 141 } 142 *out = ((in[0]-'A')<<4) + (in[1]-'A'); 143 in += 2; 144 out++; 145 } 146 ret = out[-1]; 147 out--; 148 while (out[-1] == ' ') 149 out--; 150 *out = '\0'; 151 for (; *ob; ob++) 152 if (!isprint(*ob)) 153 *ob = 'X'; 154 155 return(ret); 156 157 trunc: 158 return(-1); 159 } 160 161 /**************************************************************************** 162 find a pointer to a netbios name 163 ****************************************************************************/ 164 static const uchar *name_ptr(const uchar *buf,int ofs,const uchar *maxbuf) 165 { 166 const uchar *p; 167 uchar c; 168 169 p = buf+ofs; 170 if (p >= maxbuf) 171 return(NULL); /* name goes past the end of the buffer */ 172 TCHECK2(*p, 1); 173 174 c = *p; 175 176 /* XXX - this should use the same code that the DNS dissector does */ 177 if ((c & 0xC0) == 0xC0) 178 { 179 uint16 l = RSVAL(buf, ofs) & 0x3FFF; 180 if (l == 0) 181 { 182 /* We have a pointer that points to itself. */ 183 return(NULL); 184 } 185 p = buf + l; 186 if (p >= maxbuf) 187 return(NULL); /* name goes past the end of the buffer */ 188 TCHECK2(*p, 1); 189 return(buf + l); 190 } 191 else 192 return(buf+ofs); 193 194 trunc: 195 return(NULL); /* name goes past the end of the buffer */ 196 } 197 198 /**************************************************************************** 199 extract a netbios name from a buf 200 ****************************************************************************/ 201 static int name_extract(const uchar *buf,int ofs,const uchar *maxbuf,char *name) 202 { 203 const uchar *p = name_ptr(buf,ofs,maxbuf); 204 if (p == NULL) 205 return(-1); /* error (probably name going past end of buffer) */ 206 *name = '\0'; 207 return(name_interpret(p,maxbuf,name)); 208 } 209 210 211 /**************************************************************************** 212 return the total storage length of a mangled name 213 ****************************************************************************/ 214 static int name_len(const unsigned char *s, const unsigned char *maxbuf) 215 { 216 const unsigned char *s0 = s; 217 unsigned char c; 218 219 if (s >= maxbuf) 220 return(-1); /* name goes past the end of the buffer */ 221 TCHECK2(*s, 1); 222 c = *s; 223 if ((c & 0xC0) == 0xC0) 224 return(2); 225 while (*s) 226 { 227 if (s >= maxbuf) 228 return(-1); /* name goes past the end of the buffer */ 229 TCHECK2(*s, 1); 230 s += (*s)+1; 231 } 232 return(PTR_DIFF(s,s0)+1); 233 234 trunc: 235 return(-1); /* name goes past the end of the buffer */ 236 } 237 238 static char *name_type_str(int name_type) 239 { 240 static char *f = NULL; 241 switch (name_type) { 242 case 0: f = "Workstation"; break; 243 case 0x03: f = "Client?"; break; 244 case 0x20: f = "Server"; break; 245 case 0x1d: f = "Master Browser"; break; 246 case 0x1b: f = "Domain Controller"; break; 247 case 0x1e: f = "Browser Server"; break; 248 default: f = "Unknown"; break; 249 } 250 return(f); 251 } 252 253 static void write_bits(unsigned int val,char *fmt) 254 { 255 char *p = fmt; 256 int i=0; 257 258 while ((p=strchr(fmt,'|'))) { 259 int l = PTR_DIFF(p,fmt); 260 if (l && (val & (1<<i))) 261 printf("%.*s ",l,fmt); 262 fmt = p+1; 263 i++; 264 } 265 } 266 267 /* convert a unicode string */ 268 static const char *unistr(const char *s, int *len) 269 { 270 static char buf[1000]; 271 int l=0; 272 static int use_unicode = -1; 273 274 if (use_unicode == -1) { 275 char *p = getenv("USE_UNICODE"); 276 if (p && (atoi(p) == 1)) 277 use_unicode = 1; 278 else 279 use_unicode = 0; 280 } 281 282 /* maybe it isn't unicode - a cheap trick */ 283 if (!use_unicode || (s[0] && s[1])) { 284 *len = strlen(s)+1; 285 return s; 286 } 287 288 *len = 0; 289 290 if (s[0] == 0 && s[1] != 0) { 291 s++; 292 *len = 1; 293 } 294 295 while (l < (sizeof(buf)-1) && s[0] && s[1] == 0) { 296 buf[l] = s[0]; 297 s += 2; l++; 298 *len += 2; 299 } 300 buf[l] = 0; 301 *len += 2; 302 return buf; 303 } 304 305 static const uchar *fdata1(const uchar *buf, const char *fmt, const uchar *maxbuf) 306 { 307 int reverse=0; 308 char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|"; 309 int len; 310 311 while (*fmt && buf<maxbuf) { 312 switch (*fmt) { 313 case 'a': 314 write_bits(CVAL(buf,0),attrib_fmt); 315 buf++; fmt++; 316 break; 317 318 case 'A': 319 write_bits(SVAL(buf,0),attrib_fmt); 320 buf+=2; fmt++; 321 break; 322 323 case '{': 324 { 325 char bitfmt[128]; 326 char *p = strchr(++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