summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c571
1 files changed, 571 insertions, 0 deletions
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 00000000..fdb99c51
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,571 @@
+/**
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ * XML Parser transform and utility functions.
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ */
+#include "globals.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/transforms.h>
+#include <xmlsec/parser.h>
+#include <xmlsec/errors.h>
+
+/**************************************************************************
+ *
+ * Internal parser
+ *
+ *****************************************************************************/
+typedef struct _xmlSecParserCtx xmlSecParserCtx,
+ *xmlSecParserCtxPtr;
+struct _xmlSecParserCtx {
+ xmlParserCtxtPtr parserCtx;
+};
+
+/**************************************************************************
+ *
+ * XML Parser transform
+ *
+ * xmlSecParserCtx is located after xmlSecTransform
+ *
+ ***************************************************************************/
+#define xmlSecParserSize \
+ (sizeof(xmlSecTransform) + sizeof(xmlSecParserCtx))
+#define xmlSecParserGetCtx(transform) \
+ ((xmlSecTransformCheckSize((transform), xmlSecParserSize)) ? \
+ ((xmlSecParserCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) : \
+ (xmlSecParserCtxPtr)NULL)
+
+static int xmlSecParserInitialize (xmlSecTransformPtr transform);
+static void xmlSecParserFinalize (xmlSecTransformPtr transform);
+static int xmlSecParserPushBin (xmlSecTransformPtr transform,
+ const xmlSecByte* data,
+ xmlSecSize dataSize,
+ int final,
+ xmlSecTransformCtxPtr transformCtx);
+static int xmlSecParserPopXml (xmlSecTransformPtr transform,
+ xmlSecNodeSetPtr* nodes,
+ xmlSecTransformCtxPtr transformCtx);
+
+static xmlSecTransformKlass xmlSecParserKlass = {
+ /* klass/object sizes */
+ sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
+ xmlSecParserSize, /* xmlSecSize objSize */
+
+ BAD_CAST "xml-parser", /* const xmlChar* name; */
+ NULL, /* const xmlChar* href; */
+ xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */
+
+ xmlSecParserInitialize, /* xmlSecTransformInitializeMethod initialize; */
+ xmlSecParserFinalize, /* xmlSecTransformFinalizeMethod finalize; */
+ NULL, /* xmlSecTransformNodeReadMethod readNode; */
+ NULL, /* xmlSecTransformNodeWriteMethod writeNode; */
+ NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */
+ NULL, /* xmlSecTransformSetKeyMethod setKey; */
+ NULL, /* xmlSecTransformValidateMethod validate; */
+ xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */
+ xmlSecParserPushBin, /* xmlSecTransformPushBinMethod pushBin; */
+ NULL, /* xmlSecTransformPopBinMethod popBin; */
+ NULL, /* xmlSecTransformPushXmlMethod pushXml; */
+ xmlSecParserPopXml, /* xmlSecTransformPopXmlMethod popXml; */
+ NULL, /* xmlSecTransformExecuteMethod execute; */
+
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecTransformXmlParserGetKlass:
+ *
+ * The XML parser transform.
+ *
+ * Returns: XML parser transform klass.
+ */
+xmlSecTransformId
+xmlSecTransformXmlParserGetKlass(void) {
+ return(&xmlSecParserKlass);
+}
+
+static int
+xmlSecParserInitialize(xmlSecTransformPtr transform) {
+ xmlSecParserCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecParserSize), -1);
+
+ ctx = xmlSecParserGetCtx(transform);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ /* initialize context */
+ memset(ctx, 0, sizeof(xmlSecParserCtx));
+ return(0);
+}
+
+static void
+xmlSecParserFinalize(xmlSecTransformPtr transform) {
+ xmlSecParserCtxPtr ctx;
+
+ xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId));
+ xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecParserSize));
+
+ ctx = xmlSecParserGetCtx(transform);
+ xmlSecAssert(ctx != NULL);
+
+ if(ctx->parserCtx != NULL) {
+ xmlFreeParserCtxt(ctx->parserCtx);
+ }
+ memset(ctx, 0, sizeof(xmlSecParserCtx));
+}
+
+static int
+xmlSecParserPushBin(xmlSecTransformPtr transform, const xmlSecByte* data,
+ xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) {
+ xmlSecParserCtxPtr ctx;
+ int ret;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId), -1);
+ xmlSecAssert2(transformCtx != NULL, -1);
+
+ ctx = xmlSecParserGetCtx(transform);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ /* check/update current transform status */
+ if(transform->status == xmlSecTransformStatusNone) {
+ xmlSecAssert2(ctx->parserCtx == NULL, -1);
+
+ ctx->parserCtx = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
+ if(ctx->parserCtx == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlCreatePushParserCtxt",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* required for c14n! */
+ ctx->parserCtx->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ ctx->parserCtx->replaceEntities = 1;
+
+ transform->status = xmlSecTransformStatusWorking;
+ } else if(transform->status == xmlSecTransformStatusFinished) {
+ return(0);
+ } else if(transform->status != xmlSecTransformStatusWorking) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_STATUS,
+ "status=%d", transform->status);
+ return(-1);
+ }
+ xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1);
+ xmlSecAssert2(ctx->parserCtx != NULL, -1);
+
+ /* push data to the input buffer */
+ if((data != NULL) && (dataSize > 0)) {
+ ret = xmlParseChunk(ctx->parserCtx, (const char*)data, dataSize, 0);
+ if(ret != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlParseChunk",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "size=%d", dataSize);
+ return(-1);
+ }
+ }
+
+ /* finish parsing and push to next in the chain */
+ if(final != 0) {
+ ret = xmlParseChunk(ctx->parserCtx, NULL, 0, 1);
+ if((ret != 0) || (ctx->parserCtx->myDoc == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlParseChunk",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* todo: check that document is well formed? */
+ transform->outNodes = xmlSecNodeSetCreate(ctx->parserCtx->myDoc,
+ NULL, xmlSecNodeSetTree);
+ if(transform->outNodes == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecNodeSetCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFreeDoc(ctx->parserCtx->myDoc);
+ ctx->parserCtx->myDoc = NULL;
+ return(-1);
+ }
+ xmlSecNodeSetDocDestroy(transform->outNodes); /* this node set "owns" the doc pointer */
+ ctx->parserCtx->myDoc = NULL;
+
+ /* push result to the next transform (if exist) */
+ if(transform->next != NULL) {
+ ret = xmlSecTransformPushXml(transform->next, transform->outNodes, transformCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecTransformPushXml",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+
+ transform->status = xmlSecTransformStatusFinished;
+ }
+
+ return(0);
+}
+
+static int
+xmlSecParserPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes,
+ xmlSecTransformCtxPtr transformCtx) {
+ xmlSecParserCtxPtr ctx;
+ xmlParserInputBufferPtr buf;
+ xmlParserInputPtr input;
+ xmlParserCtxtPtr ctxt;
+ xmlDocPtr doc;
+ int ret;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId), -1);
+ xmlSecAssert2(nodes != NULL, -1);
+ xmlSecAssert2(transformCtx != NULL, -1);
+
+ ctx = xmlSecParserGetCtx(transform);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ /* check/update current transform status */
+ switch(transform->status) {
+ case xmlSecTransformStatusNone:
+ transform->status = xmlSecTransformStatusWorking;
+ break;
+ case xmlSecTransformStatusWorking:
+ /* just do nothing */
+ break;
+ case xmlSecTransformStatusFinished:
+ (*nodes) = NULL;
+ return(0);
+ default:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_STATUS,
+ "status=%d", transform->status);
+ return(-1);
+ }
+ xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1);
+
+ /* prepare parser context */
+ if(transform->prev == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_TRANSFORM,
+ "prev transform is null");
+ return(-1);
+ }
+
+ buf = xmlSecTransformCreateInputBuffer(transform->prev, transformCtx);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecTransformCreateInputBuffer",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ ctxt = xmlNewParserCtxt();
+ if (ctxt == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlNewParserCtxt",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFreeParserInputBuffer(buf);
+ return(-1);
+ }
+
+ input = xmlNewIOInputStream(ctxt, buf, XML_CHAR_ENCODING_NONE);
+ if(input == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlNewParserCtxt",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFreeParserCtxt(ctxt);
+ xmlFreeParserInputBuffer(buf);
+ return(-1);
+ }
+
+ ret = inputPush(ctxt, input);
+ if(input == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "inputPush",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFreeInputStream(input);
+ xmlFreeParserCtxt(ctxt);
+ return(-1);
+ }
+
+ /* required for c14n! */
+ ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ ctxt->replaceEntities = 1;
+
+ /* finaly do the parsing */
+ ret = xmlParseDocument(ctxt);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlParseDocument",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ if(ctxt->myDoc != NULL) {
+ xmlFreeDoc(ctxt->myDoc);
+ ctxt->myDoc = NULL;
+ }
+ xmlFreeParserCtxt(ctxt);
+ return(-1);
+ }
+
+ /* remember the result and free parsing context */
+ doc = ctxt->myDoc;
+ ctxt->myDoc = NULL;
+ xmlFreeParserCtxt(ctxt);
+
+ /* return result to the caller */
+ (*nodes) = xmlSecNodeSetCreate(doc, NULL, xmlSecNodeSetTree);
+ if((*nodes) == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecNodeSetCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFreeDoc(doc);
+ return(-1);
+ }
+ xmlSecNodeSetDocDestroy((*nodes)); /* this node set "owns" the doc pointer */
+ transform->status = xmlSecTransformStatusFinished;
+ return(0);
+}
+
+/**************************************************************************
+ *
+ * XML Parser functions
+ *
+ *************************************************************************/
+typedef struct _xmlSecExtMemoryParserCtx {
+ const xmlSecByte *prefix;
+ xmlSecSize prefixSize;
+ const xmlSecByte *buffer;
+ xmlSecSize bufferSize;
+ const xmlSecByte *postfix;
+ xmlSecSize postfixSize;
+} xmlSecExtMemoryParserCtx, *xmlSecExtMemoryParserCtxPtr;
+
+/**
+ * xmlSecParseFile:
+ * @filename: the filename.
+ *
+ * Loads XML Doc from file @filename. We need a special version because of
+ * c14n issue. The code is copied from xmlSAXParseFileWithData() function.
+ *
+ * Returns: pointer to the loaded XML document or NULL if an error occurs.
+ */
+xmlDocPtr
+xmlSecParseFile(const char *filename) {
+ xmlDocPtr ret;
+ xmlParserCtxtPtr ctxt;
+ char *directory = NULL;
+
+ xmlSecAssert2(filename != NULL, NULL);
+
+ xmlInitParser();
+ ctxt = xmlCreateFileParserCtxt(filename);
+ if (ctxt == NULL) {
+ return(NULL);
+ }
+
+ /* todo: set directories from current doc? */
+ if ((ctxt->directory == NULL) && (directory == NULL))
+ directory = xmlParserGetDirectory(filename);
+ if ((ctxt->directory == NULL) && (directory != NULL))
+ ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
+
+ /* required for c14n! */
+ ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ ctxt->replaceEntities = 1;
+
+ xmlParseDocument(ctxt);
+
+ if(ctxt->wellFormed) {
+ ret = ctxt->myDoc;
+ } else {
+ ret = NULL;
+ xmlFreeDoc(ctxt->myDoc);
+ ctxt->myDoc = NULL;
+ }
+ xmlFreeParserCtxt(ctxt);
+ return(ret);
+
+}
+
+/**
+ * xmlSecParseMemoryExt:
+ * @prefix: the first part of the input.
+ * @prefixSize: the size of the first part of the input.
+ * @buffer: the second part of the input.
+ * @bufferSize: the size of the second part of the input.
+ * @postfix: the third part of the input.
+ * @postfixSize: the size of the third part of the input.
+ *
+ * Loads XML Doc from 3 chunks of memory: @prefix, @buffer and @postfix.
+ *
+ * Returns: pointer to the loaded XML document or NULL if an error occurs.
+ */
+xmlDocPtr
+xmlSecParseMemoryExt(const xmlSecByte *prefix, xmlSecSize prefixSize,
+ const xmlSecByte *buffer, xmlSecSize bufferSize,
+ const xmlSecByte *postfix, xmlSecSize postfixSize) {
+ xmlParserCtxtPtr ctxt = NULL;
+ xmlDocPtr doc = NULL;
+ int ret;
+
+ /* create context */
+ ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
+ if(ctxt == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlCreatePushParserCtxt",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ /* required for c14n! */
+ ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ ctxt->replaceEntities = 1;
+
+ /* prefix */
+ if((prefix != NULL) && (prefixSize > 0)) {
+ ret = xmlParseChunk(ctxt, (const char*)prefix, prefixSize, 0);
+ if(ret != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlParseChunk",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "prefixSize=%d", prefixSize);
+ goto done;
+ }
+ }
+
+ /* buffer */
+ if((buffer != NULL) && (bufferSize > 0)) {
+ ret = xmlParseChunk(ctxt, (const char*)buffer, bufferSize, 0);
+ if(ret != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlParseChunk",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "bufferSize=%d", bufferSize);
+ goto done;
+ }
+ }
+
+ /* postfix */
+ if((postfix != NULL) && (postfixSize > 0)) {
+ ret = xmlParseChunk(ctxt, (const char*)postfix, postfixSize, 0);
+ if(ret != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlParseChunk",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "postfixSize=%d", postfixSize);
+ goto done;
+ }
+ }
+
+ /* finishing */
+ ret = xmlParseChunk(ctxt, NULL, 0, 1);
+ if((ret != 0) || (ctxt->myDoc == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlParseChunk",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ doc = ctxt->myDoc;
+
+done:
+ if(ctxt != NULL) {
+ xmlFreeParserCtxt(ctxt);
+ }
+ return(doc);
+}
+
+
+/**
+ * xmlSecParseMemory:
+ * @buffer: the input buffer.
+ * @size: the input buffer size.
+ * @recovery: the flag.
+ *
+ * Loads XML Doc from memory. We need a special version because of
+ * c14n issue. The code is copied from xmlSAXParseMemory() function.
+ *
+ * Returns: pointer to the loaded XML document or NULL if an error occurs.
+ */
+xmlDocPtr
+xmlSecParseMemory(const xmlSecByte *buffer, xmlSecSize size, int recovery) {
+ xmlDocPtr ret;
+ xmlParserCtxtPtr ctxt;
+
+ xmlSecAssert2(buffer != NULL, NULL);
+
+ ctxt = xmlCreateMemoryParserCtxt((char*)buffer, size);
+ if (ctxt == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlCreateMemoryParserCtxt",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ /* required for c14n! */
+ ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ ctxt->replaceEntities = 1;
+
+ xmlParseDocument(ctxt);
+
+ if((ctxt->wellFormed) || recovery) {
+ ret = ctxt->myDoc;
+ } else {
+ ret = NULL;
+ xmlFreeDoc(ctxt->myDoc);
+ ctxt->myDoc = NULL;
+ }
+ xmlFreeParserCtxt(ctxt);
+ return(ret);
+}
+