reporting the issue.
[ISC-Bugs #19]
+- The "d" domain name option format was incorrectly handled as text
+ instead of RFC 1035 wire format. Thanks to Jay Doran at BlueCat Networks
+ for reporting this issue.
+ [Gitlab #2]
+
Changes since 4.1-ESV-R15
- Corrected dhclient command line parsing for --dad-wait-time that causes
static int pretty_text(char **, char *, const unsigned char **,
const unsigned char *, int);
+static int pretty_dname(char **, char *, const unsigned char *,
+ const unsigned char *);
static int pretty_domain(char **, char *, const unsigned char **,
const unsigned char *);
static int prepare_option_buffer(struct universe *universe, struct buffer *bp,
p = format;
while (*p != '\0') {
switch (*p++) {
- case 'd':
case 't':
return 1;
case 'X':
case 'x':
case 'D':
+ case 'd':
return 0;
case 'c':
numhunk = -2;
break;
case 'd':
- fmtbuf[l] = 't';
- /* Fall Through ! */
+ /* Should not be optional, array or compressed */
+ if ((option->format[i+1] == 'o') ||
+ (option->format[i+1] == 'a') ||
+ (option->format[i+1] == 'A') ||
+ (option->format[i+1] == 'c')) {
+ log_error("%s: Illegal use of domain name: %s",
+ option->name,
+ &(option->format[i-1]));
+ fmtbuf[l + 1] = 0;
+ }
+ k = MRns_name_len(data + len, data + hunksize);
+ if (k == -1) {
+ log_error("Invalid domain name.");
+ return "<error>";
+ }
+ hunksize += k;
+ break;
case 't':
fmtbuf[l + 1] = 0;
numhunk = -2;
}
*op = 0;
break;
+ case 'd': /* RFC1035 format name */
+ k = MRns_name_len(data + len, dp);
+ /* Already tested... */
+ if (k == -1) {
+ log_error("invalid domain name.");
+ return "<error>";
+ }
+ pretty_dname(&op, endbuf-1, dp, data + len);
+ /* pretty_dname does not add the nul */
+ *op = '\0';
+ dp += k;
+ break;
case 'D': /* RFC1035 format name list */
for( ; dp < (data + len) ; dp += k) {
unsigned char nbuff[NS_MAXCDNAME];
return count;
}
+static int
+pretty_dname(char **dst, char *dend, const unsigned char *src,
+ const unsigned char *send)
+{
+ const unsigned char *tend;
+ const unsigned char *srcp = src;
+ int count = 0;
+ int tsiz, status;
+
+ if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
+ *dst == NULL || ((*dst + 1) > dend) || (src >= send))
+ return -1;
+
+ do {
+ /* Continue loop until end of src buffer. */
+ if (srcp >= send)
+ break;
+
+ /* Consume tag size. */
+ tsiz = *srcp;
+ srcp++;
+
+ /* At root, finis. */
+ if (tsiz == 0)
+ break;
+
+ tend = srcp + tsiz;
+
+ /* If the tag exceeds the source buffer, it's illegal.
+ * This should also trap compression pointers (which should
+ * not be in these buffers).
+ */
+ if (tend > send)
+ return -1;
+
+ /* dend-1 leaves room for a trailing dot and quote. */
+ status = pretty_escape(dst, dend-1, &srcp, tend);
+
+ if ((status == -1) || ((*dst + 1) > dend))
+ return -1;
+
+ **dst = '.';
+ (*dst)++;
+ count += status + 1;
+ }
+ while(1);
+
+ return count;
+}
+
static int
pretty_domain(char **dst, char *dend, const unsigned char **src,
const unsigned char *send)
break;
case 'd': /* Domain name... */
- val = parse_host_name (cfile);
- if (!val) {
- parse_warn (cfile, "not a valid domain name.");
- skip_to_semi (cfile);
+ t = parse_domain_name(cfile);
+ if (!t) {
+ parse_warn(cfile, "not a valid domain name.");
+ skip_to_semi(cfile);
return 0;
}
- len = strlen (val);
- freeval = ISC_TRUE;
- goto make_string;
+ break;
case 't': /* Text string... */
token = next_token (&val, &len, cfile);
}
return 0;
}
- make_string:
if (!make_const_data (&t, (const unsigned char *)val,
len, 1, 1, MDL))
log_fatal ("No memory for concatenation");
return t;
}
+struct expression *
+parse_domain_name(struct parse *cfile)
+{
+ const char *val;
+ struct expression *t = NULL;
+ unsigned len;
+ int result;
+ unsigned char buf[NS_MAXCDNAME];
+
+ val = parse_host_name(cfile);
+ if (!val) {
+ return NULL;
+ }
+ result = MRns_name_pton(val, buf, sizeof(buf));
+ /* No longer need val */
+ dfree((char *)val, MDL);
+
+ /* result == 1 means the input was fully qualified.
+ * result == 0 means the input wasn't.
+ * result == -1 means bad things.
+ */
+ if (result < 0) {
+ parse_warn(cfile, "Error assembling domain name: %m");
+ return NULL;
+ }
+
+ /* Compute the used length */
+ len = 0;
+ while (buf[len] != 0) {
+ len += buf[len] + 1;
+ }
+ /* Count the last label (0). */
+ len++;
+
+ if (!make_const_data(&t, buf, len, 1, 1, MDL))
+ log_fatal("No memory for domain name object.");
+
+ return t;
+}
int parse_warn (struct parse *, const char *, ...)
__attribute__((__format__(__printf__,2,3)));
struct expression *parse_domain_list(struct parse *cfile, int);
-
+struct expression *parse_domain_name(struct parse *cfile);
/* tree.c */
#if defined (NSUPDATE)
/*
- * Copyright (c) 2004,2007-2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2019 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2001-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
int minires_ninit (res_state);
ns_rcode isc_rcode_to_ns (isc_result_t);
+int MRns_name_len(const unsigned char *, const unsigned char *);
int MRns_name_compress(const char *, u_char *, size_t, const unsigned char **,
const unsigned char **);
int MRns_name_unpack(const unsigned char *, const unsigned char *,
#define ns_name_pton MRns_name_pton
#define ns_name_unpack MRns_name_unpack
#define ns_name_pack MRns_name_pack
+#define ns_name_len MRns_name_len
#define ns_name_compress MRns_name_compress
#define ns_name_skip MRns_name_skip
#define ns_subdomain MRns_subdomain
/*
- * Copyright (c) 2004,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2019 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
/* Public. */
+/*
+ * ns_name_len(eom, src)
+ * Compute the length of encoded uncompressed domain name.
+ * return:
+ * -1 if it fails, or to be consumed octets if it succeeds.
+ */
+int
+ns_name_len(const u_char *eom, const u_char *src)
+{
+ const u_char *srcp;
+ unsigned n;
+ int len;
+
+ len = -1;
+ srcp = src;
+ if (srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ /* Fetch next label in domain name. */
+ while ((n = *srcp++) != 0) {
+ /* Limit checks. */
+ if (srcp + n >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp += n;
+ }
+ if (len < 0)
+ len = srcp - src;
+ return (len);
+}
+
/*
* ns_name_ntop(src, dst, dstsiz)
* Convert an encoded domain name to printable ascii as per RFC1035.