]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
VGAuth: Customize libxml2 to open local file with unescaped file name only.
authorJohn Wolfe <jwolfe@vmware.com>
Wed, 20 Apr 2022 20:24:07 +0000 (13:24 -0700)
committerJohn Wolfe <jwolfe@vmware.com>
Wed, 20 Apr 2022 20:24:07 +0000 (13:24 -0700)
open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c

index aaa5082ac5fb684d1389dda44617edd0ee0d5ddd..f5541a9a70961c09b4ef21cfbcfae62670114948 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * 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
@@ -31,6 +31,8 @@
 #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>
@@ -53,6 +55,60 @@ static xmlSchemaValidCtxtPtr gSchemaValidateCtx = NULL;
 #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.
  *
@@ -204,9 +260,9 @@ LoadCatalogAndSchema(void)
    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.
     *
@@ -354,6 +410,12 @@ SAML_Init(void)
    /* set up the xml2 error handler */
    xmlSetGenericErrorFunc(NULL, XmlErrorHandler);
 
+   /*
+    * Register user defined UserXmlFileOpen
+    */
+   xmlRegisterInputCallbacks(xmlFileMatch, UserXmlFileOpen,
+                             xmlFileRead, xmlFileClose);
+
    /*
     * Load schemas
     */