new module with runtime security checks, it will also check and do
authorDaniel Veillard <veillard@src.gnome.org>
Thu, 10 Oct 2002 15:26:25 +0000 (15:26 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Thu, 10 Oct 2002 15:26:25 +0000 (15:26 +0000)
* libxslt/security.[ch] libxslt/Makefile.am: new module with
  runtime security checks, it will also check and do directory
  creation when allowed
* libxslt/documents.c libxslt/imports.c libxslt/transform.c
  libxslt/xslt.c libxslt/xsltInternals.h: plug-in the new
  security infrastructure probes at file reading or file creation
* xsltproc/xsltproc.c: plugged the security module there too,
  added the new options --nowrite and --nomkdir
* doc/*: updated the man page and regenerated.
Daniel

16 files changed:
ChangeLog
doc/html/libxslt-transform.html
doc/html/libxslt-xsltinternals.html
doc/libxslt-decl.txt
doc/libxslt-sections.txt
doc/xsltproc.1
doc/xsltproc.xml
libxslt/Makefile.am
libxslt/documents.c
libxslt/imports.c
libxslt/security.c [new file with mode: 0644]
libxslt/security.h [new file with mode: 0644]
libxslt/transform.c
libxslt/xslt.c
libxslt/xsltInternals.h
xsltproc/xsltproc.c

index 29676ab..677a48f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Thu Oct 10 17:16:52 CEST 2002 Daniel Veillard <daniel@veillard.com>
+
+       * libxslt/security.[ch] libxslt/Makefile.am: new module with
+         runtime security checks, it will also check and do directory
+         creation when allowed
+       * libxslt/documents.c libxslt/imports.c libxslt/transform.c
+         libxslt/xslt.c libxslt/xsltInternals.h: plug-in the new
+         security infrastructure probes at file reading or file creation
+       * xsltproc/xsltproc.c: plugged the security module there too,
+         added the new options --nowrite and --nomkdir
+       * doc/*: updated the man page and regenerated.
+
 Wed Oct  9 18:37:56 CEST 2002 Daniel Veillard <daniel@veillard.com>
 
        * doc/*: updated the doc XSLT to add the search, added the search
index 951e0da..20f2518 100644 (file)
@@ -2364,7 +2364,7 @@ HREF="libxslt-xsltinternals.html#XSLTSTYLEPRECOMPPTR"
 ></TR
 ></TABLE
 ><P
->Process an XSLT-1.1 document element</P
+>Process an EXSLT/XSLT-1.1 document element</P
 ><P
 ></P
 ><DIV
index 9934803..c770b19 100644 (file)
@@ -1084,6 +1084,7 @@ CLASS="PROGRAMLISTING"
     xsltRuntimeExtraPtr extras;                /* extra per runtime informations */
 
     xsltDocumentPtr  styleList;                /* the stylesheet docs list */
+    void                 * sec;                /* the security preferences if any */
 };</PRE
 ></TD
 ></TR
index 6aa06e2..6a7679a 100644 (file)
@@ -1087,6 +1087,85 @@ void
 <NAME>LIBXSLT_PUBLIC</NAME>
 #define LIBXSLT_PUBLIC 
 </MACRO>
