/*********************************************************
- * Copyright (C) 2016-2021 VMware, Inc. All rights reserved.
+ * Copyright (C) 2016-2022 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
#include <libxml/parser.h>
#include <libxml/catalog.h>
#include <libxml/xmlschemas.h>
+#include <libxml/xmlIO.h>
+#include <libxml/uri.h>
#include <xmlsec/xmlsec.h>
#include <xmlsec/xmltree.h>
#define CATALOG_FILENAME "catalog.xml"
#define SAML_SCHEMA_FILENAME "saml-schema-assertion-2.0.xsd"
+
+/*
+ ******************************************************************************
+ * UserXmlFileOpen -- */ /**
+ *
+ * User defined version of libxml2 export xmlFileOpen.
+ *
+ * This function opens a file with its unescaped name only.
+ *
+ * xmlInitParser() calls xmlRegisterDefaultInputCallbacks() which calls
+ * xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
+ * xmlFileRead, xmlFileClose)
+ *
+ * UserXmlFileOpen is registered at the end of the xmlInputCallback table by
+ * xmlRegisterInputCallbacks(xmlFileMatch, UserXmlFileOpen,
+ * xmlFileRead, xmlFileClose)
+ *
+ * Based on libxml2 xmlIO.c, precedence is given to user defined handlers.
+ *
+ * @param[in] filename The URI file name.
+ *
+ * @return A handler or NULL in case of failure.
+ ******************************************************************************
+ */
+
+static void *
+UserXmlFileOpen(const char *filename)
+{
+ char *unescaped;
+ void *retval = NULL;
+
+ g_debug("%s: Incoming file name is \"%s\"\n", __FUNCTION__, filename);
+
+ unescaped = xmlURIUnescapeString(filename, 0, NULL);
+ if (unescaped != NULL) {
+ g_debug("%s: Opening file \"%s\"\n", __FUNCTION__, unescaped);
+ retval = xmlFileOpen(unescaped);
+ xmlFree(unescaped);
+ }
+
+ if (retval == NULL) {
+ g_warning("%s: Failed to open file \"%s\"\n", __FUNCTION__, filename);
+ /*
+ * Do not retry xmlFileOpen(filename) here.
+ * Calling system API to open escaped file paths is risky. This can
+ * cause unexpected not-secured paths being accessed and expose
+ * privilege escalation vulnerabilities.
+ */
+ }
+
+ return retval;
+}
+
+
/*
* Hack to test expired tokens and by-pass the time checks.
*
catalogPath = g_build_filename(schemaDir, CATALOG_FILENAME, NULL);
schemaPath = g_build_filename(schemaDir, SAML_SCHEMA_FILENAME, NULL);
- xmlInitializeCatalog();
-
/*
+ * Skip calling xmlInitializeCatalog().
+ *
* xmlLoadCatalog() just adds to the default catalog, and won't return an
* error if it doesn't exist so long as a default catalog is set.
*
/* set up the xml2 error handler */
xmlSetGenericErrorFunc(NULL, XmlErrorHandler);
+ /*
+ * Register user defined UserXmlFileOpen
+ */
+ xmlRegisterInputCallbacks(xmlFileMatch, UserXmlFileOpen,
+ xmlFileRead, xmlFileClose);
+
/*
* Load schemas
*/