[PATCH] Harden Samba module functions

Andreas Schneider asn at samba.org
Thu Jun 1 08:15:59 UTC 2017


On Wednesday, 31 May 2017 19:50:49 CEST Jeremy Allison wrote:
> On Wed, May 31, 2017 at 11:24:45AM +0200, Andreas Schneider wrote:
> > On Wednesday, 31 May 2017 11:19:18 CEST Volker Lendecke wrote:
> > > On Wed, May 31, 2017 at 11:15:42AM +0200, Andreas Schneider wrote:
> > > > On Wednesday, 31 May 2017 11:03:03 CEST Volker Lendecke wrote:
> > > > > On Wed, May 31, 2017 at 10:48:09AM +0200, Andreas Schneider via
> > > > > samba-
> > > > 
> > > > technical wrote:
> > > > > > > The same here, why do we need to skip loading the module
> > > > > > > depending
> > > > > > > on
> > > > > > > a specific name at all, I'd like to avoid a having this code at
> > > > > > > all.
> > > > > > 
> > > > > > If the module is in the modules directory, smbd automatically
> > > > > > loads it
> > > > > > ...
> > > > > 
> > > > > Can't you change the dummy module to be less harmful, so that it can
> > > > > be loaded?
> > > > 
> > > > If you have a better idea how to fail if the module gets loaded ...
> > > 
> > > Can you describe the bigger picture? Do you need to test the failure
> > > paths for module initialization failure?
> > 
> > We have a test and in that test we want to make sure that the tests fails
> > if the module is loaded using the absolute path. So if the module is
> > loaded we need to fail the test ...
> 
> So I really like the module hardening changes so far, and once
> we've gotten the test methodology sorted out I plan to push.
> 
> (Just wanted to let you know I've reviewed).

Take a look at this patchset.


	Andreas


-- 
Andreas Schneider                   GPG-ID: CC014E3D
Samba Team                             asn at samba.org
www.samba.org
-------------- next part --------------
>From 9e26df7199726e7c44cb3857b5c24178ddb3ea75 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 11 May 2017 11:29:50 +0200
Subject: [PATCH 1/7] wafsamba: Pass down the install argument for samba
 modules

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 buildtools/wafsamba/wafsamba.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index 137cb0e4330..1bdabf60640 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -465,7 +465,8 @@ def SAMBA_MODULE(bld, modname, source,
                  pyembed=False,
                  manpages=None,
                  allow_undefined_symbols=False,
-                 allow_warnings=False
+                 allow_warnings=False,
+                 install=True
                  ):
     '''define a Samba module.'''
 
@@ -535,7 +536,8 @@ def SAMBA_MODULE(bld, modname, source,
                       pyembed=pyembed,
                       manpages=manpages,
                       allow_undefined_symbols=allow_undefined_symbols,
-                      allow_warnings=allow_warnings
+                      allow_warnings=allow_warnings,
+                      install=install
                       )
 
 
-- 
2.13.0


>From d59b92b556ac139c3ee08d44cea45e682de642d8 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 11 May 2017 11:29:25 +0200
Subject: [PATCH 2/7] unittest: Add testsuite for is_known_pipename()

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

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/tests.py                           |   2 +
 testsuite/unittests/rpc_test_dummy_module.c |  39 ++++++++++
 testsuite/unittests/test_sambafs_srv_pipe.c | 110 ++++++++++++++++++++++++++++
 testsuite/unittests/wscript                 |  16 ++++
 4 files changed, 167 insertions(+)
 create mode 100644 testsuite/unittests/rpc_test_dummy_module.c
 create mode 100644 testsuite/unittests/test_sambafs_srv_pipe.c

diff --git a/selftest/tests.py b/selftest/tests.py
index e3dd91414d9..9f298a6f734 100644
--- a/selftest/tests.py
+++ b/selftest/tests.py
@@ -145,3 +145,5 @@ if with_pam:
 if with_cmocka:
     plantestsuite("samba.unittests.krb5samba", "none",
                   [os.path.join(bindir(), "default/testsuite/unittests/test_krb5samba")])
+    plantestsuite("samba.unittests.sambafs_srv_pipe", "none",
+                  [os.path.join(bindir(), "default/testsuite/unittests/test_sambafs_srv_pipe")])
diff --git a/testsuite/unittests/rpc_test_dummy_module.c b/testsuite/unittests/rpc_test_dummy_module.c
new file mode 100644
index 00000000000..8872fe33a4b
--- /dev/null
+++ b/testsuite/unittests/rpc_test_dummy_module.c
@@ -0,0 +1,39 @@
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+int samba_init_module(void);
+int samba_init_module(void)
+{
+	char path[1024] = {0};
+	const char *tmpdir = getenv("TMPDIR");
+	mode_t mode = 0644;
+	int rc;
+	int fd;
+
+	fprintf(stderr, "Test dummy executed!\n");
+
+	if (tmpdir == NULL) {
+		kill(getpid(), SIGILL);
+		exit(-1);
+	}
+
+	rc = snprintf(path, sizeof(path),
+		      "%s/samba_load_module_test_failed", tmpdir);
+	if (rc < 0) {
+		kill(getpid(), SIGILL);
+		exit(-1);
+	}
+
+	fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
+	if (fd < 0) {
+		kill(getpid(), SIGILL);
+		exit(-1);
+	}
+	close(fd);
+
+	return 0;
+}
diff --git a/testsuite/unittests/test_sambafs_srv_pipe.c b/testsuite/unittests/test_sambafs_srv_pipe.c
new file mode 100644
index 00000000000..187b923a217
--- /dev/null
+++ b/testsuite/unittests/test_sambafs_srv_pipe.c
@@ -0,0 +1,110 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <cmocka.h>
+
+#include "include/config.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "source3/rpc_server/srv_pipe.h"
+#include "librpc/gen_ndr/srv_samr.h"
+
+static int setup(void **state)
+{
+	const char *tmpdir = getenv("TMPDIR");
+	char *path = NULL;
+	int rc;
+
+	if (tmpdir == NULL || tmpdir[0] == '\0') {
+		tmpdir = "/tmp";
+	}
+
+	rc = asprintf(&path, "%s/samba_load_module_test_failed", tmpdir);
+	if (rc < 0) {
+		return -1;
+	}
+	unlink(path);
+
+	*state = path;
+	return 0;
+}
+
+static int setup_samr(void **state)
+{
+	int rc;
+
+	rc = setup(state);
+	if (rc != 0) {
+		return rc;
+	}
+
+	rpc_samr_init(NULL);
+
+	return 0;
+}
+
+static int teardown(void **state)
+{
+	char *path = (char *)*state;
+
+	unlink(path);
+	free(path);
+
+	return 0;
+}
+
+static int teardown_samr(void **state)
+{
+	rpc_samr_shutdown();
+
+	teardown(state);
+
+	return 0;
+}
+
+static void test_is_known_pipename(void **state)
+{
+	struct ndr_syntax_id syntax_id = ndr_table_samr.syntax_id;
+	bool is_pipename_ok;
+
+	is_pipename_ok = is_known_pipename("samr", &syntax_id);
+	assert_true(is_pipename_ok);
+}
+
+static void test_is_known_pipename_slash(void **state)
+{
+	struct ndr_syntax_id syntax_id = ndr_table_samr.syntax_id;
+	bool is_pipename_ok;
+	char dummy_module_path[4096] = {0};
+	const char *fail_path = (const char *)*state;
+	struct stat sb;
+	int rc;
+
+	snprintf(dummy_module_path,
+		 sizeof(dummy_module_path),
+		 "%s/bin/modules/rpc/test_dummy_module.so",
+		 SRCDIR);
+
+	is_pipename_ok = is_known_pipename(dummy_module_path, &syntax_id);
+	assert_false(is_pipename_ok);
+
+	rc = lstat(fail_path, &sb);
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, ENOENT);
+}
+
+int main(void) {
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test_setup_teardown(test_is_known_pipename,
+						setup_samr,
+						teardown_samr),
+		cmocka_unit_test_setup_teardown(test_is_known_pipename_slash,
+						setup,
+						teardown),
+	};
+
+	cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/testsuite/unittests/wscript b/testsuite/unittests/wscript
index 355ab0cc10a..6edad7d701c 100644
--- a/testsuite/unittests/wscript
+++ b/testsuite/unittests/wscript
@@ -10,3 +10,19 @@ def build(bld):
                      source='test_krb5_samba.c',
                      deps='krb5samba cmocka',
                      install=False)
