udhcp: dname_dec may return NULL, account for that case

Other random cleanips included...

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko
2009-07-03 16:59:59 +02:00
parent c3b6f2c7e1
commit 7895b91743
5 changed files with 66 additions and 58 deletions

View File

@@ -25,16 +25,9 @@
*/
char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
{
const uint8_t *c;
int crtpos, retpos, depth, plen = 0, len = 0;
char *ret = ret; /* for compiler */
char *dst = NULL;
if (!cstr)
return NULL;
if (pre)
plen = strlen(pre);
/* We make two passes over the cstr string. First, we compute
* how long the resulting string would be. Then we allocate a
* new buffer of the required length, and fill it in with the
@@ -42,59 +35,71 @@ char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
* having to deal with requiring callers to supply their own
* buffer, then having to check if it's sufficiently large, etc.
*/
while (!dst) {
if (len > 0) { /* second pass? allocate dst buffer and copy pre */
dst = xmalloc(len + plen);
memcpy(dst, pre, plen);
}
while (1) {
/* note: "return NULL" below are leak-safe since
* dst isn't yet allocated */
const uint8_t *c;
unsigned crtpos, retpos, depth, len;
crtpos = retpos = depth = len = 0;
while (crtpos < clen) {
c = cstr + crtpos;
if ((*c & NS_CMPRSFLGS) != 0) { /* pointer */
if (crtpos + 2 > clen) /* no offset to jump to? abort */
if (*c & NS_CMPRSFLGS) {
/* pointer */
if (crtpos + 2 > clen) /* no offset to jump to? abort */
return NULL;
if (retpos == 0) /* toplevel? save return spot */
if (retpos == 0) /* toplevel? save return spot */
retpos = crtpos + 2;
depth++;
crtpos = ((*c & 0x3f) << 8) | (*(c + 1) & 0xff); /* jump */
} else if (*c) { /* label */
if (crtpos + *c + 1 > clen) /* label too long? abort */
crtpos = ((c[0] & 0x3f) << 8) | (c[1] & 0xff); /* jump */
} else if (*c) {
/* label */
if (crtpos + *c + 1 > clen) /* label too long? abort */
return NULL;
if (dst)
memcpy(dst + plen + len, c + 1, *c);
memcpy(dst + len, c + 1, *c);
len += *c + 1;
crtpos += *c + 1;
if (dst)
*(dst + plen + len - 1) = '.';
} else { /* null: end of current domain name */
if (retpos == 0) { /* toplevel? keep going */
dst[len - 1] = '.';
} else {
/* null: end of current domain name */
if (retpos == 0) {
/* toplevel? keep going */
crtpos++;
} else { /* return to toplevel saved spot */
} else {
/* return to toplevel saved spot */
crtpos = retpos;
retpos = depth = 0;
}
if (dst)
*(dst + plen + len - 1) = ' ';
dst[len - 1] = ' ';
}
if (depth > NS_MAXDNSRCH || /* too many jumps? abort, it's a loop */
len > NS_MAXDNAME * NS_MAXDNSRCH) /* result too long? abort */
if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */
|| len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */
) {
return NULL;
}
}
if (!len) /* expanded string has 0 length? abort */
if (!len) /* expanded string has 0 length? abort */
return NULL;
if (dst)
*(dst + plen + len - 1) = '\0';
if (!dst) { /* first pass? */
/* allocate dst buffer and copy pre */
unsigned plen = strlen(pre);
ret = dst = xmalloc(plen + len);
memcpy(dst, pre, plen);
dst += plen;
} else {
dst[len - 1] = '\0';
break;
}
}
return dst;
return ret;
}
/* Convert a domain name (src) from human-readable "foo.blah.com" format into