[master] Prevent nsupdate from immediately exiting on invalid user input in interactive mode

4683.	[bug]		Prevent nsupdate from immediately exiting on invalid
			user input in interactive mode. [RT #28194]
This commit is contained in:
Michał Kępień
2017-06-12 11:16:18 +02:00
parent 615b961e02
commit 1aa583b5a5
5 changed files with 166 additions and 36 deletions

View File

@@ -1,3 +1,6 @@
4683. [bug] Prevent nsupdate from immediately exiting on invalid
user input in interactive mode. [RT #28194]
4682. [bug] Don't report errors on records below a DNAME.
[RT #44880]

View File

@@ -450,8 +450,10 @@ reset_system(void) {
}
}
static isc_uint16_t
parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len) {
static isc_boolean_t
parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len,
isc_uint16_t *digestbitsp)
{
isc_uint16_t digestbits = 0;
isc_result_t result;
char buf[20];
@@ -459,8 +461,10 @@ parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len) {
REQUIRE(hmac != NULL && *hmac == NULL);
REQUIRE(hmacstr != NULL);
if (len >= sizeof(buf))
fatal("unknown key type '%.*s'", (int)(len), hmacstr);
if (len >= sizeof(buf)) {
error("unknown key type '%.*s'", (int)(len), hmacstr);
return (ISC_FALSE);
}
strncpy(buf, hmacstr, len);
buf[len] = 0;
@@ -471,9 +475,11 @@ parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len) {
} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
*hmac = DNS_TSIG_HMACMD5_NAME;
result = isc_parse_uint16(&digestbits, &buf[9], 10);
if (result != ISC_R_SUCCESS || digestbits > 128)
fatal("digest-bits out of range [0..128]");
digestbits = (digestbits +7) & ~0x7U;
if (result != ISC_R_SUCCESS || digestbits > 128) {
error("digest-bits out of range [0..128]");
return (ISC_FALSE);
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else
#endif
if (strcasecmp(buf, "hmac-sha1") == 0) {
@@ -481,44 +487,56 @@ parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len) {
} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
*hmac = DNS_TSIG_HMACSHA1_NAME;
result = isc_parse_uint16(&digestbits, &buf[10], 10);
if (result != ISC_R_SUCCESS || digestbits > 160)
fatal("digest-bits out of range [0..160]");
digestbits = (digestbits +7) & ~0x7U;
if (result != ISC_R_SUCCESS || digestbits > 160) {
error("digest-bits out of range [0..160]");
return (ISC_FALSE);
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha224") == 0) {
*hmac = DNS_TSIG_HMACSHA224_NAME;
} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
*hmac = DNS_TSIG_HMACSHA224_NAME;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 224)
fatal("digest-bits out of range [0..224]");
digestbits = (digestbits +7) & ~0x7U;
if (result != ISC_R_SUCCESS || digestbits > 224) {
error("digest-bits out of range [0..224]");
return (ISC_FALSE);
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha256") == 0) {
*hmac = DNS_TSIG_HMACSHA256_NAME;
} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
*hmac = DNS_TSIG_HMACSHA256_NAME;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 256)
fatal("digest-bits out of range [0..256]");
digestbits = (digestbits +7) & ~0x7U;
if (result != ISC_R_SUCCESS || digestbits > 256) {
error("digest-bits out of range [0..256]");
return (ISC_FALSE);
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha384") == 0) {
*hmac = DNS_TSIG_HMACSHA384_NAME;
} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
*hmac = DNS_TSIG_HMACSHA384_NAME;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 384)
fatal("digest-bits out of range [0..384]");
digestbits = (digestbits +7) & ~0x7U;
if (result != ISC_R_SUCCESS || digestbits > 384) {
error("digest-bits out of range [0..384]");
return (ISC_FALSE);
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha512") == 0) {
*hmac = DNS_TSIG_HMACSHA512_NAME;
} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
*hmac = DNS_TSIG_HMACSHA512_NAME;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 512)
fatal("digest-bits out of range [0..512]");
digestbits = (digestbits +7) & ~0x7U;
} else
fatal("unknown key type '%s'", buf);
return (digestbits);
if (result != ISC_R_SUCCESS || digestbits > 512) {
error("digest-bits out of range [0..512]");
return (ISC_FALSE);
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else {
error("unknown key type '%s'", buf);
return (ISC_FALSE);
}
return (ISC_TRUE);
}
static int
@@ -564,7 +582,9 @@ setup_keystr(void) {
fatal("key option must specify [hmac:]keyname:secret");
name = secretstr;
secretstr = n + 1;
digestbits = parse_hmac(&hmacname, keystr, s - keystr);
if (!parse_hmac(&hmacname, keystr, s - keystr, &digestbits)) {
exit(1);
}
} else {
#ifndef PK11_MD5_DISABLE
hmacname = DNS_TSIG_HMACMD5_NAME;
@@ -997,14 +1017,14 @@ static int
get_addresses(char *host, in_port_t port,
isc_sockaddr_t *sockaddr, int naddrs)
{
int count;
int count = 0;
isc_result_t result;
isc_app_block();
result = bind9_getaddresses(host, port, sockaddr, naddrs, &count);
isc_app_unblock();
if (result != ISC_R_SUCCESS)
fatal("couldn't get address for '%s': %s",
error("couldn't get address for '%s': %s",
host, isc_result_totext(result));
return (count);
}
@@ -1014,7 +1034,7 @@ version(void) {
fputs("nsupdate " VERSION "\n", stderr);
}
#define PARSE_ARGS_FMT "dDML:y:ghlovk:p:Pr:R::t:Tu:V"
#define PARSE_ARGS_FMT "dDML:y:ghilovk:p:Pr:R::t:Tu:V"
static void
pre_parse_args(int argc, char **argv) {
@@ -1038,7 +1058,7 @@ pre_parse_args(int argc, char **argv) {
if (isc_commandline_option != '?')
fprintf(stderr, "%s: invalid argument -%c\n",
argv[0], isc_commandline_option);
fprintf(stderr, "usage: nsupdate [-dD] [-L level] [-l]"
fprintf(stderr, "usage: nsupdate [-dDi] [-L level] [-l]"
"[-g | -o | -y keyname:secret | -k keyfile] "
"[-v] [-V] [-P] [-T] [filename]\n");
exit(1);
@@ -1085,6 +1105,7 @@ parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
int ch;
isc_uint32_t i;
isc_result_t result;
isc_boolean_t force_interactive = ISC_FALSE;
debug("parse_args");
while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
@@ -1098,6 +1119,10 @@ parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
break;
case 'M':
break;
case 'i':
force_interactive = ISC_TRUE;
interactive = ISC_TRUE;
break;
case 'l':
local_only = ISC_TRUE;
break;
@@ -1210,7 +1235,9 @@ parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
exit(1);
}
}
interactive = ISC_FALSE;
if (!force_interactive) {
interactive = ISC_FALSE;
}
}
}
@@ -1237,7 +1264,12 @@ parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
isc_buffer_init(&source, word, strlen(word));
isc_buffer_add(&source, strlen(word));
result = dns_name_fromtext(*namep, &source, dns_rootname, 0, NULL);
check_result(result, "dns_name_fromtext");
if (result != ISC_R_SUCCESS) {
error("invalid owner name: %s", isc_result_totext(result));
isc_buffer_invalidate(&source);
dns_message_puttempname(msg, namep);
return (STATUS_SYNTAX);
}
isc_buffer_invalidate(&source);
return (STATUS_MORE);
}
@@ -1482,6 +1514,9 @@ evaluate_server(char *cmdline) {
memset(servers, 0, ns_alloc * sizeof(isc_sockaddr_t));
ns_total = get_addresses(server, (in_port_t)port, servers, ns_alloc);
if (ns_total == 0) {
return (STATUS_SYNTAX);
}
return (STATUS_MORE);
}
@@ -1562,7 +1597,10 @@ evaluate_key(char *cmdline) {
n = strchr(namestr, ':');
if (n != NULL) {
digestbits = parse_hmac(&hmacname, namestr, n - namestr);
if (!parse_hmac(&hmacname, namestr, n - namestr,
&digestbits)) {
return (STATUS_SYNTAX);
}
namestr = n + 1;
} else
#ifndef PK11_MD5_DISABLE
@@ -1657,8 +1695,10 @@ evaluate_realm(char *cmdline) {
return (STATUS_MORE);
n = snprintf(buf, sizeof(buf), "@%s", word);
if (n < 0 || (size_t)n >= sizeof(buf))
fatal("realm is too long");
if (n < 0 || (size_t)n >= sizeof(buf)) {
error("realm is too long");
return (STATUS_SYNTAX);
}
realm = isc_mem_strdup(gmctx, buf);
if (realm == NULL)
fatal("out of memory");
@@ -1677,7 +1717,7 @@ evaluate_ttl(char *cmdline) {
word = nsu_strsep(&cmdline, " \t\r\n");
if (word == NULL || *word == 0) {
fprintf(stderr, "could not ttl\n");
fprintf(stderr, "could not read ttl\n");
return (STATUS_SYNTAX);
}
@@ -2636,6 +2676,9 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
memset(master_servers, 0, size);
master_total = get_addresses(serverstr, dnsport,
master_servers, master_alloc);
if (master_total == 0) {
exit(1);
}
master_inuse = 0;
} else
master_from_servers();

View File

@@ -53,6 +53,7 @@
<command>nsupdate</command>
<arg choice="opt" rep="norepeat"><option>-d</option></arg>
<arg choice="opt" rep="norepeat"><option>-D</option></arg>
<arg choice="opt" rep="norepeat"><option>-i</option></arg>
<arg choice="opt" rep="norepeat"><option>-L <replaceable class="parameter">level</replaceable></option></arg>
<group choice="opt" rep="norepeat">
<arg choice="opt" rep="norepeat"><option>-g</option></arg>
@@ -156,6 +157,15 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-i</term>
<listitem>
<para>
Force interactive mode, even when standard input is not a terminal.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-k <replaceable class="parameter">keyfile</replaceable></term>
<listitem>

View File

@@ -759,6 +759,63 @@ grep "; Communication with 10.53.0.4#5300 failed: timed out" nsupdate.out-$n > /
grep "not implemented" nsupdate.out-$n > /dev/null 2>&1 && ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
n=`expr $n + 1`
ret=0
echo "I:ensure bad owner name is fatal in non-interactive mode ($n)"
$NSUPDATE <<END > nsupdate.out 2>&1 && ret=1
update add emptylabel..nil. 600 A 10.10.10.1
END
grep "invalid owner name: empty label" nsupdate.out > /dev/null || ret=1
grep "syntax error" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
n=`expr $n + 1`
ret=0
echo "I:ensure bad owner name is not fatal in interactive mode ($n)"
$NSUPDATE -i <<END > nsupdate.out 2>&1 || ret=1
update add emptylabel..nil. 600 A 10.10.10.1
END
grep "invalid owner name: empty label" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
n=`expr $n + 1`
ret=0
echo "I:ensure invalid key type is fatal in non-interactive mode ($n)"
$NSUPDATE <<END > nsupdate.out 2>&1 && ret=1
key badkeytype:example abcd12345678
END
grep "unknown key type 'badkeytype'" nsupdate.out > /dev/null || ret=1
grep "syntax error" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
n=`expr $n + 1`
ret=0
echo "I:ensure invalid key type is not fatal in interactive mode ($n)"
$NSUPDATE -i <<END > nsupdate.out 2>&1 || ret=1
key badkeytype:example abcd12345678
END
grep "unknown key type 'badkeytype'" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
n=`expr $n + 1`
ret=0
echo "I:ensure unresolvable server name is fatal in non-interactive mode ($n)"
$NSUPDATE <<END > nsupdate.out 2>&1 && ret=1
server unresolvable..
END
grep "couldn't get address for 'unresolvable..': not found" nsupdate.out > /dev/null || ret=1
grep "syntax error" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
n=`expr $n + 1`
ret=0
echo "I:ensure unresolvable server name is not fatal in interactive mode ($n)"
$NSUPDATE -i <<END > nsupdate.out 2>&1 || ret=1
server unresolvable..
END
grep "couldn't get address for 'unresolvable..': not found" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
#
# Add client library tests here
#

View File

@@ -81,6 +81,23 @@ output=`$DIG $DIGOPTS +short cname fred.example.nil.`
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:ensure too long realm name is fatal in non-interactive mode"
ret=0
$NSUPDATE <<END > nsupdate.out 2>&1 && ret=1
realm namenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamename
END
grep "realm is too long" nsupdate.out > /dev/null || ret=1
grep "syntax error" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
echo "I:ensure too long realm name is not fatal in interactive mode"
ret=0
$NSUPDATE -i <<END > nsupdate.out 2>&1 || ret=1
realm namenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamename
END
grep "realm is too long" nsupdate.out > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
[ $status -eq 0 ] && echo "I:tsiggss tests all OK"
kill `cat authsock.pid`