+<STRUCT>
+<NAME>xsltSecurityPrefs</NAME>
+</STRUCT>
+<TYPEDEF>
+<NAME>xsltSecurityPrefsPtr</NAME>
+typedef xsltSecurityPrefs *xsltSecurityPrefsPtr;
+</TYPEDEF>
+<ENUM>
+<NAME>xsltSecurityOption</NAME>
+typedef enum {
+    XSLT_SECPREF_READ_FILE = 1,
+    XSLT_SECPREF_WRITE_FILE,
+    XSLT_SECPREF_CREATE_DIRECTORY,
+    XSLT_SECPREF_READ_NETWORK,
+    XSLT_SECPREF_WRITE_NETWORK
+} xsltSecurityOption;
+</ENUM>
+<USER_FUNCTION>
+<NAME>xsltSecurityCheck</NAME>
+<RETURNS>int </RETURNS>
+xsltSecurityPrefsPtr sec,
+                                        xsltTransformContextPtr ctxt,
+                                        const char *value
+</USER_FUNCTION>
+<FUNCTION>
+<NAME>xsltNewSecurityPrefs</NAME>
+<RETURNS>xsltSecurityPrefsPtr  </RETURNS>
+void
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltFreeSecurityPrefs</NAME>
+<RETURNS>void  </RETURNS>
+xsltSecurityPrefsPtr sec
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltSetSecurityPrefs</NAME>
+<RETURNS>int   </RETURNS>
+xsltSecurityPrefsPtr sec,xsltSecurityOption option,xsltSecurityCheck func
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltGetSecurityPrefs</NAME>
+<RETURNS>xsltSecurityCheck     </RETURNS>
+xsltSecurityPrefsPtr sec,xsltSecurityOption option
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltSetDefaultSecurityPrefs</NAME>
+<RETURNS>void  </RETURNS>
+xsltSecurityPrefsPtr sec
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltGetDefaultSecurityPrefs</NAME>
+<RETURNS>xsltSecurityPrefsPtr  </RETURNS>
+void
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltSetCtxtSecurityPrefs</NAME>
+<RETURNS>int   </RETURNS>
+xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltSecurityAllow</NAME>
+<RETURNS>int   </RETURNS>
+xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const char *value
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltSecurityForbid</NAME>
+<RETURNS>int   </RETURNS>
+xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const char *value
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltCheckWrite</NAME>
+<RETURNS>int   </RETURNS>
+xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const xmlChar *URL
+</FUNCTION>
+<FUNCTION>
+<NAME>xsltCheckRead</NAME>
+<RETURNS>int   </RETURNS>
+xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const xmlChar *URL
+</FUNCTION>
 <MACRO>
 <NAME>XSLT_MAX_SORT</NAME>
 #define XSLT_MAX_SORT 5
@@ -1525,6 +1604,7 @@ struct xsltTransformContext {
     xsltRuntimeExtraPtr extras;                /* extra per runtime informations */
 
     xsltDocumentPtr  styleList;                /* the stylesheet docs list */
+    void                 * sec;                /* the security preferences if any */
 };
 </STRUCT>
 <MACRO>
index 437e7c7..bb1c83b 100644 (file)
@@ -284,6 +284,25 @@ LIBXSLT_PUBLIC
 </SECTION>
 
 <SECTION>
+<FILE>security</FILE>
+xsltSecurityPrefs
+xsltSecurityPrefsPtr
+xsltSecurityOption
+xsltSecurityCheck
+xsltNewSecurityPrefs
+xsltFreeSecurityPrefs
+xsltSetSecurityPrefs
+xsltGetSecurityPrefs
+xsltSetDefaultSecurityPrefs
+xsltGetDefaultSecurityPrefs
+xsltSetCtxtSecurityPrefs
+xsltSecurityAllow
+xsltSecurityForbid
+xsltCheckWrite
+xsltCheckRead
+</SECTION>
+
+<SECTION>
 <FILE>xsltInternals</FILE>
 XSLT_MAX_SORT
 XSLT_PAT_NO_PRIORITY
index 71e12ce..00d0b0f 100644 (file)
@@ -28,6 +28,7 @@ xsltproc \- command line xslt processor
          | \fB--html\fR | \fB--docbook\fR | \fB--param \fIname\fR \fIvalue\fR\fR
          | \fB--stringparam \fIname\fR \fIvalue\fR\fR | \fB--nonet\fR | \fB--catalogs\fR
          | \fB--xinclude\fR | \fB--profile\fR | \fB--dumpextensions\fR] [\fBstylesheet\fR]
+         | \fB--nowrite\fR | \fB--nomkdir\fR
          [\fIfile1\fR] [\fIfile2\fR] [\fI....\fR]
 .fi
 
@@ -119,6 +120,14 @@ Output profiling information detailing the amount of time spent in each part of
 \fB--dumpextensions\fR
 Dumps the list of all registered extensions on stdout.
 
+.TP
+\fB--nowrite\fR
+Refuses to write to any file or resource.
+
+.TP
+\fB--nomkdir\fR
+Refuses to create directories.
+
 .SH "RETURN VALUES"
 
 .PP
