From a75c039d1be926946d3e87d5eb45d14960d32620 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Thu, 23 Apr 2026 18:56:21 +0200
Subject: [PATCH 32/38] CVE-2026-4408: lib/util: introduce
 strstr_for_invalid_account_characters()

This splits out the logic from samaccountname_bad_chars_check()
in source4/dsdb/samdb/ldb_modules/samldb.c, this will be used
in other places soon.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
---
 lib/util/samba_util.h |  9 +++++++++
 lib/util/util_str.c   | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

--- a/lib/util/samba_util.h
+++ b/lib/util/samba_util.h
@@ -301,6 +301,15 @@ _PUBLIC_ bool set_boolean(const char *bo
 _PUBLIC_ bool conv_str_bool(const char * str, bool * val);
 
 /**
+ * Returns a pointer to the first invalid character in name.
+ *
+ * Passing a NULL pointer as name is not allowed!
+ *
+ * This returns NULL for a valid account name.
+ **/
+_PUBLIC_ const char *strstr_for_invalid_account_characters(const char *name);
+
+/**
  * Convert a size specification like 16K into an integral number of bytes.
  **/
 _PUBLIC_ bool conv_str_size_error(const char * str, uint64_t * val);
--- a/lib/util/util_str.c
+++ b/lib/util/util_str.c
@@ -305,3 +305,41 @@ _PUBLIC_ bool set_boolean(const char *bo
 	}
 	return false;
 }
+
+_PUBLIC_ const char *strstr_for_invalid_account_characters(const char *name)
+{
+	/*
+	 * Return a pointer to the first invalid character in the
+	 * sAMAccountName, or NULL if the whole name is valid.
+	 *
+	 * The rules here are based on
+	 *
+	 * https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx
+	 */
+	size_t i;
+
+	for (i = 0; name[i] != '\0'; i++) {
+		uint8_t c = name[i];
+		const char *p = NULL;
+
+		if (iscntrl(c)) {
+			return &name[i];
+		}
+
+		p = strchr("\"[]:;|=+*?<>/\\,", c);
+		if (p != NULL) {
+			return &name[i];
+		}
+	}
+
+	if (i == 0) {
+		return &name[i];
+	}
+
+	if (name[i - 1] == '.') {
+		i -= 1;
+		return &name[i];
+	}
+
+	return NULL;
+}