+
+    bld.SAMBA_BINARY('test_sambafs_srv_pipe',
+                     source='test_sambafs_srv_pipe.c',
+                     deps='''
+                          RPC_SERVER
+                          RPC_SAMR
+                          cmocka
+                          ''',
+                     install=False)
+
+    bld.SAMBA_MODULE('rpc_test_dummy_module',
+                     source='rpc_test_dummy_module.c',
+                     subsystem='rpc',
+                     allow_undefined_symbols=True,
+                     init_function='',
+                     internal_module=False)
-- 
2.13.0


>From ca04836e1b61c112d737b7b26040ac7aa8ff9bc7 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 15 May 2017 09:06:51 +0200
Subject: [PATCH 3/7] lib:util: Add new function to load modules from absolute
 path

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

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 lib/util/modules.c | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/lib/util/modules.c b/lib/util/modules.c
index c3c05f21f33..c693e5f32bb 100644
--- a/lib/util/modules.c
+++ b/lib/util/modules.c
@@ -147,6 +147,36 @@ init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem)
 	return ret;
 }
 
+static NTSTATUS load_module_absolute_path(const char *module_path,
+					  bool is_probe)
+{
+	void *handle;
+	init_module_fn init;
+	NTSTATUS status;
+
+	DBG_INFO("%s module '%s'\n",
+		 is_probe ? "Probing" : "Loading",
+		 module_path);
+
+	init = load_module(module_path, is_probe, &handle);
+	if (init == NULL) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+
+	DBG_NOTICE("Module '%s' loaded\n", module_path);
+
+	status = init(NULL);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("Module '%s' initialization failed: %s\n",
+			module_path,
+			get_friendly_nt_error_msg(status));
+		dlclose(handle);
+		return status;
+	}
+
+	return NT_STATUS_OK;
+}
+
 
 /* Load a dynamic module.  Only log a level 0 error if we are not checking
    for the existence of a module (probling). */
