diff options
Diffstat (limited to 'contrib/sendmail/src/sm_resolve.c')
-rw-r--r-- | contrib/sendmail/src/sm_resolve.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/contrib/sendmail/src/sm_resolve.c b/contrib/sendmail/src/sm_resolve.c index e3eb77f..a6f5862 100644 --- a/contrib/sendmail/src/sm_resolve.c +++ b/contrib/sendmail/src/sm_resolve.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -46,7 +46,7 @@ # if NAMED_BIND # include "sm_resolve.h" -SM_RCSID("$Id: sm_resolve.c,v 8.24 2001/09/11 04:05:16 gshapiro Exp $") +SM_RCSID("$Id: sm_resolve.c,v 8.24.4.6 2002/06/25 04:22:41 ca Exp $") static struct stot { @@ -180,8 +180,8 @@ parse_dns_reply(data, len) p = data; /* doesn't work on Crays? */ - memcpy(&r->dns_r_h, p, sizeof(HEADER)); - p += sizeof(HEADER); + memcpy(&r->dns_r_h, p, sizeof(r->dns_r_h)); + p += sizeof(r->dns_r_h); status = dn_expand(data, data + len, p, host, sizeof host); if (status < 0) { @@ -200,7 +200,7 @@ parse_dns_reply(data, len) rr = &r->dns_r_head; while (p < data + len) { - int type, class, ttl, size; + int type, class, ttl, size, txtlen; status = dn_expand(data, data + len, p, host, sizeof host); if (status < 0) @@ -213,7 +213,21 @@ parse_dns_reply(data, len) GETSHORT(class, p); GETLONG(ttl, p); GETSHORT(size, p); - *rr = (RESOURCE_RECORD_T *) xalloc(sizeof(RESOURCE_RECORD_T)); + if (p + size > data + len) + { + /* + ** announced size of data exceeds length of + ** data paket: someone is cheating. + */ + + if (LogLevel > 5) + sm_syslog(LOG_WARNING, NOQID, + "ERROR: DNS RDLENGTH=%d > data len=%d", + size, len - (p - data)); + dns_free_data(r); + return NULL; + } + *rr = (RESOURCE_RECORD_T *) xalloc(sizeof(**rr)); if (*rr == NULL) { dns_free_data(r); @@ -260,7 +274,7 @@ parse_dns_reply(data, len) } l = strlen(host) + 1; (*rr)->rr_u.rr_mx = (MX_RECORD_T *) - xalloc(sizeof(MX_RECORD_T) + l); + xalloc(sizeof(*((*rr)->rr_u.rr_mx)) + l); if ((*rr)->rr_u.rr_mx == NULL) { dns_free_data(r); @@ -281,7 +295,7 @@ parse_dns_reply(data, len) } l = strlen(host) + 1; (*rr)->rr_u.rr_srv = (SRV_RECORDT_T*) - xalloc(sizeof(SRV_RECORDT_T) + l); + xalloc(sizeof(*((*rr)->rr_u.rr_srv)) + l); if ((*rr)->rr_u.rr_srv == NULL) { dns_free_data(r); @@ -295,14 +309,35 @@ parse_dns_reply(data, len) break; case T_TXT: - (*rr)->rr_u.rr_txt = (char *) xalloc(size + 1); + + /* + ** The TXT record contains the length as + ** leading byte, hence the value is restricted + ** to 255, which is less than the maximum value + ** of RDLENGTH (size). Nevertheless, txtlen + ** must be less than size because the latter + ** specifies the length of the entire TXT + ** record. + */ + + txtlen = *p; + if (txtlen >= size) + { + if (LogLevel > 5) + sm_syslog(LOG_WARNING, NOQID, + "ERROR: DNS TXT record size=%d <= text len=%d", + size, txtlen); + dns_free_data(r); + return NULL; + } + (*rr)->rr_u.rr_txt = (char *) xalloc(txtlen + 1); if ((*rr)->rr_u.rr_txt == NULL) { dns_free_data(r); return NULL; } - (void) strncpy((*rr)->rr_u.rr_txt, (char*) p + 1, *p); - (*rr)->rr_u.rr_txt[*p] = 0; + (void) sm_strlcpy((*rr)->rr_u.rr_txt, (char*) p + 1, + txtlen + 1); break; default: @@ -313,6 +348,7 @@ parse_dns_reply(data, len) return NULL; } (void) memcpy((*rr)->rr_u.rr_data, p, size); + break; } p += size; rr = &(*rr)->rr_next; |