index 4892582..9a09be8 100644 (file)
@@ -50,6 +50,8 @@
        <arg>--xinclude</arg>
        <arg>--profile</arg>
        <arg>--dumpextensions</arg>
+       <arg>--nowrite</arg>
+       <arg>--nomkdir</arg>
       </group>
       <arg><option><replaceable>stylesheet</replaceable></option></arg>
       <arg><replaceable>file1</replaceable></arg>
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term>
+      <option>--nowrite</option></term>
+       <listitem>
+         <simpara>Refuses to write to any file or resource.
+    </simpara>
+       </listitem>
+      </varlistentry>
+    
+      <varlistentry>
+       <term>
+      <option>--nomkdir</option></term>
+       <listitem>
+         <simpara>Refuses to create directories.
+    </simpara>
+       </listitem>
+      </varlistentry>
+    
     
     </variablelist>
   </refsect1>
index 040c59b..049a012 100644 (file)
@@ -21,6 +21,7 @@ xsltinc_HEADERS =                     \
        documents.h                     \
        preproc.h                       \
        transform.h                     \
+       security.h                      \
        xsltInternals.h                 \
        xsltconfig.h
 
@@ -41,6 +42,7 @@ libxslt_la_SOURCES =                  \
        documents.c                     \
        preproc.c                       \
        transform.c                     \
+       security.c                      \
        win32config.h                   \
        xsltwin32config.h               \
        xsltwin32config.h.in            \
index a6abf60..7c3b9eb 100644 (file)
@@ -21,6 +21,7 @@
 #include "transform.h"
 #include "imports.h"
 #include "keys.h"
+#include "security.h"
 
 #ifdef LIBXML_XINCLUDE_ENABLED
 #include <libxml/xinclude.h>
@@ -164,6 +165,22 @@ xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
        return(NULL);
 
     /*
+     * Security framework check
+     */
+    if (ctxt->sec != NULL) {
+       int res;
+       
+       res = xsltCheckRead(ctxt->sec, ctxt, URI);
+       if (res == 0) {
+           xsltPrintErrorContext(ctxt, NULL, NULL);
+           xsltGenericError(xsltGenericErrorContext,
+                "xsltLoadDocument: read rights for %s denied\n",
+                            URI);
+           return(NULL);
+       }
+    }
+
+    /*
      * Walk the context list to find the document if preparsed
      */
     ret = ctxt->docList;
@@ -211,11 +228,29 @@ xsltDocumentPtr
 xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
     xsltDocumentPtr ret;
     xmlDocPtr doc;
+    xsltSecurityPrefsPtr sec;
 
     if ((style == NULL) || (URI == NULL))
        return(NULL);
 
     /*
+     * Security framework check
+     */
+    sec = xsltGetDefaultSecurityPrefs();
+    if (sec != NULL) {
+       int res;
+
+       res = xsltCheckRead(sec, NULL, URI);
+       if (res == 0) {
+           xsltPrintErrorContext(NULL, NULL, NULL);
+           xsltGenericError(xsltGenericErrorContext,
+                "xsltLoadStyleDocument: read rights for %s denied\n",
+                            URI);
+           return(NULL);
+       }
+    }
+
+    /*
      * Walk the context list to find the document if preparsed
      */
     ret = style->docList;
index 6f9c8c9..8842af7 100644 (file)
@@ -43,6 +43,7 @@
 #include "xsltutils.h"
 #include "imports.h"
 #include "documents.h"
+#include "security.h"
 
 
 
@@ -70,6 +71,7 @@ xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) {
     xmlChar *uriRef = NULL;
     xmlChar *URI = NULL;
     xsltStylesheetPtr res;
+    xsltSecurityPrefsPtr sec;
 
     if ((cur == NULL) || (style == NULL))
        return (ret);
@@ -90,6 +92,24 @@ xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) {
            "xsl:import : invalid URI reference %s\n", uriRef);
        goto error;
     }