@@ -212,8 +242,16 @@ int smb_load_modules(const char **modules)
 	int i;
 	int success = 0;
 
-	for(i = 0; modules[i]; i++){
-		if(NT_STATUS_IS_OK(do_smb_load_module(NULL, modules[i], false))) {
+	for(i = 0; modules[i] != NULL; i++) {
+		const char *module = modules[i];
+		NTSTATUS status;
+
+		if (module[0] != '/') {
+			continue;
+		}
+
+		status = load_module_absolute_path(module, false);
+		if (NT_STATUS_IS_OK(status)) {
 			success++;
 		}
 	}
-- 
2.13.0


>From 6a1093584778b2dcdc6d1c92576e8ab9c7fe4bea Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 15 May 2017 10:49:07 +0200
Subject: [PATCH 4/7] lib:util: Rename smb_load_modules()

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

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 lib/util/modules.c       | 2 +-
 lib/util/samba_modules.h | 2 +-
 source3/smbd/process.c   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/util/modules.c b/lib/util/modules.c
index c693e5f32bb..e8a86c47fdf 100644
--- a/lib/util/modules.c
+++ b/lib/util/modules.c
@@ -237,7 +237,7 @@ static NTSTATUS do_smb_load_module(const char *subsystem,
 
 /* Load all modules in list and return number of
  * modules that has been successfully loaded */
-int smb_load_modules(const char **modules)
+int smb_load_all_modules_absoute_path(const char **modules)
 {
 	int i;
 	int success = 0;
diff --git a/lib/util/samba_modules.h b/lib/util/samba_modules.h
index 1ae9c6e0e90..d7a452159ab 100644
--- a/lib/util/samba_modules.h
+++ b/lib/util/samba_modules.h
@@ -53,7 +53,7 @@ bool run_init_functions(TALLOC_CTX *ctx, init_module_fn *fns);
  */
 init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem);
 
-int smb_load_modules(const char **modules);
+int smb_load_all_modules_absoute_path(const char **modules);
 NTSTATUS smb_probe_module(const char *subsystem, const char *module);
 NTSTATUS smb_load_module(const char *subsystem, const char *module);
 
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 8f097ecbc00..d5c03b94199 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -4018,7 +4018,7 @@ void smbd_process(struct tevent_context *ev_ctx,
 			   locaddr);
 
 	if (lp_preload_modules()) {
-		smb_load_modules(lp_preload_modules());
+		smb_load_all_modules_absoute_path(lp_preload_modules());
 	}
 
 	smb_perfcount_init();
-- 
2.13.0


>From 081e47e4da02d137f098f3cf25c896391b638701 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 15 May 2017 11:05:59 +0200
Subject: [PATCH 5/7] lib:util: Make probing of modules more secure

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

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 lib/util/modules.c       | 66 +++++++++++++++++++++++++++++++++++++++++++++++-
 lib/util/samba_modules.h |  1 +
 source3/smbd/perfcount.c |  2 +-
 3 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/lib/util/modules.c b/lib/util/modules.c
index e8a86c47fdf..978053e367b 100644
--- a/lib/util/modules.c
+++ b/lib/util/modules.c
@@ -261,9 +261,73 @@ int smb_load_all_modules_absoute_path(const char **modules)
 	return success;
 }
 
+/**
+ * @brief Check if a module exist and load it.
+ *
+ * @param[in]  subsystem  The name of the subsystem the module belongs too.
+ *
+ * @param[in]  module     The name of the module
+ *
+ * @return  A NTSTATUS code
+ */
 NTSTATUS smb_probe_module(const char *subsystem, const char *module)
 {
-	return do_smb_load_module(subsystem, module, true);
+	NTSTATUS status;
+	char *module_path = NULL;
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+	if (subsystem == NULL) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto done;
+	}
+	if (module == NULL) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto done;
+	}
+
+	if (strchr(module, '/')) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto done;
+	}
+
+	module_path = talloc_asprintf(tmp_ctx,
+				      "%s/%s.%s",
+				      modules_path(tmp_ctx, subsystem),
+				      module,
+				      shlib_ext());
+	if (module_path == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto done;
+	}
+
+	status = load_module_absolute_path(module_path, true);
+
+done:
+	TALLOC_FREE(tmp_ctx);
+	return status;
+}
+
+/**
+ * @brief Check if a module exist and load it.
+ *
+ * Warning: Using this function can have security implecations!
+ *
+ * @param[in]  subsystem  The name of the subsystem the module belongs too.
+ *
+ * @param[in]  module     Load a module using an abolute path.
+ *
+ * @return  A NTSTATUS code
+ */
+NTSTATUS smb_probe_module_absolute_path(const char *module)
+{
+	if (module == NULL) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+	if (module[0] != '/') {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	return load_module_absolute_path(module, true);
 }
 
 NTSTATUS smb_load_module(const char *subsystem, const char *module)
diff --git a/lib/util/samba_modules.h b/lib/util/samba_modules.h
index d7a452159ab..c6986910c38 100644
--- a/lib/util/samba_modules.h
+++ b/lib/util/samba_modules.h
@@ -55,6 +55,7 @@ init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem);
 
 int smb_load_all_modules_absoute_path(const char **modules);
 NTSTATUS smb_probe_module(const char *subsystem, const char *module);
