From 159d00a5a00cf3a9049dda9daa7455d7272afcfc Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Thu, 10 Oct 2002 15:26:25 +0000 Subject: [PATCH] new module with runtime security checks, it will also check and do * 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 --- ChangeLog | 12 + doc/html/libxslt-transform.html | 2 +- doc/html/libxslt-xsltinternals.html | 1 + doc/libxslt-decl.txt | 80 +++++++ doc/libxslt-sections.txt | 19 ++ doc/xsltproc.1 | 9 + doc/xsltproc.xml | 20 ++ libxslt/Makefile.am | 2 + libxslt/documents.c | 35 +++ libxslt/imports.c | 20 ++ libxslt/security.c | 429 ++++++++++++++++++++++++++++++++++++ libxslt/security.h | 89 ++++++++ libxslt/transform.c | 16 +- libxslt/xslt.c | 19 ++ libxslt/xsltInternals.h | 1 + xsltproc/xsltproc.c | 19 ++ 16 files changed, 771 insertions(+), 2 deletions(-) create mode 100644 libxslt/security.c create mode 100644 libxslt/security.h diff --git a/ChangeLog b/ChangeLog index 29676ab..677a48f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Thu Oct 10 17:16:52 CEST 2002 Daniel Veillard + + * 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 * 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 951e0da..20f2518 100644 --- a/doc/html/libxslt-transform.html +++ b/doc/html/libxslt-transform.html @@ -2364,7 +2364,7 @@ HREF="libxslt-xsltinternals.html#XSLTSTYLEPRECOMPPTR" >

Process an XSLT-1.1 document element

Process an EXSLT/XSLT-1.1 document element

LIBXSLT_PUBLIC #define LIBXSLT_PUBLIC + +xsltSecurityPrefs + + +xsltSecurityPrefsPtr +typedef xsltSecurityPrefs *xsltSecurityPrefsPtr; + + +xsltSecurityOption +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 +int +xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *value + + +xsltNewSecurityPrefs +xsltSecurityPrefsPtr +void + + +xsltFreeSecurityPrefs +void +xsltSecurityPrefsPtr sec + + +xsltSetSecurityPrefs +int +xsltSecurityPrefsPtr sec,xsltSecurityOption option,xsltSecurityCheck func + + +xsltGetSecurityPrefs +xsltSecurityCheck +xsltSecurityPrefsPtr sec,xsltSecurityOption option + + +xsltSetDefaultSecurityPrefs +void +xsltSecurityPrefsPtr sec + + +xsltGetDefaultSecurityPrefs +xsltSecurityPrefsPtr +void + + +xsltSetCtxtSecurityPrefs +int +xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt + + +xsltSecurityAllow +int +xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const char *value + + +xsltSecurityForbid +int +xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const char *value + + +xsltCheckWrite +int +xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const xmlChar *URL + + +xsltCheckRead +int +xsltSecurityPrefsPtr sec,xsltTransformContextPtr ctxt,const xmlChar *URL + XSLT_MAX_SORT #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 */ }; diff --git a/doc/libxslt-sections.txt b/doc/libxslt-sections.txt index 437e7c7..bb1c83b 100644 --- a/doc/libxslt-sections.txt +++ b/doc/libxslt-sections.txt @@ -284,6 +284,25 @@ LIBXSLT_PUBLIC
+security +xsltSecurityPrefs +xsltSecurityPrefsPtr +xsltSecurityOption +xsltSecurityCheck +xsltNewSecurityPrefs +xsltFreeSecurityPrefs +xsltSetSecurityPrefs +xsltGetSecurityPrefs +xsltSetDefaultSecurityPrefs +xsltGetDefaultSecurityPrefs +xsltSetCtxtSecurityPrefs +xsltSecurityAllow +xsltSecurityForbid +xsltCheckWrite +xsltCheckRead +
+ +
xsltInternals XSLT_MAX_SORT XSLT_PAT_NO_PRIORITY diff --git a/doc/xsltproc.1 b/doc/xsltproc.1 index 71e12ce..00d0b0f 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 4892582..9a09be8 100644 --- a/doc/xsltproc.xml +++ b/doc/xsltproc.xml @@ -50,6 +50,8 @@ --xinclude --profile --dumpextensions + --nowrite + --nomkdir file1 @@ -299,6 +301,24 @@ + + + + + Refuses to write to any file or resource. + + + + + + + + + Refuses to create directories. + + + + diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am index 040c59b..049a012 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 a6abf60..7c3b9eb 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 @@ -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 6f9c8c9..8842af7 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 0000000..8b4422c --- /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 + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_MATH_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_IEEEFP_H +#include +#endif +#ifdef HAVE_NAN_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif + +#include +#include +#include +#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 0000000..1f3112a --- /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 +#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 82bbde4..c080944 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 f7b93d0..08b6d2f 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 f074dc3..54af872 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 72eff0e..88a6dd6 100644 --- a/xsltproc/xsltproc.c +++ b/xsltproc/xsltproc.c @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -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); } -- 2.7.4