+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
></TR
></TABLE
><P
->Process an XSLT-1.1 document element</P
+>Process an EXSLT/XSLT-1.1 document element</P
><P
></P
><DIV
xsltRuntimeExtraPtr extras; /* extra per runtime informations */
xsltDocumentPtr styleList; /* the stylesheet docs list */
+ void * sec; /* the security preferences if any */
};</PRE
></TD
></TR
<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
xsltRuntimeExtraPtr extras; /* extra per runtime informations */
xsltDocumentPtr styleList; /* the stylesheet docs list */
+ void * sec; /* the security preferences if any */
};
</STRUCT>
<MACRO>
</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
| \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
\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
<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>
documents.h \
preproc.h \
transform.h \
+ security.h \
xsltInternals.h \
xsltconfig.h
documents.c \
preproc.c \
transform.c \
+ security.c \
win32config.h \
xsltwin32config.h \
xsltwin32config.h.in \
#include "transform.h"
#include "imports.h"
#include "keys.h"
+#include "security.h"
#ifdef LIBXML_XINCLUDE_ENABLED
#include <libxml/xinclude.h>
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;
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;
#include "xsltutils.h"
#include "imports.h"
#include "documents.h"
+#include "security.h"
xmlChar *uriRef = NULL;
xmlChar *URI = NULL;
xsltStylesheetPtr res;
+ xsltSecurityPrefsPtr sec;
if ((cur == NULL) || (style == NULL))
return (ret);
"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);
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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__ */
+
#include "extensions.h"
#include "extra.h"
#include "preproc.h"
+#include "security.h"
#ifdef WITH_XSLT_DEBUG
#define WITH_XSLT_DEBUG_EXTRA
cur->inst = NULL;
cur->xinclude = xsltDoXIncludeDefault;
cur->outputFile = NULL;
+ cur->sec = xsltGetDefaultSecurityPrefs();
return(cur);
}
* @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,
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;
#include "extensions.h"
#include "preproc.h"
#include "extra.h"
+#include "security.h"
#ifdef WITH_XSLT_DEBUG
#define WITH_XSLT_DEBUG_PARSING
xsltStylesheetPtr
xsltParseStylesheetFile(const xmlChar* filename) {
+ xsltSecurityPrefsPtr sec;
xsltStylesheetPtr ret;
xmlDocPtr doc;
"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);
xsltRuntimeExtraPtr extras; /* extra per runtime informations */
xsltDocumentPtr styleList; /* the stylesheet docs list */
+ void * sec; /* the security preferences if any */
};
/**
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <libxslt/extensions.h>
+#include <libxslt/security.h>
#include <libexslt/exsltconfig.h>
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");
int i;
xsltStylesheetPtr cur = NULL;
xmlDocPtr doc, style;
+ xsltSecurityPrefsPtr sec = NULL;
if (argc <= 1) {
usage(argv[0]);
LIBXML_TEST_VERSION
xmlLineNumbersDefault(1);
+ sec = xsltNewSecurityPrefs();
+ xsltSetDefaultSecurityPrefs(sec);
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-"))
} 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"))) {
#if 0
xmlMemoryDump();
#endif
+ xsltFreeSecurityPrefs(sec);
return(errorno);
}