diff options
author | Douglas Bagnall <douglas.bagnall@catalyst.net.nz> | 2016-12-07 11:54:41 +1300 |
---|---|---|
committer | Douglas Bagnall <dbagnall@samba.org> | 2016-12-14 08:55:42 +0100 |
commit | 91d5ea2ae90140cad0fa8021f07dad3f3d7b7734 (patch) | |
tree | 52308b19e14228fa2fbf2376ea1fe78f3bb16407 /librpc | |
parent | 6c9a185be260a914bc0bd2dcf76c9dcb9664a687 (diff) | |
download | samba-91d5ea2ae90140cad0fa8021f07dad3f3d7b7734.tar.gz |
librpc/ndr/uuid.c: improve speed and accuracy of GUID string parsing
GUID_from_data_blob() was relying on sscanf to parse strings, which was
slow and quite accepting of invalid GUIDs. Instead we directly read a
fixed number of hex bytes for each field.
This now passes the samba4.local.ndr.*.guid_from_string_invalid tests.
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Douglas Bagnall <dbagnall@samba.org>
Autobuild-Date(master): Wed Dec 14 08:55:42 CET 2016 on sn-devel-144
Diffstat (limited to 'librpc')
-rw-r--r-- | librpc/ndr/uuid.c | 132 |
1 files changed, 111 insertions, 21 deletions
diff --git a/librpc/ndr/uuid.c b/librpc/ndr/uuid.c index a3f68d1d344..037dd909fce 100644 --- a/librpc/ndr/uuid.c +++ b/librpc/ndr/uuid.c @@ -52,6 +52,102 @@ _PUBLIC_ NTSTATUS GUID_from_ndr_blob(const DATA_BLOB *b, struct GUID *guid) return ndr_map_error2ntstatus(ndr_err); } +static NTSTATUS read_hex_bytes(const char *s, uint hexchars, uint64_t *dest) +{ + uint64_t x = 0; + uint i; + char c; + + if ((hexchars & 1) || hexchars > 16) { + return NT_STATUS_INVALID_PARAMETER; + } + + for (i = 0; i < hexchars; i++) { + x <<= 4; + c = s[i]; + if (c >= '0' && c <= '9') { + x += c - '0'; + } + else if (c >= 'a' && c <= 'f') { + x += c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') { + x += c - 'A' + 10; + } + else { + /* BAD character (including '\0') */ + return NT_STATUS_INVALID_PARAMETER; + } + } + *dest = x; + return NT_STATUS_OK; +} + + +static NTSTATUS parse_guid_string(const char *s, + uint32_t *time_low, + uint32_t *time_mid, + uint32_t *time_hi_and_version, + uint32_t *clock_seq, + uint32_t *node) +{ + uint64_t tmp; + NTSTATUS status; + int i; + /* "e12b56b6-0a95-11d1-adbb-00c04fd8d5cd" + | | | | | + | | | | \ node[6] + | | | \_____ clock_seq[2] + | | \__________ time_hi_and_version + | \_______________ time_mid + \_____________________ time_low + */ + status = read_hex_bytes(s, 8, &tmp); + if (!NT_STATUS_IS_OK(status) || s[8] != '-') { + return NT_STATUS_INVALID_PARAMETER; + } + *time_low = tmp; + s += 9; + + status = read_hex_bytes(s, 4, &tmp); + if (!NT_STATUS_IS_OK(status) || s[4] != '-') { + return NT_STATUS_INVALID_PARAMETER; + } + *time_mid = tmp; + s += 5; + + status = read_hex_bytes(s, 4, &tmp); + if (!NT_STATUS_IS_OK(status) || s[4] != '-') { + return NT_STATUS_INVALID_PARAMETER; + } + *time_hi_and_version = tmp; + s += 5; + + for (i = 0; i < 2; i++) { + status = read_hex_bytes(s, 2, &tmp); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_INVALID_PARAMETER; + } + clock_seq[i] = tmp; + s += 2; + } + if (s[0] != '-') { + return NT_STATUS_INVALID_PARAMETER; + } + + s++; + + for (i = 0; i < 6; i++) { + status = read_hex_bytes(s, 2, &tmp); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_INVALID_PARAMETER; + } + node[i] = tmp; + s += 2; + } + + return NT_STATUS_OK; +} /** build a GUID from a string @@ -75,32 +171,26 @@ _PUBLIC_ NTSTATUS GUID_from_data_blob(const DATA_BLOB *s, struct GUID *guid) switch(s->length) { case 36: { - char string[37]; - memcpy(string, s->data, 36); - string[36] = 0; - - if (11 == sscanf(string, - "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - &time_low, &time_mid, &time_hi_and_version, - &clock_seq[0], &clock_seq[1], - &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { - status = NT_STATUS_OK; - } + status = parse_guid_string((char *)s->data, + &time_low, + &time_mid, + &time_hi_and_version, + clock_seq, + node); break; } case 38: { - char string[39]; - memcpy(string, s->data, 38); - string[38] = 0; - - if (11 == sscanf(string, - "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - &time_low, &time_mid, &time_hi_and_version, - &clock_seq[0], &clock_seq[1], - &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { - status = NT_STATUS_OK; + if (s->data[0] != '{' || s->data[37] != '}') { + break; } + + status = parse_guid_string((char *)s->data + 1, + &time_low, + &time_mid, + &time_hi_and_version, + clock_seq, + node); break; } case 32: |