/* * offdata[0]: type * offdata[1]: offset value * offdata[2]: max shift * offdata[3]: section number */ int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max) { char offcpy[65]; unsigned int n, val; char *pt; if(!info) { /* decode offset string */ if(!offstr) { cli_errmsg("cli_caloff: offstr == NULL\n"); return CL_ENULLARG; } if(!strcmp(offstr, "*")) { offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY; return CL_SUCCESS; } if(strlen(offstr) > 64) { cli_errmsg("cli_caloff: Offset string too long\n"); return CL_EMALFDB; } strcpy(offcpy, offstr); if((pt = strchr(offcpy, ','))) { if(!cli_isnumber(pt + 1)) { cli_errmsg("cli_caloff: Invalid offset shift value\n"); return CL_EMALFDB; } offdata[2] = atoi(pt + 1); *pt = 0; } else { offdata[2] = 0; } *offset_max = *offset_min = CLI_OFF_NONE; if(!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) { if(offcpy[2] == '+') offdata[0] = CLI_OFF_EP_PLUS; else offdata[0] = CLI_OFF_EP_MINUS; if(!cli_isnumber(&offcpy[3])) { cli_errmsg("cli_caloff: Invalid offset value\n"); return CL_EMALFDB; } offdata[1] = atoi(&offcpy[3]); } else if(offcpy[0] == 'S') { if(offcpy[1] == 'E') { if(!cli_isnumber(&offcpy[2])) { cli_errmsg("cli_caloff: Invalid section number\n"); return CL_EMALFDB; } offdata[0] = CLI_OFF_SE; offdata[3] = atoi(&offcpy[2]); } else if(!strncmp(offstr, "SL+", 3)) { offdata[0] = CLI_OFF_SL_PLUS; if(!cli_isnumber(&offcpy[3])) { cli_errmsg("cli_caloff: Invalid offset value\n"); return CL_EMALFDB; } offdata[1] = atoi(&offcpy[3]); } else if(sscanf(offcpy, "S%u+%u", &n, &val) == 2) { offdata[0] = CLI_OFF_SX_PLUS; offdata[1] = val; offdata[3] = n; } else { cli_errmsg("cli_caloff: Invalid offset string\n"); return CL_EMALFDB; } } else if(!strncmp(offcpy, "EOF-", 4)) { offdata[0] = CLI_OFF_EOF_MINUS; if(!cli_isnumber(&offcpy[4])) { cli_errmsg("cli_caloff: Invalid offset value\n"); return CL_EMALFDB; } offdata[1] = atoi(&offcpy[4]); } else if(!strncmp(offcpy, "VI", 2)) { /* versioninfo */ offdata[0] = CLI_OFF_VERSION; } else if (strchr(offcpy, '$')) { if (sscanf(offcpy, "$%u$", &n) != 1) { cli_errmsg("cli_caloff: Invalid macro($) in offset: %s\n", offcpy); return CL_EMALFDB; } if (n >= 32) { cli_errmsg("cli_caloff: at most 32 macro groups supported\n"); return CL_EMALFDB; } offdata[0] = CLI_OFF_MACRO; offdata[1] = n; } else { offdata[0] = CLI_OFF_ABSOLUTE; if(!cli_isnumber(offcpy)) { cli_errmsg("cli_caloff: Invalid offset value\n"); return CL_EMALFDB; } *offset_min = offdata[1] = atoi(offcpy); *offset_max = *offset_min + offdata[2]; } if(offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE && offdata[0] != CLI_OFF_EOF_MINUS && offdata[0] != CLI_OFF_MACRO) { if(target != 1 && target != 6 && target != 9) { cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target); return CL_EMALFDB; } } } else { /* calculate relative offsets */ *offset_min = CLI_OFF_NONE; if(offset_max) *offset_max = CLI_OFF_NONE; if(info->status == -1) return CL_SUCCESS; switch(offdata[0]) { case CLI_OFF_EOF_MINUS: *offset_min = info->fsize - offdata[1]; break; case CLI_OFF_EP_PLUS: *offset_min = info->exeinfo.ep + offdata[1]; break; case CLI_OFF_EP_MINUS: *offset_min = info->exeinfo.ep - offdata[1]; break; case CLI_OFF_SL_PLUS: *offset_min = info->exeinfo.section[info->exeinfo.nsections - 1].raw + offdata[1]; break; case CLI_OFF_SX_PLUS: if(offdata[3] >= info->exeinfo.nsections) *offset_min = CLI_OFF_NONE; else *offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1]; break; case CLI_OFF_SE: if(offdata[3] >= info->exeinfo.nsections) { *offset_min = CLI_OFF_NONE; } else { *offset_min = info->exeinfo.section[offdata[3]].raw; if (offset_max) *offset_max = *offset_min + info->exeinfo.section[offdata[3]].rsz + offdata[2]; } break; case CLI_OFF_VERSION: if (offset_max) *offset_min = *offset_max = CLI_OFF_ANY; break; default: cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]); return CL_EARG; } if(offset_max && *offset_max == CLI_OFF_NONE && *offset_min != CLI_OFF_NONE) *offset_max = *offset_min + offdata[2]; } return CL_SUCCESS; }
int dlp_is_valid_ssn(const unsigned char *buffer, int length, int format) { int area_number; int group_number; int serial_number; int minlength; int retval = 1; char numbuf[12]; if(buffer == NULL) return 0; minlength = (format==SSN_FORMAT_HYPHENS?11:9); if(length < minlength) return 0; if((length > minlength) && isdigit(buffer[minlength])) return 0; strncpy(numbuf, (const char*)buffer, minlength); numbuf[minlength] = 0; /* sscanf parses and (basically) validates the string for us */ switch(format) { case SSN_FORMAT_HYPHENS: if(numbuf[3] != '-' || numbuf[6] != '-') return 0; if(sscanf((const char *) numbuf, "%3d-%2d-%4d", &area_number, &group_number, &serial_number) != 3) { return 0; } break; case SSN_FORMAT_STRIPPED: if(!cli_isnumber(numbuf)) return 0; if(sscanf((const char *) numbuf, "%3d%2d%4d", &area_number, &group_number, &serial_number) != 3) { return 0; } break; default: cli_dbgmsg("dlp_is_valid_ssn: unknown format type %d \n", format); return 0; } /* start validating */ /* validation data taken from * http://en.wikipedia.org/wiki/Social_Security_number_%28United_States%29 */ if(area_number > MAX_AREA || area_number == 666 || area_number <= 0 || group_number <= 0 || group_number > 99 || serial_number <= 0 || serial_number > 9999) retval = 0; if(area_number == 987 && group_number == 65) { if(serial_number >= 4320 && serial_number <= 4329) retval = 0; } /* if(group_number > ssn_max_group[area_number]) retval = 0; */ if(retval) cli_dbgmsg("dlp_is_valid_ssn: SSN_%s: %s\n", format == SSN_FORMAT_HYPHENS ? "HYPHENS" : "STRIPPED", numbuf); return retval; }
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; }
int main(int argc, char **argv) { int ds, dms, ret; double mb; struct timeval t1, t2; #ifndef C_WINDOWS struct timezone tz; sigset_t sigset; #endif struct optstruct *opt; const char *pt; #if defined(C_WINDOWS) && defined(CL_THREAD_SAFE) if(!pthread_win32_process_attach_np()) { mprintf("!Can't start the win32 pthreads layer\n"); return 72; } #endif #if !defined(C_WINDOWS) && !defined(C_BEOS) sigemptyset(&sigset); sigaddset(&sigset, SIGXFSZ); sigprocmask(SIG_SETMASK, &sigset, NULL); #endif opt = opt_parse(argc, argv, clamscan_shortopt, clamscan_longopt, NULL, clamscan_deprecated); if(!opt) { mprintf("!Can't parse the command line\n"); return 40; } if(opt_check(opt, "verbose")) { mprintf_verbose = 1; logg_verbose = 1; } if(opt_check(opt, "quiet")) mprintf_quiet = 1; if(opt_check(opt, "stdout")) mprintf_stdout = 1; if(opt_check(opt, "debug")) { #if defined(C_LINUX) /* [email protected]: create a dump if needed */ struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; if(setrlimit(RLIMIT_CORE, &rlim) < 0) perror("setrlimit"); #endif cl_debug(); /* enable debug messages */ } if(opt_check(opt, "version")) { print_version(opt_arg(opt, "database")); opt_free(opt); return 0; } if(opt_check(opt, "help")) { opt_free(opt); help(); return 0; } if(opt_check(opt, "recursive")) recursion = 1; if(opt_check(opt, "infected")) printinfected = 1; if(opt_check(opt, "bell")) bell = 1; if(opt_check(opt, "tempdir")) cl_settempdir(opt_arg(opt, "tempdir"), 0); if(opt_check(opt, "leave-temps")) cl_settempdir(NULL, 1); /* initialize logger */ if(opt_check(opt, "log")) { logg_file = opt_arg(opt, "log"); if(logg("#\n-------------------------------------------------------------------------------\n\n")) { mprintf("!Problem with internal logger.\n"); opt_free(opt); return 62; } } else logg_file = NULL; /* validate some numerical options */ if(opt_check(opt, "max-scansize")) { pt = opt_arg(opt, "max-scansize"); if(!strchr(pt, 'M') && !strchr(pt, 'm')) { if(!cli_isnumber(pt)) { logg("!--max-scansize requires a natural number\n"); opt_free(opt); return 40; } } } if(opt_check(opt, "max-filesize")) { pt = opt_arg(opt, "max-filesize"); if(!strchr(pt, 'M') && !strchr(pt, 'm')) { if(!cli_isnumber(pt)) { logg("!--max-filesize requires a natural number\n"); opt_free(opt); return 40; } } } if(opt_check(opt, "max-files")) { if(!cli_isnumber(opt_arg(opt, "max-files"))) { logg("!--max-files requires a natural number\n"); opt_free(opt); return 40; } } if(opt_check(opt, "max-recursion")) { if(!cli_isnumber(opt_arg(opt, "max-recursion"))) { logg("!--max-recursion requires a natural number\n"); opt_free(opt); return 40; } } if(opt_check(opt, "max-mail-recursion")) { if(!cli_isnumber(opt_arg(opt, "max-mail-recursion"))) { logg("!--max-mail-recursion requires a natural number\n"); opt_free(opt); return 40; } } if(opt_check(opt, "max-dir-recursion")) { if(!cli_isnumber(opt_arg(opt, "max-dir-recursion"))) { logg("!--max-dir-recursion requires a natural number\n"); opt_free(opt); return 40; } } if(opt_check(opt, "max-ratio")) { if(!cli_isnumber(opt_arg(opt, "max-ratio"))) { logg("!--max-ratio requires a natural number\n"); opt_free(opt); return 40; } } memset(&info, 0, sizeof(struct s_info)); #ifdef _WIN32 SetConsoleCtrlHandler((PHANDLER_ROUTINE) clamscan_ctrl_handler, TRUE); #endif #ifdef C_WINDOWS _set_fmode(_O_BINARY); #ifdef CL_DEBUG { _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); } #endif gettimeofday(&t1, NULL); #else gettimeofday(&t1, &tz); #endif ret = scanmanager(opt); if(!opt_check(opt, "disable-summary") && !opt_check(opt, "no-summary")) { #ifdef C_WINDOWS gettimeofday(&t2, NULL); #else gettimeofday(&t2, &tz); #endif ds = t2.tv_sec - t1.tv_sec; dms = t2.tv_usec - t1.tv_usec; ds -= (dms < 0) ? (1):(0); dms += (dms < 0) ? (1000000):(0); logg("\n----------- SCAN SUMMARY -----------\n"); logg("Known viruses: %u\n", info.sigs); logg("Engine version: %s\n", get_version()); logg("Scanned directories: %u\n", info.dirs); logg("Scanned files: %u\n", info.files); logg("Infected files: %u\n", info.ifiles); if(info.notremoved) { logg("Not removed: %u\n", info.notremoved); } if(info.notmoved) { logg("Not %s: %u\n", opt_check(opt, "copy") ? "moved" : "copied", info.notmoved); } mb = info.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0; logg("Data scanned: %2.2lf MB\n", mb); logg("Time: %u.%3.3u sec (%u m %u s)\n", ds, dms/1000, ds/60, ds%60); } opt_free(opt); #if defined(C_WINDOWS) && defined(CL_THREAD_SAFE) if(!pthread_win32_process_detach_np()) { logg("!Can't stop the win32 pthreads layer\n"); return 72; } #endif return ret; }