~ubuntu-branches/ubuntu/natty/curl/natty-security

« back to all changes in this revision

Viewing changes to lib/curl_fnmatch.c

  • Committer: Bazaar Package Importer
  • Author(s): Bhavani Shankar
  • Date: 2010-06-20 13:56:28 UTC
  • mfrom: (3.4.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100620135628-e30tp9jldq6hq985
Tags: 7.21.0-1ubuntu1
* Merge from debian unstable.  Remaining changes: LP: #596334
  - Keep build deps in main:
    - Drop build dependencies: stunnel, libssh2-1-dev
    - Add build-dependency on openssh-server
    - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                  _   _ ____  _
 
3
 *  Project                     ___| | | |  _ \| |
 
4
 *                             / __| | | | |_) | |
 
5
 *                            | (__| |_| |  _ <| |___
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
 
9
 *
 
10
 * This software is licensed as described in the file COPYING, which
 
11
 * you should have received as part of this distribution. The terms
 
12
 * are also available at http://curl.haxx.se/docs/copyright.html.
 
13
 *
 
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 
15
 * copies of the Software, and permit persons to whom the Software is
 
16
 * furnished to do so, under the terms of the COPYING file.
 
17
 *
 
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 
19
 * KIND, either express or implied.
 
20
 *
 
21
 ***************************************************************************/
 
22
 
 
23
#include "setup.h"
 
24
 
 
25
#include "curl_fnmatch.h"
 
26
 
 
27
#define _MPRINTF_REPLACE /* use our functions only */
 
28
#include <curl/mprintf.h>
 
29
 
 
30
#include "curl_memory.h"
 
31
/* The last #include file should be: */
 
32
#include "memdebug.h"
 
33
 
 
34
#define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
 
35
#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
 
36
 
 
37
#define CURLFNM_NEGATE  CURLFNM_CHARSET_LEN
 
38
 
 
39
#define CURLFNM_ALNUM   (CURLFNM_CHARSET_LEN + 1)
 
40
#define CURLFNM_DIGIT   (CURLFNM_CHARSET_LEN + 2)
 
41
#define CURLFNM_XDIGIT  (CURLFNM_CHARSET_LEN + 3)
 
42
#define CURLFNM_ALPHA   (CURLFNM_CHARSET_LEN + 4)
 
43
#define CURLFNM_PRINT   (CURLFNM_CHARSET_LEN + 5)
 
44
#define CURLFNM_BLANK   (CURLFNM_CHARSET_LEN + 6)
 
45
#define CURLFNM_LOWER   (CURLFNM_CHARSET_LEN + 7)
 
46
#define CURLFNM_GRAPH   (CURLFNM_CHARSET_LEN + 8)
 
47
#define CURLFNM_SPACE   (CURLFNM_CHARSET_LEN + 9)
 
48
#define CURLFNM_UPPER   (CURLFNM_CHARSET_LEN + 10)
 
49
 
 
50
typedef enum {
 
51
  CURLFNM_LOOP_DEFAULT = 0,
 
52
  CURLFNM_LOOP_BACKSLASH
 
53
} loop_state;
 
54
 
 
55
typedef enum {
 
56
  CURLFNM_SCHS_DEFAULT = 0,
 
57
  CURLFNM_SCHS_MAYRANGE,
 
58
  CURLFNM_SCHS_MAYRANGE2,
 
59
  CURLFNM_SCHS_RIGHTBR,
 
60
  CURLFNM_SCHS_RIGHTBRLEFTBR
 
61
} setcharset_state;
 
62
 
 
63
typedef enum {
 
64
  CURLFNM_PKW_INIT = 0,
 
65
  CURLFNM_PKW_DDOT
 
66
} parsekey_state;
 
67
 
 
68
#define SETCHARSET_OK     1
 
69
#define SETCHARSET_FAIL   0
 
70
 
 
71
static int parsekeyword(unsigned char **pattern, unsigned char *charset)
 
72
{
 
73
  parsekey_state state = CURLFNM_PKW_INIT;
 
74
#define KEYLEN 10
 
75
  char keyword[KEYLEN] = { 0 };
 
76
  int found = FALSE;
 
77
  int i;
 
78
  unsigned char *p = *pattern;
 
79
  for(i = 0; !found; i++) {
 
80
    char c = *p++;
 
81
    if(i >= KEYLEN)
 
82
      return SETCHARSET_FAIL;
 
83
    switch(state) {
 
84
    case CURLFNM_PKW_INIT:
 
85
      if(ISALPHA(c) && ISLOWER(c))
 
86
        keyword[i] = c;
 
87
      else if(c == ':')
 
88
        state = CURLFNM_PKW_DDOT;
 
89
      else
 
90
        return 0;
 
91
      break;
 
92
    case CURLFNM_PKW_DDOT:
 
93
      if(c == ']')
 
94
        found = TRUE;
 
95
      else
 
96
        return SETCHARSET_FAIL;
 
97
    }
 
98
  }
 
99
#undef KEYLEN
 
100
 
 
101
  *pattern = p; /* move caller's pattern pointer */
 
102
  if(strcmp(keyword, "digit") == 0)
 
103
    charset[CURLFNM_DIGIT] = 1;
 
104
  else if(strcmp(keyword, "alnum") == 0)
 
105
    charset[CURLFNM_ALNUM] = 1;
 
106
  else if(strcmp(keyword, "alpha") == 0)
 
107
    charset[CURLFNM_ALPHA] = 1;
 
108
  else if(strcmp(keyword, "xdigit") == 0)
 
109
    charset[CURLFNM_XDIGIT] = 1;
 
110
  else if(strcmp(keyword, "print") == 0)
 
111
    charset[CURLFNM_PRINT] = 1;
 
112
  else if(strcmp(keyword, "graph") == 0)
 
113
    charset[CURLFNM_GRAPH] = 1;
 
114
  else if(strcmp(keyword, "space") == 0)
 
115
    charset[CURLFNM_SPACE] = 1;
 
116
  else if(strcmp(keyword, "blank") == 0)
 
117
    charset[CURLFNM_BLANK] = 1;
 
118
  else if(strcmp(keyword, "upper") == 0)
 
119
    charset[CURLFNM_UPPER] = 1;
 
120
  else if(strcmp(keyword, "lower") == 0)
 
121
    charset[CURLFNM_LOWER] = 1;
 
122
  else
 
123
    return SETCHARSET_FAIL;
 
124
  return SETCHARSET_OK;
 
125
}
 
126
 
 
127
/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
 
128
static int setcharset(unsigned char **p, unsigned char *charset)
 
129
{
 
130
  setcharset_state state = CURLFNM_SCHS_DEFAULT;
 
131
  unsigned char rangestart = 0;
 
132
  unsigned char lastchar   = 0;
 
133
  bool something_found = FALSE;
 
134
  unsigned char c;
 
135
  for(;;) {
 
136
    c = **p;
 
137
    switch(state) {
 
138
    case CURLFNM_SCHS_DEFAULT:
 
139
      if(ISALNUM(c)) { /* ASCII value */
 
140
        rangestart = c;
 
141
        charset[c] = 1;
 
142
        (*p)++;
 
143
        state = CURLFNM_SCHS_MAYRANGE;
 
144
        something_found = TRUE;
 
145
      }
 
146
      else if(c == ']') {
 
147
        if(something_found)
 
148
          return SETCHARSET_OK;
 
149
        else
 
150
          something_found = TRUE;
 
151
        state = CURLFNM_SCHS_RIGHTBR;
 
152
        charset[c] = 1;
 
153
        (*p)++;
 
154
      }
 
155
      else if(c == '[') {
 
156
        char c2 = *((*p)+1);
 
157
        if(c2 == ':') { /* there has to be a keyword */
 
158
          (*p) += 2;
 
159
          if(parsekeyword(p, charset)) {
 
160
            state = CURLFNM_SCHS_DEFAULT;
 
161
          }
 
162
          else
 
163
            return SETCHARSET_FAIL;
 
164
        }
 
165
        else {
 
166
          charset[c] = 1;
 
167
          (*p)++;
 
168
        }
 
169
        something_found = TRUE;
 
170
      }
 
171
      else if(c == '?' || c == '*') {
 
172
        something_found = TRUE;
 
173
        charset[c] = 1;
 
174
        (*p)++;
 
175
      }
 
176
      else if(c == '^' || c == '!') {
 
177
        if(!something_found) {
 
178
          if(charset[CURLFNM_NEGATE]) {
 
179
            charset[c] = 1;
 
180
            something_found = TRUE;
 
181
          }
 
182
          else
 
183
            charset[CURLFNM_NEGATE] = 1; /* negate charset */
 
184
        }
 
185
        else
 
186
          charset[c] = 1;
 
187
        (*p)++;
 
188
      }
 
189
      else if(c == '\\') {
 
190
        c = *(++(*p));
 
191
        if(ISPRINT((c))) {
 
192
          something_found = TRUE;
 
193
          state = CURLFNM_SCHS_MAYRANGE;
 
194
          charset[c] = 1;
 
195
          rangestart = c;
 
196
          (*p)++;
 
197
        }
 
198
        else
 
199
          return SETCHARSET_FAIL;
 
200
      }
 
201
      else if(c == '\0') {
 
202
        return SETCHARSET_FAIL;
 
203
      }
 
204
      else {
 
205
        charset[c] = 1;
 
206
        (*p)++;
 
207
        something_found = TRUE;
 
208
      }
 
209
      break;
 
210
    case CURLFNM_SCHS_MAYRANGE:
 
211
      if(c == '-') {
 
212
        charset[c] = 1;
 
213
        (*p)++;
 
214
        lastchar = '-';
 
215
        state = CURLFNM_SCHS_MAYRANGE2;
 
216
      }
 
217
      else if(c == '[') {
 
218
        state = CURLFNM_SCHS_DEFAULT;
 
219
      }
 
220
      else if(ISALNUM(c)) {
 
221
        charset[c] = 1;
 
222
        (*p)++;
 
223
      }
 
224
      else if(c == '\\') {
 
225
        c = *(++(*p));
 
226
        if(ISPRINT(c)) {
 
227
          charset[c] = 1;
 
228
          (*p)++;
 
229
        }
 
230
        else
 
231
          return SETCHARSET_FAIL;
 
232
      }
 
233
      else if(c == ']') {
 
234
        return SETCHARSET_OK;
 
235
      }
 
236
      else
 
237
        return SETCHARSET_FAIL;
 
238
      break;
 
239
    case CURLFNM_SCHS_MAYRANGE2:
 
240
      if(c == '\\') {
 
241
        c = *(++(*p));
 
242
        if(!ISPRINT(c))
 
243
          return SETCHARSET_FAIL;
 
244
      }
 
245
      if(c == ']') {
 
246
        return SETCHARSET_OK;
 
247
      }
 
248
      else if(c == '\\') {
 
249
        c = *(++(*p));
 
250
        if(ISPRINT(c)) {
 
251
          charset[c] = 1;
 
252
          state = CURLFNM_SCHS_DEFAULT;
 
253
          (*p)++;
 
254
        }
 
255
        else
 
256
          return SETCHARSET_FAIL;
 
257
      }
 
258
      if(c >= rangestart) {
 
259
        if((ISLOWER(c) && ISLOWER(rangestart)) ||
 
260
           (ISDIGIT(c) && ISDIGIT(rangestart)) ||
 
261
           (ISUPPER(c) && ISUPPER(rangestart))) {
 
262
          charset[lastchar] = 0;
 
263
          rangestart++;
 
264
          while(rangestart++ <= c)
 
265
            charset[rangestart-1] = 1;
 
266
          (*p)++;
 
267
          state = CURLFNM_SCHS_DEFAULT;
 
268
        }
 
269
        else
 
270
          return SETCHARSET_FAIL;
 
271
      }
 
272
      break;
 
273
    case CURLFNM_SCHS_RIGHTBR:
 
274
      if(c == '[') {
 
275
        state = CURLFNM_SCHS_RIGHTBRLEFTBR;
 
276
        charset[c] = 1;
 
277
        (*p)++;
 
278
      }
 
279
      else if(c == ']') {
 
280
        return SETCHARSET_OK;
 
281
      }
 
282
      else if(c == '\0') {
 
283
        return SETCHARSET_FAIL;
 
284
      }
 
285
      else if(ISPRINT(c)) {
 
286
        charset[c] = 1;
 
287
        (*p)++;
 
288
        state = CURLFNM_SCHS_DEFAULT;
 
289
      }
 
290
      else
 
291
        /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
 
292
         * nonsense warning 'statement not reached' at end of the fnc when
 
293
         * compiling on Solaris */
 
294
        goto fail;
 
295
      break;
 
296
    case CURLFNM_SCHS_RIGHTBRLEFTBR:
 
297
      if(c == ']') {
 
298
        return SETCHARSET_OK;
 
299
      }
 
300
      else {
 
301
        state  = CURLFNM_SCHS_DEFAULT;
 
302
        charset[c] = 1;
 
303
        (*p)++;
 
304
      }
 
305
      break;
 
306
    }
 
307
  }
 
308
fail:
 
309
  return SETCHARSET_FAIL;
 
310
}
 
311
 
 
312
static int loop(const unsigned char *pattern, const unsigned char *string)
 
313
{
 
314
  loop_state state = CURLFNM_LOOP_DEFAULT;
 
315
  unsigned char *p = (unsigned char *)pattern;
 
316
  unsigned char *s = (unsigned char *)string;
 
317
  unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
 
318
  int rc = 0;
 
319
 
 
320
  for (;;) {
 
321
    switch(state) {
 
322
    case CURLFNM_LOOP_DEFAULT:
 
323
      if(*p == '*') {
 
324
        while(*(p+1) == '*') /* eliminate multiple stars */
 
325
          p++;
 
326
        if(*s == '\0' && *(p+1) == '\0')
 
327
          return CURL_FNMATCH_MATCH;
 
328
        rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
 
329
        if(rc == CURL_FNMATCH_MATCH)
 
330
          return CURL_FNMATCH_MATCH;
 
331
        if(*s) /* let the star eat up one character */
 
332
          s++;
 
333
        else
 
334
          return CURL_FNMATCH_NOMATCH;
 
335
      }
 
336
      else if(*p == '?') {
 
337
        if(ISPRINT(*s)) {
 
338
          s++;
 
339
          p++;
 
340
        }
 
341
        else if(*s == '\0')
 
342
          return CURL_FNMATCH_NOMATCH;
 
343
        else
 
344
          return CURL_FNMATCH_FAIL; /* cannot deal with other character */
 
345
      }
 
346
      else if(*p == '\0') {
 
347
        if(*s == '\0')
 
348
          return CURL_FNMATCH_MATCH;
 
349
        else
 
350
          return CURL_FNMATCH_NOMATCH;
 
351
      }
 
352
      else if(*p == '\\') {
 
353
        state = CURLFNM_LOOP_BACKSLASH;
 
354
        p++;
 
355
      }
 
356
      else if(*p == '[') {
 
357
        unsigned char *pp = p+1; /* cannot handle with pointer to register */
 
358
        if(setcharset(&pp, charset)) {
 
359
          int found = FALSE;
 
360
          if(charset[(unsigned int)*s])
 
361
            found = TRUE;
 
362
          else if(charset[CURLFNM_ALNUM])
 
363
            found = ISALNUM(*s);
 
364
          else if(charset[CURLFNM_ALPHA])
 
365
            found = ISALPHA(*s);
 
366
          else if(charset[CURLFNM_DIGIT])
 
367
            found = ISDIGIT(*s);
 
368
          else if(charset[CURLFNM_XDIGIT])
 
369
            found = ISXDIGIT(*s);
 
370
          else if(charset[CURLFNM_PRINT])
 
371
            found = ISPRINT(*s);
 
372
          else if(charset[CURLFNM_SPACE])
 
373
            found = ISSPACE(*s);
 
374
          else if(charset[CURLFNM_UPPER])
 
375
            found = ISUPPER(*s);
 
376
          else if(charset[CURLFNM_LOWER])
 
377
            found = ISLOWER(*s);
 
378
          else if(charset[CURLFNM_BLANK])
 
379
            found = ISBLANK(*s);
 
380
          else if(charset[CURLFNM_GRAPH])
 
381
            found = ISGRAPH(*s);
 
382
 
 
383
          if(charset[CURLFNM_NEGATE])
 
384
            found = !found;
 
385
 
 
386
          if(found) {
 
387
            p = pp+1;
 
388
            s++;
 
389
            memset(charset, 0, CURLFNM_CHSET_SIZE);
 
390
          }
 
391
          else
 
392
            return CURL_FNMATCH_NOMATCH;
 
393
        }
 
394
        else
 
395
          return CURL_FNMATCH_FAIL;
 
396
      }
 
397
      else {
 
398
        if(*p++ != *s++)
 
399
          return CURL_FNMATCH_NOMATCH;
 
400
      }
 
401
      break;
 
402
    case CURLFNM_LOOP_BACKSLASH:
 
403
      if(ISPRINT(*p)) {
 
404
        if(*p++ == *s++)
 
405
          state = CURLFNM_LOOP_DEFAULT;
 
406
        else
 
407
          return CURL_FNMATCH_NOMATCH;
 
408
      }
 
409
      else
 
410
        return CURL_FNMATCH_FAIL;
 
411
      break;
 
412
    }
 
413
  }
 
414
}
 
415
 
 
416
int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
 
417
{
 
418
  (void)ptr; /* the argument is specified by the curl_fnmatch_callback
 
419
                prototype, but not used by Curl_fnmatch() */
 
420
  if(!pattern || !string) {
 
421
    return CURL_FNMATCH_FAIL;
 
422
  }
 
423
  return loop((unsigned char *)pattern, (unsigned char *)string);
 
424
}