~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/torture/masktest.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 2 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, write to the Free Software
18
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
*/
20
 
 
21
 
#include "includes.h"
22
 
 
23
 
static fstring password;
24
 
static fstring username;
25
 
static int got_pass;
26
 
static int max_protocol = PROTOCOL_NT1;
27
 
static BOOL showall = False;
28
 
static BOOL old_list = False;
29
 
static const char *maskchars = "<>\"?*abc.";
30
 
static const char *filechars = "abcdefghijklm.";
31
 
static int verbose;
32
 
static int die_on_error;
33
 
static int NumLoops = 0;
34
 
static int ignore_dot_errors = 0;
35
 
 
36
 
/* a test fn for LANMAN mask support */
37
 
int ms_fnmatch_lanman_core(const char *pattern, const char *string)
38
 
{
39
 
        const char *p = pattern, *n = string;
40
 
        char c;
41
 
 
42
 
        if (strcmp(p,"?")==0 && strcmp(n,".")==0) goto match;
43
 
 
44
 
        while ((c = *p++)) {
45
 
                switch (c) {
46
 
                case '.':
47
 
                        /* if (! *n && ! *p) goto match; */
48
 
                        if (*n != '.') goto nomatch;
49
 
                        n++;
50
 
                        break;
51
 
 
52
 
                case '?':
53
 
                        if ((*n == '.' && n[1] != '.') || ! *n) goto next;
54
 
                        n++;
55
 
                        break;
56
 
 
57
 
                case '>':
58
 
                        if (n[0] == '.') {
59
 
                                if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
60
 
                                if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
61
 
                                goto nomatch;
62
 
                        }
63
 
                        if (! *n) goto next;
64
 
                        n++;
65
 
                        break;
66
 
 
67
 
                case '*':
68
 
                        if (! *p) goto match;
69
 
                        for (; *n; n++) {
70
 
                                if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
71
 
                        }
72
 
                        break;
73
 
 
74
 
                case '<':
75
 
                        for (; *n; n++) {
76
 
                                if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
77
 
                                if (*n == '.' && !strchr_m(n+1,'.')) {
78
 
                                        n++;
79
 
                                        break;
80
 
                                }
81
 
                        }
82
 
                        break;
83
 
 
84
 
                case '"':
85
 
                        if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
86
 
                        if (*n != '.') goto nomatch;
87
 
                        n++;
88
 
                        break;
89
 
 
90
 
                default:
91
 
                        if (c != *n) goto nomatch;
92
 
                        n++;
93
 
                }
94
 
        }
95
 
        
96
 
        if (! *n) goto match;
97
 
        
98
 
 nomatch:
99
 
        if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
100
 
        return -1;
101
 
 
102
 
next:
103
 
        if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
104
 
        goto nomatch;
105
 
 
106
 
 match:
107
 
        if (verbose) printf("MATCH   pattern=[%s] string=[%s]\n", pattern, string);
108
 
        return 0;
109
 
}
110
 
 
111
 
int ms_fnmatch_lanman(const char *pattern, const char *string)
112
 
{
113
 
        if (!strpbrk(pattern, "?*<>\"")) {
114
 
                if (strcmp(string,"..") == 0) 
115
 
                        string = ".";
116
 
 
117
 
                return strcmp(pattern, string);
118
 
        }
119
 
 
120
 
        if (strcmp(string,"..") == 0 || strcmp(string,".") == 0) {
121
 
                return ms_fnmatch_lanman_core(pattern, "..") &&
122
 
                        ms_fnmatch_lanman_core(pattern, ".");
123
 
        }
124
 
 
125
 
        return ms_fnmatch_lanman_core(pattern, string);
126
 
}
127
 
 
128
 
static BOOL reg_match_one(struct cli_state *cli, const char *pattern, const char *file)
129
 
{
130
 
        /* oh what a weird world this is */
131
 
        if (old_list && strcmp(pattern, "*.*") == 0) return True;
132
 
 
133
 
        if (strcmp(pattern,".") == 0) return False;
134
 
 
135
 
        if (max_protocol <= PROTOCOL_LANMAN2) {
136
 
                return ms_fnmatch_lanman(pattern, file)==0;
137
 
        }
138
 
 
139
 
        if (strcmp(file,"..") == 0) file = ".";
140
 
 
141
 
        return ms_fnmatch(pattern, file, cli->protocol, False) == 0;
142
 
}
143
 
 
144
 
static char *reg_test(struct cli_state *cli, char *pattern, char *long_name, char *short_name)
145
 
