source: clamav/trunk/shared/cdiff.c@ 319

Last change on this file since 319 was 319, checked in by Yuri Dario, 14 years ago

clamav: update trunk to 0.97.

File size: 22.9 KB
Line 
1/*
2 * Copyright (C) 2006 Sensory Networks, Inc.
3 * (C) 2007 Tomasz Kojm <tkojm@clamav.net>
4 * Written by Tomasz Kojm
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
21
22#if HAVE_CONFIG_H
23#include "clamav-config.h"
24#endif
25
26#include <stdio.h>
27#include <string.h>
28#include <ctype.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#ifdef HAVE_UNISTD_H
32#include <unistd.h>
33#endif
34
35#include "shared/misc.h"
36#include "shared/output.h"
37#include "shared/cdiff.h"
38#include "libclamav/sha256.h"
39
40#include "libclamav/str.h"
41#include "libclamav/others.h"
42#include "libclamav/cvd.h"
43#include "libclamav/default.h"
44
45#include "zlib.h"
46
47#include "libclamav/dsig.h"
48
49#define PSS_NSTR "14783905874077467090262228516557917570254599638376203532031989214105552847269687489771975792123442185817287694951949800908791527542017115600501303394778618535864845235700041590056318230102449612217458549016089313306591388590790796515819654102320725712300822356348724011232654837503241736177907784198700834440681124727060540035754699658105895050096576226753008596881698828185652424901921668758326578462003247906470982092298106789657211905488986281078346361469524484829559560886227198091995498440676639639830463593211386055065360288422394053998134458623712540683294034953818412458362198117811990006021989844180721010947"
50#define PSS_ESTR "100002053"
51#define PSS_NBITS 2048
52#define PSS_DIGEST_LENGTH 32
53
54/* the line size can be changed from within .cdiff */
55#define CDIFF_LINE_SIZE CLI_DEFAULT_LSIG_BUFSIZE + 32
56
57struct cdiff_node {
58 unsigned int lineno;
59 char *str, *str2;
60 struct cdiff_node *next;
61};
62
63struct cdiff_ctx {
64 char *open_db;
65 struct cdiff_node *add_start, *add_last;
66 struct cdiff_node *del_start;
67 struct cdiff_node *xchg_start, *xchg_last;
68};
69
70struct cdiff_cmd {
71 const char *name;
72 unsigned short argc;
73 int (*handler)(const char *, struct cdiff_ctx *, char *, unsigned int);
74};
75
76static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen);
77static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen);
78static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen);
79static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen);
80static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen);
81static int cdiff_cmd_move(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen);
82static int cdiff_cmd_unlink(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen);
83
84static struct cdiff_cmd commands[] = {
85 /* OPEN db_name */
86 { "OPEN", 1, &cdiff_cmd_open },
87
88 /* ADD newsig */
89 { "ADD", 1, &cdiff_cmd_add },
90
91 /* DEL line_no some_first_bytes */
92 { "DEL", 2, &cdiff_cmd_del },
93
94 /* XCHG line_no some_first_bytes_of_old_line new_line */
95 { "XCHG", 3, &cdiff_cmd_xchg },
96
97 /* CLOSE */
98 { "CLOSE", 0, &cdiff_cmd_close },
99
100 /* MOVE src_db dst_db start_line first_16b end_line first_16b */
101 { "MOVE", 6, &cdiff_cmd_move },
102
103 /* UNLINK db_name */
104 { "UNLINK", 1, &cdiff_cmd_unlink },
105
106 { NULL, 0, NULL }
107};
108
109static void cdiff_ctx_free(struct cdiff_ctx *ctx)
110{
111 struct cdiff_node *pt;
112
113
114 if(ctx->open_db) {
115 free(ctx->open_db);
116 ctx->open_db = NULL;
117 }
118
119 while(ctx->add_start) {
120 free(ctx->add_start->str);
121 pt = ctx->add_start;
122 ctx->add_start = ctx->add_start->next;
123 free(pt);
124 }
125 ctx->add_last = NULL;
126
127 while(ctx->del_start) {
128 free(ctx->del_start->str);
129 pt = ctx->del_start;
130 ctx->del_start = ctx->del_start->next;
131 free(pt);
132 }
133
134 while(ctx->xchg_start) {
135 free(ctx->xchg_start->str);
136 free(ctx->xchg_start->str2);
137 pt = ctx->xchg_start;
138 ctx->xchg_start = ctx->xchg_start->next;
139 free(pt);
140 }
141}
142
143static char *cdiff_token(const char *line, unsigned int token, unsigned int last)
144{
145 unsigned int counter = 0, i, j;
146 char *buffer;
147
148
149 for(i = 0; line[i] && counter != token; i++)
150 if(line[i] == ' ')
151 counter++;
152
153 if(!line[i])
154 return NULL;
155
156 if(last)
157 return strdup(&line[i]);
158
159 for(j = i; line[j]; j++)
160 if(line[j] == ' ')
161 break;
162
163 if(i == j)
164 return NULL;
165
166 buffer = malloc(j - i + 1);
167 if(!buffer)
168 return NULL;
169
170 strncpy(buffer, line + i, j - i);
171 buffer[j - i] = '\0';
172
173 return buffer;
174}
175
176static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
177{
178 char *db;
179 unsigned int i;
180
181
182 if(!(db = cdiff_token(cmdstr, 1, 1))) {
183 logg("!cdiff_cmd_open: Can't get first argument\n");
184 return -1;
185 }
186
187 if(ctx->open_db) {
188 logg("!cdiff_cmd_open: %s not closed before opening %s\n", ctx->open_db, db);
189 free(db);
190 return -1;
191 }
192
193 for(i = 0; i < strlen(db); i++) {
194 if((db[i] != '.' && !isalnum(db[i])) || strchr("/\\", db[i])) {
195 logg("!cdiff_cmd_open: Forbidden characters found in database name\n");
196 free(db);
197 return -1;
198 }
199 }
200
201 ctx->open_db = db;
202 return 0;
203}
204
205static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
206{
207 char *sig;
208 struct cdiff_node *new;
209
210
211 if(!(sig = cdiff_token(cmdstr, 1, 1))) {
212 logg("!cdiff_cmd_add: Can't get first argument\n");
213 return -1;
214 }
215
216 new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
217 if(!new) {
218 logg("!cdiff_cmd_add: Can't allocate memory for cdiff_node\n");
219 free(sig);
220 return -1;
221 }
222 new->str = sig;
223
224 if(!ctx->add_last) {
225 ctx->add_start = ctx->add_last = new;
226 } else {
227 ctx->add_last->next = new;
228 ctx->add_last = new;
229 }
230
231 return 0;
232}
233
234static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
235{
236 char *arg;
237 struct cdiff_node *pt, *last, *new;
238 unsigned int lineno;
239
240
241 if(!(arg = cdiff_token(cmdstr, 1, 0))) {
242 logg("!cdiff_cmd_del: Can't get first argument\n");
243 return -1;
244 }
245 lineno = (unsigned int) atoi(arg);
246 free(arg);
247
248 if(!(arg = cdiff_token(cmdstr, 2, 1))) {
249 logg("!cdiff_cmd_del: Can't get second argument\n");
250 return -1;
251 }
252
253 new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
254 if(!new) {
255 logg("!cdiff_cmd_del: Can't allocate memory for cdiff_node\n");
256 free(arg);
257 return -1;
258 }
259 new->str = arg;
260 new->lineno = lineno;
261
262 if(!ctx->del_start) {
263
264 ctx->del_start = new;
265
266 } else {
267
268 if(lineno < ctx->del_start->lineno) {
269 new->next = ctx->del_start;
270 ctx->del_start = new;
271
272 } else {
273 pt = ctx->del_start;
274
275 while(pt) {
276 last = pt;
277 if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
278 break;
279
280 pt = pt->next;
281 }
282
283 new->next = last->next;
284 last->next = new;
285 }
286 }
287
288 return 0;
289}
290
291static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
292{
293 char *arg, *arg2;
294 struct cdiff_node *pt, *last, *new;
295 unsigned int lineno;
296
297
298 if(!(arg = cdiff_token(cmdstr, 1, 0))) {
299 logg("!cdiff_cmd_xchg: Can't get first argument\n");
300 return -1;
301 }
302 lineno = (unsigned int) atoi(arg);
303 free(arg);
304
305 if(!(arg = cdiff_token(cmdstr, 2, 0))) {
306 logg("!cdiff_cmd_xchg: Can't get second argument\n");
307 return -1;
308 }
309
310 if(!(arg2 = cdiff_token(cmdstr, 3, 1))) {
311 free(arg);
312 logg("!cdiff_cmd_xchg: Can't get second argument\n");
313 return -1;
314 }
315
316 new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
317 if(!new) {
318 logg("!cdiff_cmd_xchg: Can't allocate memory for cdiff_node\n");
319 free(arg);
320 free(arg2);
321 return -1;
322 }
323 new->str = arg;
324 new->str2 = arg2;
325 new->lineno = lineno;
326
327 if(!ctx->xchg_start)
328 ctx->xchg_start = new;
329 else
330 ctx->xchg_last->next = new;
331
332 ctx->xchg_last = new;
333 return 0;
334}
335
336static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
337{
338 struct cdiff_node *add, *del, *xchg;
339 unsigned int lines = 0;
340 char *tmp;
341 FILE *fh, *tmpfh;
342
343
344 if(!ctx->open_db) {
345 logg("!cdiff_cmd_close: No database to close\n");
346 return -1;
347 }
348
349 add = ctx->add_start;
350 del = ctx->del_start;
351 xchg = ctx->xchg_start;
352
353 if(del || xchg) {
354
355 if(!(fh = fopen(ctx->open_db, "rb"))) {
356 logg("!cdiff_cmd_close: Can't open file %s for reading\n", ctx->open_db);
357 return -1;
358 }
359
360 if(!(tmp = cli_gentemp("."))) {
361 logg("!cdiff_cmd_close: Can't generate temporary name\n");
362 fclose(fh);
363 return -1;
364 }
365
366 if(!(tmpfh = fopen(tmp, "wb"))) {
367 logg("!cdiff_cmd_close: Can't open file %s for writing\n", tmp);
368 fclose(fh);
369 free(tmp);
370 return -1;
371 }
372
373 while(fgets(lbuf, lbuflen, fh)) {
374 lines++;
375
376 if(del && del->lineno == lines) {
377 if(strncmp(lbuf, del->str, strlen(del->str))) {
378 fclose(fh);
379 fclose(tmpfh);
380 unlink(tmp);
381 free(tmp);
382 logg("!cdiff_cmd_close: Can't apply DEL at line %d of %s\n", lines, ctx->open_db);
383 return -1;
384 }
385 del = del->next;
386 continue;
387 }
388
389 if(xchg && xchg->lineno == lines) {
390 if(strncmp(lbuf, xchg->str, strlen(xchg->str))) {
391 fclose(fh);
392 fclose(tmpfh);
393 unlink(tmp);
394 free(tmp);
395 logg("!cdiff_cmd_close: Can't apply XCHG at line %d of %s\n", lines, ctx->open_db);
396 return -1;
397 }
398
399 if(fputs(xchg->str2, tmpfh) == EOF || fputc('\n', tmpfh) == EOF) {
400 fclose(fh);
401 fclose(tmpfh);
402 unlink(tmp);
403 logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
404 free(tmp);
405 return -1;
406 }
407 xchg = xchg->next;
408 continue;
409 }
410
411 if(fputs(lbuf, tmpfh) == EOF) {
412 fclose(fh);
413 fclose(tmpfh);
414 unlink(tmp);
415 logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
416 free(tmp);
417 return -1;
418 }
419 }
420
421 fclose(fh);
422 fclose(tmpfh);
423
424 if(del || xchg) {
425 logg("!cdiff_cmd_close: Not all DEL/XCHG have been executed\n");
426 unlink(tmp);
427 free(tmp);
428 return -1;
429 }
430
431 if(unlink(ctx->open_db) == -1) {
432 logg("!cdiff_cmd_close: Can't unlink %s\n", ctx->open_db);
433 unlink(tmp);
434 free(tmp);
435 return -1;
436 }
437
438 if(rename(tmp, ctx->open_db) == -1) {
439 logg("!cdiff_cmd_close: Can't rename %s to %s\n", tmp, ctx->open_db);
440 unlink(tmp);
441 free(tmp);
442 return -1;
443 }
444
445 free(tmp);
446 }
447
448 if(add) {
449
450 if(!(fh = fopen(ctx->open_db, "ab"))) {
451 logg("!cdiff_cmd_close: Can't open file %s for appending\n", ctx->open_db);
452 return -1;
453 }
454
455 while(add) {
456 if(fputs(add->str, fh) == EOF || fputc('\n', fh) == EOF) {
457 fclose(fh);
458 logg("!cdiff_cmd_close: Can't write to %s\n", ctx->open_db);
459 return -1;
460 }
461 add = add->next;
462 }
463
464 fclose(fh);
465 }
466
467 cdiff_ctx_free(ctx);
468
469 return 0;
470}
471
472static int cdiff_cmd_move(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
473{
474 unsigned int lines = 0, start_line, end_line;
475 char *arg, *srcdb, *dstdb, *tmpdb, *start_str, *end_str;
476 FILE *src, *dst, *tmp;
477
478
479 if(ctx->open_db) {
480 logg("!cdiff_cmd_move: Database %s is still open\n", ctx->open_db);
481 return -1;
482 }
483
484 if(!(arg = cdiff_token(cmdstr, 3, 0))) {
485 logg("!cdiff_cmd_move: Can't get third argument\n");
486 return -1;
487 }
488 start_line = atoi(arg);
489 free(arg);
490
491 if(!(arg = cdiff_token(cmdstr, 5, 0))) {
492 logg("!cdiff_cmd_move: Can't get fifth argument\n");
493 return -1;
494 }
495 end_line = atoi(arg);
496 free(arg);
497
498 if(end_line < start_line) {
499 logg("!cdiff_cmd_move: end_line < start_line\n");
500 return -1;
501 }
502
503 if(!(start_str = cdiff_token(cmdstr, 4, 0))) {
504 logg("!cdiff_cmd_move: Can't get fourth argument\n");
505 return -1;
506 }
507
508 if(!(end_str = cdiff_token(cmdstr, 6, 0))) {
509 logg("!cdiff_cmd_move: Can't get sixth argument\n");
510 free(start_str);
511 return -1;
512 }
513
514 if(!(srcdb = cdiff_token(cmdstr, 1, 0))) {
515 logg("!cdiff_cmd_move: Can't get first argument\n");
516 free(start_str);
517 free(end_str);
518 return -1;
519 }
520
521 if(!(src = fopen(srcdb, "rb"))) {
522 logg("!cdiff_cmd_move: Can't open %s for reading\n", srcdb);
523 free(start_str);
524 free(end_str);
525 free(srcdb);
526 return -1;
527 }
528
529 if(!(dstdb = cdiff_token(cmdstr, 2, 0))) {
530 logg("!cdiff_cmd_move: Can't get second argument\n");
531 free(start_str);
532 free(end_str);
533 free(srcdb);
534 fclose(src);
535 return -1;
536 }
537
538 if(!(dst = fopen(dstdb, "ab"))) {
539 logg("!cdiff_cmd_move: Can't open %s for appending\n", dstdb);
540 free(start_str);
541 free(end_str);
542 free(srcdb);
543 fclose(src);
544 free(dstdb);
545 return -1;
546 }
547
548 if(!(tmpdb = cli_gentemp("."))) {
549 logg("!cdiff_cmd_move: Can't generate temporary name\n");
550 free(start_str);
551 free(end_str);
552 free(srcdb);
553 fclose(src);
554 free(dstdb);
555 fclose(dst);
556 return -1;
557 }
558
559 if(!(tmp = fopen(tmpdb, "wb"))) {
560 logg("!cdiff_cmd_move: Can't open file %s for writing\n", tmpdb);
561 free(start_str);
562 free(end_str);
563 free(srcdb);
564 fclose(src);
565 free(dstdb);
566 fclose(dst);
567 free(tmpdb);
568 return -1;
569 }
570
571 while(fgets(lbuf, lbuflen, src)) {
572 lines++;
573
574 if(lines == start_line) {
575 if(strncmp(lbuf, start_str, strlen(start_str))) {
576 free(start_str);
577 free(end_str);
578 free(srcdb);
579 fclose(src);
580 free(dstdb);
581 fclose(dst);
582 fclose(tmp);
583 unlink(tmpdb);
584 free(tmpdb);
585 logg("!cdiff_cmd_close: Can't apply MOVE due to conflict at line %d\n", lines);
586 return -1;
587 }
588
589 do {
590 if(fputs(lbuf, dst) == EOF) {
591 free(start_str);
592 free(end_str);
593 free(srcdb);
594 fclose(src);
595 fclose(dst);
596 fclose(tmp);
597 unlink(tmpdb);
598 free(tmpdb);
599 logg("!cdiff_cmd_move: Can't write to %s\n", dstdb);
600 free(dstdb);
601 return -1;
602 }
603 } while((lines < end_line) && fgets(lbuf, lbuflen, src) && lines++);
604
605 fclose(dst);
606 dst = NULL;
607 free(dstdb);
608 free(start_str);
609
610 if(strncmp(lbuf, end_str, strlen(end_str))) {
611 free(end_str);
612 free(srcdb);
613 fclose(src);
614 fclose(tmp);
615 unlink(tmpdb);
616 free(tmpdb);
617 logg("!cdiff_cmd_close: Can't apply MOVE due to conflict at line %d\n", lines);
618 return -1;
619 }
620
621 free(end_str);
622 continue;
623 }
624
625 if(fputs(lbuf, tmp) == EOF) {
626 if(dst) {
627 fclose(dst);
628 free(dstdb);
629 free(start_str);
630 free(end_str);
631 }
632 free(srcdb);
633 fclose(src);
634 fclose(tmp);
635 unlink(tmpdb);
636 logg("!cdiff_cmd_move: Can't write to %s\n", tmpdb);
637 free(tmpdb);
638 return -1;
639 }
640 }
641
642 fclose(src);
643 fclose(tmp);
644
645 if(dst) {
646 fclose(dst);
647 free(start_str);
648 free(end_str);
649 unlink(tmpdb);
650 free(tmpdb);
651 logg("!cdiff_cmd_move: No data was moved from %s to %s\n", srcdb, dstdb);
652 free(srcdb);
653 free(dstdb);
654 return -1;
655 }
656
657 if(unlink(srcdb) == -1) {
658 logg("!cdiff_cmd_move: Can't unlink %s\n", srcdb);
659 free(srcdb);
660 unlink(tmpdb);
661 free(tmpdb);
662 return -1;
663 }
664
665 if(rename(tmpdb, srcdb) == -1) {
666 logg("!cdiff_cmd_move: Can't rename %s to %s\n", tmpdb, srcdb);
667 free(srcdb);
668 unlink(tmpdb);
669 free(tmpdb);
670 return -1;
671 }
672
673 free(srcdb);
674 free(tmpdb);
675
676 return 0;
677}
678
679static int cdiff_cmd_unlink(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
680{
681 char *db;
682 unsigned int i;
683
684
685 if(ctx->open_db) {
686 logg("!cdiff_cmd_unlink: Database %s is still open\n", ctx->open_db);
687 return -1;
688 }
689
690 if(!(db = cdiff_token(cmdstr, 1, 1))) {
691 logg("!cdiff_cmd_unlink: Can't get first argument\n");
692 return -1;
693 }
694
695 for(i = 0; i < strlen(db); i++) {
696 if((db[i] != '.' && !isalnum(db[i])) || strchr("/\\", db[i])) {
697 logg("!cdiff_cmd_unlink: Forbidden characters found in database name\n");
698 free(db);
699 return -1;
700 }
701 }
702
703 if(unlink(db) == -1) {
704 logg("!cdiff_cmd_unlink: Can't unlink %s\n", db);
705 free(db);
706 return -1;
707 }
708
709 free(db);
710 return 0;
711}
712
713static int cdiff_execute(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf, unsigned int lbuflen)
714{
715 char *cmd_name, *tmp;
716 int (*cmd_handler)(const char *, struct cdiff_ctx *, char *, unsigned int) = NULL;
717 unsigned int i;
718
719
720 cmd_name = cdiff_token(cmdstr, 0, 0);
721 if(!cmd_name) {
722 logg("!cdiff_apply: Problem parsing line\n");
723 return -1;
724 }
725
726 for(i = 0; commands[i].name; i++) {
727 if(!strcmp(commands[i].name, cmd_name)) {
728 cmd_handler = commands[i].handler;
729 break;
730 }
731 }
732
733 if(!cmd_handler) {
734 logg("!cdiff_apply: Unknown command %s\n", cmd_name);
735 free(cmd_name);
736 return -1;
737 }
738
739 if(!(tmp = cdiff_token(cmdstr, commands[i].argc, 1))) {
740 logg("!cdiff_apply: Not enough arguments for %s\n", cmd_name);
741 free(cmd_name);
742 return -1;
743 }
744 free(tmp);
745
746 if(cmd_handler(cmdstr, ctx, lbuf, lbuflen)) {
747 logg("!cdiff_apply: Can't execute command %s\n", cmd_name);
748 free(cmd_name);
749 return -1;
750 }
751
752 free(cmd_name);
753 return 0;
754}
755
756int cdiff_apply(int fd, unsigned short mode)
757{
758 struct cdiff_ctx ctx;
759 FILE *fh;
760 gzFile *gzh;
761 char *line, *lbuf, buff[FILEBUFF], *dsig = NULL;
762 unsigned int lines = 0, cmds = 0;
763 unsigned int difflen, diffremain, line_size = CDIFF_LINE_SIZE;
764 int end, i, n;
765 struct stat sb;
766 int desc;
767 SHA256_CTX sha256ctx;
768 unsigned char digest[32];
769 int sum, bread;
770#define DSIGBUFF 350
771
772 memset(&ctx, 0, sizeof(ctx));
773
774 if((desc = dup(fd)) == -1) {
775 logg("!cdiff_apply: Can't duplicate descriptor %d\n", fd);
776 return -1;
777 }
778
779 if(!(line = malloc(line_size))) {
780 logg("!cdiff_apply: Can't allocate memory for 'line'\n");
781 close(desc);
782 return -1;
783 }
784
785 if(!(lbuf = malloc(line_size))) {
786 logg("!cdiff_apply: Can't allocate memory for 'lbuf'\n");
787 close(desc);
788 free(line);
789 return -1;
790 }
791
792 if(mode == 1) { /* .cdiff */
793
794 if(lseek(desc, -DSIGBUFF, SEEK_END) == -1) {
795 logg("!cdiff_apply: lseek(desc, %d, SEEK_END) failed\n", -DSIGBUFF);
796 close(desc);
797 free(line);
798 free(lbuf);
799 return -1;
800 }
801
802 memset(line, 0, line_size);
803 if(read(desc, line, DSIGBUFF) != DSIGBUFF) {
804 logg("!cdiff_apply: Can't read %d bytes\n", DSIGBUFF);
805 close(desc);
806 free(line);
807 free(lbuf);
808 return -1;
809 }
810
811 for(i = DSIGBUFF - 1; i >= 0; i--) {
812 if(line[i] == ':') {
813 dsig = &line[i + 1];
814 break;
815 }
816 }
817
818 if(!dsig) {
819 logg("!cdiff_apply: No digital signature in cdiff file\n");
820 close(desc);
821 free(line);
822 free(lbuf);
823 return -1;
824 }
825
826 if(fstat(desc, &sb) == -1) {
827 logg("!cdiff_apply: Can't fstat file\n");
828 close(desc);
829 free(line);
830 free(lbuf);
831 return -1;
832 }
833
834 end = sb.st_size - (DSIGBUFF - i);
835 if(end < 0) {
836 logg("!cdiff_apply: compressed data end offset < 0\n");
837 close(desc);
838 free(line);
839 free(lbuf);
840 return -1;
841 }
842
843 if(lseek(desc, 0, SEEK_SET) == -1) {
844 logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
845 close(desc);
846 free(line);
847 free(lbuf);
848 return -1;
849 }
850
851 sha256_init(&sha256ctx);
852 sum = 0;
853 while((bread = read(desc, buff, FILEBUFF)) > 0) {
854 if(sum + bread >= end) {
855 sha256_update(&sha256ctx, (unsigned char *) buff, end - sum);
856 break;
857 } else {
858 sha256_update(&sha256ctx, (unsigned char *) buff, bread);
859 }
860 sum += bread;
861 }
862 sha256_final(&sha256ctx, digest);
863
864 if(cli_versig2(digest, dsig, PSS_NSTR, PSS_ESTR) != CL_SUCCESS) {
865 logg("!cdiff_apply: Incorrect digital signature\n");
866 close(desc);
867 free(line);
868 free(lbuf);
869 return -1;
870 }
871
872 if(lseek(desc, 0, SEEK_SET) == -1) {
873 logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
874 close(desc);
875 free(line);
876 free(lbuf);
877 return -1;
878 }
879
880 i = 0;
881 n = 0;
882 while(n < FILEBUFF - 1 && read(desc, &buff[n], 1) > 0) {
883 if(buff[n++] == ':')
884 if(++i == 3)
885 break;
886 }
887 buff[n] = 0;
888
889 if(sscanf(buff, "ClamAV-Diff:%*u:%u:", &difflen) != 1) {
890 logg("!cdiff_apply: Incorrect file format\n");
891 close(desc);
892 free(line);
893 free(lbuf);
894 return -1;
895 }
896
897 if(!(gzh = gzdopen(desc, "rb"))) {
898 logg("!cdiff_apply: Can't gzdopen descriptor %d\n", desc);
899 close(desc);
900 free(line);
901 free(lbuf);
902 return -1;
903 }
904
905 diffremain = difflen;
906 while(diffremain) {
907 unsigned int bufsize = diffremain < line_size ? diffremain + 1 : line_size;
908
909 if(!gzgets(gzh, line, bufsize)) {
910 logg("!cdiff_apply: Premature EOF at line %d\n", lines + 1);
911 cdiff_ctx_free(&ctx);
912 gzclose(gzh);
913 free(line);
914 free(lbuf);
915 return -1;
916 }
917 diffremain -= strlen(line);
918 lines++;
919 cli_chomp(line);
920
921 if(!strlen(line))
922 continue;
923 if(line[0] == '#') {
924 if(!strncmp(line, "#LSIZE", 6) && sscanf(line, "#LSIZE %u", &line_size) == 1) {
925 char *r1, *r2;
926 if(line_size < CDIFF_LINE_SIZE || line_size > 10485760) {
927 logg("^cdiff_apply: Ignoring new buffer size request - invalid size %d\n", line_size);
928 line_size = CDIFF_LINE_SIZE;
929 continue;
930 }
931 r1 = realloc(line, line_size);
932 r2 = realloc(lbuf, line_size);
933 if(!r1 || !r2) {
934 logg("!cdiff_apply: Can't resize line buffer to %d bytes\n", line_size);
935 cdiff_ctx_free(&ctx);
936 gzclose(gzh);
937 if(!r1 && !r2) {
938 free(line);
939 free(lbuf);
940 } else if(!r1) {
941 free(line);
942 free(r2);
943 } else {
944 free(r1);
945 free(lbuf);
946 }
947 return -1;
948 }
949 line = r1;
950 lbuf = r2;
951 }
952 continue;
953 }
954
955 if(cdiff_execute(line, &ctx, lbuf, line_size) == -1) {
956 logg("!cdiff_apply: Error executing command at line %d\n", lines);
957 cdiff_ctx_free(&ctx);
958 gzclose(gzh);
959 free(line);
960 free(lbuf);
961 return -1;
962 } else {
963 cmds++;
964 }
965 }
966 gzclose(gzh);
967
968 } else { /* .script */
969
970 if(!(fh = fdopen(desc, "rb"))) {
971 logg("!cdiff_apply: fdopen() failed for descriptor %d\n", desc);
972 close(desc);
973 free(line);
974 free(lbuf);
975 return -1;
976 }
977
978 while(fgets(line, line_size, fh)) {
979 lines++;
980 cli_chomp(line);
981
982 if(!strlen(line))
983 continue;
984 if(line[0] == '#') {
985 if(!strncmp(line, "#LSIZE", 6) && sscanf(line, "#LSIZE %u", &line_size) == 1) {
986 char *r1, *r2;
987 if(line_size < CDIFF_LINE_SIZE || line_size > 10485760) {
988 logg("^cdiff_apply: Ignoring new buffer size request - invalid size %d\n", line_size);
989 line_size = CDIFF_LINE_SIZE;
990 continue;
991 }
992 r1 = realloc(line, line_size);
993 r2 = realloc(lbuf, line_size);
994 if(!r1 || !r2) {
995 logg("!cdiff_apply: Can't resize line buffer to %d bytes\n", line_size);
996 cdiff_ctx_free(&ctx);
997 fclose(fh);
998 if(!r1 && !r2) {
999 free(line);
1000 free(lbuf);
1001 } else if(!r1) {
1002 free(line);
1003 free(r2);
1004 } else {
1005 free(r1);
1006 free(lbuf);
1007 }
1008 return -1;
1009 }
1010 line = r1;
1011 lbuf = r2;
1012 }
1013 continue;
1014 }
1015
1016 if(cdiff_execute(line, &ctx, lbuf, line_size) == -1) {
1017 logg("!cdiff_apply: Error executing command at line %d\n", lines);
1018 cdiff_ctx_free(&ctx);
1019 fclose(fh);
1020 free(line);
1021 free(lbuf);
1022 return -1;
1023 } else {
1024 cmds++;
1025 }
1026 }
1027
1028 fclose(fh);
1029 }
1030
1031 free(line);
1032 free(lbuf);
1033
1034 if(ctx.open_db) {
1035 logg("*cdiff_apply: File %s was not properly closed\n", ctx.open_db);
1036 cdiff_ctx_free(&ctx);
1037 return -1;
1038 }
1039
1040 logg("*cdiff_apply: Parsed %d lines and executed %d commands\n", lines, cmds);
1041 return 0;
1042}
Note: See TracBrowser for help on using the repository browser.