1 /*
2 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 * Copyright (C) 2007-2013 Sourcefire, Inc.
4 *
5 * Authors: Tomasz Kojm
6 *
7 * Summary: Code to parse Clamav CVD database format.
8 *
9 * Acknowledgements: ClamAV untar code is based on a public domain minitar utility
10 * by Charles G. Waldman.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 * MA 02110-1301, USA.
25 */
26
27 #if HAVE_CONFIG_H
28 #include "clamav-config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include "zlib.h"
41 #include <time.h>
42 #include <errno.h>
43
44 #include "clamav.h"
45 #include "others.h"
46 #include "dsig.h"
47 #include "str.h"
48 #include "cvd.h"
49 #include "readdb.h"
50 #include "default.h"
51
52 #define TAR_BLOCKSIZE 512
53
cli_untgz_cleanup(char * path,gzFile infile,FILE * outfile,int fdd)54 static void cli_untgz_cleanup(char *path, gzFile infile, FILE *outfile, int fdd)
55 {
56 UNUSEDPARAM(fdd);
57 cli_dbgmsg("in cli_untgz_cleanup()\n");
58 if (path != NULL)
59 free(path);
60 if (infile != NULL)
61 gzclose(infile);
62 if (outfile != NULL)
63 fclose(outfile);
64 }
65
cli_untgz(int fd,const char * destdir)66 static int cli_untgz(int fd, const char *destdir)
67 {
68 char *path, osize[13], name[101], type;
69 char block[TAR_BLOCKSIZE];
70 int nbytes, nread, nwritten, in_block = 0, fdd = -1;
71 unsigned int size, pathlen = strlen(destdir) + 100 + 5;
72 FILE *outfile = NULL;
73 STATBUF foo;
74 gzFile infile = NULL;
75
76 cli_dbgmsg("in cli_untgz()\n");
77
78 if ((fdd = dup(fd)) == -1) {
79 cli_errmsg("cli_untgz: Can't duplicate descriptor %d\n", fd);
80 return -1;
81 }
82
83 if ((infile = gzdopen(fdd, "rb")) == NULL) {
84 cli_errmsg("cli_untgz: Can't gzdopen() descriptor %d, errno = %d\n", fdd, errno);
85 if (FSTAT(fdd, &foo) == 0)
86 close(fdd);
87 return -1;
88 }
89
90 path = (char *)cli_calloc(sizeof(char), pathlen);
91 if (!path) {
92 cli_errmsg("cli_untgz: Can't allocate memory for path\n");
93 cli_untgz_cleanup(NULL, infile, NULL, fdd);
94 return -1;
95 }
96
97 while (1) {
98
99 nread = gzread(infile, block, TAR_BLOCKSIZE);
100
101 if (!in_block && !nread)
102 break;
103
104 if (nread != TAR_BLOCKSIZE) {
105 cli_errmsg("cli_untgz: Incomplete block read\n");
106 cli_untgz_cleanup(path, infile, outfile, fdd);
107 return -1;
108 }
109
110 if (!in_block) {
111 if (block[0] == '\0') /* We're done */
112 break;
113
114 strncpy(name, block, 100);
115 name[100] = '\0';
116
117 if (strchr(name, '/')) {
118 cli_errmsg("cli_untgz: Slash separators are not allowed in CVD\n");
119 cli_untgz_cleanup(path, infile, outfile, fdd);
120 return -1;
121 }
122
123 snprintf(path, pathlen, "%s" PATHSEP "%s", destdir, name);
124 cli_dbgmsg("cli_untgz: Unpacking %s\n", path);
125 type = block[156];
126
127 switch (type) {
128 case '0':
129 case '\0':
130 break;
131 case '5':
132 cli_errmsg("cli_untgz: Directories are not supported in CVD\n");
133 cli_untgz_cleanup(path, infile, outfile, fdd);
134 return -1;
135 default:
136 cli_errmsg("cli_untgz: Unknown type flag '%c'\n", type);
137 cli_untgz_cleanup(path, infile, outfile, fdd);
138 return -1;
139 }
140
141 if (outfile) {
142 if (fclose(outfile)) {
143 cli_errmsg("cli_untgz: Cannot close file %s\n", path);
144 outfile = NULL;
145 cli_untgz_cleanup(path, infile, outfile, fdd);
146 return -1;
147 }
148 outfile = NULL;
149 }
150
151 if (!(outfile = fopen(path, "wb"))) {
152 cli_errmsg("cli_untgz: Cannot create file %s\n", path);
153 cli_untgz_cleanup(path, infile, outfile, fdd);
154 return -1;
155 }
156
157 strncpy(osize, block + 124, 12);
158 osize[12] = '\0';
159
160 if ((sscanf(osize, "%o", &size)) == 0) {
161 cli_errmsg("cli_untgz: Invalid size in header\n");
162 cli_untgz_cleanup(path, infile, outfile, fdd);
163 return -1;
164 }
165
166 if (size > 0)
167 in_block = 1;
168
169 } else { /* write or continue writing file contents */
170 nbytes = size > TAR_BLOCKSIZE ? TAR_BLOCKSIZE : size;
171 nwritten = fwrite(block, 1, nbytes, outfile);
172
173 if (nwritten != nbytes) {
174 cli_errmsg("cli_untgz: Wrote %d instead of %d (%s)\n", nwritten, nbytes, path);
175 cli_untgz_cleanup(path, infile, outfile, fdd);
176 return -1;
177 }
178
179 size -= nbytes;
180 if (size == 0)
181 in_block = 0;
182 }
183 }
184
185 cli_untgz_cleanup(path, infile, outfile, fdd);
186 return 0;
187 }
188
cli_tgzload_cleanup(int comp,struct cli_dbio * dbio,int fdd)189 static void cli_tgzload_cleanup(int comp, struct cli_dbio *dbio, int fdd)
190 {
191 UNUSEDPARAM(fdd);
192 cli_dbgmsg("in cli_tgzload_cleanup()\n");
193 if (comp) {
194 gzclose(dbio->gzs);
195 dbio->gzs = NULL;
196 } else {
197 fclose(dbio->fs);
198 dbio->fs = NULL;
199 }
200 if (dbio->buf != NULL) {
201 free(dbio->buf);
202 dbio->buf = NULL;
203 }
204
205 if (dbio->hashctx) {
206 cl_hash_destroy(dbio->hashctx);
207 dbio->hashctx = NULL;
208 }
209 }
210
cli_tgzload(int fd,struct cl_engine * engine,unsigned int * signo,unsigned int options,struct cli_dbio * dbio,struct cli_dbinfo * dbinfo)211 static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, struct cli_dbinfo *dbinfo)
212 {
213 char osize[13], name[101];
214 char block[TAR_BLOCKSIZE];
215 int nread, fdd, ret;
216 unsigned int type, size, pad, compr = 1;
217 off_t off;
218 struct cli_dbinfo *db;
219 char hash[32];
220
221 cli_dbgmsg("in cli_tgzload()\n");
222
223 if (lseek(fd, 512, SEEK_SET) < 0) {
224 return CL_ESEEK;
225 }
226
227 if (cli_readn(fd, block, 7) != 7)
228 return CL_EFORMAT; /* truncated file? */
229
230 if (!strncmp(block, "COPYING", 7))
231 compr = 0;
232
233 if (lseek(fd, 512, SEEK_SET) < 0) {
234 return CL_ESEEK;
235 }
236
237 if ((fdd = dup(fd)) == -1) {
238 cli_errmsg("cli_tgzload: Can't duplicate descriptor %d\n", fd);
239 return CL_EDUP;
240 }
241
242 if (compr) {
243 if ((dbio->gzs = gzdopen(fdd, "rb")) == NULL) {
244 cli_errmsg("cli_tgzload: Can't gzdopen() descriptor %d, errno = %d\n", fdd, errno);
245 if (fdd > -1)
246 close(fdd);
247 return CL_EOPEN;
248 }
249 dbio->fs = NULL;
250 } else {
251 if ((dbio->fs = fdopen(fdd, "rb")) == NULL) {
252 cli_errmsg("cli_tgzload: Can't fdopen() descriptor %d, errno = %d\n", fdd, errno);
253 if (fdd > -1)
254 close(fdd);
255 return CL_EOPEN;
256 }
257 dbio->gzs = NULL;
258 }
259
260 dbio->bufsize = CLI_DEFAULT_DBIO_BUFSIZE;
261 dbio->buf = cli_malloc(dbio->bufsize);
262 if (!dbio->buf) {
263 cli_errmsg("cli_tgzload: Can't allocate memory for dbio->buf\n");
264 cli_tgzload_cleanup(compr, dbio, fdd);
265 return CL_EMALFDB;
266 }
267 dbio->bufpt = NULL;
268 dbio->usebuf = 1;
269 dbio->readpt = dbio->buf;
270
271 while (1) {
272
273 if (compr)
274 nread = gzread(dbio->gzs, block, TAR_BLOCKSIZE);
275 else
276 nread = fread(block, 1, TAR_BLOCKSIZE, dbio->fs);
277
278 if (!nread)
279 break;
280
281 if (nread != TAR_BLOCKSIZE) {
282 cli_errmsg("cli_tgzload: Incomplete block read\n");
283 cli_tgzload_cleanup(compr, dbio, fdd);
284 return CL_EMALFDB;
285 }
286
287 if (block[0] == '\0') /* We're done */
288 break;
289
290 strncpy(name, block, 100);
291 name[100] = '\0';
292
293 if (strchr(name, '/')) {
294 cli_errmsg("cli_tgzload: Slash separators are not allowed in CVD\n");
295 cli_tgzload_cleanup(compr, dbio, fdd);
296 return CL_EMALFDB;
297 }
298
299 type = block[156];
300
301 switch (type) {
302 case '0':
303 case '\0':
304 break;
305 case '5':
306 cli_errmsg("cli_tgzload: Directories are not supported in CVD\n");
307 cli_tgzload_cleanup(compr, dbio, fdd);
308 return CL_EMALFDB;
309 default:
310 cli_errmsg("cli_tgzload: Unknown type flag '%c'\n", type);
311 cli_tgzload_cleanup(compr, dbio, fdd);
312 return CL_EMALFDB;
313 }
314
315 strncpy(osize, block + 124, 12);
316 osize[12] = '\0';
317
318 if ((sscanf(osize, "%o", &size)) == 0) {
319 cli_errmsg("cli_tgzload: Invalid size in header\n");
320 cli_tgzload_cleanup(compr, dbio, fdd);
321 return CL_EMALFDB;
322 }
323 dbio->size = size;
324 dbio->readsize = dbio->size < dbio->bufsize ? dbio->size : dbio->bufsize - 1;
325 dbio->bufpt = NULL;
326 dbio->readpt = dbio->buf;
327 if (!(dbio->hashctx)) {
328 dbio->hashctx = cl_hash_init("sha256");
329 if (!(dbio->hashctx)) {
330 cli_tgzload_cleanup(compr, dbio, fdd);
331 return CL_EMALFDB;
332 }
333 }
334 dbio->bread = 0;
335
336 /* cli_dbgmsg("cli_tgzload: Loading %s, size: %u\n", name, size); */
337 if (compr)
338 off = (off_t)gzseek(dbio->gzs, 0, SEEK_CUR);
339 else
340 off = ftell(dbio->fs);
341
342 if ((!dbinfo && cli_strbcasestr(name, ".info")) || (dbinfo && CLI_DBEXT(name))) {
343 ret = cli_load(name, engine, signo, options, dbio);
344 if (ret) {
345 cli_errmsg("cli_tgzload: Can't load %s\n", name);
346 cli_tgzload_cleanup(compr, dbio, fdd);
347 return CL_EMALFDB;
348 }
349 if (!dbinfo) {
350 cli_tgzload_cleanup(compr, dbio, fdd);
351 return CL_SUCCESS;
352 } else {
353 db = dbinfo;
354 while (db && strcmp(db->name, name))
355 db = db->next;
356 if (!db) {
357 cli_errmsg("cli_tgzload: File %s not found in .info\n", name);
358 cli_tgzload_cleanup(compr, dbio, fdd);
359 return CL_EMALFDB;
360 }
361 if (dbio->bread) {
362 if (db->size != dbio->bread) {
363 cli_errmsg("cli_tgzload: File %s not correctly loaded\n", name);
364 cli_tgzload_cleanup(compr, dbio, fdd);
365 return CL_EMALFDB;
366 }
367 cl_finish_hash(dbio->hashctx, hash);
368 dbio->hashctx = cl_hash_init("sha256");
369 if (!(dbio->hashctx)) {
370 cli_tgzload_cleanup(compr, dbio, fdd);
371 return CL_EMALFDB;
372 }
373 if (memcmp(db->hash, hash, 32)) {
374 cli_errmsg("cli_tgzload: Invalid checksum for file %s\n", name);
375 cli_tgzload_cleanup(compr, dbio, fdd);
376 return CL_EMALFDB;
377 }
378 }
379 }
380 }
381 pad = size % TAR_BLOCKSIZE ? (TAR_BLOCKSIZE - (size % TAR_BLOCKSIZE)) : 0;
382 if (compr) {
383 if (off == gzseek(dbio->gzs, 0, SEEK_CUR))
384 gzseek(dbio->gzs, size + pad, SEEK_CUR);
385 else if (pad)
386 gzseek(dbio->gzs, pad, SEEK_CUR);
387 } else {
388 if (off == ftell(dbio->fs))
389 fseek(dbio->fs, size + pad, SEEK_CUR);
390 else if (pad)
391 fseek(dbio->fs, pad, SEEK_CUR);
392 }
393 }
394
395 cli_tgzload_cleanup(compr, dbio, fdd);
396 return CL_SUCCESS;
397 }
398
cl_cvdparse(const char * head)399 struct cl_cvd *cl_cvdparse(const char *head)
400 {
401 struct cl_cvd *cvd;
402 char *pt;
403
404 if (strncmp(head, "ClamAV-VDB:", 11)) {
405 cli_errmsg("cli_cvdparse: Not a CVD file\n");
406 return NULL;
407 }
408
409 if (!(cvd = (struct cl_cvd *)cli_malloc(sizeof(struct cl_cvd)))) {
410 cli_errmsg("cl_cvdparse: Can't allocate memory for cvd\n");
411 return NULL;
412 }
413
414 if (!(cvd->time = cli_strtok(head, 1, ":"))) {
415 cli_errmsg("cli_cvdparse: Can't parse the creation time\n");
416 free(cvd);
417 return NULL;
418 }
419
420 if (!(pt = cli_strtok(head, 2, ":"))) {
421 cli_errmsg("cli_cvdparse: Can't parse the version number\n");
422 free(cvd->time);
423 free(cvd);
424 return NULL;
425 }
426 cvd->version = atoi(pt);
427 free(pt);
428
429 if (!(pt = cli_strtok(head, 3, ":"))) {
430 cli_errmsg("cli_cvdparse: Can't parse the number of signatures\n");
431 free(cvd->time);
432 free(cvd);
433 return NULL;
434 }
435 cvd->sigs = atoi(pt);
436 free(pt);
437
438 if (!(pt = cli_strtok(head, 4, ":"))) {
439 cli_errmsg("cli_cvdparse: Can't parse the functionality level\n");
440 free(cvd->time);
441 free(cvd);
442 return NULL;
443 }
444 cvd->fl = atoi(pt);
445 free(pt);
446
447 if (!(cvd->md5 = cli_strtok(head, 5, ":"))) {
448 cli_errmsg("cli_cvdparse: Can't parse the MD5 checksum\n");
449 free(cvd->time);
450 free(cvd);
451 return NULL;
452 }
453
454 if (!(cvd->dsig = cli_strtok(head, 6, ":"))) {
455 cli_errmsg("cli_cvdparse: Can't parse the digital signature\n");
456 free(cvd->time);
457 free(cvd->md5);
458 free(cvd);
459 return NULL;
460 }
461
462 if (!(cvd->builder = cli_strtok(head, 7, ":"))) {
463 cli_errmsg("cli_cvdparse: Can't parse the builder name\n");
464 free(cvd->time);
465 free(cvd->md5);
466 free(cvd->dsig);
467 free(cvd);
468 return NULL;
469 }
470
471 if ((pt = cli_strtok(head, 8, ":"))) {
472 cvd->stime = atoi(pt);
473 free(pt);
474 } else {
475 cli_dbgmsg("cli_cvdparse: No creation time in seconds (old file format)\n");
476 cvd->stime = 0;
477 }
478
479 return cvd;
480 }
481
cl_cvdhead(const char * file)482 struct cl_cvd *cl_cvdhead(const char *file)
483 {
484 FILE *fs;
485 char head[513], *pt;
486 int i;
487 unsigned int bread;
488
489 if ((fs = fopen(file, "rb")) == NULL) {
490 cli_errmsg("cl_cvdhead: Can't open file %s\n", file);
491 return NULL;
492 }
493
494 if (!(bread = fread(head, 1, 512, fs))) {
495 cli_errmsg("cl_cvdhead: Can't read CVD header in %s\n", file);
496 fclose(fs);
497 return NULL;
498 }
499
500 fclose(fs);
501
502 head[bread] = 0;
503 if ((pt = strpbrk(head, "\n\r")))
504 *pt = 0;
505
506 for (i = bread - 1; i > 0 && (head[i] == ' ' || head[i] == '\n' || head[i] == '\r'); head[i] = 0, i--)
507 ;
508
509 return cl_cvdparse(head);
510 }
511
cl_cvdfree(struct cl_cvd * cvd)512 void cl_cvdfree(struct cl_cvd *cvd)
513 {
514 free(cvd->time);
515 free(cvd->md5);
516 free(cvd->dsig);
517 free(cvd->builder);
518 free(cvd);
519 }
520
cli_cvdverify(FILE * fs,struct cl_cvd * cvdpt,unsigned int skipsig)521 static int cli_cvdverify(FILE *fs, struct cl_cvd *cvdpt, unsigned int skipsig)
522 {
523 struct cl_cvd *cvd;
524 char *md5, head[513];
525 int i;
526
527 fseek(fs, 0, SEEK_SET);
528 if (fread(head, 1, 512, fs) != 512) {
529 cli_errmsg("cli_cvdverify: Can't read CVD header\n");
530 return CL_ECVD;
531 }
532
533 head[512] = 0;
534 for (i = 511; i > 0 && (head[i] == ' ' || head[i] == 10); head[i] = 0, i--)
535 ;
536
537 if ((cvd = cl_cvdparse(head)) == NULL)
538 return CL_ECVD;
539
540 if (cvdpt)
541 memcpy(cvdpt, cvd, sizeof(struct cl_cvd));
542
543 if (skipsig) {
544 cl_cvdfree(cvd);
545 return CL_SUCCESS;
546 }
547
548 md5 = cli_hashstream(fs, NULL, 1);
549 if (md5 == NULL) {
550 cli_dbgmsg("cli_cvdverify: Cannot generate hash, out of memory\n");
551 cl_cvdfree(cvd);
552 return CL_EMEM;
553 }
554 cli_dbgmsg("MD5(.tar.gz) = %s\n", md5);
555
556 if (strncmp(md5, cvd->md5, 32)) {
557 cli_dbgmsg("cli_cvdverify: MD5 verification error\n");
558 free(md5);
559 cl_cvdfree(cvd);
560 return CL_EVERIFY;
561 }
562
563 if (cli_versig(md5, cvd->dsig)) {
564 cli_dbgmsg("cli_cvdverify: Digital signature verification error\n");
565 free(md5);
566 cl_cvdfree(cvd);
567 return CL_EVERIFY;
568 }
569
570 free(md5);
571 cl_cvdfree(cvd);
572 return CL_SUCCESS;
573 }
574
cl_cvdverify(const char * file)575 cl_error_t cl_cvdverify(const char *file)
576 {
577 struct cl_engine *engine;
578 FILE *fs;
579 cl_error_t ret;
580 int dbtype = 0;
581
582 if ((fs = fopen(file, "rb")) == NULL) {
583 cli_errmsg("cl_cvdverify: Can't open file %s\n", file);
584 return CL_EOPEN;
585 }
586
587 if (!(engine = cl_engine_new())) {
588 cli_errmsg("cld_cvdverify: Can't create new engine\n");
589 fclose(fs);
590 return CL_EMEM;
591 }
592 engine->cb_stats_submit = NULL; /* Don't submit stats if we're just verifying a CVD */
593
594 if (!!cli_strbcasestr(file, ".cld"))
595 dbtype = 1;
596 else if (!!cli_strbcasestr(file, ".cud"))
597 dbtype = 2;
598
599 ret = cli_cvdload(fs, engine, NULL, CL_DB_STDOPT | CL_DB_PUA, dbtype, file, 1);
600
601 cl_engine_free(engine);
602 fclose(fs);
603 return ret;
604 }
605
cli_cvdload(FILE * fs,struct cl_engine * engine,unsigned int * signo,unsigned int options,unsigned int dbtype,const char * filename,unsigned int chkonly)606 int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, unsigned int dbtype, const char *filename, unsigned int chkonly)
607 {
608 struct cl_cvd cvd, dupcvd;
609 FILE *dupfs;
610 int ret;
611 time_t s_time;
612 int cfd;
613 struct cli_dbio dbio;
614 struct cli_dbinfo *dbinfo = NULL;
615 char *dupname;
616
617 dbio.hashctx = NULL;
618
619 cli_dbgmsg("in cli_cvdload()\n");
620
621 /* verify */
622 if ((ret = cli_cvdverify(fs, &cvd, dbtype)))
623 return ret;
624
625 if (dbtype <= 1) {
626 /* check for duplicate db */
627 dupname = cli_strdup(filename);
628 if (!dupname)
629 return CL_EMEM;
630 dupname[strlen(dupname) - 2] = (dbtype == 1 ? 'v' : 'l');
631 if (!access(dupname, R_OK) && (dupfs = fopen(dupname, "rb"))) {
632 if ((ret = cli_cvdverify(dupfs, &dupcvd, !dbtype))) {
633 fclose(dupfs);
634 free(dupname);
635 return ret;
636 }
637 fclose(dupfs);
638 if (dupcvd.version > cvd.version) {
639 cli_warnmsg("Detected duplicate databases %s and %s. The %s database is older and will not be loaded, you should manually remove it from the database directory.\n", filename, dupname, filename);
640 free(dupname);
641 return CL_SUCCESS;
642 } else if (dupcvd.version == cvd.version && !dbtype) {
643 cli_warnmsg("Detected duplicate databases %s and %s, please manually remove one of them\n", filename, dupname);
644 free(dupname);
645 return CL_SUCCESS;
646 }
647 }
648 free(dupname);
649 }
650
651 if (strstr(filename, "daily.")) {
652 time(&s_time);
653 if (cvd.stime > s_time) {
654 if (cvd.stime - (unsigned int)s_time > 3600) {
655 cli_warnmsg("******************************************************\n");
656 cli_warnmsg("*** Virus database timestamp in the future! ***\n");
657 cli_warnmsg("*** Please check the timezone and clock settings ***\n");
658 cli_warnmsg("******************************************************\n");
659 }
660 } else if ((unsigned int)s_time - cvd.stime > 604800) {
661 cli_warnmsg("**************************************************\n");
662 cli_warnmsg("*** The virus database is older than 7 days! ***\n");
663 cli_warnmsg("*** Please update it as soon as possible. ***\n");
664 cli_warnmsg("**************************************************\n");
665 }
666 engine->dbversion[0] = cvd.version;
667 engine->dbversion[1] = cvd.stime;
668 }
669
670 if (cvd.fl > cl_retflevel()) {
671 cli_warnmsg("*******************************************************************\n");
672 cli_warnmsg("*** This version of the ClamAV engine is outdated. ***\n");
673 cli_warnmsg("*** Read https://docs.clamav.net/manual/Installing.html ***\n");
674 cli_warnmsg("*******************************************************************\n");
675 }
676
677 cfd = fileno(fs);
678 dbio.chkonly = 0;
679 if (dbtype == 2)
680 ret = cli_tgzload(cfd, engine, signo, options | CL_DB_UNSIGNED, &dbio, NULL);
681 else
682 ret = cli_tgzload(cfd, engine, signo, options | CL_DB_OFFICIAL, &dbio, NULL);
683 if (ret != CL_SUCCESS)
684 return ret;
685
686 dbinfo = engine->dbinfo;
687 if (!dbinfo || !dbinfo->cvd || (dbinfo->cvd->version != cvd.version) || (dbinfo->cvd->sigs != cvd.sigs) || (dbinfo->cvd->fl != cvd.fl) || (dbinfo->cvd->stime != cvd.stime)) {
688 cli_errmsg("cli_cvdload: Corrupted CVD header\n");
689 return CL_EMALFDB;
690 }
691 dbinfo = engine->dbinfo ? engine->dbinfo->next : NULL;
692 if (!dbinfo) {
693 cli_errmsg("cli_cvdload: dbinfo error\n");
694 return CL_EMALFDB;
695 }
696
697 dbio.chkonly = chkonly;
698 if (dbtype == 2)
699 options |= CL_DB_UNSIGNED;
700 else
701 options |= CL_DB_SIGNED | CL_DB_OFFICIAL;
702
703 ret = cli_tgzload(cfd, engine, signo, options, &dbio, dbinfo);
704
705 while (engine->dbinfo) {
706 dbinfo = engine->dbinfo;
707 engine->dbinfo = dbinfo->next;
708 MPOOL_FREE(engine->mempool, dbinfo->name);
709 MPOOL_FREE(engine->mempool, dbinfo->hash);
710 if (dbinfo->cvd)
711 cl_cvdfree(dbinfo->cvd);
712 MPOOL_FREE(engine->mempool, dbinfo);
713 }
714
715 return ret;
716 }
717
cli_cvdunpack(const char * file,const char * dir)718 int cli_cvdunpack(const char *file, const char *dir)
719 {
720 int fd, ret;
721
722 fd = open(file, O_RDONLY | O_BINARY);
723 if (fd == -1)
724 return -1;
725
726 if (lseek(fd, 512, SEEK_SET) < 0) {
727 close(fd);
728 return -1;
729 }
730
731 ret = cli_untgz(fd, dir);
732 close(fd);
733 return ret;
734 }
735