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:
@ -166,7 +166,7 @@ int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Unicasts or broadcasts a DHCP renew message */
|
/* Unicast or broadcast a DHCP renew message */
|
||||||
int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
|
int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
|
||||||
{
|
{
|
||||||
struct dhcp_packet packet;
|
struct dhcp_packet packet;
|
||||||
@ -186,7 +186,7 @@ int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Unicasts a DHCP release message */
|
/* Unicast a DHCP release message */
|
||||||
int FAST_FUNC send_release(uint32_t server, uint32_t ciaddr)
|
int FAST_FUNC send_release(uint32_t server, uint32_t ciaddr)
|
||||||
{
|
{
|
||||||
struct dhcp_packet packet;
|
struct dhcp_packet packet;
|
||||||
|
@ -25,16 +25,9 @@
|
|||||||
*/
|
*/
|
||||||
char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
|
char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
|
||||||
{
|
{
|
||||||
const uint8_t *c;
|
char *ret = ret; /* for compiler */
|
||||||
int crtpos, retpos, depth, plen = 0, len = 0;
|
|
||||||
char *dst = NULL;
|
char *dst = NULL;
|
||||||
|
|
||||||
if (!cstr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (pre)
|
|
||||||
plen = strlen(pre);
|
|
||||||
|
|
||||||
/* We make two passes over the cstr string. First, we compute
|
/* We make two passes over the cstr string. First, we compute
|
||||||
* how long the resulting string would be. Then we allocate a
|
* how long the resulting string would be. Then we allocate a
|
||||||
* new buffer of the required length, and fill it in with the
|
* 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
|
* having to deal with requiring callers to supply their own
|
||||||
* buffer, then having to check if it's sufficiently large, etc.
|
* buffer, then having to check if it's sufficiently large, etc.
|
||||||
*/
|
*/
|
||||||
|
while (1) {
|
||||||
while (!dst) {
|
/* note: "return NULL" below are leak-safe since
|
||||||
|
* dst isn't yet allocated */
|
||||||
if (len > 0) { /* second pass? allocate dst buffer and copy pre */
|
const uint8_t *c;
|
||||||
dst = xmalloc(len + plen);
|
unsigned crtpos, retpos, depth, len;
|
||||||
memcpy(dst, pre, plen);
|
|
||||||
}
|
|
||||||
|
|
||||||
crtpos = retpos = depth = len = 0;
|
crtpos = retpos = depth = len = 0;
|
||||||
|
|
||||||
while (crtpos < clen) {
|
while (crtpos < clen) {
|
||||||
c = cstr + crtpos;
|
c = cstr + crtpos;
|
||||||
|
|
||||||
if ((*c & NS_CMPRSFLGS) != 0) { /* pointer */
|
if (*c & NS_CMPRSFLGS) {
|
||||||
if (crtpos + 2 > clen) /* no offset to jump to? abort */
|
/* pointer */
|
||||||
|
if (crtpos + 2 > clen) /* no offset to jump to? abort */
|
||||||
return NULL;
|
return NULL;
|
||||||
if (retpos == 0) /* toplevel? save return spot */
|
if (retpos == 0) /* toplevel? save return spot */
|
||||||
retpos = crtpos + 2;
|
retpos = crtpos + 2;
|
||||||
depth++;
|
depth++;
|
||||||
crtpos = ((*c & 0x3f) << 8) | (*(c + 1) & 0xff); /* jump */
|
crtpos = ((c[0] & 0x3f) << 8) | (c[1] & 0xff); /* jump */
|
||||||
} else if (*c) { /* label */
|
} else if (*c) {
|
||||||
if (crtpos + *c + 1 > clen) /* label too long? abort */
|
/* label */
|
||||||
|
if (crtpos + *c + 1 > clen) /* label too long? abort */
|
||||||
return NULL;
|
return NULL;
|
||||||
if (dst)
|
if (dst)
|
||||||
memcpy(dst + plen + len, c + 1, *c);
|
memcpy(dst + len, c + 1, *c);
|
||||||
len += *c + 1;
|
len += *c + 1;
|
||||||
crtpos += *c + 1;
|
crtpos += *c + 1;
|
||||||
if (dst)
|
if (dst)
|
||||||
*(dst + plen + len - 1) = '.';
|
dst[len - 1] = '.';
|
||||||
} else { /* null: end of current domain name */
|
} else {
|
||||||
if (retpos == 0) { /* toplevel? keep going */
|
/* null: end of current domain name */
|
||||||
|
if (retpos == 0) {
|
||||||
|
/* toplevel? keep going */
|
||||||
crtpos++;
|
crtpos++;
|
||||||
} else { /* return to toplevel saved spot */
|
} else {
|
||||||
|
/* return to toplevel saved spot */
|
||||||
crtpos = retpos;
|
crtpos = retpos;
|
||||||
retpos = depth = 0;
|
retpos = depth = 0;
|
||||||
}
|
}
|
||||||
if (dst)
|
if (dst)
|
||||||
*(dst + plen + len - 1) = ' ';
|
dst[len - 1] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth > NS_MAXDNSRCH || /* too many jumps? abort, it's a loop */
|
if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */
|
||||||
len > NS_MAXDNAME * NS_MAXDNSRCH) /* result too long? abort */
|
|| len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */
|
||||||
|
) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!len) /* expanded string has 0 length? abort */
|
if (!len) /* expanded string has 0 length? abort */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (dst)
|
if (!dst) { /* first pass? */
|
||||||
*(dst + plen + len - 1) = '\0';
|
/* 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
|
/* Convert a domain name (src) from human-readable "foo.blah.com" format into
|
||||||
|
@ -115,7 +115,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = {
|
|||||||
[OPTION_U16] = 2,
|
[OPTION_U16] = 2,
|
||||||
[OPTION_S16] = 2,
|
[OPTION_S16] = 2,
|
||||||
[OPTION_U32] = 4,
|
[OPTION_U32] = 4,
|
||||||
[OPTION_S32] = 4
|
[OPTION_S32] = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,11 +19,13 @@ enum {
|
|||||||
OPTION_U16,
|
OPTION_U16,
|
||||||
OPTION_S16,
|
OPTION_S16,
|
||||||
OPTION_U32,
|
OPTION_U32,
|
||||||
OPTION_S32
|
OPTION_S32,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPTION_REQ 0x10 /* have the client request this option */
|
/* Client requests this option by default */
|
||||||
#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
|
#define OPTION_REQ 0x10
|
||||||
|
/* There can be a list of 1 or more of these */
|
||||||
|
#define OPTION_LIST 0x20
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
/* Do not modify below here unless you know what you are doing!! */
|
/* Do not modify below here unless you know what you are doing!! */
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* get a rough idea of how long an option will be (rounding up...) */
|
/* get a rough idea of how long an option will be (rounding up...) */
|
||||||
static const uint8_t max_option_length[] = {
|
static const uint8_t len_of_option_as_string[] = {
|
||||||
[OPTION_IP] = sizeof("255.255.255.255 "),
|
[OPTION_IP] = sizeof("255.255.255.255 "),
|
||||||
[OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
|
[OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
|
||||||
[OPTION_STRING] = 1,
|
[OPTION_STRING] = 1,
|
||||||
@ -30,17 +30,10 @@ static const uint8_t max_option_length[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static inline int upper_length(int length, int opt_index)
|
|
||||||
{
|
|
||||||
return max_option_length[opt_index] *
|
|
||||||
(length / dhcp_option_lengths[opt_index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* note: ip is a pointer to an IP in network order, possibly misaliged */
|
/* note: ip is a pointer to an IP in network order, possibly misaliged */
|
||||||
static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
|
static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
|
||||||
{
|
{
|
||||||
return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);
|
return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -57,9 +50,10 @@ static int mton(uint32_t mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Allocate and fill with the text of option 'option'. */
|
/* Create "opt_name=opt_value" string */
|
||||||
static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)
|
static char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)
|
||||||
{
|
{
|
||||||
|
unsigned upper_length;
|
||||||
int len, type, optlen;
|
int len, type, optlen;
|
||||||
uint16_t val_u16;
|
uint16_t val_u16;
|
||||||
int16_t val_s16;
|
int16_t val_s16;
|
||||||
@ -67,14 +61,16 @@ static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p,
|
|||||||
int32_t val_s32;
|
int32_t val_s32;
|
||||||
char *dest, *ret;
|
char *dest, *ret;
|
||||||
|
|
||||||
len = option[OPT_LEN - 2];
|
/* option points to OPT_DATA, need to go back and get OPT_LEN */
|
||||||
|
len = option[OPT_LEN - OPT_DATA];
|
||||||
type = type_p->flags & TYPE_MASK;
|
type = type_p->flags & TYPE_MASK;
|
||||||
optlen = dhcp_option_lengths[type];
|
optlen = dhcp_option_lengths[type];
|
||||||
|
upper_length = len_of_option_as_string[type] * (len / optlen);
|
||||||
|
|
||||||
dest = ret = xmalloc(upper_length(len, type) + strlen(opt_name) + 2);
|
dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
|
||||||
dest += sprintf(ret, "%s=", opt_name);
|
dest += sprintf(ret, "%s=", opt_name);
|
||||||
|
|
||||||
for (;;) {
|
while (len >= optlen) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OPTION_IP_PAIR:
|
case OPTION_IP_PAIR:
|
||||||
dest += sprint_nip(dest, "", option);
|
dest += sprint_nip(dest, "", option);
|
||||||
@ -114,15 +110,20 @@ static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p,
|
|||||||
case OPTION_STR1035:
|
case OPTION_STR1035:
|
||||||
/* unpack option into dest; use ret for prefix (i.e., "optname=") */
|
/* unpack option into dest; use ret for prefix (i.e., "optname=") */
|
||||||
dest = dname_dec(option, len, ret);
|
dest = dname_dec(option, len, ret);
|
||||||
free(ret);
|
if (dest) {
|
||||||
return dest;
|
free(ret);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
/* error. return "optname=" string */
|
||||||
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
option += optlen;
|
option += optlen;
|
||||||
len -= optlen;
|
len -= optlen;
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
break;
|
break;
|
||||||
dest += sprintf(dest, " ");
|
*dest++ = ' ';
|
||||||
|
*dest = '\0';
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -174,7 +175,7 @@ static char **fill_envp(struct dhcp_packet *packet)
|
|||||||
temp = get_option(packet, dhcp_options[i].code);
|
temp = get_option(packet, dhcp_options[i].code);
|
||||||
if (!temp)
|
if (!temp)
|
||||||
goto next;
|
goto next;
|
||||||
*curr = alloc_fill_opts(temp, &dhcp_options[i], opt_name);
|
*curr = xmalloc_optname_optval(temp, &dhcp_options[i], opt_name);
|
||||||
putenv(*curr++);
|
putenv(*curr++);
|
||||||
|
|
||||||
/* Fill in a subnet bits option for things like /24 */
|
/* Fill in a subnet bits option for things like /24 */
|
||||||
|
Reference in New Issue
Block a user