Commit 78d5c8b7 authored by Evan Hunt's avatar Evan Hunt
Browse files

[master] Merge branch 'master' of ssh://repo/proj/git/prod/bind9

parents ceb722a4 b9a067ba
3500. [port] Support NAPTR regular expression validation on
all platforms. [RT #32688]
3499. [doc] Corrected ARM documentation of built-in zones.
[RT #32694]
......
......@@ -8305,7 +8305,7 @@ ns_server_add_zone(ns_server_t *server, char *args) {
static isc_boolean_t
inuse(const char* file, isc_boolean_t first, isc_buffer_t *text) {
#define INUSEMSG "The following files were in use and may now be removed:\n"
if (file != NULL && isc_file_exists(file) &&
isc_buffer_availablelength(text) >
strlen(file) + (first ? sizeof(INUSEMSG) : 0))
......
......@@ -25,9 +25,8 @@
#define RDATA_GENERIC_NAPTR_35_C
#define RRTYPE_NAPTR_ATTRIBUTES (0)
#ifdef HAVE_REGEX_H
#include <regex.h>
#endif
#include <isc/regex.h>
/*
* Check the wire format of the Regexp field.
......@@ -35,18 +34,15 @@
*/
static inline isc_result_t
txt_valid_regex(const unsigned char *txt) {
#ifdef HAVE_REGEX_H
regex_t preg;
unsigned int regflags = REG_EXTENDED;
unsigned int nsub = 0;
char regex[256];
char *cp;
#endif
isc_boolean_t flags = ISC_FALSE;
isc_boolean_t replace = ISC_FALSE;
unsigned char c;
unsigned char delim;
unsigned int len;
int n;
len = *txt++;
if (len == 0U)
......@@ -65,11 +61,7 @@ txt_valid_regex(const unsigned char *txt) {
return (DNS_R_SYNTAX);
}
#ifdef HAVE_REGEX_H
memset(&preg, 0, sizeof(preg));
cp = regex;
#endif
while (len-- > 0) {
c = *txt++;
if (c == 0)
......@@ -88,18 +80,13 @@ txt_valid_regex(const unsigned char *txt) {
if (flags) {
switch (c) {
case 'i':
#ifdef HAVE_REGEX_H
regflags |= REG_ICASE;
#endif
continue;
default:
return (DNS_R_SYNTAX);
}
}
#ifdef HAVE_REGEX_H
if (!replace)
*cp++ = c;
#endif
if (c == '\\') {
if (len == 0)
return (DNS_R_SYNTAX);
......@@ -110,7 +97,6 @@ txt_valid_regex(const unsigned char *txt) {
if (replace)
switch (c) {
case '0': return (DNS_R_SYNTAX);
#ifdef HAVE_REGEX_H
case '1': if (nsub < 1) nsub = 1; break;
case '2': if (nsub < 2) nsub = 2; break;
case '3': if (nsub < 3) nsub = 3; break;
......@@ -120,30 +106,17 @@ txt_valid_regex(const unsigned char *txt) {
case '7': if (nsub < 7) nsub = 7; break;
case '8': if (nsub < 8) nsub = 8; break;
case '9': if (nsub < 9) nsub = 9; break;
#endif
}
#ifdef HAVE_REGEX_H
if (!replace)
*cp++ = c;
#endif
}
}
if (!flags)
return (DNS_R_SYNTAX);
#ifdef HAVE_REGEX_H
*cp = '\0';
if (regcomp(&preg, regex, regflags))
return (DNS_R_SYNTAX);
/*
* Check that substitutions in the replacement string are consistant
* with the regular expression.
*/
if (preg.re_nsub < nsub) {
regfree(&preg);
n = isc_regex_validate(regex);
if (n < 0 || nsub > (unsigned int)n)
return (DNS_R_SYNTAX);
}
regfree(&preg);
#endif
return (ISC_R_SUCCESS);
}
......
......@@ -67,12 +67,11 @@ OBJS = @ISC_EXTRA_OBJS@ \
error.@O@ event.@O@ \
hash.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
inet_aton.@O@ iterated_hash.@O@ lex.@O@ lfsr.@O@ log.@O@ \
md5.@O@ mutexblock.@O@ \
netaddr.@O@ netscope.@O@ \
ondestroy.@O@ \
parseint.@O@ portset.@O@ radix.@O@ \
random.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ string.@O@ \
md5.@O@ mutexblock.@O@ netaddr.@O@ netscope.@O@ \
ondestroy.@O@ parseint.@O@ portset.@O@ radix.@O@ \
random.@O@ refcount.@O@ region.@O@ regex.@O@ result.@O@ \
rwlock.@O@ serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ \
stats.@O@ string.@O@ \
symtab.@O@ \
version.@O@ \
${APIOBJS} ${ISCDRIVEROBJS} \
......@@ -94,7 +93,7 @@ SRCS = @ISC_EXTRA_SRCS@ \
netaddr.c netscope.c \
ondestroy.c \
parseint.c portset.c radix.c \
random.c refcount.c region.c result.c rwlock.c \
random.c refcount.c region.c regex.c result.c rwlock.c \
serial.c sha1.c sha2.c sockaddr.c stats.c string.c symtab.c \
version.c \
${APISRCS} ${ISCDRIVERSRCS}
......
......@@ -35,7 +35,7 @@ HEADERS = app.h assertions.h base64.h bitstring.h boolean.h \
magic.h md5.h mem.h msgcat.h msgs.h \
mutexblock.h namespace.h netaddr.h ondestroy.h os.h parseint.h \
print.h quota.h radix.h random.h ratelimiter.h \
refcount.h region.h resource.h \
refcount.h regex.h region.h resource.h \
result.h resultclass.h rwlock.h serial.h sha1.h sha2.h \
sockaddr.h socket.h stdio.h stdlib.h string.h \
symtab.h \
......
......@@ -60,7 +60,8 @@ OBJS = @ISC_EXTRA_OBJS@ \
md5.@O@ mem.@O@ mutexblock.@O@ \
netaddr.@O@ netscope.@O@ pool.@O@ ondestroy.@O@ \
parseint.@O@ portset.@O@ quota.@O@ radix.@O@ random.@O@ \
ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
ratelimiter.@O@ refcount.@O@ region.@O@ regex.@O@ result.@O@ \
rwlock.@O@ \
serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ \
string.@O@ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ \
timer.@O@ version.@O@ ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS}
......@@ -76,7 +77,7 @@ SRCS = @ISC_EXTRA_SRCS@ \
md5.c mem.c mutexblock.c \
netaddr.c netscope.c pool.c ondestroy.c \
parseint.c portset.c quota.c radix.c random.c \
ratelimiter.c refcount.c region.c result.c rwlock.c \
ratelimiter.c refcount.c region.c regex.c result.c rwlock.c \
serial.c sha1.c sha2.c sockaddr.c stats.c string.c strtoul.c \
symtab.c symtbl-empty.c task.c taskpool.c timer.c version.c
......
......@@ -36,7 +36,7 @@ HEADERS = app.h assertions.h base64.h bind9.h bitstring.h boolean.h \
magic.h md5.h mem.h msgcat.h msgs.h mutexblock.h \
namespace.h netaddr.h ondestroy.h os.h parseint.h \
print.h quota.h radix.h random.h ratelimiter.h \
refcount.h region.h resource.h \
refcount.h regex.h region.h resource.h \
result.h resultclass.h rwlock.h serial.h sha1.h sha2.h \
sockaddr.h socket.h stdio.h stdlib.h string.h \
symtab.h \
......
/*
* Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ISC_REGEX_H
#define ISC_REGEX_H 1
/*! \file isc/regex.h */
#include <isc/types.h>
#include <isc/lang.h>
ISC_LANG_BEGINDECLS
int
isc_regex_validate(const char *expression);
/*%<
* Check a regular expression for syntactic correctness.
*
* Returns:
*\li -1 on error.
*\li the number of groups in the expression.
*/
ISC_LANG_ENDDECLS
#endif /* ISC_REGEX_H */
......@@ -23,6 +23,7 @@
/*! \file isc/region.h */
#include <isc/types.h>
#include <isc/lang.h>
struct isc_region {
unsigned char * base;
......@@ -81,6 +82,8 @@ struct isc_consttextregion {
} while (0)
/*@}*/
ISC_LANG_BEGINDECLS
int
isc_region_compare(isc_region_t *r1, isc_region_t *r2);
/*%<
......@@ -96,4 +99,6 @@ isc_region_compare(isc_region_t *r1, isc_region_t *r2);
*\li > 0 if r1 is lexicographically greater than r2
*/
ISC_LANG_ENDDECLS
#endif /* ISC_REGION_H */
/*
* Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <isc/file.h>
#include <isc/regex.h>
#include <isc/string.h>
#if VALREGEX_REPORT_REASON
#define FAIL(x) do { reason = (x); goto error; } while(0)
#else
#define FAIL(x) goto error
#endif
/*
* Validate the regular expression 'C' locale.
*/
int
isc_regex_validate(const char *c) {
enum {
none, parse_bracket, parse_bound,
parse_ce, parse_ec, parse_cc
} state = none;
/* Well known character classes. */
const char *cc[] = {
":alnum:", ":digit:", ":punct:", ":alpha:", ":graph:",
":space:", ":blank:", ":lower:", ":upper:", ":cntrl:",
":print:", ":xdigit:"
};
isc_boolean_t seen_comma = ISC_FALSE;
isc_boolean_t seen_high = ISC_FALSE;
isc_boolean_t seen_char = ISC_FALSE;
isc_boolean_t seen_ec = ISC_FALSE;
isc_boolean_t seen_ce = ISC_FALSE;
isc_boolean_t have_atom = ISC_FALSE;
int group = 0;
int range = 0;
int sub = 0;
isc_boolean_t empty_ok = ISC_FALSE;
isc_boolean_t neg = ISC_FALSE;
isc_boolean_t was_multiple = ISC_FALSE;
unsigned int low = 0;
unsigned int high = 0;
const char *ccname = NULL;
int range_start = 0;
#if VALREGEX_REPORT_REASON
const char *reason = "";
#endif
if (c == NULL || *c == 0)
FAIL("empty string");
while (c != NULL && *c != 0) {
switch (state) {
case none:
switch (*c) {
case '\\': /* make literal */
++c;
switch (*c) {
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
if ((*c - '0') > sub)
FAIL("bad back reference");
have_atom = ISC_TRUE;
was_multiple = ISC_FALSE;
break;
case 0:
FAIL("escaped end-of-string");
default:
goto literal;
}
++c;
break;
case '[': /* bracket start */
++c;
neg = ISC_FALSE;
was_multiple = ISC_FALSE;
seen_char = ISC_FALSE;
state = parse_bracket;
break;
case '{': /* bound start */
switch (c[1]) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
if (!have_atom)
FAIL("no atom");
if (was_multiple)
FAIL("was multiple");
seen_comma = ISC_FALSE;
seen_high = ISC_FALSE;
low = high = 0;
state = parse_bound;
break;
default:
goto literal;
}
++c;
have_atom = ISC_TRUE;
was_multiple = ISC_TRUE;
break;
case '}':
goto literal;
case '(': /* group start */
have_atom = ISC_FALSE;
was_multiple = ISC_FALSE;
empty_ok = ISC_TRUE;
++group;
++sub;
++c;
break;
case ')': /* group end */
if (group && !have_atom && !empty_ok)
FAIL("empty alternative");
have_atom = ISC_TRUE;
was_multiple = ISC_FALSE;
if (group != 0)
--group;
++c;
break;
case '|': /* alternative seperator */
if (!have_atom)
FAIL("no atom");
have_atom = ISC_FALSE;
empty_ok = ISC_FALSE;
was_multiple = ISC_FALSE;
++c;
break;
case '^':
case '$':
have_atom = ISC_TRUE;
was_multiple = ISC_TRUE;
++c;
break;
case '+':
case '*':
case '?':
if (was_multiple)
FAIL("was multiple");
if (!have_atom)
FAIL("no atom");
have_atom = ISC_TRUE;
was_multiple = ISC_TRUE;
++c;
break;
case '.':
default:
literal:
have_atom = ISC_TRUE;
was_multiple = ISC_FALSE;
++c;
break;
}
break;
case parse_bound:
switch (*c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (!seen_comma) {
low = low * 10 + *c - '0';
if (low > 255)
FAIL("lower bound too big");
} else {
seen_high = ISC_TRUE;
high = high * 10 + *c - '0';
if (high > 255)
FAIL("upper bound too big");
}
++c;
break;
case ',':
if (seen_comma)
FAIL("multiple commas");
seen_comma = ISC_TRUE;
++c;
break;
default:
case '{':
FAIL("non digit/comma");
case '}':
if (seen_high && low > high)
FAIL("bad parse bound");
seen_comma = ISC_FALSE;
state = none;
++c;
break;
}
break;
case parse_bracket:
switch (*c) {
case '^':
if (seen_char || neg) goto inside;
neg = ISC_TRUE;
++c;
break;
case '-':
if (range == 2) goto inside;
if (!seen_char) goto inside;
if (range == 1)
FAIL("bad range");
range = 2;
++c;
break;
case '[':
++c;
switch (*c) {
case '.': /* collating element */
if (range) --range;
++c;
state = parse_ce;
seen_ce = ISC_FALSE;
break;
case '=': /* equivalence class */
if (range == 2)
FAIL("equivalence class in range");
++c;
state = parse_ec;
seen_ec = ISC_FALSE;
break;
case ':': /* character class */
if (range == 2)
FAIL("character class in range");
ccname = c;
++c;
state = parse_cc;
break;
}
seen_char = ISC_TRUE;
break;
case ']':
if (!c[1] && !seen_char)
FAIL("unfinished brace");
if (!seen_char)
goto inside;
++c;
range = 0;
have_atom = ISC_TRUE;
state = none;
break;
default:
inside:
seen_char = ISC_TRUE;
if (range == 2 && *c < range_start)
FAIL("out of order range");
if (range != 0)
--range;
range_start = *c;
++c;
break;
};
break;
case parse_ce:
switch (*c) {
case '.':
++c;
switch (*c) {
case ']':
if (!seen_ce)
FAIL("empty ce");
++c;
state = parse_bracket;
break;
default:
if (seen_ce)
range_start = 256;
else
range_start = '.';
seen_ce = ISC_TRUE;
break;
}
break;
default:
if (seen_ce)
range_start = 256;
else
range_start = *c;
seen_ce = ISC_TRUE;
++c;
break;
}
break;
case parse_ec:
switch (*c) {
case '=':
++c;
switch (*c) {
case ']':
if (!seen_ec)
FAIL("no ec");
++c;
state = parse_bracket;
break;
default:
seen_ec = ISC_TRUE;
break;
}
break;
default:
seen_ec = ISC_TRUE;
++c;
break;
}
break;
case parse_cc:
switch (*c) {
case ':':
++c;
switch (*c) {
case ']': {
unsigned int i;
isc_boolean_t found = ISC_FALSE;
for (i = 0;
i < sizeof(cc)/sizeof(*cc);
i++)
{
unsigned int len;
len = strlen(cc[i]);
if (len != (c - ccname))
continue;
if (strncmp(cc[i], ccname, len))
continue;
found = ISC_TRUE;
}
if (!found)
FAIL("unknown cc");
++c;
state = parse_bracket;
break;
}
default:
break;
}
break;
default:
++c;
break;
}
break;
}
}
if (group != 0)
FAIL("group open");
if (state != none)
FAIL("incomplete");
if (!have_atom)
FAIL("no atom");
return (sub);
error:
#if VALREGEX_REPORT_REASON
fprintf(stderr, "%s\n", reason);
#endif
return (-1);
}
......@@ -37,12 +37,13 @@ LIBS = @LIBS@ @ATFLIBS@
OBJS = isctest.@O@
SRCS = isctest.c taskpool_test.c socket_test.c hash_test.c \
sockaddr_test.c symtab_test.c task_test.c queue_test.c \
parse_test.c pool_test.c
parse_test.c pool_test.c regex_test.c
SUBDIRS =
TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
sockaddr_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \
queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@
queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \
regex_test@EXEEXT@