mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
74636dfe24
Add torture test to show smbc_getxattr() should return -1 on failure, 0 on success. Add knownfail. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14808 Signed-off-by: Jeremy Allison <jra@samba.org> Reviewed-by: David Mulder <dmulder@samba.org>
1605 lines
38 KiB
C
1605 lines
38 KiB
C
/*
|
|
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 returns 0.
|
|
*/
|
|
ret = smbc_getxattr(getxattr_name, "system.*", value, sizeof(value));
|
|
torture_assert_int_equal_goto(tctx,
|
|
ret,
|
|
0,
|
|
ok,
|
|
done,
|
|
talloc_asprintf(tctx,
|
|
"smbc_getxattr(foobar) on '%s' should "
|
|
"get -1, 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;
|
|
}
|