~ubuntu-branches/ubuntu/wily/clamav/wily-proposed

« back to all changes in this revision

Viewing changes to .pc/0009-fix-ssize_t-size_t-off_t-printf-modifier.patch/sigtool/sigtool.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman, Sebastian Andrzej Siewior, Andreas Cadhalpun, Scott Kitterman, Javier Fernández-Sanguino
  • Date: 2015-01-28 00:25:13 UTC
  • mfrom: (0.48.14 sid)
  • Revision ID: package-import@ubuntu.com-20150128002513-lil2oi74cooy4lzr
Tags: 0.98.6+dfsg-1
[ Sebastian Andrzej Siewior ]
* update "fix-ssize_t-size_t-off_t-printf-modifier", include of misc.h was
  missing but was pulled in via the systemd patch.
* Don't leak return codes from libmspack to clamav API. (Closes: #774686).

[ Andreas Cadhalpun ]
* Add patch to avoid emitting incremental progress messages when not
  outputting to a terminal. (Closes: #767350)
* Update lintian-overrides for unused-file-paragraph-in-dep5-copyright.
* clamav-base.postinst: always chown /var/log/clamav and /var/lib/clamav
  to clamav:clamav, not only on fresh installations. (Closes: #775400)
* Adapt the clamav-daemon and clamav-freshclam logrotate scripts,
  so that they correctly work under systemd.
* Move the PidFile variable from the clamd/freshclam configuration files
  to the init scripts. This makes the init scripts more robust against
  misconfiguration and avoids error messages with systemd. (Closes: #767353)
* debian/copyright: drop files from Files-Excluded only present in github
  tarballs
* Drop Workaround-a-bug-in-libc-on-Hurd.patch, because hurd got fixed.
  (see #752237)
* debian/rules: Remove useless --with-system-tommath --without-included-ltdl
  configure options.

[ Scott Kitterman ]
* Stop stripping llvm when repacking the tarball as the system llvm on some
  releases is too old to use
* New upstream bugfix release
  - Library shared object revisions.
  - Includes a patch from Sebastian Andrzej Siewior making ClamAV pid files
    compatible with systemd.
  - Fix a heap out of bounds condition with crafted Yoda's crypter files.
    This issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted mew packer files. This
    issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted upx packer files. This
    issue was discovered by Kevin Szkudlapski of Quarkslab.
  - Fix a heap out of bounds condition with crafted upack packer files. This
    issue was discovered by Sebastian Andrzej Siewior. CVE-2014-9328.
  - Compensate a crash due to incorrect compiler optimization when handling
    crafted petite packer files. This issue was discovered by Sebastian
    Andrzej Siewior.
* Update lintian override for embedded zlib to match new so version

[ Javier Fernández-Sanguino ]
* Updated Spanish Debconf template translation (Closes: #773563)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Copyright (C) 2014 Cisco Systems, Inc.
3
 
 *  Copyright (C) 2007 - 2013 Sourcefire, Inc.
4
 
 *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm@clamav.net>
5
 
 *  CDIFF code (C) 2006 Sensory Networks, Inc.
6
 
 *  Author: Tomasz Kojm <tkojm@clamav.net>
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
 
 
24
 
#if HAVE_CONFIG_H
25
 
#include "clamav-config.h"
26
 
#endif
27
 
 
28
 
#include <stdio.h>
29
 
#include <stdlib.h>
30
 
#include <string.h>
31
 
#ifdef HAVE_UNISTD_H
32
 
#include <unistd.h>
33
 
#endif
34
 
#include <zlib.h>
35
 
#include <time.h>
36
 
#include <locale.h>
37
 
#include <sys/types.h>
38
 
#include <sys/stat.h>
39
 
#include <fcntl.h>
40
 
#ifndef _WIN32
41
 
#include <sys/socket.h>
42
 
#include <sys/un.h>
43
 
#include <netinet/in.h>
44
 
#include <arpa/inet.h>
45
 
#include <sys/wait.h>
46
 
#endif
47
 
#include <dirent.h>
48
 
#include <ctype.h>
49
 
#include <libgen.h>
50
 
 
51
 
#ifdef HAVE_TERMIOS_H
52
 
#include <termios.h>
53
 
#endif
54
 
 
55
 
#include "vba.h"
56
 
 
57
 
#include "shared/output.h"
58
 
#include "shared/optparser.h"
59
 
#include "shared/misc.h"
60
 
#include "shared/cdiff.h"
61
 
#include "shared/tar.h"
62
 
 
63
 
#include "libclamav/clamav.h"
64
 
#include "libclamav/matcher.h"
65
 
#include "libclamav/cvd.h"
66
 
#include "libclamav/str.h"
67
 
#include "libclamav/ole2_extract.h"
68
 
#include "libclamav/htmlnorm.h"
69
 
#include "libclamav/default.h"
70
 
#include "libclamav/fmap.h"
71
 
#include "libclamav/readdb.h"
72
 
#include "libclamav/others.h"
73
 
#include "libclamav/pe.h"
74
 
 
75
 
#define MAX_DEL_LOOKAHEAD   5000
76
 
 
77
 
//struct s_info info;
78
 
short recursion = 0, bell = 0;
79
 
short printinfected = 0, printclean = 1;
80
 
 
81
 
static const struct dblist_s {
82
 
    const char *ext;
83
 
    unsigned int count;
84
 
} dblist[] = {
85
 
 
86
 
    /* special files */
87
 
    { "info",  0 },
88
 
    { "cfg",  0 },
89
 
    { "ign",  0 },
90
 
    { "ign2",  0 },
91
 
    { "ftm",  0 },
92
 
 
93
 
    /* databases */
94
 
    { "db",    1 },
95
 
    { "hdb",   1 },
96
 
    { "hdu",   1 },
97
 
    { "hsb",   1 },
98
 
    { "hsu",   1 },
99
 
    { "mdb",   1 },
100
 
    { "mdu",   1 },
101
 
    { "msb",   1 },
102
 
    { "msu",   1 },
103
 
    { "ndb",   1 },
104
 
    { "ndu",   1 },
105
 
    { "ldb",   1 },
106
 
    { "ldu",   1 },
107
 
    { "sdb",   1 },
108
 
    { "zmd",   1 },
109
 
    { "rmd",   1 },
110
 
    { "idb",   0 },
111
 
    { "fp",    0 },
112
 
    { "sfp",   0 },
113
 
    { "gdb",   1 },
114
 
    { "pdb",   1 },
115
 
    { "wdb",   0 },
116
 
    { "crb", 1 },
117
 
 
118
 
    { NULL,         0 }
119
 
};
120
 
 
121
 
static char *getdbname(const char *str, char *dst, int dstlen)
122
 
{
123
 
        int len = strlen(str);
124
 
 
125
 
    if(cli_strbcasestr(str, ".cvd") || cli_strbcasestr(str, ".cld") || cli_strbcasestr(str, ".cud"))
126
 
        len -= 4;
127
 
 
128
 
    if(dst) {
129
 
        strncpy(dst, str, MIN(dstlen - 1, len));
130
 
        dst[MIN(dstlen - 1, len)] = 0;
131
 
    } else {
132
 
        dst = (char *) malloc(len + 1);
133
 
        if(!dst)
134
 
            return NULL;
135
 
        strncpy(dst, str, len - 4);
136
 
        dst[MIN(dstlen - 1, len - 4)] = 0;
137
 
    }
138
 
    return dst;
139
 
}
140
 
 
141
 
static int hexdump(void)
142
 
{
143
 
        char buffer[FILEBUFF], *pt;
144
 
        int bytes;
145
 
 
146
 
 
147
 
    while((bytes = read(0, buffer, FILEBUFF)) > 0) {
148
 
        pt = cli_str2hex(buffer, bytes);
149
 
        if(write(1, pt, 2 * bytes) == -1) {
150
 
            mprintf("!hexdump: Can't write to stdout\n");
151
 
            free(pt);
152
 
            return -1;
153
 
        }
154
 
        free(pt);
155
 
    }
156
 
 
157
 
    if(bytes == -1)
158
 
        return -1;
159
 
 
160
 
    return 0;
161
 
}
162
 
 
163
 
static int hashsig(const struct optstruct *opts, unsigned int mdb, int type)
164
 
{
165
 
        char *hash;
166
 
        unsigned int i;
167
 
        STATBUF sb;
168
 
 
169
 
 
170
 
    if(opts->filename) {
171
 
        for(i = 0; opts->filename[i]; i++) {
172
 
            if(CLAMSTAT(opts->filename[i], &sb) == -1) {
173
 
                perror("hashsig");
174
 
                mprintf("!hashsig: Can't access file %s\n", opts->filename[i]);
175
 
                return -1;
176
 
            } else {
177
 
                if((sb.st_mode & S_IFMT) == S_IFREG) {
178
 
                    if((hash = cli_hashfile(opts->filename[i], type))) {
179
 
                        if(mdb)
180
 
                            mprintf("%u:%s:%s\n", (unsigned int) sb.st_size, hash, basename(opts->filename[i]));
181
 
                        else
182
 
                            mprintf("%s:%u:%s\n", hash, (unsigned int) sb.st_size, basename(opts->filename[i]));
183
 
                        free(hash);
184
 
                    } else {
185
 
                        mprintf("!hashsig: Can't generate hash for %s\n", opts->filename[i]);
186
 
                        return -1;
187
 
                    }
188
 
                }
189
 
            }
190
 
        }
191
 
 
192
 
    } else { /* stream */
193
 
        hash = cli_hashstream(stdin, NULL, type);
194
 
        if(!hash) {
195
 
            mprintf("!hashsig: Can't generate hash for input stream\n");
196
 
            return -1;
197
 
        }
198
 
        mprintf("%s\n", hash);
199
 
        free(hash);
200
 
    }
201
 
 
202
 
    return 0;
203
 
}
204
 
 
205
 
static int htmlnorm(const struct optstruct *opts)
206
 
{
207
 
        int fd;
208
 
        fmap_t *map;
209
 
 
210
 
    if((fd = open(optget(opts, "html-normalise")->strarg, O_RDONLY)) == -1) {
211
 
        mprintf("!htmlnorm: Can't open file %s\n", optget(opts, "html-normalise")->strarg);
212
 
        return -1;
213
 
    }
214
 
 
215
 
    if((map = fmap(fd, 0, 0))) {
216
 
        html_normalise_map(map, ".", NULL, NULL);
217
 
        funmap(map);
218
 
    } else
219
 
        mprintf("!fmap failed\n");
220
 
        
221
 
    close(fd);
222
 
 
223
 
    return 0;
224
 
}
225
 
 
226
 
static int utf16decode(const struct optstruct *opts)
227
 
{
228
 
        const char *fname;
229
 
        char *newname, buff[512], *decoded;
230
 
        int fd1, fd2, bytes;
231
 
 
232
 
 
233
 
    fname = optget(opts, "utf16-decode")->strarg;
234
 
    if((fd1 = open(fname, O_RDONLY)) == -1) {
235
 
        mprintf("!utf16decode: Can't open file %s\n", fname);
236
 
        return -1;
237
 
    }
238
 
 
239
 
    newname = malloc(strlen(fname) + 7);
240
 
    if(!newname) {
241
 
        mprintf("!utf16decode: Can't allocate memory\n");
242
 
        close(fd1);
243
 
        return -1;
244
 
    }
245
 
    sprintf(newname, "%s.ascii", fname);
246
 
 
247
 
    if((fd2 = open(newname, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
248
 
        mprintf("!utf16decode: Can't create file %s\n", newname);
249
 
        free(newname);
250
 
        close(fd1);
251
 
        return -1;
252
 
    }
253
 
 
254
 
    while((bytes = read(fd1, buff, sizeof(buff))) > 0) {
255
 
        decoded = cli_utf16toascii(buff, bytes);
256
 
        if(decoded) {
257
 
            if(write(fd2, decoded, strlen(decoded)) == -1) {
258
 
                mprintf("!utf16decode: Can't write to file %s\n", newname);
259
 
                free(decoded);
260
 
                close(fd1);
261
 
                close(fd2);
262
 
                unlink(newname);
263
 
                free(newname);
264
 
                return -1;
265
 
            }
266
 
            free(decoded);
267
 
        }
268
 
    }
269
 
 
270
 
    free(newname);
271
 
    close(fd1);
272
 
    close(fd2);
273
 
 
274
 
    return 0;
275
 
}
276
 
 
277
 
static char *getdsig(const char *host, const char *user, const unsigned char *data, unsigned int datalen, unsigned short mode)
278
 
{
279
 
        char buff[512], cmd[128], pass[30], *pt;
280
 
        struct sockaddr_in server;
281
 
        int sockd, bread, len;
282
 
#ifdef HAVE_TERMIOS_H
283
 
        struct termios old, new;
284
 
#endif
285
 
 
286
 
    memset(&server, 0x00, sizeof(struct sockaddr_in));
287
 
 
288
 
    if((pt = getenv("SIGNDPASS"))) {
289
 
        strncpy(pass, pt, sizeof(pass));
290
 
        pass[sizeof(pass)-1]='\0';
291
 
    } else {
292
 
        mprintf("Password: ");
293
 
 
294
 
#ifdef HAVE_TERMIOS_H
295
 
        if(tcgetattr(0, &old)) {
296
 
            mprintf("!getdsig: tcgetattr() failed\n");
297
 
            return NULL;
298
 
        }
299
 
        new = old;
300
 
        new.c_lflag &= ~ECHO;
301
 
        if(tcsetattr(0, TCSAFLUSH, &new)) {
302
 
            mprintf("!getdsig: tcsetattr() failed\n");
303
 
            return NULL;
304
 
        }
305
 
#endif
306
 
        if(scanf("%30s", pass) == EOF || !pt) {
307
 
            mprintf("!getdsig: Can't get password\n");
308
 
#ifdef HAVE_TERMIOS_H
309
 
            tcsetattr(0, TCSAFLUSH, &old);
310
 
#endif
311
 
            return NULL;
312
 
        }
313
 
 
314
 
#ifdef HAVE_TERMIOS_H
315
 
        if(tcsetattr(0, TCSAFLUSH, &old)) {
316
 
            mprintf("!getdsig: tcsetattr() failed\n");
317
 
            memset(pass, 0, sizeof(pass));
318
 
            return NULL;
319
 
        }
320
 
#endif
321
 
        mprintf("\n");
322
 
    }
323
 
 
324
 
    if((sockd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
325
 
        perror("socket()");
326
 
        mprintf("!getdsig: Can't create socket\n");
327
 
        memset(pass, 0, sizeof(pass));
328
 
        return NULL;
329
 
    }
330
 
 
331
 
    server.sin_family = AF_INET;
332
 
    server.sin_addr.s_addr = inet_addr(host);
333
 
    server.sin_port = htons(33101);
334
 
 
335
 
    if(connect(sockd, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) < 0) {
336
 
        perror("connect()");
337
 
        closesocket(sockd);
338
 
        mprintf("!getdsig: Can't connect to ClamAV Signing Service at %s\n", host);
339
 
        memset(pass, 0, sizeof(pass));
340
 
        return NULL;
341
 
    }
342
 
    memset(cmd, 0, sizeof(cmd));
343
 
 
344
 
    if(mode == 1)
345
 
        snprintf(cmd, sizeof(cmd) - datalen, "ClamSign:%s:%s:", user, pass);
346
 
    else if(mode == 2)
347
 
        snprintf(cmd, sizeof(cmd) - datalen, "ClamSignPSS:%s:%s:", user, pass);
348
 
    else
349
 
        snprintf(cmd, sizeof(cmd) - datalen, "ClamSignPSS2:%s:%s:", user, pass);
350
 
 
351
 
    len = strlen(cmd);
352
 
    pt = cmd + len;
353
 
    memcpy(pt, data, datalen);
354
 
    len += datalen;
355
 
 
356
 
    if(send(sockd, cmd, len, 0) < 0) {
357
 
        mprintf("!getdsig: Can't write to socket\n");
358
 
        closesocket(sockd);
359
 
        memset(cmd, 0, sizeof(cmd));
360
 
        memset(pass, 0, sizeof(pass));
361
 
        return NULL;
362
 
    }
363
 
 
364
 
    memset(cmd, 0, sizeof(cmd));
365
 
    memset(pass, 0, sizeof(pass));
366
 
    memset(buff, 0, sizeof(buff));
367
 
 
368
 
    if((bread = recv(sockd, buff, sizeof(buff)-1, 0)) > 0) {
369
 
        buff[bread] = '\0';
370
 
        if(!strstr(buff, "Signature:")) {
371
 
            mprintf("!getdsig: Error generating digital signature\n");
372
 
            mprintf("!getdsig: Answer from remote server: %s\n", buff);
373
 
            closesocket(sockd);
374
 
            return NULL;
375
 
        } else {
376
 
            mprintf("Signature received (length = %lu)\n", (unsigned long)strlen(buff) - 10);
377
 
        }
378
 
    } else {
379
 
        mprintf("!getdsig: Communication error with remote server\n");
380
 
        closesocket(sockd);
381
 
        return NULL;
382
 
    }
383
 
 
384
 
    closesocket(sockd);
385
 
 
386
 
    pt = buff;
387
 
    pt += 10;
388
 
    return strdup(pt);
389
 
}
390
 
 
391
 
static char *sha256file(const char *file, unsigned int *size)
392
 
{
393
 
        FILE *fh;
394
 
        unsigned int i, bytes;
395
 
        unsigned char digest[32], buffer[FILEBUFF];
396
 
        char *sha;
397
 
        void *ctx;
398
 
 
399
 
    ctx = cl_hash_init("sha256");
400
 
    if (!(ctx))
401
 
        return NULL;
402
 
 
403
 
    if(!(fh = fopen(file, "rb"))) {
404
 
        mprintf("!sha256file: Can't open file %s\n", file);
405
 
    cl_hash_destroy(ctx);
406
 
        return NULL;
407
 
    }
408
 
    if(size)
409
 
        *size = 0;
410
 
    while((bytes = fread(buffer, 1, sizeof(buffer), fh))) {
411
 
        cl_update_hash(ctx, buffer, bytes);
412
 
        if(size)
413
 
            *size += bytes;
414
 
    }
415
 
    cl_finish_hash(ctx, digest);
416
 
    sha = (char *) malloc(65);
417
 
    if(!sha)
418
 
    {
419
 
        fclose(fh);
420
 
        return NULL;
421
 
    }   
422
 
    for(i = 0; i < 32; i++)
423
 
        sprintf(sha + i * 2, "%02x", digest[i]);
424
 
 
425
 
    fclose(fh); 
426
 
    return sha;
427
 
}
428
 
 
429
 
static int writeinfo(const char *dbname, const char *builder, const char *header, const struct optstruct *opts, char * const *dblist2, unsigned int dblist2cnt)
430
 
{
431
 
        FILE *fh;
432
 
        unsigned int i, bytes;
433
 
        char file[32], *pt, dbfile[32];
434
 
        unsigned char digest[32], buffer[FILEBUFF];
435
 
        void *ctx;
436
 
 
437
 
    snprintf(file, sizeof(file), "%s.info", dbname);
438
 
    if(!access(file, R_OK)) {
439
 
        if(unlink(file) == -1) {
440
 
            mprintf("!writeinfo: Can't unlink %s\n", file);
441
 
            return -1;
442
 
        }
443
 
    }
444
 
 
445
 
    if(!(fh = fopen(file, "wb+"))) {
446
 
        mprintf("!writeinfo: Can't create file %s\n", file);
447
 
        return -1;
448
 
    }
449
 
 
450
 
    if(fprintf(fh, "%s\n", header) < 0) {
451
 
        mprintf("!writeinfo: Can't write to %s\n", file);
452
 
        fclose(fh);
453
 
        return -1;
454
 
    }
455
 
 
456
 
    if(dblist2cnt) {
457
 
        for(i = 0; i < dblist2cnt; i++) {
458
 
            if(!(pt = sha256file(dblist2[i], &bytes))) {
459
 
                mprintf("!writeinfo: Can't generate SHA256 for %s\n", file);
460
 
                fclose(fh);
461
 
                return -1;
462
 
            }
463
 
            if(fprintf(fh, "%s:%u:%s\n", dblist2[i], bytes, pt) < 0) {
464
 
                mprintf("!writeinfo: Can't write to info file\n");
465
 
                fclose(fh);
466
 
                free(pt);
467
 
                return -1;
468
 
            }
469
 
            free(pt);
470
 
        }
471
 
    } else {
472
 
        for(i = 0; dblist[i].ext; i++) {
473
 
            snprintf(dbfile, sizeof(dbfile), "%s.%s", dbname, dblist[i].ext);
474
 
            if(strcmp(dblist[i].ext, "info") && !access(dbfile, R_OK)) {
475
 
                if(!(pt = sha256file(dbfile, &bytes))) {
476
 
                    mprintf("!writeinfo: Can't generate SHA256 for %s\n", file);
477
 
                    fclose(fh);
478
 
                    return -1;
479
 
                }
480
 
                if(fprintf(fh, "%s:%u:%s\n", dbfile, bytes, pt) < 0) {
481
 
                    mprintf("!writeinfo: Can't write to info file\n");
482
 
                    fclose(fh);
483
 
                    free(pt);
484
 
                    return -1;
485
 
                }
486
 
                free(pt);
487
 
            }
488
 
        }
489
 
    }
490
 
    if(!optget(opts, "unsigned")->enabled) {
491
 
        rewind(fh);
492
 
    ctx = cl_hash_init("sha256");
493
 
    if (!(ctx)) {
494
 
        fclose(fh);
495
 
        return -1;
496
 
    }
497
 
 
498
 
        while((bytes = fread(buffer, 1, sizeof(buffer), fh)))
499
 
            cl_update_hash(ctx, buffer, bytes);
500
 
        cl_finish_hash(ctx, digest);
501
 
        if(!(pt = getdsig(optget(opts, "server")->strarg, builder, digest, 32, 3))) {
502
 
            mprintf("!writeinfo: Can't get digital signature from remote server\n");
503
 
            fclose(fh);
504
 
            return -1;
505
 
        }
506
 
        fprintf(fh, "DSIG:%s\n", pt);
507
 
        free(pt);
508
 
    }
509
 
    fclose(fh);
510
 
    return 0;
511
 
}
512
 
 
513
 
static int diffdirs(const char *old, const char *new, const char *patch);
514
 
static int verifydiff(const char *diff, const char *cvd, const char *incdir);
515
 
 
516
 
static int script2cdiff(const char *script, const char *builder, const struct optstruct *opts)
517
 
{
518
 
        char *cdiff, *pt, buffer[FILEBUFF];
519
 
        unsigned char digest[32];
520
 
        void *ctx;
521
 
        STATBUF sb;
522
 
        FILE *scripth, *cdiffh;
523
 
        gzFile gzh;
524
 
        unsigned int ver, osize;
525
 
        int bytes;
526
 
 
527
 
 
528
 
    if(CLAMSTAT(script, &sb) == -1) {
529
 
        mprintf("!script2diff: Can't stat file %s\n", script);
530
 
        return -1;
531
 
    }
532
 
    osize = (unsigned int) sb.st_size;
533
 
 
534
 
    cdiff = strdup(script);
535
 
    pt = strstr(cdiff, ".script");
536
 
    if(!pt) {
537
 
        mprintf("!script2cdiff: Incorrect file name (no .script extension)\n");
538
 
        free(cdiff);
539
 
        return -1;
540
 
    }
541
 
    strcpy(pt, ".cdiff");
542
 
 
543
 
    if(!(pt = strchr(script, '-'))) {
544
 
        mprintf("!script2cdiff: Incorrect file name syntax\n");
545
 
        free(cdiff);
546
 
        return -1;
547
 
    }
548
 
 
549
 
    if(sscanf(++pt, "%u.script", &ver) == EOF) {
550
 
        mprintf("!script2cdiff: Incorrect file name syntax\n");
551
 
        free(cdiff);
552
 
        return -1;
553
 
    }
554
 
 
555
 
    if(!(cdiffh = fopen(cdiff, "wb"))) {
556
 
        mprintf("!script2cdiff: Can't open %s for writing\n", cdiff);
557
 
        free(cdiff);
558
 
        return -1;
559
 
    }
560
 
 
561
 
    if(fprintf(cdiffh, "ClamAV-Diff:%u:%u:", ver, osize) < 0) {
562
 
        mprintf("!script2cdiff: Can't write to %s\n", cdiff);
563
 
        fclose(cdiffh);
564
 
        free(cdiff);
565
 
        return -1;
566
 
    }
567
 
    fclose(cdiffh);
568
 
 
569
 
    if(!(scripth = fopen(script, "rb"))) {
570
 
        mprintf("!script2cdiff: Can't open file %s for reading\n", script);
571
 
        unlink(cdiff);
572
 
        free(cdiff);
573
 
        return -1;
574
 
    }
575
 
 
576
 
    if(!(gzh = gzopen(cdiff, "ab9f"))) {
577
 
        mprintf("!script2cdiff: Can't open file %s for appending\n", cdiff);
578
 
        unlink(cdiff);
579
 
        free(cdiff);
580
 
        fclose(scripth);
581
 
        return -1;
582
 
    }
583
 
 
584
 
    while((bytes = fread(buffer, 1, sizeof(buffer), scripth)) > 0) {
585
 
        if(!gzwrite(gzh, buffer, bytes)) {
586
 
            mprintf("!script2cdiff: Can't gzwrite to %s\n", cdiff);
587
 
            unlink(cdiff);
588
 
            free(cdiff);
589
 
            fclose(scripth);
590
 
            gzclose(gzh);
591
 
            return -1;
592
 
        }
593
 
    }
594
 
    fclose(scripth);
595
 
    gzclose(gzh);
596
 
 
597
 
    if(!(cdiffh = fopen(cdiff, "rb"))) {
598
 
        mprintf("!script2cdiff: Can't open %s for reading/writing\n", cdiff);
599
 
        unlink(cdiff);
600
 
        free(cdiff);
601
 
        return -1;
602
 
    }
603
 
 
604
 
    ctx = cl_hash_init("sha256");
605
 
    if (!(ctx)) {
606
 
        unlink(cdiff);
607
 
        free(cdiff);
608
 
        fclose(cdiffh);
609
 
        return -1;
610
 
    }
611
 
 
612
 
    while((bytes = fread(buffer, 1, sizeof(buffer), cdiffh)))
613
 
        cl_update_hash(ctx, (unsigned char *) buffer, bytes);
614
 
 
615
 
    fclose(cdiffh);
616
 
    cl_finish_hash(ctx, digest);
617
 
 
618
 
    if(!(pt = getdsig(optget(opts, "server")->strarg, builder, digest, 32, 2))) {
619
 
        mprintf("!script2cdiff: Can't get digital signature from remote server\n");
620
 
        unlink(cdiff);
621
 
        free(cdiff);
622
 
        return -1;
623
 
    }
624
 
 
625
 
    if(!(cdiffh = fopen(cdiff, "ab"))) {
626
 
        mprintf("!script2cdiff: Can't open %s for appending\n", cdiff);
627
 
        unlink(cdiff);
628
 
        free(cdiff);
629
 
        return -1;
630
 
    }
631
 
    fprintf(cdiffh, ":%s", pt);
632
 
    free(pt);
633
 
    fclose(cdiffh);
634
 
 
635
 
    mprintf("Created %s\n", cdiff);
636
 
    free(cdiff);
637
 
 
638
 
    return 0;
639
 
}
640
 
 
641
 
static int qcompare(const void *a, const void *b)
642
 
{
643
 
    return strcmp(*(char * const *) a, *(char * const *) b);
644
 
}
645
 
 
646
 
static int build(const struct optstruct *opts)
647
 
{
648
 
        int ret, bc = 0;
649
 
        size_t bytes;
650
 
        unsigned int i, sigs = 0, oldsigs = 0, entries = 0, version, real_header, fl, maxentries;
651
 
        STATBUF foo;
652
 
        unsigned char buffer[FILEBUFF];
653
 
        char *tarfile, header[513], smbuff[32], builder[32], *pt, olddb[512];
654
 
        char patch[32], broken[32], dbname[32], dbfile[32];
655
 
        const char *newcvd, *localdbdir = NULL;
656
 
        struct cl_engine *engine;
657
 
        FILE *cvd, *fh;
658
 
        gzFile tar;
659
 
        time_t timet;
660
 
        struct tm *brokent;
661
 
        struct cl_cvd *oldcvd;
662
 
        char **dblist2 = NULL;
663
 
        unsigned int dblist2cnt = 0;
664
 
        DIR *dd;
665
 
        struct dirent *dent;
666
 
 
667
 
#define FREE_LS(x)                  \
668
 
    for(i = 0; i < dblist2cnt; i++) \
669
 
        free(x[i]);                 \
670
 
    free(x);
671
 
 
672
 
    if(!optget(opts, "server")->enabled && !optget(opts, "unsigned")->enabled) {
673
 
        mprintf("!build: --server is required for --build\n");
674
 
        return -1;
675
 
    }
676
 
 
677
 
    if(optget(opts, "datadir")->active)
678
 
        localdbdir = optget(opts, "datadir")->strarg;
679
 
 
680
 
    if(CLAMSTAT("COPYING", &foo) == -1) {
681
 
        mprintf("!build: COPYING file not found in current working directory.\n");
682
 
        return -1;
683
 
    }
684
 
 
685
 
    getdbname(optget(opts, "build")->strarg, dbname, sizeof(dbname));
686
 
    if(!strcmp(dbname, "bytecode"))
687
 
        bc = 1;
688
 
 
689
 
    if(!(engine = cl_engine_new())) {
690
 
        mprintf("!build: Can't initialize antivirus engine\n");
691
 
        return 50;
692
 
    }
693
 
 
694
 
    if((ret = cl_load(".", engine, &sigs, CL_DB_STDOPT | CL_DB_PUA | CL_DB_SIGNED))) {
695
 
        mprintf("!build: Can't load database: %s\n", cl_strerror(ret));
696
 
        cl_engine_free(engine);
697
 
        return -1;
698
 
    }
699
 
    cl_engine_free(engine);
700
 
 
701
 
    if(!sigs) {
702
 
        mprintf("!build: There are no signatures in database files\n");
703
 
    } else {
704
 
        if(bc) {
705
 
            if((dd = opendir(".")) == NULL) {
706
 
                mprintf("!build: Can't open current directory\n");
707
 
                return -1;
708
 
            }
709
 
            while((dent = readdir(dd))) {
710
 
                if(dent->d_ino) {
711
 
                    if(cli_strbcasestr(dent->d_name, ".cbc")) {
712
 
                        dblist2 = (char **) realloc(dblist2, (dblist2cnt + 1) * sizeof(char *));
713
 
                        if(!dblist2) { /* dblist2 leaked but we don't really care */
714
 
                            mprintf("!build: Memory allocation error\n");
715
 
                            closedir(dd);
716
 
                            return -1;
717
 
                        }
718
 
                        dblist2[dblist2cnt] = strdup(dent->d_name);
719
 
                        if(!dblist2[dblist2cnt]) {
720
 
                            FREE_LS(dblist2);
721
 
                            mprintf("!build: Memory allocation error\n");
722
 
                            return -1;
723
 
                        }
724
 
                        dblist2cnt++;
725
 
                    }
726
 
                }
727
 
            }
728
 
            closedir(dd);
729
 
            entries += dblist2cnt;
730
 
            if(dblist2 != NULL) {
731
 
                qsort(dblist2, dblist2cnt, sizeof(char *), qcompare);
732
 
            }
733
 
 
734
 
            if(!access("last.hdb", R_OK)) {
735
 
                if(!dblist2cnt) {
736
 
                    mprintf("!build: dblist2 == NULL (no .cbc files?)\n");
737
 
                    return -1;
738
 
                }
739
 
                dblist2 = (char **) realloc(dblist2, (dblist2cnt + 1) * sizeof(char *));
740
 
                if(!dblist2) {
741
 
                    mprintf("!build: Memory allocation error\n");
742
 
                    return -1;
743
 
                }
744
 
                dblist2[dblist2cnt] = strdup("last.hdb");
745
 
                if(!dblist2[dblist2cnt]) {
746
 
                    FREE_LS(dblist2);
747
 
                    mprintf("!build: Memory allocation error\n");
748
 
                    return -1;
749
 
                }
750
 
                dblist2cnt++;
751
 
                entries += countlines("last.hdb");
752
 
            }
753
 
        } else {
754
 
            for(i = 0; dblist[i].ext; i++) {
755
 
                snprintf(dbfile, sizeof(dbfile), "%s.%s", dbname, dblist[i].ext);
756
 
                if(dblist[i].count && !access(dbfile, R_OK))
757
 
                    entries += countlines(dbfile);
758
 
            }
759
 
        }
760
 
 
761
 
        if(entries != sigs)
762
 
            mprintf("^build: Signatures in %s db files: %u, loaded by libclamav: %u\n", dbname, entries, sigs);
763
 
 
764
 
    maxentries = optget(opts, "max-bad-sigs")->numarg;
765
 
 
766
 
    if (maxentries) {
767
 
        if(!entries || (sigs > entries && sigs - entries >= maxentries)) {
768
 
            mprintf("!Bad number of signatures in database files\n");
769
 
            FREE_LS(dblist2);
770
 
            return -1;
771
 
        }
772
 
    }
773
 
    }
774
 
 
775
 
    /* try to read cvd header of current database */
776
 
    if(opts->filename) {
777
 
        if(cli_strbcasestr(opts->filename[0], ".cvd") || cli_strbcasestr(opts->filename[0], ".cld") || cli_strbcasestr(opts->filename[0], ".cud")) {
778
 
            strncpy(olddb, opts->filename[0], sizeof(olddb));
779
 
            olddb[sizeof(olddb)-1]='\0';
780
 
        } else {
781
 
            mprintf("!build: Not a CVD/CLD/CUD file\n");
782
 
            FREE_LS(dblist2);
783
 
            return -1;
784
 
        }
785
 
 
786
 
    } else {
787
 
        pt = freshdbdir();
788
 
        snprintf(olddb, sizeof(olddb), "%s"PATHSEP"%s.cvd", localdbdir ? localdbdir : pt, dbname);
789
 
        if(access(olddb, R_OK))
790
 
            snprintf(olddb, sizeof(olddb), "%s"PATHSEP"%s.cld", localdbdir ? localdbdir : pt, dbname);
791
 
        if(access(olddb, R_OK))
792
 
            snprintf(olddb, sizeof(olddb), "%s"PATHSEP"%s.cud", localdbdir ? localdbdir : pt, dbname);
793
 
        free(pt);
794
 
    }
795
 
 
796
 
    if(!(oldcvd = cl_cvdhead(olddb)) && !optget(opts, "unsigned")->enabled) {
797
 
        mprintf("^build: CAN'T READ CVD HEADER OF CURRENT DATABASE %s (wait 3 s)\n", olddb);
798
 
        sleep(3);
799
 
    }
800
 
 
801
 
    if(oldcvd) {
802
 
        version = oldcvd->version + 1;
803
 
        oldsigs = oldcvd->sigs;
804
 
        cl_cvdfree(oldcvd);
805
 
    } else if (optget(opts, "cvd-version")->numarg != 0) {
806
 
        version = optget(opts, "cvd-version")->numarg;
807
 
    } else {
808
 
        mprintf("Version number: ");
809
 
        if(scanf("%u", &version) == EOF) {
810
 
            mprintf("!build: scanf() failed\n");
811
 
            FREE_LS(dblist2);
812
 
            return -1;
813
 
        }
814
 
    }
815
 
 
816
 
    mprintf("Total sigs: %u\n", sigs);
817
 
    if(sigs > oldsigs)
818
 
        mprintf("New sigs: %u\n", sigs - oldsigs);
819
 
 
820
 
    strcpy(header, "ClamAV-VDB:");
821
 
 
822
 
    /* time */
823
 
    time(&timet);
824
 
    brokent = localtime(&timet);
825
 
    setlocale(LC_TIME, "C");
826
 
    strftime(smbuff, sizeof(smbuff), "%d %b %Y %H-%M %z", brokent);
827
 
    strcat(header, smbuff);
828
 
 
829
 
    /* version */
830
 
    sprintf(header + strlen(header), ":%u:", version);
831
 
 
832
 
    /* number of signatures */
833
 
    sprintf(header + strlen(header), "%u:", sigs);
834
 
 
835
 
    /* functionality level */
836
 
    fl = (unsigned int)(optget(opts, "flevel")->numarg);
837
 
    sprintf(header + strlen(header), "%u:", fl);
838
 
 
839
 
    real_header = strlen(header);
840
 
 
841
 
    /* add fake MD5 and dsig (for writeinfo) */
842
 
    strcat(header, "X:X:");
843
 
 
844
 
    if((pt = getenv("SIGNDUSER"))) {
845
 
        strncpy(builder, pt, sizeof(builder));
846
 
        builder[sizeof(builder)-1]='\0';
847
 
    } else {
848
 
        mprintf("Builder name: ");
849
 
        if(scanf("%32s", builder) == EOF || !pt) {
850
 
            mprintf("!build: Can't get builder name\n");
851
 
            free(dblist2);
852
 
            return -1;
853
 
        }
854
 
    }
855
 
 
856
 
    /* add builder */
857
 
    strcat(header, builder);
858
 
 
859
 
    /* add current time */
860
 
    sprintf(header + strlen(header), ":%u", (unsigned int) timet);
861
 
 
862
 
    if(writeinfo(dbname, builder, header, opts, dblist2, dblist2cnt) == -1) {
863
 
        mprintf("!build: Can't generate info file\n");
864
 
        FREE_LS(dblist2);
865
 
        return -1;
866
 
    }
867
 
 
868
 
    header[real_header] = 0;
869
 
 
870
 
    if(!(tarfile = cli_gentemp("."))) {
871
 
        mprintf("!build: Can't generate temporary name for tarfile\n");
872
 
        FREE_LS(dblist2);
873
 
        return -1;
874
 
    }
875
 
 
876
 
    if((tar = gzopen(tarfile, "wb9f")) == NULL) {
877
 
        mprintf("!build: Can't open file %s for writing\n", tarfile);
878
 
        free(tarfile);
879
 
        FREE_LS(dblist2);
880
 
        return -1;
881
 
    }
882
 
 
883
 
    if(tar_addfile(-1, tar, "COPYING") == -1) {
884
 
        mprintf("!build: Can't add COPYING to tar archive\n");
885
 
        gzclose(tar);
886
 
        unlink(tarfile);
887
 
        free(tarfile);
888
 
        FREE_LS(dblist2);
889
 
        return -1;
890
 
    }
891
 
 
892
 
    if(bc) {
893
 
        if(tar_addfile(-1, tar, "bytecode.info") == -1) {
894
 
            gzclose(tar);
895
 
            unlink(tarfile);
896
 
            free(tarfile);
897
 
            FREE_LS(dblist2);
898
 
            return -1;
899
 
        }
900
 
        for(i = 0; i < dblist2cnt; i++) {
901
 
            if(tar_addfile(-1, tar, dblist2[i]) == -1) {
902
 
                gzclose(tar);
903
 
                unlink(tarfile);
904
 
                free(tarfile);
905
 
                FREE_LS(dblist2);
906
 
                return -1;
907
 
            }
908
 
        }
909
 
    } else {
910
 
        for(i = 0; dblist[i].ext; i++) {
911
 
            snprintf(dbfile, sizeof(dbfile), "%s.%s", dbname, dblist[i].ext);
912
 
            if(!access(dbfile, R_OK)) {
913
 
                if(tar_addfile(-1, tar, dbfile) == -1) {
914
 
                    gzclose(tar);
915
 
                    unlink(tarfile);
916
 
                    free(tarfile);
917
 
                    FREE_LS(dblist2);
918
 
                    return -1;
919
 
                }
920
 
            }
921
 
        }
922
 
    }
923
 
    gzclose(tar);
924
 
    FREE_LS(dblist2);
925
 
 
926
 
    /* MD5 + dsig */
927
 
    if(!(fh = fopen(tarfile, "rb"))) {
928
 
        mprintf("!build: Can't open file %s for reading\n", tarfile);
929
 
        unlink(tarfile);
930
 
        free(tarfile);
931
 
        return -1;
932
 
    }
933
 
 
934
 
    if(!(pt = cli_hashstream(fh, buffer, 1))) {
935
 
        mprintf("!build: Can't generate MD5 checksum for %s\n", tarfile);
936
 
        fclose(fh);
937
 
        unlink(tarfile);
938
 
        free(tarfile);
939
 
        return -1;
940
 
    }
941
 
    rewind(fh);
942
 
    sprintf(header + strlen(header), "%s:", pt);
943
 
    free(pt);
944
 
 
945
 
    if(!optget(opts, "unsigned")->enabled) {
946
 
        if(!(pt = getdsig(optget(opts, "server")->strarg, builder, buffer, 16, 1))) {
947
 
            mprintf("!build: Can't get digital signature from remote server\n");
948
 
            fclose(fh);
949
 
            unlink(tarfile);
950
 
            free(tarfile);
951
 
            return -1;
952
 
        }
953
 
        sprintf(header + strlen(header), "%s:", pt);
954
 
        free(pt);
955
 
    } else {
956
 
        sprintf(header + strlen(header), "X:");
957
 
    }
958
 
 
959
 
    /* add builder */
960
 
    strcat(header, builder);
961
 
 
962
 
    /* add current time */
963
 
    sprintf(header + strlen(header), ":%u", (unsigned int) timet);
964
 
 
965
 
    /* fill up with spaces */
966
 
    while(strlen(header) < sizeof(header) - 1)
967
 
        strcat(header, " ");
968
 
 
969
 
    /* build the final database */
970
 
    newcvd = optget(opts, "build")->strarg;
971
 
    if(!(cvd = fopen(newcvd, "wb"))) {
972
 
        mprintf("!build: Can't create final database %s\n", newcvd);
973
 
        fclose(fh);
974
 
        unlink(tarfile);
975
 
        free(tarfile);
976
 
        return -1;
977
 
    }
978
 
 
979
 
    if(fwrite(header, 1, 512, cvd) != 512) {
980
 
        mprintf("!build: Can't write to %s\n", newcvd);
981
 
        fclose(fh);
982
 
        unlink(tarfile);
983
 
        free(tarfile);
984
 
        fclose(cvd);
985
 
        unlink(newcvd);
986
 
        return -1;
987
 
    }
988
 
 
989
 
    while((bytes = fread(buffer, 1, FILEBUFF, fh)) > 0) {
990
 
        if(fwrite(buffer, 1, bytes, cvd) != bytes) {
991
 
            mprintf("!build: Can't write to %s\n", newcvd);
992
 
            fclose(fh);
993
 
            unlink(tarfile);
994
 
            free(tarfile);
995
 
            fclose(cvd);
996
 
            unlink(newcvd);
997
 
            return -1;
998
 
        }
999
 
    }
1000
 
 
1001
 
    fclose(fh);
1002
 
    fclose(cvd);
1003
 
 
1004
 
    if(unlink(tarfile) == -1) {
1005
 
        mprintf("^build: Can't unlink %s\n", tarfile);
1006
 
        unlink(tarfile);
1007
 
        free(tarfile);
1008
 
        unlink(newcvd);
1009
 
        return -1;
1010
 
    }
1011
 
    free(tarfile);
1012
 
 
1013
 
    mprintf("Created %s\n", newcvd);
1014
 
 
1015
 
    if(optget(opts, "unsigned")->enabled)
1016
 
        return 0;
1017
 
 
1018
 
    if(!oldcvd || optget(opts, "no-cdiff")->enabled) {
1019
 
        mprintf("Skipping .cdiff creation\n");
1020
 
        return 0;
1021
 
    }
1022
 
 
1023
 
    /* generate patch */
1024
 
    if(!(pt = cli_gentemp(NULL))) {
1025
 
        mprintf("!build: Can't generate temporary name\n");
1026
 
        unlink(newcvd);
1027
 
        return -1;
1028
 
    }
1029
 
 
1030
 
    if(mkdir(pt, 0700)) {
1031
 
        mprintf("!build: Can't create temporary directory %s\n", pt);
1032
 
        free(pt);
1033
 
        unlink(newcvd);
1034
 
        return -1;
1035
 
    }
1036
 
 
1037
 
    if(cli_cvdunpack(olddb, pt) == -1) {
1038
 
        mprintf("!build: Can't unpack CVD file %s\n", olddb);
1039
 
        cli_rmdirs(pt);
1040
 
        free(pt);
1041
 
        unlink(newcvd);
1042
 
        return -1;
1043
 
    }
1044
 
    strncpy(olddb, pt, sizeof(olddb));
1045
 
    olddb[sizeof(olddb)-1]='\0';
1046
 
    free(pt);
1047
 
 
1048
 
    if(!(pt = cli_gentemp(NULL))) {
1049
 
        mprintf("!build: Can't generate temporary name\n");
1050
 
        cli_rmdirs(olddb);
1051
 
        unlink(newcvd);
1052
 
        return -1;
1053
 
    }
1054
 
 
1055
 
    if(mkdir(pt, 0700)) {
1056
 
        mprintf("!build: Can't create temporary directory %s\n", pt);
1057
 
        free(pt);
1058
 
        cli_rmdirs(olddb);
1059
 
        unlink(newcvd);
1060
 
        return -1;
1061
 
    }
1062
 
 
1063
 
    if(cli_cvdunpack(newcvd, pt) == -1) {
1064
 
        mprintf("!build: Can't unpack CVD file %s\n", newcvd);
1065
 
        cli_rmdirs(pt);
1066
 
        free(pt);
1067
 
        cli_rmdirs(olddb);
1068
 
        unlink(newcvd);
1069
 
        return -1;
1070
 
    }
1071
 
 
1072
 
    snprintf(patch, sizeof(patch), "%s-%u.script", dbname, version);
1073
 
    ret = diffdirs(olddb, pt, patch);
1074
 
 
1075
 
    cli_rmdirs(pt);
1076
 
    free(pt);
1077
 
 
1078
 
    if(ret == -1) {
1079
 
        cli_rmdirs(olddb);
1080
 
        unlink(newcvd);
1081
 
        return -1;
1082
 
    }
1083
 
 
1084
 
    ret = verifydiff(patch, NULL, olddb);
1085
 
    cli_rmdirs(olddb);
1086
 
 
1087
 
    if(ret == -1) {
1088
 
        snprintf(broken, sizeof(broken), "%s.broken", patch);
1089
 
        if(rename(patch, broken)) {
1090
 
            unlink(patch);
1091
 
            mprintf("!Generated file is incorrect, removed");
1092
 
        } else {
1093
 
            mprintf("!Generated file is incorrect, renamed to %s\n", broken);
1094
 
        }
1095
 
    } else {
1096
 
        ret = script2cdiff(patch, builder, opts);
1097
 
    }
1098
 
 
1099
 
    return ret;
1100
 
}
1101
 
 
1102
 
static int unpack(const struct optstruct *opts)
1103
 
{
1104
 
        char name[512], *dbdir;
1105
 
        const char *localdbdir = NULL;
1106
 
 
1107
 
    if(optget(opts, "datadir")->active)
1108
 
        localdbdir = optget(opts, "datadir")->strarg;
1109
 
 
1110
 
    if(optget(opts, "unpack-current")->enabled) {
1111
 
        dbdir = freshdbdir();
1112
 
        snprintf(name, sizeof(name), "%s"PATHSEP"%s.cvd", localdbdir ? localdbdir : dbdir, optget(opts, "unpack-current")->strarg);
1113
 
        if(access(name, R_OK)) {
1114
 
            snprintf(name, sizeof(name), "%s"PATHSEP"%s.cld", localdbdir ? localdbdir : dbdir, optget(opts, "unpack-current")->strarg);
1115
 
            if(access(name, R_OK)) {
1116
 
                mprintf("!unpack: Couldn't find %s CLD/CVD database in %s\n", optget(opts, "unpack-current")->strarg, localdbdir ? localdbdir : dbdir);
1117
 
                free(dbdir);
1118
 
                return -1;
1119
 
            }
1120
 
        }
1121
 
        free(dbdir);
1122
 
 
1123
 
    } else {
1124
 
        strncpy(name, optget(opts, "unpack")->strarg, sizeof(name));
1125
 
        name[sizeof(name)-1]='\0';
1126
 
    }
1127
 
 
1128
 
    if (cl_cvdverify(name) != CL_SUCCESS) {
1129
 
        mprintf("!unpack: %s is not a valid CVD\n", name);
1130
 
        return -1;
1131
 
    }
1132
 
 
1133
 
    if(cli_cvdunpack(name, ".") == -1) {
1134
 
        mprintf("!unpack: Can't unpack file %s\n", name);
1135
 
        return -1;
1136
 
    }
1137
 
 
1138
 
    return 0;
1139
 
}
1140
 
 
1141
 
static int cvdinfo(const struct optstruct *opts)
1142
 
{
1143
 
        struct cl_cvd *cvd;
1144
 
        char *pt;
1145
 
        int ret;
1146
 
 
1147
 
 
1148
 
    pt = optget(opts, "info")->strarg;
1149
 
    if((cvd = cl_cvdhead(pt)) == NULL) {
1150
 
        mprintf("!cvdinfo: Can't read/parse CVD header of %s\n", pt);
1151
 
        return -1;
1152
 
    }
1153
 
    mprintf("File: %s\n", pt);
1154
 
 
1155
 
    pt = strchr(cvd->time, '-');
1156
 
    if(!pt){
1157
 
        cl_cvdfree(cvd);
1158
 
        return -1;
1159
 
    }
1160
 
    *pt = ':';
1161
 
    mprintf("Build time: %s\n", cvd->time);
1162
 
    mprintf("Version: %u\n", cvd->version);
1163
 
    mprintf("Signatures: %u\n", cvd->sigs);
1164
 
    mprintf("Functionality level: %u\n", cvd->fl);
1165
 
    mprintf("Builder: %s\n", cvd->builder);
1166
 
 
1167
 
    pt = optget(opts, "info")->strarg;
1168
 
    if(cli_strbcasestr(pt, ".cvd")) {
1169
 
        mprintf("MD5: %s\n", cvd->md5);
1170
 
        mprintf("Digital signature: %s\n", cvd->dsig);
1171
 
    }
1172
 
    cl_cvdfree(cvd);
1173
 
    if(cli_strbcasestr(pt, ".cud"))
1174
 
        mprintf("Verification: Unsigned container\n");
1175
 
    else if((ret = cl_cvdverify(pt))) {
1176
 
        mprintf("!cvdinfo: Verification: %s\n", cl_strerror(ret));
1177
 
        return -1;
1178
 
    } else
1179
 
        mprintf("Verification OK.\n");
1180
 
 
1181
 
    return 0;
1182
 
}
1183
 
 
1184
 
static int listdb(const char *filename, const regex_t *regex);
1185
 
 
1186
 
static int listdir(const char *dirname, const regex_t *regex)
1187
 
{
1188
 
        DIR *dd;
1189
 
        struct dirent *dent;
1190
 
        char *dbfile;
1191
 
 
1192
 
    if((dd = opendir(dirname)) == NULL) {
1193
 
        mprintf("!listdir: Can't open directory %s\n", dirname);
1194
 
        return -1;
1195
 
    }
1196
 
 
1197
 
    while((dent = readdir(dd))) {
1198
 
        if(dent->d_ino)
1199
 
        {
1200
 
            if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") &&
1201
 
            (cli_strbcasestr(dent->d_name, ".db")  ||
1202
 
             cli_strbcasestr(dent->d_name, ".hdb") ||
1203
 
             cli_strbcasestr(dent->d_name, ".hdu") ||
1204
 
             cli_strbcasestr(dent->d_name, ".hsb") ||
1205
 
             cli_strbcasestr(dent->d_name, ".hsu") ||
1206
 
             cli_strbcasestr(dent->d_name, ".mdb") ||
1207
 
             cli_strbcasestr(dent->d_name, ".mdu") ||
1208
 
             cli_strbcasestr(dent->d_name, ".msb") ||
1209
 
             cli_strbcasestr(dent->d_name, ".msu") ||
1210
 
             cli_strbcasestr(dent->d_name, ".ndb") ||
1211
 
             cli_strbcasestr(dent->d_name, ".ndu") ||
1212
 
             cli_strbcasestr(dent->d_name, ".ldb") ||
1213
 
             cli_strbcasestr(dent->d_name, ".ldu") ||
1214
 
             cli_strbcasestr(dent->d_name, ".sdb") ||
1215
 
             cli_strbcasestr(dent->d_name, ".zmd") ||
1216
 
             cli_strbcasestr(dent->d_name, ".rmd") ||
1217
 
             cli_strbcasestr(dent->d_name, ".cdb") ||
1218
 
             cli_strbcasestr(dent->d_name, ".cbc") ||
1219
 
             cli_strbcasestr(dent->d_name, ".cld") ||
1220
 
             cli_strbcasestr(dent->d_name, ".cvd") ||  
1221
 
             cli_strbcasestr(dent->d_name, ".crb"))) {
1222
 
 
1223
 
                dbfile = (char *) malloc(strlen(dent->d_name) + strlen(dirname) + 2);
1224
 
                if(!dbfile) {
1225
 
                    mprintf("!listdir: Can't allocate memory for dbfile\n");
1226
 
                    closedir(dd);
1227
 
                    return -1;
1228
 
                }
1229
 
                sprintf(dbfile, "%s"PATHSEP"%s", dirname, dent->d_name);
1230
 
 
1231
 
                if(listdb(dbfile, regex) == -1) {
1232
 
                    mprintf("!listdb: Error listing database %s\n", dbfile);
1233
 
                    free(dbfile);
1234
 
                    closedir(dd);
1235
 
                    return -1;
1236
 
                }
1237
 
                free(dbfile);
1238
 
            }
1239
 
        }
1240
 
    }
1241
 
 
1242
 
    closedir(dd);
1243
 
    return 0;
1244
 
}
1245
 
 
1246
 
static int listdb(const char *filename, const regex_t *regex)
1247
 
{
1248
 
        FILE *fh;
1249
 
        char *buffer, *pt, *start, *dir;
1250
 
        const char *dbname, *pathsep = PATHSEP;
1251
 
        unsigned int line = 0;
1252
 
 
1253
 
 
1254
 
    if((fh = fopen(filename, "rb")) == NULL) {
1255
 
        mprintf("!listdb: Can't open file %s\n", filename);
1256
 
        return -1;
1257
 
    }
1258
 
 
1259
 
    if(!(buffer = (char *) malloc(FILEBUFF))) {
1260
 
        mprintf("!listdb: Can't allocate memory for buffer\n");
1261
 
        fclose(fh);
1262
 
        return -1;
1263
 
    }
1264
 
 
1265
 
    /* check for CVD file */
1266
 
    if(!fgets(buffer, 12, fh)) {
1267
 
        mprintf("!listdb: fgets failed\n");
1268
 
        free(buffer);
1269
 
        fclose(fh);
1270
 
        return -1;
1271
 
    }
1272
 
    rewind(fh);
1273
 
 
1274
 
    if(!strncmp(buffer, "ClamAV-VDB:", 11)) {
1275
 
        free(buffer);
1276
 
        fclose(fh);
1277
 
 
1278
 
        if(!(dir = cli_gentemp(NULL))) {
1279
 
            mprintf("!listdb: Can't generate temporary name\n");
1280
 
            return -1;
1281
 
        }
1282
 
 
1283
 
        if(mkdir(dir, 0700)) {
1284
 
            mprintf("!listdb: Can't create temporary directory %s\n", dir);
1285
 
            free(dir);
1286
 
            return -1;
1287
 
        }
1288
 
 
1289
 
        if(cli_cvdunpack(filename, dir) == -1) {
1290
 
            mprintf("!listdb: Can't unpack CVD file %s\n", filename);
1291
 
            cli_rmdirs(dir);
1292
 
            free(dir);
1293
 
            return -1;
1294
 
        }
1295
 
 
1296
 
        /* list extracted directory */
1297
 
        if(listdir(dir, regex) == -1) {
1298
 
            mprintf("!listdb: Can't list directory %s\n", filename);
1299
 
            cli_rmdirs(dir);
1300
 
            free(dir);
1301
 
            return -1;
1302
 
        }
1303
 
 
1304
 
        cli_rmdirs(dir);
1305
 
        free(dir);
1306
 
 
1307
 
        return 0;
1308
 
    }
1309
 
 
1310
 
    if(!(dbname = strrchr(filename, *pathsep))) {
1311
 
        mprintf("!listdb: Invalid filename %s\n", filename);
1312
 
        fclose(fh);
1313
 
        free(buffer);
1314
 
        return -1;
1315
 
    }
1316
 
    dbname++;
1317
 
 
1318
 
    if(cli_strbcasestr(filename, ".db")) { /* old style database */
1319
 
 
1320
 
        while(fgets(buffer, FILEBUFF, fh)) {
1321
 
            if(regex) {
1322
 
                cli_chomp(buffer);
1323
 
                if(!cli_regexec(regex, buffer, 0, NULL, 0))
1324
 
                    mprintf("[%s] %s\n", dbname, buffer);
1325
 
                continue;
1326
 
            }
1327
 
            line++;
1328
 
            pt = strchr(buffer, '=');
1329
 
            if(!pt) {
1330
 
                mprintf("!listdb: Malformed pattern line %u (file %s)\n", line, filename);
1331
 
                fclose(fh);
1332
 
                free(buffer);
1333
 
                return -1;
1334
 
            }
1335
 
 
1336
 
            start = buffer;
1337
 
            *pt = 0;
1338
 
 
1339
 
            if((pt = strstr(start, " (Clam)")))
1340
 
                *pt = 0;
1341
 
 
1342
 
            mprintf("%s\n", start);
1343
 
        }
1344
 
 
1345
 
    } else if (cli_strbcasestr(filename, ".crb")) {
1346
 
        while (fgets(buffer, FILEBUFF, fh)) {
1347
 
            cli_chomp(buffer);
1348
 
            
1349
 
            if (buffer[0] == '#')
1350
 
                continue;
1351
 
 
1352
 
            if (regex) {
1353
 
                if (!cli_regexec(regex, buffer, 0 , NULL, 0))
1354
 
                    mprintf("[%s] %s\n", dbname, buffer);
1355
 
 
1356
 
                continue;
1357
 
            }
1358
 
            line++;
1359
 
            mprintf("%s\n", buffer);
1360
 
        }
1361
 
    } else if(cli_strbcasestr(filename, ".hdb") || cli_strbcasestr(filename, ".hdu") || cli_strbcasestr(filename, ".mdb") || cli_strbcasestr(filename, ".mdu") || cli_strbcasestr(filename, ".hsb") || cli_strbcasestr(filename, ".hsu") || cli_strbcasestr(filename, ".msb") || cli_strbcasestr(filename, ".msu")) { /* hash database */
1362
 
 
1363
 
        while(fgets(buffer, FILEBUFF, fh)) {
1364
 
            cli_chomp(buffer);
1365
 
            if(regex) {
1366
 
                if(!cli_regexec(regex, buffer, 0, NULL, 0))
1367
 
                    mprintf("[%s] %s\n", dbname, buffer);
1368
 
                continue;
1369
 
            }
1370
 
            line++;
1371
 
            start = cli_strtok(buffer, 2, ":");
1372
 
 
1373
 
            if(!start) {
1374
 
                mprintf("!listdb: Malformed pattern line %u (file %s)\n", line, filename);
1375
 
                fclose(fh);
1376
 
                free(buffer);
1377
 
                return -1;
1378
 
            }
1379
 
 
1380
 
            if((pt = strstr(start, " (Clam)")))
1381
 
                *pt = 0;
1382
 
 
1383
 
            mprintf("%s\n", start);
1384
 
            free(start);
1385
 
        }
1386
 
 
1387
 
    } else if(cli_strbcasestr(filename, ".ndb") || cli_strbcasestr(filename, ".ndu") || cli_strbcasestr(filename, ".ldb") || cli_strbcasestr(filename, ".ldu") || cli_strbcasestr(filename, ".sdb") || cli_strbcasestr(filename, ".zmd") || cli_strbcasestr(filename, ".rmd") || cli_strbcasestr(filename, ".cdb")) {
1388
 
 
1389
 
        while(fgets(buffer, FILEBUFF, fh)) {
1390
 
            cli_chomp(buffer);
1391
 
            if(regex) {
1392
 
                if(!cli_regexec(regex, buffer, 0, NULL, 0))
1393
 
                    mprintf("[%s] %s\n", dbname, buffer);
1394
 
                continue;
1395
 
            }
1396
 
            line++;
1397
 
 
1398
 
            if(cli_strbcasestr(filename, ".ldb") || cli_strbcasestr(filename, ".ldu"))
1399
 
                pt = strchr(buffer, ';');
1400
 
            else
1401
 
                pt = strchr(buffer, ':');
1402
 
 
1403
 
            if(!pt) {
1404
 
                mprintf("!listdb: Malformed pattern line %u (file %s)\n", line, filename);
1405
 
                fclose(fh);
1406
 
                free(buffer);
1407
 
                return -1;
1408
 
            }
1409
 
            *pt = 0;
1410
 
 
1411
 
            if((pt = strstr(buffer, " (Clam)")))
1412
 
                *pt = 0;
1413
 
 
1414
 
            mprintf("%s\n", buffer);
1415
 
        }
1416
 
 
1417
 
    } else if(cli_strbcasestr(filename, ".cbc")) {
1418
 
        if(fgets(buffer, FILEBUFF, fh) && fgets(buffer, FILEBUFF, fh)) {
1419
 
            pt = strchr(buffer, ';');
1420
 
            if(!pt) { /* not a real sig */
1421
 
                fclose(fh);
1422
 
                free(buffer);
1423
 
                return 0;
1424
 
            }
1425
 
            if(regex) {
1426
 
                if(!cli_regexec(regex, buffer, 0, NULL, 0)) {
1427
 
                    mprintf("[%s BYTECODE] %s", dbname, buffer);
1428
 
                }
1429
 
            } else {
1430
 
                *pt = 0;
1431
 
                mprintf("%s\n", buffer);
1432
 
            }
1433
 
        }
1434
 
    }
1435
 
    fclose(fh);
1436
 
    free(buffer);
1437
 
    return 0;
1438
 
}
1439
 
 
1440
 
static int listsigs(const struct optstruct *opts, int mode)
1441
 
{
1442
 
        int ret;
1443
 
        const char *name;
1444
 
        char *dbdir;
1445
 
        STATBUF sb;
1446
 
        regex_t reg;
1447
 
        const char *localdbdir = NULL;
1448
 
 
1449
 
    if(optget(opts, "datadir")->active)
1450
 
        localdbdir = optget(opts, "datadir")->strarg;
1451
 
 
1452
 
    if(mode == 0) {
1453
 
        name = optget(opts, "list-sigs")->strarg;
1454
 
        if(access(name, R_OK) && localdbdir)
1455
 
            name = localdbdir;
1456
 
        if(CLAMSTAT(name, &sb) == -1) {
1457
 
            mprintf("--list-sigs: Can't get status of %s\n", name);
1458
 
            return -1;
1459
 
        }
1460
 
 
1461
 
        mprintf_stdout = 1;
1462
 
        if(S_ISDIR(sb.st_mode)) {
1463
 
            if(!strcmp(name, DATADIR)) {
1464
 
                dbdir = freshdbdir();
1465
 
                ret = listdir(localdbdir ? localdbdir : dbdir, NULL);
1466
 
                free(dbdir);
1467
 
            } else {
1468
 
                ret = listdir(name, NULL);
1469
 
            }
1470
 
        } else {
1471
 
            ret = listdb(name, NULL);
1472
 
        }
1473
 
 
1474
 
    } else {
1475
 
        if(cli_regcomp(&reg, optget(opts, "find-sigs")->strarg, REG_EXTENDED | REG_NOSUB) != 0) {
1476
 
            mprintf("--find-sigs: Can't compile regex\n");
1477
 
            return -1;
1478
 
        }
1479
 
        mprintf_stdout = 1;
1480
 
        dbdir = freshdbdir();
1481
 
        ret = listdir(localdbdir ? localdbdir : dbdir, &reg);
1482
 
        free(dbdir);
1483
 
        cli_regfree(&reg);
1484
 
    }
1485
 
 
1486
 
    return ret;
1487
 
}
1488
 
 
1489
 
static int vbadump(const struct optstruct *opts)
1490
 
{
1491
 
        int fd, hex_output;
1492
 
        char *dir;
1493
 
        const char *pt;
1494
 
        struct uniq *vba = NULL;
1495
 
        cli_ctx *ctx;
1496
 
 
1497
 
 
1498
 
    if(optget(opts, "vba-hex")->enabled) {
1499
 
        hex_output = 1;
1500
 
        pt = optget(opts, "vba-hex")->strarg;
1501
 
    } else {
1502
 
        hex_output = 0;
1503
 
        pt = optget(opts, "vba")->strarg;
1504
 
    }
1505
 
 
1506
 
    if((fd = open(pt, O_RDONLY|O_BINARY)) == -1) {
1507
 
        mprintf("!vbadump: Can't open file %s\n", pt);
1508
 
        return -1;
1509
 
    }
1510
 
 
1511
 
    /* generate the temporary directory */
1512
 
    if(!(dir = cli_gentemp(NULL))) {
1513
 
        mprintf("!vbadump: Can't generate temporary name\n");
1514
 
        close(fd);
1515
 
        return -1;
1516
 
    }
1517
 
 
1518
 
    if(mkdir(dir, 0700)) {
1519
 
        mprintf("!vbadump: Can't create temporary directory %s\n", dir);
1520
 
        free(dir);
1521
 
        close(fd);
1522
 
        return -1;
1523
 
    }
1524
 
    if(!(ctx = convenience_ctx(fd))) {
1525
 
        close(fd);
1526
 
    free(dir);
1527
 
        return -1;
1528
 
    }
1529
 
    if(cli_ole2_extract(dir, ctx, &vba)) {
1530
 
        destroy_ctx(-1, ctx);
1531
 
        cli_rmdirs(dir);
1532
 
        free(dir);
1533
 
        return -1;
1534
 
    }
1535
 
    destroy_ctx(-1, ctx);
1536
 
    if (vba) 
1537
 
      sigtool_vba_scandir(dir, hex_output, vba);
1538
 
    cli_rmdirs(dir);
1539
 
    free(dir);
1540
 
    return 0;
1541
 
}
1542
 
 
1543
 
static int comparesha(const char *diff)
1544
 
{
1545
 
        char info[32], buff[FILEBUFF], *sha, *pt, *name;
1546
 
        const char *tokens[3];
1547
 
        FILE *fh;
1548
 
        int ret = 0, tokens_count;
1549
 
 
1550
 
    name = strdup(diff);
1551
 
    if(!name) {
1552
 
        mprintf("!verifydiff: strdup() failed\n");
1553
 
        return -1;
1554
 
    }
1555
 
    if(!(pt = strrchr(name, '-')) || !isdigit(pt[1])) {
1556
 
        mprintf("!verifydiff: Invalid diff name\n");
1557
 
        free(name);
1558
 
        return -1;
1559
 
    }
1560
 
    *pt = 0;
1561
 
    if((pt = strrchr(name, *PATHSEP)))
1562
 
        pt++;
1563
 
    else
1564
 
        pt = name;
1565
 
 
1566
 
    snprintf(info, sizeof(info), "%s.info", pt);
1567
 
    free(name);
1568
 
 
1569
 
    if(!(fh = fopen(info, "rb"))) {
1570
 
        mprintf("!verifydiff: Can't open %s\n", info);
1571
 
        return -1;
1572
 
    }
1573
 
 
1574
 
    if(!fgets(buff, sizeof(buff), fh) || strncmp(buff, "ClamAV-VDB", 10)) {
1575
 
        mprintf("!verifydiff: Incorrect info file %s\n", info);
1576
 
        fclose(fh);
1577
 
        return -1;
1578
 
    }
1579
 
 
1580
 
    while(fgets(buff, sizeof(buff), fh)) {
1581
 
        cli_chomp(buff);
1582
 
        tokens_count = cli_strtokenize(buff, ':', 3, tokens);
1583
 
        if(tokens_count != 3) {
1584
 
            if(!strcmp(tokens[0], "DSIG"))
1585
 
                continue;
1586
 
            mprintf("!verifydiff: Incorrect format of %s\n", info);
1587
 
            ret = -1;
1588
 
            break;
1589
 
        }
1590
 
        if(!(sha = sha256file(tokens[0], NULL))) {
1591
 
            mprintf("!verifydiff: Can't generate SHA256 for %s\n", buff);
1592
 
            ret = -1;
1593
 
            break;
1594
 
        }
1595
 
        if(strcmp(sha, tokens[2])) {
1596
 
            mprintf("!verifydiff: %s has incorrect checksum\n", buff);
1597
 
            ret = -1;
1598
 
            free(sha);
1599
 
            break;
1600
 
        }
1601
 
        free(sha);
1602
 
    }
1603
 
 
1604
 
    fclose(fh);
1605
 
    return ret;
1606
 
}
1607
 
 
1608
 
static int rundiff(const struct optstruct *opts)
1609
 
{
1610
 
        int fd, ret;
1611
 
        unsigned short mode;
1612
 
        const char *diff;
1613
 
 
1614
 
 
1615
 
    diff = optget(opts, "run-cdiff")->strarg;
1616
 
    if(strstr(diff, ".cdiff")) {
1617
 
        mode = 1;
1618
 
    } else if(strstr(diff, ".script")) {
1619
 
        mode = 0;
1620
 
    } else {
1621
 
        mprintf("!rundiff: Incorrect file name (no .cdiff/.script extension)\n");
1622
 
        return -1;
1623
 
    }
1624
 
 
1625
 
    if((fd = open(diff, O_RDONLY | O_BINARY)) == -1) {
1626
 
        mprintf("!rundiff: Can't open file %s\n", diff);
1627
 
        return -1;
1628
 
    }
1629
 
 
1630
 
    ret = cdiff_apply(fd, mode);
1631
 
    close(fd);
1632
 
 
1633
 
    if(!ret)
1634
 
        ret = comparesha(diff);
1635
 
 
1636
 
    return ret;
1637
 
}
1638
 
 
1639
 
static int maxlinelen(const char *file)
1640
 
{
1641
 
        int fd, bytes, n = 0, nmax = 0, i;
1642
 
        char buff[512];
1643
 
 
1644
 
    if((fd = open(file, O_RDONLY)) == -1) {
1645
 
        mprintf("!maxlinelen: Can't open file %s\n", file);
1646
 
        return -1;
1647
 
    }
1648
 
 
1649
 
    while((bytes = read(fd, buff, 512)) > 0) {
1650
 
        for(i = 0; i < bytes; i++, ++n) {
1651
 
            if(buff[i] == '\n') {
1652
 
                if(n > nmax)
1653
 
                    nmax = n;
1654
 
                n = 0;
1655
 
            }
1656
 
        }
1657
 
    }
1658
 
 
1659
 
    if(bytes == -1) {
1660
 
        mprintf("!maxlinelen: Can't read file %s\n", file);
1661
 
        close(fd);
1662
 
        return -1;
1663
 
    }
1664
 
    
1665
 
    close(fd);
1666
 
    return nmax + 1;
1667
 
}
1668
 
 
1669
 
static int compare(const char *oldpath, const char *newpath, FILE *diff)
1670
 
{
1671
 
        FILE *old, *new;
1672
 
        char *obuff, *nbuff, *tbuff, *pt, *omd5, *nmd5;
1673
 
        unsigned int oline = 0, tline, found, i, badxchg = 0;
1674
 
        int l1 = 0, l2;
1675
 
        long opos;
1676
 
 
1677
 
    if(!access(oldpath, R_OK) && (omd5 = cli_hashfile(oldpath, 1))) {
1678
 
        if(!(nmd5 = cli_hashfile(newpath, 1))) {
1679
 
            mprintf("!compare: Can't get MD5 checksum of %s\n", newpath);
1680
 
            free(omd5);
1681
 
            return -1;
1682
 
        }
1683
 
        if(!strcmp(omd5, nmd5)) {
1684
 
            free(omd5);
1685
 
            free(nmd5);
1686
 
            return 0;
1687
 
        }
1688
 
        free(omd5);
1689
 
        free(nmd5);
1690
 
        l1 = maxlinelen(oldpath);
1691
 
    }
1692
 
 
1693
 
    l2 = maxlinelen(newpath);
1694
 
    if(l1 == -1 || l2 == -1)
1695
 
        return -1;
1696
 
    l1 = MAX(l1, l2) + 1;
1697
 
 
1698
 
    obuff = malloc(l1);
1699
 
    if(!obuff) {
1700
 
        mprintf("!compare: Can't allocate memory for 'obuff'\n");
1701
 
        return -1;
1702
 
    }
1703
 
    nbuff = malloc(l1);
1704
 
    if(!nbuff) {
1705
 
        mprintf("!compare: Can't allocate memory for 'nbuff'\n");
1706
 
        free(obuff);
1707
 
        return -1;
1708
 
    }
1709
 
    tbuff = malloc(l1);
1710
 
    if(!tbuff) {
1711
 
        mprintf("!compare: Can't allocate memory for 'tbuff'\n");
1712
 
        free(obuff);
1713
 
        free(nbuff);
1714
 
        return -1;
1715
 
    }
1716
 
 
1717
 
    if(l1 > CLI_DEFAULT_LSIG_BUFSIZE)
1718
 
        fprintf(diff, "#LSIZE %u\n", l1 + 32);
1719
 
 
1720
 
    fprintf(diff, "OPEN %s\n", newpath);
1721
 
 
1722
 
    if(!(new = fopen(newpath, "rb"))) {
1723
 
        mprintf("!compare: Can't open file %s for reading\n", newpath);
1724
 
        free(obuff);
1725
 
        free(nbuff);
1726
 
        free(tbuff);
1727
 
        return -1;
1728
 
    }
1729
 
    old = fopen(oldpath, "rb");
1730
 
 
1731
 
    while(fgets(nbuff, l1, new)) {
1732
 
        i = strlen(nbuff);
1733
 
        if(i >= 2 && (nbuff[i - 1] == '\r' || (nbuff[i - 1] == '\n' && nbuff[i - 2] == '\r'))) {
1734
 
            mprintf("!compare: New %s file contains lines terminated with CRLF or CR\n", newpath);
1735
 
            if(old)
1736
 
                fclose(old);
1737
 
            fclose(new);
1738
 
            free(obuff);
1739
 
            free(nbuff);
1740
 
            free(tbuff);
1741
 
            return -1;
1742
 
        }
1743
 
        cli_chomp(nbuff);
1744
 
        if(!old) {
1745
 
            fprintf(diff, "ADD %s\n", nbuff);
1746
 
        } else {
1747
 
            if(fgets(obuff, l1, old)) {
1748
 
                oline++;
1749
 
                cli_chomp(obuff);
1750
 
                if(!strcmp(nbuff, obuff)) {
1751
 
                    continue;
1752
 
                } else {
1753
 
                    tline = 0;
1754
 
                    found = 0;
1755
 
                    opos = ftell(old);
1756
 
                    while(fgets(tbuff, l1, old)) {
1757
 
                        tline++;
1758
 
                        cli_chomp(tbuff);
1759
 
 
1760
 
                        if(tline > MAX_DEL_LOOKAHEAD)
1761
 
                            break;
1762
 
 
1763
 
                        if(!strcmp(tbuff, nbuff)) {
1764
 
                            found = 1;
1765
 
                            break;
1766
 
                        }
1767
 
                    }
1768
 
                    fseek(old, opos, SEEK_SET);
1769
 
 
1770
 
                    if(found) {
1771
 
                        strncpy(tbuff, obuff, l1);
1772
 
                        tbuff[l1-1]='\0';
1773
 
                        for(i = 0; i < tline; i++) {
1774
 
                            tbuff[MIN(16, l1-1)] = 0;
1775
 
                            if((pt = strchr(tbuff, ' ')))
1776
 
                                *pt = 0;
1777
 
                            fprintf(diff, "DEL %u %s\n", oline + i, tbuff);
1778
 
                            if(!fgets(tbuff, l1, old))
1779
 
                                break;
1780
 
                        }
1781
 
                        oline += tline;
1782
 
 
1783
 
                    } else {
1784
 
                        if(!*obuff || *obuff == ' ') {
1785
 
                            badxchg = 1;
1786
 
                            break;
1787
 
                        }
1788
 
                        obuff[MIN(16, l1-1)] = 0;
1789
 
                        if((pt = strchr(obuff, ' ')))
1790
 
                            *pt = 0;
1791
 
                        fprintf(diff, "XCHG %u %s %s\n", oline, obuff, nbuff);
1792
 
                    }
1793
 
                }
1794
 
            } else {
1795
 
                fclose(old);
1796
 
                old = NULL;
1797
 
                fprintf(diff, "ADD %s\n", nbuff);
1798
 
            }
1799
 
        }
1800
 
    }
1801
 
 
1802
 
    if(old) {
1803
 
        if(!badxchg) {
1804
 
            while(fgets(obuff, l1, old)) {
1805
 
                oline++;
1806
 
                cli_chomp(obuff);
1807
 
                obuff[MIN(16, l1-1)] = 0;
1808
 
                if((pt = strchr(obuff, ' ')))
1809
 
                    *pt = 0;
1810
 
                fprintf(diff, "DEL %u %s\n", oline, obuff);
1811
 
            }
1812
 
        }
1813
 
        fclose(old);
1814
 
    }
1815
 
    fprintf(diff, "CLOSE\n");
1816
 
    free(obuff);
1817
 
    free(tbuff);
1818
 
    if(badxchg) {
1819
 
        fprintf(diff, "UNLINK %s\n", newpath);
1820
 
        fprintf(diff, "OPEN %s\n", newpath);
1821
 
        rewind(new);
1822
 
        while(fgets(nbuff, l1, new)) {
1823
 
            cli_chomp(nbuff);
1824
 
            fprintf(diff, "ADD %s\n", nbuff);
1825
 
        }
1826
 
        fprintf(diff, "CLOSE\n");
1827
 
    }
1828
 
    free(nbuff);
1829
 
    fclose(new);
1830
 
    return 0;
1831
 
}
1832
 
 
1833
 
static int compareone(const struct optstruct *opts)
1834
 
{
1835
 
    if(!opts->filename) {
1836
 
        mprintf("!makediff: --compare requires two arguments\n");
1837
 
        return -1;
1838
 
    }
1839
 
    return compare(optget(opts,"compare")->strarg, opts->filename[0], stdout);
1840
 
}
1841
 
 
1842
 
static int dircopy(const char *src, const char *dest)
1843
 
{
1844
 
        DIR *dd;
1845
 
        struct dirent *dent;
1846
 
        STATBUF sb;
1847
 
        char spath[512], dpath[512];
1848
 
 
1849
 
 
1850
 
    if(CLAMSTAT(dest, &sb) == -1) {
1851
 
        if(mkdir(dest, 0755)) {
1852
 
            /* mprintf("!dircopy: Can't create temporary directory %s\n", dest); */
1853
 
            return -1;
1854
 
        }
1855
 
    }
1856
 
 
1857
 
    if((dd = opendir(src)) == NULL) {
1858
 
        /* mprintf("!dircopy: Can't open directory %s\n", src); */
1859
 
        return -1;
1860
 
    }
1861
 
 
1862
 
    while((dent = readdir(dd))) {
1863
 
        if(dent->d_ino)
1864
 
        {
1865
 
            if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1866
 
                continue;
1867
 
 
1868
 
            snprintf(spath, sizeof(spath), "%s"PATHSEP"%s", src, dent->d_name);
1869
 
            snprintf(dpath, sizeof(dpath), "%s"PATHSEP"%s", dest, dent->d_name);
1870
 
 
1871
 
            if(filecopy(spath, dpath) == -1) {
1872
 
                /* mprintf("!dircopy: Can't copy %s to %s\n", spath, dpath); */
1873
 
                cli_rmdirs(dest);
1874
 
                closedir(dd);
1875
 
                return -1;
1876
 
            }
1877
 
        }
1878
 
    }
1879
 
 
1880
 
    closedir(dd);
1881
 
    return 0;
1882
 
}
1883
 
 
1884
 
static int verifydiff(const char *diff, const char *cvd, const char *incdir)
1885
 
{
1886
 
        char *tempdir, cwd[512];
1887
 
        int ret = 0, fd;
1888
 
        unsigned short mode;
1889
 
 
1890
 
 
1891
 
    if(strstr(diff, ".cdiff")) {
1892
 
        mode = 1;
1893
 
    } else if(strstr(diff, ".script")) {
1894
 
        mode = 0;
1895
 
    } else {
1896
 
        mprintf("!verifydiff: Incorrect file name (no .cdiff/.script extension)\n");
1897
 
        return -1;
1898
 
    }
1899
 
 
1900
 
    tempdir = cli_gentemp(NULL);
1901
 
    if(!tempdir) {
1902
 
        mprintf("!verifydiff: Can't generate temporary name for tempdir\n");
1903
 
        return -1;
1904
 
    }
1905
 
 
1906
 
    if(mkdir(tempdir, 0700) == -1) {
1907
 
        mprintf("!verifydiff: Can't create directory %s\n", tempdir);
1908
 
        free(tempdir);
1909
 
        return -1;
1910
 
    }
1911
 
 
1912
 
    if(cvd) {
1913
 
        if(cli_cvdunpack(cvd, tempdir) == -1) {
1914
 
            mprintf("!verifydiff: Can't unpack CVD file %s\n", cvd);
1915
 
            cli_rmdirs(tempdir);
1916
 
            free(tempdir);
1917
 
            return -1;
1918
 
        }
1919
 
    } else {
1920
 
        if(dircopy(incdir, tempdir) == -1) {
1921
 
            mprintf("!verifydiff: Can't copy dir %s to %s\n", incdir, tempdir);
1922
 
            cli_rmdirs(tempdir);
1923
 
            free(tempdir);
1924
 
            return -1;
1925
 
        }
1926
 
    }
1927
 
 
1928
 
    if(!getcwd(cwd, sizeof(cwd))) {
1929
 
        mprintf("!verifydiff: getcwd() failed\n");
1930
 
        cli_rmdirs(tempdir);
1931
 
        free(tempdir);
1932
 
        return -1;
1933
 
    }
1934
 
 
1935
 
    if((fd = open(diff, O_RDONLY | O_BINARY)) == -1) {
1936
 
        mprintf("!verifydiff: Can't open diff file %s\n", diff);
1937
 
        cli_rmdirs(tempdir);
1938
 
        free(tempdir);
1939
 
        return -1;
1940
 
    }
1941
 
 
1942
 
    if(chdir(tempdir) == -1) {
1943
 
        mprintf("!verifydiff: Can't chdir to %s\n", tempdir);
1944
 
        cli_rmdirs(tempdir);
1945
 
        free(tempdir);
1946
 
        close(fd);
1947
 
        return -1;
1948
 
    }
1949
 
 
1950
 
    if(cdiff_apply(fd, mode) == -1) {
1951
 
        mprintf("!verifydiff: Can't apply %s\n", diff);
1952
 
        if(chdir(cwd) == -1)
1953
 
            mprintf("^verifydiff: Can't chdir to %s\n", cwd);
1954
 
        cli_rmdirs(tempdir);
1955
 
        free(tempdir);
1956
 
        close(fd);
1957
 
        return -1;
1958
 
    }
1959
 
    close(fd);
1960
 
 
1961
 
    ret = comparesha(diff);
1962
 
 
1963
 
    if(chdir(cwd) == -1)
1964
 
        mprintf("^verifydiff: Can't chdir to %s\n", cwd);
1965
 
    cli_rmdirs(tempdir);
1966
 
    free(tempdir);
1967
 
 
1968
 
    if(!ret) {
1969
 
        if(cvd)
1970
 
            mprintf("Verification: %s correctly applies to %s\n", diff, cvd);
1971
 
        else
1972
 
            mprintf("Verification: %s correctly applies to the previous version\n", diff);
1973
 
    }
1974
 
 
1975
 
    return ret;
1976
 
}
1977
 
 
1978
 
static void matchsig(const char *sig, const char *offset, int fd)
1979
 
{
1980
 
        struct cl_engine *engine;
1981
 
        struct cli_ac_result *acres = NULL, *res;
1982
 
        STATBUF sb;
1983
 
        unsigned int matches = 0;
1984
 
        cli_ctx ctx;
1985
 
        int ret;
1986
 
 
1987
 
    if(!(engine = cl_engine_new())) {
1988
 
        mprintf("!matchsig: Can't create new engine\n");
1989
 
        return;
1990
 
    }
1991
 
    cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
1992
 
 
1993
 
    if(cli_initroots(engine, 0) != CL_SUCCESS) {
1994
 
        mprintf("!matchsig: cli_initroots() failed\n");
1995
 
        cl_engine_free(engine);
1996
 
        return;
1997
 
    }
1998
 
 
1999
 
    if(cli_parse_add(engine->root[0], "test", sig, 0, 0, "*", 0, NULL, 0) != CL_SUCCESS) {
2000
 
        mprintf("!matchsig: Can't parse signature\n");
2001
 
        cl_engine_free(engine);
2002
 
        return;
2003
 
    }
2004
 
 
2005
 
    if(cl_engine_compile(engine) != CL_SUCCESS) {
2006
 
        mprintf("!matchsig: Can't compile engine\n");
2007
 
        cl_engine_free(engine);
2008
 
        return;
2009
 
    }
2010
 
    memset(&ctx, '\0', sizeof(cli_ctx));
2011
 
    ctx.engine = engine;
2012
 
    ctx.options = CL_SCAN_STDOPT;
2013
 
    ctx.container_type = CL_TYPE_ANY;
2014
 
    ctx.dconf = (struct cli_dconf *) engine->dconf;
2015
 
    ctx.fmap = calloc(sizeof(fmap_t *), 1);
2016
 
    if(!ctx.fmap) {
2017
 
        cl_engine_free(engine);
2018
 
        return;
2019
 
    }
2020
 
    lseek(fd, 0, SEEK_SET);
2021
 
    FSTAT(fd, &sb);
2022
 
    if(!(*ctx.fmap = fmap(fd, 0, sb.st_size))) {
2023
 
        free(ctx.fmap);
2024
 
        cl_engine_free(engine);
2025
 
        return;
2026
 
    }
2027
 
    ret = cli_fmap_scandesc(&ctx, 0, 0, NULL, AC_SCAN_VIR, &acres, NULL);
2028
 
    res = acres;
2029
 
    while(res) {
2030
 
        matches++;
2031
 
        res = res->next;
2032
 
    }
2033
 
    if(matches) {
2034
 
        /* TODO: check offsets automatically */
2035
 
        mprintf("MATCH: ** YES%s ** (%u %s:", offset ? "/CHECK OFFSET" : "",  matches, matches > 1 ? "matches at offsets" : "match at offset");
2036
 
        res = acres;
2037
 
        while(res) {
2038
 
            mprintf(" %u", (unsigned int) res->offset);
2039
 
            res = res->next;
2040
 
        }
2041
 
        mprintf(")\n");
2042
 
    } else {
2043
 
        mprintf("MATCH: ** NO **\n");
2044
 
    }
2045
 
    while(acres) {
2046
 
        res = acres;
2047
 
        acres = acres->next;
2048
 
        free(res);
2049
 
    }
2050
 
    free(ctx.fmap);
2051
 
    cl_engine_free(engine);
2052
 
}
2053
 
 
2054
 
static char *decodehexstr(const char *hex, unsigned int *dlen)
2055
 
{
2056
 
        uint16_t *str16;
2057
 
        char *decoded;
2058
 
        unsigned int i, p = 0, wildcard = 0, len = strlen(hex)/2;
2059
 
 
2060
 
    str16 = cli_hex2ui(hex);
2061
 
    if(!str16)
2062
 
        return NULL;
2063
 
 
2064
 
    for(i = 0; i < len; i++)
2065
 
        if(str16[i] & CLI_MATCH_WILDCARD)
2066
 
            wildcard++;
2067
 
 
2068
 
    decoded = calloc(len + 1 + wildcard * 32, sizeof(char));
2069
 
    if(!decoded) {
2070
 
        free(str16);
2071
 
        mprintf("!decodehexstr: Can't allocate memory for decoded\n");
2072
 
        return NULL;
2073
 
    }
2074
 
 
2075
 
    for(i = 0; i < len; i++) {
2076
 
        if(str16[i] & CLI_MATCH_WILDCARD) {
2077
 
            switch(str16[i] & CLI_MATCH_WILDCARD) {
2078
 
                case CLI_MATCH_IGNORE:
2079
 
                    p += sprintf(decoded + p, "{WILDCARD_IGNORE}");
2080
 
                    break;
2081
 
 
2082
 
                case CLI_MATCH_NIBBLE_HIGH:
2083
 
                    p += sprintf(decoded + p, "{WILDCARD_NIBBLE_HIGH:0x%x}", str16[i] & 0x00f0);
2084
 
                    break;
2085
 
 
2086
 
                case CLI_MATCH_NIBBLE_LOW:
2087
 
                    p += sprintf(decoded + p, "{WILDCARD_NIBBLE_LOW:0x%x}", str16[i] & 0x000f);
2088
 
                    break;
2089
 
 
2090
 
                default:
2091
 
                    mprintf("!decodehexstr: Unknown wildcard (0x%x@%u)\n", str16[i] & CLI_MATCH_WILDCARD, i);
2092
 
                    free(decoded);
2093
 
                    free(str16);
2094
 
                    return NULL;
2095
 
            }
2096
 
        } else {
2097
 
            decoded[p] = str16[i];
2098
 
            p++;
2099
 
        }
2100
 
    }
2101
 
 
2102
 
    if(dlen)
2103
 
        *dlen = p;
2104
 
    free(str16);
2105
 
    return decoded;
2106
 
}
2107
 
 
2108
 
static char *decodehexspecial(const char *hex, unsigned int *dlen)
2109
 
{
2110
 
        char *pt, *start, *hexcpy, *decoded, *h, *c;
2111
 
        unsigned int i, len = 0, hlen, negative, altnum, alttype;
2112
 
        char *buff;
2113
 
 
2114
 
    
2115
 
    hexcpy = NULL;
2116
 
    buff = NULL;
2117
 
 
2118
 
    hexcpy = strdup(hex);
2119
 
    if(!hexcpy) {
2120
 
        mprintf("!decodehexspecial: strdup(hex) failed\n");
2121
 
        return NULL;
2122
 
    }
2123
 
    pt = strchr(hexcpy, '(');
2124
 
    if(!pt) {
2125
 
        free(hexcpy);
2126
 
        return decodehexstr(hex, dlen);
2127
 
    } else {
2128
 
        buff = calloc(strlen(hex) + 512, sizeof(char));
2129
 
        if(!buff) {
2130
 
            mprintf("!decodehexspecial: Can't allocate memory for buff\n");
2131
 
            free(hexcpy);
2132
 
            return NULL;
2133
 
        }
2134
 
        start = hexcpy;
2135
 
        do {
2136
 
            negative = 0;
2137
 
            *pt++ = 0;
2138
 
            if(!start) {
2139
 
                mprintf("!decodehexspecial: Unexpected EOL\n");
2140
 
                free(hexcpy);
2141
 
                free(buff);
2142
 
                return NULL;
2143
 
            }
2144
 
            if(pt >= hexcpy + 2) {
2145
 
                if(pt[-2] == '!') {
2146
 
                    negative = 1;
2147
 
                    pt[-2] = 0;
2148
 
                }
2149
 
            }
2150
 
            if(!(decoded = decodehexstr(start, &hlen))) {
2151
 
                mprintf("!Decoding failed (1): %s\n", pt);
2152
 
                free(hexcpy);
2153
 
                free(buff);
2154
 
                return NULL;
2155
 
            }
2156
 
            memcpy(&buff[len], decoded, hlen);
2157
 
            len += hlen;
2158
 
            free(decoded);
2159
 
 
2160
 
            if(!(start = strchr(pt, ')'))) {
2161
 
                mprintf("!decodehexspecial: Missing closing parethesis\n");
2162
 
                free(hexcpy);
2163
 
                free(buff);
2164
 
                return NULL;
2165
 
            }
2166
 
 
2167
 
            *start++ = 0;
2168
 
            if(!strlen(pt)) {
2169
 
                mprintf("!decodehexspecial: Empty block\n");
2170
 
                free(hexcpy);
2171
 
                free(buff);
2172
 
                return NULL;
2173
 
            }
2174
 
 
2175
 
            if(!strcmp(pt, "B")) {
2176
 
                if(!*start) {
2177
 
                    if(negative)
2178
 
                        len += sprintf(buff + len, "{NOT_BOUNDARY_RIGHT}");
2179
 
                    else
2180
 
                        len += sprintf(buff + len, "{BOUNDARY_RIGHT}");
2181
 
                    continue;
2182
 
                } else if(pt - 1 == hexcpy) {
2183
 
                    if(negative)
2184
 
                        len += sprintf(buff + len, "{NOT_BOUNDARY_LEFT}");
2185
 
                    else
2186
 
                        len += sprintf(buff + len, "{BOUNDARY_LEFT}");
2187
 
                    continue;
2188
 
                }
2189
 
            } else if(!strcmp(pt, "L")) {
2190
 
                if(!*start) {
2191
 
                    if(negative)
2192
 
                        len += sprintf(buff + len, "{NOT_LINE_MARKER_RIGHT}");
2193
 
                    else
2194
 
                        len += sprintf(buff + len, "{LINE_MARKER_RIGHT}");
2195
 
                    continue;
2196
 
                } else if(pt - 1 == hexcpy) {
2197
 
                    if(negative)
2198
 
                        len += sprintf(buff + len, "{NOT_LINE_MARKER_LEFT}");
2199
 
                    else
2200
 
                        len += sprintf(buff + len, "{LINE_MARKER_LEFT}");
2201
 
                    continue;
2202
 
                }
2203
 
            } else {
2204
 
                altnum = 0;
2205
 
                for(i = 0; i < strlen(pt); i++)
2206
 
                    if(pt[i] == '|')
2207
 
                        altnum++;
2208
 
 
2209
 
                if(!altnum) {
2210
 
                    mprintf("!decodehexspecial: Empty block\n");
2211
 
                    free(hexcpy);
2212
 
                    free(buff);
2213
 
                    return NULL;
2214
 
                }
2215
 
                altnum++;
2216
 
 
2217
 
                if(3 * altnum - 1 == (uint16_t) strlen(pt)) {
2218
 
                    alttype = 1; /* char */
2219
 
                    if(negative)
2220
 
                        len += sprintf(buff + len, "{EXCLUDING_CHAR_ALTERNATIVE:");
2221
 
                    else
2222
 
                        len += sprintf(buff + len, "{CHAR_ALTERNATIVE:");
2223
 
                } else {
2224
 
                    alttype = 2; /* str */
2225
 
                    if(negative)
2226
 
                        len += sprintf(buff + len, "{EXCLUDING_STRING_ALTERNATIVE:");
2227
 
                    else
2228
 
                        len += sprintf(buff + len, "{STRING_ALTERNATIVE:");
2229
 
                }
2230
 
 
2231
 
                for(i = 0; i < altnum; i++) {
2232
 
                    if(!(h = cli_strtok(pt, i, "|"))) {
2233
 
                        free(hexcpy);
2234
 
                        free(buff);
2235
 
                        return NULL;
2236
 
                    }
2237
 
 
2238
 
                    if(!(c = cli_hex2str(h))) {
2239
 
                        free(h);
2240
 
                        free(hexcpy);
2241
 
                        free(buff);
2242
 
                        return NULL;
2243
 
                    }
2244
 
 
2245
 
                    if(alttype == 1) {
2246
 
                        buff[len++] = *c;
2247
 
                    } else {
2248
 
                        memcpy(&buff[len], c, strlen(h) / 2);
2249
 
                        len += strlen(h) / 2;
2250
 
                    }
2251
 
                    if(i + 1 != altnum)
2252
 
                        buff[len++] = '|';
2253
 
 
2254
 
                    free(h);
2255
 
                    free(c);    
2256
 
                }
2257
 
                buff[len++] = '}';
2258
 
            }
2259
 
        } while((pt = strchr(start, '(')));
2260
 
 
2261
 
        if(start) {
2262
 
            if(!(decoded = decodehexstr(start, &hlen))) {
2263
 
                mprintf("!Decoding failed (2)\n");
2264
 
                free(buff);
2265
 
                free(hexcpy);
2266
 
                return NULL;
2267
 
            }
2268
 
            memcpy(&buff[len], decoded, hlen);
2269
 
            len += hlen;
2270
 
            free(decoded);
2271
 
        }
2272
 
    }
2273
 
    free(hexcpy);
2274
 
    if(dlen)
2275
 
        *dlen = len;
2276
 
    return buff;
2277
 
}
2278
 
 
2279
 
static int decodehex(const char *hexsig)
2280
 
{
2281
 
        char *pt, *hexcpy, *start, *n, *decoded;
2282
 
        int asterisk = 0;
2283
 
        unsigned int i, j, hexlen, dlen, parts = 0, bw;
2284
 
        int mindist = 0, maxdist = 0, error = 0;
2285
 
 
2286
 
 
2287
 
    hexlen = strlen(hexsig);
2288
 
    if(strchr(hexsig, '{') || strchr(hexsig, '[')) {
2289
 
        if(!(hexcpy = strdup(hexsig)))
2290
 
            return -1;
2291
 
 
2292
 
        for(i = 0; i < hexlen; i++)
2293
 
            if(hexsig[i] == '{' || hexsig[i] == '[' || hexsig[i] == '*')
2294
 
                parts++;
2295
 
 
2296
 
        if(parts)
2297
 
            parts++;
2298
 
 
2299
 
        start = pt = hexcpy;
2300
 
        for(i = 1; i <= parts; i++) {
2301
 
            if(i != parts) {
2302
 
                for(j = 0; j < strlen(start); j++) {
2303
 
                    if(start[j] == '{' || start[j] == '[') {
2304
 
                        asterisk = 0;
2305
 
                        pt = start + j;
2306
 
                        break;
2307
 
                    }
2308
 
                    if(start[j] == '*') {
2309
 
                        asterisk = 1;
2310
 
                        pt = start + j;
2311
 
                        break;
2312
 
                    }
2313
 
                }
2314
 
                *pt++ = 0;
2315
 
            }
2316
 
 
2317
 
            if(mindist && maxdist) {
2318
 
                if(mindist == maxdist)
2319
 
                    mprintf("{WILDCARD_ANY_STRING(LENGTH==%u)}", mindist);
2320
 
                else
2321
 
                    mprintf("{WILDCARD_ANY_STRING(LENGTH>=%u&&<=%u)}", mindist, maxdist);
2322
 
            } else if(mindist)
2323
 
                mprintf("{WILDCARD_ANY_STRING(LENGTH>=%u)}", mindist);
2324
 
            else if(maxdist)
2325
 
                mprintf("{WILDCARD_ANY_STRING(LENGTH<=%u)}", maxdist);
2326
 
 
2327
 
            if(!(decoded = decodehexspecial(start, &dlen))) {
2328
 
                mprintf("!Decoding failed\n");
2329
 
                free(hexcpy);
2330
 
                return -1;
2331
 
            }
2332
 
            bw = write(1, decoded, dlen);
2333
 
            free(decoded);
2334
 
 
2335
 
            if(i == parts)
2336
 
                break;
2337
 
 
2338
 
            if(asterisk)
2339
 
                mprintf("{WILDCARD_ANY_STRING}");
2340
 
 
2341
 
            mindist = maxdist = 0;
2342
 
 
2343
 
            if(asterisk) {
2344
 
                start = pt;
2345
 
                continue;
2346
 
            }
2347
 
 
2348
 
            if(!(start = strchr(pt, '}')) && !(start = strchr(pt, ']'))) {
2349
 
                error = 1;
2350
 
                break;
2351
 
            }
2352
 
            *start++ = 0;
2353
 
 
2354
 
            if(!pt) {
2355
 
                error = 1;
2356
 
                break;
2357
 
            }
2358
 
 
2359
 
            if(!strchr(pt, '-')) {
2360
 
                if(!cli_isnumber(pt) || (mindist = maxdist = atoi(pt)) < 0) {
2361
 
                    error = 1;
2362
 
                    break;
2363
 
                }
2364
 
            } else {
2365
 
                if((n = cli_strtok(pt, 0, "-"))) {
2366
 
                    if(!cli_isnumber(n) || (mindist = atoi(n)) < 0) {
2367
 
                        error = 1;
2368
 
                        free(n);
2369
 
                        break;
2370
 
                    }
2371
 
                    free(n);
2372
 
                }
2373
 
 
2374
 
                if((n = cli_strtok(pt, 1, "-"))) {
2375
 
                    if(!cli_isnumber(n) || (maxdist = atoi(n)) < 0) {
2376
 
                        error = 1;
2377
 
                        free(n);
2378
 
                        break;
2379
 
                    }
2380
 
                    free(n);
2381
 
                }
2382
 
 
2383
 
                if((n = cli_strtok(pt, 2, "-"))) { /* strict check */
2384
 
                    error = 1;
2385
 
                    free(n);
2386
 
                    break;
2387
 
                }
2388
 
            }
2389
 
        }
2390
 
 
2391
 
        free(hexcpy);
2392
 
        if(error)
2393
 
            return -1;
2394
 
 
2395
 
    } else if(strchr(hexsig, '*')) {
2396
 
        for(i = 0; i < hexlen; i++)
2397
 
            if(hexsig[i] == '*')
2398
 
                parts++;
2399
 
 
2400
 
        if(parts)
2401
 
            parts++;
2402
 
 
2403
 
        for(i = 1; i <= parts; i++) {
2404
 
            if((pt = cli_strtok(hexsig, i - 1, "*")) == NULL) {
2405
 
                mprintf("!Can't extract part %u of partial signature\n", i);
2406
 
                return -1;
2407
 
            }
2408
 
            if(!(decoded = decodehexspecial(pt, &dlen))) {
2409
 
                mprintf("!Decoding failed\n");
2410
 
        free(pt);
2411
 
                return -1;
2412
 
            }
2413
 
            bw = write(1, decoded, dlen);
2414
 
            free(decoded);
2415
 
            if(i < parts)
2416
 
                mprintf("{WILDCARD_ANY_STRING}");
2417
 
            free(pt);
2418
 
        }
2419
 
 
2420
 
    } else {
2421
 
        if(!(decoded = decodehexspecial(hexsig, &dlen))) {
2422
 
            mprintf("!Decoding failed\n");
2423
 
            return -1;
2424
 
        }
2425
 
        bw = write(1, decoded, dlen);
2426
 
        free(decoded);
2427
 
    }
2428
 
 
2429
 
    mprintf("\n");
2430
 
    return 0;
2431
 
}
2432
 
 
2433
 
static int decodesig(char *sig, int fd)
2434
 
{
2435
 
        char *pt;
2436
 
        const char *tokens[68];
2437
 
        int tokens_count, subsigs, i, bc = 0;
2438
 
 
2439
 
    if(*sig == '[') {
2440
 
        if(!(pt = strchr(sig, ']'))) {
2441
 
            mprintf("!decodesig: Invalid input\n");
2442
 
            return -1;
2443
 
        }
2444
 
        sig = &pt[2];
2445
 
    }
2446
 
 
2447
 
    if(strchr(sig, ';')) { /* lsig */
2448
 
        tokens_count = cli_strtokenize(sig, ';', 67 + 1, (const char **) tokens);
2449
 
        if(tokens_count < 4) {
2450
 
            mprintf("!decodesig: Invalid or not supported signature format\n");
2451
 
            return -1;
2452
 
        }
2453
 
        mprintf("VIRUS NAME: %s\n", tokens[0]);
2454
 
        if(strlen(tokens[0]) && strstr(tokens[0], ".{") && tokens[0][strlen(tokens[0]) - 1] == '}')
2455
 
            bc = 1;
2456
 
        mprintf("TDB: %s\n", tokens[1]);
2457
 
        mprintf("LOGICAL EXPRESSION: %s\n", tokens[2]);
2458
 
        subsigs = cli_ac_chklsig(tokens[2], tokens[2] + strlen(tokens[2]), NULL, NULL, NULL, 1);
2459
 
        if(subsigs == -1) {
2460
 
            mprintf("!decodesig: Broken logical expression\n");
2461
 
            return -1;
2462
 
        }
2463
 
        subsigs++;
2464
 
        if(subsigs > 64) {
2465
 
            mprintf("!decodesig: Too many subsignatures\n");
2466
 
            return -1;
2467
 
        }
2468
 
        if(!bc && subsigs != tokens_count - 3) {
2469
 
            mprintf("!decodesig: The number of subsignatures (==%u) doesn't match the IDs in the logical expression (==%u)\n", tokens_count - 3, subsigs);
2470
 
            return -1;
2471
 
        }
2472
 
        for(i = 0; i < tokens_count - 3; i++) {
2473
 
            if(i >= subsigs)
2474
 
                mprintf(" * BYTECODE SUBSIG\n");
2475
 
            else
2476
 
                mprintf(" * SUBSIG ID %d\n", i);
2477
 
            if((pt = strchr(tokens[3 + i], ':'))) {
2478
 
                *pt++ = 0;
2479
 
                mprintf(" +-> OFFSET: %s\n", tokens[3 + i]);
2480
 
            } else {
2481
 
                mprintf(" +-> OFFSET: ANY\n");
2482
 
            }
2483
 
            if(fd == -1) {
2484
 
                mprintf(" +-> DECODED SUBSIGNATURE:\n");
2485
 
                decodehex(pt ? pt : tokens[3 + i]);
2486
 
            } else {
2487
 
                mprintf(" +-> ");
2488
 
                matchsig(pt ? pt : tokens[3 + i], pt ? tokens[3 + i] : NULL, fd);
2489
 
            }
2490
 
        }
2491
 
    } else if(strchr(sig, ':')) { /* ndb */
2492
 
        tokens_count = cli_strtokenize(sig, ':', 6 + 1, tokens);
2493
 
        if(tokens_count < 4 || tokens_count > 6) {
2494
 
            mprintf("!decodesig: Invalid or not supported signature format\n");
2495
 
            mprintf("TOKENS COUNT: %u\n", tokens_count);
2496
 
            return -1;
2497
 
        }
2498
 
        mprintf("VIRUS NAME: %s\n", tokens[0]);
2499
 
        if(tokens_count == 5)
2500
 
            mprintf("FUNCTIONALITY LEVEL: >=%s\n", tokens[4]);
2501
 
        else if(tokens_count == 6)
2502
 
            mprintf("FUNCTIONALITY LEVEL: %s..%s\n", tokens[4], tokens[5]);
2503
 
 
2504
 
        if(!cli_isnumber(tokens[1])) {
2505
 
            mprintf("!decodesig: Invalid target type\n");
2506
 
            return -1;
2507
 
        }
2508
 
        mprintf("TARGET TYPE: ");
2509
 
        switch(atoi(tokens[1])) {
2510
 
            case 0:
2511
 
                mprintf("ANY FILE\n");
2512
 
                break;
2513
 
            case 1:
2514
 
                mprintf("PE\n");
2515
 
                break;
2516
 
            case 2:
2517
 
                mprintf("OLE2\n");
2518
 
                break;
2519
 
            case 3:
2520
 
                mprintf("HTML\n");
2521
 
                break;
2522
 
            case 4:
2523
 
                mprintf("MAIL\n");
2524
 
                break;
2525
 
            case 5:
2526
 
                mprintf("GRAPHICS\n");
2527
 
                break;
2528
 
            case 6:
2529
 
                mprintf("ELF\n");
2530
 
                break;
2531
 
            case 7:
2532
 
                mprintf("NORMALIZED ASCII TEXT\n");
2533
 
                break;
2534
 
            case 8:
2535
 
                mprintf("DISASM DATA\n");
2536
 
                break;
2537
 
            case 9:
2538
 
                mprintf("MACHO\n");
2539
 
                break;
2540
 
            case 10:
2541
 
                mprintf("PDF\n");
2542
 
                break;
2543
 
            case 11:
2544
 
                mprintf("FLASH\n");
2545
 
                break;
2546
 
            case 12:
2547
 
                mprintf("JAVA CLASS\n");
2548
 
                break;
2549
 
            default:
2550
 
                mprintf("!decodesig: Invalid target type\n");
2551
 
                return -1;
2552
 
        }
2553
 
        mprintf("OFFSET: %s\n", tokens[2]);
2554
 
        if(fd == -1) {
2555
 
            mprintf("DECODED SIGNATURE:\n");
2556
 
            decodehex(tokens[3]);
2557
 
        } else {
2558
 
            matchsig(tokens[3], strcmp(tokens[2], "*") ? tokens[2] : NULL, fd);
2559
 
        }
2560
 
    } else if((pt = strchr(sig, '='))) {
2561
 
        *pt++ = 0;
2562
 
        mprintf("VIRUS NAME: %s\n", sig);
2563
 
        if(fd == -1) {
2564
 
            mprintf("DECODED SIGNATURE:\n");
2565
 
            decodehex(pt);
2566
 
        } else {
2567
 
            matchsig(pt, NULL, fd);
2568
 
        }
2569
 
    } else {
2570
 
        mprintf("decodesig: Not supported signature format\n");
2571
 
        return -1;
2572
 
    }
2573
 
 
2574
 
    return 0;
2575
 
}
2576
 
 
2577
 
static int decodesigs(void)
2578
 
{
2579
 
        char buffer[32769];
2580
 
 
2581
 
    fflush(stdin);
2582
 
    while(fgets(buffer, sizeof(buffer), stdin)) {
2583
 
        cli_chomp(buffer);
2584
 
        if(!strlen(buffer))
2585
 
            break;
2586
 
        if(decodesig(buffer, -1) == -1)
2587
 
            return -1;
2588
 
    }
2589
 
    return 0;
2590
 
}
2591
 
 
2592
 
static int testsigs(const struct optstruct *opts)
2593
 
{
2594
 
        char buffer[32769];
2595
 
        FILE *sigs;
2596
 
        int ret = 0, fd;
2597
 
 
2598
 
 
2599
 
    if(!opts->filename) {
2600
 
        mprintf("!--test-sigs requires two arguments\n");
2601
 
        return -1;
2602
 
    }
2603
 
 
2604
 
    sigs = fopen(optget(opts, "test-sigs")->strarg, "rb");
2605
 
    if(!sigs) {
2606
 
        mprintf("!testsigs: Can't open file %s\n", optget(opts, "test-sigs")->strarg);
2607
 
        return -1;
2608
 
    }
2609
 
 
2610
 
    fd = open(opts->filename[0], O_RDONLY|O_BINARY);
2611
 
    if(fd == -1) {
2612
 
        mprintf("!testsigs: Can't open file %s\n", optget(opts, "test-sigs")->strarg);
2613
 
        fclose(sigs);
2614
 
        return -1;
2615
 
    }
2616
 
 
2617
 
    while(fgets(buffer, sizeof(buffer), sigs)) {
2618
 
        cli_chomp(buffer);
2619
 
        if(!strlen(buffer))
2620
 
            break;
2621
 
        if(decodesig(buffer, fd) == -1) {
2622
 
            ret = -1;
2623
 
            break;
2624
 
        }
2625
 
    }
2626
 
 
2627
 
    close(fd);
2628
 
    fclose(sigs);
2629
 
    return ret;
2630
 
}
2631
 
 
2632
 
static int diffdirs(const char *old, const char *new, const char *patch)
2633
 
{
2634
 
        FILE *diff;
2635
 
        DIR *dd;
2636
 
        struct dirent *dent;
2637
 
        char cwd[512], path[1024];
2638
 
 
2639
 
 
2640
 
    if(!getcwd(cwd, sizeof(cwd))) {
2641
 
        mprintf("!diffdirs: getcwd() failed\n");
2642
 
        return -1;
2643
 
    }
2644
 
 
2645
 
    if(!(diff = fopen(patch, "wb"))) {
2646
 
        mprintf("!diffdirs: Can't open %s for writing\n", patch);
2647
 
        return -1;
2648
 
    }
2649
 
 
2650
 
    if(chdir(new) == -1) {
2651
 
        mprintf("!diffdirs: Can't chdir to %s\n", new);
2652
 
        fclose(diff);
2653
 
        return -1;
2654
 
    }
2655
 
 
2656
 
    if((dd = opendir(new)) == NULL) {
2657
 
        mprintf("!diffdirs: Can't open directory %s\n", new);
2658
 
        fclose(diff);
2659
 
        return -1;
2660
 
    }
2661
 
 
2662
 
    while((dent = readdir(dd))) {
2663
 
        if(dent->d_ino)
2664
 
        {
2665
 
            if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2666
 
                continue;
2667
 
 
2668
 
            snprintf(path, sizeof(path), "%s"PATHSEP"%s", old, dent->d_name);
2669
 
            if(compare(path, dent->d_name, diff) == -1) {
2670
 
                if(chdir(cwd) == -1)
2671
 
                    mprintf("^diffdirs: Can't chdir to %s\n", cwd);
2672
 
                fclose(diff);
2673
 
                unlink(patch);
2674
 
                closedir(dd);
2675
 
                return -1;
2676
 
            }
2677
 
        }
2678
 
    }
2679
 
    closedir(dd);
2680
 
 
2681
 
    /* check for removed files */
2682
 
    if((dd = opendir(old)) == NULL) {
2683
 
        mprintf("!diffdirs: Can't open directory %s\n", old);
2684
 
        fclose(diff);
2685
 
        return -1;
2686
 
    }
2687
 
 
2688
 
    while((dent = readdir(dd))) {
2689
 
        if(dent->d_ino)
2690
 
        {
2691
 
            if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2692
 
                continue;
2693
 
 
2694
 
            snprintf(path, sizeof(path), "%s"PATHSEP"%s", new, dent->d_name);
2695
 
            if(access(path, R_OK))
2696
 
                fprintf(diff, "UNLINK %s\n", dent->d_name);
2697
 
        }
2698
 
    }
2699
 
    closedir(dd);
2700
 
 
2701
 
    fclose(diff);
2702
 
    mprintf("Generated diff file %s\n", patch);
2703
 
    if(chdir(cwd) == -1)
2704
 
        mprintf("^diffdirs: Can't chdir to %s\n", cwd);
2705
 
 
2706
 
    return 0;
2707
 
}
2708
 
 
2709
 
static int makediff(const struct optstruct *opts)
2710
 
{
2711
 
        char *odir, *ndir, name[32], broken[32], dbname[32];
2712
 
        struct cl_cvd *cvd;
2713
 
        unsigned int oldver, newver;
2714
 
        int ret;
2715
 
 
2716
 
 
2717
 
    if(!opts->filename) {
2718
 
        mprintf("!makediff: --diff requires two arguments\n");
2719
 
        return -1;
2720
 
    }
2721
 
 
2722
 
    if(!(cvd = cl_cvdhead(opts->filename[0]))) {
2723
 
        mprintf("!makediff: Can't read CVD header from %s\n", opts->filename[0]);
2724
 
        return -1;
2725
 
    }
2726
 
    newver = cvd->version;
2727
 
    free(cvd);
2728
 
 
2729
 
    if(!(cvd = cl_cvdhead(optget(opts, "diff")->strarg))) {
2730
 
        mprintf("!makediff: Can't read CVD header from %s\n", optget(opts, "diff")->strarg);
2731
 
        return -1;
2732
 
    }
2733
 
    oldver = cvd->version;
2734
 
    free(cvd);
2735
 
 
2736
 
    if(oldver + 1 != newver) {
2737
 
        mprintf("!makediff: The old CVD must be %u\n", newver - 1);
2738
 
        return -1;
2739
 
    }
2740
 
 
2741
 
    odir = cli_gentemp(NULL);
2742
 
    if(!odir) {
2743
 
        mprintf("!makediff: Can't generate temporary name for odir\n");
2744
 
        return -1;
2745
 
    }
2746
 
 
2747
 
    if(mkdir(odir, 0700) == -1) {
2748
 
        mprintf("!makediff: Can't create directory %s\n", odir);
2749
 
        free(odir);
2750
 
        return -1;
2751
 
    }
2752
 
 
2753
 
    if(cli_cvdunpack(optget(opts, "diff")->strarg, odir) == -1) {
2754
 
        mprintf("!makediff: Can't unpack CVD file %s\n", optget(opts, "diff")->strarg);
2755
 
        cli_rmdirs(odir);
2756
 
        free(odir);
2757
 
        return -1;
2758
 
    }
2759
 
 
2760
 
    ndir = cli_gentemp(NULL);
2761
 
    if(!ndir) {
2762
 
        mprintf("!makediff: Can't generate temporary name for ndir\n");
2763
 
        cli_rmdirs(odir);
2764
 
        free(odir);
2765
 
        return -1;
2766
 
    }
2767
 
 
2768
 
    if(mkdir(ndir, 0700) == -1) {
2769
 
        mprintf("!makediff: Can't create directory %s\n", ndir);
2770
 
        free(ndir);
2771
 
        cli_rmdirs(odir);
2772
 
        free(odir);
2773
 
        return -1;
2774
 
    }
2775
 
 
2776
 
    if(cli_cvdunpack(opts->filename[0], ndir) == -1) {
2777
 
        mprintf("!makediff: Can't unpack CVD file %s\n", opts->filename[0]);
2778
 
        cli_rmdirs(odir);
2779
 
        cli_rmdirs(ndir);
2780
 
        free(odir);
2781
 
        free(ndir);
2782
 
        return -1;
2783
 
    }
2784
 
 
2785
 
    snprintf(name, sizeof(name), "%s-%u.script", getdbname(opts->filename[0], dbname, sizeof(dbname)), newver);
2786
 
    ret = diffdirs(odir, ndir, name);
2787
 
 
2788
 
    cli_rmdirs(odir);
2789
 
    cli_rmdirs(ndir);
2790
 
    free(odir);
2791
 
    free(ndir);
2792
 
 
2793
 
    if(ret == -1)
2794
 
        return -1;
2795
 
 
2796
 
    if(verifydiff(name, optget(opts, "diff")->strarg, NULL) == -1) {
2797
 
        snprintf(broken, sizeof(broken), "%s.broken", name);
2798
 
        if(rename(name, broken)) {
2799
 
            unlink(name);
2800
 
            mprintf("!Generated file is incorrect, removed");
2801
 
        } else {
2802
 
            mprintf("!Generated file is incorrect, renamed to %s\n", broken);
2803
 
        }
2804
 
        return -1;
2805
 
    }
2806
 
 
2807
 
    return 0;
2808
 
}
2809
 
 
2810
 
static int dumpcerts(const struct optstruct *opts)
2811
 
{
2812
 
    char * filename = NULL;
2813
 
    STATBUF sb;
2814
 
    const char * fmptr;
2815
 
    struct cl_engine *engine;
2816
 
    cli_ctx ctx;
2817
 
    int fd, ret;
2818
 
    uint8_t shash1[SHA1_HASH_SIZE];
2819
 
 
2820
 
    logg_file = NULL;
2821
 
 
2822
 
    filename = optget(opts, "print-certs")->strarg;
2823
 
    if(!filename) {
2824
 
        mprintf("!dumpcerts: No filename!\n");
2825
 
        return -1;
2826
 
    }
2827
 
 
2828
 
    /* build engine */
2829
 
    if(!(engine = cl_engine_new())) {
2830
 
        mprintf("!dumpcerts: Can't create new engine\n");
2831
 
        return -1;
2832
 
    }
2833
 
    cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
2834
 
 
2835
 
    if(cli_initroots(engine, 0) != CL_SUCCESS) {
2836
 
        mprintf("!dumpcerts: cli_initroots() failed\n");
2837
 
        cl_engine_free(engine);
2838
 
        return -1;
2839
 
    }
2840
 
 
2841
 
    if(cli_parse_add(engine->root[0], "test", "deadbeef", 0, 0, "*", 0, NULL, 0) != CL_SUCCESS) {
2842
 
        mprintf("!dumpcerts: Can't parse signature\n");
2843
 
        cl_engine_free(engine);
2844
 
        return -1;
2845
 
    }
2846
 
 
2847
 
    if(cl_engine_compile(engine) != CL_SUCCESS) {
2848
 
        mprintf("!dumpcerts: Can't compile engine\n");
2849
 
        cl_engine_free(engine);
2850
 
        return -1;
2851
 
    }
2852
 
 
2853
 
    engine->dconf->pe |= PE_CONF_DUMPCERT;
2854
 
    cl_debug();
2855
 
 
2856
 
    /* prepare context */
2857
 
    memset(&ctx, '\0', sizeof(cli_ctx));
2858
 
    ctx.engine = engine;
2859
 
    ctx.options = CL_SCAN_STDOPT;
2860
 
    ctx.container_type = CL_TYPE_ANY;
2861
 
    ctx.dconf = (struct cli_dconf *) engine->dconf;
2862
 
    ctx.fmap = calloc(sizeof(fmap_t *), 1);
2863
 
    if(!ctx.fmap) {
2864
 
        cl_engine_free(engine);
2865
 
        return -1;
2866
 
    }
2867
 
 
2868
 
    /* Prepare file */
2869
 
    fd = open(filename, O_RDONLY);
2870
 
    if(fd < 0) {
2871
 
        mprintf("!dumpcerts: Can't open file %s!\n", filename);
2872
 
        cl_engine_free(engine);
2873
 
        return -1;
2874
 
    }
2875
 
 
2876
 
    lseek(fd, 0, SEEK_SET);
2877
 
    FSTAT(fd, &sb);
2878
 
    if(!(*ctx.fmap = fmap(fd, 0, sb.st_size))) {
2879
 
        free(ctx.fmap);
2880
 
        close(fd);
2881
 
        cl_engine_free(engine);
2882
 
        return -1;
2883
 
    }
2884
 
 
2885
 
    fmptr = fmap_need_off_once(*ctx.fmap, 0, sb.st_size);
2886
 
    if(!fmptr) {
2887
 
        mprintf("!dumpcerts: fmap_need_off_once failed!\n");
2888
 
        free(ctx.fmap);
2889
 
        close(fd);
2890
 
        cl_engine_free(engine);
2891
 
        return -1;
2892
 
    }
2893
 
 
2894
 
    /* Generate SHA1 */
2895
 
    cl_sha1(fmptr, sb.st_size, shash1, NULL);
2896
 
 
2897
 
    ret = cli_checkfp_pe(&ctx, shash1, NULL, CL_CHECKFP_PE_FLAG_AUTHENTICODE);
2898
 
    
2899
 
    switch(ret) {
2900
 
        case CL_CLEAN:
2901
 
            mprintf("*dumpcerts: CL_CLEAN after cli_checkfp_pe()!\n");
2902
 
            break;
2903
 
        case CL_VIRUS:
2904
 
            mprintf("*dumpcerts: CL_VIRUS after cli_checkfp_pe()!\n");
2905
 
            break;
2906
 
        case CL_BREAK:
2907
 
            mprintf("*dumpcerts: CL_BREAK after cli_checkfp_pe()!\n");
2908
 
            break;
2909
 
        case CL_EFORMAT:
2910
 
            mprintf("!dumpcerts: Not a valid PE file!\n");
2911
 
            break;
2912
 
        default:
2913
 
            mprintf("!dumpcerts: Other error %d inside cli_checkfp_pe.\n", ret);
2914
 
            break;
2915
 
    }
2916
 
 
2917
 
    /* Cleanup */
2918
 
    free(ctx.fmap);
2919
 
    close(fd);
2920
 
    cl_engine_free(engine);
2921
 
    return 0;
2922
 
}
2923
 
 
2924
 
static void help(void)
2925
 
{
2926
 
    mprintf("\n");
2927
 
    mprintf("Clam AntiVirus: Signature Tool (sigtool)  %s\n", get_version());
2928
 
    mprintf("       By The ClamAV Team: http://www.clamav.net/team\n");
2929
 
    mprintf("       (C) 2007-2009 Sourcefire, Inc. et al.\n\n");
2930
 
 
2931
 
    mprintf("    --help                 -h              show help\n");
2932
 
    mprintf("    --version              -V              print version number and exit\n");
2933
 
    mprintf("    --quiet                                be quiet, output only error messages\n");
2934
 
    mprintf("    --debug                                enable debug messages\n");
2935
 
    mprintf("    --stdout                               write to stdout instead of stderr\n");
2936
 
    mprintf("    --hex-dump                             convert data from stdin to a hex\n");
2937
 
    mprintf("                                           string and print it on stdout\n");
2938
 
    mprintf("    --md5 [FILES]                          generate MD5 checksum from stdin\n");
2939
 
    mprintf("                                           or MD5 sigs for FILES\n");
2940
 
    mprintf("    --sha1 [FILES]                         generate SHA1 checksum from stdin\n");
2941
 
    mprintf("                                           or SHA1 sigs for FILES\n");
2942
 
    mprintf("    --sha256 [FILES]                       generate SHA256 checksum from stdin\n");
2943
 
    mprintf("                                           or SHA256 sigs for FILES\n");
2944
 
    mprintf("    --mdb [FILES]                          generate .mdb sigs\n");
2945
 
    mprintf("    --html-normalise=FILE                  create normalised parts of HTML file\n");
2946
 
    mprintf("    --utf16-decode=FILE                    decode UTF16 encoded files\n");
2947
 
    mprintf("    --info=FILE            -i FILE         print database information\n");
2948
 
    mprintf("    --build=NAME [cvd] -b NAME             build a CVD file\n");
2949
 
    mprintf("    --max-bad-sigs=NUMBER                  Maximum number of mismatched signatures\n");
2950
 
    mprintf("                                           when building a CVD. Default: 3000\n");
2951
 
    mprintf("    --flevel=FLEVEL                        Specify a custom flevel.\n");
2952
 
    mprintf("                                           Default: %u\n", cl_retflevel());
2953
 
    mprintf("    --cvd-version=NUMBER                   Specify the version number to use for\n");
2954
 
    mprintf("                                           the build. Default is to use the value+1\n");
2955
 
    mprintf("                                           from the current CVD in --datadir.\n");
2956
 
    mprintf("                                           If no datafile is found the default\n");
2957
 
    mprintf("                                           behaviour is to prompt for a version\n");
2958
 
    mprintf("                                           number, this switch will prevent the\n");
2959
 
    mprintf("                                           prompt.  NOTE: If a CVD is found in the\n");
2960
 
    mprintf("                                           --datadir its version+1 is used and\n");
2961
 
    mprintf("                                           this value is ignored.\n");
2962
 
    mprintf("    --no-cdiff                             Don't generate .cdiff file\n");
2963
 
    mprintf("    --unsigned                             Create unsigned database file (.cud)\n");
2964
 
    mprintf("    --print-certs=FILE                     Print Authenticode details from a PE\n");
2965
 
    mprintf("    --server=ADDR                          ClamAV Signing Service address\n");
2966
 
    mprintf("    --datadir=DIR                          Use DIR as default database directory\n");
2967
 
    mprintf("    --unpack=FILE          -u FILE         Unpack a CVD/CLD file\n");
2968
 
    mprintf("    --unpack-current=SHORTNAME             Unpack local CVD/CLD into cwd\n");
2969
 
    mprintf("    --list-sigs[=FILE]     -l[FILE]        List signature names\n");
2970
 
    mprintf("    --find-sigs=REGEX      -fREGEX         Find signatures matching REGEX\n");
2971
 
    mprintf("    --decode-sigs                          Decode signatures from stdin\n");
2972
 
    mprintf("    --test-sigs=DATABASE TARGET_FILE       Test signatures from DATABASE against \n");
2973
 
    mprintf("                                           TARGET_FILE\n");
2974
 
    mprintf("    --vba=FILE                             Extract VBA/Word6 macro code\n");
2975
 
    mprintf("    --vba-hex=FILE                         Extract Word6 macro code with hex values\n");
2976
 
    mprintf("    --diff=OLD NEW         -d OLD NEW      Create diff for OLD and NEW CVDs\n");
2977
 
    mprintf("    --compare=OLD NEW      -c OLD NEW      Show diff between OLD and NEW files in\n");
2978
 
    mprintf("                                           cdiff format\n");
2979
 
    mprintf("    --run-cdiff=FILE       -r FILE         Execute update script FILE in cwd\n");
2980
 
    mprintf("    --verify-cdiff=DIFF CVD/CLD            Verify DIFF against CVD/CLD\n");
2981
 
    mprintf("\n");
2982
 
 
2983
 
    return;
2984
 
}
2985
 
 
2986
 
int main(int argc, char **argv)
2987
 
{
2988
 
        int ret;
2989
 
        struct optstruct *opts;
2990
 
        STATBUF sb;
2991
 
 
2992
 
    if(check_flevel())
2993
 
        exit(1);
2994
 
 
2995
 
    if((ret = cl_init(CL_INIT_DEFAULT)) != CL_SUCCESS) {
2996
 
        mprintf("!Can't initialize libclamav: %s\n", cl_strerror(ret));
2997
 
        return -1;
2998
 
    }
2999
 
    ret = 1;
3000
 
 
3001
 
    opts = optparse(NULL, argc, argv, 1, OPT_SIGTOOL, 0, NULL);
3002
 
    if(!opts) {
3003
 
        mprintf("!Can't parse command line options\n");
3004
 
        return 1;
3005
 
    }
3006
 
 
3007
 
    if(optget(opts, "quiet")->enabled)
3008
 
        mprintf_quiet = 1;
3009
 
 
3010
 
    if(optget(opts, "stdout")->enabled)
3011
 
        mprintf_stdout = 1;
3012
 
 
3013
 
    if(optget(opts, "debug")->enabled)
3014
 
        cl_debug();
3015
 
 
3016
 
    if(optget(opts, "version")->enabled) {
3017
 
        print_version(NULL);
3018
 
        optfree(opts);
3019
 
        return 0;
3020
 
    }
3021
 
 
3022
 
    if(optget(opts, "help")->enabled) {
3023
 
        optfree(opts);
3024
 
        help();
3025
 
        return 0;
3026
 
    }
3027
 
 
3028
 
    if(optget(opts, "hex-dump")->enabled)
3029
 
        ret = hexdump();
3030
 
    else if(optget(opts, "md5")->enabled)
3031
 
        ret = hashsig(opts, 0, 1);
3032
 
    else if(optget(opts, "sha1")->enabled)
3033
 
        ret = hashsig(opts, 0, 2);
3034
 
    else if(optget(opts, "sha256")->enabled)
3035
 
        ret = hashsig(opts, 0, 3);
3036
 
    else if(optget(opts, "mdb")->enabled)
3037
 
        ret = hashsig(opts, 1, 1);
3038
 
    else if(optget(opts, "html-normalise")->enabled)
3039
 
        ret = htmlnorm(opts);
3040
 
    else if(optget(opts, "utf16-decode")->enabled)
3041
 
        ret = utf16decode(opts);
3042
 
    else if(optget(opts, "build")->enabled)
3043
 
        ret = build(opts);
3044
 
    else if(optget(opts, "unpack")->enabled)
3045
 
        ret = unpack(opts);
3046
 
    else if(optget(opts, "unpack-current")->enabled)
3047
 
        ret = unpack(opts);
3048
 
    else if(optget(opts, "info")->enabled)
3049
 
        ret = cvdinfo(opts);
3050
 
    else if(optget(opts, "list-sigs")->active)
3051
 
        ret = listsigs(opts, 0);
3052
 
    else if(optget(opts, "find-sigs")->active)
3053
 
        ret = listsigs(opts, 1);
3054
 
    else if(optget(opts, "decode-sigs")->active)
3055
 
        ret = decodesigs();
3056
 
    else if(optget(opts, "test-sigs")->enabled)
3057
 
        ret = testsigs(opts);
3058
 
    else if(optget(opts, "vba")->enabled || optget(opts, "vba-hex")->enabled)
3059
 
        ret = vbadump(opts);
3060
 
    else if(optget(opts, "diff")->enabled)
3061
 
        ret = makediff(opts);
3062
 
    else if(optget(opts, "compare")->enabled)
3063
 
        ret = compareone(opts);
3064
 
    else if(optget(opts, "print-certs")->enabled)
3065
 
        ret = dumpcerts(opts);
3066
 
    else if(optget(opts, "run-cdiff")->enabled)
3067
 
        ret = rundiff(opts);
3068
 
    else if(optget(opts, "verify-cdiff")->enabled) {
3069
 
        if(!opts->filename) {
3070
 
            mprintf("!--verify-cdiff requires two arguments\n");
3071
 
            ret = -1;
3072
 
        } else {
3073
 
            if(CLAMSTAT(opts->filename[0], &sb) == -1) {
3074
 
                mprintf("--verify-cdiff: Can't get status of %s\n", opts->filename[0]);
3075
 
                ret = -1;
3076
 
            } else {
3077
 
                if(S_ISDIR(sb.st_mode))
3078
 
                    ret = verifydiff(optget(opts, "verify-cdiff")->strarg, NULL, opts->filename[0]);
3079
 
                else
3080
 
                    ret = verifydiff(optget(opts, "verify-cdiff")->strarg, opts->filename[0], NULL);
3081
 
            }
3082
 
        }
3083
 
    } else
3084
 
        help();
3085
 
 
3086
 
    optfree(opts);
3087
 
    cl_cleanup_crypto();
3088
 
    return ret ? 1 : 0;
3089
 
}