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
14 static const char rcsid
[] _U_
=
15 "@(#) $Header: /tcpdump/master/tcpdump/smbutil.c,v 1.34 2004-12-29 05:27:27 guy Exp $";
18 #include <tcpdump-stdinc.h>
24 #include "interface.h"
28 static u_int32_t stringlen
;
29 extern const u_char
*startbuf
;
32 * interpret a 32 bit dos packed date/time to some parameters
35 interpret_dos_date(u_int32_t date
, struct tm
*tp
)
37 u_int32_t p0
, p1
, p2
, p3
;
40 p1
= ((date
& 0xFF00) >> 8) & 0xFF;
41 p2
= ((date
& 0xFF0000) >> 16) & 0xFF;
42 p3
= ((date
& 0xFF000000) >> 24) & 0xFF;
44 tp
->tm_sec
= 2 * (p0
& 0x1F);
45 tp
->tm_min
= ((p0
>> 5) & 0xFF) + ((p1
& 0x7) << 3);
46 tp
->tm_hour
= (p1
>> 3) & 0xFF;
47 tp
->tm_mday
= (p2
& 0x1F);
48 tp
->tm_mon
= ((p2
>> 5) & 0xFF) + ((p3
& 0x1) << 3) - 1;
49 tp
->tm_year
= ((p3
>> 1) & 0xFF) + 80;
54 * create a unix date from a dos date
57 int_unix_date(u_int32_t dos_date
)
64 interpret_dos_date(dos_date
, &t
);
73 * create a unix date from a dos date
74 * in network byte order
77 make_unix_date(const u_char
*date_ptr
)
79 u_int32_t dos_date
= 0;
81 dos_date
= EXTRACT_LE_32BITS(date_ptr
);
83 return int_unix_date(dos_date
);
87 * create a unix date from a dos date
88 * in halfword-swapped network byte order!
91 make_unix_date2(const u_char
*date_ptr
)
95 x
= EXTRACT_LE_32BITS(date_ptr
);
96 x2
= ((x
& 0xFFFF) << 16) | ((x
& 0xFFFF0000) >> 16);
97 return int_unix_date(x2
);
101 * interpret an 8 byte "filetime" structure to a time_t
102 * It's originally in "100ns units since jan 1st 1601"
105 interpret_long_date(const u_char
*p
)
110 /* this gives us seconds since jan 1st 1601 (approx) */
111 d
= (EXTRACT_LE_32BITS(p
+ 4) * 256.0 + p
[3]) * (1.0e-7 * (1 << 24));
113 /* now adjust by 369 years to make the secs since 1970 */
114 d
-= 369.0 * 365.25 * 24 * 60 * 60;
116 /* and a fudge factor as we got it wrong by a few days */
117 d
+= (3 * 24 * 60 * 60 + 6 * 60 * 60 + 2);
128 * interpret the weird netbios "name". Return the name type, or -1 if
129 * we run past the end of the buffer
132 name_interpret(const u_char
*in
, const u_char
*maxbuf
, char *out
)
138 return(-1); /* name goes past the end of the buffer */
144 if (len
> 30 || len
< 1)
149 if (in
+ 1 >= maxbuf
)
150 return(-1); /* name goes past the end of the buffer */
151 if (in
[0] < 'A' || in
[0] > 'P' || in
[1] < 'A' || in
[1] > 'P') {
155 *out
= ((in
[0] - 'A') << 4) + (in
[1] - 'A');
169 * find a pointer to a netbios name
171 static const u_char
*
172 name_ptr(const u_char
*buf
, int ofs
, const u_char
*maxbuf
)
179 return(NULL
); /* name goes past the end of the buffer */
184 /* XXX - this should use the same code that the DNS dissector does */
185 if ((c
& 0xC0) == 0xC0) {
189 if ((p
+ 1) >= maxbuf
)
190 return(NULL
); /* name goes past the end of the buffer */
191 l
= EXTRACT_16BITS(p
) & 0x3FFF;
193 /* We have a pointer that points to itself. */
198 return(NULL
); /* name goes past the end of the buffer */
204 return(NULL
); /* name goes past the end of the buffer */
208 * extract a netbios name from a buf
211 name_extract(const u_char
*buf
, int ofs
, const u_char
*maxbuf
, char *name
)
213 const u_char
*p
= name_ptr(buf
, ofs
, maxbuf
);
215 return(-1); /* error (probably name going past end of buffer) */
217 return(name_interpret(p
, maxbuf
, name
));
222 * return the total storage length of a mangled name
225 name_len(const unsigned char *s
, const unsigned char *maxbuf
)
227 const unsigned char *s0
= s
;
231 return(-1); /* name goes past the end of the buffer */
234 if ((c
& 0xC0) == 0xC0)
238 return(-1); /* name goes past the end of the buffer */
242 return(PTR_DIFF(s
, s0
) + 1);
245 return(-1); /* name goes past the end of the buffer */
249 print_asc(const unsigned char *buf
, int len
)
252 for (i
= 0; i
< len
; i
++)
257 name_type_str(int name_type
)
259 const char *f
= NULL
;
262 case 0: f
= "Workstation"; break;
263 case 0x03: f
= "Client?"; break;
264 case 0x20: f
= "Server"; break;
265 case 0x1d: f
= "Master Browser"; break;
266 case 0x1b: f
= "Domain Controller"; break;
267 case 0x1e: f
= "Browser Server"; break;
268 default: f
= "Unknown"; break;
274 print_data(const unsigned char *buf
, int len
)
280 printf("[%03X] ", i
);
281 for (i
= 0; i
< len
; /*nothing*/) {
282 printf("%02X ", buf
[i
] & 0xff);
287 print_asc(&buf
[i
- 16], 8);
289 print_asc(&buf
[i
- 8], 8);
292 printf("[%03X] ", i
);
305 n
= SMBMIN(8, i
% 16);
306 print_asc(&buf
[i
- (i
% 16)], n
);
310 print_asc(&buf
[i
- n
], n
);
317 write_bits(unsigned int val
, const char *fmt
)
322 while ((p
= strchr(fmt
, '|'))) {
323 size_t l
= PTR_DIFF(p
, fmt
);
324 if (l
&& (val
& (1 << i
)))
325 printf("%.*s ", (int)l
, fmt
);
331 /* convert a UCS2 string into iso-8859-1 string */
332 #define MAX_UNISTR_SIZE 1000
334 unistr(const u_char
*s
, u_int32_t
*len
, int use_unicode
)
336 static char buf
[MAX_UNISTR_SIZE
+1];
343 * Skip padding that puts the string on an even boundary.
345 if (((s
- startbuf
) % 2) != 0) {
352 * Null-terminated string.
369 if (sp
[0] == 0 && sp
[1] == 0)
382 while (strsize
!= 0) {
384 if (l
>= MAX_UNISTR_SIZE
)
398 while (strsize
!= 0) {
400 if (l
>= MAX_UNISTR_SIZE
)
402 if (s
[1] == 0 && isprint(s
[0])) {
403 /* It's a printable ASCII character */
406 /* It's a non-ASCII character or a non-printable ASCII character */
407 if (s
[0] == 0 && s
[1] == 0)
425 static const u_char
*
426 smb_fdata1(const u_char
*buf
, const char *fmt
, const u_char
*maxbuf
,
430 const char *attrib_fmt
= "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|";
433 while (*fmt
&& buf
<maxbuf
) {
437 write_bits(buf
[0], attrib_fmt
);
444 write_bits(EXTRACT_LE_16BITS(buf
), attrib_fmt
);
455 p
= strchr(++fmt
, '}');
456 l
= PTR_DIFF(p
, fmt
);
458 if ((unsigned int)l
> sizeof(bitfmt
) - 1)
459 l
= sizeof(bitfmt
)-1;
461 strncpy(bitfmt
, fmt
, l
);
465 write_bits(buf
[0], bitfmt
);
472 int l
= atoi(fmt
+ 1);
476 while (isdigit((unsigned char)*fmt
))
489 printf("%u (0x%x)", x
, x
);
498 x
= reverse
? EXTRACT_16BITS(buf
) :
499 EXTRACT_LE_16BITS(buf
);
500 printf("%d (0x%x)", x
, x
);
509 x
= reverse
? EXTRACT_32BITS(buf
) :
510 EXTRACT_LE_32BITS(buf
);
511 printf("%d (0x%x)", x
, x
);
520 x
= reverse
? EXTRACT_64BITS(buf
) :
521 EXTRACT_LE_64BITS(buf
);
522 printf("%" PRIu64
" (0x%" PRIx64
")", x
, x
);
529 /* Weird mixed-endian length values in 64-bit locks */
533 x1
= reverse
? EXTRACT_32BITS(buf
) :
534 EXTRACT_LE_32BITS(buf
);
535 x2
= reverse
? EXTRACT_32BITS(buf
+ 4) :
536 EXTRACT_LE_32BITS(buf
+ 4);
537 x
= (((u_int64_t
)x1
) << 32) | x2
;
538 printf("%" PRIu64
" (0x%" PRIx64
")", x
, x
);
557 x
= reverse
? EXTRACT_16BITS(buf
) :
558 EXTRACT_LE_16BITS(buf
);
568 x
= reverse
? EXTRACT_32BITS(buf
) :
569 EXTRACT_LE_32BITS(buf
);
583 printf("%u", stringlen
);
589 stringlen
= reverse
? EXTRACT_16BITS(buf
) :
590 EXTRACT_LE_16BITS(buf
);
591 printf("%u", stringlen
);
597 stringlen
= reverse
? EXTRACT_32BITS(buf
) :
598 EXTRACT_LE_32BITS(buf
);
599 printf("%u", stringlen
);
607 case 'R': /* like 'S', but always ASCII */
612 s
= unistr(buf
, &len
, (*fmt
== 'R') ? 0 : unicodestr
);
621 case 'Y': /* like 'Z', but always ASCII */
625 if (*buf
!= 4 && *buf
!= 2) {
626 printf("Error! ASCIIZ buffer of type %u", *buf
);
627 return maxbuf
; /* give up */
630 s
= unistr(buf
+ 1, &len
, (*fmt
== 'Y') ? 0 : unicodestr
);
640 int l
= atoi(fmt
+ 1);
642 printf("%-*.*s", l
, l
, buf
);
645 while (isdigit((unsigned char)*fmt
))
651 TCHECK2(*buf
, stringlen
);
652 printf("%-*.*s", stringlen
, stringlen
, buf
);
655 while (isdigit((unsigned char)*fmt
))
662 s
= unistr(buf
, &stringlen
, unicodestr
);
672 int l
= atoi(fmt
+ 1);
675 printf("%02x", *buf
++);
677 while (isdigit((unsigned char)*fmt
))
690 name_type
= name_extract(startbuf
, PTR_DIFF(buf
, startbuf
),
694 len
= name_len(buf
, maxbuf
);
698 printf("%-15.15s NameType=0x%02X (%s)", nbuf
, name_type
,
699 name_type_str(name_type
));
704 printf("%-15.15s NameType=0x%02X (%s)", buf
, name_type
,
705 name_type_str(name_type
));
710 while (isdigit((unsigned char)*fmt
))
721 switch (atoi(fmt
+ 1)) {
724 x
= EXTRACT_LE_32BITS(buf
);
725 if (x
== 0 || x
== 0xFFFFFFFF)
728 t
= make_unix_date(buf
);
733 x
= EXTRACT_LE_32BITS(buf
);
734 if (x
== 0 || x
== 0xFFFFFFFF)
737 t
= make_unix_date2(buf
);
742 t
= interpret_long_date(buf
);
749 tstring
= asctime(lt
);
751 tstring
= "(Can't convert time)\n";
754 printf("%s", tstring
);
756 while (isdigit((unsigned char)*fmt
))
767 if (buf
>= maxbuf
&& *fmt
)
768 printf("END OF BUFFER\n");
774 printf("WARNING: Short packet. Try increasing the snap length\n");
779 smb_fdata(const u_char
*buf
, const char *fmt
, const u_char
*maxbuf
,
782 static int depth
= 0;
790 while (buf
< maxbuf
) {
793 buf2
= smb_fdata(buf
, fmt
, maxbuf
, unicodestr
);
823 memset(s
, 0, sizeof(s
));
824 p
= strchr(fmt
, ']');
825 if ((size_t)(p
- fmt
+ 1) > sizeof(s
)) {
829 strncpy(s
, fmt
, p
- fmt
);
832 buf
= smb_fdata1(buf
, s
, maxbuf
, unicodestr
);
844 if (!depth
&& buf
< maxbuf
) {
845 size_t len
= PTR_DIFF(maxbuf
, buf
);
846 printf("Data: (%lu bytes)\n", (unsigned long)len
);
847 print_data(buf
, len
);
859 /* Dos Error Messages */
860 static err_code_struct dos_msgs
[] = {
861 { "ERRbadfunc", 1, "Invalid function." },
862 { "ERRbadfile", 2, "File not found." },
863 { "ERRbadpath", 3, "Directory invalid." },
864 { "ERRnofids", 4, "No file descriptors available" },
865 { "ERRnoaccess", 5, "Access denied." },
866 { "ERRbadfid", 6, "Invalid file handle." },
867 { "ERRbadmcb", 7, "Memory control blocks destroyed." },
868 { "ERRnomem", 8, "Insufficient server memory to perform the requested function." },
869 { "ERRbadmem", 9, "Invalid memory block address." },
870 { "ERRbadenv", 10, "Invalid environment." },
871 { "ERRbadformat", 11, "Invalid format." },
872 { "ERRbadaccess", 12, "Invalid open mode." },
873 { "ERRbaddata", 13, "Invalid data." },
874 { "ERR", 14, "reserved." },
875 { "ERRbaddrive", 15, "Invalid drive specified." },
876 { "ERRremcd", 16, "A Delete Directory request attempted to remove the server's current directory." },
877 { "ERRdiffdevice", 17, "Not same device." },
878 { "ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria." },
879 { "ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing FIDs on the file." },
880 { "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." },
881 { "ERRfilexists", 80, "The file named in a Create Directory, Make New File or Link request already exists." },
882 { "ERRbadpipe", 230, "Pipe invalid." },
883 { "ERRpipebusy", 231, "All instances of the requested pipe are busy." },
884 { "ERRpipeclosing", 232, "Pipe close in progress." },
885 { "ERRnotconnected", 233, "No process on other end of pipe." },
886 { "ERRmoredata", 234, "There is more data to be returned." },
890 /* Server Error Messages */
891 err_code_struct server_msgs
[] = {
892 { "ERRerror", 1, "Non-specific error code." },
893 { "ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid." },
894 { "ERRbadtype", 3, "reserved." },
895 { "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." },
896 { "ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid." },
897 { "ERRinvnetname", 6, "Invalid network name in tree connect." },
898 { "ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection." },
899 { "ERRqfull", 49, "Print queue full (files) -- returned by open print file." },
900 { "ERRqtoobig", 50, "Print queue full -- no space." },
901 { "ERRqeof", 51, "EOF on print queue dump." },
902 { "ERRinvpfid", 52, "Invalid print file FID." },
903 { "ERRsmbcmd", 64, "The server did not recognize the command received." },
904 { "ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable." },
905 { "ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid combination of values." },
906 { "ERRreserved", 68, "reserved." },
907 { "ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute." },
908 { "ERRreserved", 70, "reserved." },
909 { "ERRsetattrmode", 71, "The attribute mode in the Set File Attribute request is invalid." },
910 { "ERRpaused", 81, "Server is paused." },
911 { "ERRmsgoff", 82, "Not receiving messages." },
912 { "ERRnoroom", 83, "No room to buffer message." },
913 { "ERRrmuns", 87, "Too many remote user names." },
914 { "ERRtimeout", 88, "Operation timed out." },
915 { "ERRnoresource", 89, "No resources currently available for request." },
916 { "ERRtoomanyuids", 90, "Too many UIDs active on this session." },
917 { "ERRbaduid", 91, "The UID is not known as a valid ID on this session." },
918 { "ERRusempx", 250, "Temp unable to support Raw, use MPX mode." },
919 { "ERRusestd", 251, "Temp unable to support Raw, use standard read/write." },
920 { "ERRcontmpx", 252, "Continue in MPX mode." },
921 { "ERRreserved", 253, "reserved." },
922 { "ERRreserved", 254, "reserved." },
923 { "ERRnosupport", 0xFFFF, "Function not supported." },
927 /* Hard Error Messages */
928 err_code_struct hard_msgs
[] = {
929 { "ERRnowrite", 19, "Attempt to write on write-protected diskette." },
930 { "ERRbadunit", 20, "Unknown unit." },
931 { "ERRnotready", 21, "Drive not ready." },
932 { "ERRbadcmd", 22, "Unknown command." },
933 { "ERRdata", 23, "Data error (CRC)." },
934 { "ERRbadreq", 24, "Bad request structure length." },
935 { "ERRseek", 25 , "Seek error." },
936 { "ERRbadmedia", 26, "Unknown media type." },
937 { "ERRbadsector", 27, "Sector not found." },
938 { "ERRnopaper", 28, "Printer out of paper." },
939 { "ERRwrite", 29, "Write fault." },
940 { "ERRread", 30, "Read fault." },
941 { "ERRgeneral", 31, "General failure." },
942 { "ERRbadshare", 32, "A open conflicts with an existing open." },
943 { "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." },
944 { "ERRwrongdisk", 34, "The wrong disk was found in a drive." },
945 { "ERRFCBUnavail", 35, "No FCBs are available to process request." },
946 { "ERRsharebufexc", 36, "A sharing buffer has been exceeded." },
953 err_code_struct
*err_msgs
;
955 { 0, "SUCCESS", NULL
},
956 { 0x01, "ERRDOS", dos_msgs
},
957 { 0x02, "ERRSRV", server_msgs
},
958 { 0x03, "ERRHRD", hard_msgs
},
959 { 0x04, "ERRXOS", NULL
},
960 { 0xE1, "ERRRMX1", NULL
},
961 { 0xE2, "ERRRMX2", NULL
},
962 { 0xE3, "ERRRMX3", NULL
},
963 { 0xFF, "ERRCMD", NULL
},
968 * return a SMB error string from a SMB buffer
971 smb_errstr(int class, int num
)
973 static char ret
[128];
978 for (i
= 0; err_classes
[i
].class; i
++)
979 if (err_classes
[i
].code
== class) {
980 if (err_classes
[i
].err_msgs
) {
981 err_code_struct
*err
= err_classes
[i
].err_msgs
;
982 for (j
= 0; err
[j
].name
; j
++)
983 if (num
== err
[j
].code
) {
984 snprintf(ret
, sizeof(ret
), "%s - %s (%s)",
985 err_classes
[i
].class, err
[j
].name
, err
[j
].message
);
990 snprintf(ret
, sizeof(ret
), "%s - %d", err_classes
[i
].class, num
);
994 snprintf(ret
, sizeof(ret
), "ERROR: Unknown error (%d,%d)", class, num
);