diff options
Diffstat (limited to 'source4/torture/masktest.c')
-rw-r--r-- | source4/torture/masktest.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/source4/torture/masktest.c b/source4/torture/masktest.c new file mode 100644 index 0000000000..35e9a57fe8 --- /dev/null +++ b/source4/torture/masktest.c @@ -0,0 +1,378 @@ +/* + Unix SMB/CIFS implementation. + mask_match tester + Copyright (C) Andrew Tridgell 1999 + + 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 "lib/cmdline/popt_common.h" +#include "system/filesys.h" +#include "system/dir.h" +#include "libcli/libcli.h" +#include "libcli/raw/libcliraw.h" +#include "system/time.h" +#include "pstring.h" +#include "auth/credentials/credentials.h" +#include "auth/gensec/gensec.h" +#include "param/param.h" +#include "dynconfig/dynconfig.h" +#include "libcli/resolve/resolve.h" +#include "lib/events/events.h" + +static bool showall = false; +static bool old_list = false; +static const char *maskchars = "<>\"?*abc."; +static const char *filechars = "abcdefghijklm."; +static int die_on_error; +static int NumLoops = 0; +static int max_length = 20; +struct masktest_state { + TALLOC_CTX *mem_ctx; +}; + +static bool reg_match_one(struct smbcli_state *cli, const char *pattern, const char *file) +{ + /* oh what a weird world this is */ + if (old_list && strcmp(pattern, "*.*") == 0) return true; + + if (ISDOT(pattern)) return false; + + if (ISDOTDOT(file)) file = "."; + + return ms_fnmatch(pattern, file, cli->transport->negotiate.protocol)==0; +} + +static char *reg_test(struct smbcli_state *cli, char *pattern, char *long_name, char *short_name) +{ + static fstring ret; + fstrcpy(ret, "---"); + + pattern = 1+strrchr_m(pattern,'\\'); + + if (reg_match_one(cli, pattern, ".")) ret[0] = '+'; + if (reg_match_one(cli, pattern, "..")) ret[1] = '+'; + if (reg_match_one(cli, pattern, long_name) || + (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+'; + return ret; +} + + +/***************************************************** +return a connection to a server +*******************************************************/ +static struct smbcli_state *connect_one(struct resolve_context *resolve_ctx, + struct event_context *ev, + char *share, const char **ports, + struct smbcli_options *options) +{ + struct smbcli_state *c; + fstring server; + NTSTATUS status; + + fstrcpy(server,share+2); + share = strchr_m(server,'\\'); + if (!share) return NULL; + *share = 0; + share++; + + cli_credentials_set_workstation(cmdline_credentials, "masktest", CRED_SPECIFIED); + + status = smbcli_full_connection(NULL, &c, + server, + ports, + share, NULL, + cmdline_credentials, resolve_ctx, ev, + options); + + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + + return c; +} + +static char *resultp; +static struct { + char *long_name; + char *short_name; +} last_hit; +static bool f_info_hit; + +static void listfn(struct clilist_file_info *f, const char *s, void *state) +{ + struct masktest_state *m = (struct masktest_state *)state; + + if (ISDOT(f->name)) { + resultp[0] = '+'; + } else if (ISDOTDOT(f->name)) { + resultp[1] = '+'; + } else { + resultp[2] = '+'; + } + + last_hit.long_name = talloc_strdup(m->mem_ctx, f->name); + last_hit.short_name = talloc_strdup(m->mem_ctx, f->short_name); + f_info_hit = true; +} + +static void get_real_name(TALLOC_CTX *mem_ctx, struct smbcli_state *cli, + char **long_name, fstring short_name) +{ + const char *mask; + struct masktest_state state; + + if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1) { + mask = "\\masktest\\*.*"; + } else { + mask = "\\masktest\\*"; + } + + f_info_hit = false; + + state.mem_ctx = mem_ctx; + + smbcli_list_new(cli->tree, mask, + FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY, + RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, + listfn, &state); + + if (f_info_hit) { + fstrcpy(short_name, last_hit.short_name); + strlower(short_name); + *long_name = talloc_strdup(mem_ctx, last_hit.long_name); + strlower(*long_name); + } + + if (*short_name == '\0') { + fstrcpy(short_name, *long_name); + } +} + +static void testpair(TALLOC_CTX *mem_ctx, struct smbcli_state *cli, char *mask, + char *file) +{ + int fnum; + fstring res1; + char *res2; + static int count; + fstring short_name; + char *long_name = NULL; + struct masktest_state state; + + count++; + + fstrcpy(res1, "---"); + + state.mem_ctx = mem_ctx; + + fnum = smbcli_open(cli->tree, file, O_CREAT|O_TRUNC|O_RDWR, 0); + if (fnum == -1) { + DEBUG(0,("Can't create %s\n", file)); + return; + } + smbcli_close(cli->tree, fnum); + + resultp = res1; + fstrcpy(short_name, ""); + get_real_name(mem_ctx, cli, &long_name, short_name); + fstrcpy(res1, "---"); + smbcli_list_new(cli->tree, mask, + FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY, + RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, + listfn, &state); + + res2 = reg_test(cli, mask, long_name, short_name); + + if (showall || strcmp(res1, res2)) { + d_printf("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n", + res1, res2, count, mask, file, long_name, short_name); + if (die_on_error) exit(1); + } + + smbcli_unlink(cli->tree, file); + + if (count % 100 == 0) DEBUG(0,("%d\n", count)); + + resultp = NULL; +} + +static void test_mask(int argc, char *argv[], + struct smbcli_state *cli) +{ + TALLOC_CTX *mem_ctx; + char *mask, *file; + int l1, l2, i, l; + int mc_len = strlen(maskchars); + int fc_len = strlen(filechars); + + mem_ctx = talloc_init("test_mask"); + + smbcli_mkdir(cli->tree, "\\masktest"); + + smbcli_unlink(cli->tree, "\\masktest\\*"); + + if (argc >= 2) { + while (argc >= 2) { + mask = talloc_strdup(mem_ctx, "\\masktest\\"); + file = talloc_strdup(mem_ctx, "\\masktest\\"); + mask = talloc_strdup_append(mask, argv[0]); + file = talloc_strdup_append(file, argv[1]); + testpair(mem_ctx, cli, mask, file); + argv += 2; + argc -= 2; + } + goto finished; + } + + while (1) { + l1 = 1 + random() % max_length; + l2 = 1 + random() % max_length; + mask = talloc_strdup(mem_ctx, "\\masktest\\"); + file = talloc_strdup(mem_ctx, "\\masktest\\"); + mask = talloc_realloc_size(mem_ctx, mask, strlen(mask)+l1+1); + file = talloc_realloc_size(mem_ctx, file, strlen(file)+l2+1); + l = strlen(mask); + for (i=0;i<l1;i++) { + mask[i+l] = maskchars[random() % mc_len]; + } + mask[l+l1] = 0; + + for (i=0;i<l2;i++) { + file[i+l] = filechars[random() % fc_len]; + } + file[l+l2] = 0; + + if (ISDOT(file+l) || ISDOTDOT(file+l) || ISDOTDOT(mask+l)) { + continue; + } + + if (strspn(file+l, ".") == strlen(file+l)) continue; + + testpair(mem_ctx, cli, mask, file); + if (NumLoops && (--NumLoops == 0)) + break; + } + + finished: + smbcli_rmdir(cli->tree, "\\masktest"); + talloc_free(mem_ctx); +} + + +static void usage(poptContext pc) +{ + printf( +"Usage:\n\ + masktest //server/share [options..]\n\ +\n\ + This program tests wildcard matching between two servers. It generates\n\ + random pairs of filenames/masks and tests that they match in the same\n\ + way on the servers and internally\n"); + poptPrintUsage(pc, stdout, 0); +} + +/**************************************************************************** + main program +****************************************************************************/ + int main(int argc,char *argv[]) +{ + char *share; + struct smbcli_state *cli; + int opt; + int seed; + struct event_context *ev; + struct loadparm_context *lp_ctx; + struct smbcli_options options; + poptContext pc; + int argc_new, i; + char **argv_new; + enum {OPT_UNCLIST=1000}; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"seed", 0, POPT_ARG_INT, &seed, 0, "Seed to use for randomizer", NULL}, + {"num-ops", 0, POPT_ARG_INT, &NumLoops, 0, "num ops", NULL}, + {"maxlength", 0, POPT_ARG_INT, &max_length,0, "maximum length", NULL}, + {"dieonerror", 0, POPT_ARG_NONE, &die_on_error, 0, "die on errors", NULL}, + {"showall", 0, POPT_ARG_NONE, &showall, 0, "display all operations", NULL}, + {"oldlist", 0, POPT_ARG_NONE, &old_list, 0, "use old list call", NULL}, + {"maskchars", 0, POPT_ARG_STRING, &maskchars, 0,"mask characters", NULL}, + {"filechars", 0, POPT_ARG_STRING, &filechars, 0,"file characters", NULL}, + POPT_COMMON_SAMBA + POPT_COMMON_CONNECTION + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + { NULL } + }; + + setlinebuf(stdout); + seed = time(NULL); + + pc = poptGetContext("locktest", argc, (const char **) argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + + poptSetOtherOptionHelp(pc, "<unc>"); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_UNCLIST: + lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc)); + break; + } + } + + argv_new = discard_const_p(char *, poptGetArgs(pc)); + argc_new = argc; + for (i=0; i<argc; i++) { + if (argv_new[i] == NULL) { + argc_new = i; + break; + } + } + + if (!(argc_new >= 2)) { + usage(pc); + exit(1); + } + + setup_logging("masktest", DEBUG_STDOUT); + + share = argv_new[1]; + + all_string_sub(share,"/","\\",0); + + lp_ctx = cmdline_lp_ctx; + + ev = s4_event_context_init(talloc_autofree_context()); + + gensec_init(lp_ctx); + + lp_smbcli_options(lp_ctx, &options); + + cli = connect_one(lp_resolve_context(lp_ctx), ev, share, + lp_smb_ports(lp_ctx), &options); + if (!cli) { + DEBUG(0,("Failed to connect to %s\n", share)); + exit(1); + } + + /* need to init seed after connect as clientgen uses random numbers */ + DEBUG(0,("seed=%d format --- --- (server, correct)\n", seed)); + srandom(seed); + + test_mask(argc_new-1, argv_new+1, cli); + + return(0); +} |