/* Unix SMB/Netbios implementation. Version 1.9. SMB torture tester Copyright (C) Andrew Tridgell 1997-1998 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. */ #define NO_SYSLOG #include "includes.h" static fstring host, workgroup, share, password, username, myname; static int max_protocol = PROTOCOL_NT1; static char *sockops="TCP_NODELAY"; static int nprocs=1, numops=100; static int procnum; /* records process count number when forking */ static struct cli_state current_cli; static fstring randomfname; static BOOL use_oplocks; static BOOL use_level_II_oplocks; static double create_procs(void (*fn)(int)); static struct timeval tp1,tp2; static void start_timer(void) { gettimeofday(&tp1,NULL); } static double end_timer(void) { gettimeofday(&tp2,NULL); return((tp2.tv_sec - tp1.tv_sec) + (tp2.tv_usec - tp1.tv_usec)*1.0e-6); } /* 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 */ static 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; } static BOOL open_nbt_connection(struct cli_state *c) { struct nmb_name called, calling; struct in_addr ip; extern struct in_addr ipzero; ZERO_STRUCTP(c); make_nmb_name(&calling, myname, 0x0); make_nmb_name(&called , host, 0x20); ip = ipzero; if (!cli_initialise(c) || !cli_connect(c, host, &ip)) { printf("Failed to connect with %s\n", host); return False; } c->timeout = 120000; /* set a really long timeout (2 minutes) */ if (use_oplocks) c->use_oplocks = True; if (use_level_II_oplocks) c->use_level_II_oplocks = True; if (!cli_session_request(c, &calling, &called)) { printf("%s rejected the session\n",host); cli_shutdown(c); return False; } return True; } static BOOL open_connection(struct cli_state *c) { ZERO_STRUCTP(c); if (!open_nbt_connection(c)) { return False; } if (!cli_negprot(c)) { printf("%s rejected the negprot (%s)\n",host, cli_errstr(c)); cli_shutdown(c); return False; } if (!cli_session_setup(c, username, password, strlen(password), password, strlen(password), workgroup)) { printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c)); cli_shutdown(c); return False; } if (!cli_send_tconX(c, share, "?????", password, strlen(password)+1)) { printf("%s refused tree connect (%s)\n", host, cli_errstr(c)); cli_shutdown(c); return False; } return True; } static void close_connection(struct cli_state *c) { if (!cli_tdis(c)) { printf("tdis failed (%s)\n", cli_errstr(c)); } cli_shutdown(c); } /* check if the server produced the expected error code */ static BOOL check_error(struct cli_state *c, uint8 eclass, uint32 ecode, uint32 nterr) { uint8 class; uint32 num; (void)cli_error(c, &class, &num, NULL); if ((eclass != class || ecode != num) && num != (nterr&0xFFFFFF)) { printf("unexpected error code class=%d code=%d\n", (int)class, (int)num); printf(" expected %d/%d %d\n", (int)eclass, (int)ecode, (int)nterr); return False; } return True; } static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len) { while (!cli_lock(c, fnum, offset, len, -1, WRITE_LOCK)) { if (!check_error(c, ERRDOS, ERRlock, 0)) return False; } return True; } static BOOL rw_torture(struct cli_state *c) { char *lockfname = "\\torture.lck"; fstring fname; int fnum; int fnum2; pid_t pid2, pid = getpid(); int i, j; char buf[1024]; fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, DENY_NONE); if (fnum2 == -1) fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE); if (fnum2 == -1) { printf("open of %s failed (%s)\n", lockfname, cli_errstr(c)); return False; } for (i=0;i= countprev) { printf("%d %8d\r", i, count); fflush(stdout); i++; countprev += (sizeof(buf) / 20); } if (procnum == 0) { sent = ((unsigned)sys_random()%(20))+ 1; if (sent > sizeof(buf) - count) { sent = sizeof(buf) - count; } if (cli_write(c, fnum, 0, buf+count, count, sent) != sent) { printf("write failed (%s)\n", cli_errstr(c)); } } else { sent = cli_read(c, fnum, buf_rd+count, count, sizeof(buf)-count); if (sent < 0) { printf("read failed offset:%d size:%d (%s)\n", count, sizeof(buf)-count, cli_errstr(c)); sent = 0; } if (sent > 0) { if (memcmp(buf_rd+count, buf+count, sent) != 0) { printf("read/write compare failed\n"); printf("offset: %d req %d recvd %d\n", count, sizeof(buf)-count, sent); break; } } } } if (!cli_close(c, fnum)) { printf("close failed (%s)\n", cli_errstr(c)); } return True; } static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2) { char *lockfname = "\\torture.lck"; int fnum1; int fnum2; int i; char buf[131072]; char buf_rd[131072]; if (!cli_unlink(c1, lockfname)) { printf("unlink failed (%s)\n", cli_errstr(c1)); } fnum1 = cli_open(c1, lockfname, O_RDWR | O_CREAT | O_EXCL, DENY_NONE); if (fnum1 == -1) { printf("first open read/write of %s failed (%s)\n", lockfname, cli_errstr(c1)); return False; } fnum2 = cli_open(c2, lockfname, O_RDONLY, DENY_NONE); if (fnum2 == -1) { printf("second open read-only of %s failed (%s)\n", lockfname, cli_errstr(c2)); cli_close(c1, fnum1); return False; } for (i=0;i 0) { fnum--; slprintf(fname,sizeof(fname)-1,template, fnum,(int)getpid()); cli_close(&cli, fnum); if (!cli_unlink(&cli, fname)) { printf("unlink of %s failed (%s)\n", fname, cli_errstr(&cli)); } } printf("maxfid test finished\n"); close_connection(&cli); } /* generate a random buffer */ static void rand_buf(char *buf, int len) { while (len--) { *buf = (char)sys_random(); buf++; } } /* send smb negprot commands, not reading the response */ static void run_negprot_nowait(int dummy) { int i; static struct cli_state cli; printf("starting negprot nowait test\n"); if (!open_nbt_connection(&cli)) { return; } for (i=0;i<50000;i++) { cli_negprot_send(&cli); } close_connection(&cli); printf("finished negprot nowait test\n"); } /* send random IPC commands */ static void run_randomipc(int dummy) { char *rparam = NULL; char *rdata = NULL; int rdrcnt,rprcnt; pstring param; int api, param_len, i; static struct cli_state cli; printf("starting random ipc test\n"); if (!open_connection(&cli)) { return; } for (i=0;i<50000;i++) { api = sys_random() % 500; param_len = (sys_random() % 64); rand_buf(param, param_len); SSVAL(param,0,api); cli_api(&cli, param, param_len, 8, NULL, 0, BUFFER_SIZE, &rparam, &rprcnt, &rdata, &rdrcnt); } close_connection(&cli); printf("finished random ipc test\n"); } static void browse_callback(const char *sname, uint32 stype, const char *comment, void *state) { printf("\t%20.20s %08x %s\n", sname, stype, comment); } /* This test checks the browse list code */ static void run_browsetest(int dummy) { static struct cli_state cli; printf("starting browse test\n"); if (!open_connection(&cli)) { return; } printf("domain list:\n"); cli_NetServerEnum(&cli, cli.server_domain, SV_TYPE_DOMAIN_ENUM, browse_callback, NULL); printf("machine list:\n"); cli_NetServerEnum(&cli, cli.server_domain, SV_TYPE_ALL, browse_callback, NULL); close_connection(&cli); printf("browse test finished\n"); } /* This checks how the getatr calls works */ static void run_attrtest(int dummy) { static struct cli_state cli; int fnum; time_t t, t2; char *fname = "\\attrib.tst"; printf("starting attrib test\n"); if (!open_connection(&cli)) { return; } cli_unlink(&cli, fname); fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE); cli_close(&cli, fnum); if (!cli_getatr(&cli, fname, NULL, NULL, &t)) { printf("getatr failed (%s)\n", cli_errstr(&cli)); } if (abs(t - time(NULL)) > 2) { printf("ERROR: SMBgetatr bug. time is %s", ctime(&t)); t = time(NULL); } t2 = t-60*60*24; /* 1 day ago */ if (!cli_setatr(&cli, fname, 0, t2)) { printf("setatr failed (%s)\n", cli_errstr(&cli)); } if (!cli_getatr(&cli, fname, NULL, NULL, &t)) { printf("getatr failed (%s)\n", cli_errstr(&cli)); } if (t != t2) { printf("ERROR: getatr/setatr bug. times are\n%s", ctime(&t)); printf("%s", ctime(&t2)); } cli_unlink(&cli, fname); close_connection(&cli); printf("attrib test finished\n"); } /* This checks a couple of trans2 calls */ static void run_trans2test(int dummy) { static struct cli_state cli; int fnum; size_t size; time_t c_time, a_time, m_time, w_time, m_time2; char *fname = "\\trans2.tst"; char *dname = "\\trans2"; char *fname2 = "\\trans2\\trans2.tst"; printf("starting trans2 test\n"); if (!open_connection(&cli)) { return; } cli_unlink(&cli, fname); fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE); if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time, NULL, NULL)) { printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli)); } cli_close(&cli, fnum); sleep(2); cli_unlink(&cli, fname); fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE); cli_close(&cli, fnum); if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) { printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli)); } else { if (c_time != m_time) { printf("create time=%s", ctime(&c_time)); printf("modify time=%s", ctime(&m_time)); printf("This system appears to have sticky create times\n"); } if (a_time % (60*60) == 0) { printf("access time=%s", ctime(&a_time)); printf("This system appears to set a midnight access time\n"); } if (abs(m_time - time(NULL)) > 60*60*24*7) { printf("ERROR: totally incorrect times - maybe word reversed?\n"); } } cli_unlink(&cli, fname); fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE); cli_close(&cli, fnum); if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time, &w_time, &size, NULL, NULL)) { printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)); } else { if (w_time < 60*60*24*2) { printf("write time=%s", ctime(&w_time)); printf("This system appears to set a initial 0 write time\n"); } } cli_unlink(&cli, fname); /* check if the server updates the directory modification time when creating a new file */ if (!cli_mkdir(&cli, dname)) { printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli)); } sleep(3); if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time, &w_time, &size, NULL, NULL)) { printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)); } fnum = cli_open(&cli, fname2, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE); cli_write(&cli, fnum, 0, (char *)&fnum, 0, sizeof(fnum)); cli_close(&cli, fnum); if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2, &w_time, &size, NULL, NULL)) { printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)); } else { if (m_time2 == m_time) printf("This system does not update directory modification times\n"); } cli_unlink(&cli, fname2); cli_rmdir(&cli, dname); close_connection(&cli); printf("trans2 test finished\n"); } /* This checks new W2K calls. */ void new_trans(struct cli_state *pcli, int fnum, int level) { char buf[4096]; memset(buf, 0xff, sizeof(buf)); if (!cli_qfileinfo_test(pcli, fnum, level, buf)) { printf("ERROR: qfileinfo (%d) failed (%s)\n", level, cli_errstr(pcli)); } else { printf("qfileinfo: level %d\n", level); dump_data(0, buf, 256); printf("\n"); } } static void run_w2ktest(int dummy) { static struct cli_state cli; int fnum; char *fname = "\\w2ktest\\w2k.tst"; int level; printf("starting w2k test\n"); if (!open_connection(&cli)) { return; } fnum = cli_open(&cli, fname, O_RDWR | O_CREAT , DENY_NONE); for (level = 1004; level < 1040; level++) new_trans(&cli, fnum, level); cli_close(&cli, fnum); close_connection(&cli); printf("w2k test finished\n"); } /* this is a harness for some oplock tests */ static void run_oplock1(int dummy) { static struct cli_state cli1; char *fname = "\\lockt1.lck"; int fnum1; printf("starting oplock test 1\n"); if (!open_connection(&cli1)) { return; } cli_unlink(&cli1, fname); cli_sockopt(&cli1, sockops); cli1.use_oplocks = True; fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); if (fnum1 == -1) { printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } cli1.use_oplocks = False; cli_unlink(&cli1, fname); cli_unlink(&cli1, fname); if (!cli_close(&cli1, fnum1)) { printf("close2 failed (%s)\n", cli_errstr(&cli1)); return; } if (!cli_unlink(&cli1, fname)) { printf("unlink failed (%s)\n", cli_errstr(&cli1)); return; } close_connection(&cli1); printf("finished oplock test 1\n"); } static void run_oplock2(int dummy) { static struct cli_state cli1, cli2; char *fname = "\\lockt2.lck"; int fnum1, fnum2; int saved_use_oplocks = use_oplocks; char buf[4]; use_level_II_oplocks = True; use_oplocks = True; printf("starting oplock test 2\n"); if (!open_connection(&cli1)) { use_level_II_oplocks = False; use_oplocks = saved_use_oplocks; return; } cli1.use_oplocks = True; cli1.use_level_II_oplocks = True; if (!open_connection(&cli2)) { use_level_II_oplocks = False; use_oplocks = saved_use_oplocks; return; } cli2.use_oplocks = True; cli2.use_level_II_oplocks = True; cli_unlink(&cli1, fname); cli_sockopt(&cli1, sockops); cli_sockopt(&cli2, sockops); fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); if (fnum1 == -1) { printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* Don't need the globals any more. */ use_level_II_oplocks = False; use_oplocks = saved_use_oplocks; if (fork() == 0) { /* Child code */ fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE); if (fnum2 == -1) { printf("second open of %s failed (%s)\n", fname, cli_errstr(&cli1)); exit(0); } sleep(2); if (!cli_close(&cli2, fnum2)) { printf("close2 failed (%s)\n", cli_errstr(&cli1)); } exit(0); } sleep(2); /* Ensure cli1 processes the break. */ if (cli_read(&cli1, fnum1, buf, 0, 4) != 4) { printf("read on fnum1 failed (%s)\n", cli_errstr(&cli1)); } /* Should now be at level II. */ /* Test if sending a write locks causes a break to none. */ if (!cli_lock(&cli1, fnum1, 0, 4, 0, READ_LOCK)) { printf("lock failed (%s)\n", cli_errstr(&cli1)); } cli_unlock(&cli1, fnum1, 0, 4); sleep(2); if (!cli_lock(&cli1, fnum1, 0, 4, 0, WRITE_LOCK)) { printf("lock failed (%s)\n", cli_errstr(&cli1)); } cli_unlock(&cli1, fnum1, 0, 4); sleep(2); cli_read(&cli1, fnum1, buf, 0, 4); #if 0 if (cli_write(&cli1, fnum1, 0, buf, 0, 4) != 4) { printf("write on fnum1 failed (%s)\n", cli_errstr(&cli1)); } #endif if (!cli_close(&cli1, fnum1)) { printf("close1 failed (%s)\n", cli_errstr(&cli1)); } sleep(4); if (!cli_unlink(&cli1, fname)) { printf("unlink failed (%s)\n", cli_errstr(&cli1)); } close_connection(&cli1); printf("finished oplock test 2\n"); } /* handler for oplock 3 tests */ static BOOL oplock3_handler(struct cli_state *cli, int fnum, unsigned char level) { printf("got oplock break fnum=%d level=%d\n", fnum, level); return cli_oplock_ack(cli, fnum, level); } static void run_oplock3(int dummy) { static struct cli_state cli; char *fname = "\\oplockt3.dat"; int fnum; char buf[4] = "abcd"; printf("starting oplock test 3\n"); if (fork() == 0) { /* Child code */ use_oplocks = True; use_level_II_oplocks = True; if (!open_connection(&cli)) return; sleep(2); /* try to trigger a oplock break in parent */ fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE); cli_write(&cli, fnum, 0, buf, 0, 4); exit(0); } /* parent code */ use_oplocks = True; use_level_II_oplocks = True; if (!open_connection(&cli)) return; cli_oplock_handler(&cli, oplock3_handler); fnum = cli_open(&cli, fname, O_RDWR|O_CREAT, DENY_NONE); cli_write(&cli, fnum, 0, buf, 0, 4); cli_close(&cli, fnum); fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE); cli.timeout = 20000; cli_receive_smb(&cli); printf("finished oplock test 3\n"); } /* Test delete on close semantics. */ static void run_deletetest(int dummy) { static struct cli_state cli1; static struct cli_state cli2; char *fname = "\\delete.file"; int fnum1, fnum2; printf("starting delete test\n"); if (!open_connection(&cli1)) { return; } cli_sockopt(&cli1, sockops); /* Test 1 - this should *NOT* delete the file on close. */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); fnum1 = cli_nt_create_full(&cli1, fname, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE, FILE_OVERWRITE_IF, DELETE_ON_CLOSE_FLAG); if (fnum1 == -1) { printf("[1] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum1)) { printf("[1] close failed (%s)\n", cli_errstr(&cli1)); return; } fnum1 = cli_open(&cli1, fname, O_RDWR, DENY_NONE); if (fnum1 == -1) { printf("[1] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum1)) { printf("[1] close failed (%s)\n", cli_errstr(&cli1)); return; } printf("first delete on close test succeeded.\n"); /* Test 2 - this should delete the file on close. */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); fnum1 = cli_nt_create_full(&cli1, fname, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0); if (fnum1 == -1) { printf("[2] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_nt_delete_on_close(&cli1, fnum1, True)) { printf("[2] setting delete_on_close failed (%s)\n", cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum1)) { printf("[2] close failed (%s)\n", cli_errstr(&cli1)); return; } fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE); if (fnum1 != -1) { printf("[2] open of %s succeeded should have been deleted on close !\n", fname); if (!cli_close(&cli1, fnum1)) { printf("[2] close failed (%s)\n", cli_errstr(&cli1)); } cli_unlink(&cli1, fname); } else printf("second delete on close test succeeded.\n"); /* Test 3 - ... */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); fnum1 = cli_nt_create_full(&cli1, fname, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0); if (fnum1 == -1) { printf("[3] open - 1 of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* This should fail with a sharing violation - open for delete is only compatible with SHARE_DELETE. */ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0); if (fnum2 != -1) { printf("[3] open - 2 of %s succeeded - should have failed.\n", fname); return; } /* This should succeed. */ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0); if (fnum2 == -1) { printf("[3] open - 2 of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_nt_delete_on_close(&cli1, fnum1, True)) { printf("[3] setting delete_on_close failed (%s)\n", cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum1)) { printf("[3] close 1 failed (%s)\n", cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum2)) { printf("[3] close 2 failed (%s)\n", cli_errstr(&cli1)); return; } /* This should fail - file should no longer be there. */ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE); if (fnum1 != -1) { printf("[3] open of %s succeeded should have been deleted on close !\n", fname); if (!cli_close(&cli1, fnum1)) { printf("[3] close failed (%s)\n", cli_errstr(&cli1)); } cli_unlink(&cli1, fname); } else printf("third delete on close test succeeded.\n"); /* Test 4 ... */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0); if (fnum1 == -1) { printf("[4] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* This should succeed. */ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0); if (fnum2 == -1) { printf("[4] open - 2 of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum2)) { printf("[4] close - 1 failed (%s)\n", cli_errstr(&cli1)); return; } if (!cli_nt_delete_on_close(&cli1, fnum1, True)) { printf("[4] setting delete_on_close failed (%s)\n", cli_errstr(&cli1)); return; } /* This should fail - no more opens once delete on close set. */ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0); if (fnum2 != -1) { printf("[4] open - 3 of %s succeeded ! Should have failed.\n", fname ); return; } else printf("fourth delete on close test succeeded.\n"); if (!cli_close(&cli1, fnum1)) { printf("[4] close - 2 failed (%s)\n", cli_errstr(&cli1)); return; } /* Test 5 ... */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT, DENY_NONE); if (fnum1 == -1) { printf("[5] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* This should fail - only allowed on NT opens with DELETE access. */ if (cli_nt_delete_on_close(&cli1, fnum1, True)) { printf("[5] setting delete_on_close on OpenX file succeeded - should fail !\n"); return; } if (!cli_close(&cli1, fnum1)) { printf("[5] close - 2 failed (%s)\n", cli_errstr(&cli1)); return; } printf("fifth delete on close test succeeded.\n"); /* Test 6 ... */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0); if (fnum1 == -1) { printf("[6] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* This should fail - only allowed on NT opens with DELETE access. */ if (cli_nt_delete_on_close(&cli1, fnum1, True)) { printf("[6] setting delete_on_close on file with no delete access succeeded - should fail !\n"); return; } if (!cli_close(&cli1, fnum1)) { printf("[6] close - 2 failed (%s)\n", cli_errstr(&cli1)); return; } printf("sixth delete on close test succeeded.\n"); /* Test 7 ... */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, 0); if (fnum1 == -1) { printf("[7] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_nt_delete_on_close(&cli1, fnum1, True)) { printf("[7] setting delete_on_close on file failed !\n"); return; } if (!cli_nt_delete_on_close(&cli1, fnum1, False)) { printf("[7] unsetting delete_on_close on file failed !\n"); return; } if (!cli_close(&cli1, fnum1)) { printf("[7] close - 2 failed (%s)\n", cli_errstr(&cli1)); return; } /* This next open should succeed - we reset the flag. */ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE); if (fnum1 == -1) { printf("[5] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum1)) { printf("[7] close - 2 failed (%s)\n", cli_errstr(&cli1)); return; } printf("seventh delete on close test succeeded.\n"); /* Test 7 ... */ cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); if (!open_connection(&cli2)) { printf("[8] failed to open second connection.\n"); return; } cli_sockopt(&cli1, sockops); fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0); if (fnum1 == -1) { printf("[8] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } fnum2 = cli_nt_create_full(&cli2, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0); if (fnum2 == -1) { printf("[8] open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_nt_delete_on_close(&cli1, fnum1, True)) { printf("[8] setting delete_on_close on file failed !\n"); return; } if (!cli_close(&cli1, fnum1)) { printf("[8] close - 1 failed (%s)\n", cli_errstr(&cli1)); return; } if (!cli_close(&cli2, fnum2)) { printf("[8] close - 2 failed (%s)\n", cli_errstr(&cli2)); return; } /* This should fail.. */ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE); if (fnum1 != -1) { printf("[8] open of %s succeeded should have been deleted on close !\n", fname); if (!cli_close(&cli1, fnum1)) { printf("[8] close failed (%s)\n", cli_errstr(&cli1)); } cli_unlink(&cli1, fname); } else printf("eighth delete on close test succeeded.\n"); printf("finished delete test\n"); cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); close_connection(&cli1); close_connection(&cli2); } /* Test open mode returns on read-only files. */ static void run_opentest(int dummy) { static struct cli_state cli1; char *fname = "\\readonly.file"; int fnum1, fnum2; uint8 eclass; uint32 errnum; char buf[20]; size_t fsize; printf("starting open test\n"); if (!open_connection(&cli1)) { return; } cli_setatr(&cli1, fname, 0, 0); cli_unlink(&cli1, fname); cli_sockopt(&cli1, sockops); fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); if (fnum1 == -1) { printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum1)) { printf("close2 failed (%s)\n", cli_errstr(&cli1)); return; } if (!cli_setatr(&cli1, fname, aRONLY, 0)) { printf("cli_setatr failed (%s)\n", cli_errstr(&cli1)); return; } fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_WRITE); if (fnum1 == -1) { printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* This will fail - but the error should be ERRnoaccess, not ERRbadshare. */ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_ALL); cli_error( &cli1, &eclass, &errnum, NULL); if (eclass != ERRDOS || errnum != ERRnoaccess) { printf("wrong error code (%x,%x) = %s\n", (unsigned int)eclass, (unsigned int)errnum, cli_errstr(&cli1) ); } else { printf("correct error code ERRDOS/ERRnoaccess returned\n"); } printf("finished open test 1\n"); cli_close(&cli1, fnum1); /* Now try not readonly and ensure ERRbadshare is returned. */ cli_setatr(&cli1, fname, 0, 0); fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_WRITE); if (fnum1 == -1) { printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* This will fail - but the error should be ERRshare. */ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_ALL); cli_error( &cli1, &eclass, &errnum, NULL); if (eclass != ERRDOS || errnum != ERRbadshare) { printf("wrong error code (%x,%x) = %s\n", (unsigned int)eclass, (unsigned int)errnum, cli_errstr(&cli1) ); } else { printf("correct error code ERRDOS/ERRbadshare returned\n"); } if (!cli_close(&cli1, fnum1)) { printf("close2 failed (%s)\n", cli_errstr(&cli1)); return; } cli_unlink(&cli1, fname); printf("finished open test 2\n"); /* Test truncate open disposition on file opened for read. */ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); if (fnum1 == -1) { printf("(3) open (1) of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } /* write 20 bytes. */ memset(buf, '\0', 20); if (cli_write(&cli1, fnum1, 0, buf, 0, 20) != 20) { printf("write failed (%s)\n", cli_errstr(&cli1)); } if (!cli_close(&cli1, fnum1)) { printf("(3) close1 failed (%s)\n", cli_errstr(&cli1)); return; } /* Ensure size == 20. */ if (!cli_getatr(&cli1, fname, NULL, &fsize, NULL)) { printf("(3) getatr failed (%s)\n", cli_errstr(&cli1)); return; } if (fsize != 20) { printf("(3) file size != 20\n"); return; } /* Now test if we can truncate a file opened for readonly. */ fnum1 = cli_open(&cli1, fname, O_RDONLY|O_TRUNC, DENY_NONE); if (fnum1 == -1) { printf("(3) open (2) of %s failed (%s)\n", fname, cli_errstr(&cli1)); return; } if (!cli_close(&cli1, fnum1)) { printf("close2 failed (%s)\n", cli_errstr(&cli1)); return; } /* Ensure size == 0. */ if (!cli_getatr(&cli1, fname, NULL, &fsize, NULL)) { printf("(3) getatr failed (%s)\n", cli_errstr(&cli1)); return; } if (fsize != 0) { printf("(3) file size != 0\n"); return; } printf("finished open test 3\n"); cli_unlink(&cli1, fname); printf("testing ctemp\n"); { char *tmp_path; fnum1 = cli_ctemp(&cli1, "\\", &tmp_path); if (fnum1 == -1) { printf("ctemp failed (%s)\n", cli_errstr(&cli1)); return; } printf("ctemp gave path %s\n", tmp_path); cli_close(&cli1, fnum1); cli_unlink(&cli1, tmp_path); } close_connection(&cli1); } static void list_fn(file_info *finfo, const char *name, void *state) { } /* test directory listing speed */ static void run_dirtest(int dummy) { int i; static struct cli_state cli; int fnum; double t1; printf("starting directory test\n"); if (!open_connection(&cli)) { return; } cli_sockopt(&cli, sockops); srandom(0); for (i=0;i TEST1 TEST2 ...\n"); printf("\t-d debuglevel\n"); printf("\t-U user%%pass\n"); printf("\t-N numprocs\n"); printf("\t-n my_netbios_name\n"); printf("\t-W workgroup\n"); printf("\t-o num_operations\n"); printf("\t-O socket_options\n"); printf("\t-m maximum protocol\n"); printf("\t-L use oplocks\n"); printf("\n\n"); printf("tests are:"); for (i=0;torture_ops[i].name;i++) { printf(" %s", torture_ops[i].name); } printf("\n"); printf("default test is ALL\n"); exit(1); } /**************************************************************************** main program ****************************************************************************/ int main(int argc,char *argv[]) { int opt, i; char *p; int gotpass = 0; extern char *optarg; extern int optind; extern FILE *dbf; static pstring servicesf = CONFIGFILE; dbf = stdout; setbuffer(stdout, NULL, 0); charset_initialise(); codepage_initialise(lp_client_code_page()); codepage_initialise(lp_client_code_page()); lp_load(servicesf,True,False,False); load_interfaces(); if (argc < 2) { usage(); } for(p = argv[1]; *p; p++) if(*p == '\\') *p = '/'; if (strncmp(argv[1], "//", 2)) { usage(); } fstrcpy(host, &argv[1][2]); p = strchr(&host[2],'/'); if (!p) { usage(); } *p = 0; fstrcpy(share, p+1); get_myname(myname); if (*username == 0 && getenv("LOGNAME")) { pstrcpy(username,getenv("LOGNAME")); } argc--; argv++; fstrcpy(workgroup, lp_workgroup()); while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:Ld:")) != EOF) { switch (opt) { case 'W': fstrcpy(workgroup,optarg); break; case 'm': max_protocol = interpret_protocol(optarg, max_protocol); break; case 'N': nprocs = atoi(optarg); break; case 'o': numops = atoi(optarg); break; case 'd': DEBUGLEVEL = atoi(optarg); break; case 'O': sockops = optarg; break; case 'L': use_oplocks = True; break; case 'n': fstrcpy(myname, optarg); break; case 'U': pstrcpy(username,optarg); p = strchr(username,'%'); if (p) { *p = 0; pstrcpy(password, p+1); gotpass = 1; } break; default: printf("Unknown option %c (%d)\n", (char)opt, opt); usage(); } } while (!gotpass) { p = getpass("Password:"); if (p) { pstrcpy(password, p); gotpass = 1; } } printf("host=%s share=%s user=%s myname=%s\n", host, share, username, myname); if (argc == 1) { run_test("ALL"); } else { for (i=1;i