{
146
 
        static fstring ret;
147
 
        fstrcpy(ret, "---");
148
 
 
149
 
        pattern = 1+strrchr_m(pattern,'\\');
150
 
 
151
 
        if (reg_match_one(cli, pattern, ".")) ret[0] = '+';
152
 
        if (reg_match_one(cli, pattern, "..")) ret[1] = '+';
153
 
        if (reg_match_one(cli, pattern, long_name) || 
154
 
            (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+';
155
 
        return ret;
156
 
}
157
 
 
158
 
 
159
 
/***************************************************** 
160
 
return a connection to a server
161
 
*******************************************************/
162
 
struct cli_state *connect_one(char *share)
163
 
{
164
 
        struct cli_state *c;
165
 
        struct nmb_name called, calling;
166
 
        char *server_n;
167
 
        char *server;
168
 
        struct in_addr ip;
169
 
 
170
 
        server = share+2;
171
 
        share = strchr_m(server,'\\');
172
 
        if (!share) return NULL;
173
 
        *share = 0;
174
 
        share++;
175
 
 
176
 
        server_n = server;
177
 
        
178
 
        zero_ip(&ip);
179
 
 
180
 
        make_nmb_name(&calling, "masktest", 0x0);
181
 
        make_nmb_name(&called , server, 0x20);
182
 
 
183
 
 again:
184
 
        zero_ip(&ip);
185
 
 
186
 
        /* have to open a new connection */
187
 
        if (!(c=cli_initialise()) || !cli_connect(c, server_n, &ip)) {
188
 
                DEBUG(0,("Connection to %s failed\n", server_n));
189
 
                return NULL;
190
 
        }
191
 
 
192
 
        c->protocol = max_protocol;
193
 
 
194
 
        if (!cli_session_request(c, &calling, &called)) {
195
 
                DEBUG(0,("session request to %s failed\n", called.name));
196
 
                cli_shutdown(c);
197
 
                if (strcmp(called.name, "*SMBSERVER")) {
198
 
                        make_nmb_name(&called , "*SMBSERVER", 0x20);
199
 
                        goto again;
200
 
                }
201
 
                return NULL;
202
 
        }
203
 
 
204
 
        DEBUG(4,(" session request ok\n"));
205
 
 
206
 
        if (!cli_negprot(c)) {
207
 
                DEBUG(0,("protocol negotiation failed\n"));
208
 
                cli_shutdown(c);
209
 
                return NULL;
210
 
        }
211
 
 
212
 
        if (!got_pass) {
213
 
                char *pass = getpass("Password: ");
214
 
                if (pass) {
215
 
                        fstrcpy(password, pass);
216
 
                }
217
 
        }
218
 
 
219
 
        if (!cli_session_setup(c, username, 
220
 
                               password, strlen(password),
221
 
                               password, strlen(password),
222
 
                               lp_workgroup())) {
223
 
                DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
224
 
                return NULL;
225
 
        }
226
 
 
227
 
        /*
228
 
         * These next two lines are needed to emulate
229
 
         * old client behaviour for people who have
230
 
         * scripts based on client output.
231
 
         * QUESTION ? Do we want to have a 'client compatibility
232
 
         * mode to turn these on/off ? JRA.
233
 
         */
234
 
 
235
 
        if (*c->server_domain || *c->server_os || *c->server_type)
236
 
                DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
237
 
                        c->server_domain,c->server_os,c->server_type));
238
 
        
239
 
        DEBUG(4,(" session setup ok\n"));
240
 
 
241
 
        if (!cli_send_tconX(c, share, "?????",
242
 
                            password, strlen(password)+1)) {
243
 
                DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
244
 
                cli_shutdown(c);
245
 
                return NULL;
246
 
        }
247
 
 
248
 
        DEBUG(4,(" tconx ok\n"));
249
 
 
250
 
        return c;
251
 
}
252
 
 
253
 
static char *resultp;
254
 
static file_info *f_info;
255
 
 
256
 
static void listfn(const char *mnt, file_info *f, const char *s, void *state)
257
 
{
258
 
        if (strcmp(f->name,".") == 0) {
259
 
                resultp[0] = '+';
260
 
        } else if (strcmp(f->name,"..") == 0) {
261
 
                resultp[1] = '+';               
262
 
        } else {
263
 
                resultp[2] = '+';
264
 
        }
265
 
        f_info = f;
266
 
}
267
 
 
268
 
static void get_real_name(struct cli_state *cli, 
269
 
                          pstring long_name, fstring short_name)
270
 
