mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-07-10 14:40:58 +03:00
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
This commit is contained in:
12
ChangeLog
12
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -283,6 +283,25 @@ ATTRIBUTE_UNUSED
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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 \
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "transform.h"
|
||||
#include "imports.h"
|
||||
#include "keys.h"
|
||||
#include "security.h"
|
||||
|
||||
#ifdef LIBXML_XINCLUDE_ENABLED
|
||||
#include <libxml/xinclude.h>
|
||||
@ -163,6 +164,22 @@ xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
|
||||
if ((ctxt == NULL) || (URI == NULL))
|
||||
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
|
||||
*/
|
||||
@ -211,10 +228,28 @@ 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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
429
libxslt/security.c
Normal file
429
libxslt/security.c
Normal file
@ -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);
|
||||
}
|
||||
|
89
libxslt/security.h
Normal file
89
libxslt/security.h
Normal file
@ -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__ */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user