Blame SOURCES/computer-ou.patch

2c6b19
From 3db35ad73ec57c8af499a0dcef96ffd4da914236 Mon Sep 17 00:00:00 2001
2c6b19
From: Stef Walter <stefw@redhat.com>
2c6b19
Date: Mon, 7 Sep 2015 13:49:10 +0200
2c6b19
Subject: [PATCH 2/2] service: Fully qualify --computer-ou DN before passing to
2c6b19
 adcli
2c6b19
2c6b19
This allows us to have a similar behavior for both the Samba and
2c6b19
adcli membership software.
2c6b19
---
2c6b19
 service/Makefile.am          |   4 +-
2c6b19
 service/realm-adcli-enroll.c |  11 +-
2c6b19
 service/realm-dn-util.c      | 239 +++++++++++++++++++++++++++++++++++++++++++
2c6b19
 service/realm-dn-util.h      |  32 ++++++
2c6b19
 service/realm-samba-enroll.c |   4 +-
2c6b19
 service/realm-samba-util.c   | 172 -------------------------------
2c6b19
 service/realm-samba-util.h   |  29 ------
2c6b19
 tests/Makefile.am            |  16 +--
2c6b19
 tests/test-dn-util.c         | 129 +++++++++++++++++++++++
2c6b19
 tests/test-samba-ou-format.c |  89 ----------------
2c6b19
 11 files changed, 422 insertions(+), 305 deletions(-)
2c6b19
 create mode 100644 service/realm-dn-util.c
2c6b19
 create mode 100644 service/realm-dn-util.h
2c6b19
 delete mode 100644 service/realm-samba-util.c
2c6b19
 delete mode 100644 service/realm-samba-util.h
2c6b19
 create mode 100644 tests/test-dn-util.c
2c6b19
 delete mode 100644 tests/test-samba-ou-format.c
2c6b19
2c6b19
diff --git a/service/Makefile.am b/service/Makefile.am
2c6b19
index 06a95ef..88ee780 100644
2c6b19
--- a/service/Makefile.am
2c6b19
+++ b/service/Makefile.am
2c6b19
@@ -43,6 +43,8 @@ realmd_SOURCES = \
2c6b19
 	service/realm-disco-mscldap.h \
2c6b19
 	service/realm-disco-rootdse.c \
2c6b19
 	service/realm-disco-rootdse.h \
2c6b19
+	service/realm-dn-util.c \
2c6b19
+	service/realm-dn-util.h \
2c6b19
 	service/realm-errors.c \
2c6b19
 	service/realm-errors.h \
2c6b19
 	service/realm-example.c \
2c6b19
@@ -79,8 +81,6 @@ realmd_SOURCES = \
2c6b19
 	service/realm-samba-enroll.h \
2c6b19
 	service/realm-samba-provider.c \
2c6b19
 	service/realm-samba-provider.h \
2c6b19
-	service/realm-samba-util.c \
2c6b19
-	service/realm-samba-util.h \
2c6b19
 	service/realm-samba-winbind.c \
2c6b19
 	service/realm-samba-winbind.h \
2c6b19
 	service/realm-service.c \
2c6b19
diff --git a/service/realm-adcli-enroll.c b/service/realm-adcli-enroll.c
2c6b19
index 7448647..ef1b563 100644
2c6b19
--- a/service/realm-adcli-enroll.c
2c6b19
+++ b/service/realm-adcli-enroll.c
2c6b19
@@ -18,6 +18,7 @@
2c6b19
 #include "realm-command.h"
2c6b19
 #include "realm-daemon.h"
2c6b19
 #include "realm-diagnostics.h"
2c6b19
+#include "realm-dn-util.h"
2c6b19
 #include "realm-errors.h"
2c6b19
 #include "realm-ini-config.h"
2c6b19
 #include "realm-options.h"
