void fileblobPartialSet(fileblob *fb, const char *fullname, const char *arg) { UNUSEDPARAM(arg); if(fb->b.name) return; assert(fullname != NULL); cli_dbgmsg("fileblobPartialSet: saving to %s\n", fullname); fb->fd = open(fullname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY|O_EXCL, 0600); if(fb->fd < 0) { cli_errmsg("fileblobPartialSet: unable to create file: %s\n",fullname); return; } fb->fp = fdopen(fb->fd, "wb"); if(fb->fp == NULL) { cli_errmsg("fileblobSetFilename: fdopen failed\n"); close(fb->fd); return; } blobSetFilename(&fb->b, fb->ctx ? fb->ctx->engine->tmpdir : NULL, fullname); if(fb->b.data) if(fileblobAddData(fb, fb->b.data, fb->b.len) == 0) { free(fb->b.data); fb->b.data = NULL; fb->b.len = fb->b.size = 0; fb->isNotEmpty = 1; } fb->fullname = cli_strdup(fullname); }
/* * Returns the value, or -1 for failure */ int tableInsert(table_t *table, const char *key, int value) { const int v = tableFind(table, key); if(v > 0) /* duplicate key */ return (v == value) ? value : -1; /* allow real dups */ assert(value != -1); /* that would confuse us */ if(table->tableHead == NULL) table->tableLast = table->tableHead = (tableEntry *)cli_malloc(sizeof(tableEntry)); else { /* * Re-use deleted items */ if(table->flags&TABLE_HAS_DELETED_ENTRIES) { tableEntry *tableItem; assert(table->tableHead != NULL); for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) if(tableItem->key == NULL) { /* This item has been deleted */ tableItem->key = cli_strdup(key); tableItem->value = value; return value; } table->flags &= ~TABLE_HAS_DELETED_ENTRIES; } table->tableLast = table->tableLast->next = (tableEntry *)cli_malloc(sizeof(tableEntry)); } if(table->tableLast == NULL) { cli_dbgmsg("tableInsert: Unable to allocate memory for table\n"); return -1; } table->tableLast->next = NULL; table->tableLast->key = cli_strdup(key); table->tableLast->value = value; return value; }
/*lint -e578*/ static void cli_history_item_init( cli_history_item_t * item, const cli_int8 * line, cli_uint32 index) { item->line = cli_strdup(line); item->index = index; }
/*ARGSUSED*/ void blobSetFilename(blob *b, const char *dir, const char *filename) { assert(b != NULL); assert(b->magic == BLOBCLASS); assert(filename != NULL); cli_dbgmsg("blobSetFilename: %s\n", filename); if(b->name) free(b->name); b->name = cli_strdup(filename); if(b->name) sanitiseName(b->name); }
static char *cab_readstr(int fd, int *ret) { int i, bread, found = 0; char buff[256], *str; off_t pos; if((pos = lseek(fd, 0, SEEK_CUR)) == -1) { *ret = CL_ESEEK; return NULL; } bread = read(fd, buff, sizeof(buff)); for(i = 0; i < bread; i++) { if(!buff[i]) { found = 1; break; } } if(!found) { *ret = CL_EFORMAT; return NULL; } if(lseek(fd, (off_t) (pos + i + 1), SEEK_SET) == -1) { *ret = CL_EFORMAT; /* most likely a corrupted file */ return NULL; } if(!(str = cli_strdup(buff))) { *ret = CL_EMEM; return NULL; } *ret = CL_SUCCESS; return str; }
/* buffer is html-normlike "chunk", if original file is bigger than buffer, * we rewind to a space, so we'll know that tokens won't be broken in half at * the end of a buffer. All tokens except string-literals of course. * So we can assume that after the buffer there is either a space, EOF, or a * chunk of text not containing whitespace at all (for which we care only if its * a stringliteral)*/ void cli_js_process_buffer(struct parser_state *state, const char *buf, size_t n) { struct scope* current = state->current; YYSTYPE val; int yv; YY_BUFFER_STATE yyb; if(!state->global) { /* this state has either not been initialized, * or cli_js_parse_done() was already called on it */ cli_warnmsg(MODULE "invalid state\n"); return; } yyb = yy_scan_bytes(buf, n, state->scanner); memset(&val, 0, sizeof(val)); val.vtype = vtype_undefined; /* on EOF yylex will return 0 */ while( (yv=yylex(&val, state->scanner)) != 0) { const char *text; size_t leng; val.type = yv; switch(yv) { case TOK_VAR: current->fsm_state = InsideVar; break; case TOK_IDENTIFIER_NAME: text = yyget_text(state->scanner); leng = yyget_leng(state->scanner); if(current->last_token == TOK_DOT) { /* this is a member name, don't normalize */ TOKEN_SET(&val, string, cli_strdup(text)); val.type = TOK_UNNORM_IDENTIFIER; } else { switch(current->fsm_state) { case WaitParameterList: state->syntax_errors++; /* fall through */ case Base: case InsideInitializer: TOKEN_SET(&val, cstring, scope_use(current, text, leng)); break; case InsideVar: case InsideFunctionDecl: TOKEN_SET(&val, cstring, scope_declare(current, text, leng, state)); current->fsm_state = InsideInitializer; current->brackets = 0; break; case WaitFunctionName: TOKEN_SET(&val, cstring, scope_declare(current, text, leng, state)); current->fsm_state = WaitParameterList; break; } } break; case TOK_PAR_OPEN: switch(current->fsm_state) { case WaitFunctionName: /* fallthrough */ case WaitParameterList: current->fsm_state = InsideFunctionDecl; break; default: /* noop */ break; } break; case TOK_PAR_CLOSE: switch(current->fsm_state) { case WaitFunctionName: state->syntax_errors++; break; case WaitParameterList: current->fsm_state = Base; break; default: /* noop */ break; } break; case TOK_CURLY_BRACE_OPEN: switch(current->fsm_state) { case WaitFunctionName: /* fallthrough */ case WaitParameterList: case InsideFunctionDecl: /* in a syntactically correct * file, we would already be in * the Base state when we see a { */ current->fsm_state = Base; /* fall-through */ case InsideVar: case InsideInitializer: state->syntax_errors++; /* fall-through */ case Base: default: current->blocks++; break; } break; case TOK_CURLY_BRACE_CLOSE: if(current->blocks > 0) current->blocks--; else state->syntax_errors++; if(!current->blocks) { if(current->parent) { /* add dummy FUNCTION token to * mark function end */ TOKEN_SET(&val, cstring, "}"); add_token(state, &val); TOKEN_SET(&val, scope, NULL); val.type = TOK_FUNCTION; state->current = current = current->parent; } else{ /* extra } */ state->syntax_errors++; } } break; case TOK_BRACKET_OPEN: current->brackets++; break; case TOK_BRACKET_CLOSE: if(current->brackets > 0) current->brackets--; else state->syntax_errors++; break; case TOK_COMMA: if (current->fsm_state == InsideInitializer && current->brackets == 0 && current->blocks == 0) { /* initializer ended only if we * encountered a comma, and [] are * balanced. * This avoids switching state on: * var x = [4,y,u];*/ current->fsm_state = InsideVar; } break; case TOK_SEMICOLON: if (current->brackets == 0 && current->blocks == 0) { /* avoid switching state on unbalanced []: * var x = [test;testi]; */ current->fsm_state = Base; } break; case TOK_FUNCTION: current = scope_new(state); current->fsm_state = WaitFunctionName; TOKEN_SET(&val, scope, state->current); break; case TOK_StringLiteral: if(state->tokens.cnt > 1 && state->tokens.data[state->tokens.cnt-1].type == TOK_PLUS) { /* see if can fold */ yystype *prev_string = &state->tokens.data[state->tokens.cnt-2]; if(prev_string->type == TOK_StringLiteral) { char *str = TOKEN_GET(prev_string, string); size_t str_len = strlen(str); text = yyget_text(state->scanner); leng = yyget_leng(state->scanner); /* delete TOK_PLUS */ free_token(&state->tokens.data[--state->tokens.cnt]); str = cli_realloc(str, str_len + leng + 1); if (!str) break; strncpy(str+str_len, text, leng); str[str_len + leng] = '\0'; TOKEN_SET(prev_string, string, str); free(val.val.string); memset(&val, 0, sizeof(val)); val.vtype = vtype_undefined; continue; } } break; } if(val.vtype == vtype_undefined) { text = yyget_text(state->scanner); TOKEN_SET(&val, string, cli_strdup(text)); abort(); } add_token(state, &val); current->last_token = yv; memset(&val, 0, sizeof(val)); val.vtype = vtype_undefined; } }
char *pdf_finalize_string(struct pdf_struct *pdf, struct pdf_obj *obj, const char *in, size_t len) { char *wrkstr, *output = NULL; size_t wrklen = len, outlen; unsigned int i, likelyutf = 0; if (!in) return NULL; /* get a working copy */ wrkstr = cli_calloc(len+1, sizeof(char)); if (!wrkstr) return NULL; memcpy(wrkstr, in, len); //cli_errmsg("pdf_final: start(%d): %s\n", wrklen, wrkstr); /* convert PDF specific escape sequences, like octal sequences */ /* TODO: replace the escape sequences directly in the wrkstr */ if (strchr(wrkstr, '\\')) { output = cli_calloc(wrklen+1, sizeof(char)); if (!output) { free(wrkstr); return NULL; } outlen = 0; for (i = 0; i < wrklen; ++i) { if ((i+1 < wrklen) && wrkstr[i] == '\\') { if ((i+3 < wrklen) && (isdigit(wrkstr[i+1]) && isdigit(wrkstr[i+2]) && isdigit(wrkstr[i+3]))) { /* octal sequence */ char octal[4], *check; unsigned long value; memcpy(octal, &wrkstr[i+1], 3); octal[3] = '\0'; value = (char)strtoul(octal, &check, 8); /* check if all characters were converted */ if (check == &octal[3]) output[outlen++] = value; i += 3; /* 4 with for loop [\ddd] */ } else { /* other sequences */ switch(wrkstr[i+1]) { case 'n': output[outlen++] = 0x0a; break; case 'r': output[outlen++] = 0x0d; break; case 't': output[outlen++] = 0x09; break; case 'b': output[outlen++] = 0x08; break; case 'f': output[outlen++] = 0x0c; break; case '(': output[outlen++] = 0x28; break; case ')': output[outlen++] = 0x29; break; case '\\': output[outlen++] = 0x5c; break; default: /* IGNORE THE REVERSE SOLIDUS - PDF3000-2008 */ break; } i += 1; /* 2 with for loop [\c] */ } } else { output[outlen++] = wrkstr[i]; } } free(wrkstr); wrkstr = cli_strdup(output); free(output); wrklen = outlen; } //cli_errmsg("pdf_final: escaped(%d): %s\n", wrklen, wrkstr); /* check for encryption and decrypt */ if (pdf->flags & (1 << ENCRYPTED_PDF)) { off_t tmpsz = (off_t)wrklen; output = pdf_decrypt_string(pdf, obj, wrkstr, &tmpsz); outlen = (size_t)tmpsz; free(wrkstr); if (output) { wrkstr = cli_calloc(outlen+1, sizeof(char)); if (!wrkstr) { free(output); return NULL; } memcpy(wrkstr, output, outlen); free(output); wrklen = outlen; } else { return NULL; } } //cli_errmsg("pdf_final: decrypt(%d): %s\n", wrklen, wrkstr); /* check for UTF-* and convert to UTF-8 */ for (i = 0; i < wrklen; ++i) { if (((unsigned char)wrkstr[i] > (unsigned char)0x7f) || (wrkstr[i] == '\0')) { likelyutf = 1; break; } } if (likelyutf) { output = pdf_convert_utf(wrkstr, wrklen); free(wrkstr); wrkstr = output; } //cli_errmsg("pdf_final: postutf(%d): %s\n", wrklen, wrkstr); return wrkstr; }
int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, unsigned int dbtype, const char *filename, unsigned int chkonly) { struct cl_cvd cvd, dupcvd; FILE *dupfs; int ret; time_t s_time; int cfd; struct cli_dbio dbio; struct cli_dbinfo *dbinfo = NULL; char *dupname; dbio.hashctx = NULL; cli_dbgmsg("in cli_cvdload()\n"); /* verify */ if((ret = cli_cvdverify(fs, &cvd, dbtype))) return ret; if(dbtype <= 1) { /* check for duplicate db */ dupname = cli_strdup(filename); if(!dupname) return CL_EMEM; dupname[strlen(dupname) - 2] = (dbtype == 1 ? 'v' : 'l'); if(!access(dupname, R_OK) && (dupfs = fopen(dupname, "rb"))) { if((ret = cli_cvdverify(dupfs, &dupcvd, !dbtype))) { fclose(dupfs); free(dupname); return ret; } fclose(dupfs); if(dupcvd.version > cvd.version) { cli_warnmsg("Detected duplicate databases %s and %s. The %s database is older and will not be loaded, you should manually remove it from the database directory.\n", filename, dupname, filename); free(dupname); return CL_SUCCESS; } else if(dupcvd.version == cvd.version && !dbtype) { cli_warnmsg("Detected duplicate databases %s and %s, please manually remove one of them\n", filename, dupname); free(dupname); return CL_SUCCESS; } } free(dupname); } if(strstr(filename, "daily.")) { time(&s_time); if(cvd.stime > s_time) { if(cvd.stime - (unsigned int ) s_time > 3600) { cli_warnmsg("******************************************************\n"); cli_warnmsg("*** Virus database timestamp in the future! ***\n"); cli_warnmsg("*** Please check the timezone and clock settings ***\n"); cli_warnmsg("******************************************************\n"); } } else if((unsigned 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"); } engine->dbversion[0] = cvd.version; engine->dbversion[1] = cvd.stime; } 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"); } cfd = fileno(fs); dbio.chkonly = 0; if(dbtype == 2) ret = cli_tgzload(cfd, engine, signo, options | CL_DB_UNSIGNED, &dbio, NULL); else ret = cli_tgzload(cfd, engine, signo, options | CL_DB_OFFICIAL, &dbio, NULL); if(ret != CL_SUCCESS) return ret; dbinfo = engine->dbinfo; if(!dbinfo || !dbinfo->cvd || (dbinfo->cvd->version != cvd.version) || (dbinfo->cvd->sigs != cvd.sigs) || (dbinfo->cvd->fl != cvd.fl) || (dbinfo->cvd->stime != cvd.stime)) { cli_errmsg("cli_cvdload: Corrupted CVD header\n"); return CL_EMALFDB; } dbinfo = engine->dbinfo ? engine->dbinfo->next : NULL; if(!dbinfo) { cli_errmsg("cli_cvdload: dbinfo error\n"); return CL_EMALFDB; } dbio.chkonly = chkonly; if(dbtype == 2) options |= CL_DB_UNSIGNED; else options |= CL_DB_SIGNED | CL_DB_OFFICIAL; ret = cli_tgzload(cfd, engine, signo, options, &dbio, dbinfo); while(engine->dbinfo) { dbinfo = engine->dbinfo; engine->dbinfo = dbinfo->next; mpool_free(engine->mempool, dbinfo->name); mpool_free(engine->mempool, dbinfo->hash); if(dbinfo->cvd) cl_cvdfree(dbinfo->cvd); mpool_free(engine->mempool, dbinfo); } return ret; }
static void do_phishing_test(const struct rtest *rtest) { char *realurl; cli_ctx ctx; const char *virname = NULL; tag_arguments_t hrefs; int rc; memset(&ctx, 0, sizeof(ctx)); realurl = cli_strdup(rtest->realurl); fail_unless(!!realurl, "cli_strdup"); hrefs.count = 1; hrefs.value = cli_malloc(sizeof(*hrefs.value)); fail_unless(!!hrefs.value, "cli_malloc"); hrefs.value[0] = (unsigned char*)realurl; hrefs.contents = cli_malloc(sizeof(*hrefs.contents)); fail_unless(!!hrefs.contents, "cli_malloc"); hrefs.tag = cli_malloc(sizeof(*hrefs.tag)); fail_unless(!!hrefs.tag, "cli_malloc"); hrefs.tag[0] = (unsigned char*)cli_strdup("href"); hrefs.contents[0] = (unsigned char*)cli_strdup(rtest->displayurl); ctx.engine = engine; ctx.virname = &virname; rc = phishingScan(&ctx, &hrefs); html_tag_arg_free(&hrefs); fail_unless(rc == CL_CLEAN,"phishingScan"); switch(rtest->result) { case 0: fail_unless_fmt(ctx.found_possibly_unwanted, "this should be phishing, realURL: %s, displayURL: %s", rtest->realurl, rtest->displayurl); break; case 1: fail_unless_fmt(!ctx.found_possibly_unwanted, "this should be whitelisted, realURL: %s, displayURL: %s", rtest->realurl, rtest->displayurl); break; case 2: fail_unless_fmt(!ctx.found_possibly_unwanted, "this should be clean, realURL: %s, displayURL: %s", rtest->realurl, rtest->displayurl); break; case 3: if(!loaded_2) fail_unless_fmt(!ctx.found_possibly_unwanted, "this should be clean, realURL: %s, displayURL: %s", rtest->realurl, rtest->displayurl); else { fail_unless_fmt(ctx.found_possibly_unwanted, "this should be blacklisted, realURL: %s, displayURL: %s", rtest->realurl, rtest->displayurl); if (*ctx.virname) fail_unless_fmt(!strstr((const char*)*ctx.virname,"Blacklisted"), "should be blacklisted, but is: %s\n", ctx.virname); } break; } }