+NTSTATUS smb_probe_module_absolute_path(const char *module);
 NTSTATUS smb_load_module(const char *subsystem, const char *module);
 
 #endif /* _SAMBA_MODULES_H */
diff --git a/source3/smbd/perfcount.c b/source3/smbd/perfcount.c
index a7c268a2fef..1555ea24b64 100644
--- a/source3/smbd/perfcount.c
+++ b/source3/smbd/perfcount.c
@@ -144,7 +144,7 @@ static bool smb_load_perfcount_module(const char *name)
 
 	/* load the perfcounter module */
 	if((entry = smb_perfcount_find_module(module_name)) ||
-	   (NT_STATUS_IS_OK(smb_probe_module("perfcount", module_path)) &&
+	   (NT_STATUS_IS_OK(smb_probe_module_absolute_path(module_path)) &&
 		(entry = smb_perfcount_find_module(module_name)))) {
 
 		DEBUG(3,("Successfully loaded perfcounter module [%s] \n", name));
-- 
2.13.0


>From bee56dd12046abdee044f93ebf5732298cbbcc96 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 15 May 2017 11:08:19 +0200
Subject: [PATCH 6/7] lib:util: Make loading of modules more secure

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

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 lib/util/modules.c | 101 ++++++++++++++++++++++-------------------------------
 1 file changed, 42 insertions(+), 59 deletions(-)

diff --git a/lib/util/modules.c b/lib/util/modules.c
index 978053e367b..cf52594f619 100644
--- a/lib/util/modules.c
+++ b/lib/util/modules.c
@@ -177,64 +177,6 @@ static NTSTATUS load_module_absolute_path(const char *module_path,
 	return NT_STATUS_OK;
 }
 
-
-/* Load a dynamic module.  Only log a level 0 error if we are not checking
-   for the existence of a module (probling). */
-
-static NTSTATUS do_smb_load_module(const char *subsystem,
-				   const char *module_name, bool is_probe)
-{
-	void *handle;
-	init_module_fn init;
-	NTSTATUS status;
-
-	char *full_path = NULL;
-	TALLOC_CTX *ctx = talloc_stackframe();
-
-	if (module_name == NULL) {
-		TALLOC_FREE(ctx);
-		return NT_STATUS_INVALID_PARAMETER;
-	}
-
-	/* Check for absolute path */
-
-	DEBUG(5, ("%s module '%s'\n", is_probe ? "Probing" : "Loading", module_name));
-
-	if (subsystem && module_name[0] != '/') {
-		full_path = talloc_asprintf(ctx,
-					    "%s/%s.%s",
-					    modules_path(ctx, subsystem),
-					    module_name,
-					    shlib_ext());
-		if (!full_path) {
-			TALLOC_FREE(ctx);
-			return NT_STATUS_NO_MEMORY;
-		}
-
-		DEBUG(5, ("%s module '%s': Trying to load from %s\n",
-			  is_probe ? "Probing": "Loading", module_name, full_path));
-		init = load_module(full_path, is_probe, &handle);
-	} else {
-		init = load_module(module_name, is_probe, &handle);
-	}
-
-	if (!init) {
-		TALLOC_FREE(ctx);
-		return NT_STATUS_UNSUCCESSFUL;
-	}
-
-	DEBUG(2, ("Module '%s' loaded\n", module_name));
-
-	status = init(NULL);
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("Module '%s' initialization failed: %s\n",
-			  module_name, get_friendly_nt_error_msg(status)));
-		dlclose(handle);
-	}
-	TALLOC_FREE(ctx);
-	return status;
-}
-
 /* Load all modules in list and return number of
  * modules that has been successfully loaded */
 int smb_load_all_modules_absoute_path(const char **modules)
