Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : mask_match tester
4 : Copyright (C) Andrew Tridgell 1999
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "lib/cmdline/cmdline.h"
22 : #include "system/filesys.h"
23 : #include "system/dir.h"
24 : #include "libcli/libcli.h"
25 : #include "system/time.h"
26 : #include "auth/credentials/credentials.h"
27 : #include "auth/gensec/gensec.h"
28 : #include "param/param.h"
29 : #include "libcli/resolve/resolve.h"
30 : #include "lib/events/events.h"
31 :
32 : static bool showall = false;
33 : static bool old_list = false;
34 : static const char *maskchars = "<>\"?*abc.";
35 : static const char *filechars = "abcdefghijklm.";
36 : static int die_on_error;
37 : static int NumLoops = 0;
38 : static int max_length = 20;
39 : struct masktest_state {
40 : TALLOC_CTX *mem_ctx;
41 : };
42 :
43 793 : static bool reg_match_one(struct smbcli_state *cli, const char *pattern, const char *file)
44 : {
45 : /* oh what a weird world this is */
46 793 : if (old_list && strcmp(pattern, "*.*") == 0) return true;
47 :
48 793 : if (ISDOT(pattern)) return false;
49 :
50 793 : if (ISDOTDOT(file)) file = ".";
51 :
52 793 : return ms_fnmatch_protocol(
53 793 : pattern, file, cli->transport->negotiate.protocol, false)==0;
54 : }
55 :
56 200 : static char *reg_test(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *pattern, const char *long_name, const char *short_name)
57 : {
58 : char *ret;
59 200 : ret = talloc_strdup(mem_ctx, "---");
60 :
61 200 : pattern = 1+strrchr_m(pattern,'\\');
62 :
63 200 : if (reg_match_one(cli, pattern, ".")) ret[0] = '+';
64 200 : if (reg_match_one(cli, pattern, "..")) ret[1] = '+';
65 200 : if (reg_match_one(cli, pattern, long_name) ||
66 200 : (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+';
67 200 : return ret;
68 : }
69 :
70 :
71 : /*****************************************************
72 : return a connection to a server
73 : *******************************************************/
74 1 : static struct smbcli_state *connect_one(struct resolve_context *resolve_ctx,
75 : struct tevent_context *ev,
76 : TALLOC_CTX *mem_ctx,
77 : char *share, const char **ports,
78 : const char *socket_options,
79 : struct smbcli_options *options,
80 : struct smbcli_session_options *session_options,
81 : struct gensec_settings *gensec_settings)
82 : {
83 : struct smbcli_state *c;
84 : char *server;
85 : NTSTATUS status;
86 1 : struct cli_credentials *creds = samba_cmdline_get_creds();
87 :
88 1 : server = talloc_strdup(mem_ctx, share+2);
89 1 : share = strchr_m(server,'\\');
90 1 : if (!share) return NULL;
91 1 : *share = 0;
92 1 : share++;
93 :
94 1 : cli_credentials_set_workstation(creds,
95 : "masktest", CRED_SPECIFIED);
96 :
97 1 : status = smbcli_full_connection(NULL, &c,
98 : server,
99 : ports,
100 : share, NULL,
101 : socket_options,
102 : creds,
103 : resolve_ctx, ev,
104 : options, session_options,
105 : gensec_settings);
106 :
107 1 : if (!NT_STATUS_IS_OK(status)) {
108 0 : return NULL;
109 : }
110 :
111 1 : return c;
112 : }
113 :
114 : static char *resultp;
115 : static struct {
116 : char *long_name;
117 : char *short_name;
118 : } last_hit;
119 : static bool f_info_hit;
120 :
121 634 : static void listfn(struct clilist_file_info *f, const char *s, void *state)
122 : {
123 634 : struct masktest_state *m = (struct masktest_state *)state;
124 :
125 634 : if (ISDOT(f->name)) {
126 213 : resultp[0] = '+';
127 421 : } else if (ISDOTDOT(f->name)) {
128 213 : resultp[1] = '+';
129 : } else {
130 208 : resultp[2] = '+';
131 : }
132 :
133 634 : last_hit.long_name = talloc_strdup(m->mem_ctx, f->name);
134 634 : last_hit.short_name = talloc_strdup(m->mem_ctx, f->short_name);
135 634 : f_info_hit = true;
136 634 : }
137 :
138 200 : static void get_real_name(TALLOC_CTX *mem_ctx, struct smbcli_state *cli,
139 : char **long_name, char **short_name)
140 : {
141 : const char *mask;
142 : struct masktest_state state;
143 :
144 200 : if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1) {
145 0 : mask = "\\masktest\\*.*";
146 : } else {
147 200 : mask = "\\masktest\\*";
148 : }
149 :
150 200 : f_info_hit = false;
151 :
152 200 : state.mem_ctx = mem_ctx;
153 :
154 200 : smbcli_list_new(cli->tree, mask,
155 : FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,
156 : RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
157 : listfn, &state);
158 :
159 200 : if (f_info_hit) {
160 200 : *short_name = strlower_talloc(mem_ctx, last_hit.short_name);
161 200 : *long_name = strlower_talloc(mem_ctx, last_hit.long_name);
162 : }
163 :
164 200 : if (*short_name[0] == '\0') {
165 0 : *short_name = talloc_strdup(mem_ctx, *long_name);
166 : }
167 200 : }
168 :
169 200 : static void testpair(TALLOC_CTX *mem_ctx, struct smbcli_state *cli, char *mask,
170 : char *file)
171 : {
172 : int fnum;
173 : char res1[256];
174 : char *res2;
175 : static int count;
176 200 : char *short_name = NULL;
177 200 : char *long_name = NULL;
178 : struct masktest_state state;
179 :
180 200 : count++;
181 :
182 200 : strlcpy(res1, "---", sizeof(res1));
183 :
184 200 : state.mem_ctx = mem_ctx;
185 :
186 200 : fnum = smbcli_open(cli->tree, file, O_CREAT|O_TRUNC|O_RDWR, 0);
187 200 : if (fnum == -1) {
188 0 : DEBUG(0,("Can't create %s\n", file));
189 0 : return;
190 : }
191 200 : smbcli_close(cli->tree, fnum);
192 :
193 200 : resultp = res1;
194 200 : short_name = talloc_strdup(mem_ctx, "");
195 200 : get_real_name(mem_ctx, cli, &long_name, &short_name);
196 200 : strlcpy(res1, "---", sizeof(res1));
197 200 : smbcli_list_new(cli->tree, mask,
198 : FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,
199 : RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
200 : listfn, &state);
201 :
202 200 : res2 = reg_test(cli, mem_ctx, mask, long_name, short_name);
203 :
204 200 : if (showall || strcmp(res1, res2)) {
205 0 : d_printf("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
206 : res1, res2, count, mask, file, long_name, short_name);
207 0 : if (die_on_error) exit(1);
208 : }
209 :
210 200 : smbcli_unlink(cli->tree, file);
211 :
212 200 : if (count % 100 == 0) DEBUG(0,("%d\n", count));
213 :
214 200 : resultp = NULL;
215 : }
216 :
217 1 : static void test_mask(int argc, char *argv[],
218 : TALLOC_CTX *mem_ctx,
219 : struct smbcli_state *cli)
220 : {
221 : char *mask, *file;
222 : int l1, l2, i, l;
223 1 : int mc_len = strlen(maskchars);
224 1 : int fc_len = strlen(filechars);
225 :
226 1 : smbcli_mkdir(cli->tree, "\\masktest");
227 :
228 1 : smbcli_unlink_wcard(cli->tree, "\\masktest\\*");
229 :
230 1 : if (argc >= 2) {
231 0 : while (argc >= 2) {
232 0 : mask = talloc_strdup(mem_ctx, "\\masktest\\");
233 0 : file = talloc_strdup(mem_ctx, "\\masktest\\");
234 0 : mask = talloc_strdup_append(mask, argv[0]);
235 0 : file = talloc_strdup_append(file, argv[1]);
236 0 : testpair(mem_ctx, cli, mask, file);
237 0 : argv += 2;
238 0 : argc -= 2;
239 : }
240 0 : goto finished;
241 : }
242 :
243 : while (1) {
244 201 : l1 = 1 + random() % max_length;
245 201 : l2 = 1 + random() % max_length;
246 201 : mask = talloc_strdup(mem_ctx, "\\masktest\\");
247 201 : file = talloc_strdup(mem_ctx, "\\masktest\\");
248 201 : mask = talloc_realloc_size(mem_ctx, mask, strlen(mask)+l1+1);
249 201 : file = talloc_realloc_size(mem_ctx, file, strlen(file)+l2+1);
250 201 : l = strlen(mask);
251 2364 : for (i=0;i<l1;i++) {
252 2163 : mask[i+l] = maskchars[random() % mc_len];
253 : }
254 201 : mask[l+l1] = 0;
255 :
256 2345 : for (i=0;i<l2;i++) {
257 2144 : file[i+l] = filechars[random() % fc_len];
258 : }
259 201 : file[l+l2] = 0;
260 :
261 201 : if (ISDOT(file+l) || ISDOTDOT(file+l) || ISDOTDOT(mask+l)) {
262 1 : continue;
263 : }
264 :
265 200 : if (strspn(file+l, ".") == strlen(file+l)) continue;
266 :
267 200 : testpair(mem_ctx, cli, mask, file);
268 200 : if (NumLoops && (--NumLoops == 0))
269 1 : break;
270 : }
271 :
272 1 : finished:
273 1 : smbcli_rmdir(cli->tree, "\\masktest");
274 1 : }
275 :
276 :
277 0 : static void usage(poptContext pc)
278 : {
279 0 : printf(
280 : "Usage:\n\
281 : masktest //server/share [options..]\n\
282 : \n\
283 : This program tests wildcard matching between two servers. It generates\n\
284 : random pairs of filenames/masks and tests that they match in the same\n\
285 : way on the servers and internally\n");
286 0 : poptPrintUsage(pc, stdout, 0);
287 0 : }
288 :
289 : /****************************************************************************
290 : main program
291 : ****************************************************************************/
292 1 : int main(int argc, const char *argv[])
293 : {
294 : char *share;
295 : struct smbcli_state *cli;
296 : int opt;
297 : int seed;
298 : struct tevent_context *ev;
299 : struct loadparm_context *lp_ctx;
300 : struct smbcli_options options;
301 : struct smbcli_session_options session_options;
302 : poptContext pc;
303 : int argc_new, i;
304 : char **argv_new;
305 1 : TALLOC_CTX *mem_ctx = NULL;
306 : enum {OPT_UNCLIST=1000};
307 6 : struct poptOption long_options[] = {
308 : POPT_AUTOHELP
309 : {"seed", 0, POPT_ARG_INT, &seed, 0, "Seed to use for randomizer", NULL},
310 : {"num-ops", 0, POPT_ARG_INT, &NumLoops, 0, "num ops", NULL},
311 : {"maxlength", 0, POPT_ARG_INT, &max_length,0, "maximum length", NULL},
312 : {"dieonerror", 0, POPT_ARG_NONE, &die_on_error, 0, "die on errors", NULL},
313 : {"showall", 0, POPT_ARG_NONE, &showall, 0, "display all operations", NULL},
314 : {"oldlist", 0, POPT_ARG_NONE, &old_list, 0, "use old list call", NULL},
315 : {"maskchars", 0, POPT_ARG_STRING, &maskchars, 0,"mask characters", NULL},
316 : {"filechars", 0, POPT_ARG_STRING, &filechars, 0,"file characters", NULL},
317 1 : POPT_COMMON_SAMBA
318 1 : POPT_COMMON_CONNECTION
319 1 : POPT_COMMON_CREDENTIALS
320 1 : POPT_COMMON_VERSION
321 1 : POPT_LEGACY_S4
322 : POPT_TABLEEND
323 : };
324 : bool ok;
325 :
326 1 : setlinebuf(stdout);
327 1 : seed = time(NULL);
328 :
329 1 : mem_ctx = talloc_named_const(NULL, 0, "masktest_ctx");
330 1 : if (mem_ctx == NULL) {
331 0 : exit(1);
332 : }
333 :
334 1 : ok = samba_cmdline_init(mem_ctx,
335 : SAMBA_CMDLINE_CONFIG_CLIENT,
336 : false /* require_smbconf */);
337 1 : if (!ok) {
338 0 : DBG_ERR("Failed to init cmdline parser!\n");
339 0 : exit(1);
340 : }
341 :
342 1 : pc = samba_popt_get_context(getprogname(),
343 : argc,
344 : argv,
345 : long_options,
346 : POPT_CONTEXT_KEEP_FIRST);
347 1 : if (pc == NULL) {
348 0 : DBG_ERR("Failed to setup popt context!\n");
349 0 : exit(1);
350 : }
351 :
352 1 : poptSetOtherOptionHelp(pc, "<unc>");
353 :
354 1 : lp_ctx = samba_cmdline_get_lp_ctx();
355 :
356 1 : while((opt = poptGetNextOpt(pc)) != -1) {
357 0 : switch (opt) {
358 0 : case OPT_UNCLIST:
359 0 : lpcfg_set_cmdline(lp_ctx,
360 : "torture:unclist",
361 0 : poptGetOptArg(pc));
362 0 : break;
363 0 : case POPT_ERROR_BADOPT:
364 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
365 : poptBadOption(pc, 0), poptStrerror(opt));
366 0 : poptPrintUsage(pc, stderr, 0);
367 0 : exit(1);
368 : }
369 : }
370 :
371 1 : argv_new = discard_const_p(char *, poptGetArgs(pc));
372 1 : argc_new = argc;
373 3 : for (i=0; i<argc; i++) {
374 3 : if (argv_new[i] == NULL) {
375 1 : argc_new = i;
376 1 : break;
377 : }
378 : }
379 :
380 1 : if (!(argc_new >= 2)) {
381 0 : usage(pc);
382 0 : talloc_free(mem_ctx);
383 0 : exit(1);
384 : }
385 :
386 1 : setup_logging("masktest", DEBUG_STDOUT);
387 :
388 1 : share = argv_new[1];
389 :
390 1 : all_string_sub(share,"/","\\",0);
391 :
392 1 : ev = s4_event_context_init(mem_ctx);
393 :
394 1 : gensec_init();
395 :
396 1 : lpcfg_smbcli_options(lp_ctx, &options);
397 1 : lpcfg_smbcli_session_options(lp_ctx, &session_options);
398 :
399 1 : cli = connect_one(lpcfg_resolve_context(lp_ctx), ev, mem_ctx, share,
400 : lpcfg_smb_ports(lp_ctx), lpcfg_socket_options(lp_ctx),
401 : &options, &session_options,
402 : lpcfg_gensec_settings(mem_ctx, lp_ctx));
403 1 : if (!cli) {
404 0 : DEBUG(0,("Failed to connect to %s\n", share));
405 0 : talloc_free(mem_ctx);
406 0 : exit(1);
407 : }
408 :
409 : /* need to init seed after connect as clientgen uses random numbers */
410 1 : DEBUG(0,("seed=%d format --- --- (server, correct)\n", seed));
411 1 : srandom(seed);
412 :
413 1 : test_mask(argc_new-1, argv_new+1, mem_ctx, cli);
414 :
415 1 : poptFreeContext(pc);
416 1 : talloc_free(mem_ctx);
417 1 : return(0);
418 : }
|