#include "extract.h"
#include "smb.h"
+static int stringlen_is_set;
static uint32_t stringlen;
extern const u_char *startbuf;
+/*
+ * Reset SMB state.
+ */
+void
+smb_reset(void)
+{
+ stringlen_is_set = 0;
+ stringlen = 0;
+}
+
/*
* interpret a 32 bit dos packed date/time to some parameters
*/
s += GET_U_1(s) + 1;
ND_TCHECK_1(s);
}
- return(PTR_DIFF(s, s0) + 1);
+ return(ND_BYTES_BETWEEN(s, s0) + 1);
trunc:
return(-1); /* name goes past the end of the buffer */
u_int i = 0;
while ((p = strchr(fmt, '|'))) {
- size_t l = PTR_DIFF(p, fmt);
+ u_int l = ND_BYTES_BETWEEN(p, fmt);
if (l && (val & (1 << i)))
ND_PRINT("%.*s ", (int)l, fmt);
fmt = p + 1;
/* convert a UCS-2 string into an ASCII string */
#define MAX_UNISTR_SIZE 1000
-static const char *
-unistr(netdissect_options *ndo,
- const u_char *s, uint32_t *len, int use_unicode)
+static const u_char *
+unistr(netdissect_options *ndo, char (*buf)[MAX_UNISTR_SIZE+1],
+ const u_char *s, uint32_t strsize, int is_null_terminated,
+ int use_unicode)
{
- static char buf[MAX_UNISTR_SIZE+1];
+ u_int c;
size_t l = 0;
- uint32_t strsize;
const u_char *sp;
if (use_unicode) {
s++;
}
}
- if (*len == 0) {
+ if (is_null_terminated) {
/*
* Null-terminated string.
+ * Find the length, counting the terminating NUL.
*/
strsize = 0;
sp = s;
if (!use_unicode) {
for (;;) {
ND_TCHECK_1(sp);
- *len += 1;
- if (GET_U_1(sp) == 0)
- break;
+ c = GET_U_1(sp);
sp++;
+ strsize++;
+ if (c == '\0')
+ break;
}
- strsize = *len - 1;
} else {
for (;;) {
ND_TCHECK_2(sp);
- *len += 2;
- if (GET_U_1(sp) == 0 && GET_U_1(sp + 1) == 0)
- break;
+ c = GET_LE_U_2(sp);
sp += 2;
+ strsize += 2;
+ if (c == '\0')
+ break;
}
- strsize = *len - 2;
}
- } else {
- /*
- * Counted string.
- */
- strsize = *len;
}
if (!use_unicode) {
while (strsize != 0) {
- ND_TCHECK_1(s);
- if (l >= MAX_UNISTR_SIZE)
- break;
- if (ND_ISPRINT(GET_U_1(s)))
- buf[l] = GET_U_1(s);
- else {
- if (GET_U_1(s) == 0)
- break;
- buf[l] = '.';
- }
- l++;
+ ND_TCHECK_1(s);
+ c = GET_U_1(s);
s++;
strsize--;
+ if (c == 0) {
+ /*
+ * Even counted strings may have embedded null
+ * terminators, so quit here, and skip past
+ * the rest of the data.
+ *
+ * Make sure, however, that the rest of the data
+ * is there, so we don't overflow the buffer when
+ * skipping past it.
+ */
+ ND_TCHECK_LEN(s, strsize);
+ s += strsize;
+ strsize = 0;
+ break;
+ }
+ if (l < MAX_UNISTR_SIZE) {
+ if (ND_ISPRINT(c)) {
+ /* It's a printable ASCII character */
+ (*buf)[l] = c;
+ } else {
+ /* It's a non-ASCII character or a non-printable ASCII character */
+ (*buf)[l] = '.';
+ }
+ l++;
+ }
}
} else {
- while (strsize != 0) {
+ while (strsize > 1) {
ND_TCHECK_2(s);
- if (l >= MAX_UNISTR_SIZE)
- break;
- if (GET_U_1(s + 1) == 0 && ND_ISPRINT(GET_U_1(s))) {
- /* It's a printable ASCII character */
- buf[l] = GET_U_1(s);
- } else {
- /* It's a non-ASCII character or a non-printable ASCII character */
- if (GET_U_1(s) == 0 && GET_U_1(s + 1) == 0)
- break;
- buf[l] = '.';
- }
- l++;
+ c = GET_LE_U_2(s);
s += 2;
- if (strsize == 1)
- break;
strsize -= 2;
+ if (c == 0) {
+ /*
+ * Even counted strings may have embedded null
+ * terminators, so quit here, and skip past
+ * the rest of the data.
+ *
+ * Make sure, however, that the rest of the data
+ * is there, so we don't overflow the buffer when
+ * skipping past it.
+ */
+ ND_TCHECK_LEN(s, strsize);
+ s += strsize;
+ strsize = 0;
+ break;
+ }
+ if (l < MAX_UNISTR_SIZE) {
+ if (ND_ISPRINT(c)) {
+ /* It's a printable ASCII character */
+ (*buf)[l] = c;
+ } else {
+ /* It's a non-ASCII character or a non-printable ASCII character */
+ (*buf)[l] = '.';
+ }
+ l++;
+ }
+ }
+ if (strsize == 1) {
+ /* We have half of a code point; skip past it */
+ ND_TCHECK_1(s);
+ s++;
}
}
- buf[l] = 0;
- return buf;
+ (*buf)[l] = 0;
+ return s;
trunc:
+ (*buf)[l] = 0;
return NULL;
}
{
int reverse = 0;
const char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|";
+ char strbuf[MAX_UNISTR_SIZE+1];
while (*fmt && buf<maxbuf) {
switch (*fmt) {
u_int l;
p = strchr(++fmt, '}');
- l = PTR_DIFF(p, fmt);
+ l = ND_BYTES_BETWEEN(p, fmt);
if (l > sizeof(bitfmt) - 1)
l = sizeof(bitfmt)-1;
case 'b':
ND_TCHECK_1(buf);
stringlen = GET_U_1(buf);
+ stringlen_is_set = 1;
ND_PRINT("%u", stringlen);
buf += 1;
break;
ND_TCHECK_2(buf);
stringlen = reverse ? GET_BE_U_2(buf) :
GET_LE_U_2(buf);
+ stringlen_is_set = 1;
ND_PRINT("%u", stringlen);
buf += 2;
break;
ND_TCHECK_4(buf);
stringlen = reverse ? GET_BE_U_4(buf) :
GET_LE_U_4(buf);
+ stringlen_is_set = 1;
ND_PRINT("%u", stringlen);
buf += 4;
break;
case 'R': /* like 'S', but always ASCII */
{
/*XXX unistr() */
- const char *s;
- uint32_t len;
-
- len = 0;
- s = unistr(ndo, buf, &len, (*fmt == 'R') ? 0 : unicodestr);
- if (s == NULL)
+ buf = unistr(ndo, &strbuf, buf, 0, 1, (*fmt == 'R') ? 0 : unicodestr);
+ ND_PRINT("%s", strbuf);
+ if (buf == NULL)
goto trunc;
- ND_PRINT("%s", s);
- buf += len;
fmt++;
break;
}
case 'Z':
case 'Y': /* like 'Z', but always ASCII */
{
- const char *s;
- uint32_t len;
-
ND_TCHECK_1(buf);
if (GET_U_1(buf) != 4 && GET_U_1(buf) != 2) {
ND_PRINT("Error! ASCIIZ buffer of type %u", GET_U_1(buf));
return maxbuf; /* give up */
}
- len = 0;
- s = unistr(ndo, buf + 1, &len, (*fmt == 'Y') ? 0 : unicodestr);
- if (s == NULL)
+ buf = unistr(ndo, &strbuf, buf + 1, 0, 1, (*fmt == 'Y') ? 0 : unicodestr);
+ ND_PRINT("%s", strbuf);
+ if (buf == NULL)
goto trunc;
- ND_PRINT("%s", s);
- buf += len + 1;
fmt++;
break;
}
}
case 'c':
{
+ if (!stringlen_is_set) {
+ ND_PRINT("{stringlen not set}");
+ goto trunc;
+ }
ND_TCHECK_LEN(buf, stringlen);
ND_PRINT("%-*.*s", (int)stringlen, (int)stringlen, buf);
buf += stringlen;
}
case 'C':
{
- const char *s;
- s = unistr(ndo, buf, &stringlen, unicodestr);
- if (s == NULL)
+ if (!stringlen_is_set) {
+ ND_PRINT("{stringlen not set}");
+ goto trunc;
+ }
+ buf = unistr(ndo, &strbuf, buf, stringlen, 0, unicodestr);
+ ND_PRINT("%s", strbuf);
+ if (buf == NULL)
goto trunc;
- ND_PRINT("%s", s);
- buf += stringlen;
fmt++;
break;
}
switch (t) {
case 1:
- name_type = name_extract(ndo, startbuf, PTR_DIFF(buf, startbuf),
+ name_type = name_extract(ndo, startbuf, ND_BYTES_BETWEEN(buf, startbuf),
maxbuf, nbuf);
if (name_type < 0)
goto trunc;
s[p - fmt] = '\0';
fmt = p + 1;
buf = smb_fdata1(ndo, buf, s, maxbuf, unicodestr);
- if (buf == NULL)
+ if (buf == NULL) {
+ /*
+ * Truncated.
+ * Is the next character a newline?
+ * If so, print it before quitting, so we don't
+ * get stuff in the middle of the line.
+ */
+ if (*fmt == '\n')
+ ND_PRINT("\n");
return(NULL);
+ }
break;
default:
}
}
if (!depth && buf < maxbuf) {
- size_t len = PTR_DIFF(maxbuf, buf);
- ND_PRINT("Data: (%lu bytes)\n", (unsigned long)len);
+ u_int len = ND_BYTES_BETWEEN(maxbuf, buf);
+ ND_PRINT("Data: (%u bytes)\n", len);
smb_data_print(ndo, buf, len);
return(buf + len);
}
const err_code_struct *err = err_classes[i].err_msgs;
for (j = 0; err[j].name; j++)
if (num == err[j].code) {
- nd_snprintf(ret, sizeof(ret), "%s - %s (%s)",
+ snprintf(ret, sizeof(ret), "%s - %s (%s)",
err_classes[i].class, err[j].name, err[j].message);
return ret;
}
}
- nd_snprintf(ret, sizeof(ret), "%s - %d", err_classes[i].class, num);
+ snprintf(ret, sizeof(ret), "%s - %d", err_classes[i].class, num);
return ret;
}
- nd_snprintf(ret, sizeof(ret), "ERROR: Unknown error (%d,%d)", class, num);
+ snprintf(ret, sizeof(ret), "ERROR: Unknown error (%d,%d)", class, num);
return(ret);
}
return nt_errors[i].name;
}
- nd_snprintf(ret, sizeof(ret), "0x%08x", err);
+ snprintf(ret, sizeof(ret), "0x%08x", err);
return ret;
}