2c6b19
@@ -82,6 +83,7 @@ realm_adcli_enroll_join_async (RealmDisco *disco,
2c6b19
 	gchar *ccache_arg = NULL;
2c6b19
 	gchar *upn_arg = NULL;
2c6b19
 	gchar *server_arg = NULL;
2c6b19
+	gchar *ou_arg = NULL;
2c6b19
 
2c6b19
 	g_return_if_fail (cred != NULL);
2c6b19
 	g_return_if_fail (disco != NULL);
2c6b19
@@ -120,9 +122,13 @@ realm_adcli_enroll_join_async (RealmDisco *disco,
2c6b19
 	}
2c6b19
 
2c6b19
 	computer_ou = realm_options_computer_ou (options, disco->domain_name);
2c6b19
-	if (computer_ou) {
2c6b19
+	if (computer_ou != NULL) {
2c6b19
+		ou_arg = realm_dn_util_build_qualified (computer_ou, disco->domain_name);
2c6b19
 		g_ptr_array_add (args, "--computer-ou");
2c6b19
-		g_ptr_array_add (args, (gpointer)computer_ou);
2c6b19
+		if (ou_arg)
2c6b19
+			g_ptr_array_add (args, ou_arg);
2c6b19
+		else
2c6b19
+			g_ptr_array_add (args, (gpointer)computer_ou);
2c6b19
 	}
2c6b19
 
2c6b19
 	os = realm_settings_value ("active-directory", "os-name");
2c6b19
@@ -190,6 +196,7 @@ realm_adcli_enroll_join_async (RealmDisco *disco,
2c6b19
 	free (ccache_arg);
2c6b19
 	free (upn_arg);
2c6b19
 	free (server_arg);
2c6b19
+	free (ou_arg);
2c6b19
 }
2c6b19
 
2c6b19
 gboolean
2c6b19
diff --git a/service/realm-dn-util.c b/service/realm-dn-util.c
2c6b19
new file mode 100644
2c6b19
index 0000000..85bcdb9
2c6b19
--- /dev/null
2c6b19
+++ b/service/realm-dn-util.c
2c6b19
@@ -0,0 +1,239 @@
2c6b19
+/* realmd -- Realm configuration service
2c6b19
+ *
2c6b19
+ * Copyright 2012 Red Hat Inc
2c6b19
+ *
2c6b19
+ * This program is free software: you can redistribute it and/or modify
2c6b19
+ * it under the terms of the GNU Lesser General Public License as published
2c6b19
+ * by the Free Software Foundation; either version 2 of the licence or (at
2c6b19
+ * your option) any later version.
2c6b19
+ *
2c6b19
+ * See the included COPYING file for more information.
2c6b19
+ *
2c6b19
+ * Author: Stef Walter <stefw@gnome.org>
2c6b19
+ */
2c6b19
+
2c6b19
+#include "config.h"
2c6b19
+
2c6b19
+#include "realm-dn-util.h"
2c6b19
+
2c6b19
+#include <glib.h>
2c6b19
+
2c6b19
+#include <ldap.h>
2c6b19
+
2c6b19
+static gboolean
2c6b19
+berval_is_string (const struct berval *bv,
2c6b19
+                  const gchar *string,
2c6b19
+                  gsize length)
2c6b19
+{
2c6b19
+	return (bv->bv_len == length &&
2c6b19
+	        g_ascii_strncasecmp (bv->bv_val, string, length) == 0);
2c6b19
+
2c6b19
+}
2c6b19
+
2c6b19
+static gboolean
2c6b19
+berval_case_equals (const struct berval *v1,
2c6b19
+                    const struct berval *v2)
2c6b19
+{
2c6b19
+	return (v1->bv_len == v2->bv_len &&
2c6b19
+	        g_ascii_strncasecmp (v1->bv_val, v2->bv_val, v1->bv_len) == 0);
2c6b19
+}
2c6b19
+
2c6b19
+static gboolean
2c6b19
+dn_equals_domain (LDAPDN dn,
2c6b19
+                  const gchar *domain_dn_str,
2c6b19
+                  const gchar *domain)
2c6b19
+{
2c6b19
+	LDAPDN domain_dn;
2c6b19
+	gboolean ret;
2c6b19
+	int rc;
2c6b19
+	gint i, j;
2c6b19
+
2c6b19
+	rc = ldap_str2dn (domain_dn_str, &domain_dn, LDAP_DN_FORMAT_LDAPV3);
2c6b19
+	g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
2c6b19
+
2c6b19
+	for (i = 0; dn[i] != NULL && domain_dn[i] != NULL; i++) {
2c6b19
+		for (j = 0; dn[i][j] != NULL && domain_dn[i][j] != NULL; j++) {
2c6b19
+			if (!berval_case_equals (&(dn[i][j]->la_attr), &(domain_dn[i][j]->la_attr)) ||
2c6b19
+			    !berval_case_equals (&(dn[i][j]->la_value), &(domain_dn[i][j]->la_value)))
2c6b19
+				break;
2c6b19
+		}
2c6b19
+
2c6b19
+		if (dn[i][j] != NULL && domain_dn[i][j] != NULL)
2c6b19
+			break;
2c6b19
+	}
2c6b19
+
2c6b19
+	/* Did we reach end of both DNs? */
2c6b19
+	ret = (dn[i] == NULL && domain_dn[i] == NULL);
2c6b19
+
2c6b19
+	ldap_dnfree (domain_dn);
2c6b19
+
2c6b19
+	return ret;
2c6b19
+}
2c6b19
+
2c6b19
+gchar *
2c6b19
+realm_dn_util_build_samba_ou (const gchar *ldap_dn,
2c6b19
+                              const gchar *domain)
2c6b19
+{
2c6b19
+	gchar *domain_dn_str = NULL;
2c6b19
+	GArray *parts;
2c6b19
+	GString *part;
2c6b19
+	gchar **strv;
2c6b19
+	gchar *str;
2c6b19
+	LDAPAVA* ava;
2c6b19
+	gboolean ret;
2c6b19
+	LDAPDN dn;
2c6b19
+	int rc;
2c6b19
+	gint i, j;
2c6b19
+
2c6b19
+	/*
2c6b19
+	 * Here we convert a standard LDAP DN to the strange samba net format,
2c6b19
+	 * as "documented" here:
2c6b19
+	 *
2c6b19
+	 * createcomputer=OU  Precreate the computer account in a specific OU.
2c6b19
+	 *                    The OU string read from top to bottom without RDNs and delimited by a '/'.
2c6b19
+	 *                    E.g. "createcomputer=Computers/Servers/Unix"
2c6b19
+	 *                    NB: A backslash '\' is used as escape at multiple levels and may
2c6b19
+	 *                        need to be doubled or even quadrupled.  It is not used as a separator.
2c6b19
+	 */
2c6b19
+
2c6b19
+	/* ldap_str2dn doesn't like empty strings */
2c6b19
+	while (g_ascii_isspace (ldap_dn[0]))
2c6b19
+		ldap_dn++;
2c6b19
+	if (g_str_equal (ldap_dn, ""))
2c6b19
+		return NULL;
2c6b19
+
2c6b19
+	rc = ldap_str2dn (ldap_dn, &dn, LDAP_DN_FORMAT_LDAPV3);
2c6b19
+	if (rc != LDAP_SUCCESS)
2c6b19
+		return NULL;
2c6b19
+
2c6b19
+	ret = TRUE;
2c6b19
+	parts = g_array_new (TRUE, TRUE, sizeof (gchar *));
2c6b19
+
2c6b19
+	for (i = 0; dn[i] != NULL; i++) {
2c6b19
+		ava = dn[i][0];
2c6b19
+
2c6b19
+		/*
2c6b19
+		 * Make sure this is a valid DN, we only support one value per
2c6b19
+		 * RDN, string values, and must be an OU. DC values are allowed
2c6b19
+		 * but only at the end of the DN.
2c6b19
+		 */
2c6b19
+
2c6b19
+		if (ava == NULL || dn[i][1] != NULL || !(ava->la_flags & LDAP_AVA_STRING)) {
2c6b19
+			ret = FALSE;
2c6b19
+			break;
2c6b19
+
2c6b19
+		/* A DC, remainder must match the domain */
2c6b19
+		} else if (berval_is_string (&ava->la_attr, "DC", 2)) {
2c6b19
+			rc = ldap_domain2dn (domain, &domain_dn_str);
2c6b19
+			if (rc != LDAP_SUCCESS)
2c6b19
+				ret = FALSE;
2c6b19
+			else
2c6b19
+				ret = dn_equals_domain (dn + i, domain_dn_str, domain);
2c6b19
+			break;
2c6b19
+
2c6b19
+		/* An OU, include */
2c6b19
+		} else if (berval_is_string (&ava->la_attr, "OU", 2)) {
2c6b19
+			part = g_string_sized_new (ava->la_value.bv_len);
2c6b19
+			for (j = 0; j < ava->la_value.bv_len; j++) {
2c6b19
+				switch (ava->la_value.bv_val[j]) {
2c6b19
+				case '\\':
2c6b19
+					g_string_append (part, "\\\\");
2c6b19
+					break;
2c6b19
+				case '/':
2c6b19
+					g_string_append (part, "\\/");
2c6b19
+					break;
2c6b19
+				default:
2c6b19
+					g_string_append_c (part, ava->la_value.bv_val[j]);
2c6b19
+					break;
2c6b19
+				}
2c6b19
+			}
2c6b19
+			str = g_string_free (part, FALSE);
2c6b19
+			g_array_insert_val (parts, 0, str);
2c6b19
+
2c6b19
+		/* Invalid, stop */
2c6b19
+		} else {
2c6b19
+			ret = FALSE;
2c6b19
+			break;
2c6b19
+		}
2c6b19
+	}
2c6b19
+
2c6b19
+	ldap_dnfree (dn);
2c6b19
+	if (domain_dn_str)
2c6b19
+		ldap_memfree (domain_dn_str);
2c6b19
+
2c6b19
+	strv = (gchar **)g_array_free (parts, FALSE);
2c6b19
+	str = NULL;
2c6b19
+
2c6b19
+	/* Loop completed successfully */
2c6b19
+	if (ret)
2c6b19
+		str = g_strjoinv ("/", strv);
2c6b19
+
2c6b19
+	g_strfreev (strv);
2c6b19
+
2c6b19
+	return str;
2c6b19
+}
2c6b19
+
2c6b19
+gchar *
2c6b19
+realm_dn_util_build_qualified (const gchar *ldap_dn,
2c6b19
+                               const gchar *domain)
2c6b19
+{
2c6b19
+	gchar *domain_dn_str = NULL;
2c6b19
+	gboolean had_dc = FALSE;
2c6b19
+	gchar *str;
2c6b19
+	LDAPAVA* ava;
2c6b19
+	gboolean ret;
2c6b19
+	LDAPDN dn;
2c6b19
+	int rc;
2c6b19
+	gint i;
2c6b19
+
2c6b19
+	/* ldap_str2dn doesn't like empty strings */
2c6b19
+	while (g_ascii_isspace (ldap_dn[0]))
2c6b19
+		ldap_dn++;
2c6b19
+	if (g_str_equal (ldap_dn, ""))
2c6b19
+		return NULL;
2c6b19
+
2c6b19
+	rc = ldap_str2dn (ldap_dn, &dn, LDAP_DN_FORMAT_LDAPV3);
2c6b19
+	if (rc != LDAP_SUCCESS)
2c6b19
+		return NULL;
2c6b19
+
2c6b19
+	rc = ldap_domain2dn (domain, &domain_dn_str);
2c6b19
+	if (rc != LDAP_SUCCESS) {
2c6b19
+		ldap_dnfree (dn);
2c6b19
+		return NULL;
2c6b19
+	}
2c6b19
+
2c6b19
+	ret = TRUE;
2c6b19
+
2c6b19
+	for (i = 0; dn[i] != NULL; i++) {
2c6b19
+		ava = dn[i][0];
2c6b19
+
2c6b19
+		/*
2c6b19
+		 * Make sure this is a valid DN, we only support one value per
2c6b19
+		 * RDN, string values. DC values are allowed but only at the end of the DN.
2c6b19
+		 */
2c6b19
+
2c6b19
+		if (ava == NULL || dn[i][1] != NULL || !(ava->la_flags & LDAP_AVA_STRING)) {
2c6b19
+			ret = FALSE;
2c6b19
+			break;
2c6b19
+
2c6b19
+		/* A DC, remainder must match the domain */
2c6b19
+		} else if (berval_is_string (&ava->la_attr, "DC", 2)) {
2c6b19
+			had_dc = TRUE;
2c6b19
+			ret = dn_equals_domain (dn + i, domain_dn_str, domain);
2c6b19
+			break;
2c6b19
+		}
2c6b19
+	}
2c6b19
+
2c6b19
+	ldap_dnfree (dn);
2c6b19
+
2c6b19
+	if (!ret)
2c6b19
+		return NULL;
2c6b19
+
2c6b19
+	if (had_dc)
2c6b19
+		str = g_strdup (ldap_dn);
2c6b19
+	else
2c6b19
+		str = g_strdup_printf ("%s,%s", ldap_dn, domain_dn_str);
2c6b19
+
2c6b19
+	ldap_memfree (domain_dn_str);
2c6b19
+	return str;
2c6b19
+}
2c6b19
diff --git a/service/realm-dn-util.h b/service/realm-dn-util.h
2c6b19
new file mode 100644
2c6b19
index 0000000..f5e5e69
2c6b19
--- /dev/null
2c6b19
+++ b/service/realm-dn-util.h
2c6b19
@@ -0,0 +1,32 @@
2c6b19
+/* realmd -- Realm configuration service
2c6b19
+ *
2c6b19
+ * Copyright 2012 Red Hat Inc
2c6b19
+ *
2c6b19
+ * This program is free software: you can redistribute it and/or modify
2c6b19
+ * it under the terms of the GNU Lesser General Public License as published
2c6b19
+ * by the Free Software Foundation; either version 2 of the licence or (at
2c6b19
+ * your option) any later version.
2c6b19
+ *
2c6b19
+ * See the included COPYING file for more information.
2c6b19
+ *
2c6b19
+ * Author: Stef Walter <stefw@gnome.org>
2c6b19
+ */
2c6b19
+
2c6b19
+#include "config.h"
2c6b19
+
2c6b19
+#ifndef __REALM_DN_UTIL_H__
2c6b19
+#define __REALM_DN_UTIL_H__
2c6b19
+
2c6b19
+#include <gio/gio.h>
2c6b19
+
2c6b19
+G_BEGIN_DECLS
2c6b19
+
2c6b19
+gchar *           realm_dn_util_build_samba_ou     (const gchar *ldap_dn,
2c6b19
+                                                    const gchar *domain);
2c6b19
+
2c6b19
+gchar *           realm_dn_util_build_qualified    (const gchar *ldap_dn,
2c6b19
+                                                    const gchar *domain);
2c6b19
+
2c6b19
+G_END_DECLS
2c6b19
+
2c6b19
+#endif /* __REALM_DN_UTIL_H__ */
2c6b19
diff --git a/service/realm-samba-enroll.c b/service/realm-samba-enroll.c
2c6b19
index e8739d7..e749764 100644
2c6b19
--- a/service/realm-samba-enroll.c
2c6b19
+++ b/service/realm-samba-enroll.c
2c6b19
@@ -18,12 +18,12 @@
2c6b19
 #include "realm-daemon.h"
2c6b19
 #include "realm-dbus-constants.h"
2c6b19
 #include "realm-diagnostics.h"
2c6b19
+#include "realm-dn-util.h"
2c6b19
 #include "realm-errors.h"
2c6b19
 #include "realm-options.h"
2c6b19
 #include "realm-samba-config.h"
2c6b19
 #include "realm-samba-enroll.h"
2c6b19
 #include "realm-samba-provider.h"
2c6b19
-#include "realm-samba-util.h"
2c6b19
 #include "realm-settings.h"
2c6b19
 
2c6b19
 #include <glib/gstdio.h>
2c6b19
@@ -314,7 +314,7 @@ begin_join (GTask *task,
2c6b19
 
2c6b19
 	computer_ou = realm_options_computer_ou (options, join->disco->domain_name);
2c6b19
 	if (computer_ou != NULL) {
2c6b19
-		strange_ou = realm_samba_util_build_strange_ou (computer_ou, join->disco->domain_name);
2c6b19
+		strange_ou = realm_dn_util_build_samba_ou (computer_ou, join->disco->domain_name);
2c6b19
 		if (strange_ou) {
2c6b19
 			if (!g_str_equal (strange_ou, ""))
2c6b19
 				join->join_args[at++] = g_strdup_printf ("createcomputer=%s", strange_ou);
2c6b19
diff --git a/service/realm-samba-util.c b/service/realm-samba-util.c
2c6b19
deleted file mode 100644
2c6b19
index 3f6a53e..0000000
2c6b19
--- a/service/realm-samba-util.c
2c6b19
+++ /dev/null
2c6b19
@@ -1,172 +0,0 @@
2c6b19
-/* realmd -- Realm configuration service
2c6b19
- *
2c6b19
- * Copyright 2012 Red Hat Inc
2c6b19
- *
2c6b19
- * This program is free software: you can redistribute it and/or modify
2c6b19
- * it under the terms of the GNU Lesser General Public License as published
2c6b19
- * by the Free Software Foundation; either version 2 of the licence or (at
2c6b19
- * your option) any later version.
2c6b19
- *
2c6b19
- * See the included COPYING file for more information.
2c6b19
- *
2c6b19
- * Author: Stef Walter <stefw@gnome.org>
2c6b19
- */
2c6b19
-
2c6b19
-#include "config.h"
2c6b19
-
2c6b19
-#include "realm-samba-util.h"
2c6b19
-
2c6b19
-#include <glib.h>
2c6b19
-
2c6b19
-#include <ldap.h>
2c6b19
-
2c6b19
-static gboolean
2c6b19
-berval_is_string (const struct berval *bv,
2c6b19
-                  const gchar *string,
2c6b19
-                  gsize length)
2c6b19
-{
2c6b19
-	return (bv->bv_len == length &&
2c6b19
-	        g_ascii_strncasecmp (bv->bv_val, string, length) == 0);
2c6b19
-
2c6b19
-}
2c6b19
-
2c6b19
-static gboolean
2c6b19
-berval_case_equals (const struct berval *v1,
2c6b19
-                    const struct berval *v2)
2c6b19
-{
2c6b19
-	return (v1->bv_len == v2->bv_len &&
2c6b19
-	        g_ascii_strncasecmp (v1->bv_val, v2->bv_val, v1->bv_len) == 0);
2c6b19
-}
2c6b19
-
2c6b19
-static gboolean
2c6b19
-dn_equals_domain (LDAPDN dn,
2c6b19
-                  const gchar *domain)
2c6b19
-{
2c6b19
-	LDAPDN domain_dn;
2c6b19
-	gchar *domain_dn_str;
2c6b19
-	gboolean ret;
2c6b19
-	int rc;
2c6b19
-	gint i, j;
2c6b19
-
2c6b19
-	rc = ldap_domain2dn (domain, &domain_dn_str);
2c6b19
-	g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
2c6b19
-
2c6b19
-	rc = ldap_str2dn (domain_dn_str, &domain_dn, LDAP_DN_FORMAT_LDAPV3);
2c6b19
-	g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
2c6b19
-
2c6b19
-	ldap_memfree (domain_dn_str);
2c6b19
-
2c6b19
-	for (i = 0; dn[i] != NULL && domain_dn[i] != NULL; i++) {
2c6b19
-		for (j = 0; dn[i][j] != NULL && domain_dn[i][j] != NULL; j++) {
2c6b19
-			if (!berval_case_equals (&(dn[i][j]->la_attr), &(domain_dn[i][j]->la_attr)) ||
2c6b19
-			    !berval_case_equals (&(dn[i][j]->la_value), &(domain_dn[i][j]->la_value)))
2c6b19
-				break;
2c6b19
-		}
2c6b19
-
2c6b19
-		if (dn[i][j] != NULL && domain_dn[i][j] != NULL)
2c6b19
-			break;
2c6b19
-	}
2c6b19
-
2c6b19
-	/* Did we reach end of both DNs? */
2c6b19
-	ret = (dn[i] == NULL && domain_dn[i] == NULL);
2c6b19
-
2c6b19
-	ldap_dnfree (domain_dn);
2c6b19
-
2c6b19
-	return ret;
2c6b19
-}
2c6b19
-
2c6b19
-gchar *
2c6b19
-realm_samba_util_build_strange_ou (const gchar *ldap_dn,
2c6b19
-                                   const gchar *domain)
2c6b19
-{
2c6b19
-	GArray *parts;
2c6b19
-	GString *part;
2c6b19
-	gchar **strv;
2c6b19
-	gchar *str;
2c6b19
-	LDAPAVA* ava;
2c6b19
-	gboolean ret;
2c6b19
-	LDAPDN dn;
2c6b19
-	int rc;
2c6b19
-	gint i, j;
2c6b19
-
2c6b19
-	/*
2c6b19
-	 * Here we convert a standard LDAP DN to the strange samba net format,
2c6b19
-	 * as "documented" here:
2c6b19
-	 *
2c6b19
-	 * createcomputer=OU  Precreate the computer account in a specific OU.
2c6b19
-	 *                    The OU string read from top to bottom without RDNs and delimited by a '/'.
2c6b19
-	 *                    E.g. "createcomputer=Computers/Servers/Unix"
2c6b19
-	 *                    NB: A backslash '\' is used as escape at multiple levels and may
2c6b19
-	 *                        need to be doubled or even quadrupled.  It is not used as a separator.
2c6b19
-	 */
2c6b19
-
2c6b19
-	/* ldap_str2dn doesn't like empty strings */
2c6b19
-	while (g_ascii_isspace (ldap_dn[0]))
2c6b19
-		ldap_dn++;
2c6b19
-	if (g_str_equal (ldap_dn, ""))
2c6b19
-		return NULL;
2c6b19
-
2c6b19
-	rc = ldap_str2dn (ldap_dn, &dn, LDAP_DN_FORMAT_LDAPV3);
2c6b19
-	if (rc != LDAP_SUCCESS)
2c6b19
-		return NULL;
2c6b19
-
2c6b19
-	ret = TRUE;
2c6b19
-	parts = g_array_new (TRUE, TRUE, sizeof (gchar *));
2c6b19
-
2c6b19
-	for (i = 0; dn[i] != NULL; i++) {
2c6b19
-		ava = dn[i][0];
2c6b19
-
2c6b19
-		/*
2c6b19
-		 * Make sure this is a valid DN, we only support one value per
2c6b19
-		 * RDN, string values, and must be an OU. DC values are allowed
2c6b19
-		 * but only at the end of the DN.
2c6b19
-		 */
2c6b19
-
2c6b19
-		if (ava == NULL || dn[i][1] != NULL || !(ava->la_flags & LDAP_AVA_STRING)) {
2c6b19
-			ret = FALSE;
2c6b19
-			break;
2c6b19
-
2c6b19
-		/* A DC, remainder must match the domain */
2c6b19
-		} else if (berval_is_string (&ava->la_attr, "DC", 2)) {
2c6b19
-			ret = dn_equals_domain (dn + i, domain);
2c6b19
-			break;
2c6b19
-
2c6b19
-		/* An OU, include */
2c6b19
-		} else if (berval_is_string (&ava->la_attr, "OU", 2)) {
2c6b19
-			part = g_string_sized_new (ava->la_value.bv_len);
2c6b19
-			for (j = 0; j < ava->la_value.bv_len; j++) {
2c6b19
-				switch (ava->la_value.bv_val[j]) {
2c6b19
-				case '\\':
2c6b19
-					g_string_append (part, "\\\\");
2c6b19
-					break;
2c6b19
-				case '/':
2c6b19
-					g_string_append (part, "\\/");
2c6b19
-					break;
2c6b19
-				default:
2c6b19
-					g_string_append_c (part, ava->la_value.bv_val[j]);
2c6b19
-					break;
2c6b19
-				}
2c6b19
-			}
2c6b19
-			str = g_string_free (part, FALSE);
2c6b19
-			g_array_insert_val (parts, 0, str);
2c6b19
-
2c6b19
-		/* Invalid, stop */
2c6b19
-		} else {
2c6b19
-			ret = FALSE;
2c6b19
-			break;
2c6b19
-		}
2c6b19
-	}
2c6b19
-
2c6b19
-	ldap_dnfree (dn);
2c6b19
-
2c6b19
-	strv = (gchar **)g_array_free (parts, FALSE);
2c6b19
-	str = NULL;
2c6b19
-
2c6b19
-	/* Loop completed successfully */
2c6b19
-	if (ret)
2c6b19
-		str = g_strjoinv ("/", strv);
2c6b19
-
2c6b19
-	g_strfreev (strv);
2c6b19
-
2c6b19
-	return str;
2c6b19
-}
2c6b19
diff --git a/service/realm-samba-util.h b/service/realm-samba-util.h
2c6b19
deleted file mode 100644
2c6b19
index 2a680e7..0000000
2c6b19
--- a/service/realm-samba-util.h
2c6b19
+++ /dev/null
2c6b19
@@ -1,29 +0,0 @@
2c6b19
-/* realmd -- Realm configuration service
2c6b19
- *
2c6b19
- * Copyright 2012 Red Hat Inc
2c6b19
- *
2c6b19
- * This program is free software: you can redistribute it and/or modify
2c6b19
- * it under the terms of the GNU Lesser General Public License as published
2c6b19
- * by the Free Software Foundation; either version 2 of the licence or (at
2c6b19
- * your option) any later version.
2c6b19
- *
2c6b19
- * See the included COPYING file for more information.
2c6b19
- *
2c6b19
- * Author: Stef Walter <stefw@gnome.org>
2c6b19
- */
2c6b19
-
2c6b19
-#include "config.h"
2c6b19
-
2c6b19
-#ifndef __REALM_SAMBA_UTIL_H__
2c6b19
-#define __REALM_SAMBA_UTIL_H__
2c6b19
-
2c6b19
-#include <gio/gio.h>
2c6b19
-
2c6b19
-G_BEGIN_DECLS
2c6b19
-
2c6b19
-gchar *           realm_samba_util_build_strange_ou   (const gchar *ldap_dn,
2c6b19
-                                                       const gchar *suffix_dn);
2c6b19
-
2c6b19
-G_END_DECLS
2c6b19
-
2c6b19
-#endif /* __REALM_SAMBA_UTIL_H__ */
2c6b19
diff --git a/tests/Makefile.am b/tests/Makefile.am
2c6b19
index ddeba4d..3b05066 100644
2c6b19
--- a/tests/Makefile.am
2c6b19
+++ b/tests/Makefile.am
2c6b19
@@ -12,11 +12,11 @@ TEST_LIBS = \
2c6b19
 	$(GLIB_LIBS)
2c6b19
 
2c6b19
 TEST_PROGS = \
2c6b19
+	test-dn-util \
2c6b19
 	test-ini-config \
2c6b19
 	test-sssd-config \
2c6b19
 	test-safe-format \
2c6b19
 	test-login-name \
2c6b19
-	test-samba-ou-format \
2c6b19
 	test-settings \
2c6b19
 	$(NULL)
2c6b19
 
2c6b19
@@ -27,6 +27,13 @@ noinst_PROGRAMS +=  \
2c6b19
 	frob-install-packages \
2c6b19
 	$(NULL)
2c6b19
 
2c6b19
+test_dn_util_SOURCES = \
2c6b19
+	tests/test-dn-util.c \
2c6b19
+	service/realm-dn-util.c \
2c6b19
+	$(NULL)
2c6b19
+test_dn_util_LDADD = $(TEST_LIBS)
2c6b19
+test_dn_util_CFLAGS = $(TEST_CFLAGS)
2c6b19
+
2c6b19
 test_ini_config_SOURCES = \
2c6b19
 	tests/test-ini-config.c \
2c6b19
 	service/realm-ini-config.c \
2c6b19
@@ -59,13 +66,6 @@ test_login_name_SOURCES = \
2c6b19
 test_login_name_LDADD = $(TEST_LIBS)
2c6b19
 test_login_name_CFLAGS = $(TEST_CFLAGS)
2c6b19
 
2c6b19
-test_samba_ou_format_SOURCES = \
2c6b19
-	tests/test-samba-ou-format.c \
2c6b19
-	service/realm-samba-util.c \
2c6b19
-	$(NULL)
2c6b19
-test_samba_ou_format_LDADD = $(TEST_LIBS)
2c6b19
-test_samba_ou_format_CFLAGS = $(TEST_CFLAGS)
2c6b19
-
2c6b19
 test_settings_SOURCES = \
2c6b19
 	tests/test-settings.c \
2c6b19
 	service/realm-settings.c \
2c6b19
diff --git a/tests/test-dn-util.c b/tests/test-dn-util.c
2c6b19
new file mode 100644
2c6b19
index 0000000..c62a40f
2c6b19
--- /dev/null
2c6b19
+++ b/tests/test-dn-util.c
2c6b19
@@ -0,0 +1,129 @@
2c6b19
+/* realmd -- Realm configuration service
2c6b19
+ *
2c6b19
+ * Copyright 2012 Red Hat Inc
2c6b19
+ *
2c6b19
+ * This program is free software: you can redistribute it and/or modify
2c6b19
+ * it under the terms of the GNU Lesser General Public License as published
2c6b19
+ * by the Free Software Foundation; either version 2 of the licence or (at
2c6b19
+ * your option) any later version.
2c6b19
+ *
2c6b19
+ * See the included COPYING file for more information.
2c6b19
+ *
2c6b19
+ * Author: Stef Walter <stefw@gnome.org>
2c6b19
+ */
2c6b19
+
2c6b19
+#include "config.h"
2c6b19
+
2c6b19
+#include "service/realm-dn-util.h"
2c6b19
+
2c6b19
+#include <glib/gstdio.h>
2c6b19
+
2c6b19
+#include <string.h>
2c6b19
+
2c6b19
+typedef struct {
2c6b19
+	const gchar *ldap_dn;
2c6b19
+	const gchar *domain;
2c6b19
+	const gchar *result;
2c6b19
+} Fixture;
2c6b19
+
2c6b19
+static void
2c6b19
+test_samba_ou_format (gconstpointer user_data)
2c6b19
+{
2c6b19
+	const Fixture *fixture = user_data;
2c6b19
+	gchar *result;
2c6b19
+
2c6b19
+	result = realm_dn_util_build_samba_ou (fixture->ldap_dn, fixture->domain);
2c6b19
+	g_assert_cmpstr (result, ==, fixture->result);
2c6b19
+	g_free (result);
2c6b19
+}
2c6b19
+
2c6b19
+static const Fixture samba_ou_fixtures[] = {
2c6b19
+	{ "OU=One", "domain.example.com", "One" },
2c6b19
+	{ "OU=One,ou=two", "domain.example.com", "two/One" },
2c6b19
+	{ "Ou=One Long,OU=two", "domain.example.com", "two/One Long" },
2c6b19
+	{ "Ou=One,OU=two, ou=Three", "domain.example.com", "Three/two/One" },
2c6b19
+	{ "Ou=Test/Escape,Ou=Two", "domain.example.com", "Two/Test\\/Escape" },
2c6b19
+	{ "Ou=Test\\\\Escape,Ou=Two", "domain.example.com", "Two/Test\\\\Escape" },
2c6b19
+	{ "OU=One,DC=domain,dc=example,Dc=COM", "domain.example.com", "One" },
2c6b19
+	{ "OU=One,OU=Two Here,DC=domain,dc=example,Dc=COM", "domain.example.com", "Two Here/One" },
2c6b19
+	{ "OU=One,OU=Two Here,DC=invalid,Dc=COM", "domain.example.com", NULL },
2c6b19
+	{ " ", "domain.example.com", NULL },
2c6b19
+	{ "", "domain.example.com", NULL },
2c6b19
+	{ "OU", "domain.example.com", NULL },
2c6b19
+	{ "OU=One,", "domain.example.com", NULL },
2c6b19
+	{ "CN=Unsupported", "domain.example.com", NULL },
2c6b19
+	{ "OU=One+CN=Unsupported", "domain.example.com", NULL },
2c6b19
+	{ "DC=radi07, DC=segad, DC=lab, DC=sjc, DC=redhat, DC=com", "radi08.segad.lab.sjc.redhat.com", NULL },
2c6b19
+
2c6b19
+};
2c6b19
+
2c6b19
+static void
2c6b19
+test_qualify_dn (gconstpointer user_data)
2c6b19
+{
2c6b19
+	const Fixture *fixture = user_data;
2c6b19
+	gchar *result;
2c6b19
+
2c6b19
+	result = realm_dn_util_build_qualified (fixture->ldap_dn, fixture->domain);
2c6b19
+	g_assert_cmpstr (result, ==, fixture->result);
2c6b19
+	g_free (result);
2c6b19
+}
2c6b19
+
2c6b19
+static const Fixture qualify_fixtures[] = {
2c6b19
+	{ "OU=One", "domain.example.com", "OU=One,dc=domain,dc=example,dc=com" },
2c6b19
+	{ "OU=One,ou=two", "domain.example.com", "OU=One,ou=two,dc=domain,dc=example,dc=com" },
2c6b19
+	{ "Ou=One Long,OU=two", "domain.example.com", "Ou=One Long,OU=two,dc=domain,dc=example,dc=com" },
2c6b19
+	{ "OU=One,DC=domain,dc=example,Dc=COM", "domain.example.com", "OU=One,DC=domain,dc=example,Dc=COM" },
2c6b19
+	{ "OU=One,OU=Two Here,DC=domain,dc=example,Dc=COM", "domain.example.com", "OU=One,OU=Two Here,DC=domain,dc=example,Dc=COM" },
2c6b19
+	{ "OU=One,OU=Two Here,DC=invalid,Dc=COM", "domain.example.com", NULL },
2c6b19
+	{ " ", "domain.example.com", NULL },
2c6b19
+	{ "", "domain.example.com", NULL },
2c6b19
+	{ "OU", "domain.example.com", NULL },
2c6b19
+	{ "OU=One,", "domain.example.com", NULL },
2c6b19
+	{ "CN=Test", "domain.example.com", "CN=Test,dc=domain,dc=example,dc=com" },
2c6b19
+	{ "OU=One+CN=Unsupported", "domain.example.com", NULL },
2c6b19
+	{ "DC=radi07, DC=segad, DC=lab, DC=sjc, DC=redhat, DC=com", "radi08.segad.lab.sjc.redhat.com", NULL },
2c6b19
+};
2c6b19
+
2c6b19
+int
2c6b19
+main (int argc,
2c6b19
+      char **argv)
2c6b19
+{
2c6b19
+	gchar *escaped;
2c6b19
+	gchar *name;
2c6b19
+	gint i;
2c6b19
+
2c6b19
+#if !GLIB_CHECK_VERSION(2, 36, 0)
2c6b19
+	g_type_init ();
2c6b19
+#endif
2c6b19
+
2c6b19
+	g_test_init (&argc, &argv, NULL);
2c6b19
+	g_set_prgname ("test-dn-util");
2c6b19
+
2c6b19
+	for (i = 0; i < G_N_ELEMENTS (samba_ou_fixtures); i++) {
2c6b19
+		if (g_str_equal (samba_ou_fixtures[i].ldap_dn, ""))
2c6b19
+			escaped = g_strdup ("_empty_");
2c6b19
+		else
2c6b19
+			escaped = g_strdup (samba_ou_fixtures[i].ldap_dn);
2c6b19
+		g_strdelimit (escaped, ", =\\/", '_');
2c6b19
+		name = g_strdup_printf ("/realmd/samba-ou-format/%s", escaped);
2c6b19
+		g_free (escaped);
2c6b19
+
2c6b19
+		g_test_add_data_func (name, samba_ou_fixtures + i, test_samba_ou_format);
2c6b19
+		g_free (name);
2c6b19
+	}
2c6b19
+
2c6b19
+	for (i = 0; i < G_N_ELEMENTS (qualify_fixtures); i++) {
2c6b19
+		if (g_str_equal (qualify_fixtures[i].ldap_dn, ""))
2c6b19
+			escaped = g_strdup ("_empty_");
2c6b19
+		else
2c6b19
+			escaped = g_strdup (qualify_fixtures[i].ldap_dn);
2c6b19
+		g_strdelimit (escaped, ", =\\/", '_');
2c6b19
+		name = g_strdup_printf ("/realmd/qualify-dn/%s", escaped);
2c6b19
+		g_free (escaped);
2c6b19
+
2c6b19
+		g_test_add_data_func (name, qualify_fixtures + i, test_qualify_dn);
2c6b19
+		g_free (name);
2c6b19
+	}
2c6b19
+
2c6b19
+	return g_test_run ();
2c6b19
+}
2c6b19
diff --git a/tests/test-samba-ou-format.c b/tests/test-samba-ou-format.c
2c6b19
deleted file mode 100644
2c6b19
index 0a482ee..0000000
2c6b19
--- a/tests/test-samba-ou-format.c
2c6b19
+++ /dev/null
2c6b19
@@ -1,89 +0,0 @@
2c6b19
-/* realmd -- Realm configuration service
2c6b19
- *
2c6b19
- * Copyright 2012 Red Hat Inc
2c6b19
- *
2c6b19
- * This program is free software: you can redistribute it and/or modify
2c6b19
- * it under the terms of the GNU Lesser General Public License as published
2c6b19
- * by the Free Software Foundation; either version 2 of the licence or (at
2c6b19
- * your option) any later version.
2c6b19
- *
2c6b19
- * See the included COPYING file for more information.
2c6b19
- *
2c6b19
- * Author: Stef Walter <stefw@gnome.org>
2c6b19
- */
2c6b19
-
2c6b19
-#include "config.h"
2c6b19
-
2c6b19
-#include "service/realm-samba-util.h"
2c6b19
-
2c6b19
-#include <glib/gstdio.h>
2c6b19
-
2c6b19
-#include <string.h>
2c6b19
-
2c6b19
-typedef struct {
2c6b19
-	const gchar *ldap_dn;
2c6b19
-	const gchar *domain;
2c6b19
-	const gchar *ou_format;
2c6b19
-} Fixture;
2c6b19
-
2c6b19
-static void
2c6b19
-test_samba_ou_format (gconstpointer user_data)
2c6b19
-{
2c6b19
-	const Fixture *fixture = user_data;
2c6b19
-	gchar *result;
2c6b19
-
2c6b19
-	result = realm_samba_util_build_strange_ou (fixture->ldap_dn, fixture->domain);
2c6b19
-	g_assert_cmpstr (result, ==, fixture->ou_format);
2c6b19
-	g_free (result);
2c6b19
-}
2c6b19
-
2c6b19
-static const Fixture samba_ou_fixtures[] = {
2c6b19
-	{ "OU=One", "domain.example.com", "One" },
2c6b19
-	{ "OU=One,ou=two", "domain.example.com", "two/One" },
2c6b19
-	{ "Ou=One Long,OU=two", "domain.example.com", "two/One Long" },
2c6b19
-	{ "Ou=One,OU=two, ou=Three", "domain.example.com", "Three/two/One" },
2c6b19
-	{ "Ou=Test/Escape,Ou=Two", "domain.example.com", "Two/Test\\/Escape" },
2c6b19
-	{ "Ou=Test\\\\Escape,Ou=Two", "domain.example.com", "Two/Test\\\\Escape" },
2c6b19
-	{ "OU=One,DC=domain,dc=example,Dc=COM", "domain.example.com", "One" },
2c6b19
-	{ "OU=One,OU=Two Here,DC=domain,dc=example,Dc=COM", "domain.example.com", "Two Here/One" },
2c6b19
-	{ "OU=One,OU=Two Here,DC=invalid,Dc=COM", "domain.example.com", NULL },
2c6b19
-	{ " ", "domain.example.com", NULL },
2c6b19
-	{ "", "domain.example.com", NULL },
2c6b19
-	{ "OU", "domain.example.com", NULL },
2c6b19
-	{ "OU=One,", "domain.example.com", NULL },
2c6b19
-	{ "CN=Unsupported", "domain.example.com", NULL },
2c6b19
-	{ "OU=One+CN=Unsupported", "domain.example.com", NULL },
2c6b19
-	{ "DC=radi07, DC=segad, DC=lab, DC=sjc, DC=redhat, DC=com", "radi08.segad.lab.sjc.redhat.com", NULL },
2c6b19
-
2c6b19
-};
2c6b19
-
2c6b19
-int
2c6b19
-main (int argc,
2c6b19
-      char **argv)
2c6b19
-{
2c6b19
-	gchar *escaped;
2c6b19
-	gchar *name;
2c6b19
-	gint i;
2c6b19
-
2c6b19
-#if !GLIB_CHECK_VERSION(2, 36, 0)
2c6b19
-	g_type_init ();
2c6b19
-#endif
2c6b19
-
2c6b19
-	g_test_init (&argc, &argv, NULL);
2c6b19
-	g_set_prgname ("test-samba-ou-format");
2c6b19
-
2c6b19
-	for (i = 0; i < G_N_ELEMENTS (samba_ou_fixtures); i++) {
2c6b19
-		if (g_str_equal (samba_ou_fixtures[i].ldap_dn, ""))
2c6b19
-			escaped = g_strdup ("_empty_");
2c6b19
-		else
2c6b19
-			escaped = g_strdup (samba_ou_fixtures[i].ldap_dn);
2c6b19
-		g_strdelimit (escaped, ", =\\/", '_');
2c6b19
-		name = g_strdup_printf ("/realmd/samba-ou-format/%s", escaped);
2c6b19
-		g_free (escaped);
2c6b19
-
2c6b19
-		g_test_add_data_func (name, samba_ou_fixtures + i, test_samba_ou_format);
2c6b19
-		g_free (name);
2c6b19
-	}
2c6b19
-
2c6b19
-	return g_test_run ();
2c6b19
-}
2c6b19
-- 
2c6b19
2.7.4
2c6b19