|
|
|
@ -78,11 +78,29 @@ static int ooxml_is_int(const char *value, size_t len, int32_t *val) |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ooxml_add_parse_error(json_object *wrkptr, const xmlChar *errstr) |
|
|
|
|
{ |
|
|
|
|
json_object *perr; |
|
|
|
|
|
|
|
|
|
if (!wrkptr) |
|
|
|
|
return CL_ENULLARG; |
|
|
|
|
|
|
|
|
|
perr = cli_jsonarray(wrkptr, "ParseErrors"); |
|
|
|
|
if (perr == NULL) { |
|
|
|
|
return CL_EMEM; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return cli_jsonstr(perr, NULL, errstr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ooxml_parse_value(json_object *wrkptr, const char *arrname, const xmlChar *node_value) |
|
|
|
|
{ |
|
|
|
|
json_object *newobj, *arrobj; |
|
|
|
|
int val; |
|
|
|
|
|
|
|
|
|
if (!wrkptr) |
|
|
|
|
return CL_ENULLARG; |
|
|
|
|
|
|
|
|
|
arrobj = cli_jsonarray(wrkptr, arrname); |
|
|
|
|
if (arrobj == NULL) { |
|
|
|
|
return CL_EMEM; |
|
|
|
@ -247,7 +265,7 @@ static int ooxml_parse_element(cli_ctx *ctx, xmlTextReaderPtr reader, json_objec |
|
|
|
|
|
|
|
|
|
if (node_type != XML_READER_TYPE_ELEMENT) { |
|
|
|
|
cli_dbgmsg("ooxml_parse_element: first node typed %d, not %d\n", node_type, XML_READER_TYPE_ELEMENT); |
|
|
|
|
return CL_EPARSE; /* first type is not an element */ |
|
|
|
|
return CL_EFORMAT; /* first type is not an element */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
node_name = xmlTextReaderConstLocalName(reader); |
|
|
|
@ -267,7 +285,7 @@ static int ooxml_parse_element(cli_ctx *ctx, xmlTextReaderPtr reader, json_objec |
|
|
|
|
/* generate json object */ |
|
|
|
|
thisjobj = cli_jsonobj(wrkptr, element_tag); |
|
|
|
|
if (!thisjobj) { |
|
|
|
|
return CL_EPARSE; |
|
|
|
|
return CL_EMEM; |
|
|
|
|
} |
|
|
|
|
cli_dbgmsg("ooxml_parse_element: generated json object [%s]\n", element_tag); |
|
|
|
|
|
|
|
|
@ -406,10 +424,8 @@ static int ooxml_parse_document(int fd, cli_ctx *ctx) |
|
|
|
|
|
|
|
|
|
ret = ooxml_parse_element(ctx, reader, ctx->wrkproperty, 0, NULL); |
|
|
|
|
|
|
|
|
|
if (ret != CL_SUCCESS && ret != CL_ETIMEOUT && ret != CL_BREAK) { |
|
|
|
|
if (ret != CL_SUCCESS && ret != CL_ETIMEOUT && ret != CL_BREAK) |
|
|
|
|
cli_warnmsg("ooxml_parse_document: encountered issue in parsing properties document\n"); |
|
|
|
|
cli_jsonbool(ctx->wrkproperty, "ParseError", 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
xmlTextReaderClose(reader); |
|
|
|
|
xmlFreeTextReader(reader); |
|
|
|
@ -418,21 +434,35 @@ static int ooxml_parse_document(int fd, cli_ctx *ctx) |
|
|
|
|
|
|
|
|
|
static int ooxml_core_cb(int fd, cli_ctx *ctx) |
|
|
|
|
{ |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
cli_dbgmsg("in ooxml_core_cb\n"); |
|
|
|
|
return ooxml_parse_document(fd, ctx); |
|
|
|
|
//return ooxml_basic_json(fd, ctx, "CoreProperties");
|
|
|
|
|
ret = ooxml_parse_document(fd, ctx); |
|
|
|
|
if (ret == CL_EPARSE) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_CORE_XMLPARSER"); |
|
|
|
|
else if (ret == CL_EFORMAT) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_CORE_MALFORMED"); |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ooxml_extn_cb(int fd, cli_ctx *ctx) |
|
|
|
|
{ |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
cli_dbgmsg("in ooxml_extn_cb\n"); |
|
|
|
|
return ooxml_parse_document(fd, ctx); |
|
|
|
|
//return ooxml_basic_json(fd, ctx, "ExtendedProperties");
|
|
|
|
|
ret = ooxml_parse_document(fd, ctx); |
|
|
|
|
if (ret == CL_EPARSE) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_EXTN_XMLPARSER"); |
|
|
|
|
else if (ret == CL_EFORMAT) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_EXTN_MALFORMED"); |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ooxml_content_cb(int fd, cli_ctx *ctx) |
|
|
|
|
{ |
|
|
|
|
int ret = CL_SUCCESS, tmp, toval = 0; |
|
|
|
|
int ret = CL_SUCCESS, tmp, toval = 0, state; |
|
|
|
|
int core=0, extn=0, cust=0, dsig=0; |
|
|
|
|
int mcore=0, mextn=0, mcust=0; |
|
|
|
|
const xmlChar *name, *value, *CT, *PN; |
|
|
|
@ -444,11 +474,12 @@ static int ooxml_content_cb(int fd, cli_ctx *ctx) |
|
|
|
|
reader = xmlReaderForFd(fd, "[Content_Types].xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS); |
|
|
|
|
if (reader == NULL) { |
|
|
|
|
cli_dbgmsg("ooxml_content_cb: xmlReaderForFd error for ""[Content_Types].xml""\n"); |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_XML_READER_FD"); |
|
|
|
|
return CL_SUCCESS; // libxml2 failed!
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* locate core-properties, extended-properties, and custom-properties (optional) */ |
|
|
|
|
while (xmlTextReaderRead(reader) == 1) { |
|
|
|
|
/* locate core-properties, extended-properties, and custom-properties (optional) */ |
|
|
|
|
while ((state = xmlTextReaderRead(reader)) == 1) { |
|
|
|
|
if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { |
|
|
|
|
ret = CL_ETIMEOUT; |
|
|
|
|
goto ooxml_content_exit; |
|
|
|
@ -480,88 +511,107 @@ static int ooxml_content_cb(int fd, cli_ctx *ctx) |
|
|
|
|
if (!CT && !PN) continue; |
|
|
|
|
|
|
|
|
|
if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-package.core-properties+xml")) { |
|
|
|
|
if (!core) { |
|
|
|
|
/* default: /docProps/core.xml*/ |
|
|
|
|
tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); |
|
|
|
|
if (tmp == CL_ETIMEOUT) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
else if (tmp != CL_VIRUS) { |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: failed to find core properties file \"%s\"!\n", PN); |
|
|
|
|
mcore++; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
cli_dbgmsg("ooxml_content_cb: found core properties file \"%s\" @ %x\n", PN, loff); |
|
|
|
|
ret = unzip_single_internal(ctx, loff, ooxml_core_cb); |
|
|
|
|
core++; |
|
|
|
|
/* default: /docProps/core.xml*/ |
|
|
|
|
tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); |
|
|
|
|
if (tmp == CL_ETIMEOUT) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
else if (tmp != CL_VIRUS) { |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: failed to find core properties file \"%s\"!\n", PN); |
|
|
|
|
mcore++; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
cli_dbgmsg("ooxml_content_cb: found core properties file \"%s\" @ %x\n", PN, loff); |
|
|
|
|
if (!core) { |
|
|
|
|
tmp = unzip_single_internal(ctx, loff, ooxml_core_cb); |
|
|
|
|
if (tmp == CL_ETIMEOUT || tmp == CL_EMEM) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
core++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-officedocument.extended-properties+xml")) { |
|
|
|
|
if (!extn) { |
|
|
|
|
/* default: /docProps/app.xml */ |
|
|
|
|
tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); |
|
|
|
|
if (tmp == CL_ETIMEOUT) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
else if (tmp != CL_VIRUS) { |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: failed to find extended properties file \"%s\"!\n", PN); |
|
|
|
|
mextn++; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
cli_dbgmsg("ooxml_content_cb: found extended properties file \"%s\" @ %x\n", PN, loff); |
|
|
|
|
ret = unzip_single_internal(ctx, loff, ooxml_extn_cb); |
|
|
|
|
extn++; |
|
|
|
|
/* default: /docProps/app.xml */ |
|
|
|
|
tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); |
|
|
|
|
if (tmp == CL_ETIMEOUT) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
else if (tmp != CL_VIRUS) { |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: failed to find extended properties file \"%s\"!\n", PN); |
|
|
|
|
mextn++; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
cli_dbgmsg("ooxml_content_cb: found extended properties file \"%s\" @ %x\n", PN, loff); |
|
|
|
|
if (!extn) { |
|
|
|
|
tmp = unzip_single_internal(ctx, loff, ooxml_extn_cb); |
|
|
|
|
if (tmp == CL_ETIMEOUT || tmp == CL_EMEM) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
extn++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-officedocument.custom-properties+xml")) { |
|
|
|
|
if (!cust) { |
|
|
|
|
/* default: /docProps/custom.xml */ |
|
|
|
|
tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); |
|
|
|
|
if (tmp == CL_ETIMEOUT) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
else if (tmp != CL_VIRUS) { |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: failed to find custom properties file \"%s\"!\n", PN); |
|
|
|
|
mcust++; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
cli_dbgmsg("ooxml_content_cb: found custom properties file \"%s\" @ %x\n", PN, loff); |
|
|
|
|
cust++; |
|
|
|
|
//ret = unzip_single_internal(ctx, loff, ooxml_cust_cb);
|
|
|
|
|
} |
|
|
|
|
/* default: /docProps/custom.xml */ |
|
|
|
|
tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); |
|
|
|
|
if (tmp == CL_ETIMEOUT) { |
|
|
|
|
ret = tmp; |
|
|
|
|
} |
|
|
|
|
else if (tmp != CL_VIRUS) { |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: failed to find custom properties file \"%s\"!\n", PN); |
|
|
|
|
mcust++; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
cli_dbgmsg("ooxml_content_cb: found custom properties file \"%s\" @ %x\n", PN, loff); |
|
|
|
|
/* custom properties are not parsed */ |
|
|
|
|
cust++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml")) { |
|
|
|
|
dsig++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ret != CL_BREAK && ret != CL_SUCCESS) |
|
|
|
|
if (ret != CL_SUCCESS) |
|
|
|
|
goto ooxml_content_exit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ooxml_content_exit: |
|
|
|
|
if (core) |
|
|
|
|
if (core) { |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "CorePropertiesFileCount", core); |
|
|
|
|
if (core > 1) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CORE_PROPFILES"); |
|
|
|
|
} |
|
|
|
|
else if (!mcore) |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: file does not contain core properties file\n"); |
|
|
|
|
if (mcore) |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "CorePropertiesMissingFileCount", core); |
|
|
|
|
if (mcore) { |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "CorePropertiesMissingFileCount", mcore); |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CORE_PROPFILES"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (extn) |
|
|
|
|
if (extn) { |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesFileCount", extn); |
|
|
|
|
if (extn > 1) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_EXTN_PROPFILES"); |
|
|
|
|
} |
|
|
|
|
else if (!mextn) |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: file does not contain extended properties file\n"); |
|
|
|
|
if (mextn) |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesMissingFileCount", extn); |
|
|
|
|
if (mextn) { |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesMissingFileCount", mextn); |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_EXTN_PROPFILES"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (cust) |
|
|
|
|
if (cust) { |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "CustomPropertiesFileCount", cust); |
|
|
|
|
if (cust > 1) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CUSTOM_PROPFILES"); |
|
|
|
|
} |
|
|
|
|
else if (!mcust) |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: file does not contain custom properties file\n"); |
|
|
|
|
if (mcust) |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "CustomPropertiesMissingFileCount", cust); |
|
|
|
|
if (mcust) { |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "CustomPropertiesMissingFileCount", mcust); |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CUST_PROPFILES"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (dsig) { |
|
|
|
|
cli_jsonint(ctx->wrkproperty, "DigitalSignaturesCount", dsig); |
|
|
|
@ -620,15 +670,23 @@ int cli_process_ooxml(cli_ctx *ctx) |
|
|
|
|
/* find "[Content Types].xml" */ |
|
|
|
|
tmp = unzip_search_single(ctx, "[Content_Types].xml", 18, &loff); |
|
|
|
|
if (tmp == CL_ETIMEOUT) { |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_TIMEOUT"); |
|
|
|
|
return CL_ETIMEOUT; |
|
|
|
|
} |
|
|
|
|
else if (tmp != CL_VIRUS) { |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: failed to find ""[Content_Types].xml""!\n"); |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_NO_CONTENT_TYPES"); |
|
|
|
|
return CL_EFORMAT; |
|
|
|
|
} |
|
|
|
|
cli_dbgmsg("cli_process_ooxml: found ""[Content_Types].xml"" @ %x\n", loff); |
|
|
|
|
|
|
|
|
|
return unzip_single_internal(ctx, loff, ooxml_content_cb); |
|
|
|
|
tmp = unzip_single_internal(ctx, loff, ooxml_content_cb); |
|
|
|
|
if (tmp == CL_ETIMEOUT) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_TIMEOUT"); |
|
|
|
|
else if (tmp == CL_EMEM) |
|
|
|
|
ooxml_add_parse_error(ctx->wrkproperty, "OOXML_ERROR_OUTOFMEM"); |
|
|
|
|
|
|
|
|
|
return tmp; |
|
|
|
|
#else |
|
|
|
|
UNUSEDPARAM(ctx); |
|
|
|
|
cli_dbgmsg("in cli_processooxml\n"); |
|
|
|
|