int scanmanager(const struct optstruct *opts) { int ret = 0, i; unsigned int options = 0, dboptions = 0, dirlnk = 1, filelnk = 1; struct cl_engine *engine; STATBUF sb; char *file, cwd[1024], *pua_cats = NULL; const char *filename; const struct optstruct *opt; #ifndef _WIN32 struct rlimit rlim; #endif dirlnk = optget(opts, "follow-dir-symlinks")->numarg; if(dirlnk > 2) { logg("!--follow-dir-symlinks: Invalid argument\n"); return 2; } filelnk = optget(opts, "follow-file-symlinks")->numarg; if(filelnk > 2) { logg("!--follow-file-symlinks: Invalid argument\n"); return 2; } if(optget(opts, "yara-rules")->enabled) { char *p = optget(opts, "yara-rules")->strarg; if(strcmp(p, "yes")) { if(!strcmp(p, "only")) dboptions |= CL_DB_YARA_ONLY; else if (!strcmp(p, "no")) dboptions |= CL_DB_YARA_EXCLUDE; } } if(optget(opts, "phishing-sigs")->enabled) dboptions |= CL_DB_PHISHING; if(optget(opts, "official-db-only")->enabled) dboptions |= CL_DB_OFFICIAL_ONLY; if(optget(opts,"phishing-scan-urls")->enabled) dboptions |= CL_DB_PHISHING_URLS; if(optget(opts,"bytecode")->enabled) dboptions |= CL_DB_BYTECODE; if((ret = cl_init(CL_INIT_DEFAULT))) { logg("!Can't initialize libclamav: %s\n", cl_strerror(ret)); return 2; } if(!(engine = cl_engine_new())) { logg("!Can't initialize antivirus engine\n"); return 2; } cl_engine_set_clcb_virus_found(engine, clamscan_virus_found_cb); if (optget(opts, "disable-cache")->enabled) cl_engine_set_num(engine, CL_ENGINE_DISABLE_CACHE, 1); if (optget(opts, "disable-pe-stats")->enabled) { cl_engine_set_num(engine, CL_ENGINE_DISABLE_PE_STATS, 1); } if (optget(opts, "enable-stats")->enabled) { cl_engine_stats_enable(engine); } if (optget(opts, "stats-timeout")->enabled) { cl_engine_set_num(engine, CL_ENGINE_STATS_TIMEOUT, optget(opts, "StatsTimeout")->numarg); } if (optget(opts, "stats-host-id")->enabled) { char *p = optget(opts, "stats-host-id")->strarg; if (strcmp(p, "default")) { if (!strcmp(p, "none")) { cl_engine_set_clcb_stats_get_hostid(engine, NULL); } else if (!strcmp(p, "anonymous")) { strcpy(hostid, STATS_ANON_UUID); } else { if (strlen(p) > 36) { logg("!Invalid HostID\n"); cl_engine_set_clcb_stats_submit(engine, NULL); cl_engine_free(engine); return 2; } strcpy(hostid, p); } cl_engine_set_clcb_stats_get_hostid(engine, get_hostid); } } if(optget(opts, "detect-pua")->enabled) { dboptions |= CL_DB_PUA; if((opt = optget(opts, "exclude-pua"))->enabled) { dboptions |= CL_DB_PUA_EXCLUDE; i = 0; while(opt) { if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) { logg("!Can't allocate memory for pua_cats\n"); cl_engine_free(engine); return 2; } sprintf(pua_cats + i, ".%s", opt->strarg); i += strlen(opt->strarg) + 1; pua_cats[i] = 0; opt = opt->nextarg; } pua_cats[i] = '.'; pua_cats[i + 1] = 0; } if((opt = optget(opts, "include-pua"))->enabled) { if(pua_cats) { logg("!--exclude-pua and --include-pua cannot be used at the same time\n"); cl_engine_free(engine); free(pua_cats); return 2; } dboptions |= CL_DB_PUA_INCLUDE; i = 0; while(opt) { if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) { logg("!Can't allocate memory for pua_cats\n"); cl_engine_free(engine); return 2; } sprintf(pua_cats + i, ".%s", opt->strarg); i += strlen(opt->strarg) + 1; pua_cats[i] = 0; opt = opt->nextarg; } pua_cats[i] = '.'; pua_cats[i + 1] = 0; } if(pua_cats) { if((ret = cl_engine_set_str(engine, CL_ENGINE_PUA_CATEGORIES, pua_cats))) { logg("!cli_engine_set_str(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret)); free(pua_cats); cl_engine_free(engine); return 2; } free(pua_cats); } } if(optget(opts, "dev-ac-only")->enabled) cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1); if(optget(opts, "dev-ac-depth")->enabled) cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, optget(opts, "dev-ac-depth")->numarg); if(optget(opts, "leave-temps")->enabled) cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1); if(optget(opts, "force-to-disk")->enabled) cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1); if(optget(opts, "bytecode-unsigned")->enabled) dboptions |= CL_DB_BYTECODE_UNSIGNED; if((opt = optget(opts,"bytecode-timeout"))->enabled) cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg); if (optget(opts, "nocerts")->enabled) cl_engine_set_num(engine, CL_ENGINE_DISABLE_PE_CERTS, 1); if (optget(opts, "dumpcerts")->enabled) cl_engine_set_num(engine, CL_ENGINE_PE_DUMPCERTS, 1); if((opt = optget(opts,"bytecode-mode"))->enabled) { enum bytecode_mode mode; if (!strcmp(opt->strarg, "ForceJIT")) mode = CL_BYTECODE_MODE_JIT; else if(!strcmp(opt->strarg, "ForceInterpreter")) mode = CL_BYTECODE_MODE_INTERPRETER; else if(!strcmp(opt->strarg, "Test")) mode = CL_BYTECODE_MODE_TEST; else mode = CL_BYTECODE_MODE_AUTO; cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode); } if((opt = optget(opts, "statistics"))->enabled) { while(opt) { if (!strcasecmp(opt->strarg, "bytecode")) { dboptions |= CL_DB_BYTECODE_STATS; } else if (!strcasecmp(opt->strarg, "pcre")) { dboptions |= CL_DB_PCRE_STATS; } opt = opt->nextarg; } } if((opt = optget(opts, "tempdir"))->enabled) { if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) { logg("!cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "database"))->active) { while(opt) { if((ret = cl_load(opt->strarg, engine, &info.sigs, dboptions))) { logg("!%s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } opt = opt->nextarg; } } else { char *dbdir = freshdbdir(); if((ret = cl_load(dbdir, engine, &info.sigs, dboptions))) { logg("!%s\n", cl_strerror(ret)); free(dbdir); cl_engine_free(engine); return 2; } free(dbdir); } /* pcre engine limits - required for cl_engine_compile */ if ((opt = optget(opts, "pcre-match-limit"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_MATCH_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_PCRE_MATCH_LIMIT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if ((opt = optget(opts, "pcre-recmatch-limit"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_RECMATCH_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_PCRE_RECMATCH_LIMIT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((ret = cl_engine_compile(engine)) != 0) { logg("!Database initialization error: %s\n", cl_strerror(ret));; cl_engine_free(engine); return 2; } if(optget(opts, "archive-verbose")->enabled) { cl_engine_set_clcb_meta(engine, meta); cl_engine_set_clcb_pre_cache(engine, pre); cl_engine_set_clcb_post_scan(engine, post); } /* set limits */ if((opt = optget(opts, "max-scansize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_SCANSIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-filesize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } #ifndef _WIN32 if(getrlimit(RLIMIT_FSIZE, &rlim) == 0) { if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_FILESIZE, NULL)) logg("^System limit for file size is lower than engine->maxfilesize\n"); if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_SCANSIZE, NULL)) logg("^System limit for file size is lower than engine->maxscansize\n"); } else { logg("^Cannot obtain resource limits for file size\n"); } #endif if((opt = optget(opts, "max-files"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILES, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_FILES) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-recursion"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_RECURSION, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_RECURSION) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } /* Engine max sizes */ if((opt = optget(opts, "max-embeddedpe"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_EMBEDDEDPE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_EMBEDDEDPE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-htmlnormalize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_HTMLNORMALIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_HTMLNORMALIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-htmlnotags"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_HTMLNOTAGS, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_HTMLNOTAGS) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-scriptnormalize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCRIPTNORMALIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_SCRIPTNORMALIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-ziptypercg"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_ZIPTYPERCG, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_ZIPTYPERCG) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-partitions"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_PARTITIONS, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_PARTITIONS) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-iconspe"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_ICONSPE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_ICONSPE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-rechwp3"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_RECHWP3, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_RECHWP3) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if ((opt = optget(opts, "timelimit"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_TIME_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_TIME_LIMIT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if ((opt = optget(opts, "pcre-max-filesize"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_MAX_FILESIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_PCRE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } /* set scan options */ if(optget(opts, "allmatch")->enabled) { options |= CL_SCAN_ALLMATCHES; } if(optget(opts,"phishing-ssl")->enabled) options |= CL_SCAN_PHISHING_BLOCKSSL; if(optget(opts,"phishing-cloak")->enabled) options |= CL_SCAN_PHISHING_BLOCKCLOAK; if(optget(opts,"partition-intersection")->enabled) options |= CL_SCAN_PARTITION_INTXN; if(optget(opts,"heuristic-scan-precedence")->enabled) options |= CL_SCAN_HEURISTIC_PRECEDENCE; if(optget(opts, "scan-archive")->enabled) options |= CL_SCAN_ARCHIVE; if(optget(opts, "detect-broken")->enabled) options |= CL_SCAN_BLOCKBROKEN; if(optget(opts, "block-encrypted")->enabled) options |= CL_SCAN_BLOCKENCRYPTED; if(optget(opts, "block-macros")->enabled) options |= CL_SCAN_BLOCKMACROS; if(optget(opts, "scan-pe")->enabled) options |= CL_SCAN_PE; if(optget(opts, "scan-elf")->enabled) options |= CL_SCAN_ELF; if(optget(opts, "scan-ole2")->enabled) options |= CL_SCAN_OLE2; if(optget(opts, "scan-pdf")->enabled) options |= CL_SCAN_PDF; if(optget(opts, "scan-swf")->enabled) options |= CL_SCAN_SWF; if(optget(opts, "scan-html")->enabled && optget(opts, "normalize")->enabled) options |= CL_SCAN_HTML; if(optget(opts, "scan-mail")->enabled) options |= CL_SCAN_MAIL; if(optget(opts, "scan-xmldocs")->enabled) options |= CL_SCAN_XMLDOCS; if(optget(opts, "scan-hwp3")->enabled) options |= CL_SCAN_HWP3; if(optget(opts, "algorithmic-detection")->enabled) options |= CL_SCAN_ALGORITHMIC; if(optget(opts, "block-max")->enabled) { options |= CL_SCAN_BLOCKMAX; } #ifdef HAVE__INTERNAL__SHA_COLLECT if(optget(opts, "dev-collect-hashes")->enabled) options |= CL_SCAN_INTERNAL_COLLECT_SHA; #endif if(optget(opts, "dev-performance")->enabled) options |= CL_SCAN_PERFORMANCE_INFO; if(optget(opts, "detect-structured")->enabled) { options |= CL_SCAN_STRUCTURED; if((opt = optget(opts, "structured-ssn-format"))->enabled) { switch(opt->numarg) { case 0: options |= CL_SCAN_STRUCTURED_SSN_NORMAL; break; case 1: options |= CL_SCAN_STRUCTURED_SSN_STRIPPED; break; case 2: options |= (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED); break; default: logg("!Invalid argument for --structured-ssn-format\n"); return 2; } } else { options |= CL_SCAN_STRUCTURED_SSN_NORMAL; } if((opt = optget(opts, "structured-ssn-count"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_SSN_COUNT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MIN_SSN_COUNT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "structured-cc-count"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_CC_COUNT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MIN_CC_COUNT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } } else { options &= ~CL_SCAN_STRUCTURED; } #ifdef C_LINUX procdev = (dev_t) 0; if(CLAMSTAT("/proc", &sb) != -1 && !sb.st_size) procdev = sb.st_dev; #endif #if HAVE_JSON if (optget(opts, "gen-json")->enabled) options |= CL_SCAN_FILE_PROPERTIES; #endif /* check filetype */ if(!opts->filename && !optget(opts, "file-list")->enabled) { /* we need full path for some reasons (eg. archive handling) */ if(!getcwd(cwd, sizeof(cwd))) { logg("!Can't get absolute pathname of current working directory\n"); ret = 2; } else { CLAMSTAT(cwd, &sb); scandirs(cwd, engine, opts, options, 1, sb.st_dev); } } else if(opts->filename && !optget(opts, "file-list")->enabled && !strcmp(opts->filename[0], "-")) { /* read data from stdin */ ret = scanstdin(engine, opts, options); } else { if(opts->filename && optget(opts, "file-list")->enabled) logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n"); while((filename = filelist(opts, &ret)) && (file = strdup(filename))) { if(LSTAT(file, &sb) == -1) { perror(file); logg("^%s: Can't access file\n", file); ret = 2; } else { for(i = strlen(file) - 1; i > 0; i--) { if(file[i] == *PATHSEP) file[i] = 0; else break; } if(S_ISLNK(sb.st_mode)) { if(dirlnk == 0 && filelnk == 0) { if(!printinfected) logg("%s: Symbolic link\n", file); } else if(CLAMSTAT(file, &sb) != -1) { if(S_ISREG(sb.st_mode) && filelnk) { scanfile(file, engine, opts, options); } else if(S_ISDIR(sb.st_mode) && dirlnk) { scandirs(file, engine, opts, options, 1, sb.st_dev); } else { if(!printinfected) logg("%s: Symbolic link\n", file); } } } else if(S_ISREG(sb.st_mode)) { scanfile(file, engine, opts, options); } else if(S_ISDIR(sb.st_mode)) { scandirs(file, engine, opts, options, 1, sb.st_dev); } else { logg("^%s: Not supported file type\n", file); ret = 2; } } free(file); } } if((opt = optget(opts, "statistics"))->enabled) { while(opt) { if (!strcasecmp(opt->strarg, "bytecode")) { cli_sigperf_print(); cli_sigperf_events_destroy(); } #if HAVE_PCRE else if (!strcasecmp(opt->strarg, "pcre")) { cli_pcre_perf_print(); cli_pcre_perf_events_destroy(); } #endif opt = opt->nextarg; } } /* free the engine */ cl_engine_free(engine); /* overwrite return code - infection takes priority */ if(info.ifiles) ret = 1; else if(info.errors) ret = 2; return ret; }
int sbbs_t::exec_file(csi_t *csi) { char str[256],ch; int s; uint i,j,x,y; file_t f; switch(*(csi->ip++)) { case CS_FILE_SELECT_AREA: csi->logic=LOGIC_FALSE; if(!usrlibs) return(0); while(online) { j=0; if(usrlibs>1) { sprintf(str,"%smenu/libs.*", cfg.text_dir); if(fexist(str)) menu("libs"); else { bputs(text[CfgLibLstHdr]); for(i=0;i<usrlibs && !msgabort();i++) { if(i==curlib) outchar('*'); else outchar(' '); if(i<9) outchar(' '); if(i<99) outchar(' '); bprintf(text[CfgLibLstFmt] ,i+1,cfg.lib[usrlib[i]]->lname); } } sprintf(str,text[JoinWhichLib],curlib+1); mnemonics(str); j=getnum(usrlibs); if((int)j==-1) return(0); if(!j) j=curlib; else j--; } sprintf(str,"%smenu/dirs%u.*", cfg.text_dir, usrlib[j]+1); if(fexist(str)) { sprintf(str,"dirs%u",usrlib[j]+1); menu(str); } else { CLS; bprintf(text[DirLstHdr], cfg.lib[usrlib[j]]->lname); for(i=0;i<usrdirs[j] && !msgabort();i++) { if(i==curdir[j]) outchar('*'); else outchar(' '); sprintf(str,text[DirLstFmt],i+1 ,cfg.dir[usrdir[j][i]]->lname,nulstr ,getfiles(&cfg,usrdir[j][i])); if(i<9) outchar(' '); if(i<99) outchar(' '); bputs(str); } } sprintf(str,text[JoinWhichDir],curdir[j]+1); mnemonics(str); i=getnum(usrdirs[j]); if((int)i==-1) { if(usrlibs==1) return(0); continue; } if(!i) i=curdir[j]; else i--; curlib=j; curdir[curlib]=i; csi->logic=LOGIC_TRUE; return(0); } return(0); case CS_FILE_GET_DIR_NUM: if(useron.misc&COLDKEYS) { i=atoi(csi->str); if(i && i<=usrdirs[curlib] && usrlibs) curdir[curlib]=i-1; return(0); } ch=getkey(K_UPPER); outchar(ch); if((ch&0xf)*10U<=usrdirs[curlib] && (ch&0xf) && usrlibs) { i=(ch&0xf)*10; ch=getkey(K_UPPER); if(!isdigit(ch) && ch!=CR) { ungetkey(ch); curdir[curlib]=(i/10)-1; return(0); } outchar(ch); if(ch==CR) { curdir[curlib]=(i/10)-1; return(0); } logch(ch,0); i+=ch&0xf; if(i*10<=usrdirs[curlib]) { /* 100+ dirs */ i*=10; ch=getkey(K_UPPER); if(!isdigit(ch) && ch!=CR) { ungetkey(ch); curdir[curlib]=(i/10)-1; return(0); } outchar(ch); if(ch==CR) { curdir[curlib]=(i/10)-1; return(0); } logch(ch,0); i+=ch&0xf; } if(i<=usrdirs[curlib]) curdir[curlib]=i-1; return(0); } if((ch&0xf)<=(int)usrdirs[curlib] && (ch&0xf) && usrlibs) curdir[curlib]=(ch&0xf)-1; return(0); case CS_FILE_GET_LIB_NUM: if(useron.misc&COLDKEYS) { i=atoi(csi->str); if(i && i<=usrlibs) curlib=i-1; return(0); } ch=getkey(K_UPPER); outchar(ch); if((ch&0xf)*10U<=usrlibs && (ch&0xf)) { i=(ch&0xf)*10; ch=getkey(K_UPPER); if(!isdigit(ch) && ch!=CR) { ungetkey(ch); curlib=(i/10)-1; return(0); } outchar(ch); if(ch==CR) { curlib=(i/10)-1; return(0); } logch(ch,0); i+=ch&0xf; if(i<=usrlibs) curlib=i-1; return(0); } if((ch&0xf)<=(int)usrlibs && (ch&0xf)) curlib=(ch&0xf)-1; return(0); case CS_FILE_SHOW_LIBRARIES: if(!usrlibs) return(0); sprintf(str,"%smenu/libs.*", cfg.text_dir); if(fexist(str)) { menu("libs"); return(0); } bputs(text[LibLstHdr]); for(i=0;i<usrlibs && !msgabort();i++) { if(i==curlib) outchar('*'); else outchar(' '); if(i<9) outchar(' '); bprintf(text[LibLstFmt],i+1 ,cfg.lib[usrlib[i]]->lname,nulstr,usrdirs[i]); } return(0); case CS_FILE_SHOW_DIRECTORIES: if(!usrlibs) return(0); sprintf(str,"%smenu/dirs%u.*", cfg.text_dir, usrlib[curlib]+1); if(fexist(str)) { sprintf(str,"dirs%u",usrlib[curlib]+1); menu(str); return(0); } CRLF; bprintf(text[DirLstHdr],cfg.lib[usrlib[curlib]]->lname); for(i=0;i<usrdirs[curlib] && !msgabort();i++) { if(i==curdir[curlib]) outchar('*'); else outchar(' '); sprintf(str,text[DirLstFmt],i+1 ,cfg.dir[usrdir[curlib][i]]->lname,nulstr ,getfiles(&cfg,usrdir[curlib][i])); if(i<9) outchar(' '); if(i<99) outchar(' '); bputs(str); } return(0); case CS_FILE_LIBRARY_UP: curlib++; if(curlib>=usrlibs) curlib=0; return(0); case CS_FILE_LIBRARY_DOWN: if(!curlib) curlib=usrlibs-1; else curlib--; return(0); case CS_FILE_DIRECTORY_UP: if(!usrlibs) return(0); curdir[curlib]++; if(curdir[curlib]>=usrdirs[curlib]) curdir[curlib]=0; return(0); case CS_FILE_DIRECTORY_DOWN: if(!usrlibs) return(0); if(!curdir[curlib]) curdir[curlib]=usrdirs[curlib]-1; else curdir[curlib]--; return(0); case CS_FILE_SET_AREA: csi->logic=LOGIC_TRUE; for(i=0;i<usrlibs;i++) for(j=0;j<usrdirs[i];j++) if(!stricmp(csi->str,cfg.dir[usrdir[i][j]]->code)) { curlib=i; curdir[i]=j; return(0); } csi->logic=LOGIC_FALSE; return(0); case CS_FILE_SET_LIBRARY: csi->logic=LOGIC_TRUE; for(i=0;i<usrlibs;i++) if(!stricmp(cfg.lib[usrlib[i]]->sname,csi->str)) break; if(i<usrlibs) curlib=i; else csi->logic=LOGIC_FALSE; return(0); case CS_FILE_UPLOAD: csi->logic=LOGIC_FALSE; if(usrlibs) { i=usrdir[curlib][curdir[curlib]]; if(cfg.upload_dir!=INVALID_DIR && !dir_op(i) && !(useron.exempt&FLAG('U')) && !chk_ar(cfg.dir[i]->ul_ar,&useron,&client)) i=cfg.upload_dir; } else i=cfg.upload_dir; csi->logic=upload(i) ? LOGIC_TRUE:LOGIC_FALSE; return(0); case CS_FILE_UPLOAD_USER: csi->logic=LOGIC_FALSE; if(cfg.user_dir==INVALID_DIR) { bputs(text[NoUserDir]); return(0); } csi->logic=upload(cfg.user_dir) ? LOGIC_TRUE:LOGIC_FALSE; return(0); case CS_FILE_UPLOAD_SYSOP: csi->logic=LOGIC_FALSE; if(cfg.sysop_dir==INVALID_DIR) { bputs(text[NoSysopDir]); return(0); } csi->logic=upload(cfg.sysop_dir) ? LOGIC_TRUE:LOGIC_FALSE; return(0); case CS_FILE_DOWNLOAD: if(!usrlibs) return(0); if(useron.rest&FLAG('D')) { bputs(text[R_Download]); return(0); } padfname(csi->str,str); strupr(str); if(!listfileinfo(usrdir[curlib][curdir[curlib]],str,FI_DOWNLOAD)) { bputs(text[SearchingAllDirs]); for(i=0;i<usrdirs[curlib];i++) if(i!=curdir[curlib] && (s=listfileinfo(usrdir[curlib][i],str,FI_DOWNLOAD))!=0) if(s==-1 || (!strchr(str,'?') && !strchr(str,'*'))) return(0); bputs(text[SearchingAllLibs]); for(i=0;i<usrlibs;i++) { if(i==curlib) continue; for(j=0;j<usrdirs[i];j++) if((s=listfileinfo(usrdir[i][j],str,FI_DOWNLOAD))!=0) if(s==-1 || (!strchr(str,'?') && !strchr(str,'*'))) return(0); } } return(0); case CS_FILE_DOWNLOAD_USER: /* Download from user dir */ csi->logic=LOGIC_FALSE; if(cfg.user_dir==INVALID_DIR) { bputs(text[NoUserDir]); return(0); } if(useron.rest&FLAG('D')) { bputs(text[R_Download]); return(0); } CRLF; if(!listfileinfo(cfg.user_dir,nulstr,FI_USERXFER)) bputs(text[NoFilesForYou]); else csi->logic=LOGIC_TRUE; return(0); case CS_FILE_DOWNLOAD_BATCH: if(batdn_total && (text[DownloadBatchQ][0]==0 || yesno(text[DownloadBatchQ]))) { start_batch_download(); csi->logic=LOGIC_TRUE; } else csi->logic=LOGIC_FALSE; return(0); case CS_FILE_BATCH_ADD_LIST: batch_add_list(csi->str); return(0); case CS_FILE_BATCH_ADD: csi->logic=LOGIC_FALSE; if(!csi->str[0]) return(0); padfname(csi->str,f.name); for(x=y=0;x<usrlibs;x++) { for(y=0;y<usrdirs[x];y++) if(findfile(&cfg,usrdir[x][y],f.name)) break; if(y<usrdirs[x]) break; } if(x>=usrlibs) return(0); f.dir=usrdir[x][y]; getfileixb(&cfg,&f); f.size=0; getfiledat(&cfg,&f); addtobatdl(&f); csi->logic=LOGIC_TRUE; return(0); case CS_FILE_BATCH_CLEAR: if(!batdn_total) { csi->logic=LOGIC_FALSE; return(0); } csi->logic=LOGIC_TRUE; for(i=0;i<batdn_total;i++) { f.dir=batdn_dir[i]; f.datoffset=batdn_offset[i]; f.size=batdn_size[i]; strcpy(f.name,batdn_name[i]); closefile(&f); } batdn_total=0; return(0); case CS_FILE_VIEW: if(!usrlibs) return(0); padfname(csi->str,str); strupr(str); csi->logic=LOGIC_TRUE; if(listfiles(usrdir[curlib][curdir[curlib]],str,0,FL_VIEW)) return(0); bputs(text[SearchingAllDirs]); for(i=0;i<usrdirs[curlib];i++) { if(i==curdir[curlib]) continue; if(listfiles(usrdir[curlib][i],str,0,FL_VIEW)) break; } if(i<usrdirs[curlib]) return(0); bputs(text[SearchingAllLibs]); for(i=0;i<usrlibs;i++) { if(i==curlib) continue; for(j=0;j<usrdirs[i];j++) if(listfiles(usrdir[i][j],str,0,FL_VIEW)) return(0); } csi->logic=LOGIC_FALSE; bputs(text[FileNotFound]); return(0); case CS_FILE_LIST: /* List files in current dir */ if(!usrlibs) return(0); csi->logic=LOGIC_FALSE; if(!getfiles(&cfg,usrdir[curlib][curdir[curlib]])) { bputs(text[EmptyDir]); return(0); } padfname(csi->str,str); strupr(str); s=listfiles(usrdir[curlib][curdir[curlib]],str,0,0); if(s>1) { bprintf(text[NFilesListed],s); } csi->logic=!s; return(0); case CS_FILE_LIST_EXTENDED: /* Extended Information on files */ if(!usrlibs) return(0); padfname(csi->str,str); strupr(str); if(!listfileinfo(usrdir[curlib][curdir[curlib]],str,FI_INFO)) { bputs(text[SearchingAllDirs]); for(i=0;i<usrdirs[curlib];i++) if(i!=curdir[curlib] && (s=listfileinfo(usrdir[curlib][i] ,str,FI_INFO))!=0) if(s==-1 || (!strchr(str,'?') && !strchr(str,'*'))) return(0); bputs(text[SearchingAllLibs]); for(i=0;i<usrlibs;i++) { if(i==curlib) continue; for(j=0;j<usrdirs[i];j++) if((s=listfileinfo(usrdir[i][j],str,FI_INFO))!=0) if(s==-1 || (!strchr(str,'?') && !strchr(str,'*'))) return(0); } } return(0); case CS_FILE_FIND_TEXT: /* Find text in descriptions */ scandirs(FL_FINDDESC); return(0); case CS_FILE_FIND_TEXT_ALL: /* Find text in descriptions */ scanalldirs(FL_FINDDESC); return(0); case CS_FILE_FIND_NAME: /* Find text in descriptions */ scandirs(FL_NO_HDR); return(0); case CS_FILE_FIND_NAME_ALL: /* Find text in descriptions */ scanalldirs(FL_NO_HDR); return(0); case CS_FILE_BATCH_SECTION: batchmenu(); return(0); case CS_FILE_TEMP_SECTION: temp_xfer(); return(0); case CS_FILE_PTRS_CFG: csi->logic=!inputnstime(&ns_time); return(0); case CS_FILE_NEW_SCAN: scandirs(FL_ULTIME); return(0); case CS_FILE_NEW_SCAN_ALL: scanalldirs(FL_ULTIME); return(0); case CS_FILE_REMOVE: if(!usrlibs) return(0); if(useron.rest&FLAG('R')) { bputs(text[R_RemoveFiles]); return(0); } padfname(csi->str,str); strupr(str); if(!listfileinfo(usrdir[curlib][curdir[curlib]],str,FI_REMOVE)) { if(cfg.user_dir!=INVALID_DIR && cfg.user_dir!=usrdir[curlib][curdir[curlib]]) if((s=listfileinfo(cfg.user_dir,str,FI_REMOVE))!=0) if(s==-1 || (!strchr(str,'?') && !strchr(str,'*'))) return(0); bputs(text[SearchingAllDirs]); for(i=0;i<usrdirs[curlib];i++) if(i!=curdir[curlib] && i!=cfg.user_dir && (s=listfileinfo(usrdir[curlib][i],str,FI_REMOVE))!=0) if(s==-1 || (!strchr(str,'?') && !strchr(str,'*'))) return(0); bputs(text[SearchingAllLibs]); for(i=0;i<usrlibs;i++) { if(i==curlib || i==cfg.user_dir) continue; for(j=0;j<usrdirs[i]; j++) if((s=listfileinfo(usrdir[i][j],str,FI_REMOVE))!=0) if(s==-1 || (!strchr(str,'?') && !strchr(str,'*'))) return(0); } } return(0); } errormsg(WHERE,ERR_CHK,"shell function",*(csi->ip-1)); return(0); }
static void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, unsigned int options, unsigned int depth, dev_t dev) { DIR *dd; struct dirent *dent; STATBUF sb; char *fname; int included; const struct optstruct *opt; unsigned int dirlnk, filelnk; if((opt = optget(opts, "exclude-dir"))->enabled) { while(opt) { if(match_regex(dirname, opt->strarg) == 1) { if(!printinfected) logg("~%s: Excluded\n", dirname); return; } opt = opt->nextarg; } } if((opt = optget(opts, "include-dir"))->enabled) { included = 0; while(opt) { if(match_regex(dirname, opt->strarg) == 1) { included = 1; break; } opt = opt->nextarg; } if(!included) { if(!printinfected) logg("~%s: Excluded\n", dirname); return; } } if(depth > (unsigned int) optget(opts, "max-dir-recursion")->numarg) return; dirlnk = optget(opts, "follow-dir-symlinks")->numarg; filelnk = optget(opts, "follow-file-symlinks")->numarg; if((dd = opendir(dirname)) != NULL) { info.dirs++; depth++; while((dent = readdir(dd))) { if(dent->d_ino) { if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { /* build the full name */ fname = malloc(strlen(dirname) + strlen(dent->d_name) + 2); if (fname == NULL) { /* oops, malloc() failed, print warning and return */ logg("!scandirs: Memory allocation failed for fname\n"); break; } if(!strcmp(dirname, PATHSEP)) sprintf(fname, PATHSEP"%s", dent->d_name); else sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name); /* stat the file */ if(LSTAT(fname, &sb) != -1) { if(!optget(opts, "cross-fs")->enabled) { if(sb.st_dev != dev) { if(!printinfected) logg("~%s: Excluded\n", fname); free(fname); continue; } } if(S_ISLNK(sb.st_mode)) { if(dirlnk != 2 && filelnk != 2) { if(!printinfected) logg("%s: Symbolic link\n", fname); } else if(CLAMSTAT(fname, &sb) != -1) { if(S_ISREG(sb.st_mode) && filelnk == 2) { scanfile(fname, engine, opts, options); } else if(S_ISDIR(sb.st_mode) && dirlnk == 2) { if(recursion) scandirs(fname, engine, opts, options, depth, dev); } else { if(!printinfected) logg("%s: Symbolic link\n", fname); } } } else if(S_ISREG(sb.st_mode)) { scanfile(fname, engine, opts, options); } else if(S_ISDIR(sb.st_mode) && recursion) { scandirs(fname, engine, opts, options, depth, dev); } } free(fname); } } } closedir(dd); } else { if(!printinfected) logg("~%s: Can't open directory.\n", dirname); info.errors++; } }
static int scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options, unsigned int depth) { DIR *dd; struct dirent *dent; struct stat statbuf; char *fname; int scanret = 0, included; unsigned int maxdepth; const struct optnode *optnode; char *argument; if(opt_check(opt, "exclude-dir")) { argument = opt_firstarg(opt, "exclude-dir", &optnode); while(argument) { if(cli_matchregex(dirname, argument)) { if(!printinfected) logg("~%s: Excluded\n", dirname); return 0; } argument = opt_nextarg(&optnode, "exclude-dir"); } } if(opt_check(opt, "include-dir")) { included = 0; argument = opt_firstarg(opt, "include-dir", &optnode); while(argument && !included) { if(cli_matchregex(dirname, argument)) { included = 1; break; } argument = opt_nextarg(&optnode, "include-dir"); } if(!included) { if(!printinfected) logg("~%s: Excluded\n", dirname); return 0; } } if(opt_check(opt, "max-dir-recursion")) maxdepth = atoi(opt_arg(opt, "max-dir-recursion")); else maxdepth = 15; if(depth > maxdepth) return 0; info.dirs++; depth++; if((dd = opendir(dirname)) != NULL) { while((dent = readdir(dd))) { #if !defined(C_INTERIX) && !defined(_WIN32) if(dent->d_ino) #endif { if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { /* build the full name */ fname = malloc(strlen(dirname) + strlen(dent->d_name) + 2); if(!strcmp(dirname, "/")) sprintf(fname, "/%s", dent->d_name); else sprintf(fname, "%s/%s", dirname, dent->d_name); #ifdef _WIN32 NORMALIZE_PATH(fname, 1, continue); #endif /* stat the file */ if(lstat(fname, &statbuf) != -1) { if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode) && recursion) { if(scandirs(fname, engine, opt, limits, options, depth) == 1) scanret++; } else { if(S_ISREG(statbuf.st_mode)) scanret += scanfile(fname, engine, opt, limits, options); } } free(fname); } } } } else {