~ubuntu-branches/ubuntu/raring/clamav/raring

« back to all changes in this revision

Viewing changes to libclamav/dlp.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Gran
  • Date: 2008-09-05 17:25:34 UTC
  • mfrom: (0.35.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080905172534-yi3f8fkye1o7u1r3
* New upstream version (closes: #497662, #497773)
  - lots of new options for clamd.conf
  - fixes CVEs CVE-2008-3912, CVE-2008-3913, CVE-2008-3914, and
    CVE-2008-1389
* No longer supports --unzip option, so typo is gone (closes: #496276)
* Translations:
  - sv (thanks Martin Bagge <brother@bsnet.se>) (closes: #491760)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 *  Simple library to detect and validate SSN and Credit Card numbers.
 
3
 *
 
4
 *  Copyright (C) 2007-2008 Sourcefire, Inc.
 
5
 *
 
6
 *  Authors: Martin Roesch <roesch@sourcefire.com>
 
7
 *
 
8
 *  This program is free software; you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License version 2 as
 
10
 *  published by the Free Software Foundation.
 
11
 *
 
12
 *  This program is distributed in the hope that it will be useful,
 
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *  GNU General Public License for more details.
 
16
 *
 
17
 *  You should have received a copy of the GNU General Public License
 
18
 *  along with this program; if not, write to the Free Software
 
19
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
20
 *  MA 02110-1301, USA.
 
21
 */
 
22
 
 
23
#if HAVE_CONFIG_H
 
24
#include "clamav-config.h"
 
25
#endif
 
26
 
 
27
#include <stdio.h>
 
28
#include <ctype.h>  
 
29
#include <string.h>
 
30
#include <stdarg.h>
 
31
#include <stdlib.h>
 
32
#include "dlp.h"
 
33
#include "others.h"
 
34
#include "str.h"
 
35
 
 
36
/* detection mode macros for the contains_* functions */
 
37
#define DETECT_MODE_DETECT  0
 
38
#define DETECT_MODE_COUNT   1
 
39
 
 
40
/* group number mapping is here */
 
41
/* http://www.socialsecurity.gov/employer/highgroup.txt */
 
42
/* here's a perl script to convert the raw data from the highgroup.txt
 
43
 * file to the data set in ssn_max_group[]:
 
44
--
 
45
local $/;
 
46
my $i = <>;
 
47
my $count = 0;
 
48
while ($i =~ s/(\d{3}) (\d{2})//) {
 
49
    print int($2) .", ";
 
50
    if ($count == 18) 
 
51
    {
 
52
        print "\n";
 
53
        $count = 0;
 
54
    }
 
55
    else
 
56
    {
 
57
        $count++;
 
58
    }
 
59
 }
 
60
 --
 
61
  *
 
62
  * run 'perl convert.pl < highgroup.txt' to generate the data
 
63
  *
 
64
  */
 
65
 
 
66
/* MAX_AREA is the maximum assigned area number.  This can be derived from 
 
67
 * the data in the highgroup.txt file by looking at the last area->group 
 
68
 * mapping from that file.
 
69
 */ 
 
70
#define MAX_AREA 772
 
71
 
 
72
/* array of max group numbers for a given area number */
 
73
static int ssn_max_group[MAX_AREA+1] = { 0,
 
74
    6, 6, 4, 8, 8, 8, 6, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 
 
75
    90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 88, 88, 88, 88, 72, 72, 72, 72, 
 
76
    70, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 96, 96, 96, 96, 96, 96, 96, 96, 
 
77
    96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 
 
78
    96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 
 
79
    96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 
 
80
    96, 96, 96, 96, 96, 96, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 
 
81
    94, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 17, 17, 17, 17, 17, 17, 
 
82
    17, 17, 17, 17, 17, 17, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 
 
83
    84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 82, 82, 82, 82, 82, 82, 82, 82, 
 
84
    82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 
 
85
    82, 82, 79, 79, 79, 79, 79, 79, 79, 79, 77, 6, 4, 99, 99, 99, 99, 99, 99, 
 
86
    99, 99, 99, 53, 53, 53, 53, 53, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 
 
87
    99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 
 
88
    99, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 
 
89
    13, 13, 13, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 33, 33, 
 
90
    31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 6, 6, 6, 6, 6, 6, 
 
91
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
 
92
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
 
93
    35, 35, 35, 35, 35, 35, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 
 
94
    33, 33, 33, 33, 33, 33, 29, 29, 29, 29, 29, 29, 29, 29, 27, 27, 27, 27, 27, 
 
95
    67, 67, 67, 67, 67, 67, 67, 67, 99, 99, 99, 99, 99, 99, 99, 99, 63, 61, 61, 
 
96
    61, 61, 61, 61, 61, 61, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 
 
97
    99, 99, 23, 23, 23, 23, 23, 23, 23, 21, 21, 99, 99, 99, 99, 99, 99, 99, 99, 
 
98
    99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 51, 51, 51, 51, 49, 49, 49, 49, 
 
99
    49, 49, 37, 37, 37, 37, 37, 37, 37, 37, 25, 25, 25, 25, 25, 25, 25, 25, 25, 
 
100
    25, 25, 25, 23, 23, 23, 33, 33, 41, 39, 53, 51, 51, 51, 27, 27, 27, 27, 27, 
 
101
    27, 27, 45, 43, 79, 77, 55, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 63, 63, 
 
102
    63, 61, 61, 61, 61, 61, 61, 75, 73, 73, 73, 73, 99, 99, 99, 99, 99, 99, 99, 
 
103
    99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 
 
104
    99, 99, 99, 51, 99, 99, 45, 45, 43, 37, 99, 99, 99, 99, 99, 61, 99, 3, 99, 
 
105
    99, 99, 99, 99, 99, 99, 84, 84, 84, 84, 99, 99, 67, 67, 65, 65, 65, 65, 65, 
 
106
    65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 11, 
 
107
    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 96, 
 
108
    96, 44, 44, 46, 46, 46, 44, 28, 26, 26, 26, 26, 16, 16, 16, 14, 14, 14, 14, 
 
109
    36, 34, 34, 34, 34, 34, 34, 34, 34, 14, 14, 12, 12, 90, 14, 14, 14, 14, 12, 
 
110
    12, 12, 12, 12, 12, 9, 9, 7, 7, 7, 7, 7, 7, 7, 18, 18, 18, 18, 18, 
 
111
    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
 
112
    28, 18, 18, 10, 14, 10, 10, 10, 10, 10, 9, 9, 3, 1, 5, 5, 5, 5, 5, 
 
113
    5, 3, 3, 82, 82, 66, 66, 64, 64, 64, 64, 64
 
114
};
 
115
 
 
116
 
 
117
 
 
118
int dlp_is_valid_cc(const unsigned char *buffer, int length)
 
119
{
 
120
    int even = 1;
 
121
    int sum = 0;
 
122
    int i = 0;
 
123
    int val = 0;
 
124
    int digits = 0;
 
125
    char cc_digits[20];
 
126
    
 
127
    if(buffer == NULL || length < 13)
 
128
        return 0;
 
129
    /* if the first digit is greater than 6 it isn't one of the major
 
130
     * credit cards
 
131
     * reference => http://www.beachnet.com/~hstiles/cardtype.html
 
132
     */
 
133
    if(!isdigit(buffer[0]) || buffer[0] > '6')
 
134
        return 0;
 
135
        
 
136
    if(length > 19)
 
137
        length = 19;
 
138
 
 
139
    for(i = 0; i < length; i++)
 
140
    {
 
141
        if(isdigit(buffer[i]) == 0)
 
142
        {
 
143
            if(isspace(buffer[i]))
 
144
                continue;
 
145
            else
 
146
                break;
 
147
        }
 
148
 
 
149
        cc_digits[digits] = buffer[i];
 
150
        digits++;
 
151
        val = buffer[i] - '0';
 
152
        
 
153
        if(even)
 
154
        {
 
155
            if((val *= 2) > 9) val = (val - 10) + 1;
 
156
        }
 
157
        
 
158
        even = !even;
 
159
        sum += val;
 
160
    }
 
161
    cc_digits[digits] = 0;
 
162
    if(i < length && isdigit(buffer[i]))
 
163
        return 0;
 
164
 
 
165
    if((sum % 10 != 0) || (digits < 13))
 
166
        return 0;
 
167
 
 
168
    if(digits == 13) /* VISA */
 
169
    {
 
170
        if(cc_digits[0] == '4') {
 
171
            cli_dbgmsg("dlp_is_valid_cc: VISA [1] (%s)\n", cc_digits);
 
172
            return 1;
 
173
        }
 
174
    }
 
175
    else if(digits == 14) /* Diners Club */
 
176
    {
 
177
        if(cc_digits[0] == '3' && (cc_digits[1] == '6' || cc_digits[1] == '8'))
 
178
        {
 
179
            cli_dbgmsg("dlp_is_valid_cc: Diners Club [1] (%s)\n", cc_digits);
 
180
            return 1;
 
181
        }
 
182
        else if(cc_digits[0] == '3' && cc_digits[1] == '0')
 
183
        {
 
184
            val = cc_digits[2] - '0';
 
185
            if(val >= 0 && val <= 5) {
 
186
                cli_dbgmsg("dlp_is_valid_cc: Diners Club [2] (%s)\n", cc_digits);
 
187
                return 1;
 
188
            }
 
189
        }
 
190
    }
 
191
    else if(digits == 15)
 
192
    {
 
193
        if(cc_digits[0] == '3' && (cc_digits[1] == '4' || cc_digits[1] == '7')) /*AMEX*/
 
194
        {
 
195
            cli_dbgmsg("dlp_is_valid_cc: AMEX (%s)\n", cc_digits);
 
196
            return 1;
 
197
        }
 
198
        else if(!strncmp(cc_digits, "2131", 4) || !strncmp(cc_digits, "1800", 4))
 
199
        { /* JCB  */
 
200
            cli_dbgmsg("dlp_is_valid_cc: JCB [1] (%s)\n", cc_digits);
 
201
            return 1;
 
202
        }
 
203
    }
 
204
    else if(digits == 16)
 
205
    {
 
206
        if(cc_digits[0] == '3') /* JCB */
 
207
        {
 
208
            cli_dbgmsg("dlp_is_valid_cc: JCB [2] (%s)\n", cc_digits);
 
209
            return 1;
 
210
        }
 
211
        else if(cc_digits[0] == '4') /* VISA */
 
212
        {
 
213
            cli_dbgmsg("dlp_is_valid_cc: VISA [2] (%s)\n", cc_digits);
 
214
            return 1;
 
215
        }
 
216
        else if(cc_digits[0] == '5') /* MASTERCARD */
 
217
        {
 
218
            val = cc_digits[1] - '0';
 
219
            if(val >= 1 && val <= 5) {
 
220
                cli_dbgmsg("dlp_is_valid_cc: MASTERCARD (%s)\n", cc_digits);
 
221
                return 1;
 
222
            }
 
223
        }
 
224
        else if(!strncmp(cc_digits, "6011", 4)) /* Discover */
 
225
        {
 
226
            cli_dbgmsg("dlp_is_valid_cc: Discover (%s)\n", cc_digits);
 
227
            return 1;
 
228
        } 
 
229
    }
 
230
 
 
231
    return 0;
 
232
}
 
233
 
 
234
static int contains_cc(const unsigned char *buffer, int length, int detmode)
 
235
{
 
236
    const unsigned char *idx;
 
237
    const unsigned char *end;
 
238
    int count = 0;
 
239
    
 
240
    if(buffer == NULL || length < 13)
 
241
    {
 
242
        return 0;         
 
243
    }
 
244
 
 
245
    end = buffer + length;
 
246
    idx = buffer;
 
247
    while(idx < end)
 
248
    {
 
249
        if(isdigit(*idx))
 
250
        {
 
251
            if((idx == buffer || !isdigit(idx[-1])) && dlp_is_valid_cc(idx, length - (idx - buffer)) == 1)
 
252
            {
 
253
                if(detmode == DETECT_MODE_DETECT)
 
254
                    return 1;
 
255
                else
 
256
                {
 
257
                    count++;
 
258
                    /* if we got a valid match we should increment the idx ptr
 
259
                     * to gain a little performance
 
260
                     */
 
261
                    idx += (length > 15?15:(length-1));
 
262
                }
 
263
            }
 
264
        }
 
265
        idx++;
 
266
    }
 
267
    
 
268
    return count;
 
269
}
 
270
 
 
271
int dlp_get_cc_count(const unsigned char *buffer, int length)
 
272
{
 
273
    return contains_cc(buffer, length, DETECT_MODE_COUNT);
 
274
}
 
275
 
 
276
int dlp_has_cc(const unsigned char *buffer, int length)
 
277
{
 
278
    return contains_cc(buffer, length, DETECT_MODE_DETECT);
 
279
}
 
280
 
 
281
int dlp_is_valid_ssn(const unsigned char *buffer, int length, int format)
 
282
{
 
283
    int area_number;
 
284
    int group_number;
 
285
    int serial_number;
 
286
    int minlength;
 
287
    int retval = 1;
 
288
    char numbuf[12];
 
289
    
 
290
    if(buffer == NULL)
 
291
        return 0;
 
292
        
 
293
    minlength = (format==SSN_FORMAT_HYPHENS?11:9);
 
294
 
 
295
    if(length < minlength)
 
296
        return 0;
 
297
 
 
298
    if((length > minlength) && isdigit(buffer[minlength]))
 
299
        return 0;
 
300
        
 
301
    strncpy(numbuf, buffer, minlength);
 
302
    numbuf[minlength] = 0;
 
303
 
 
304
    /* sscanf parses and (basically) validates the string for us */
 
305
    switch(format)
 
306
    {
 
307
        case SSN_FORMAT_HYPHENS:
 
308
            if(numbuf[3] != '-' || numbuf[6] != '-')
 
309
                return 0;
 
310
 
 
311
            if(sscanf((const char *) numbuf, 
 
312
                      "%3d-%2d-%4d", 
 
313
                      &area_number, 
 
314
                      &group_number, 
 
315
                      &serial_number) != 3)
 
316
            {
 
317
                return 0;
 
318
            }       
 
319
            break;
 
320
        case SSN_FORMAT_STRIPPED:
 
321
            if(!cli_isnumber(numbuf))
 
322
                return 0;
 
323
 
 
324
            if(sscanf((const char *) numbuf,  
 
325
                       "%3d%2d%4d", 
 
326
                       &area_number, 
 
327
                       &group_number, 
 
328
                       &serial_number) != 3)
 
329
             {
 
330
                 return 0;
 
331
             }       
 
332
             break;
 
333
    }
 
334
        
 
335
    /* start validating */
 
336
    /* validation data taken from 
 
337
     * http://en.wikipedia.org/wiki/Social_Security_number_%28United_States%29
 
338
     */
 
339
    if(area_number > MAX_AREA || 
 
340
       area_number == 666 || 
 
341
       area_number <= 0 || 
 
342
       group_number <= 0 || 
 
343
       group_number > 99 || 
 
344
       serial_number <= 0 ||
 
345
       serial_number > 9999)
 
346
        retval = 0;
 
347
        
 
348
    if(area_number == 987 && group_number == 65) 
 
349
    {
 
350
        if(serial_number >= 4320 && serial_number <= 4329)
 
351
            retval = 0;
 
352
    }
 
353
    
 
354
    if(group_number > ssn_max_group[area_number])
 
355
        retval = 0;
 
356
   
 
357
    if(retval)
 
358
        cli_dbgmsg("dlp_is_valid_ssn: SSN_%s: %s\n", format == SSN_FORMAT_HYPHENS ? "HYPHENS" : "STRIPPED", numbuf);
 
359
 
 
360
    return retval;
 
361
}
 
362
 
 
363
static int contains_ssn(const unsigned char *buffer, int length, int format, int detmode)
 
364
{
 
365
    const unsigned char *idx;
 
366
    const unsigned char *end;
 
367
    int count = 0;
 
368
    
 
369
    if(buffer == NULL || length < 11)
 
370
        return 0; 
 
371
 
 
372
    end = buffer + length;
 
373
    idx = buffer;
 
374
    while(idx < end)
 
375
    {
 
376
        if(isdigit(*idx))
 
377
        {
 
378
            /* check for area number and the first hyphen */
 
379
            if((idx == buffer || !isdigit(idx[-1])) && dlp_is_valid_ssn(idx, length - (idx - buffer), format) == 1)
 
380
            {
 
381
                if(detmode == DETECT_MODE_COUNT)
 
382
                {
 
383
                    count++;
 
384
                        /* hop over the matched bytes if we found an SSN */
 
385
                    idx += ((format == SSN_FORMAT_HYPHENS)?11:9);
 
386
                }
 
387
                else
 
388
                {
 
389
                    return 1;                                                                            
 
390
                }
 
391
            }
 
392
        }
 
393
        idx++;
 
394
    }
 
395
    
 
396
    return count;   
 
397
}
 
398
 
 
399
int dlp_get_stripped_ssn_count(const unsigned char *buffer, int length)
 
400
{
 
401
    return contains_ssn(buffer, 
 
402
                        length, 
 
403
                        SSN_FORMAT_STRIPPED, 
 
404
                        DETECT_MODE_COUNT);
 
405
}
 
406
 
 
407
int dlp_get_normal_ssn_count(const unsigned char *buffer, int length)
 
408
{
 
409
    return contains_ssn(buffer, 
 
410
                        length, 
 
411
                        SSN_FORMAT_HYPHENS, 
 
412
                        DETECT_MODE_COUNT);
 
413
}
 
414
 
 
415
int dlp_get_ssn_count(const unsigned char *buffer, int length)
 
416
{
 
417
    /* this will suck for performance but will find SSNs in either
 
418
     * format
 
419
     */
 
420
    return (dlp_get_stripped_ssn_count(buffer, length) + dlp_get_normal_ssn_count(buffer, length));
 
421
}
 
422
 
 
423
int dlp_has_ssn(const unsigned char *buffer, int length)
 
424
{
 
425
    return (contains_ssn(buffer, 
 
426
                         length, 
 
427
                         SSN_FORMAT_HYPHENS, 
 
428
                         DETECT_MODE_DETECT)
 
429
            | contains_ssn(buffer, 
 
430
                           length, 
 
431
                           SSN_FORMAT_STRIPPED, 
 
432
                           DETECT_MODE_DETECT));
 
433
}
 
434
 
 
435
int dlp_has_stripped_ssn(const unsigned char *buffer, int length)
 
436
{
 
437
    return contains_ssn(buffer, 
 
438
                        length, 
 
439
                        SSN_FORMAT_STRIPPED, 
 
440
                        DETECT_MODE_DETECT);
 
441
}
 
442
 
 
443
int dlp_has_normal_ssn(const unsigned char *buffer, int length)
 
444
{
 
445
    return contains_ssn(buffer, 
 
446
                        length, 
 
447
                        SSN_FORMAT_HYPHENS, 
 
448
                        DETECT_MODE_DETECT);
 
449
}