X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/c672f002763b3a4fc30ca229e57f50d3b2e6d766..ae05d24b8704024d2331d03475a9e6a213b19c69:/smbutil.c diff --git a/smbutil.c b/smbutil.c index 69744423..d3020085 100644 --- a/smbutil.c +++ b/smbutil.c @@ -11,26 +11,21 @@ #endif #ifndef lint -static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/smbutil.c,v 1.17 2001-09-17 21:58:05 fenner Exp $"; +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/tcpdump/smbutil.c,v 1.34 2004-12-29 05:27:27 guy Exp $"; #endif -#include -#include -#include -#include +#include -#include - -#include #include #include #include -#include #include "interface.h" +#include "extract.h" #include "smb.h" +static u_int32_t stringlen; extern const u_char *startbuf; /* @@ -55,16 +50,14 @@ interpret_dos_date(u_int32_t date, struct tm *tp) } /* + * common portion: * create a unix date from a dos date */ static time_t -make_unix_date(const u_char *date_ptr) +int_unix_date(u_int32_t dos_date) { - u_int32_t dos_date = 0; struct tm t; - dos_date = IVAL(date_ptr, 0); - if (dos_date == 0) return(0); @@ -78,17 +71,30 @@ make_unix_date(const u_char *date_ptr) /* * create a unix date from a dos date + * in network byte order + */ +static time_t +make_unix_date(const u_char *date_ptr) +{ + u_int32_t dos_date = 0; + + dos_date = EXTRACT_LE_32BITS(date_ptr); + + return int_unix_date(dos_date); +} + +/* + * create a unix date from a dos date + * in halfword-swapped network byte order! */ static time_t make_unix_date2(const u_char *date_ptr) { u_int32_t x, x2; - x = IVAL(date_ptr, 0); + x = EXTRACT_LE_32BITS(date_ptr); x2 = ((x & 0xFFFF) << 16) | ((x & 0xFFFF0000) >> 16); - SIVAL(&x, 0, x2); - - return(make_unix_date((void *)&x)); + return int_unix_date(x2); } /* @@ -96,13 +102,13 @@ make_unix_date2(const u_char *date_ptr) * It's originally in "100ns units since jan 1st 1601" */ static time_t -interpret_long_date(const char *p) +interpret_long_date(const u_char *p) { double d; time_t ret; /* this gives us seconds since jan 1st 1601 (approx) */ - d = (IVAL(p, 4) * 256.0 + CVAL(p, 3)) * (1.0e-7 * (1 << 24)); + d = (EXTRACT_LE_32BITS(p + 4) * 256.0 + p[3]) * (1.0e-7 * (1 << 24)); /* now adjust by 369 years to make the secs since 1970 */ d -= 369.0 * 365.25 * 24 * 60 * 60; @@ -139,9 +145,9 @@ name_interpret(const u_char *in, const u_char *maxbuf, char *out) return(0); while (len--) { + TCHECK2(*in, 2); if (in + 1 >= maxbuf) return(-1); /* name goes past the end of the buffer */ - TCHECK2(*in, 2); if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { *out = 0; return(0); @@ -177,7 +183,12 @@ name_ptr(const u_char *buf, int ofs, const u_char *maxbuf) /* XXX - this should use the same code that the DNS dissector does */ if ((c & 0xC0) == 0xC0) { - u_int16_t l = RSVAL(buf, ofs) & 0x3FFF; + u_int16_t l; + + TCHECK2(*p, 2); + if ((p + 1) >= maxbuf) + return(NULL); /* name goes past the end of the buffer */ + l = EXTRACT_16BITS(p) & 0x3FFF; if (l == 0) { /* We have a pointer that points to itself. */ return(NULL); @@ -186,9 +197,8 @@ name_ptr(const u_char *buf, int ofs, const u_char *maxbuf) if (p >= maxbuf) return(NULL); /* name goes past the end of the buffer */ TCHECK2(*p, 1); - return(buf + l); - } else - return(buf + ofs); + } + return(p); trunc: return(NULL); /* name goes past the end of the buffer */ @@ -243,10 +253,10 @@ print_asc(const unsigned char *buf, int len) safeputchar(buf[i]); } -static char * +static const char * name_type_str(int name_type) { - char *f = NULL; + const char *f = NULL; switch (name_type) { case 0: f = "Workstation"; break; @@ -292,7 +302,7 @@ print_data(const unsigned char *buf, int len) while (n--) printf(" "); - n = MIN(8, i % 16); + n = SMBMIN(8, i % 16); print_asc(&buf[i - (i % 16)], n); printf(" "); n = (i % 16) - n; @@ -304,9 +314,9 @@ print_data(const unsigned char *buf, int len) static void -write_bits(unsigned int val, char *fmt) +write_bits(unsigned int val, const char *fmt) { - char *p = fmt; + const char *p = fmt; int i = 0; while ((p = strchr(fmt, '|'))) { @@ -319,62 +329,119 @@ write_bits(unsigned int val, char *fmt) } /* convert a UCS2 string into iso-8859-1 string */ +#define MAX_UNISTR_SIZE 1000 static const char * -unistr(const char *s, int *len) +unistr(const u_char *s, u_int32_t *len, int use_unicode) { - static char buf[1000]; - int l=0; - static int use_unicode = -1; - - if (use_unicode == -1) { - char *p = getenv("USE_UNICODE"); - if (p && (atoi(p) == 1)) - use_unicode = 1; - else - use_unicode = 0; - } - - /* maybe it isn't unicode - a cheap trick */ - if (!use_unicode || (s[0] && s[1])) { - *len = strlen(s) + 1; - return s; + static char buf[MAX_UNISTR_SIZE+1]; + size_t l = 0; + u_int32_t strsize; + const u_char *sp; + + if (use_unicode) { + /* + * Skip padding that puts the string on an even boundary. + */ + if (((s - startbuf) % 2) != 0) { + TCHECK(s[0]); + s++; + } } - - *len = 0; - - if (s[0] == 0 && s[1] != 0) { - s++; - *len = 1; + if (*len == 0) { + /* + * Null-terminated string. + */ + strsize = 0; + sp = s; + if (!use_unicode) { + for (;;) { + TCHECK(sp[0]); + *len += 1; + if (sp[0] == 0) + break; + sp++; + } + strsize = *len - 1; + } else { + for (;;) { + TCHECK2(sp[0], 2); + *len += 2; + if (sp[0] == 0 && sp[1] == 0) + break; + sp += 2; + } + strsize = *len - 2; + } + } else { + /* + * Counted string. + */ + strsize = *len; } - - while (l < (sizeof(buf) - 1) && s[0] && s[1] == 0) { - buf[l] = s[0]; - s += 2; - l++; - *len += 2; + if (!use_unicode) { + while (strsize != 0) { + TCHECK(s[0]); + if (l >= MAX_UNISTR_SIZE) + break; + if (isprint(s[0])) + buf[l] = s[0]; + else { + if (s[0] == 0) + break; + buf[l] = '.'; + } + l++; + s++; + strsize--; + } + } else { + while (strsize != 0) { + TCHECK2(s[0], 2); + if (l >= MAX_UNISTR_SIZE) + break; + if (s[1] == 0 && isprint(s[0])) { + /* It's a printable ASCII character */ + buf[l] = s[0]; + } else { + /* It's a non-ASCII character or a non-printable ASCII character */ + if (s[0] == 0 && s[1] == 0) + break; + buf[l] = '.'; + } + l++; + s += 2; + if (strsize == 1) + break; + strsize -= 2; + } } buf[l] = 0; - *len += 2; return buf; + +trunc: + return NULL; } static const u_char * -smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) +smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf, + int unicodestr) { int reverse = 0; - char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|"; + const char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|"; int len; while (*fmt && buf sizeof(bitfmt) - 1) + l = sizeof(bitfmt)-1; + strncpy(bitfmt, fmt, l); - bitfmt[l] = 0; + bitfmt[l] = '\0'; fmt = p + 1; - write_bits(CVAL(buf, 0), bitfmt); + TCHECK(buf[0]); + write_bits(buf[0], bitfmt); buf++; break; } @@ -395,9 +470,10 @@ smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) case 'P': { int l = atoi(fmt + 1); + TCHECK2(buf[0], l); buf += l; fmt++; - while (isdigit(*fmt)) + while (isdigit((unsigned char)*fmt)) fmt++; break; } @@ -405,9 +481,33 @@ smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) reverse = !reverse; fmt++; break; + case 'b': + { + unsigned int x; + TCHECK(buf[0]); + x = buf[0]; + printf("%u (0x%x)", x, x); + buf += 1; + fmt++; + break; + } + case 'd': + { + unsigned int x; + TCHECK2(buf[0], 2); + x = reverse ? EXTRACT_16BITS(buf) : + EXTRACT_LE_16BITS(buf); + printf("%d (0x%x)", x, x); + buf += 2; + fmt++; + break; + } case 'D': { - unsigned int x = reverse ? RIVAL(buf, 0) : IVAL(buf, 0); + unsigned int x; + TCHECK2(buf[0], 4); + x = reverse ? EXTRACT_32BITS(buf) : + EXTRACT_LE_32BITS(buf); printf("%d (0x%x)", x, x); buf += 4; fmt++; @@ -415,70 +515,122 @@ smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) } case 'L': { - unsigned int x1 = reverse ? RIVAL(buf, 0) : IVAL(buf, 0); - unsigned int x2 = reverse ? RIVAL(buf, 4) : IVAL(buf, 4); - if (x2) - printf("0x%08x:%08x", x2, x1); - else - printf("%d (0x%08x%08x)", x1, x2, x1); + u_int64_t x; + TCHECK2(buf[0], 8); + x = reverse ? EXTRACT_64BITS(buf) : + EXTRACT_LE_64BITS(buf); + printf("%" PRIu64 " (0x%" PRIx64 ")", x, x); buf += 8; fmt++; break; } - case 'd': + case 'M': { - unsigned int x = reverse ? RSVAL(buf, 0) : SVAL(buf, 0); - printf("%d (0x%x)", x, x); - buf += 2; + /* Weird mixed-endian length values in 64-bit locks */ + u_int32_t x1, x2; + u_int64_t x; + TCHECK2(buf[0], 8); + x1 = reverse ? EXTRACT_32BITS(buf) : + EXTRACT_LE_32BITS(buf); + x2 = reverse ? EXTRACT_32BITS(buf + 4) : + EXTRACT_LE_32BITS(buf + 4); + x = (((u_int64_t)x1) << 32) | x2; + printf("%" PRIu64 " (0x%" PRIx64 ")", x, x); + buf += 8; fmt++; break; } - case 'W': + case 'B': { - unsigned int x = reverse ? RIVAL(buf, 0) : IVAL(buf, 0); + unsigned int x; + TCHECK(buf[0]); + x = buf[0]; printf("0x%X", x); - buf += 4; + buf += 1; fmt++; break; } case 'w': { - unsigned int x = reverse ? RSVAL(buf, 0) : SVAL(buf, 0); + unsigned int x; + TCHECK2(buf[0], 2); + x = reverse ? EXTRACT_16BITS(buf) : + EXTRACT_LE_16BITS(buf); printf("0x%X", x); buf += 2; fmt++; break; } - case 'B': + case 'W': { - unsigned int x = CVAL(buf,0); + unsigned int x; + TCHECK2(buf[0], 4); + x = reverse ? EXTRACT_32BITS(buf) : + EXTRACT_LE_32BITS(buf); printf("0x%X", x); - buf += 1; + buf += 4; fmt++; break; } - case 'b': + case 'l': { - unsigned int x = CVAL(buf, 0); - printf("%u (0x%x)", x, x); - buf += 1; + fmt++; + switch (*fmt) { + + case 'b': + TCHECK(buf[0]); + stringlen = buf[0]; + printf("%u", stringlen); + buf += 1; + break; + + case 'd': + TCHECK2(buf[0], 2); + stringlen = reverse ? EXTRACT_16BITS(buf) : + EXTRACT_LE_16BITS(buf); + printf("%u", stringlen); + buf += 2; + break; + + case 'D': + TCHECK2(buf[0], 4); + stringlen = reverse ? EXTRACT_32BITS(buf) : + EXTRACT_LE_32BITS(buf); + printf("%u", stringlen); + buf += 4; + break; + } fmt++; break; } case 'S': + case 'R': /* like 'S', but always ASCII */ { - printf("%.*s", (int)PTR_DIFF(maxbuf, buf), unistr(buf, &len)); + /*XXX unistr() */ + const char *s; + len = 0; + s = unistr(buf, &len, (*fmt == 'R') ? 0 : unicodestr); + if (s == NULL) + goto trunc; + printf("%s", s); buf += len; fmt++; break; } case 'Z': + case 'Y': /* like 'Z', but always ASCII */ { - if (*buf != 4 && *buf != 2) - printf("Error! ASCIIZ buffer of type %u (safety=%lu)\n", *buf, - (unsigned long)PTR_DIFF(maxbuf, buf)); - printf("%.*s", (int)PTR_DIFF(maxbuf, buf + 1), - unistr(buf + 1, &len)); + const char *s; + TCHECK(*buf); + if (*buf != 4 && *buf != 2) { + printf("Error! ASCIIZ buffer of type %u", *buf); + return maxbuf; /* give up */ + } + len = 0; + s = unistr(buf + 1, &len, (*fmt == 'Y') ? 0 : unicodestr); + if (s == NULL) + goto trunc; + printf("%s", s); buf += len + 1; fmt++; break; @@ -486,20 +638,43 @@ smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) case 's': { int l = atoi(fmt + 1); + TCHECK2(*buf, l); printf("%-*.*s", l, l, buf); buf += l; fmt++; - while (isdigit(*fmt)) + while (isdigit((unsigned char)*fmt)) fmt++; break; } + case 'c': + { + TCHECK2(*buf, stringlen); + printf("%-*.*s", stringlen, stringlen, buf); + buf += stringlen; + fmt++; + while (isdigit((unsigned char)*fmt)) + fmt++; + break; + } + case 'C': + { + const char *s; + s = unistr(buf, &stringlen, unicodestr); + if (s == NULL) + goto trunc; + printf("%s", s); + buf += stringlen; + fmt++; + break; + } case 'h': { int l = atoi(fmt + 1); + TCHECK2(*buf, l); while (l--) printf("%02x", *buf++); fmt++; - while (isdigit(*fmt)) + while (isdigit((unsigned char)*fmt)) fmt++; break; } @@ -524,6 +699,7 @@ smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) name_type_str(name_type)); break; case 2: + TCHECK(buf[15]); name_type = buf[15]; printf("%-15.15s NameType=0x%02X (%s)", buf, name_type, name_type_str(name_type)); @@ -531,38 +707,53 @@ smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf) break; } fmt++; - while (isdigit(*fmt)) + while (isdigit((unsigned char)*fmt)) fmt++; break; } case 'T': { time_t t; - int x = IVAL(buf,0); + struct tm *lt; + const char *tstring; + u_int32_t x; switch (atoi(fmt + 1)) { case 1: - if (x == 0 || x == -1 || x == 0xFFFFFFFF) + TCHECK2(buf[0], 4); + x = EXTRACT_LE_32BITS(buf); + if (x == 0 || x == 0xFFFFFFFF) t = 0; else t = make_unix_date(buf); buf += 4; break; case 2: - if (x == 0 || x == -1 || x == 0xFFFFFFFF) + TCHECK2(buf[0], 4); + x = EXTRACT_LE_32BITS(buf); + if (x == 0 || x == 0xFFFFFFFF) t = 0; else t = make_unix_date2(buf); buf += 4; break; case 3: + TCHECK2(buf[0], 8); t = interpret_long_date(buf); buf += 8; break; } - printf("%s", t ? asctime(localtime(&t)) : "NULL\n"); + if (t != 0) { + lt = localtime(&t); + if (lt != NULL) + tstring = asctime(lt); + else + tstring = "(Can't convert time)\n"; + } else + tstring = "NULL\n"; + printf("%s", tstring); fmt++; - while (isdigit(*fmt)) + while (isdigit((unsigned char)*fmt)) fmt++; break; } @@ -585,7 +776,8 @@ trunc: } const u_char * -smb_fdata(const u_char *buf, const char *fmt, const u_char *maxbuf) +smb_fdata(const u_char *buf, const char *fmt, const u_char *maxbuf, + int unicodestr) { static int depth = 0; char s[128]; @@ -598,13 +790,15 @@ smb_fdata(const u_char *buf, const char *fmt, const u_char *maxbuf) while (buf < maxbuf) { const u_char *buf2; depth++; - buf2 = smb_fdata(buf, fmt, maxbuf); + buf2 = smb_fdata(buf, fmt, maxbuf, unicodestr); depth--; + if (buf2 == NULL) + return(NULL); if (buf2 == buf) return(buf); buf = buf2; } - break; + return(buf); case '|': fmt++; @@ -628,14 +822,14 @@ smb_fdata(const u_char *buf, const char *fmt, const u_char *maxbuf) return(buf); memset(s, 0, sizeof(s)); p = strchr(fmt, ']'); - if (p - fmt + 1 > sizeof(s)) { + if ((size_t)(p - fmt + 1) > sizeof(s)) { /* overrun */ return(buf); } strncpy(s, fmt, p - fmt); s[p - fmt] = '\0'; fmt = p + 1; - buf = smb_fdata1(buf, s, maxbuf); + buf = smb_fdata1(buf, s, maxbuf, unicodestr); if (buf == NULL) return(NULL); break; @@ -679,12 +873,12 @@ static err_code_struct dos_msgs[] = { { "ERRbaddata", 13, "Invalid data." }, { "ERR", 14, "reserved." }, { "ERRbaddrive", 15, "Invalid drive specified." }, - { "ERRremcd", 16, "A Delete Directory request attempted to remove the server's current directory." }, + { "ERRremcd", 16, "A Delete Directory request attempted to remove the server's current directory." }, { "ERRdiffdevice", 17, "Not same device." }, { "ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria." }, - { "ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing FIDs on the file." }, - { "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." }, - { "ERRfilexists", 80, "The file named in a Create Directory, Make New File or Link request already exists." }, + { "ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing FIDs on the file." }, + { "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." }, + { "ERRfilexists", 80, "The file named in a Create Directory, Make New File or Link request already exists." }, { "ERRbadpipe", 230, "Pipe invalid." }, { "ERRpipebusy", 231, "All instances of the requested pipe are busy." }, { "ERRpipeclosing", 232, "Pipe close in progress." }, @@ -698,17 +892,17 @@ err_code_struct server_msgs[] = { { "ERRerror", 1, "Non-specific error code." }, { "ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid." }, { "ERRbadtype", 3, "reserved." }, - { "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." }, + { "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." }, { "ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid." }, { "ERRinvnetname", 6, "Invalid network name in tree connect." }, - { "ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection." }, + { "ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection." }, { "ERRqfull", 49, "Print queue full (files) -- returned by open print file." }, { "ERRqtoobig", 50, "Print queue full -- no space." }, { "ERRqeof", 51, "EOF on print queue dump." }, { "ERRinvpfid", 52, "Invalid print file FID." }, { "ERRsmbcmd", 64, "The server did not recognize the command received." }, - { "ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable." }, - { "ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid combination of values." }, + { "ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable." }, + { "ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid combination of values." }, { "ERRreserved", 68, "reserved." }, { "ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute." }, { "ERRreserved", 70, "reserved." }, @@ -721,8 +915,8 @@ err_code_struct server_msgs[] = { { "ERRnoresource", 89, "No resources currently available for request." }, { "ERRtoomanyuids", 90, "Too many UIDs active on this session." }, { "ERRbaduid", 91, "The UID is not known as a valid ID on this session." }, - { "ERRusempx", 250, "Temp unable to support Raw, use MPX mode." }, - { "ERRusestd", 251, "Temp unable to support Raw, use standard read/write." }, + { "ERRusempx", 250, "Temp unable to support Raw, use MPX mode." }, + { "ERRusestd", 251, "Temp unable to support Raw, use standard read/write." }, { "ERRcontmpx", 252, "Continue in MPX mode." }, { "ERRreserved", 253, "reserved." }, { "ERRreserved", 254, "reserved." }, @@ -746,7 +940,7 @@ err_code_struct hard_msgs[] = { { "ERRread", 30, "Read fault." }, { "ERRgeneral", 31, "General failure." }, { "ERRbadshare", 32, "A open conflicts with an existing open." }, - { "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." }, + { "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." }, { "ERRwrongdisk", 34, "The wrong disk was found in a drive." }, { "ERRFCBUnavail", 35, "No FCBs are available to process request." }, { "ERRsharebufexc", 36, "A sharing buffer has been exceeded." }, @@ -755,7 +949,7 @@ err_code_struct hard_msgs[] = { static struct { int code; - char *class; + const char *class; err_code_struct *err_msgs; } err_classes[] = { { 0, "SUCCESS", NULL },