{
271
 
        /* nasty hack to force level 260 listings - tridge */
272
 
        cli->capabilities |= CAP_NT_SMBS;
273
 
        if (max_protocol <= PROTOCOL_LANMAN1) {
274
 
                cli_list_new(cli, "\\masktest\\*.*", aHIDDEN | aDIR, listfn, NULL);
275
 
        } else {
276
 
                cli_list_new(cli, "\\masktest\\*", aHIDDEN | aDIR, listfn, NULL);
277
 
        }
278
 
        if (f_info) {
279
 
                fstrcpy(short_name, f_info->short_name);
280
 
                strlower_m(short_name);
281
 
                pstrcpy(long_name, f_info->name);
282
 
                strlower_m(long_name);
283
 
        }
284
 
 
285
 
        if (*short_name == 0) {
286
 
                fstrcpy(short_name, long_name);
287
 
        }
288
 
 
289
 
#if 0
290
 
        if (!strchr_m(short_name,'.')) {
291
 
                fstrcat(short_name,".");
292
 
        }
293
 
#endif
294
 
}
295
 
 
296
 
static void testpair(struct cli_state *cli, char *mask, char *file)
297
 
{
298
 
        int fnum;
299
 
        fstring res1;
300
 
        char *res2;
301
 
        static int count;
302
 
        fstring short_name;
303
 
        pstring long_name;
304
 
 
305
 
        count++;
306
 
 
307
 
        fstrcpy(res1, "---");
308
 
 
309
 
        fnum = cli_open(cli, file, O_CREAT|O_TRUNC|O_RDWR, 0);
310
 
        if (fnum == -1) {
311
 
                DEBUG(0,("Can't create %s\n", file));
312
 
                return;
313
 
        }
314
 
        cli_close(cli, fnum);
315
 
 
316
 
        resultp = res1;
317
 
        fstrcpy(short_name, "");
318
 
        f_info = NULL;
319
 
        get_real_name(cli, long_name, short_name);
320
 
        f_info = NULL;
321
 
        fstrcpy(res1, "---");
322
 
        cli_list(cli, mask, aHIDDEN | aDIR, listfn, NULL);
323
 
 
324
 
        res2 = reg_test(cli, mask, long_name, short_name);
325
 
 
326
 
        if (showall || 
327
 
            ((strcmp(res1, res2) && !ignore_dot_errors) ||
328
 
             (strcmp(res1+2, res2+2) && ignore_dot_errors))) {
329
 
                DEBUG(0,("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
330
 
                         res1, res2, count, mask, file, long_name, short_name));
331
 
                if (die_on_error) exit(1);
332
 
        }
333
 
 
334
 
        cli_unlink(cli, file);
335
 
 
336
 
        if (count % 100 == 0) DEBUG(0,("%d\n", count));
337
 
}
338
 
 
339
 
static void test_mask(int argc, char *argv[], 
340
 
                      struct cli_state *cli)
341
 
{
342
 
        pstring mask, file;
343
 
        int l1, l2, i, l;
344
 
        int mc_len = strlen(maskchars);
345
 
        int fc_len = strlen(filechars);
346
 
 
347
 
        cli_mkdir(cli, "\\masktest");
348
 
 
349
 
        cli_unlink(cli, "\\masktest\\*");
350
 
 
351
 
        if (argc >= 2) {
352
 
                while (argc >= 2) {
353
 
                        pstrcpy(mask,"\\masktest\\");
354
 
                        pstrcpy(file,"\\masktest\\");
355
 
                        pstrcat(mask, argv[0]);
356
 
                        pstrcat(file, argv[1]);
357
 
                        testpair(cli, mask, file);
358
 
                        argv += 2;
359
 
                        argc -= 2;
360
 
                }
361
 
                goto finished;
362
 
        }
363
 
 
364
 
        while (1) {
365
 
                l1 = 1 + random() % 20;
366
 
                l2 = 1 + random() % 20;
367
 
                pstrcpy(mask,"\\masktest\\");
368
 
                pstrcpy(file,"\\masktest\\");
369
 
                l = strlen(mask);
370
 
                for (i=0;i<l1;i++) {
371
 
                        mask[i+l] = maskchars[random() % mc_len];
372
 
                }
373
 
                mask[l+l1] = 0;
374
 
 
375
 
                for (i=0;i<l2;i++) {
376
 
                        file[i+l] = filechars[random() % fc_len];
377
 
                }
378
 
                file[l+l2] = 0;
379
 
 
380
 
                if (strcmp(file+l,".") == 0 || 
381
 
                    strcmp(file+l,"..") == 0 ||
382
 
                    strcmp(mask+l,"..") == 0) continue;
383
 
 
384
 
                if (strspn(file+l, ".") == strlen(file+l)) continue;
385
 
 
386
 
                testpair(cli, mask, file);
387
 
                if (NumLoops && (--NumLoops == 0))
388
 
                        break;
389
 
        }
390
 
 
391
 
 finished:
392
 
        cli_rmdir(cli, "\\masktest");
393
 
}
394
 
 
395
 
 
396
 
static void usage(void)
397
 
