2 Copyright (C) Andrew Tridgell 1995-1999
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
13 static const char rcsid
[] =
14 "@(#) $Header: /tcpdump/master/tcpdump/smbutil.c,v 1.15 2001-06-25 18:58:09 itojun Exp $";
17 #include <sys/param.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
23 #include <netinet/in.h>
31 #include "interface.h"
34 extern const uchar
*startbuf
;
36 /*******************************************************************
37 interpret a 32 bit dos packed date/time to some parameters
38 ********************************************************************/
39 static void interpret_dos_date(uint32 date
,int *year
,int *month
,int *day
,int *hour
,int *minute
,int *second
)
43 p0
=date
&0xFF; p1
=((date
&0xFF00)>>8)&0xFF;
44 p2
=((date
&0xFF0000)>>16)&0xFF; p3
=((date
&0xFF000000)>>24)&0xFF;
46 *second
= 2*(p0
& 0x1F);
47 *minute
= ((p0
>>5)&0xFF) + ((p1
&0x7)<<3);
50 *month
= ((p2
>>5)&0xFF) + ((p3
&0x1)<<3) - 1;
51 *year
= ((p3
>>1)&0xFF) + 80;
54 /*******************************************************************
55 create a unix date from a dos date
56 ********************************************************************/
57 static time_t make_unix_date(const void *date_ptr
)
62 dos_date
= IVAL(date_ptr
,0);
64 if (dos_date
== 0) return(0);
66 interpret_dos_date(dos_date
,&t
.tm_year
,&t
.tm_mon
,
67 &t
.tm_mday
,&t
.tm_hour
,&t
.tm_min
,&t
.tm_sec
);
75 /*******************************************************************
76 create a unix date from a dos date
77 ********************************************************************/
78 static time_t make_unix_date2(const void *date_ptr
)
83 x2
= ((x
&0xFFFF)<<16) | ((x
&0xFFFF0000)>>16);
86 return(make_unix_date((void *)&x
));
89 /****************************************************************************
90 interpret an 8 byte "filetime" structure to a time_t
91 It's originally in "100ns units since jan 1st 1601"
92 ****************************************************************************/
93 static time_t interpret_long_date(const char *p
)
98 /* this gives us seconds since jan 1st 1601 (approx) */
99 d
= (IVAL(p
,4)*256.0 + CVAL(p
,3)) * (1.0e-7 * (1<<24));
101 /* now adjust by 369 years to make the secs since 1970 */
102 d
-= 369.0*365.25*24*60*60;
104 /* and a fudge factor as we got it wrong by a few days */
105 d
+= (3*24*60*60 + 6*60*60 + 2);
116 /****************************************************************************
117 interpret the weird netbios "name". Return the name type, or -1 if
118 we run past the end of the buffer
119 ****************************************************************************/
120 static int name_interpret(const uchar
*in
,const uchar
*maxbuf
,char *out
)
126 return(-1); /* name goes past the end of the buffer */
132 if (len
> 30 || len
<1) return(0);
136 if (in
+ 1 >= maxbuf
)
137 return(-1); /* name goes past the end of the buffer */
139 if (in
[0] < 'A' || in
[0] > 'P' || in
[1] < 'A' || in
[1] > 'P') {
143 *out
= ((in
[0]-'A')<<4) + (in
[1]-'A');
156 /****************************************************************************
157 find a pointer to a netbios name
158 ****************************************************************************/
159 static const uchar
*name_ptr(const uchar
*buf
,int ofs
,const uchar
*maxbuf
)
166 return(NULL
); /* name goes past the end of the buffer */
171 /* XXX - this should use the same code that the DNS dissector does */
172 if ((c
& 0xC0) == 0xC0)
174 uint16 l
= RSVAL(buf
, ofs
) & 0x3FFF;
177 /* We have a pointer that points to itself. */
182 return(NULL
); /* name goes past the end of the buffer */
190 return(NULL
); /* name goes past the end of the buffer */
193 /****************************************************************************
194 extract a netbios name from a buf
195 ****************************************************************************/
196 static int name_extract(const uchar
*buf
,int ofs
,const uchar
*maxbuf
,char *name
)
198 const uchar
*p
= name_ptr(buf
,ofs
,maxbuf
);
200 return(-1); /* error (probably name going past end of buffer) */
202 return(name_interpret(p
,maxbuf
,name
));
206 /****************************************************************************
207 return the total storage length of a mangled name
208 ****************************************************************************/
209 static int name_len(const unsigned char *s
, const unsigned char *maxbuf
)
211 const unsigned char *s0
= s
;
215 return(-1); /* name goes past the end of the buffer */
218 if ((c
& 0xC0) == 0xC0)
223 return(-1); /* name goes past the end of the buffer */
227 return(PTR_DIFF(s
,s0
)+1);
230 return(-1); /* name goes past the end of the buffer */
233 static void print_asc(const unsigned char *buf
,int len
)
240 static char *name_type_str(int name_type
)
242 static char *f
= NULL
;
244 case 0: f
= "Workstation"; break;
245 case 0x03: f
= "Client?"; break;
246 case 0x20: f
= "Server"; break;
247 case 0x1d: f
= "Master Browser"; break;
248 case 0x1b: f
= "Domain Controller"; break;
249 case 0x1e: f
= "Browser Server"; break;
250 default: f
= "Unknown"; break;
255 void print_data(const unsigned char *buf
, int len
)
261 printf("%02X ",(int)buf
[i
]);
263 if (i
%8 == 0) printf(" ");
265 print_asc(&buf
[i
-16],8); printf(" ");
266 print_asc(&buf
[i
-8],8); printf("\n");
267 if (i
<len
) printf("[%03X] ",i
);
275 if (n
>8) printf(" ");
276 while (n
--) printf(" ");
279 print_asc(&buf
[i
-(i
%16)],n
); printf(" ");
281 if (n
>0) print_asc(&buf
[i
-n
],n
);
287 static void write_bits(unsigned int val
,char *fmt
)
292 while ((p
=strchr(fmt
,'|'))) {
293 int l
= PTR_DIFF(p
,fmt
);
294 if (l
&& (val
& (1<<i
)))
295 printf("%.*s ",l
,fmt
);
301 /* convert a unicode string */
302 static const char *unistr(const char *s
, int *len
)
304 static char buf
[1000];
306 static int use_unicode
= -1;
308 if (use_unicode
== -1) {
309 char *p
= getenv("USE_UNICODE");
310 if (p
&& (atoi(p
) == 1))
316 /* maybe it isn't unicode - a cheap trick */
317 if (!use_unicode
|| (s
[0] && s
[1])) {
324 if (s
[0] == 0 && s
[1] != 0) {
329 while (l
< (sizeof(buf
)-1) && s
[0] && s
[1] == 0) {
340 fdata1(const uchar
*buf
, const char *fmt
, const uchar
*maxbuf
)
343 char *attrib_fmt
= "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|";
346 while (*fmt
&& buf
<maxbuf
) {
349 write_bits(CVAL(buf
,0), attrib_fmt
);
355 write_bits(SVAL(buf
, 0), attrib_fmt
);
363 char *p
= strchr(++fmt
, '}');
364 int l
= PTR_DIFF(p
, fmt
);
365 strncpy(bitfmt
, fmt
, l
);
368 write_bits(CVAL(buf
, 0), bitfmt
);
375 int l
= atoi(fmt
+ 1);
378 while (isdigit(*fmt
))
388 unsigned int x
= reverse
? RIVAL(buf
, 0) : IVAL(buf
, 0);
389 printf("%d (0x%x)", x
, x
);
396 unsigned int x1
= reverse
? RIVAL(buf
, 0) : IVAL(buf
, 0);
397 unsigned int x2
= reverse
? RIVAL(buf
, 4) : IVAL(buf
, 4);
399 printf("0x%08x:%08x", x2
, x1
);
401 printf("%d (0x%08x%08x)", x1
, x2
, x1
);
408 unsigned int x
= reverse
? RSVAL(buf
, 0) : SVAL(buf
, 0);
409 printf("%d (0x%x)", x
, x
);
416 unsigned int x
= reverse
? RIVAL(buf
, 0) : IVAL(buf
, 0);
424 unsigned int x
= reverse
? RSVAL(buf
, 0) : SVAL(buf
, 0);
432 unsigned int x
= CVAL(buf
,0);
440 unsigned int x
= CVAL(buf
, 0);
441 printf("%u (0x%x)", x
, x
);
448 printf("%.*s", (int)PTR_DIFF(maxbuf
, buf
), unistr(buf
, &len
));
455 if (*buf
!= 4 && *buf
!= 2)
456 printf("Error! ASCIIZ buffer of type %u (safety=%lu)\n", *buf
,
457 (unsigned long)PTR_DIFF(maxbuf
, buf
));
458 printf("%.*s", (int)PTR_DIFF(maxbuf
, buf
+ 1),
459 unistr(buf
+ 1, &len
));
466 int l
= atoi(fmt
+ 1);
467 printf("%-*.*s", l
, l
, buf
);
470 while (isdigit(*fmt
))
476 int l
= atoi(fmt
+ 1);
478 printf("%02x", *buf
++);
480 while (isdigit(*fmt
))
493 name_type
= name_extract(startbuf
, PTR_DIFF(buf
, startbuf
),
497 len
= name_len(buf
, maxbuf
);
501 printf("%-15.15s NameType=0x%02X (%s)", nbuf
, name_type
,
502 name_type_str(name_type
));
506 printf("%-15.15s NameType=0x%02X (%s)", buf
, name_type
,
507 name_type_str(name_type
));
512 while (isdigit(*fmt
))
521 switch (atoi(fmt
+ 1)) {
523 if (x
== 0 || x
== -1 || x
== 0xFFFFFFFF)
526 t
= make_unix_date(buf
);
530 if (x
== 0 || x
== -1 || x
== 0xFFFFFFFF)
533 t
= make_unix_date2(buf
);
537 t
= interpret_long_date(buf
);
541 printf("%s", t
? asctime(localtime(&t
)) : "NULL\n");
543 while (isdigit(*fmt
))
554 if (buf
>= maxbuf
&& *fmt
)
555 printf("END OF BUFFER\n");
561 printf("WARNING: Short packet. Try increasing the snap length\n");
566 fdata(const uchar
*buf
, const char *fmt
, const uchar
*maxbuf
)
568 static int depth
= 0;
576 while (buf
< maxbuf
) {
579 buf2
= fdata(buf
, fmt
, maxbuf
);
607 memset(s
, 0, sizeof(s
));
608 p
= strchr(fmt
, ']');
609 if (p
- fmt
+ 1 > sizeof(s
)) {
613 strncpy(s
, fmt
, p
- fmt
);
616 buf
= fdata1(buf
, s
, maxbuf
);
628 if (!depth
&& buf
< maxbuf
) {
629 size_t len
= PTR_DIFF(maxbuf
, buf
);
630 printf("Data: (%lu bytes)\n", (unsigned long)len
);
631 print_data(buf
, len
);
643 /* Dos Error Messages */
644 static err_code_struct dos_msgs
[] = {
645 { "ERRbadfunc", 1, "Invalid function." },
646 { "ERRbadfile", 2, "File not found." },
647 { "ERRbadpath", 3, "Directory invalid." },
648 { "ERRnofids", 4, "No file descriptors available" },
649 { "ERRnoaccess", 5, "Access denied." },
650 { "ERRbadfid", 6, "Invalid file handle." },
651 { "ERRbadmcb", 7, "Memory control blocks destroyed." },
652 { "ERRnomem", 8, "Insufficient server memory to perform the requested function." },
653 { "ERRbadmem", 9, "Invalid memory block address." },
654 { "ERRbadenv", 10, "Invalid environment." },
655 { "ERRbadformat", 11, "Invalid format." },
656 { "ERRbadaccess", 12, "Invalid open mode." },
657 { "ERRbaddata", 13, "Invalid data." },
658 { "ERR", 14, "reserved." },
659 { "ERRbaddrive", 15, "Invalid drive specified." },
660 { "ERRremcd", 16, "A Delete Directory request attempted to remove the server's current directory." },
661 { "ERRdiffdevice", 17, "Not same device." },
662 { "ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria." },
663 { "ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing FIDs on the file." },
664 { "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." },
665 { "ERRfilexists", 80, "The file named in a Create Directory, Make New File or Link request already exists." },
666 { "ERRbadpipe", 230, "Pipe invalid." },
667 { "ERRpipebusy", 231, "All instances of the requested pipe are busy." },
668 { "ERRpipeclosing", 232, "Pipe close in progress." },
669 { "ERRnotconnected", 233, "No process on other end of pipe." },
670 { "ERRmoredata", 234, "There is more data to be returned." },
674 /* Server Error Messages */
675 err_code_struct server_msgs
[] = {
676 { "ERRerror", 1, "Non-specific error code." },
677 { "ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid." },
678 { "ERRbadtype", 3, "reserved." },
679 { "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." },
680 { "ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid." },
681 { "ERRinvnetname", 6, "Invalid network name in tree connect." },
682 { "ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection." },
683 { "ERRqfull", 49, "Print queue full (files) -- returned by open print file." },
684 { "ERRqtoobig", 50, "Print queue full -- no space." },
685 { "ERRqeof", 51, "EOF on print queue dump." },
686 { "ERRinvpfid", 52, "Invalid print file FID." },
687 { "ERRsmbcmd", 64, "The server did not recognize the command received." },
688 { "ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable." },
689 { "ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid combination of values." },
690 { "ERRreserved", 68, "reserved." },
691 { "ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute." },
692 { "ERRreserved", 70, "reserved." },
693 { "ERRsetattrmode", 71, "The attribute mode in the Set File Attribute request is invalid." },
694 { "ERRpaused", 81, "Server is paused." },
695 { "ERRmsgoff", 82, "Not receiving messages." },
696 { "ERRnoroom", 83, "No room to buffer message." },
697 { "ERRrmuns", 87, "Too many remote user names." },
698 { "ERRtimeout", 88, "Operation timed out." },
699 { "ERRnoresource", 89, "No resources currently available for request." },
700 { "ERRtoomanyuids", 90, "Too many UIDs active on this session." },
701 { "ERRbaduid", 91, "The UID is not known as a valid ID on this session." },
702 { "ERRusempx", 250, "Temp unable to support Raw, use MPX mode." },
703 { "ERRusestd", 251, "Temp unable to support Raw, use standard read/write." },
704 { "ERRcontmpx", 252, "Continue in MPX mode." },
705 { "ERRreserved", 253, "reserved." },
706 { "ERRreserved", 254, "reserved." },
707 { "ERRnosupport", 0xFFFF, "Function not supported." },
711 /* Hard Error Messages */
712 err_code_struct hard_msgs
[] = {
713 { "ERRnowrite", 19, "Attempt to write on write-protected diskette." },
714 { "ERRbadunit", 20, "Unknown unit." },
715 { "ERRnotready", 21, "Drive not ready." },
716 { "ERRbadcmd", 22, "Unknown command." },
717 { "ERRdata", 23, "Data error (CRC)." },
718 { "ERRbadreq", 24, "Bad request structure length." },
719 { "ERRseek", 25 , "Seek error." },
720 { "ERRbadmedia", 26, "Unknown media type." },
721 { "ERRbadsector", 27, "Sector not found." },
722 { "ERRnopaper", 28, "Printer out of paper." },
723 { "ERRwrite", 29, "Write fault." },
724 { "ERRread", 30, "Read fault." },
725 { "ERRgeneral", 31, "General failure." },
726 { "ERRbadshare", 32, "A open conflicts with an existing open." },
727 { "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." },
728 { "ERRwrongdisk", 34, "The wrong disk was found in a drive." },
729 { "ERRFCBUnavail", 35, "No FCBs are available to process request." },
730 { "ERRsharebufexc", 36, "A sharing buffer has been exceeded." },
737 err_code_struct
*err_msgs
;
739 { 0, "SUCCESS", NULL
},
740 { 0x01, "ERRDOS", dos_msgs
},
741 { 0x02, "ERRSRV", server_msgs
},
742 { 0x03, "ERRHRD", hard_msgs
},
743 { 0x04, "ERRXOS", NULL
},
744 { 0xE1, "ERRRMX1", NULL
},
745 { 0xE2, "ERRRMX2", NULL
},
746 { 0xE3, "ERRRMX3", NULL
},
747 { 0xFF, "ERRCMD", NULL
},
752 * return a SMB error string from a SMB buffer
755 smb_errstr(int class, int num
)
757 static char ret
[128];
762 for (i
= 0; err_classes
[i
].class; i
++)
763 if (err_classes
[i
].code
== class) {
764 if (err_classes
[i
].err_msgs
) {
765 err_code_struct
*err
= err_classes
[i
].err_msgs
;
766 for (j
= 0; err
[j
].name
; j
++)
767 if (num
== err
[j
].code
) {
768 snprintf(ret
, sizeof(ret
), "%s - %s (%s)",
769 err_classes
[i
].class, err
[j
].name
, err
[j
].message
);
774 snprintf(ret
, sizeof(ret
), "%s - %d", err_classes
[i
].class, num
);
778 snprintf(ret
, sizeof(ret
), "ERROR: Unknown error (%d,%d)", class, num
);