]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib/util: add dns_cmp() as it's own file
authorStefan Metzmacher <metze@samba.org>
Tue, 5 Jun 2018 01:18:56 +0000 (03:18 +0200)
committerDouglas Bagnall <dbagnall@samba.org>
Wed, 29 Jan 2025 01:14:40 +0000 (01:14 +0000)
This is a copy of the function in source4/dsdb/common/util_trusts.c, which will
be removed soon.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
lib/util/dns_cmp.c [new file with mode: 0644]
lib/util/dns_cmp.h [new file with mode: 0644]
lib/util/wscript_build

diff --git a/lib/util/dns_cmp.c b/lib/util/dns_cmp.c
new file mode 100644 (file)
index 0000000..e20c429
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+*/
+
+#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 (file)
index 0000000..c01a7a9
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+*/
+
+#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_ */
index 1eab2bb5805e0b560857ad033f5e2465a5c18390..9dff0e8925db711addd9f52f1155395d82ef06ab 100644 (file)
@@ -186,6 +186,7 @@ else:
                   source='''
                          base64.c
                          dprintf.c
+                         dns_cmp.c
                          fsusage.c
                          genrand_util.c
                          getpass.c