summaryrefslogtreecommitdiffstats
path: root/source4/torture/libsmbclient
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source4/torture/libsmbclient
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/torture/libsmbclient')
-rw-r--r--source4/torture/libsmbclient/libsmbclient.c1617
-rw-r--r--source4/torture/libsmbclient/wscript_build14
2 files changed, 1631 insertions, 0 deletions
diff --git a/source4/torture/libsmbclient/libsmbclient.c b/source4/torture/libsmbclient/libsmbclient.c
new file mode 100644
index 0000000..72af8fc
--- /dev/null
+++ b/source4/torture/libsmbclient/libsmbclient.c
@@ -0,0 +1,1617 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Guenther Deschner 2010
+
+ 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 "includes.h"
+#include "system/dir.h"
+#include "torture/smbtorture.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include <libsmbclient.h>
+#include "torture/libsmbclient/proto.h"
+#include "lib/param/loadparm.h"
+#include "lib/param/param_global.h"
+#include "libcli/smb/smb_constants.h"
+#include "dynconfig.h"
+#include "lib/util/time.h"
+
+/* test string to compare with when debug_callback is called */
+#define TEST_STRING "smbc_setLogCallback test"
+
+/* Dummy log callback function */
+static void debug_callback(void *private_ptr, int level, const char *msg)
+{
+ bool *found = private_ptr;
+ if (strstr(msg, TEST_STRING) != NULL) {
+ *found = true;
+ }
+ return;
+}
+
+static void auth_callback(const char *srv,
+ const char *shr,
+ char *wg, int wglen,
+ char *un, int unlen,
+ char *pw, int pwlen)
+{
+ const char *workgroup =
+ cli_credentials_get_domain(samba_cmdline_get_creds());
+ const char *username =
+ cli_credentials_get_username(samba_cmdline_get_creds());
+ const char *password =
+ cli_credentials_get_password(samba_cmdline_get_creds());
+ ssize_t ret;
+
+ if (workgroup != NULL) {
+ ret = strlcpy(wg, workgroup, wglen);
+ if (ret >= wglen) {
+ abort();
+ }
+ }
+
+ if (username != NULL) {
+ ret = strlcpy(un, username, unlen);
+ if (ret >= unlen) {
+ abort();
+ }
+ }
+
+ if (password != NULL) {
+ ret = strlcpy(pw, password, pwlen);
+ if (ret >= pwlen) {
+ abort();
+ }
+ }
+};
+
+bool torture_libsmbclient_init_context(struct torture_context *tctx,
+ SMBCCTX **ctx_p)
+{
+ const char *workgroup =
+ cli_credentials_get_domain(samba_cmdline_get_creds());
+ const char *username =
+ cli_credentials_get_username(samba_cmdline_get_creds());
+ const char *client_proto =
+ torture_setting_string(tctx, "clientprotocol", NULL);
+ SMBCCTX *ctx = NULL;
+ SMBCCTX *p = NULL;
+ bool ok = true;
+ int dbglevel = DEBUGLEVEL;
+
+ ctx = smbc_new_context();
+ torture_assert_not_null_goto(tctx,
+ ctx,
+ ok,
+ out,
+ "Failed to create new context");
+
+ p = smbc_init_context(ctx);
+ torture_assert_not_null_goto(tctx,
+ p,
+ ok,
+ out,
+ "Failed to initialize context");
+
+ smbc_setDebug(ctx, dbglevel);
+ smbc_setOptionDebugToStderr(ctx, 1);
+
+ if (workgroup != NULL) {
+ smbc_setWorkgroup(ctx, workgroup);
+ }
+ if (username != NULL) {
+ smbc_setUser(ctx, username);
+ }
+
+ smbc_setFunctionAuthData(ctx, auth_callback);
+
+ if (client_proto != NULL) {
+ smbc_setOptionProtocols(ctx, client_proto, client_proto);
+ }
+
+ *ctx_p = ctx;
+
+out:
+ if (!ok) {
+ smbc_free_context(ctx, 1);
+ }
+
+ return ok;
+}
+
+static bool torture_libsmbclient_version(struct torture_context *tctx)
+{
+ torture_comment(tctx, "Testing smbc_version\n");
+
+ torture_assert(tctx, smbc_version(), "failed to get version");
+
+ return true;
+}
+
+static bool torture_libsmbclient_initialize(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ bool ret = false;
+
+ torture_comment(tctx, "Testing smbc_new_context\n");
+
+ ctx = smbc_new_context();
+ torture_assert(tctx, ctx, "failed to get new context");
+
+ torture_comment(tctx, "Testing smbc_init_context\n");
+
+ torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
+
+ smbc_setLogCallback(ctx, &ret, debug_callback);
+ DEBUG(0, (TEST_STRING"\n"));
+ torture_assert(tctx, ret, "Failed debug_callback not called");
+ ret = false;
+ smbc_setLogCallback(ctx, NULL, NULL);
+ DEBUG(0, (TEST_STRING"\n"));
+ torture_assert(tctx, !ret, "Failed debug_callback called");
+
+ smbc_free_context(ctx, 1);
+
+ return true;
+}
+
+static bool torture_libsmbclient_setConfiguration(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ struct loadparm_global *global_config = NULL;
+ const char *new_smb_conf = torture_setting_string(tctx,
+ "replace_smbconf",
+ "");
+
+ ctx = smbc_new_context();
+ torture_assert_not_null(tctx, ctx, "failed to get new context");
+
+ torture_assert_not_null(
+ tctx, smbc_init_context(ctx), "failed to init context");
+
+ torture_comment(tctx, "Testing smbc_setConfiguration - new file %s\n",
+ new_smb_conf);
+
+ global_config = get_globals();
+ torture_assert(tctx, global_config, "Global Config is NULL");
+
+ /* check configuration before smbc_setConfiguration call */
+ torture_comment(tctx, "'workgroup' before setConfiguration %s\n",
+ global_config->workgroup);
+ torture_comment(tctx, "'client min protocol' before "
+ "setConfiguration %d\n",
+ global_config->client_min_protocol);
+ torture_comment(tctx, "'client max protocol' before "
+ "setConfiguration %d\n",
+ global_config->_client_max_protocol);
+ torture_comment(tctx, "'client signing' before setConfiguration %d\n",
+ global_config->client_signing);
+ torture_comment(tctx, "'deadtime' before setConfiguration %d\n",
+ global_config->deadtime);
+
+ torture_assert_int_equal(tctx, smbc_setConfiguration(ctx, new_smb_conf),
+ 0, "setConfiguration conf file not found");
+
+ /* verify configuration */
+ torture_assert_str_equal(tctx, global_config->workgroup,
+ "NEW_WORKGROUP",
+ "smbc_setConfiguration failed, "
+ "'workgroup' not updated");
+ torture_assert_int_equal(tctx, global_config->client_min_protocol, PROTOCOL_NT1,
+ "smbc_setConfiguration failed, 'client min protocol' "
+ "not updated");
+ torture_assert_int_equal(tctx, global_config->_client_max_protocol, PROTOCOL_SMB3_00,
+ "smbc_setConfiguration failed, 'client max protocol' "
+ "not updated");
+ torture_assert_int_equal(tctx, global_config->client_signing, 1,
+ "smbc_setConfiguration failed, 'client signing' "
+ "not updated");
+ torture_assert_int_equal(tctx, global_config->deadtime, 5,
+ "smbc_setConfiguration failed, 'deadtime' not updated");
+
+ /* Restore configuration to default */
+ smbc_setConfiguration(ctx, get_dyn_CONFIGFILE());
+
+ smbc_free_context(ctx, 1);
+
+ return true;
+}
+
+static bool test_opendir(struct torture_context *tctx,
+ SMBCCTX *ctx,
+ const char *fname,
+ bool expect_success)
+{
+ int handle, ret;
+
+ torture_comment(tctx, "Testing smbc_opendir(%s)\n", fname);
+
+ handle = smbc_opendir(fname);
+ if (!expect_success) {
+ return true;
+ }
+ if (handle < 0) {
+ torture_fail(tctx, talloc_asprintf(tctx, "failed to obain file handle for '%s'", fname));
+ }
+
+ ret = smbc_closedir(handle);
+ torture_assert_int_equal(tctx, ret, 0,
+ talloc_asprintf(tctx, "failed to close file handle for '%s'", fname));
+
+ return true;
+}
+
+static bool torture_libsmbclient_opendir(struct torture_context *tctx)
+{
+ size_t i;
+ SMBCCTX *ctx;
+ bool ret = true;
+ const char *bad_urls[] = {
+ "",
+ NULL,
+ "smb",
+ "smb:",
+ "smb:/",
+ "smb:///",
+ "bms://",
+ ":",
+ ":/",
+ "://",
+ ":///",
+ "/",
+ "//",
+ "///"
+ };
+ const char *good_urls[] = {
+ "smb://",
+ "smb://WORKGROUP",
+ "smb://WORKGROUP/"
+ };
+
+ torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+ smbc_set_context(ctx);
+
+ for (i=0; i < ARRAY_SIZE(bad_urls); i++) {
+ ret &= test_opendir(tctx, ctx, bad_urls[i], false);
+ }
+ for (i=0; i < ARRAY_SIZE(good_urls); i++) {
+ ret &= test_opendir(tctx, ctx, good_urls[i], true);
+ }
+
+ smbc_free_context(ctx, 1);
+
+ return ret;
+}
+
+static bool torture_libsmbclient_readdirplus(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ int ret = -1;
+ int dhandle = -1;
+ int fhandle = -1;
+ bool found = false;
+ const char *filename = NULL;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+ }
+
+ torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+ smbc_set_context(ctx);
+
+ filename = talloc_asprintf(tctx,
+ "%s/test_readdirplus.txt",
+ smburl);
+ if (filename == NULL) {
+ torture_fail(tctx,
+ "talloc fail\n");
+ }
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(filename);
+
+ /* Create it. */
+ fhandle = smbc_creat(filename, 0666);
+ if (fhandle < 0) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal(tctx,
+ ret,
+ 0,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename));
+
+ dhandle = smbc_opendir(smburl);
+ if (dhandle < 0) {
+ int saved_errno = errno;
+ smbc_unlink(filename);
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "failed to obtain "
+ "directory handle for '%s' : %s",
+ smburl,
+ strerror(saved_errno)));
+ }
+
+ /* Readdirplus to ensure we see the new file. */
+ for (;;) {
+ const struct libsmb_file_info *exstat =
+ smbc_readdirplus(dhandle);
+ if (exstat == NULL) {
+ break;
+ }
+ if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ /* Remove it again. */
+ smbc_unlink(filename);
+ ret = smbc_closedir(dhandle);
+ torture_assert_int_equal(tctx,
+ ret,
+ 0,
+ talloc_asprintf(tctx,
+ "failed to close directory handle for '%s'",
+ smburl));
+
+ smbc_free_context(ctx, 1);
+
+ if (!found) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "failed to find file '%s'",
+ filename));
+ }
+
+ return true;
+}
+
+static bool torture_libsmbclient_readdirplus_seek(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ int ret = -1;
+ int dhandle = -1;
+ int fhandle = -1;
+ const char *dname = NULL;
+ const char *full_filename[100] = {0};
+ const char *filename[100] = {0};
+ const struct libsmb_file_info *direntries[102] = {0};
+ unsigned int i = 0;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ bool success = false;
+ off_t telldir_50 = (off_t)-1;
+ off_t telldir_20 = (off_t)-1;
+ size_t getdentries_size = 0;
+ struct smbc_dirent *getdentries = NULL;
+ struct smbc_dirent *dirent_20 = NULL;
+ const struct libsmb_file_info *direntries_20 = NULL;
+ const struct libsmb_file_info *direntriesplus_20 = NULL;
+ const char *plus2_stat_path = NULL;
+ struct stat st = {0};
+ struct stat st2 = {0};
+
+ torture_assert_not_null(
+ tctx,
+ smburl,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek start\n"));
+
+ torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+ smbc_set_context(ctx);
+
+ dname = talloc_asprintf(tctx,
+ "%s/rd_seek",
+ smburl);
+ torture_assert_not_null_goto(
+ tctx, dname, success, done, "talloc fail\n");
+
+ /* Ensure the files don't exist. */
+ for (i = 0; i < 100; i++) {
+ filename[i] = talloc_asprintf(tctx,
+ "test_readdirplus_%u.txt",
+ i);
+ torture_assert_not_null_goto(
+ tctx, filename[i], success, done, "talloc fail");
+ full_filename[i] = talloc_asprintf(tctx,
+ "%s/%s",
+ dname,
+ filename[i]);
+ torture_assert_not_null_goto(
+ tctx, full_filename[i], success, done, "talloc fail");
+ (void)smbc_unlink(full_filename[i]);
+ }
+ /* Ensure the directory doesn't exist. */
+ (void)smbc_rmdir(dname);
+
+ /* Create containing directory. */
+ ret = smbc_mkdir(dname, 0777);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create directory '%s': %s",
+ dname,
+ strerror(errno)));
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek create\n"));
+
+ /* Create them. */
+ for (i = 0; i < 100; i++) {
+ fhandle = smbc_creat(full_filename[i], 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ full_filename[i],
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ full_filename[i]));
+ }
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek enum\n"));
+
+ /* Now enumerate the directory. */
+ dhandle = smbc_opendir(dname);
+ torture_assert_goto(
+ tctx,
+ dhandle >= 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to obtain "
+ "directory handle for '%s' : %s",
+ dname,
+ strerror(errno)));
+
+ /* Read all the files. 100 we created plus . and .. */
+ for (i = 0; i < 102; i++) {
+ bool found = false;
+ unsigned int j;
+
+ direntries[i] = smbc_readdirplus(dhandle);
+ if (direntries[i] == NULL) {
+ break;
+ }
+
+ /* Store at offset 50. */
+ if (i == 50) {
+ telldir_50 = smbc_telldir(dhandle);
+ torture_assert_goto(
+ tctx,
+ telldir_50 != (off_t)-1,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "telldir failed file %s\n",
+ direntries[i]->name));
+ }
+
+ if (ISDOT(direntries[i]->name)) {
+ continue;
+ }
+ if (ISDOTDOT(direntries[i]->name)) {
+ continue;
+ }
+
+ /* Ensure all our files exist. */
+ for (j = 0; j < 100; j++) {
+ if (strcmp(direntries[i]->name,
+ filename[j]) == 0) {
+ found = true;
+ }
+ }
+ torture_assert_goto(
+ tctx,
+ found,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to find file %s\n",
+ direntries[i]->name));
+ }
+
+ /*
+ * We're seeking on in-memory lists here, so
+ * whilst the handle is open we really should
+ * get the same files back in the same order.
+ */
+
+ ret = smbc_lseekdir(dhandle, telldir_50);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (50) directory handle for '%s'",
+ dname));
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek seek\n"));
+
+ for (i = 51; i < 102; i++) {
+ const struct libsmb_file_info *entry =
+ smbc_readdirplus(dhandle);
+ torture_assert_goto(
+ tctx,
+ entry == direntries[i],
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek - failed to find "
+ "file %s - got %s\n",
+ direntries[i]->name,
+ entry->name));
+ }
+
+ /* Seek back to the start. */
+ ret = smbc_lseekdir(dhandle, 0);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek directory handle to start for '%s'",
+ dname));
+
+ /*
+ * Mix getdents/readdir/readdirplus with lseek to ensure
+ * we get the same result.
+ */
+
+ /* Allocate the space for 20 entries.
+ * Tricky as we need to allocate 20 struct smbc_dirent's + space
+ * for the name lengths.
+ */
+ getdentries_size = 20 * (sizeof(struct smbc_dirent) +
+ strlen("test_readdirplus_1000.txt") + 1);
+
+ getdentries = (struct smbc_dirent *)talloc_array_size(tctx,
+ getdentries_size,
+ 1);
+ torture_assert_not_null_goto(
+ tctx,
+ getdentries,
+ success,
+ done,
+ "talloc fail");
+
+ ret = smbc_getdents(dhandle, getdentries, getdentries_size);
+ torture_assert_goto(tctx,
+ (ret != -1),
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "smbd_getdents(1) for '%s' failed\n",
+ dname));
+
+ telldir_20 = smbc_telldir(dhandle);
+ torture_assert_goto(
+ tctx,
+ telldir_20 != (off_t)-1,
+ success,
+ done,
+ "telldir (20) failed\n");
+
+ /* Read another 20. */
+ ret = smbc_getdents(dhandle, getdentries, getdentries_size);
+ torture_assert_goto(tctx,
+ (ret != -1),
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "smbd_getdents(2) for '%s' failed\n",
+ dname));
+
+ /* Seek back to 20. */
+ ret = smbc_lseekdir(dhandle, telldir_20);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (20) directory handle for '%s'",
+ dname));
+
+ /* Read with readdir. */
+ dirent_20 = smbc_readdir(dhandle);
+ torture_assert_not_null_goto(
+ tctx,
+ dirent_20,
+ success,
+ done,
+ "smbc_readdir (20) failed\n");
+
+ /* Ensure the getdents and readdir names are the same. */
+ ret = strcmp(dirent_20->name, getdentries[0].name);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek (20) readdir name mismatch "
+ "file %s - got %s\n",
+ dirent_20->name,
+ getdentries[0].name));
+
+ /* Seek back to 20. */
+ ret = smbc_lseekdir(dhandle, telldir_20);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (20) directory handle for '%s'",
+ dname));
+ /* Read with readdirplus. */
+ direntries_20 = smbc_readdirplus(dhandle);
+ torture_assert_not_null_goto(
+ tctx,
+ direntries_20,
+ success,
+ done,
+ "smbc_readdirplus (20) failed\n");
+
+ /* Ensure the readdirplus and readdir names are the same. */
+ ret = strcmp(dirent_20->name, direntries_20->name);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek (20) readdirplus name mismatch "
+ "file %s - got %s\n",
+ dirent_20->name,
+ direntries_20->name));
+
+ /* Seek back to 20. */
+ ret = smbc_lseekdir(dhandle, telldir_20);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (20) directory handle for '%s'",
+ dname));
+
+ /* Read with readdirplus2. */
+ direntriesplus_20 = smbc_readdirplus2(dhandle, &st2);
+ torture_assert_not_null_goto(
+ tctx,
+ direntriesplus_20,
+ success,
+ done,
+ "smbc_readdirplus2 (20) failed\n");
+
+ /* Ensure the readdirplus2 and readdirplus names are the same. */
+ ret = strcmp(direntries_20->name, direntriesplus_20->name);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek (20) readdirplus2 name mismatch "
+ "file %s - got %s\n",
+ dirent_20->name,
+ direntries_20->name));
+
+ /* Ensure doing stat gets the same data. */
+ plus2_stat_path = talloc_asprintf(tctx,
+ "%s/%s",
+ dname,
+ direntriesplus_20->name);
+ torture_assert_not_null_goto(
+ tctx,
+ plus2_stat_path,
+ success,
+ done,
+ "talloc fail\n");
+
+ ret = smbc_stat(plus2_stat_path, &st);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to stat file '%s'",
+ plus2_stat_path));
+
+ torture_assert_int_equal(tctx,
+ st.st_ino,
+ st2.st_ino,
+ talloc_asprintf(tctx,
+ "file %s mismatched ino value "
+ "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
+ plus2_stat_path,
+ (uint64_t)st.st_ino,
+ (uint64_t)st2.st_ino));
+
+ torture_assert_int_equal(tctx,
+ st.st_dev,
+ st2.st_dev,
+ talloc_asprintf(tctx,
+ "file %s mismatched dev value "
+ "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
+ plus2_stat_path,
+ (uint64_t)st.st_dev,
+ (uint64_t)st2.st_dev));
+
+ ret = smbc_closedir(dhandle);
+ torture_assert_int_equal(tctx,
+ ret,
+ 0,
+ talloc_asprintf(tctx,
+ "failed to close directory handle for '%s'",
+ dname));
+
+ dhandle = -1;
+ success = true;
+
+ done:
+
+ /* Clean up. */
+ if (dhandle != -1) {
+ smbc_closedir(dhandle);
+ }
+ for (i = 0; i < 100; i++) {
+ if (full_filename[i] != NULL) {
+ smbc_unlink(full_filename[i]);
+ }
+ }
+ if (dname != NULL) {
+ smbc_rmdir(dname);
+ }
+
+ smbc_free_context(ctx, 1);
+
+ return success;
+}
+
+#ifndef SMBC_FILE_MODE
+#define SMBC_FILE_MODE (S_IFREG | 0444)
+#endif
+
+static bool torture_libsmbclient_readdirplus2(struct torture_context *tctx)
+{
+ SMBCCTX *ctx = NULL;
+ int dhandle = -1;
+ int fhandle = -1;
+ bool found = false;
+ bool success = false;
+ const char *filename = NULL;
+ struct stat st2 = {0};
+ struct stat st = {0};
+ int ret;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+ }
+
+ torture_assert_goto(tctx, torture_libsmbclient_init_context(tctx, &ctx), success, done, "");
+ smbc_set_context(ctx);
+
+ filename = talloc_asprintf(tctx,
+ "%s/test_readdirplus.txt",
+ smburl);
+ if (filename == NULL) {
+ torture_fail_goto(tctx, done, "talloc fail\n");
+ }
+
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(filename);
+
+ /* Create it. */
+ fhandle = smbc_creat(filename, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename));
+
+ dhandle = smbc_opendir(smburl);
+ if (dhandle < 0) {
+ int saved_errno = errno;
+ smbc_unlink(filename);
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to obtain "
+ "directory handle for '%s' : %s",
+ smburl,
+ strerror(saved_errno)));
+ }
+
+ /* readdirplus2 to ensure we see the new file. */
+ for (;;) {
+ const struct libsmb_file_info *exstat =
+ smbc_readdirplus2(dhandle, &st2);
+ if (exstat == NULL) {
+ break;
+ }
+
+ if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ smbc_unlink(filename);
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to find file '%s'",
+ filename));
+ }
+
+ /* Ensure mode is as expected. */
+ /*
+ * New file gets SMBC_FILE_MODE plus
+ * archive bit -> S_IXUSR
+ * !READONLY -> S_IWUSR.
+ */
+ torture_assert_int_equal_goto(tctx,
+ st2.st_mode,
+ SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "file %s st_mode should be 0%o, got 0%o'",
+ filename,
+ SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
+ (unsigned int)st2.st_mode));
+
+ /* Ensure smbc_stat() gets the same data. */
+ ret = smbc_stat(filename, &st);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to stat file '%s'",
+ filename));
+
+ torture_assert_int_equal_goto(tctx,
+ st2.st_ino,
+ st.st_ino,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "filename '%s' ino mismatch. "
+ "From smbc_readdirplus2 = %"PRIx64" "
+ "From smbc_stat = %"PRIx64"",
+ filename,
+ (uint64_t)st2.st_ino,
+ (uint64_t)st.st_ino));
+
+
+ /* Remove it again. */
+ smbc_unlink(filename);
+ ret = smbc_closedir(dhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close directory handle for '%s'",
+ filename));
+ success = true;
+
+ done:
+ smbc_free_context(ctx, 1);
+ return success;
+}
+
+bool torture_libsmbclient_configuration(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ bool ok = true;
+
+ ctx = smbc_new_context();
+ torture_assert(tctx, ctx, "failed to get new context");
+ torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
+
+ torture_comment(tctx, "Testing smbc_(set|get)Debug\n");
+ smbc_setDebug(ctx, DEBUGLEVEL);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getDebug(ctx),
+ DEBUGLEVEL,
+ ok,
+ done,
+ "failed to set DEBUGLEVEL");
+
+ torture_comment(tctx, "Testing smbc_(set|get)NetbiosName\n");
+ smbc_setNetbiosName(ctx, discard_const("torture_netbios"));
+ torture_assert_str_equal_goto(tctx,
+ smbc_getNetbiosName(ctx),
+ "torture_netbios",
+ ok,
+ done,
+ "failed to set NetbiosName");
+
+ torture_comment(tctx, "Testing smbc_(set|get)Workgroup\n");
+ smbc_setWorkgroup(ctx, discard_const("torture_workgroup"));
+ torture_assert_str_equal_goto(tctx,
+ smbc_getWorkgroup(ctx),
+ "torture_workgroup",
+ ok,
+ done,
+ "failed to set Workgroup");
+
+ torture_comment(tctx, "Testing smbc_(set|get)User\n");
+ smbc_setUser(ctx, "torture_user");
+ torture_assert_str_equal_goto(tctx,
+ smbc_getUser(ctx),
+ "torture_user",
+ ok,
+ done,
+ "failed to set User");
+
+ torture_comment(tctx, "Testing smbc_(set|get)Timeout\n");
+ smbc_setTimeout(ctx, 12345);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getTimeout(ctx),
+ 12345,
+ ok,
+ done,
+ "failed to set Timeout");
+
+done:
+ smbc_free_context(ctx, 1);
+
+ return ok;
+}
+
+bool torture_libsmbclient_options(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ bool ok = true;
+
+ ctx = smbc_new_context();
+ torture_assert(tctx, ctx, "failed to get new context");
+ torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionDebugToStderr\n");
+ smbc_setOptionDebugToStderr(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionDebugToStderr(ctx),
+ ok,
+ done,
+ "failed to set OptionDebugToStderr");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionFullTimeNames\n");
+ smbc_setOptionFullTimeNames(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionFullTimeNames(ctx),
+ ok,
+ done,
+ "failed to set OptionFullTimeNames");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionOpenShareMode\n");
+ smbc_setOptionOpenShareMode(ctx, SMBC_SHAREMODE_DENY_ALL);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getOptionOpenShareMode(ctx),
+ SMBC_SHAREMODE_DENY_ALL,
+ ok,
+ done,
+ "failed to set OptionOpenShareMode");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionUserData\n");
+ smbc_setOptionUserData(ctx, (void *)discard_const("torture_user_data"));
+ torture_assert_str_equal_goto(tctx,
+ (const char*)smbc_getOptionUserData(ctx),
+ "torture_user_data",
+ ok,
+ done,
+ "failed to set OptionUserData");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionSmbEncryptionLevel\n");
+ smbc_setOptionSmbEncryptionLevel(ctx, SMBC_ENCRYPTLEVEL_REQUEST);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getOptionSmbEncryptionLevel(ctx),
+ SMBC_ENCRYPTLEVEL_REQUEST,
+ ok,
+ done,
+ "failed to set OptionSmbEncryptionLevel");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionCaseSensitive\n");
+ smbc_setOptionCaseSensitive(ctx, false);
+ torture_assert_goto(tctx,
+ !smbc_getOptionCaseSensitive(ctx),
+ ok,
+ done,
+ "failed to set OptionCaseSensitive");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionBrowseMaxLmbCount\n");
+ smbc_setOptionBrowseMaxLmbCount(ctx, 2);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getOptionBrowseMaxLmbCount(ctx),
+ 2,
+ ok,
+ done,
+ "failed to set OptionBrowseMaxLmbCount");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionUrlEncodeReaddirEntries\n");
+ smbc_setOptionUrlEncodeReaddirEntries(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionUrlEncodeReaddirEntries(ctx),
+ ok,
+ done,
+ "failed to set OptionUrlEncodeReaddirEntries");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionOneSharePerServer\n");
+ smbc_setOptionOneSharePerServer(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionOneSharePerServer(ctx),
+ ok,
+ done,
+ "failed to set OptionOneSharePerServer");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionUseKerberos\n");
+ smbc_setOptionUseKerberos(ctx, false);
+ torture_assert_goto(tctx,
+ !smbc_getOptionUseKerberos(ctx),
+ ok,
+ done,
+ "failed to set OptionUseKerberos");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionFallbackAfterKerberos\n");
+ smbc_setOptionFallbackAfterKerberos(ctx, false);
+ torture_assert_goto(tctx,
+ !smbc_getOptionFallbackAfterKerberos(ctx),
+ ok,
+ done,
+ "failed to set OptionFallbackAfterKerberos");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionNoAutoAnonymousLogin\n");
+ smbc_setOptionNoAutoAnonymousLogin(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionNoAutoAnonymousLogin(ctx),
+ ok,
+ done,
+ "failed to set OptionNoAutoAnonymousLogin");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionUseCCache\n");
+ smbc_setOptionUseCCache(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionUseCCache(ctx),
+ ok,
+ done,
+ "failed to set OptionUseCCache");
+
+done:
+ smbc_free_context(ctx, 1);
+
+ return ok;
+}
+
+static bool torture_libsmbclient_list_shares(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ struct smbc_dirent *dirent = NULL;
+ SMBCCTX *ctx = NULL;
+ int dhandle = -1;
+ bool ipc_share_found = false;
+ bool ok = true;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert_goto(tctx,
+ ok,
+ ok,
+ out,
+ "Failed to init context");
+ smbc_set_context(ctx);
+
+ torture_comment(tctx, "Listing: %s\n", smburl);
+ dhandle = smbc_opendir(smburl);
+ torture_assert_int_not_equal_goto(tctx,
+ dhandle,
+ -1,
+ ok,
+ out,
+ "Failed to open smburl");
+
+ while((dirent = smbc_readdir(dhandle)) != NULL) {
+ torture_comment(tctx, "DIR: %s\n", dirent->name);
+ torture_assert_not_null_goto(tctx,
+ dirent->name,
+ ok,
+ out,
+ "Failed to read name");
+
+ if (strequal(dirent->name, "IPC$")) {
+ ipc_share_found = true;
+ }
+ }
+
+ torture_assert_goto(tctx,
+ ipc_share_found,
+ ok,
+ out,
+ "Failed to list IPC$ share");
+
+out:
+ smbc_closedir(dhandle);
+ return ok;
+}
+
+static bool torture_libsmbclient_utimes(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ SMBCCTX *ctx = NULL;
+ struct stat st;
+ int fhandle, ret;
+ struct timeval tbuf[2];
+ bool ok;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert(tctx, ok, "Failed to init context");
+ smbc_set_context(ctx);
+
+ fhandle = smbc_open(smburl, O_RDWR|O_CREAT, 0644);
+ torture_assert_int_not_equal(tctx, fhandle, -1, "smbc_open failed");
+
+ ret = smbc_fstat(fhandle, &st);
+ torture_assert_int_not_equal(tctx, ret, -1, "smbc_fstat failed");
+
+ tbuf[0] = convert_timespec_to_timeval(get_atimespec(&st));
+ tbuf[1] = convert_timespec_to_timeval(get_mtimespec(&st));
+
+ tbuf[1] = timeval_add(&tbuf[1], 0, 100000); /* 100 msec */
+
+ ret = smbc_utimes(smburl, tbuf);
+ torture_assert_int_not_equal(tctx, ret, -1, "smbc_utimes failed");
+
+ ret = smbc_fstat(fhandle, &st);
+ torture_assert_int_not_equal(tctx, ret, -1, "smbc_fstat failed");
+
+ torture_assert_int_equal(
+ tctx,
+ get_mtimensec(&st) / 1000,
+ tbuf[1].tv_usec,
+ "smbc_utimes did not update msec");
+
+ smbc_close(fhandle);
+ smbc_unlink(smburl);
+ return true;
+}
+
+static bool torture_libsmbclient_noanon_list(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ struct smbc_dirent *dirent = NULL;
+ SMBCCTX *ctx = NULL;
+ int dhandle = -1;
+ bool ok = true;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert_goto(tctx,
+ ok,
+ ok,
+ out,
+ "Failed to init context");
+ torture_comment(tctx,
+ "Testing smbc_setOptionNoAutoAnonymousLogin\n");
+ smbc_setOptionNoAutoAnonymousLogin(ctx, true);
+ smbc_set_context(ctx);
+
+ torture_comment(tctx, "Listing: %s\n", smburl);
+ dhandle = smbc_opendir(smburl);
+ torture_assert_int_not_equal_goto(tctx,
+ dhandle,
+ -1,
+ ok,
+ out,
+ "Failed to open smburl");
+
+ while((dirent = smbc_readdir(dhandle)) != NULL) {
+ torture_comment(tctx, "DIR: %s\n", dirent->name);
+ torture_assert_not_null_goto(tctx,
+ dirent->name,
+ ok,
+ out,
+ "Failed to read name");
+ }
+
+out:
+ smbc_closedir(dhandle);
+ return ok;
+}
+
+static bool torture_libsmbclient_rename(struct torture_context *tctx)
+{
+ SMBCCTX *ctx = NULL;
+ int fhandle = -1;
+ bool success = false;
+ const char *filename_src = NULL;
+ const char *filename_dst = NULL;
+ int ret;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+ }
+
+ torture_assert_goto(tctx,
+ torture_libsmbclient_init_context(tctx, &ctx),
+ success,
+ done,
+ "");
+
+ smbc_set_context(ctx);
+
+ filename_src = talloc_asprintf(tctx,
+ "%s/src",
+ smburl);
+ if (filename_src == NULL) {
+ torture_fail_goto(tctx, done, "talloc fail\n");
+ }
+
+ filename_dst = talloc_asprintf(tctx,
+ "%s/dst",
+ smburl);
+ if (filename_dst == NULL) {
+ torture_fail_goto(tctx, done, "talloc fail\n");
+ }
+
+ /* Ensure the files don't exist. */
+ smbc_unlink(filename_src);
+ smbc_unlink(filename_dst);
+
+ /* Create them. */
+ fhandle = smbc_creat(filename_src, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename_src,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename_src));
+
+ fhandle = smbc_creat(filename_dst, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename_dst,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename_dst));
+
+ ret = smbc_rename(filename_src, filename_dst);
+
+ /*
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14938
+ * gives ret == -1, but errno = 0 for overwrite renames
+ * over SMB2.
+ */
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_rename '%s' -> '%s' failed with %s\n",
+ filename_src,
+ filename_dst,
+ strerror(errno)));
+
+ /* Remove them again. */
+ smbc_unlink(filename_src);
+ smbc_unlink(filename_dst);
+ success = true;
+
+ done:
+ smbc_free_context(ctx, 1);
+ return success;
+}
+
+static bool torture_libsmbclient_getatr(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ SMBCCTX *ctx = NULL;
+ char *getatr_name = NULL;
+ struct stat st = {0};
+ bool ok;
+ int ret = 0;
+ int err = 0;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert(tctx, ok, "Failed to init context");
+ smbc_set_context(ctx);
+
+ getatr_name = talloc_asprintf(tctx,
+ "%s/noexist",
+ smburl);
+ if (getatr_name == NULL) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__": %s",
+ "talloc fail\n");
+ return false;
+ }
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(getatr_name);
+ /*
+ * smbc_stat() internally uses SMBC_getatr().
+ * Make sure doing getatr on a non-existent file gives
+ * an error of -1, errno = ENOENT.
+ */
+
+ ret = smbc_stat(getatr_name, &st);
+ if (ret == -1) {
+ err = errno;
+ }
+ torture_assert_int_equal(tctx,
+ ret,
+ -1,
+ talloc_asprintf(tctx,
+ "smbc_stat on '%s' should "
+ "get -1, got %d\n",
+ getatr_name,
+ ret));
+ torture_assert_int_equal(tctx,
+ err,
+ ENOENT,
+ talloc_asprintf(tctx,
+ "smbc_stat on '%s' should "
+ "get errno = ENOENT, got %s\n",
+ getatr_name,
+ strerror(err)));
+ return true;
+}
+
+static bool torture_libsmbclient_getxattr(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ int fhandle = -1;
+ SMBCCTX *ctx = NULL;
+ char *getxattr_name = NULL;
+ char value[4096];
+ bool ok = false;
+ int ret = -1;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert(tctx, ok, "Failed to init context");
+ smbc_set_context(ctx);
+
+ getxattr_name = talloc_asprintf(tctx,
+ "%s/getxattr",
+ smburl);
+ if (getxattr_name == NULL) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__": %s",
+ "talloc fail\n");
+ return false;
+ }
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(getxattr_name);
+
+ /* Create testfile. */
+ fhandle = smbc_creat(getxattr_name, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ getxattr_name,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ getxattr_name));
+
+ /*
+ * Ensure getting a non-existent attribute returns -1.
+ */
+ ret = smbc_getxattr(getxattr_name, "foobar", value, sizeof(value));
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ -1,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_getxattr(foobar) on '%s' should "
+ "get -1, got %d\n",
+ getxattr_name,
+ ret));
+
+ /*
+ * Ensure getting a valid attribute computes its size.
+ */
+ ret = smbc_getxattr(getxattr_name, "system.*", NULL, 0);
+ torture_assert_goto(tctx,
+ ret >= 0,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_getxattr(foobar, NULL) on '%s' should "
+ "get >=0, got %d\n",
+ getxattr_name,
+ ret));
+
+ /*
+ * Ensure getting a valid attribute returns its size.
+ */
+ ret = smbc_getxattr(getxattr_name, "system.*", value, sizeof(value));
+ torture_assert_goto(tctx,
+ ret >= 0,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_getxattr(foobar, value) on '%s' should "
+ "get >=0, got %d\n",
+ getxattr_name,
+ ret));
+
+ ok = true;
+
+ done:
+
+ smbc_unlink(getxattr_name);
+ smbc_free_context(ctx, 1);
+ return ok;
+}
+
+NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(ctx, "libsmbclient");
+
+ torture_suite_add_simple_test(suite, "version", torture_libsmbclient_version);
+ torture_suite_add_simple_test(suite, "initialize", torture_libsmbclient_initialize);
+ torture_suite_add_simple_test(suite, "configuration", torture_libsmbclient_configuration);
+ torture_suite_add_simple_test(suite, "setConfiguration", torture_libsmbclient_setConfiguration);
+ torture_suite_add_simple_test(suite, "options", torture_libsmbclient_options);
+ torture_suite_add_simple_test(suite, "opendir", torture_libsmbclient_opendir);
+ torture_suite_add_simple_test(suite, "list_shares", torture_libsmbclient_list_shares);
+ torture_suite_add_simple_test(suite, "readdirplus",
+ torture_libsmbclient_readdirplus);
+ torture_suite_add_simple_test(suite, "readdirplus_seek",
+ torture_libsmbclient_readdirplus_seek);
+ torture_suite_add_simple_test(suite, "readdirplus2",
+ torture_libsmbclient_readdirplus2);
+ torture_suite_add_simple_test(
+ suite, "utimes", torture_libsmbclient_utimes);
+ torture_suite_add_simple_test(
+ suite, "noanon_list", torture_libsmbclient_noanon_list);
+ torture_suite_add_simple_test(suite,
+ "rename",
+ torture_libsmbclient_rename);
+ torture_suite_add_simple_test(suite, "getatr",
+ torture_libsmbclient_getatr);
+ torture_suite_add_simple_test(suite, "getxattr",
+ torture_libsmbclient_getxattr);
+
+ suite->description = talloc_strdup(suite, "libsmbclient interface tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/libsmbclient/wscript_build b/source4/torture/libsmbclient/wscript_build
new file mode 100644
index 0000000..61d819b
--- /dev/null
+++ b/source4/torture/libsmbclient/wscript_build
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_MODULE('TORTURE_LIBSMBCLIENT',
+ source='libsmbclient.c',
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_libsmbclient_init',
+ deps='smbclient CMDLINE_S4',
+ internal_module=True
+ )
+
+
+