summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--doc/html/libxslt-transform.html2
-rw-r--r--doc/html/libxslt-xsltinternals.html1
-rw-r--r--doc/libxslt-decl.txt80
-rw-r--r--doc/libxslt-sections.txt19
-rw-r--r--doc/xsltproc.19
-rw-r--r--doc/xsltproc.xml20
-rw-r--r--libxslt/Makefile.am2
-rw-r--r--libxslt/documents.c35
-rw-r--r--libxslt/imports.c20
-rw-r--r--libxslt/security.c429
-rw-r--r--libxslt/security.h89
-rw-r--r--libxslt/transform.c16
-rw-r--r--libxslt/xslt.c19
-rw-r--r--libxslt/xsltInternals.h1
-rw-r--r--xsltproc/xsltproc.c19
16 files changed, 771 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 29676ab2..677a48f7 100644
--- 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
diff --git a/doc/html/libxslt-transform.html b/doc/html/libxslt-transform.html
index 951e0da4..20f2518c 100644
--- a/doc/html/libxslt-transform.html
+++ b/doc/html/libxslt-transform.html
@@ -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
diff --git a/doc/html/libxslt-xsltinternals.html b/doc/html/libxslt-xsltinternals.html
index 99348030..c770b19c 100644
--- a/doc/html/libxslt-xsltinternals.html
+++ b/doc/html/libxslt-xsltinternals.html
@@ -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
diff --git a/doc/libxslt-decl.txt b/doc/libxslt-decl.txt
index 6aa06e20..6a7679ae 100644
--- a/doc/libxslt-decl.txt
+++ b/doc/libxslt-decl.txt
@@ -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>
diff --git a/doc/libxslt-sections.txt b/doc/libxslt-sections.txt
index 437e7c70..bb1c83ba 100644
--- a/doc/libxslt-sections.txt
+++ b/doc/libxslt-sections.txt
@@ -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
diff --git a/doc/xsltproc.1 b/doc/xsltproc.1
index 71e12cea..00d0b0f4 100644
--- a/doc/xsltproc.1
+++ b/doc/xsltproc.1
@@ -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
diff --git a/doc/xsltproc.xml b/doc/xsltproc.xml
index 48925823..9a09be8b 100644
--- a/doc/xsltproc.xml
+++ b/doc/xsltproc.xml
@@ -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>
@@ -299,6 +301,24 @@
</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>
diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am
index 040c59be..049a0125 100644
--- a/libxslt/Makefile.am
+++ b/libxslt/Makefile.am
@@ -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 \
diff --git a/libxslt/documents.c b/libxslt/documents.c
index a6abf60f..7c3b9eb9 100644
--- a/libxslt/documents.c
+++ b/libxslt/documents.c
@@ -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;
diff --git a/libxslt/imports.c b/libxslt/imports.c
index 6f9c8c90..8842af70 100644
--- a/libxslt/imports.c
+++ b/libxslt/imports.c
@@ -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
index 00000000..8b4422c0
--- /dev/null
+++ b/libxslt/security.c
@@ -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
index 00000000..1f3112a2
--- /dev/null
+++ b/libxslt/security.h
@@ -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__ */
+
diff --git a/libxslt/transform.c b/libxslt/transform.c
index 82bbde4a..c080944c 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -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;
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
index f7b93d04..08b6d2f0 100644
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -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);
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
index f074dc38..54af8728 100644
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -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 */
};
/**
diff --git a/xsltproc/xsltproc.c b/xsltproc/xsltproc.c
index 72eff0e6..88a6dd6a 100644
--- a/xsltproc/xsltproc.c
+++ b/xsltproc/xsltproc.c
@@ -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);
}