If we quit because we see a NUL, make sure we have all the remaining
data claimed to be in the string, so that our caller doesn't add a
ridiculously large number to the current packet pointer and overflow it.
Keep processing packets even if we see more than MAX_UNISTR_SIZE
characters to print - just don't add them to the buffer - so that we
check the presence of every byte in the string.
Also, print the string even if it was truncated, *but* quit processing
after that. Print a newline if smb_fdata1() indicates a truncation and
if there's a newline in the format string after the item being printed,
so the newline is printed no matter what.
unistr(netdissect_options *ndo, char (*buf)[MAX_UNISTR_SIZE+1],
const u_char *s, uint32_t *len, int is_null_terminated, int use_unicode)
{
unistr(netdissect_options *ndo, char (*buf)[MAX_UNISTR_SIZE+1],
const u_char *s, uint32_t *len, int is_null_terminated, int use_unicode)
{
size_t l = 0;
uint32_t strsize;
const u_char *sp;
size_t l = 0;
uint32_t strsize;
const u_char *sp;
if (is_null_terminated) {
/*
* Null-terminated string.
if (is_null_terminated) {
/*
* Null-terminated string.
+ * Find the length, counting the terminating NUL.
}
if (!use_unicode) {
while (strsize != 0) {
}
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);
+ 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);
+ 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 (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++;
- if (strsize == 1)
- break;
+ 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);
+ 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 0;
trunc:
}
}
(*buf)[l] = 0;
return 0;
trunc:
{
/*XXX unistr() */
uint32_t len;
{
/*XXX unistr() */
uint32_t len;
- if (unistr(ndo, &strbuf, buf, &len, 1, (*fmt == 'R') ? 0 : unicodestr) == -1)
- goto trunc;
+ result = unistr(ndo, &strbuf, buf, &len, 1, (*fmt == 'R') ? 0 : unicodestr);
+ if (result == -1)
+ goto trunc;
buf += len;
fmt++;
break;
buf += len;
fmt++;
break;
case 'Y': /* like 'Z', but always ASCII */
{
uint32_t len;
case 'Y': /* like 'Z', but always ASCII */
{
uint32_t len;
ND_TCHECK_1(buf);
if (GET_U_1(buf) != 4 && GET_U_1(buf) != 2) {
ND_TCHECK_1(buf);
if (GET_U_1(buf) != 4 && GET_U_1(buf) != 2) {
return maxbuf; /* give up */
}
len = 0;
return maxbuf; /* give up */
}
len = 0;
- if (unistr(ndo, &strbuf, buf + 1, &len, 1, (*fmt == 'Y') ? 0 : unicodestr) == -1)
- goto trunc;
+ result = unistr(ndo, &strbuf, buf + 1, &len, 1, (*fmt == 'Y') ? 0 : unicodestr);
+ if (result == -1)
+ goto trunc;
buf += len + 1;
fmt++;
break;
buf += len + 1;
fmt++;
break;
- if (unistr(ndo, &strbuf, buf, &stringlen, 0, unicodestr) == -1)
- goto trunc;
+ int result;
+
+ result = unistr(ndo, &strbuf, buf, &stringlen, 0, unicodestr);
+ if (result == -1)
+ goto trunc;
buf += stringlen;
fmt++;
break;
buf += stringlen;
fmt++;
break;
s[p - fmt] = '\0';
fmt = p + 1;
buf = smb_fdata1(ndo, buf, s, maxbuf, unicodestr);
s[p - fmt] = '\0';
fmt = p + 1;
buf = smb_fdata1(ndo, buf, s, maxbuf, unicodestr);
+ 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");