+
+    /*
+     * Security framework check
+     */
+    sec = xsltGetDefaultSecurityPrefs();
+    if (sec != NULL) {
+       int res;
+
+       res = xsltCheckRead(sec, NULL, URI);
+       if (res == 0) {
+           xsltPrintErrorContext(NULL, NULL, NULL);
+           xsltGenericError(xsltGenericErrorContext,
+                "xsl:import: read rights for %s denied\n",
+                            URI);
+           goto error;
+       }
+    }
+
     import = xmlParseFile((const char *)URI);
     if (import == NULL) {
        xsltPrintErrorContext(NULL, style, cur);
diff --git a/libxslt/security.c b/libxslt/security.c
new file mode 100644 (file)
index 0000000..8b4422c
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * security.c: Implementation of the XSLT security framework
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/uri.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "security.h"
+
+
+struct _xsltSecurityPrefs {
+    xsltSecurityCheck readFile;
+    xsltSecurityCheck createFile;
+    xsltSecurityCheck createDir;
+    xsltSecurityCheck readNet;
+    xsltSecurityCheck writeNet;
+};
+
+static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs = NULL;
+
+/************************************************************************
+ *                                                                     *
+ *                     Module interfaces                               *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltNewSecurityPrefs:
+ *
+ * Create a new security preference block
+ *
+ * Returns a pointer to the new block or NULL in case of error
+ */
+xsltSecurityPrefsPtr
+xsltNewSecurityPrefs(void) {
+    xsltSecurityPrefsPtr ret;
+
+    ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs));
+    if (ret == NULL) {
+       xsltPrintErrorContext(NULL, NULL, NULL);
+       xsltGenericError(xsltGenericErrorContext,
+               "xsltNewSecurityPrefs : malloc failed\n");
+       return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltSecurityPrefs));
+    return(ret);
+}
+
+/**
+ * xsltFreeSecurityPrefs:
+ * @sec:  the security block to free
+ *
+ * Free up a security preference block
+ */
+void
+xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) {
+    if (sec == NULL)
+       return;
+    xmlFree(sec);
+}
+
+/**
+ * xsltSetSecurityPrefs:
+ * @sec:  the security block to update
+ * @option:  the option to update
+ * @func:  the user callback to use for this option
+ *
+ * Update the security option to use the new callback checking function
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+int
+xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option,
+                     xsltSecurityCheck func) {
+    if (sec == NULL)
+       return(-1);
+    switch (option) {
+        case XSLT_SECPREF_READ_FILE:
+            sec->readFile = func; return(0);
+        case XSLT_SECPREF_WRITE_FILE:
+            sec->createFile = func; return(0);
+        case XSLT_SECPREF_CREATE_DIRECTORY:
+            sec->createDir = func; return(0);
+        case XSLT_SECPREF_READ_NETWORK:
+            sec->readNet = func; return(0);
+        case XSLT_SECPREF_WRITE_NETWORK:
+            sec->writeNet = func; return(0);
+    }
+    return(-1);
+}
+
+/**
+ * xsltGetSecurityPrefs:
+ * @sec:  the security block to update
+ * @option:  the option to lookup
+ *
+ * Lookup the security option to get the callback checking function
+ *
+ * Returns NULL if not found, the function otherwise
+ */
+xsltSecurityCheck
+xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) {
+    if (sec == NULL)
+       return(NULL);
+    switch (option) {
+        case XSLT_SECPREF_READ_FILE:
+            return(sec->readFile);
+        case XSLT_SECPREF_WRITE_FILE:
+            return(sec->createFile);
+        case XSLT_SECPREF_CREATE_DIRECTORY:
+            return(sec->createDir);
+        case XSLT_SECPREF_READ_NETWORK:
+            return(sec->readNet);
+        case XSLT_SECPREF_WRITE_NETWORK:
+            return(sec->writeNet);
+    }
+    return(NULL);
+}
+
+/**
+ * xsltSetDefaultSecurityPrefs:
+ * @sec:  the security block to use
+ *
+ * Set the default security preference application-wide
+ */
+void
+xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) {
+    xsltDefaultSecurityPrefs = sec;
+}
+
+/**
+ * xsltSetDefaultSecurityPrefs:
+ *
+ * Get the default security preference application-wide
+ *
+ * Returns the current xsltSecurityPrefsPtr in use or NULL if none
+ */
+xsltSecurityPrefsPtr
+xsltGetDefaultSecurityPrefs(void) {
+    return(xsltDefaultSecurityPrefs);
+}
+
+/**
+ * xsltSetCtxtSecurityPrefs:
+ * @sec:  the security block to use
+ * @ctxt:  an XSLT transformation context
+ *
+ * Set the security preference for a specific transformation
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+int                    
+xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec,
+                        xsltTransformContextPtr ctxt) {
+    if (ctxt == NULL)
+       return(-1);
+    ctxt->sec = (void *) sec;
+    return(0);
+}
+
+
+/**
+ * xsltSecurityAllow:
+ * @sec:  the security block to use
+ * @ctxt:  an XSLT transformation context
+ * @value:  unused
+ *
+ * Function used to always allow an operation
+ *
+ * Returns 1 always
+ */
+int
+xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
+                 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+                 const char *value ATTRIBUTE_UNUSED) {
+    return(1);
+}
+
+/**
+ * xsltSecurityForbid:
+ * @sec:  the security block to use
+ * @ctxt:  an XSLT transformation context
+ * @value:  unused
+ *
+ * Function used to always forbid an operation
+ *
+ * Returns 0 always
+ */
+int
+xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
+                 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+                 const char *value ATTRIBUTE_UNUSED) {
+    return(0);
+}
+
+/************************************************************************
+ *                                                                     *
+ *                     Internal interfaces                             *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltCheckFilename
+ * @path:  the path to check
+ *
+ * function checks to see if @path is a valid source
+ * (file, socket...) for XML.
+ *
+ * TODO: remove at some point !!!
+ * Local copy of xmlCheckFilename to avoid a hard dependancy on
+ * a new version of libxml2 
+ *
+ * if stat is not available on the target machine,
+ * returns 1.  if stat fails, returns 0 (if calling
+ * stat on the filename fails, it can't be right).
+ * if stat succeeds and the file is a directory,
+ * returns 2.  otherwise returns 1.
+ */
+
+static int
+xsltCheckFilename (const char *path)
+{
+#ifdef HAVE_STAT
+    struct stat stat_buffer;
+
+    if (stat(path, &stat_buffer) == -1)
+        return 0;
+
+#ifdef S_ISDIR
+    if (S_ISDIR(stat_buffer.st_mode)) {
+        return 2;
+    }
+#endif
+#endif
+    return 1;
+}
+
+/**
+ * xsltCheckWrite:
+ * @sec:  the security options
+ * @ctxt:  an XSLT transformation context
+ * @URL:  the resource to be written
+ *
+ * Check if the resource is allowed to be written, if necessary makes
+ * some preliminary work like creating directories
+ *
+ * Return 1 if write is allowed, 0 if not and -1 in case or error.
+ */
+int
+xsltCheckWrite(xsltSecurityPrefsPtr sec,
+              xsltTransformContextPtr ctxt, const xmlChar *URL) {
+    int ret;
+    xmlURIPtr uri;
+    xsltSecurityCheck check;
+
+    uri = xmlParseURI((const char *)URL);
+    if (uri == NULL) {
+       xsltPrintErrorContext(ctxt, NULL, NULL);
+       xsltGenericError(xsltGenericErrorContext,
+        "xsltDocumentElem: URL parsing failed for %s\n",
+                        URL);
+       return(-1);
+    }
+    if ((uri->scheme == NULL) ||
+       (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
+       char *directory;
+
+       /*
+        * Check if we are allowed to write this file
+        */
+       check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE);
+       if (check != NULL) {
+           ret = check(sec, ctxt, uri->path);
+           if (ret == 0) {
+               xsltPrintErrorContext(ctxt, NULL, NULL);
+               xsltGenericError(xsltGenericErrorContext,
+                            "File write for %s refused\n", URL);
+               xmlFreeURI(uri);
+               return(0);
+           }
+       }
+
+       directory = xmlParserGetDirectory (uri->path);
+       if (directory != NULL) {
+           ret = xsltCheckFilename(directory);
+           if (ret == 0) {
+               /*
+                * The directory doesn't exist check for creation
+                */
+               check = xsltGetSecurityPrefs(sec,
+                                XSLT_SECPREF_CREATE_DIRECTORY);
+               if (check != NULL) {
+                   ret = check(sec, ctxt, directory);
+                   if (ret == 0) {
+                       xsltPrintErrorContext(ctxt, NULL, NULL);
+                       xsltGenericError(xsltGenericErrorContext,
+                                        "Directory creation for %s refused\n",
+                                        URL);
+                       xmlFree(directory);
+                       xmlFreeURI(uri);
+                       return(0);
+                   }
+               }
+               ret = xsltCheckWrite(sec, ctxt, (const xmlChar *)directory);
+               if (ret == 1)
+                   ret = mkdir(directory, 0755);
+               if (ret < 0)
+                   return(ret);
+           }
+           xmlFree(directory);
+       }
+    } else {
+       /*
+        * Check if we are allowed to write this network resource
+        */
+       check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK);
+       if (check != NULL) {
+           ret = check(sec, ctxt, uri->path);
+           if (ret == 0) {
+               xsltPrintErrorContext(ctxt, NULL, NULL);
+               xsltGenericError(xsltGenericErrorContext,
+                            "File write for %s refused\n", URL);
+               xmlFreeURI(uri);
+               return(0);
+           }
+       }
+    }
+    xmlFreeURI(uri);
+    return(1);
+}
+
+
+/**
+ * xsltCheckRead:
+ * @sec:  the security options
+ * @ctxt: an XSLT transformation context
+ * @URL:  the resource to be read
+ *
+ * Check if the resource is allowed to be read
+ *
+ * Return 1 if read is allowed, 0 if not and -1 in case or error.
+ */
+int
+xsltCheckRead(xsltSecurityPrefsPtr sec,
+             xsltTransformContextPtr ctxt, const xmlChar *URL) {
+    int ret;
+    xmlURIPtr uri;
+    xsltSecurityCheck check;
+
+    uri = xmlParseURI((const char *)URL);
+    if (uri == NULL) {
+       xsltPrintErrorContext(ctxt, NULL, NULL);
+       xsltGenericError(xsltGenericErrorContext,
+        "xsltCheckRead: URL parsing failed for %s\n",
+                        URL);
+       return(-1);
+    }
+    if ((uri->scheme == NULL) ||
+       (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
+
+       /*
+        * Check if we are allowed to read this file
+        */
+       check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE);
+       if (check != NULL) {
+           ret = check(sec, ctxt, uri->path);
+           if (ret == 0) {
+               xsltPrintErrorContext(ctxt, NULL, NULL);
+               xsltGenericError(xsltGenericErrorContext,
+                            "Local file read for %s refused\n", URL);
+               xmlFreeURI(uri);
+               return(0);
+           }
+       }
+    } else {
+       /*
+        * Check if we are allowed to write this network resource
+        */
+       check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK);
+       if (check != NULL) {
+           ret = check(sec, ctxt, uri->path);
+           if (ret == 0) {
+               xsltPrintErrorContext(ctxt, NULL, NULL);
+               xsltGenericError(xsltGenericErrorContext,
+                            "Network file read for %s refused\n", URL);
+               xmlFreeURI(uri);
+               return(0);
+           }
+       }
+    }
+    xmlFreeURI(uri);
+    return(1);
+}
+
diff --git a/libxslt/security.h b/libxslt/security.h
new file mode 100644 (file)
index 0000000..1f3112a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * security.h: interface for the XSLT security framework
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#ifndef __XML_XSLT_SECURITY_H__
+#define __XML_XSLT_SECURITY_H__
+
+#include <libxml/tree.h>
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * xsltSecurityPref:
+ *
+ * structure to indicate the preferences for security in the XSLT
+ * transformation.
+ */
+typedef struct _xsltSecurityPrefs xsltSecurityPrefs;
+typedef xsltSecurityPrefs *xsltSecurityPrefsPtr;
+
+/**
+ * xsltSecurityOption:
+ *
+ * the set of option that can be configured
+ */
+typedef enum {
+    XSLT_SECPREF_READ_FILE = 1,
+    XSLT_SECPREF_WRITE_FILE,
+    XSLT_SECPREF_CREATE_DIRECTORY,
+    XSLT_SECPREF_READ_NETWORK,
+    XSLT_SECPREF_WRITE_NETWORK
+} xsltSecurityOption;
+
+/**
+ * xsltSecurityCheck:
+ *
+ * User provided function to check the value of a string like a file
+ * path or an URL ...
+ */
+typedef int (*xsltSecurityCheck)       (xsltSecurityPrefsPtr sec,
+                                        xsltTransformContextPtr ctxt,
+                                        const char *value);
+
+/*
+ * Module interfaces
+ */
+xsltSecurityPrefsPtr   xsltNewSecurityPrefs    (void);
+void                   xsltFreeSecurityPrefs   (xsltSecurityPrefsPtr sec);
+int                    xsltSetSecurityPrefs    (xsltSecurityPrefsPtr sec,
+                                                xsltSecurityOption option,
+                                                xsltSecurityCheck func);
+xsltSecurityCheck      xsltGetSecurityPrefs    (xsltSecurityPrefsPtr sec,
+                                                xsltSecurityOption option);
+
+void                   xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec);
+xsltSecurityPrefsPtr   xsltGetDefaultSecurityPrefs(void);
+
+int                    xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec,
+                                                xsltTransformContextPtr ctxt);
+
+int                    xsltSecurityAllow       (xsltSecurityPrefsPtr sec,
+                                                xsltTransformContextPtr ctxt,
+                                                const char *value);
+int                    xsltSecurityForbid      (xsltSecurityPrefsPtr sec,
+                                                xsltTransformContextPtr ctxt,
+                                                const char *value);
+/*
+ * internal interfaces
+ */
+int                    xsltCheckWrite          (xsltSecurityPrefsPtr sec,
+                                                xsltTransformContextPtr ctxt,
+                                                const xmlChar *URL);
+int                    xsltCheckRead           (xsltSecurityPrefsPtr sec,
+                                                xsltTransformContextPtr ctxt,
+                                                const xmlChar *URL);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_SECURITY_H__ */
+
index 82bbde4..c080944 100644 (file)
@@ -50,6 +50,7 @@
 #include "extensions.h"
 #include "extra.h"
 #include "preproc.h"