@@ -330,7 +272,48 @@ NTSTATUS smb_probe_module_absolute_path(const char *module)
 	return load_module_absolute_path(module, true);
 }
 
+/**
+ * @brief Load a module.
+ *
+ * @param[in]  subsystem  The name of the subsystem the module belongs too.
+ *
+ * @param[in]  module     Check if a module exists and load it.
+ *
+ * @return  A NTSTATUS code
+ */
 NTSTATUS smb_load_module(const char *subsystem, const char *module)
 {
-	return do_smb_load_module(subsystem, module, false);
+	NTSTATUS status;
+	char *module_path = NULL;
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+	if (subsystem == NULL) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto done;
+	}
+	if (module == NULL) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto done;
+	}
+
+	if (strchr(module, '/')) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto done;
+	}
+
+	module_path = talloc_asprintf(tmp_ctx,
+				      "%s/%s.%s",
+				      modules_path(tmp_ctx, subsystem),
+				      module,
+				      shlib_ext());
+	if (module_path == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto done;
+	}
+
+	status = load_module_absolute_path(module_path, false);
+
+done:
+	TALLOC_FREE(tmp_ctx);
+	return status;
 }
-- 
2.13.0


>From 5f1b48d4523ab4cd262d61f8e112a6de8715b8fa Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 12 May 2017 14:13:42 +0200
Subject: [PATCH 7/7] unittest: Add testsuite for smb_probe_module()

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

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/tests.py                           |  2 +
 testsuite/unittests/test_lib_util_modules.c | 87 +++++++++++++++++++++++++++++
 testsuite/unittests/wscript                 |  8 +++
 3 files changed, 97 insertions(+)
 create mode 100644 testsuite/unittests/test_lib_util_modules.c

