diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | doc/html/libxslt-transform.html | 2 | ||||
-rw-r--r-- | doc/html/libxslt-xsltinternals.html | 1 | ||||
-rw-r--r-- | doc/libxslt-decl.txt | 80 | ||||
-rw-r--r-- | doc/libxslt-sections.txt | 19 | ||||
-rw-r--r-- | doc/xsltproc.1 | 9 | ||||
-rw-r--r-- | doc/xsltproc.xml | 20 | ||||
-rw-r--r-- | libxslt/Makefile.am | 2 | ||||
-rw-r--r-- | libxslt/documents.c | 35 | ||||
-rw-r--r-- | libxslt/imports.c | 20 | ||||
-rw-r--r-- | libxslt/security.c | 429 | ||||
-rw-r--r-- | libxslt/security.h | 89 | ||||
-rw-r--r-- | libxslt/transform.c | 16 | ||||
-rw-r--r-- | libxslt/xslt.c | 19 | ||||
-rw-r--r-- | libxslt/xsltInternals.h | 1 | ||||
-rw-r--r-- | xsltproc/xsltproc.c | 19 |
16 files changed, 771 insertions, 2 deletions
@@ -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); } |