+#include "security.h"
 
 #ifdef WITH_XSLT_DEBUG
 #define WITH_XSLT_DEBUG_EXTRA
@@ -290,6 +291,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
     cur->inst = NULL;
     cur->xinclude = xsltDoXIncludeDefault;
     cur->outputFile = NULL;
+    cur->sec = xsltGetDefaultSecurityPrefs();
     return(cur);
 }
 
@@ -1526,7 +1528,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
  * @inst:  the instruction in the stylesheet
  * @comp:  precomputed information
  *
- * Process an XSLT-1.1 document element
+ * Process an EXSLT/XSLT-1.1 document element
  */
 void
 xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
@@ -1621,6 +1623,18 @@ xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
        xmlFree(URL);
        return;
     }
+    if (ctxt->sec != NULL) {
+       ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
+       if (ret == 0) {
+           xsltPrintErrorContext(ctxt, NULL, inst);
+           xsltGenericError(xsltGenericErrorContext,
+                "xsltDocumentElem: write rights for %s denied\n",
+                            filename);
+           xmlFree(URL);
+           xmlFree(filename);
+           return;
+       }
+    }
 
     oldOutputFile = ctxt->outputFile;
     oldOutput = ctxt->output;
index f7b93d0..08b6d2f 100644 (file)
@@ -40,6 +40,7 @@
 #include "extensions.h"
 #include "preproc.h"
 #include "extra.h"
