From: Stefan Metzmacher Date: Tue, 5 Jun 2018 01:18:56 +0000 (+0200) Subject: lib/util: add dns_cmp() as it's own file X-Git-Tag: tdb-1.4.13~64 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b505db5046dff05347470012eaca169ad5ff1c2;p=thirdparty%2Fsamba.git lib/util: add dns_cmp() as it's own file This is a copy of the function in source4/dsdb/common/util_trusts.c, which will be removed soon. Signed-off-by: Stefan Metzmacher Reviewed-by: Douglas Bagnall --- diff --git a/lib/util/dns_cmp.c b/lib/util/dns_cmp.c new file mode 100644 index 00000000000..e20c4297963 --- /dev/null +++ b/lib/util/dns_cmp.c @@ -0,0 +1,188 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Stefan Metzmacher 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "replace.h" +#include "lib/util/charset/charset.h" +#include "lib/util/fault.h" +#include "lib/util/dns_cmp.h" + +/* + * this function assumes names are well formed DNS names. + * it doesn't validate them + * + * It allows strings up to a length of UINT16_MAX - 1 + * with up to UINT8_MAX components. On overflow this + * just returns the result of strcasecmp_m(). + * + * Trailing dots (only one) are ignored. + * + * The DNS names are compared per component, starting from + * the last one. + * + * The function is usable in a sort, but the return value contains more + * information than a simple comparison. There are 5 return values, defined + * above. + * + * DNS_CMP_FIRST_IS_CHILD (-2) means the first argument is a sub-domain of the + * second. e.g. dns_cmp("foo.example.org", "example.org") + * + * DNS_CMP_FIRST_IS_LESS (-1) means the first argument sorts before the + * second, but is not a sub-domain. e.g. dns_cmp("eggsample.org", "example.org"). + * + * DNS_CMP_SECOND_IS_CHILD (+2) and DNS_CMP_SECOND_IS_LESS (+1) have the + * similar expected meanings. DNS_CMP_MATCH (0) means equality. + * + * NULL values are the parent of all addresses, which means comparisons + * between a string and NULL will return +2 or -2. + */ +int dns_cmp(const char *s1, const char *s2) +{ + size_t l1 = 0; + const char *p1 = NULL; + size_t num_comp1 = 0; + uint16_t comp1[UINT8_MAX] = {0}; + size_t l2 = 0; + const char *p2 = NULL; + size_t num_comp2 = 0; + uint16_t comp2[UINT8_MAX] = {0}; + size_t i; + + if (s1 == s2) { + /* this includes the both NULL case */ + return DNS_CMP_MATCH; + } + if (s1 == NULL) { + return DNS_CMP_SECOND_IS_CHILD; + } + if (s2 == NULL) { + return DNS_CMP_FIRST_IS_CHILD; + } + + l1 = strlen(s1); + l2 = strlen(s2); + + /* + * trailing '.' are ignored. + */ + if (l1 > 1 && s1[l1 - 1] == '.') { + l1--; + } + if (l2 > 1 && s2[l2 - 1] == '.') { + l2--; + } + + for (i = 0; i < ARRAY_SIZE(comp1); i++) { + char *p; + + if (i == 0) { + p1 = s1; + + if (l1 == 0 || l1 >= UINT16_MAX) { + /* just use one single component on overflow */ + break; + } + } + + comp1[num_comp1++] = PTR_DIFF(p1, s1); + + p = strchr_m(p1, '.'); + if (p == NULL) { + p1 = NULL; + break; + } + + p1 = p + 1; + } + + if (p1 != NULL) { + /* just use one single component on overflow */ + num_comp1 = 0; + comp1[num_comp1++] = 0; + p1 = NULL; + } + + for (i = 0; i < ARRAY_SIZE(comp2); i++) { + char *p; + + if (i == 0) { + p2 = s2; + + if (l2 == 0 || l2 >= UINT16_MAX) { + /* just use one single component on overflow */ + break; + } + } + + comp2[num_comp2++] = PTR_DIFF(p2, s2); + + p = strchr_m(p2, '.'); + if (p == NULL) { + p2 = NULL; + break; + } + + p2 = p + 1; + } + + if (p2 != NULL) { + /* just use one single component on overflow */ + num_comp2 = 0; + comp2[num_comp2++] = 0; + p2 = NULL; + } + + for (i = 0; i < UINT8_MAX; i++) { + int cmp; + + if (i < num_comp1) { + size_t idx = num_comp1 - (i + 1); + p1 = s1 + comp1[idx]; + } else { + p1 = NULL; + } + + if (i < num_comp2) { + size_t idx = num_comp2 - (i + 1); + p2 = s2 + comp2[idx]; + } else { + p2 = NULL; + } + + if (p1 == NULL && p2 == NULL) { + return DNS_CMP_MATCH; + } + if (p1 != NULL && p2 == NULL) { + return DNS_CMP_FIRST_IS_CHILD; + } + if (p1 == NULL && p2 != NULL) { + return DNS_CMP_SECOND_IS_CHILD; + } + + cmp = strcasecmp_m(p1, p2); + if (cmp < 0) { + return DNS_CMP_FIRST_IS_LESS; + } + if (cmp > 0) { + return DNS_CMP_SECOND_IS_LESS; + } + } + + smb_panic(__location__); + return -1; +} diff --git a/lib/util/dns_cmp.h b/lib/util/dns_cmp.h new file mode 100644 index 00000000000..c01a7a9f83e --- /dev/null +++ b/lib/util/dns_cmp.h @@ -0,0 +1,63 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Stefan Metzmacher 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _LIB_UTIL_DNS_CMP_H_ +#define _LIB_UTIL_DNS_CMP_H_ 1 + +#define DNS_CMP_FIRST_IS_CHILD -2 +#define DNS_CMP_FIRST_IS_LESS -1 +#define DNS_CMP_MATCH 0 +#define DNS_CMP_SECOND_IS_LESS 1 +#define DNS_CMP_SECOND_IS_CHILD 2 + +#define DNS_CMP_IS_NO_MATCH(__cmp) \ + ((__cmp == DNS_CMP_FIRST_IS_LESS) || (__cmp == DNS_CMP_SECOND_IS_LESS)) + +/* + * this function assumes names are well formed DNS names. + * it doesn't validate them + * + * It allows strings up to a length of UINT16_MAX - 1 + * with up to UINT8_MAX components. On overflow this + * just returns the result of strcasecmp_m(). + * + * Trailing dots (only one) are ignored. + * + * The DNS names are compared per component, starting from + * the last one. + * + * The function is usable in a sort, but the return value contains more + * information than a simple comparison. There are 5 return values, defined + * above. + * + * DNS_CMP_FIRST_IS_CHILD (-2) means the first argument is a sub-domain of the + * second. e.g. dns_cmp("foo.example.org", "example.org") + * + * DNS_CMP_FIRST_IS_LESS (-1) means the first argument sorts before the + * second, but is not a sub-domain. e.g. dns_cmp("eggsample.org", "example.org"). + * + * DNS_CMP_SECOND_IS_CHILD (+2) and DNS_CMP_SECOND_IS_LESS (+1) have the + * similar expected meanings. DNS_CMP_MATCH (0) means equality. + * + * NULL values are the parent of all addresses, which means comparisons + * between a string and NULL will return +2 or -2. + */ +int dns_cmp(const char *s1, const char *s2); + +#endif /* _LIB_UTIL_DNS_CMP_H_ */ diff --git a/lib/util/wscript_build b/lib/util/wscript_build index 1eab2bb5805..9dff0e8925d 100644 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -186,6 +186,7 @@ else: source=''' base64.c dprintf.c + dns_cmp.c fsusage.c genrand_util.c getpass.c