diff options
Diffstat (limited to 'crypto/heimdal/lib/roken/resolve.c')
-rw-r--r-- | crypto/heimdal/lib/roken/resolve.c | 82 |
1 files changed, 65 insertions, 17 deletions
diff --git a/crypto/heimdal/lib/roken/resolve.c b/crypto/heimdal/lib/roken/resolve.c index eddaa7d..f17ae4c 100644 --- a/crypto/heimdal/lib/roken/resolve.c +++ b/crypto/heimdal/lib/roken/resolve.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan + * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -45,7 +45,7 @@ #include <assert.h> -RCSID("$Id: resolve.c,v 1.30 2001/10/02 15:39:41 joda Exp $"); +RCSID("$Id: resolve.c,v 1.33 2002/08/28 20:07:24 joda Exp $"); #if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) @@ -113,10 +113,10 @@ dns_free_data(struct dns_reply *r) static struct dns_reply* parse_reply(unsigned char *data, int len) { - unsigned char *p; + const unsigned char *p; char host[128]; int status; - + const unsigned char *end_data = data + len; struct dns_reply *r; struct resource_record **rr; @@ -133,7 +133,7 @@ parse_reply(unsigned char *data, int len) memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */ p += 12; #endif - status = dn_expand(data, data + len, p, host, sizeof(host)); + status = dn_expand(data, end_data, p, host, sizeof(host)); if(status < 0){ dns_free_data(r); return NULL; @@ -143,19 +143,27 @@ parse_reply(unsigned char *data, int len) dns_free_data(r); return NULL; } + if (p + status + 4 > end_data) { + dns_free_data(r); + return NULL; + } p += status; r->q.type = (p[0] << 8 | p[1]); p += 2; r->q.class = (p[0] << 8 | p[1]); p += 2; rr = &r->head; - while(p < data + len){ + while(p < end_data){ int type, class, ttl, size; - status = dn_expand(data, data + len, p, host, sizeof(host)); + status = dn_expand(data, end_data, p, host, sizeof(host)); if(status < 0){ dns_free_data(r); return NULL; } + if (p + status + 10 > end_data) { + dns_free_data(r); + return NULL; + } p += status; type = (p[0] << 8) | p[1]; p += 2; @@ -165,6 +173,12 @@ parse_reply(unsigned char *data, int len) p += 4; size = (p[0] << 8) | p[1]; p += 2; + + if (p + size > end_data) { + dns_free_data(r); + return NULL; + } + *rr = (struct resource_record*)calloc(1, sizeof(struct resource_record)); if(*rr == NULL) { @@ -184,7 +198,7 @@ parse_reply(unsigned char *data, int len) case T_NS: case T_CNAME: case T_PTR: - status = dn_expand(data, data + len, p, host, sizeof(host)); + status = dn_expand(data, end_data, p, host, sizeof(host)); if(status < 0){ dns_free_data(r); return NULL; @@ -197,11 +211,16 @@ parse_reply(unsigned char *data, int len) break; case T_MX: case T_AFSDB:{ - status = dn_expand(data, data + len, p + 2, host, sizeof(host)); + status = dn_expand(data, end_data, p + 2, host, sizeof(host)); if(status < 0){ dns_free_data(r); return NULL; } + if (status + 2 > size) { + dns_free_data(r); + return NULL; + } + (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + strlen(host)); if((*rr)->u.mx == NULL) { @@ -213,11 +232,16 @@ parse_reply(unsigned char *data, int len) break; } case T_SRV:{ - status = dn_expand(data, data + len, p + 6, host, sizeof(host)); + status = dn_expand(data, end_data, p + 6, host, sizeof(host)); if(status < 0){ dns_free_data(r); return NULL; } + if (status + 6 > size) { + dns_free_data(r); + return NULL; + } + (*rr)->u.srv = (struct srv_record*)malloc(sizeof(struct srv_record) + strlen(host)); @@ -244,6 +268,11 @@ parse_reply(unsigned char *data, int len) case T_KEY : { size_t key_len; + if (size < 4) { + dns_free_data (r); + return NULL; + } + key_len = size - 4; (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1); if ((*rr)->u.key == NULL) { @@ -261,11 +290,16 @@ parse_reply(unsigned char *data, int len) case T_SIG : { size_t sig_len; - status = dn_expand (data, data + len, p + 18, host, sizeof(host)); + status = dn_expand (data, end_data, p + 18, host, sizeof(host)); if (status < 0) { dns_free_data (r); return NULL; } + if (status + 18 > size) { + dns_free_data(r); + return NULL; + } + sig_len = len - 18 - status; (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig) + strlen(host) + sig_len); @@ -293,6 +327,11 @@ parse_reply(unsigned char *data, int len) case T_CERT : { size_t cert_len; + if (size < 5) { + dns_free_data(r); + return NULL; + } + cert_len = size - 5; (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1); if ((*rr)->u.cert == NULL) { @@ -327,24 +366,32 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type) { unsigned char reply[1024]; int len; - struct dns_reply *r = NULL; +#ifdef HAVE__RES u_long old_options = 0; +#endif if (_resolve_debug) { +#ifdef HAVE__RES old_options = _res.options; _res.options |= RES_DEBUG; +#endif fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain, rr_class, dns_type_to_string(rr_type)); } len = res_search(domain, rr_class, rr_type, reply, sizeof(reply)); if (_resolve_debug) { +#ifdef HAVE__RES _res.options = old_options; +#endif fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", domain, rr_class, dns_type_to_string(rr_type), len); } - if (len >= 0) - r = parse_reply(reply, len); - return r; + if(len < 0) { + return NULL; + } else { + len = min(len, sizeof(reply)); + return parse_reply(reply, len); + } } struct dns_reply * @@ -385,7 +432,8 @@ dns_srv_order(struct dns_reply *r) int num_srv = 0; #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) - char state[256], *oldstate; + int state[256 / sizeof(int)]; + char *oldstate; #endif for(rr = r->head; rr; rr = rr->next) @@ -414,7 +462,7 @@ dns_srv_order(struct dns_reply *r) qsort(srvs, num_srv, sizeof(*srvs), compare_srv); #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) - oldstate = initstate(time(NULL), state, sizeof(state)); + oldstate = initstate(time(NULL), (char*)state, sizeof(state)); #endif headp = &r->head; |