1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source4/torture/torture_util.c
Andrew Tridgell 0becf4d683 thanks to ntfsd and some google searches I worked out what the unknown
fields in level 261 and level 262 of directory search are, plus the
names of the levels

the unknown fields are a 64bit unique file id, and match the 64 bit
number from the internal_information qfileinfo level
(This used to be commit b69f54eb02)
2003-09-02 04:37:33 +00:00

343 lines
9.1 KiB
C

/*
Unix SMB/CIFS implementation.
SMB torture tester utility functions
Copyright (C) Andrew Tridgell 2003
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
static struct timeval tp1,tp2;
void start_timer(void)
{
gettimeofday(&tp1,NULL);
}
double end_timer(void)
{
gettimeofday(&tp2,NULL);
return((tp2.tv_sec - tp1.tv_sec) +
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
}
/*
create a directory, returning a handle to it
*/
int create_directory_handle(struct cli_tree *tree, const char *dname)
{
NTSTATUS status;
union smb_open io;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("create_directory_handle");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SA_RIGHT_FILE_ALL_ACCESS;
io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = dname;
status = smb_raw_open(tree, mem_ctx, &io);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return -1;
}
talloc_destroy(mem_ctx);
return io.ntcreatex.out.fnum;
}
/*
sometimes we need a fairly complex file to work with, so we can test
all possible attributes.
*/
int create_complex_file(struct cli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
{
int fnum;
char buf[7] = "abc";
union smb_setfileinfo setfile;
union smb_fileinfo fileinfo;
time_t t = (time(NULL) & ~1);
NTSTATUS status;
cli_unlink(cli, fname);
fnum = cli_nt_create_full(cli, fname, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
FILE_ATTRIBUTE_NORMAL,
NTCREATEX_SHARE_ACCESS_DELETE|
NTCREATEX_SHARE_ACCESS_READ|
NTCREATEX_SHARE_ACCESS_WRITE,
NTCREATEX_DISP_OVERWRITE_IF,
0, 0);
if (fnum == -1) return -1;
cli_write(cli, fnum, 0, buf, 0, sizeof(buf));
/* setup some EAs */
setfile.generic.level = RAW_SFILEINFO_EA_SET;
setfile.generic.file.fnum = fnum;
setfile.ea_set.in.ea.flags = 0;
setfile.ea_set.in.ea.name.s = "EAONE";
setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "VALUE1", 6);
status = smb_raw_setfileinfo(cli->tree, &setfile);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to setup EAs\n");
}
setfile.ea_set.in.ea.name.s = "SECONDEA";
setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
status = smb_raw_setfileinfo(cli->tree, &setfile);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to setup EAs\n");
}
/* make sure all the timestamps aren't the same */
setfile.generic.level = RAW_SFILEINFO_SETATTRE;
setfile.generic.file.fnum = fnum;
setfile.setattre.in.create_time = t + 60;
setfile.setattre.in.access_time = t + 120;
setfile.setattre.in.write_time = t + 180;
status = smb_raw_setfileinfo(cli->tree, &setfile);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to setup file times - %s\n", nt_errstr(status));
}
/* make sure all the timestamps aren't the same */
fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
fileinfo.generic.in.fnum = fnum;
status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to query file times - %s\n", nt_errstr(status));
}
if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
printf("create_time not setup correctly\n");
}
if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
printf("access_time not setup correctly\n");
}
if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
printf("write_time not setup correctly\n");
}
return fnum;
}
/* return a pointer to a anonymous shared memory segment of size "size"
which will persist across fork() but will disappear when all processes
exit
The memory is not zeroed
This function uses system5 shared memory. It takes advantage of a property
that the memory is not destroyed if it is attached when the id is removed
*/
void *shm_setup(int size)
{
int shmid;
void *ret;
shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
if (shmid == -1) {
printf("can't get shared memory\n");
exit(1);
}
ret = (void *)shmat(shmid, 0, 0);
if (!ret || ret == (void *)-1) {
printf("can't attach to shared memory\n");
return NULL;
}
/* the following releases the ipc, but note that this process
and all its children will still have access to the memory, its
just that the shmid is no longer valid for other shm calls. This
means we don't leave behind lots of shm segments after we exit
See Stevens "advanced programming in unix env" for details
*/
shmctl(shmid, IPC_RMID, 0);
return ret;
}
/*
check that a wire string matches the flags specified
not 100% accurate, but close enough for testing
*/
BOOL wire_bad_flags(WIRE_STRING *str, int flags)
{
int len;
if (!str || !str->s) return True;
len = strlen(str->s);
if (flags & STR_TERMINATE) len++;
if ((flags & STR_UNICODE) || !getenv("CLI_FORCE_ASCII")) {
len *= 2;
} else if (flags & STR_TERMINATE_ASCII) {
len++;
}
if (str->private_length != len) {
printf("Expected wire_length %d but got %d for '%s'\n",
len, str->private_length, str->s);
return True;
}
return False;
}
/*
return a talloced string representing a time_t for human consumption
*/
const char *time_string(TALLOC_CTX *mem_ctx, time_t t)
{
return talloc_strdup(mem_ctx, http_timestring(mem_ctx, t));
}
/*
check if 2 NTTIMEs are equal
*/
BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
{
return t1->low == t2->low && t1->high == t2->high;
}
/*
dump a all_info QFILEINFO structure
*/
void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
{
d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.create_time));
d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.access_time));
d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.write_time));
d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, &finfo->all_info.out.change_time));
d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
d_printf("\talloc_size: %llu\n", (unsigned long long)finfo->all_info.out.alloc_size);
d_printf("\tsize: %llu\n", (unsigned long long)finfo->all_info.out.size);
d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
}
/*
dump file infor by name
*/
void torture_all_info(struct cli_tree *tree, const char *fname)
{
TALLOC_CTX *mem_ctx = talloc_init(fname);
union smb_fileinfo finfo;
NTSTATUS status;
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
finfo.generic.in.fname = fname;
status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
if (!NT_STATUS_IS_OK(status)) {
d_printf("%s - %s\n", fname, nt_errstr(status));
return;
}
d_printf("%s:\n", fname);
dump_all_info(mem_ctx, &finfo);
talloc_destroy(mem_ctx);
}
/*
split a UNC name into server and share names
*/
BOOL split_unc_name(const char *unc, char **server, char **share)
{
char *p = strdup(unc);
if (!p) return False;
all_string_sub(p, "\\", "/", 0);
if (strncmp(p, "//", 2) != 0) return False;
(*server) = p+2;
p = strchr(*server, '/');
if (!p) return False;
*p = 0;
(*share) = p+1;
return True;
}
/*
split a USER%PASS pair into username and password
*/
BOOL split_username(const char *pair, char **user, char **pass)
{
char *p = strdup(pair);
if (!p) return False;
(*user) = p;
p = strchr(*user, '%');
if (!p) return False;
*p = 0;
(*pass) = p+1;
return True;
}
/*
set a attribute on a file
*/
BOOL torture_set_file_attribute(struct cli_tree *tree, const char *fname, uint16 attrib)
{
union smb_setfileinfo sfinfo;
NTSTATUS status;
sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
sfinfo.generic.file.fname = fname;
ZERO_STRUCT(sfinfo.basic_info.in);
sfinfo.basic_info.in.attrib = attrib;
status = smb_raw_setpathinfo(tree, &sfinfo);
return NT_STATUS_IS_OK(status);
}
/*
set a file descriptor as sparse
*/
NTSTATUS torture_set_sparse(struct cli_tree *tree, int fnum)
{
struct smb_ntioctl nt;
nt.in.function = 0x900c4;
nt.in.fnum = fnum;
nt.in.fsctl = True;
nt.in.filter = 0;
return smb_raw_ntioctl(tree, &nt);
}