{
398
 
        printf(
399
 
"Usage:\n\
400
 
  masktest //server/share [options..]\n\
401
 
  options:\n\
402
 
        -d debuglevel\n\
403
 
        -n numloops\n\
404
 
        -W workgroup\n\
405
 
        -U user%%pass\n\
406
 
        -s seed\n\
407
 
        -M max protocol\n\
408
 
        -f filechars (default %s)\n\
409
 
        -m maskchars (default %s)\n\
410
 
        -v                             verbose mode\n\
411
 
        -E                             die on error\n\
412
 
        -a                             show all tests\n\
413
 
        -i                             ignore . and .. errors\n\
414
 
\n\
415
 
  This program tests wildcard matching between two servers. It generates\n\
416
 
  random pairs of filenames/masks and tests that they match in the same\n\
417
 
  way on the servers and internally\n\
418
 
", 
419
 
  filechars, maskchars);
420
 
}
421
 
 
422
 
/****************************************************************************
423
 
  main program
424
 
****************************************************************************/
425
 
 int main(int argc,char *argv[])
426
 
{
427
 
        char *share;
428
 
        struct cli_state *cli;  
429
 
        extern char *optarg;
430
 
        extern int optind;
431
 
        extern BOOL AllowDebugChange;
432
 
        int opt;
433
 
        char *p;
434
 
        int seed;
435
 
 
436
 
        setlinebuf(stdout);
437
 
 
438
 
        dbf = x_stderr;
439
 
 
440
 
        DEBUGLEVEL = 0;
441
 
        AllowDebugChange = False;
442
 
 
443
 
        if (argc < 2 || argv[1][0] == '-') {
444
 
                usage();
445
 
                exit(1);
446
 
        }
447
 
 
448
 
        share = argv[1];
449
 
 
450
 
        all_string_sub(share,"/","\\",0);
451
 
 
452
 
        setup_logging(argv[0],True);
453
 
 
454
 
        argc -= 1;
455
 
        argv += 1;
456
 
 
457
 
        lp_load(dyn_CONFIGFILE,True,False,False,True);
458
 
        load_interfaces();
459
 
 
460
 
        if (getenv("USER")) {
461
 
                fstrcpy(username,getenv("USER"));
462
 
        }
463
 
 
464
 
        seed = time(NULL);
465
 
 
466
 
        while ((opt = getopt(argc, argv, "n:d:U:s:hm:f:aoW:M:vEi")) != EOF) {
467
 
                switch (opt) {
468
 
                case 'n':
469
 
                        NumLoops = atoi(optarg);
470
 
                        break;
471
 
                case 'd':
472
 
                        DEBUGLEVEL = atoi(optarg);
473
 
                        break;
474
 
                case 'E':
475
 
                        die_on_error = 1;
476
 
                        break;
477
 
                case 'i':
478
 
                        ignore_dot_errors = 1;
479
 
                        break;
480
 
                case 'v':
481
 
                        verbose++;
482
 
                        break;
483
 
                case 'M':
484
 
                        max_protocol = interpret_protocol(optarg, max_protocol);
485
 
                        break;
486
 
                case 'U':
487
 
                        fstrcpy(username,optarg);
488
 
                        p = strchr_m(username,'%');
489
 
                        if (p) {
490
 
                                *p = 0;
491
 
                                fstrcpy(password, p+1);
492
 
                                got_pass = 1;
493
 
                        }
494
 
                        break;
495
 
                case 's':
496
 
                        seed = atoi(optarg);
497
 
                        break;
498
 
                case 'h':
499
 
                        usage();
500
 
                        exit(1);
501
 
                case 'm':
502
 
                        maskchars = optarg;
503
 
                        break;
504
 
                case 'f':
505
 
                        filechars = optarg;
506
 
                        break;
507
 
                case 'a':
508
 
                        showall = 1;
509
 
                        break;
510
 
                case 'o':
511
 
                        old_list = True;
512
 
                        break;
513
 
                default:
514
 
                        printf("Unknown option %c (%d)\n", (char)opt, opt);
515
 
                        exit(1);
516
 
                }
517
 
        }
518
 
 
519
 
        argc -= optind;
520
 
        argv += optind;
521
 
 
522
 
 
523
 
        cli = connect_one(share);
524
 
        if (!cli) {
525
 
                DEBUG(0,("Failed to connect to %s\n", share));
526
 
                exit(1);
527
 
        }
528
 
 
529
 
        /* need to init seed after connect as clientgen uses random numbers */
530
 
        DEBUG(0,("seed=%d\n", seed));
531
 
        srandom(seed);
532
 
 
533
 
        test_mask(argc, argv, cli);
534
 
 
535
 
        return(0);
536
 
}