+#include "security.h"
 
 #ifdef WITH_XSLT_DEBUG
 #define WITH_XSLT_DEBUG_PARSING
@@ -1992,6 +1993,7 @@ xsltParseStylesheetDoc(xmlDocPtr doc) {
 
 xsltStylesheetPtr
 xsltParseStylesheetFile(const xmlChar* filename) {
+    xsltSecurityPrefsPtr sec;
     xsltStylesheetPtr ret;
     xmlDocPtr doc;
     
@@ -2004,6 +2006,23 @@ xsltParseStylesheetFile(const xmlChar* filename) {
            "xsltParseStylesheetFile : parse %s\n", filename);
 #endif
 
+    /*
+     * Security framework check
+     */
+    sec = xsltGetDefaultSecurityPrefs();
+    if (sec != NULL) {
+       int res;
+
+       res = xsltCheckRead(sec, NULL, filename);
+       if (res == 0) {
+           xsltPrintErrorContext(NULL, NULL, NULL);
+           xsltGenericError(xsltGenericErrorContext,
+                "xsltParseStylesheetFile: read rights for %s denied\n",
+                            filename);
+           return(NULL);
+       }
+    }
+
     doc = xmlParseFile((const char *) filename);
     if (doc == NULL) {
        xsltPrintErrorContext(NULL, NULL, NULL);
index f074dc3..54af872 100644 (file)
@@ -455,6 +455,7 @@ struct _xsltTransformContext {
     xsltRuntimeExtraPtr extras;                /* extra per runtime informations */
 
     xsltDocumentPtr  styleList;                /* the stylesheet docs list */
+    void                 * sec;                /* the security preferences if any */
 };
 
 /**
index 72eff0e..88a6dd6 100644 (file)
@@ -49,6 +49,7 @@
 #include <libxslt/transform.h>
 #include <libxslt/xsltutils.h>
 #include <libxslt/extensions.h>
+#include <libxslt/security.h>
 
 #include <libexslt/exsltconfig.h>
 
@@ -381,6 +382,8 @@ static void usage(const char *name) {
     printf("\t       use stringparam to avoid it\n");
     printf("\t--stringparam name value : pass a (parameter, UTF8 string value) pair\n");
     printf("\t--nonet refuse to fetch DTDs or entities over network\n");
+    printf("\t--nowrite refuse to write to any file or resource\n");
+    printf("\t--nomkdir refuse to create directories\n");
 #ifdef LIBXML_CATALOG_ENABLED
     printf("\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES\n");
     printf("\t             otherwise XML Catalogs starting from \n");
@@ -400,6 +403,7 @@ main(int argc, char **argv)
     int i;
     xsltStylesheetPtr cur = NULL;
     xmlDocPtr doc, style;
+    xsltSecurityPrefsPtr sec = NULL;
 
     if (argc <= 1) {
         usage(argv[0]);
@@ -411,6 +415,8 @@ main(int argc, char **argv)
     LIBXML_TEST_VERSION
 
     xmlLineNumbersDefault(1);
+    sec = xsltNewSecurityPrefs();
+    xsltSetDefaultSecurityPrefs(sec);
 
     for (i = 1; i < argc; i++) {
         if (!strcmp(argv[i], "-"))
@@ -478,6 +484,18 @@ main(int argc, char **argv)
         } else if ((!strcmp(argv[i], "-nonet")) ||
                    (!strcmp(argv[i], "--nonet"))) {
             xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader);
+        } else if ((!strcmp(argv[i], "-nowrite")) ||
+                   (!strcmp(argv[i], "--nowrite"))) {
+           xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE,
+                                xsltSecurityForbid);
+           xsltSetSecurityPrefs(sec, XSLT_SECPREF_CREATE_DIRECTORY,
+                                xsltSecurityForbid);
+           xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK,
+                                xsltSecurityForbid);
+        } else if ((!strcmp(argv[i], "-nomkdir")) ||
+                   (!strcmp(argv[i], "--nomkdir"))) {
+           xsltSetSecurityPrefs(sec, XSLT_SECPREF_CREATE_DIRECTORY,
+                                xsltSecurityForbid);
 #ifdef LIBXML_CATALOG_ENABLED
         } else if ((!strcmp(argv[i], "-catalogs")) ||
                    (!strcmp(argv[i], "--catalogs"))) {
@@ -679,6 +697,7 @@ done:
 #if 0
     xmlMemoryDump();
 #endif
+    xsltFreeSecurityPrefs(sec);
     return(errorno);
 }