static void htmlnorm_teardown(void) { dconf_teardown(); /* can't call fail() functions in teardown, it can cause SEGV */ cli_rmdirs(dir); free(dir); dir = NULL; }
int cli_scannulsft(cli_ctx *ctx, off_t offset) { int ret; struct nsis_st nsist; cli_dbgmsg("in scannulsft()\n"); memset(&nsist, 0, sizeof(struct nsis_st)); nsist.off = offset; if (!(nsist.dir = cli_gentemp(ctx->engine->tmpdir))) return CL_ETMPDIR; if(mkdir(nsist.dir, 0700)) { cli_dbgmsg("NSIS: Can't create temporary directory %s\n", nsist.dir); free(nsist.dir); return CL_ETMPDIR; } nsist.map = *ctx->fmap; if(ctx->engine->keeptmp) cli_dbgmsg("NSIS: Extracting files to %s\n", nsist.dir); do { ret = cli_nsis_unpack(&nsist, ctx); if (ret == CL_SUCCESS && nsist.opened == 0) { /* Don't scan a non-existent file */ continue; } if (ret == CL_SUCCESS) { cli_dbgmsg("NSIS: Successully extracted file #%u\n", nsist.fno); if (lseek(nsist.ofd, 0, SEEK_SET) == -1) { cli_dbgmsg("NSIS: call to lseek() failed\n"); free(nsist.dir); return CL_ESEEK; } if(nsist.fno == 1) ret=cli_scandesc(nsist.ofd, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL); else ret=cli_magic_scandesc(nsist.ofd, ctx); close(nsist.ofd); if(!ctx->engine->keeptmp) if(cli_unlink(nsist.ofn)) ret = CL_EUNLINK; } else if(ret == CL_EMAXSIZE) { ret = nsist.solid ? CL_BREAK : CL_SUCCESS; } } while(ret == CL_SUCCESS); if(ret == CL_BREAK || ret == CL_EMAXFILES) ret = CL_CLEAN; nsis_shutdown(&nsist); if(!ctx->engine->keeptmp) cli_rmdirs(nsist.dir); free(nsist.dir); return ret; }
static void jstest_teardown(void) { if(tmpdir) { cli_rmdirs(tmpdir); free(tmpdir); } cli_js_destroy(state); state = NULL; }
END_TEST #endif START_TEST(test_screnc_nullterminate) { int fd = open_testfile("input/screnc_test"); fmap_t *map; fail_unless(mkdir(dir, 0700) == 0,"mkdir failed"); map = fmap(fd, 0, 0); fail_unless(!!map, "fmap failed"); fail_unless(html_screnc_decode(map, dir) == 1, "html_screnc_decode failed"); funmap(map); fail_unless(cli_rmdirs(dir) == 0, "rmdirs failed"); close(fd); }
/* * TODO: * - strptime() is most likely not portable enough */ int submitstats(const char *clamdcfg, const struct optstruct *opts) { int fd, sd, bread, lread = 0, cnt, ret; char post[SUBMIT_MIN_ENTRIES * 256 + 512]; char query[SUBMIT_MIN_ENTRIES * 256]; char buff[512], statsdat[512], newstatsdat[512], uastr[128]; char logfile[256], fbuff[FILEBUFF]; char *pt, *pt2, *auth = NULL; const char *line, *country = NULL, *user, *proxy = NULL; struct optstruct *clamdopt; const struct optstruct *opt; struct stat sb; struct tm tms; time_t epoch; unsigned int qcnt, entries, submitted = 0, permfail = 0, port = 0; if((opt = optget(opts, "DetectionStatsCountry"))->enabled) { if(strlen(opt->strarg) != 2 || !isalpha(opt->strarg[0]) || !isalpha(opt->strarg[1])) { logg("!SubmitDetectionStats: DetectionStatsCountry requires a two-letter country code\n"); return 56; } country = opt->strarg; } if(!(clamdopt = optparse(clamdcfg, 0, NULL, 1, OPT_CLAMD, 0, NULL))) { logg("!SubmitDetectionStats: Can't open or parse configuration file %s\n", clamdcfg); return 56; } if(!(opt = optget(clamdopt, "LogFile"))->enabled) { logg("!SubmitDetectionStats: LogFile needs to be enabled in %s\n", clamdcfg); optfree(clamdopt); return 56; } strncpy(logfile, opt->strarg, sizeof(logfile)); logfile[sizeof(logfile) - 1] = 0; if(!optget(clamdopt, "LogTime")->enabled) { logg("!SubmitDetectionStats: LogTime needs to be enabled in %s\n", clamdcfg); optfree(clamdopt); return 56; } optfree(clamdopt); if((fd = open("stats.dat", O_RDONLY)) != -1) { if((bread = read(fd, statsdat, sizeof(statsdat) - 1)) == -1) { logg("^SubmitDetectionStats: Can't read stats.dat\n"); bread = 0; } statsdat[bread] = 0; close(fd); } else { *statsdat = 0; } if((fd = open(logfile, O_RDONLY)) == -1) { logg("!SubmitDetectionStats: Can't open %s for reading\n", logfile); return 56; } if(fstat(fd, &sb) == -1) { logg("!SubmitDetectionStats: fstat() failed\n"); close(fd); return 56; } while((line = readbline(fd, fbuff, FILEBUFF, sb.st_size, &lread))) if(strlen(line) >= 32 && !strcmp(&line[strlen(line) - 6], " FOUND")) break; if(!line) { logg("SubmitDetectionStats: No detection records found\n"); close(fd); return 1; } if(*statsdat && !strcmp(line, statsdat)) { logg("SubmitDetectionStats: No new detection records found\n"); close(fd); return 1; } else { strncpy(newstatsdat, line, sizeof(newstatsdat)); } if((opt = optget(opts, "HTTPUserAgent"))->enabled) strncpy(uastr, opt->strarg, sizeof(uastr)); else snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")%s%s", get_version(), country ? ":" : "", country ? country : ""); uastr[sizeof(uastr) - 1] = 0; if((opt = optget(opts, "HTTPProxyServer"))->enabled) { proxy = opt->strarg; if(!strncasecmp(proxy, "http://", 7)) proxy += 7; if((opt = optget(opts, "HTTPProxyUsername"))->enabled) { user = opt->strarg; if(!(opt = optget(opts, "HTTPProxyPassword"))->enabled) { logg("!SubmitDetectionStats: HTTPProxyUsername requires HTTPProxyPassword\n"); close(fd); return 56; } auth = proxyauth(user, opt->strarg); if(!auth) { close(fd); return 56; } } if((opt = optget(opts, "HTTPProxyPort"))->enabled) port = opt->numarg; logg("*Connecting via %s\n", proxy); } ret = 0; memset(query, 0, sizeof(query)); qcnt = 0; entries = 0; do { if(strlen(line) < 32 || strcmp(&line[strlen(line) - 6], " FOUND")) continue; if(*statsdat && !strcmp(line, statsdat)) break; strncpy(buff, line, sizeof(buff)); buff[sizeof(buff) - 1] = 0; if(!(pt = strstr(buff, " -> "))) { logg("*SubmitDetectionStats: Skipping detection entry logged without time\b"); continue; } *pt = 0; pt += 4; if(!strptime(buff, "%a %b %d %H:%M:%S %Y", &tms) || (epoch = mktime(&tms)) == -1) { logg("!SubmitDetectionStats: Failed to convert date string\n"); ret = 1; break; } pt2 = &pt[strlen(pt) - 6]; *pt2 = 0; if(!(pt2 = strrchr(pt, ':'))) { logg("!SubmitDetectionStats: Incorrect format of the log file (1)\n"); ret = 1; break; } *pt2 = 0; pt2 += 2; #ifdef C_WINDOWS if((pt = strrchr(pt, '\\'))) #else if((pt = strrchr(pt, '/'))) #endif *pt++ = 0; if(!pt) pt = (char*) "NOFNAME"; qcnt += snprintf(&query[qcnt], sizeof(query) - qcnt, "ts[]=%u&fname[]=%s&virus[]=%s&", (unsigned int) epoch, pt, pt2); entries++; if(entries == SUBMIT_MIN_ENTRIES) { sd = wwwconnect("stats.clamav.net", proxy, port, NULL, optget(opts, "LocalIPAddress")->strarg, optget(opts, "ConnectTimeout")->numarg, NULL, 0, 0); if(sd == -1) { logg("!SubmitDetectionStats: Can't connect to server\n"); ret = 52; break; } query[sizeof(query) - 1] = 0; snprintf(post, sizeof(post), "POST http://stats.clamav.net/submit.php HTTP/1.0\r\n" "Host: stats.clamav.net\r\n%s" "Content-Type: application/x-www-form-urlencoded\r\n" "User-Agent: %s\r\n" "Content-Length: %u\r\n\n" "%s", auth ? auth : "", uastr, (unsigned int) strlen(query), query); if(send(sd, post, strlen(post), 0) < 0) { logg("!SubmitDetectionStats: Can't write to socket\n"); ret = 52; closesocket(sd); break; } pt = post; cnt = sizeof(post) - 1; #ifdef SO_ERROR while((bread = wait_recv(sd, pt, cnt, 0, optget(opts, "ReceiveTimeout")->numarg)) > 0) { #else while((bread = recv(sd, pt, cnt, 0)) > 0) { #endif pt += bread; cnt -= bread; if(cnt <= 0) break; } *pt = 0; closesocket(sd); if(bread < 0) { logg("!SubmitDetectionStats: Can't read from socket\n"); ret = 52; break; } if(strstr(post, "SUBMIT_OK")) { submitted += entries; if(submitted + SUBMIT_MIN_ENTRIES > SUBMIT_MAX_ENTRIES) break; qcnt = 0; entries = 0; memset(query, 0, sizeof(query)); continue; } ret = 52; if((pt = strstr(post, "SUBMIT_PERMANENT_FAILURE"))) { if(!submitted) { permfail = 1; if((pt + 32 <= post + sizeof(post)) && pt[24] == ':') logg("!SubmitDetectionStats: Remote server reported permanent failure: %s\n", &pt[25]); else logg("!SubmitDetectionStats: Remote server reported permanent failure\n"); } } else if((pt = strstr(post, "SUBMIT_TEMPORARY_FAILURE"))) { if(!submitted) { if((pt + 32 <= post + sizeof(post)) && pt[24] == ':') logg("!SubmitDetectionStats: Remote server reported temporary failure: %s\n", &pt[25]); else logg("!SubmitDetectionStats: Remote server reported temporary failure\n"); } } else { if(!submitted) logg("!SubmitDetectionStats: Incorrect answer from server\n"); } break; } } while((line = readbline(fd, fbuff, FILEBUFF, sb.st_size, &lread))); close(fd); if(auth) free(auth); if(submitted || permfail) { if((fd = open("stats.dat", O_WRONLY | O_CREAT | O_TRUNC, 0600)) == -1) { logg("^SubmitDetectionStats: Can't open stats.dat for writing\n"); } else { if((bread = write(fd, newstatsdat, sizeof(newstatsdat))) != sizeof(newstatsdat)) logg("^SubmitDetectionStats: Can't write to stats.dat\n"); close(fd); } } if(ret == 0) { if(!submitted) logg("SubmitDetectionStats: Not enough recent data for submission\n"); else logg("SubmitDetectionStats: Submitted %u records\n", submitted); } return ret; } static int Rfc2822DateTime(char *buf, time_t mtime) { struct tm *gmt; gmt = gmtime(&mtime); return strftime(buf, 36, "%a, %d %b %Y %X GMT", gmt); } static struct cl_cvd *remote_cvdhead(const char *cvdfile, const char *localfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int *ims, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist) { char cmd[512], head[513], buffer[FILEBUFF], ipaddr[46], *ch, *tmp; int bread, cnt, sd; unsigned int i, j; char *remotename = NULL, *authorization = NULL; struct cl_cvd *cvd; char last_modified[36], uastr[128]; if(proxy) { remotename = malloc(strlen(hostname) + 8); if(!remotename) { logg("!remote_cvdhead: Can't allocate memory for 'remotename'\n"); return NULL; } sprintf(remotename, "http://%s", hostname); if(user) { authorization = proxyauth(user, pass); if(!authorization) { free(remotename); return NULL; } } } if(!access(localfile, R_OK)) { cvd = cl_cvdhead(localfile); if(!cvd) { logg("!remote_cvdhead: Can't parse file %s\n", localfile); free(remotename); free(authorization); return NULL; } Rfc2822DateTime(last_modified, (time_t) cvd->stime); cl_cvdfree(cvd); } else { time_t mtime = 1104119530; Rfc2822DateTime(last_modified, mtime); logg("*Assuming modification time in the past\n"); } logg("*If-Modified-Since: %s\n", last_modified); logg("Reading CVD header (%s): ", cvdfile); if(uas) strncpy(uastr, uas, sizeof(uastr)); else snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version()); uastr[sizeof(uastr) - 1] = 0; snprintf(cmd, sizeof(cmd), "GET %s/%s HTTP/1.0\r\n" "Host: %s\r\n%s" "User-Agent: %s\r\n" "Connection: close\r\n" "Range: bytes=0-511\r\n" "If-Modified-Since: %s\r\n" "\r\n", (remotename != NULL) ? remotename : "", cvdfile, hostname, (authorization != NULL) ? authorization : "", uastr, last_modified); free(remotename); free(authorization); memset(ipaddr, 0, sizeof(ipaddr)); if(ip[0]) /* use ip to connect */ sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist); else sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist); if(sd < 0) { return NULL; } else { logg("*Connected to %s (IP: %s).\n", hostname, ipaddr); logg("*Trying to retrieve CVD header of http://%s/%s\n", hostname, cvdfile); } if(!ip[0]) strcpy(ip, ipaddr); if(send(sd, cmd, strlen(cmd), 0) < 0) { logg("%cremote_cvdhead: write failed\n", logerr ? '!' : '^'); closesocket(sd); return NULL; } tmp = buffer; cnt = FILEBUFF; #ifdef SO_ERROR while((bread = wait_recv(sd, tmp, cnt, 0, rtimeout)) > 0) { #else while((bread = recv(sd, tmp, cnt, 0)) > 0) { #endif tmp += bread; cnt -= bread; if(cnt <= 0) break; } closesocket(sd); if(bread == -1) { logg("%cremote_cvdhead: Error while reading CVD header from %s\n", logerr ? '!' : '^', hostname); mirman_update(mdat->currip, mdat->af, mdat, 1); return NULL; } if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) { logg("%cCVD file not found on remote server\n", logerr ? '!' : '^'); mirman_update(mdat->currip, mdat->af, mdat, 2); return NULL; } /* check whether the resource is up-to-date */ if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) { *ims = 0; logg("OK (IMS)\n"); mirman_update(mdat->currip, mdat->af, mdat, 0); return NULL; } else { *ims = 1; } if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") && !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) { logg("%cUnknown response from remote server\n", logerr ? '!' : '^'); mirman_update(mdat->currip, mdat->af, mdat, 1); return NULL; } i = 3; ch = buffer + i; while(i < sizeof(buffer)) { if (*ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') { ch++; i++; break; } ch++; i++; } if(sizeof(buffer) - i < 512) { logg("%cremote_cvdhead: Malformed CVD header (too short)\n", logerr ? '!' : '^'); mirman_update(mdat->currip, mdat->af, mdat, 1); return NULL; } memset(head, 0, sizeof(head)); for(j = 0; j < 512; j++) { if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) { logg("%cremote_cvdhead: Malformed CVD header (bad chars)\n", logerr ? '!' : '^'); mirman_update(mdat->currip, mdat->af, mdat, 1); return NULL; } head[j] = ch[j]; } if(!(cvd = cl_cvdparse(head))) { logg("%cremote_cvdhead: Malformed CVD header (can't parse)\n", logerr ? '!' : '^'); mirman_update(mdat->currip, mdat->af, mdat, 1); } else { logg("OK\n"); mirman_update(mdat->currip, mdat->af, mdat, 0); } return cvd; } static int getfile(const char *srcfile, const char *destfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist) { char cmd[512], uastr[128], buffer[FILEBUFF], *ch; int bread, fd, totalsize = 0, rot = 0, totaldownloaded = 0, percentage = 0, sd; unsigned int i; char *remotename = NULL, *authorization = NULL, *headerline, ipaddr[46]; const char *rotation = "|/-\\"; #ifdef FILTER_RULES pid_t pid = -1; #endif if(proxy) { remotename = malloc(strlen(hostname) + 8); if(!remotename) { logg("!getfile: Can't allocate memory for 'remotename'\n"); return 75; /* FIXME */ } sprintf(remotename, "http://%s", hostname); if(user) { authorization = proxyauth(user, pass); if(!authorization) { free(remotename); return 75; /* FIXME */ } } } if(uas) strncpy(uastr, uas, sizeof(uastr)); else snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version()); uastr[sizeof(uastr) - 1] = 0; snprintf(cmd, sizeof(cmd), "GET %s/%s HTTP/1.0\r\n" "Host: %s\r\n%s" "User-Agent: %s\r\n" #ifdef FRESHCLAM_NO_CACHE "Cache-Control: no-cache\r\n" #endif "Connection: close\r\n" "\r\n", (remotename != NULL) ? remotename : "", srcfile, hostname, (authorization != NULL) ? authorization : "", uastr); if(remotename) free(remotename); if(authorization) free(authorization); memset(ipaddr, 0, sizeof(ipaddr)); if(ip[0]) /* use ip to connect */ sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist); else sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist); if(sd < 0) { return 52; } else { logg("*Trying to download http://%s/%s (IP: %s)\n", hostname, srcfile, ipaddr); } if(!ip[0]) strcpy(ip, ipaddr); if(send(sd, cmd, strlen(cmd), 0) < 0) { logg("%cgetfile: Can't write to socket\n", logerr ? '!' : '^'); closesocket(sd); return 52; } /* read http headers */ ch = buffer; i = 0; while(1) { /* recv one byte at a time, until we reach \r\n\r\n */ #ifdef SO_ERROR if((i >= sizeof(buffer) - 1) || wait_recv(sd, buffer + i, 1, 0, rtimeout) == -1) { #else if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) { #endif logg("%cgetfile: Error while reading database from %s (IP: %s)\n", logerr ? '!' : '^', hostname, ipaddr); mirman_update(mdat->currip, mdat->af, mdat, 1); closesocket(sd); return 52; } if(i > 2 && *ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') { i++; break; } ch++; i++; } buffer[i] = 0; /* check whether the resource actually existed or not */ if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) { logg("^getfile: %s not found on remote server (IP: %s)\n", srcfile, ipaddr); mirman_update(mdat->currip, mdat->af, mdat, 2); closesocket(sd); return 58; } if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") && !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) { logg("%cgetfile: Unknown response from remote server (IP: %s)\n", logerr ? '!' : '^', ipaddr); mirman_update(mdat->currip, mdat->af, mdat, 1); closesocket(sd); return 58; } /* get size of resource */ for(i = 0; (headerline = cli_strtok(buffer, i, "\n")); i++){ if(strstr(headerline, "Content-Length:")) { if((ch = cli_strtok(headerline, 1, ": "))) { totalsize = atoi(ch); free(ch); } else { totalsize = 0; } } free(headerline); } #ifdef FILTER_RULES { int pfd[2]; if (pipe(pfd) == -1) { logg("!getfile: Can't create pipe to filter\n"); closesocket(sd); return 57; } pid = fork(); if (pid == -1) { logg("!getfile: Can't filter fork failed\n"); closesocket(sd); return 57; } if (pid == 0) { /* Child */ close(pfd[1]); dup2(pfd[0], 0); close(pfd[0]); execl("/bin/clamfilter", "clamfilter", destfile, NULL); _exit(1); } /* Parent */ close(pfd[0]); fd = pfd[1]; destfile = "clam-filter"; } #else if((fd = open(destfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) { char currdir[512]; if(getcwd(currdir, sizeof(currdir))) logg("!getfile: Can't create new file %s in %s\n", destfile, currdir); else logg("!getfile: Can't create new file %s in the current directory\n", destfile); logg("Hint: The database directory must be writable for UID %d or GID %d\n", getuid(), getgid()); closesocket(sd); return 57; } #endif #ifdef SO_ERROR while((bread = wait_recv(sd, buffer, FILEBUFF, 0, rtimeout)) > 0) { #else while((bread = recv(sd, buffer, FILEBUFF, 0)) > 0) { #endif if(write(fd, buffer, bread) != bread) { logg("getfile: Can't write %d bytes to %s\n", bread, destfile); #ifdef FILTER_RULES // if (pid == -1) // unlink(destfile); #else unlink(destfile); #endif close(fd); closesocket(sd); return 57; /* FIXME */ } if(totalsize > 0) { totaldownloaded += bread; percentage = (int) (100 * (float) totaldownloaded / totalsize); } if(!mprintf_quiet) { if(totalsize > 0) { mprintf("Downloading %s [%3i%%]\r", srcfile, percentage); } else { mprintf("Downloading %s [%c]\r", srcfile, rotation[rot]); rot++; rot %= 4; } fflush(stdout); } } closesocket(sd); close(fd); #ifdef FILTER_RULES /*if (pid != -1)*/ { int status; waitpid(pid, &status, 0); if (! WIFEXITED(status) || WEXITSTATUS(status) != 0) { logg("!getfile: Filter failed\n"); return 57; } } #endif if(totalsize > 0) logg("Downloading %s [%i%%]\n", srcfile, percentage); else logg("Downloading %s [*]\n", srcfile); mirman_update(mdat->currip, mdat->af, mdat, 0); return 0; } static int getcvd(const char *cvdfile, const char *newfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, unsigned int newver, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist) { struct cl_cvd *cvd; int ret; logg("*Retrieving http://%s/%s\n", hostname, cvdfile); if((ret = getfile(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist))) { logg("%cCan't download %s from %s\n", logerr ? '!' : '^', cvdfile, hostname); unlink(newfile); return ret; } if((ret = cl_cvdverify(newfile))) { logg("!Verification: %s\n", cl_strerror(ret)); unlink(newfile); return 54; } if(!(cvd = cl_cvdhead(newfile))) { logg("!Can't read CVD header of new %s database.\n", cvdfile); unlink(newfile); return 54; } if(cvd->version < newver) { logg("^Mirror %s is not synchronized.\n", ip); mirman_update(mdat->currip, mdat->af, mdat, 2); cl_cvdfree(cvd); unlink(newfile); return 59; } cl_cvdfree(cvd); return 0; } static int chdir_tmp(const char *dbname, const char *tmpdir) { char cvdfile[32]; if(access(tmpdir, R_OK|W_OK) == -1) { sprintf(cvdfile, "%s.cvd", dbname); if(access(cvdfile, R_OK) == -1) { sprintf(cvdfile, "%s.cld", dbname); if(access(cvdfile, R_OK) == -1) { logg("!chdir_tmp: Can't access local %s database\n", dbname); return -1; } } if(mkdir(tmpdir, 0755) == -1) { logg("!chdir_tmp: Can't create directory %s\n", tmpdir); return -1; } if(cli_cvdunpack(cvdfile, tmpdir) == -1) { logg("!chdir_tmp: Can't unpack %s into %s\n", cvdfile, tmpdir); cli_rmdirs(tmpdir); return -1; } } if(chdir(tmpdir) == -1) { logg("!chdir_tmp: Can't change directory to %s\n", tmpdir); return -1; } return 0; } static int getpatch(const char *dbname, const char *tmpdir, int version, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist) { char *tempname, patch[32], olddir[512]; int ret, fd; if(!getcwd(olddir, sizeof(olddir))) { logg("!getpatch: Can't get path of current working directory\n"); return 50; /* FIXME */ } if(chdir_tmp(dbname, tmpdir) == -1) return 50; tempname = cli_gentemp("."); snprintf(patch, sizeof(patch), "%s-%d.cdiff", dbname, version); logg("*Retrieving http://%s/%s\n", hostname, patch); if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist))) { logg("%cgetpatch: Can't download %s from %s\n", logerr ? '!' : '^', patch, hostname); unlink(tempname); free(tempname); CHDIR_ERR(olddir); return ret; } if((fd = open(tempname, O_RDONLY|O_BINARY)) == -1) { logg("!getpatch: Can't open %s for reading\n", tempname); unlink(tempname); free(tempname); CHDIR_ERR(olddir); return 55; } if(cdiff_apply(fd, 1) == -1) { logg("!getpatch: Can't apply patch\n"); close(fd); unlink(tempname); free(tempname); CHDIR_ERR(olddir); return 70; /* FIXME */ } close(fd); unlink(tempname); free(tempname); if(chdir(olddir) == -1) { logg("!getpatch: Can't chdir to %s\n", olddir); return 50; /* FIXME */ } return 0; }
static int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct optstruct *opts, const char *dnsreply, char *localip, int outdated, struct mirdat *mdat, int logerr) { struct cl_cvd *current, *remote; const struct optstruct *opt; unsigned int nodb = 0, currver = 0, newver = 0, port = 0, i, j; int ret, ims = -1; char *pt, cvdfile[32], localname[32], *tmpdir = NULL, *newfile, newdb[32], cwd[512]; const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL; unsigned int flevel = cl_retflevel(), remote_flevel = 0, maxattempts; unsigned int can_whitelist = 0; int ctimeout, rtimeout; snprintf(cvdfile, sizeof(cvdfile), "%s.cvd", dbname); if(!(current = currentdb(dbname, localname))) { nodb = 1; } else { mdat->dbflevel = current->fl; } if(!nodb && dnsreply) { int field = 0; if(!strcmp(dbname, "main")) { field = 1; } else if(!strcmp(dbname, "daily")) { field = 2; } else if(!strcmp(dbname, "safebrowsing")) { field = 6; } else { logg("!updatedb: Unknown database name (%s) passed.\n", dbname); cl_cvdfree(current); return 70; } if(field && (pt = cli_strtok(dnsreply, field, ":"))) { if(!cli_isnumber(pt)) { logg("^Broken database version in TXT record.\n"); } else { newver = atoi(pt); logg("*%s version from DNS: %d\n", cvdfile, newver); } free(pt); } else { logg("^Invalid DNS reply. Falling back to HTTP mode.\n"); } } if(dnsreply) { if((pt = cli_strtok(dnsreply, 5, ":"))) { remote_flevel = atoi(pt); free(pt); if(remote_flevel && (remote_flevel - flevel < 4)) can_whitelist = 1; } } /* Initialize proxy settings */ if((opt = optget(opts, "HTTPProxyServer"))->enabled) { proxy = opt->strarg; if(strncasecmp(proxy, "http://", 7) == 0) proxy += 7; if((opt = optget(opts, "HTTPProxyUsername"))->enabled) { user = opt->strarg; if((opt = optget(opts, "HTTPProxyPassword"))->enabled) { pass = opt->strarg; } else { logg("HTTPProxyUsername requires HTTPProxyPassword\n"); if(current) cl_cvdfree(current); return 56; } } if((opt = optget(opts, "HTTPProxyPort"))->enabled) port = opt->numarg; logg("Connecting via %s\n", proxy); } if((opt = optget(opts, "HTTPUserAgent"))->enabled) uas = opt->strarg; ctimeout = optget(opts, "ConnectTimeout")->numarg; rtimeout = optget(opts, "ReceiveTimeout")->numarg; if(!nodb && !newver) { remote = remote_cvdhead(cvdfile, localname, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout, mdat, logerr, can_whitelist); if(!nodb && !ims) { logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder); *signo += current->sigs; cl_cvdfree(current); return 1; } if(!remote) { logg("^Can't read %s header from %s (IP: %s)\n", cvdfile, hostname, ip); cl_cvdfree(current); return 58; } newver = remote->version; cl_cvdfree(remote); } if(!nodb && (current->version >= newver)) { logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder); if(!outdated && flevel < current->fl) { /* display warning even for already installed database */ logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl); logg("Please check if ClamAV tools are linked against the proper version of libclamav\n"); logg("DON'T PANIC! Read http://www.clamav.net/support/faq\n"); } *signo += current->sigs; cl_cvdfree(current); return 1; } if(current) { currver = current->version; cl_cvdfree(current); } /* if(ipaddr[0]) { hostfd = wwwconnect(ipaddr, proxy, port, NULL, localip); } else { hostfd = wwwconnect(hostname, proxy, port, ipaddr, localip); if(!ip[0]) strcpy(ip, ipaddr); } if(hostfd < 0) { if(ipaddr[0]) logg("Connection with %s (IP: %s) failed.\n", hostname, ipaddr); else logg("Connection with %s failed.\n", hostname); return 52; }; */ if(!optget(opts, "ScriptedUpdates")->enabled) nodb = 1; if(!getcwd(cwd, sizeof(cwd))) { logg("!updatedb: Can't get path of current working directory\n"); return 50; /* FIXME */ } newfile = cli_gentemp(cwd); if(nodb) { ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist); if(ret) { memset(ip, 0, 16); free(newfile); return ret; } snprintf(newdb, sizeof(newdb), "%s.cvd", dbname); } else { ret = 0; tmpdir = cli_gentemp("."); maxattempts = optget(opts, "MaxAttempts")->numarg; for(i = currver + 1; i <= newver; i++) { for(j = 0; j < maxattempts; j++) { int llogerr = logerr; if(logerr) llogerr = (j == maxattempts - 1); ret = getpatch(dbname, tmpdir, i, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, llogerr, can_whitelist); if(ret == 52 || ret == 58) { memset(ip, 0, 16); continue; } else { break; } } if(ret) break; } if(ret) { cli_rmdirs(tmpdir); free(tmpdir); logg("^Incremental update failed, trying to download %s\n", cvdfile); mirman_whitelist(mdat, 2); ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist); if(ret) { free(newfile); return ret; } snprintf(newdb, sizeof(newdb), "%s.cvd", dbname); } else { if(buildcld(tmpdir, dbname, newfile, optget(opts, "CompressLocalDatabase")->enabled) == -1) { logg("!Can't create local database\n"); cli_rmdirs(tmpdir); free(tmpdir); free(newfile); return 70; /* FIXME */ } snprintf(newdb, sizeof(newdb), "%s.cld", dbname); cli_rmdirs(tmpdir); free(tmpdir); } } if(!(current = cl_cvdhead(newfile))) { logg("!Can't parse new database %s\n", newfile); unlink(newfile); free(newfile); return 55; /* FIXME */ } if(!nodb && !access(localname, R_OK) && unlink(localname)) { logg("!Can't unlink %s. Please fix it and try again.\n", localname); unlink(newfile); free(newfile); return 53; } #ifdef C_WINDOWS if(!access(newdb, R_OK) && unlink(newdb)) { logg("!Can't unlink %s. Please fix the problem manually and try again.\n", newdb); unlink(newfile); free(newfile); return 53; } #endif if(rename(newfile, newdb) == -1) { logg("!Can't rename %s to %s: %s\n", newfile, newdb, strerror(errno)); unlink(newfile); free(newfile); return 57; } free(newfile); logg("%s updated (version: %d, sigs: %d, f-level: %d, builder: %s)\n", newdb, current->version, current->sigs, current->fl, current->builder); if(flevel < current->fl) { logg("Your ClamAV installation is out of date.\n"); logg("Current functionality level = %d, recommended = %d\n", flevel, current->fl); logg("A firmware upgrade might resolve this issue.\n"); logg("Also read http://sgkb.securecomputing.com/article.asp?article=11282&p=2\n"); } *signo += current->sigs; cl_cvdfree(current); return 0; }
/* Base scan function for scanning HFS+ or HFSX partitions */ int cli_scanhfsplus(cli_ctx *ctx) { char *targetdir = NULL; int ret = CL_CLEAN; hfsPlusVolumeHeader *volHeader = NULL; hfsNodeDescriptor catFileDesc; hfsHeaderRecord catFileHeader; hfsNodeDescriptor extentFileDesc; hfsHeaderRecord extentFileHeader; if (!ctx || !ctx->fmap) { cli_errmsg("cli_scanhfsplus: Invalid context\n"); return CL_ENULLARG; } cli_dbgmsg("cli_scanhfsplus: scanning partition content\n"); /* first, read volume header contents */ ret = hfsplus_volumeheader(ctx, &volHeader); if (ret != CL_CLEAN) { goto freeHeader; } /* cli_dbgmsg("sizeof(hfsUniStr255) is %lu\n", sizeof(hfsUniStr255)); cli_dbgmsg("sizeof(hfsPlusBSDInfo) is %lu\n", sizeof(hfsPlusBSDInfo)); cli_dbgmsg("sizeof(hfsPlusExtentDescriptor) is %lu\n", sizeof(hfsPlusExtentDescriptor)); cli_dbgmsg("sizeof(hfsPlusExtentRecord) is %lu\n", sizeof(hfsPlusExtentRecord)); cli_dbgmsg("sizeof(hfsPlusForkData) is %lu\n", sizeof(hfsPlusForkData)); cli_dbgmsg("sizeof(hfsPlusVolumeHeader) is %lu\n", sizeof(hfsPlusVolumeHeader)); cli_dbgmsg("sizeof(hfsNodeDescriptor) is %lu\n", sizeof(hfsNodeDescriptor)); */ /* Get root node (header node) of extent overflow file */ ret = hfsplus_readheader(ctx, volHeader, &extentFileDesc, &extentFileHeader, HFS_FILETREE_EXTENTS, "extentFile"); if (ret != CL_CLEAN) { goto freeHeader; } /* Get root node (header node) of catalog file */ ret = hfsplus_readheader(ctx, volHeader, &catFileDesc, &catFileHeader, HFS_FILETREE_CATALOG, "catalogFile"); if (ret != CL_CLEAN) { goto freeHeader; } /* Create temp folder for contents */ if (!(targetdir = cli_gentemp(ctx->engine->tmpdir))) { cli_errmsg("cli_scandmg: cli_gentemp failed\n"); ret = CL_ETMPDIR; goto freeHeader; } if (mkdir(targetdir, 0700)) { cli_errmsg("cli_scandmg: Cannot create temporary directory %s\n", targetdir); ret = CL_ETMPDIR; goto freeDirname; } cli_dbgmsg("cli_scandmg: Extracting into %s\n", targetdir); /* Can build and scan catalog file if we want *** ret = hfsplus_scanfile(ctx, volHeader, &extentFileHeader, &(volHeader->catalogFile), targetdir); */ if (ret == CL_CLEAN) { ret = hfsplus_validate_catalog(ctx, volHeader, &catFileHeader); if (ret == CL_CLEAN) { cli_dbgmsg("cli_scandmg: validation successful\n"); } else { cli_dbgmsg("cli_scandmg: validation returned %d : %s\n", ret, cl_strerror(ret)); } } /* Walk through catalog to identify files to scan */ if (ret == CL_CLEAN) { ret = hfsplus_walk_catalog(ctx, volHeader, &catFileHeader, &extentFileHeader, targetdir); cli_dbgmsg("cli_scandmg: walk catalog finished\n"); } /* Clean up extracted content, if needed */ if (!ctx->engine->keeptmp) { cli_rmdirs(targetdir); } freeDirname: free(targetdir); freeHeader: free(volHeader); return ret; }
static int sigtool_scandir (const char *dirname, int hex_output) { DIR *dd; struct dirent *dent; struct stat statbuf; char *fname; const char *tmpdir; char *dir; int ret = CL_CLEAN, desc; if ((dd = opendir (dirname)) != NULL) { while ((dent = readdir (dd))) { if (dent->d_ino) { if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) { /* build the full name */ fname = (char *) cli_calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char)); sprintf (fname, "%s/%s", dirname, dent->d_name); /* stat the file */ if (lstat (fname, &statbuf) != -1) { if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode)) { if (sigtool_scandir (fname, hex_output)) { free (fname); closedir (dd); return CL_VIRUS; } } else { if (S_ISREG (statbuf.st_mode)) { tmpdir = getenv ("TMPDIR"); if (tmpdir == NULL) #ifdef P_tmpdir tmpdir = P_tmpdir; #else tmpdir = "/tmp"; #endif /* generate the temporary directory */ dir = cli_gentemp (tmpdir); if (mkdir (dir, 0700)) { printf ("Can't create temporary directory %s\n", dir); return CL_ETMPDIR; } if ((desc = open (fname, O_RDONLY)) == -1) { printf ("Can't open file %s\n", fname); return 1; } if ((ret = cli_ole2_extract (desc, dir, NULL))) { printf ("ERROR %s\n", cl_strerror (ret)); cli_rmdirs (dir); free (dir); return ret; } sigtool_vba_scandir (dir, hex_output); cli_rmdirs (dir); free (dir); } } } free (fname); } } } } else { cli_errmsg ("Can't open directory %s.\n", dirname); return CL_EOPEN; } closedir (dd); return 0; }
int sigtool_vba_scandir (const char *dirname, int hex_output) { int ret = CL_CLEAN, i, fd, data_len; vba_project_t *vba_project; DIR *dd; struct dirent *dent; struct stat statbuf; char *fname, *fullname; unsigned char *data; cli_dbgmsg ("VBA scan dir: %s\n", dirname); if ((vba_project = (vba_project_t *) vba56_dir_read (dirname))) { for (i = 0; i < vba_project->count; i++) { fullname = (char *) malloc (strlen (vba_project->dir) + strlen (vba_project->name[i]) + 2); sprintf (fullname, "%s/%s", vba_project->dir, vba_project->name[i]); fd = open (fullname, O_RDONLY); if (fd == -1) { cli_errmsg ("Scan->OLE2 -> Can't open file %s\n", fullname); free (fullname); ret = CL_EOPEN; break; } free (fullname); cli_dbgmsg ("decompress VBA project '%s'\n", vba_project->name[i]); printf ("-------------- start of %s ------------------\n", vba_project->name[i]); data = (unsigned char *) vba_decompress (fd, vba_project->offset[i], &data_len); close (fd); if (!data) { cli_dbgmsg ("WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]); } else { data = (unsigned char *) realloc (data, data_len + 1); data[data_len] = '\0'; printf ("%s", data); free (data); } printf ("-------------- end of %s ------------------\n", vba_project->name[i]); } for (i = 0; i < vba_project->count; i++) free (vba_project->name[i]); free (vba_project->name); free (vba_project->dir); free (vba_project->offset); free (vba_project); } else if ((fullname = ppt_vba_read (dirname))) { if (sigtool_scandir (fullname, hex_output) == CL_VIRUS) { ret = CL_VIRUS; } cli_rmdirs (fullname); free (fullname); } else if ((vba_project = (vba_project_t *) wm_dir_read (dirname))) { for (i = 0; i < vba_project->count; i++) { fullname = (char *) malloc (strlen (vba_project->dir) + strlen (vba_project->name[i]) + 2); sprintf (fullname, "%s/%s", vba_project->dir, vba_project->name[i]); fd = open (fullname, O_RDONLY); if (fd == -1) { cli_errmsg ("Scan->OLE2 -> Can't open file %s\n", fullname); free (fullname); ret = CL_EOPEN; break; } free (fullname); cli_dbgmsg ("decompress WM project '%s' macro %d\n", vba_project->name[i], i); printf ("\n\n-------------- start of macro:%d key:%d length:%d ------------------\n", i, vba_project->key[i], vba_project->length[i]); data = (unsigned char *) wm_decrypt_macro (fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]); close (fd); if (!data) { cli_dbgmsg ("WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i); } else { wm_decode_macro (data, vba_project->length[i], hex_output); free (data); } printf ("\n-------------- end of macro %d ------------------\n\n", i); } for (i = 0; i < vba_project->count; i++) free (vba_project->name[i]); free (vba_project->key); free (vba_project->length); free (vba_project->offset); free (vba_project->name); free (vba_project->dir); free (vba_project); } if ((dd = opendir (dirname)) != NULL) { while ((dent = readdir (dd))) { if (dent->d_ino) { if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) { /* build the full name */ fname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char)); sprintf (fname, "%s/%s", dirname, dent->d_name); /* stat the file */ if (lstat (fname, &statbuf) != -1) { if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode)) sigtool_vba_scandir (fname, hex_output); } free (fname); } } } } else { cli_errmsg ("ScanDir -> Can't open directory %s.\n", dirname); return CL_EOPEN; } closedir (dd); return ret; }
int cli_scannulsft(int desc, cli_ctx *ctx, off_t offset) { int ret; struct nsis_st nsist; cli_dbgmsg("in scannulsft()\n"); if(ctx->limits && ctx->limits->maxreclevel && ctx->arec >= ctx->limits->maxreclevel) { cli_dbgmsg("Archive recursion limit exceeded (arec == %u).\n", ctx->arec+1); return CL_EMAXREC; } memset(&nsist, 0, sizeof(struct nsis_st)); nsist.ifd = desc; nsist.off = offset; if (!(nsist.dir = cli_gentemp(NULL))) return CL_ETMPDIR; if(mkdir(nsist.dir, 0700)) { cli_dbgmsg("NSIS: Can't create temporary directory %s\n", nsist.dir); free(nsist.dir); return CL_ETMPDIR; } if(cli_leavetemps_flag) cli_dbgmsg("NSIS: Extracting files to %s\n", nsist.dir); ctx->arec++; do { ret = cli_nsis_unpack(&nsist, ctx); if(ret != CL_SUCCESS) { if(ret == CL_EMAXSIZE) { if(BLOCKMAX) { *ctx->virname = "NSIS.ExceededFileSize"; ret=CL_VIRUS; } else { ret = nsist.solid ? CL_BREAK : CL_SUCCESS; } } } else { cli_dbgmsg("NSIS: Successully extracted file #%u\n", nsist.fno); lseek(nsist.ofd, 0, SEEK_SET); if(nsist.fno == 1) ret=cli_scandesc(nsist.ofd, ctx, 0, 0, 0, NULL); else ret=cli_magic_scandesc(nsist.ofd, ctx); close(nsist.ofd); if(!cli_leavetemps_flag) unlink(nsist.ofn); } } while(ret == CL_SUCCESS); if(ret == CL_BREAK) ret = CL_CLEAN; cli_nsis_free(&nsist); if(!cli_leavetemps_flag) cli_rmdirs(nsist.dir); free(nsist.dir); ctx->arec--; return ret; }
int sigtool_vba_scandir (const char *dirname, int hex_output, struct uniq *U) { int ret = CL_CLEAN, i, j, fd, data_len; vba_project_t *vba_project; DIR *dd; struct dirent *dent; STATBUF statbuf; char *fullname, vbaname[1024], *hash; unsigned char *data; uint32_t hashcnt; hashcnt = uniq_get(U, "_vba_project", 12, NULL); while(hashcnt--) { if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue; for(i = 0; i < vba_project->count; i++) { for(j = 0; j < vba_project->colls[i]; j++) { snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j); vbaname[sizeof(vbaname)-1] = '\0'; fd = open(vbaname, O_RDONLY|O_BINARY); if(fd == -1) continue; data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len); close(fd); if(data) { data = (unsigned char *) realloc (data, data_len + 1); data[data_len]='\0'; printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); free(data); } } } free(vba_project->name); free(vba_project->colls); free(vba_project->dir); free(vba_project->offset); free(vba_project); } if((hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) { while(hashcnt--) { snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt); vbaname[sizeof(vbaname)-1] = '\0'; fd = open(vbaname, O_RDONLY|O_BINARY); if (fd == -1) continue; if ((fullname = cli_ppt_vba_read(fd, NULL))) { sigtool_scandir(fullname, hex_output); cli_rmdirs(fullname); free(fullname); } close(fd); } } if ((hashcnt = uniq_get(U, "worddocument", 12, &hash))) { while(hashcnt--) { snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt); vbaname[sizeof(vbaname)-1] = '\0'; fd = open(vbaname, O_RDONLY|O_BINARY); if (fd == -1) continue; if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) { close(fd); continue; } for (i = 0; i < vba_project->count; i++) { data_len = vba_project->length[i]; data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], data_len , vba_project->key[i]); if(data) { data = (unsigned char *) realloc (data, data_len + 1); data[data_len]='\0'; printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); free(data); } } close(fd); free(vba_project->name); free(vba_project->colls); free(vba_project->dir); free(vba_project->offset); free(vba_project->key); free(vba_project->length); free(vba_project); } } if ((dd = opendir (dirname)) != NULL) { while ((dent = readdir (dd))) { if (dent->d_ino) { if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) { /* build the full name */ fullname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char)); sprintf (fullname, "%s"PATHSEP"%s", dirname, dent->d_name); /* stat the file */ if (LSTAT (fullname, &statbuf) != -1) { if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode)) sigtool_vba_scandir (fullname, hex_output, U); } free (fullname); } } } } else { logg("!ScanDir -> Can't open directory %s.\n", dirname); return CL_EOPEN; } closedir (dd); return ret; }
int cli_unzip(cli_ctx *ctx) { unsigned int fc=0, fu=0; int ret=CL_CLEAN; uint32_t fsize, lhoff = 0, coff = 0; fmap_t *map = *ctx->fmap; char *tmpd; const char *ptr; int virus_found = 0; #if HAVE_JSON int toval = 0; #endif cli_dbgmsg("in cli_unzip\n"); fsize = (uint32_t)map->len; if(sizeof(off_t)!=sizeof(uint32_t) && (size_t)fsize!=map->len) { cli_dbgmsg("cli_unzip: file too big\n"); return CL_CLEAN; } if (fsize < SIZEOF_CH) { cli_dbgmsg("cli_unzip: file too short\n"); return CL_CLEAN; } if (!(tmpd = cli_gentemp(ctx->engine->tmpdir))) { return CL_ETMPDIR; } if (mkdir(tmpd, 0700)) { cli_dbgmsg("cli_unzip: Can't create temporary directory %s\n", tmpd); free(tmpd); return CL_ETMPDIR; } for(coff=fsize-22 ; coff>0 ; coff--) { /* sizeof(EOC)==22 */ if(!(ptr = fmap_need_off_once(map, coff, 20))) continue; if(cli_readint32(ptr)==0x06054b50) { uint32_t chptr = cli_readint32(&ptr[16]); if(!CLI_ISCONTAINED(0, fsize, chptr, SIZEOF_CH)) continue; coff=chptr; break; } } if(coff) { cli_dbgmsg("cli_unzip: central @%x\n", coff); while(ret==CL_CLEAN && (coff=chdr(map, coff, fsize, &fu, fc+1, &ret, ctx, tmpd, NULL))) { fc++; if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) { cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles); ret=CL_EMAXFILES; } #if HAVE_JSON if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { return CL_ETIMEOUT; } #endif } } else cli_dbgmsg("cli_unzip: central not found, using localhdrs\n"); if(fu<=(fc/4)) { /* FIXME: make up a sane ratio or remove the whole logic */ fc = 0; while (ret==CL_CLEAN && lhoff<fsize && (coff=lhdr(map, lhoff, fsize-lhoff, &fu, fc+1, NULL, &ret, ctx, tmpd, 1, zip_scan_cb))) { fc++; lhoff+=coff; if (SCAN_ALL && ret == CL_VIRUS) { ret = CL_CLEAN; virus_found = 1; } if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) { cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles); ret=CL_EMAXFILES; } #if HAVE_JSON if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { return CL_ETIMEOUT; } #endif } } if (!ctx->engine->keeptmp) cli_rmdirs(tmpd); free(tmpd); if (ret == CL_CLEAN && virus_found) ret = CL_VIRUS; return ret; }
int cli_cvdload(FILE *fs, struct cl_engine **engine, unsigned int *signo, short warn, unsigned int options) { char *dir; struct cl_cvd cvd; int ret; time_t s_time; int cfd; cli_dbgmsg("in cli_cvdload()\n"); /* verify */ if((ret = cli_cvdverify(fs, &cvd))) return ret; if(cvd.stime && warn) { time(&s_time); if((int) s_time - cvd.stime > 604800) { cli_warnmsg("**************************************************\n"); cli_warnmsg("*** The virus database is older than 7 days! ***\n"); cli_warnmsg("*** Please update it as soon as possible. ***\n"); cli_warnmsg("**************************************************\n"); } } if(cvd.fl > cl_retflevel()) { cli_warnmsg("***********************************************************\n"); cli_warnmsg("*** This version of the ClamAV engine is outdated. ***\n"); cli_warnmsg("*** DON'T PANIC! Read http://www.clamav.net/support/faq ***\n"); cli_warnmsg("***********************************************************\n"); } dir = cli_gentemp(NULL); if(mkdir(dir, 0700)) { cli_errmsg("cli_cvdload(): Can't create temporary directory %s\n", dir); free(dir); return CL_ETMPDIR; } cfd = fileno(fs); /* use only operations on file descriptors, and not on the FILE* from here on * if we seek the FILE*, the underlying descriptor may not seek as expected * (for example on OpenBSD, cygwin, etc.). * So seek the descriptor directly. */ if(lseek(cfd, 512, SEEK_SET) == -1) { cli_errmsg("cli_cvdload(): lseek(fs, 512, SEEK_SET) failed\n"); return CL_EIO; } if(cli_untgz(cfd, dir)) { cli_errmsg("cli_cvdload(): Can't unpack CVD file.\n"); free(dir); return CL_ECVDEXTR; } /* load extracted directory */ ret = cl_load(dir, engine, signo, options); cli_rmdirs(dir); free(dir); return ret; }
int cli_scandmg(cli_ctx *ctx) { struct dmg_koly_block hdr; int ret, namelen, ofd; size_t maplen, nread; off_t pos = 0; char *dirname, *tmpfile; const char *outdata; unsigned int file = 0; struct dmg_mish_with_stripes *mish_list = NULL, *mish_list_tail = NULL; enum dmgReadState state = DMG_FIND_BASE_PLIST; int stateDepth[DMG_MAX_STATE]; #if HAVE_LIBXML2 xmlTextReaderPtr reader; #endif if (!ctx || !ctx->fmap) { cli_errmsg("cli_scandmg: Invalid context\n"); return CL_ENULLARG; } maplen = (*ctx->fmap)->real_len; pos = maplen - 512; if (pos <= 0) { cli_dbgmsg("cli_scandmg: Sizing problem for DMG archive.\n"); return CL_CLEAN; } /* Grab koly block */ if (fmap_readn(*ctx->fmap, &hdr, pos, sizeof(hdr)) != sizeof(hdr)) { cli_dbgmsg("cli_scandmg: Invalid DMG trailer block\n"); return CL_EFORMAT; } /* Check magic */ hdr.magic = be32_to_host(hdr.magic); if (hdr.magic == 0x6b6f6c79) { cli_dbgmsg("cli_scandmg: Found koly block @ %ld\n", (long) pos); } else { cli_dbgmsg("cli_scandmg: No koly magic, %8x\n", hdr.magic); return CL_EFORMAT; } hdr.dataForkOffset = be64_to_host(hdr.dataForkOffset); hdr.dataForkLength = be64_to_host(hdr.dataForkLength); cli_dbgmsg("cli_scandmg: data offset %lu len %d\n", (unsigned long)hdr.dataForkOffset, (int)hdr.dataForkLength); hdr.xmlOffset = be64_to_host(hdr.xmlOffset); hdr.xmlLength = be64_to_host(hdr.xmlLength); if (hdr.xmlLength > (uint64_t)INT_MAX) { cli_dbgmsg("cli_scandmg: The embedded XML is way larger than necessary, and probably corrupt or tampered with.\n"); return CL_EFORMAT; } if ((hdr.xmlOffset > (uint64_t)maplen) || (hdr.xmlLength > (uint64_t)maplen) || (hdr.xmlOffset + hdr.xmlLength) > (uint64_t)maplen) { cli_dbgmsg("cli_scandmg: XML out of range for this file\n"); return CL_EFORMAT; } cli_dbgmsg("cli_scandmg: XML offset %lu len %d\n", (unsigned long)hdr.xmlOffset, (int)hdr.xmlLength); if (hdr.xmlLength == 0) { cli_dbgmsg("cli_scandmg: Embedded XML length is zero.\n"); return CL_EFORMAT; } /* Create temp folder for contents */ if (!(dirname = cli_gentemp(ctx->engine->tmpdir))) { return CL_ETMPDIR; } if (mkdir(dirname, 0700)) { cli_errmsg("cli_scandmg: Cannot create temporary directory %s\n", dirname); free(dirname); return CL_ETMPDIR; } cli_dbgmsg("cli_scandmg: Extracting into %s\n", dirname); /* Dump XML to tempfile, if needed */ if (ctx->engine->keeptmp) { int xret; xret = dmg_extract_xml(ctx, dirname, &hdr); if (xret != CL_SUCCESS) { /* Printed err detail inside dmg_extract_xml */ free(dirname); return xret; } } /* scan XML with cli_map_scandesc */ ret = cli_map_scandesc(*ctx->fmap, (off_t)hdr.xmlOffset, (size_t)hdr.xmlLength, ctx); if (ret != CL_CLEAN) { cli_dbgmsg("cli_scandmg: retcode from scanning TOC xml: %s\n", cl_strerror(ret)); if (!ctx->engine->keeptmp) cli_rmdirs(dirname); free(dirname); return ret; } /* page data from map */ outdata = fmap_need_off_once_len(*ctx->fmap, hdr.xmlOffset, hdr.xmlLength, &nread); if (!outdata || (nread != hdr.xmlLength)) { cli_errmsg("cli_scandmg: Failed getting XML from map, len %d\n", (int)hdr.xmlLength); if (!ctx->engine->keeptmp) cli_rmdirs(dirname); free(dirname); return CL_EMAP; } /* time to walk the tree */ /* plist -> dict -> (key:resource_fork) dict -> (key:blkx) array -> dict */ /* each of those bottom level dict should have 4 parts */ /* [ Attributes, Data, ID, Name ], where Data is Base64 mish block */ /* This is the block where we require libxml2 */ #if HAVE_LIBXML2 /* XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_COMPACT */ #define DMG_XML_PARSE_OPTS (1 << 1 | 1 << 11 | 1 << 16) reader = xmlReaderForMemory(outdata, (int)hdr.xmlLength, "toc.xml", NULL, DMG_XML_PARSE_OPTS); if (!reader) { cli_dbgmsg("cli_scandmg: Failed parsing XML!\n"); if (!ctx->engine->keeptmp) cli_rmdirs(dirname); free(dirname); return CL_EFORMAT; } stateDepth[DMG_FIND_BASE_PLIST] = -1; // May need to check for (xmlTextReaderIsEmptyElement(reader) == 0) /* Break loop if have return code or reader can't read any more */ while ((ret == CL_CLEAN) && (xmlTextReaderRead(reader) == 1)) { xmlReaderTypes nodeType; nodeType = xmlTextReaderNodeType(reader); if (nodeType == XML_READER_TYPE_ELEMENT) { // New element, do name check xmlChar *nodeName; int depth; depth = xmlTextReaderDepth(reader); if (depth < 0) { break; } if ((depth > 50) && SCAN_ALGO) { // Possible heuristic, should limit runaway cli_dbgmsg("cli_scandmg: Excessive nesting in DMG TOC.\n"); break; } nodeName = xmlTextReaderLocalName(reader); if (!nodeName) continue; dmg_parsemsg("read: name %s depth %d\n", nodeName, depth); if ((state == DMG_FIND_DATA_MISH) && (depth == stateDepth[state-1])) { xmlChar * textValue; struct dmg_mish_with_stripes *mish_set; /* Reset state early, for continue cases */ stateDepth[DMG_FIND_KEY_DATA] = -1; state--; if (xmlStrcmp(nodeName, "data") != 0) { cli_dbgmsg("cli_scandmg: Not blkx data element\n"); xmlFree(nodeName); continue; } dmg_parsemsg("read: Found blkx data element\n"); /* Pull out data content from text */ if (xmlTextReaderIsEmptyElement(reader)) { cli_dbgmsg("cli_scandmg: blkx data element is empty\n"); xmlFree(nodeName); continue; } if (xmlTextReaderRead(reader) != 1) { xmlFree(nodeName); break; } if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_TEXT) { cli_dbgmsg("cli_scandmg: Next node not text\n"); xmlFree(nodeName); continue; } textValue = xmlTextReaderValue(reader); if (textValue == NULL) { xmlFree(nodeName); continue; } /* Have encoded mish block */ mish_set = cli_malloc(sizeof(struct dmg_mish_with_stripes)); if (mish_set == NULL) { ret = CL_EMEM; xmlFree(textValue); xmlFree(nodeName); break; } ret = dmg_decode_mish(ctx, &file, textValue, mish_set); xmlFree(textValue); if (ret == CL_EFORMAT) { /* Didn't decode, or not a mish block */ ret = CL_CLEAN; xmlFree(nodeName); continue; } else if (ret != CL_CLEAN) { xmlFree(nodeName); continue; } /* Add mish block to list */ if (mish_list_tail != NULL) { mish_list_tail->next = mish_set; mish_list_tail = mish_set; } else { mish_list = mish_set; mish_list_tail = mish_set; } mish_list_tail->next = NULL; } if ((state == DMG_FIND_KEY_DATA) && (depth > stateDepth[state-1]) && (xmlStrcmp(nodeName, "key") == 0)) { xmlChar * textValue; dmg_parsemsg("read: Found key - checking for Data\n"); if (xmlTextReaderRead(reader) != 1) { xmlFree(nodeName); break; } if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_TEXT) { cli_dbgmsg("cli_scandmg: Key node no text\n"); xmlFree(nodeName); continue; } textValue = xmlTextReaderValue(reader); if (textValue == NULL) { cli_dbgmsg("cli_scandmg: no value from xmlTextReaderValue\n"); xmlFree(nodeName); continue; } if (xmlStrcmp(textValue, "Data") == 0) { dmg_parsemsg("read: Matched data\n"); stateDepth[DMG_FIND_KEY_DATA] = depth; state++; } else { dmg_parsemsg("read: text value is %s\n", textValue); } xmlFree(textValue); } if ((state == DMG_FIND_BLKX_CONTAINER) && (depth == stateDepth[state-1])) { if (xmlStrcmp(nodeName, "array") == 0) { dmg_parsemsg("read: Found array blkx\n"); stateDepth[DMG_FIND_BLKX_CONTAINER] = depth; state++; } else if (xmlStrcmp(nodeName, "dict") == 0) { dmg_parsemsg("read: Found dict blkx\n"); stateDepth[DMG_FIND_BLKX_CONTAINER] = depth; state++; } else { cli_dbgmsg("cli_scandmg: Bad blkx, not container\n"); stateDepth[DMG_FIND_KEY_BLKX] = -1; state--; } } if ((state == DMG_FIND_KEY_BLKX) && (depth == stateDepth[state-1] + 1) && (xmlStrcmp(nodeName, "key") == 0)) { xmlChar * textValue; dmg_parsemsg("read: Found key - checking for blkx\n"); if (xmlTextReaderRead(reader) != 1) { xmlFree(nodeName); break; } if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_TEXT) { cli_dbgmsg("cli_scandmg: Key node no text\n"); xmlFree(nodeName); continue; } textValue = xmlTextReaderValue(reader); if (textValue == NULL) { cli_dbgmsg("cli_scandmg: no value from xmlTextReaderValue\n"); xmlFree(nodeName); continue; } if (xmlStrcmp(textValue, "blkx") == 0) { cli_dbgmsg("cli_scandmg: Matched blkx\n"); stateDepth[DMG_FIND_KEY_BLKX] = depth; state++; } else { cli_dbgmsg("cli_scandmg: wanted blkx, text value is %s\n", textValue); } xmlFree(textValue); } if ((state == DMG_FIND_DICT_RESOURCE_FORK) && (depth == stateDepth[state-1])) { if (xmlStrcmp(nodeName, "dict") == 0) { dmg_parsemsg("read: Found resource-fork dict\n"); stateDepth[DMG_FIND_DICT_RESOURCE_FORK] = depth; state++; } else { dmg_parsemsg("read: Not resource-fork dict\n"); stateDepth[DMG_FIND_KEY_RESOURCE_FORK] = -1; state--; } } if ((state == DMG_FIND_KEY_RESOURCE_FORK) && (depth == stateDepth[state-1] + 1) && (xmlStrcmp(nodeName, "key") == 0)) { dmg_parsemsg("read: Found resource-fork key\n"); stateDepth[DMG_FIND_KEY_RESOURCE_FORK] = depth; state++; } if ((state == DMG_FIND_BASE_DICT) && (depth == stateDepth[state-1] + 1) && (xmlStrcmp(nodeName, "dict") == 0)) { dmg_parsemsg("read: Found dict start\n"); stateDepth[DMG_FIND_BASE_DICT] = depth; state++; } if ((state == DMG_FIND_BASE_PLIST) && (xmlStrcmp(nodeName, "plist") == 0)) { dmg_parsemsg("read: Found plist start\n"); stateDepth[DMG_FIND_BASE_PLIST] = depth; state++; } xmlFree(nodeName); } else if ((nodeType == XML_READER_TYPE_END_ELEMENT) && (state > DMG_FIND_BASE_PLIST)) { int significantEnd = 0; int depth = xmlTextReaderDepth(reader); if (depth < 0) { break; } else if (depth < stateDepth[state-1]) { significantEnd = 1; } else if ((depth == stateDepth[state-1]) && (state-1 == DMG_FIND_BLKX_CONTAINER)) { /* Special case, ending blkx container */ significantEnd = 1; } if (significantEnd) { dmg_parsemsg("read: significant end tag, state %d\n", state); stateDepth[state-1] = -1; state--; if ((state-1 == DMG_FIND_KEY_RESOURCE_FORK) || (state-1 == DMG_FIND_KEY_BLKX)) { /* Keys end their own tag (validly) and the next state depends on the following tag */ // cli_dbgmsg("read: significant end tag ending prior key state\n"); stateDepth[state-1] = -1; state--; } } else { dmg_parsemsg("read: not significant end tag, state %d depth %d prior depth %d\n", state, depth, stateDepth[state-1]); } } } xmlFreeTextReader(reader); xmlCleanupParser(); #else cli_dbgmsg("cli_scandmg: libxml2 support is compiled out. It is required for full DMG support.\n"); #endif /* Loop over mish array */ file = 0; while ((ret == CL_CLEAN) && (mish_list != NULL)) { /* Handle & scan mish block */ ret = dmg_handle_mish(ctx, file++, dirname, hdr.xmlOffset, mish_list); free(mish_list->mish); mish_list_tail = mish_list; mish_list = mish_list->next; free(mish_list_tail); } /* Cleanup */ /* If error occurred, need to free mish items and mish blocks */ while (mish_list != NULL) { free(mish_list->mish); mish_list_tail = mish_list; mish_list = mish_list->next; free(mish_list_tail); } if (!ctx->engine->keeptmp) cli_rmdirs(dirname); free(dirname); return ret; }
int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pTempRoot, const wchar_t *pLicenseKey, BOOL bLoadMinDefs) { BOOL cant_convert; int ret; logg("*in Scan_Initialize(pEnginesFolder = %S, pTempRoot = %S)\n", pEnginesFolder, pTempRoot); if(!pEnginesFolder) FAIL(CL_ENULLARG, "pEnginesFolder is NULL"); if(!pTempRoot) FAIL(CL_ENULLARG, "pTempRoot is NULL"); if(lock_engine()) FAIL(CL_ELOCK, "failed to lock engine"); if(engine) { unlock_engine(); FAIL(CL_ESTATE, "Already initialized"); } if(!(engine = cl_engine_new())) { unlock_engine(); FAIL(CL_EMEM, "Not enough memory for a new engine"); } cl_engine_set_clcb_pre_cache(engine, filetype_cb); cl_engine_set_clcb_pre_scan(engine, prescan_cb); cl_engine_set_clcb_post_scan(engine, postscan_cb); minimal_definitions = bLoadMinDefs; if(bLoadMinDefs) logg("^MINIMAL DEFINITIONS MODE ON!\n"); if(!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pTempRoot, -1, tmpdir, sizeof(tmpdir), NULL, &cant_convert) || cant_convert) { free_engine_and_unlock(); FAIL(CL_EARG, "Can't translate pTempRoot"); } ret = strlen(tmpdir); while(ret>0 && tmpdir[--ret] == '\\') tmpdir[ret] = '\0'; if(!ret || ret + 8 + 1 >= sizeof(tmpdir)) { free_engine_and_unlock(); FAIL(CL_EARG, "Bad or too long pTempRoot '%s'", tmpdir); } memcpy(&tmpdir[ret+1], "\\clamtmp", 9); cli_rmdirs(tmpdir); if((ret = SHCreateDirectoryExA(NULL, tmpdir, NULL) != ERROR_SUCCESS) && ret != ERROR_ALREADY_EXISTS) { free_engine_and_unlock(); FAIL(CL_ETMPDIR, "Cannot create pTempRoot '%s': error %d", tmpdir, ret); } if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, tmpdir))) { free_engine_and_unlock(); FAIL(ret, "Failed to set engine tempdir to '%s': %s", tmpdir, cl_strerror(ret)); } if(!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pEnginesFolder, -1, dbdir, sizeof(dbdir), NULL, &cant_convert) || cant_convert) { free_engine_and_unlock(); FAIL(CL_EARG, "Can't translate pEnginesFolder"); } ret = load_db(); unlock_engine(); if(!ret) { ResetEvent(monitor_event); if(!(monitor_hdl = CreateThread(NULL, 0, monitor_thread, NULL, 0, NULL))) logg("^Failed to start db monitoring thread\n"); } logg("*Scan_Initialize: returning %d\n", ret); return ret; }
int cli_scanrtf(cli_ctx *ctx) { char* tempname; const unsigned char* ptr; const unsigned char* ptr_end; int ret = CL_CLEAN; struct rtf_state state; struct stack stack; size_t bread; table_t* actiontable; uint8_t main_symbols[256]; size_t offset = 0; cli_dbgmsg("in cli_scanrtf()\n"); memset(main_symbols, 0, 256); main_symbols['{']=1; main_symbols['}']=1; main_symbols['\\']=1; stack.stack_cnt = 0; stack.stack_size = 16; stack.elements = 0; stack.warned = 0; stack.states = cli_malloc(stack.stack_size*sizeof(*stack.states)); if(!stack.states) { cli_errmsg("ScanRTF: Unable to allocate memory for stack states\n"); return CL_EMEM; } if(!(tempname = cli_gentemp(ctx->engine->tmpdir))) return CL_EMEM; if(mkdir(tempname, 0700)) { cli_dbgmsg("ScanRTF -> Can't create temporary directory %s\n", tempname); free(stack.states); free(tempname); return CL_ETMPDIR; } actiontable = tableCreate(); if((ret = load_actions(actiontable))) { cli_dbgmsg("RTF: Unable to load rtf action table\n"); free(stack.states); if(!ctx->engine->keeptmp) cli_rmdirs(tempname); free(tempname); tableDestroy(actiontable); return ret; } init_rtf_state(&state); for (offset = 0; (ptr = fmap_need_off_once_len(*ctx->fmap, offset, BUFF_SIZE, &bread)) && bread; offset += bread) { ptr_end = ptr + bread; while(ptr < ptr_end) { switch(state.parse_state) { case PARSE_MAIN: switch(*ptr++) { case '{': if(( ret = push_state(&stack,&state) )) { cli_dbgmsg("RTF:Push failure!\n"); SCAN_CLEANUP; return ret; } break; case '}': if(state.cb_data && state.cb_end) if(( ret = state.cb_end(&state, ctx) )) { SCAN_CLEANUP; return ret; } if(( ret = pop_state(&stack,&state) )) { cli_dbgmsg("RTF:pop failure!\n"); SCAN_CLEANUP; return ret; } break; case '\\': state.parse_state = PARSE_CONTROL_; break; default: ptr--; { size_t i; size_t left = ptr_end - ptr; size_t use = left; for(i = 1;i < left; i++) if(main_symbols[ptr[i]]) { use = i; break; } if(state.cb_begin) { if(!state.cb_data) if(( ret = state.cb_begin(&state, ctx,tempname) )) { SCAN_CLEANUP; return ret; } if(( ret = state.cb_process(&state, ptr, use) )) { if(state.cb_end) { state.cb_end(&state,ctx); } SCAN_CLEANUP; return ret; } } ptr += use; } } break; case PARSE_CONTROL_: if(isalpha(*ptr)) { state.parse_state = PARSE_CONTROL_WORD; state.controlword_cnt = 0; } else state.parse_state = PARSE_CONTROL_SYMBOL; break; case PARSE_CONTROL_SYMBOL: ptr++; /* Do nothing */ state.parse_state = PARSE_MAIN; break; case PARSE_CONTROL_WORD: if(state.controlword_cnt == 32) { cli_dbgmsg("Invalid control word: maximum size exceeded:%s\n",state.controlword); state.parse_state = PARSE_MAIN; } else if(isalpha(*ptr)) state.controlword[state.controlword_cnt++] = *ptr++; else { if(isspace(*ptr)) { state.controlword[state.controlword_cnt++] = *ptr++; state.parse_state = PARSE_INTERPRET_CONTROLWORD; } else if (isdigit(*ptr)) { state.parse_state = PARSE_CONTROL_WORD_PARAM; state.controlword_param = 0; state.controlword_param_sign = 1; } else if(*ptr == '-') { ptr++; state.parse_state = PARSE_CONTROL_WORD_PARAM; state.controlword_param = 0; state.controlword_param_sign = -1; } else { state.parse_state = PARSE_INTERPRET_CONTROLWORD; } } break; case PARSE_CONTROL_WORD_PARAM: if(isdigit(*ptr)) { state.controlword_param = state.controlword_param*10 + *ptr++ - '0'; } else if(isalpha(*ptr)) { ptr++; } else { if(state.controlword_param_sign < 0) state.controlword_param = -state.controlword_param; state.parse_state = PARSE_INTERPRET_CONTROLWORD; } break; case PARSE_INTERPRET_CONTROLWORD: { int action; state.controlword[state.controlword_cnt] = '\0'; action = tableFind(actiontable, state.controlword); if(action != -1) { if(state.cb_data && state.cb_end) {/* premature end of previous block */ state.cb_end(&state,ctx); state.cb_begin = NULL; state.cb_end = NULL; state.cb_data = NULL; } rtf_action(&state,action); } state.parse_state = PARSE_MAIN; break; } } } } SCAN_CLEANUP; return ret; }
static int sigtool_scandir (const char *dirname, int hex_output) { DIR *dd; struct dirent *dent; STATBUF statbuf; char *fname; const char *tmpdir; char *dir; int ret = CL_CLEAN, desc; cli_ctx *ctx; fname = NULL; if ((dd = opendir (dirname)) != NULL) { while ((dent = readdir (dd))) { if (dent->d_ino) { if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) { /* build the full name */ fname = (char *) cli_calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char)); if(!fname){ closedir(dd); return -1; } sprintf (fname, "%s"PATHSEP"%s", dirname, dent->d_name); /* stat the file */ if (LSTAT (fname, &statbuf) != -1) { if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode)) { if (sigtool_scandir (fname, hex_output)) { free (fname); closedir (dd); return CL_VIRUS; } } else { if (S_ISREG (statbuf.st_mode)) { struct uniq *vba = NULL; tmpdir = cli_gettmpdir(); /* generate the temporary directory */ dir = cli_gentemp (tmpdir); if(!dir) { printf("cli_gentemp() failed\n"); free(fname); closedir (dd); return -1; } if (mkdir (dir, 0700)) { printf ("Can't create temporary directory %s\n", dir); free(fname); closedir (dd); free(dir); return CL_ETMPDIR; } if ((desc = open (fname, O_RDONLY|O_BINARY)) == -1) { printf ("Can't open file %s\n", fname); free(fname); closedir (dd); free(dir); return 1; } if(!(ctx = convenience_ctx(desc))) { free(fname); close(desc); closedir(dd); free(dir); return 1; } if ((ret = cli_ole2_extract (dir, ctx, &vba))) { printf ("ERROR %s\n", cl_strerror (ret)); destroy_ctx(desc, ctx); cli_rmdirs (dir); free (dir); closedir (dd); free(fname); return ret; } if(vba) sigtool_vba_scandir (dir, hex_output, vba); destroy_ctx(desc, ctx); cli_rmdirs (dir); free (dir); } } } free (fname); } } } } else { logg("!Can't open directory %s.\n", dirname); return CL_EOPEN; } closedir (dd); return 0; }