diff --git a/selftest/tests.py b/selftest/tests.py
index 9f298a6f734..b9c470c557a 100644
--- a/selftest/tests.py
+++ b/selftest/tests.py
@@ -147,3 +147,5 @@ if with_cmocka:
                   [os.path.join(bindir(), "default/testsuite/unittests/test_krb5samba")])
     plantestsuite("samba.unittests.sambafs_srv_pipe", "none",
                   [os.path.join(bindir(), "default/testsuite/unittests/test_sambafs_srv_pipe")])
+    plantestsuite("samba.unittests.lib_util_modules", "none",
+                  [os.path.join(bindir(), "default/testsuite/unittests/test_lib_util_modules")])
diff --git a/testsuite/unittests/test_lib_util_modules.c b/testsuite/unittests/test_lib_util_modules.c
new file mode 100644
index 00000000000..14dfeb5229d
--- /dev/null
+++ b/testsuite/unittests/test_lib_util_modules.c
@@ -0,0 +1,87 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <talloc.h>
+
+#include "include/config.h"
+#include "libcli/util/ntstatus.h"
+#include "lib/util/samba_modules.h"
+
+static int setup(void **state)
+{
+	const char *tmpdir = getenv("TMPDIR");
+	char *path = NULL;
+	int rc;
+
+	if (tmpdir == NULL || tmpdir[0] == '\0') {
+		tmpdir = "/tmp";
+	}
+
+	rc = asprintf(&path, "%s/samba_load_module_test_failed", tmpdir);
+	if (rc < 0) {
+		return -1;
+	}
+	unlink(path);
+
+	*state = path;
+	return 0;
+}
+
+static int teardown(void **state)
+{
+	char *path = (char *)*state;
+
+	unlink(path);
+	free(path);
+
+	return 0;
+}
+
+static void test_samba_module_probe(void **state)
+{
+	NTSTATUS status;
+
+	status = smb_probe_module("auth", "skel");
+	assert_true(NT_STATUS_IS_OK(status));
+}
+
+static void test_samba_module_probe_slash(void **state)
+{
+	char dummy_module_path[4096] = {0};
+	const char *fail_path = (const char *)*state;
+	struct stat sb;
+	int rc;
+	NTSTATUS status;
+
+	snprintf(dummy_module_path,
+		 sizeof(dummy_module_path),
+		 "%s/bin/modules/rpc/test_dummy_module.so",
+		 SRCDIR);
+
+	status = smb_probe_module("rpc", dummy_module_path);
+	assert_true(NT_STATUS_IS_ERR(status));
+
+	rc = lstat(fail_path, &sb);
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, ENOENT);
+}
+
+int main(void) {
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(test_samba_module_probe),
+		cmocka_unit_test_setup_teardown(test_samba_module_probe_slash,
+						setup,
+						teardown),
+	};
+
+	cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/testsuite/unittests/wscript b/testsuite/unittests/wscript
index 6edad7d701c..4bbc18416da 100644
--- a/testsuite/unittests/wscript
+++ b/testsuite/unittests/wscript
@@ -20,6 +20,14 @@ def build(bld):
                           ''',
                      install=False)
 
+    bld.SAMBA_BINARY('test_lib_util_modules',
+                     source='test_lib_util_modules.c',
+                     deps='''
+                          samba-modules
+                          cmocka
+                          ''',
+                     install=False)
+
     bld.SAMBA_MODULE('rpc_test_dummy_module',
                      source='rpc_test_dummy_module.c',
                      subsystem='rpc',
-- 
2.13.0



More information about the samba-technical mailing list