#endif
#ifndef lint
-static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/tcpdump/smbutil.c,v 1.25 2002-09-05 00:00:25 guy 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 <tcpdump-stdinc.h>
#include "extract.h"
#include "smb.h"
+static u_int32_t stringlen;
extern const u_char *startbuf;
/*
double d;
time_t ret;
- TCHECK2(p[4], 4);
-
/* this gives us seconds since jan 1st 1601 (approx) */
d = (EXTRACT_LE_32BITS(p + 4) * 256.0 + p[3]) * (1.0e-7 * (1 << 24));
ret = (time_t)d;
return(ret);
-trunc:
- return(0);
}
/*
/* XXX - this should use the same code that the DNS dissector does */
if ((c & 0xC0) == 0xC0) {
- u_int16_t l = EXTRACT_16BITS(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);
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 */
}
/* convert a UCS2 string into iso-8859-1 string */
+#define MAX_UNISTR_SIZE 1000
static const char *
-unistr(const u_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((const char *)s) + 1;
- return (const char *)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 < (int)(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;
const char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|";
while (*fmt && buf<maxbuf) {
switch (*fmt) {
case 'a':
+ TCHECK(buf[0]);
write_bits(buf[0], attrib_fmt);
buf++;
fmt++;
break;
case 'A':
+ TCHECK2(buf[0], 2);
write_bits(EXTRACT_LE_16BITS(buf), attrib_fmt);
buf += 2;
fmt++;
p = strchr(++fmt, '}');
l = PTR_DIFF(p, fmt);
+
+ if ((unsigned int)l > sizeof(bitfmt) - 1)
+ l = sizeof(bitfmt)-1;
+
strncpy(bitfmt, fmt, l);
- bitfmt[l] = 0;
+ bitfmt[l] = '\0';
fmt = p + 1;
+ TCHECK(buf[0]);
write_bits(buf[0], bitfmt);
buf++;
break;
case 'P':
{
int l = atoi(fmt + 1);
+ TCHECK2(buf[0], l);
buf += l;
fmt++;
while (isdigit((unsigned char)*fmt))
reverse = !reverse;
fmt++;
break;
- case 'D':
+ case 'b':
{
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++;
- break;
- }
- case 'L':
- {
- unsigned int x1, x2;
-
- TCHECK2(buf[4], 4);
- x1 = reverse ? EXTRACT_32BITS(buf) :
- EXTRACT_LE_32BITS(buf);
- x2 = reverse ? EXTRACT_32BITS(buf + 4) :
- EXTRACT_LE_32BITS(buf + 4);
- if (x2)
- printf("0x%08x:%08x", x2, x1);
- else
- printf("%d (0x%08x%08x)", x1, x2, x1);
- buf += 8;
+ TCHECK(buf[0]);
+ x = buf[0];
+ printf("%u (0x%x)", x, x);
+ buf += 1;
fmt++;
break;
}
fmt++;
break;
}
- case 'W':
+ case 'D':
{
unsigned int x;
TCHECK2(buf[0], 4);
x = reverse ? EXTRACT_32BITS(buf) :
EXTRACT_LE_32BITS(buf);
- printf("0x%X", x);
+ printf("%d (0x%x)", x, x);
buf += 4;
fmt++;
break;
}
+ case 'L':
+ {
+ 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 'M':
+ {
+ /* 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 'B':
+ {
+ unsigned int x;
+ TCHECK(buf[0]);
+ x = buf[0];
+ printf("0x%X", x);
+ buf += 1;
+ fmt++;
+ break;
+ }
case 'w':
{
unsigned int x;
fmt++;
break;
}
- case 'B':
+ case 'W':
{
unsigned int x;
- TCHECK(buf[0]);
- x = buf[0];
+ 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;
- TCHECK(buf[0]);
- x = 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 */
{
/*XXX unistr() */
- printf("%.*s", (int)PTR_DIFF(maxbuf, buf), unistr(buf, &len));
+ 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;
case 's':
{
int l = atoi(fmt + 1);
+ TCHECK2(*buf, l);
printf("%-*.*s", l, l, buf);
buf += l;
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++;
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));
struct tm *lt;
const char *tstring;
u_int32_t x;
- x = EXTRACT_LE_32BITS(buf);
switch (atoi(fmt + 1)) {
case 1:
+ TCHECK2(buf[0], 4);
+ x = EXTRACT_LE_32BITS(buf);
if (x == 0 || x == 0xFFFFFFFF)
t = 0;
else
buf += 4;
break;
case 2:
+ TCHECK2(buf[0], 4);
+ x = EXTRACT_LE_32BITS(buf);
if (x == 0 || x == 0xFFFFFFFF)
t = 0;
else
buf += 4;
break;
case 3:
+ TCHECK2(buf[0], 8);
t = interpret_long_date(buf);
buf += 8;
break;
}
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];
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);
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;
{ "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." },
{ "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." },
{ "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." },
{ "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." },