diff options
Diffstat (limited to 'source4/torture/masktest.c')
-rw-r--r-- | source4/torture/masktest.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/source4/torture/masktest.c b/source4/torture/masktest.c new file mode 100644 index 0000000..e311769 --- /dev/null +++ b/source4/torture/masktest.c @@ -0,0 +1,418 @@ +/* + 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/cmdline.h" +#include "system/filesys.h" +#include "system/dir.h" +#include "libcli/libcli.h" +#include "system/time.h" +#include "auth/credentials/credentials.h" +#include "auth/gensec/gensec.h" +#include "param/param.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_protocol( + pattern, file, cli->transport->negotiate.protocol, false)==0; +} + +static char *reg_test(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *pattern, const char *long_name, const char *short_name) +{ + char *ret; + ret = talloc_strdup(mem_ctx, "---"); + + 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 tevent_context *ev, + TALLOC_CTX *mem_ctx, + char *share, const char **ports, + const char *socket_options, + struct smbcli_options *options, + struct smbcli_session_options *session_options, + struct gensec_settings *gensec_settings) +{ + struct smbcli_state *c; + char *server; + NTSTATUS status; + struct cli_credentials *creds = samba_cmdline_get_creds(); + + server = talloc_strdup(mem_ctx, share+2); + share = strchr_m(server,'\\'); + if (!share) return NULL; + *share = 0; + share++; + + cli_credentials_set_workstation(creds, + "masktest", CRED_SPECIFIED); + + status = smbcli_full_connection(NULL, &c, + server, + ports, + share, NULL, + socket_options, + creds, + resolve_ctx, ev, + options, session_options, + gensec_settings); + + 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, char **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) { + *short_name = strlower_talloc(mem_ctx, last_hit.short_name); + *long_name = strlower_talloc(mem_ctx, last_hit.long_name); + } + + if (*short_name[0] == '\0') { + *short_name = talloc_strdup(mem_ctx, *long_name); + } +} + +static void testpair(TALLOC_CTX *mem_ctx, struct smbcli_state *cli, char *mask, + char *file) +{ + int fnum; + char res1[256]; + char *res2; + static int count; + char *short_name = NULL; + char *long_name = NULL; + struct masktest_state state; + + count++; + + strlcpy(res1, "---", sizeof(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; + short_name = talloc_strdup(mem_ctx, ""); + get_real_name(mem_ctx, cli, &long_name, &short_name); + strlcpy(res1, "---", sizeof(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, mem_ctx, 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[], + TALLOC_CTX *mem_ctx, + struct smbcli_state *cli) +{ + char *mask, *file; + int l1, l2, i, l; + int mc_len = strlen(maskchars); + int fc_len = strlen(filechars); + + smbcli_mkdir(cli->tree, "\\masktest"); + + smbcli_unlink_wcard(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"); +} + + +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, const char *argv[]) +{ + char *share; + struct smbcli_state *cli; + int opt; + int seed; + struct tevent_context *ev; + struct loadparm_context *lp_ctx; + struct smbcli_options options; + struct smbcli_session_options session_options; + poptContext pc; + int argc_new, i; + char **argv_new; + TALLOC_CTX *mem_ctx = NULL; + 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 + POPT_LEGACY_S4 + POPT_TABLEEND + }; + bool ok; + + setlinebuf(stdout); + seed = time(NULL); + + mem_ctx = talloc_named_const(NULL, 0, "masktest_ctx"); + if (mem_ctx == NULL) { + exit(1); + } + + ok = samba_cmdline_init(mem_ctx, + SAMBA_CMDLINE_CONFIG_CLIENT, + false /* require_smbconf */); + if (!ok) { + DBG_ERR("Failed to init cmdline parser!\n"); + exit(1); + } + + pc = samba_popt_get_context(getprogname(), + argc, + argv, + long_options, + POPT_CONTEXT_KEEP_FIRST); + if (pc == NULL) { + DBG_ERR("Failed to setup popt context!\n"); + exit(1); + } + + poptSetOtherOptionHelp(pc, "<unc>"); + + lp_ctx = samba_cmdline_get_lp_ctx(); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_UNCLIST: + lpcfg_set_cmdline(lp_ctx, + "torture:unclist", + poptGetOptArg(pc)); + break; + case POPT_ERROR_BADOPT: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + exit(1); + } + } + + 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); + talloc_free(mem_ctx); + exit(1); + } + + setup_logging("masktest", DEBUG_STDOUT); + + share = argv_new[1]; + + all_string_sub(share,"/","\\",0); + + ev = s4_event_context_init(mem_ctx); + + gensec_init(); + + lpcfg_smbcli_options(lp_ctx, &options); + lpcfg_smbcli_session_options(lp_ctx, &session_options); + + cli = connect_one(lpcfg_resolve_context(lp_ctx), ev, mem_ctx, share, + lpcfg_smb_ports(lp_ctx), lpcfg_socket_options(lp_ctx), + &options, &session_options, + lpcfg_gensec_settings(mem_ctx, lp_ctx)); + if (!cli) { + DEBUG(0,("Failed to connect to %s\n", share)); + talloc_free(mem_ctx); + 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, mem_ctx, cli); + + poptFreeContext(pc); + talloc_free(mem_ctx); + return(0); +} |