2 * security.c: Implementation of the XSLT security framework
4 * See Copyright for the status of this software.
14 #ifdef HAVE_SYS_TYPES_H
15 #include <sys/types.h>
17 #ifdef HAVE_SYS_STAT_H
37 #if defined(WIN32) && !defined(__CYGWIN__)
39 #ifndef INVALID_FILE_ATTRIBUTES
40 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
46 /* MS C library seems to define stat and _stat. The definition
47 * is identical. Still, mapping them to each other causes a warning. */
49 # define stat(x,y) _stat(x,y)
55 #include <libxml/xmlmemory.h>
56 #include <libxml/tree.h>
57 #include <libxml/uri.h>
59 #include "xsltInternals.h"
60 #include "xsltutils.h"
61 #include "extensions.h"
65 struct _xsltSecurityPrefs
{
66 xsltSecurityCheck readFile
;
67 xsltSecurityCheck createFile
;
68 xsltSecurityCheck createDir
;
69 xsltSecurityCheck readNet
;
70 xsltSecurityCheck writeNet
;
73 static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs
= NULL
;
75 /************************************************************************
79 ************************************************************************/
82 * xsltNewSecurityPrefs:
84 * Create a new security preference block
86 * Returns a pointer to the new block or NULL in case of error
89 xsltNewSecurityPrefs(void) {
90 xsltSecurityPrefsPtr ret
;
94 ret
= (xsltSecurityPrefsPtr
) xmlMalloc(sizeof(xsltSecurityPrefs
));
96 xsltTransformError(NULL
, NULL
, NULL
,
97 "xsltNewSecurityPrefs : malloc failed\n");
100 memset(ret
, 0, sizeof(xsltSecurityPrefs
));
105 * xsltFreeSecurityPrefs:
106 * @sec: the security block to free
108 * Free up a security preference block
111 xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec
) {
118 * xsltSetSecurityPrefs:
119 * @sec: the security block to update
120 * @option: the option to update
121 * @func: the user callback to use for this option
123 * Update the security option to use the new callback checking function
125 * Returns -1 in case of error, 0 otherwise
128 xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec
, xsltSecurityOption option
,
129 xsltSecurityCheck func
) {
134 case XSLT_SECPREF_READ_FILE
:
135 sec
->readFile
= func
; return(0);
136 case XSLT_SECPREF_WRITE_FILE
:
137 sec
->createFile
= func
; return(0);
138 case XSLT_SECPREF_CREATE_DIRECTORY
:
139 sec
->createDir
= func
; return(0);
140 case XSLT_SECPREF_READ_NETWORK
:
141 sec
->readNet
= func
; return(0);
142 case XSLT_SECPREF_WRITE_NETWORK
:
143 sec
->writeNet
= func
; return(0);
149 * xsltGetSecurityPrefs:
150 * @sec: the security block to update
151 * @option: the option to lookup
153 * Lookup the security option to get the callback checking function
155 * Returns NULL if not found, the function otherwise
158 xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec
, xsltSecurityOption option
) {
162 case XSLT_SECPREF_READ_FILE
:
163 return(sec
->readFile
);
164 case XSLT_SECPREF_WRITE_FILE
:
165 return(sec
->createFile
);
166 case XSLT_SECPREF_CREATE_DIRECTORY
:
167 return(sec
->createDir
);
168 case XSLT_SECPREF_READ_NETWORK
:
169 return(sec
->readNet
);
170 case XSLT_SECPREF_WRITE_NETWORK
:
171 return(sec
->writeNet
);
177 * xsltSetDefaultSecurityPrefs:
178 * @sec: the security block to use
180 * Set the default security preference application-wide
183 xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec
) {
185 xsltDefaultSecurityPrefs
= sec
;
189 * xsltGetDefaultSecurityPrefs:
191 * Get the default security preference application-wide
193 * Returns the current xsltSecurityPrefsPtr in use or NULL if none
196 xsltGetDefaultSecurityPrefs(void) {
197 return(xsltDefaultSecurityPrefs
);
201 * xsltSetCtxtSecurityPrefs:
202 * @sec: the security block to use
203 * @ctxt: an XSLT transformation context
205 * Set the security preference for a specific transformation
207 * Returns -1 in case of error, 0 otherwise
210 xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec
,
211 xsltTransformContextPtr ctxt
) {
214 ctxt
->sec
= (void *) sec
;
221 * @sec: the security block to use
222 * @ctxt: an XSLT transformation context
225 * Function used to always allow an operation
230 xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED
,
231 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED
,
232 const char *value ATTRIBUTE_UNUSED
) {
237 * xsltSecurityForbid:
238 * @sec: the security block to use
239 * @ctxt: an XSLT transformation context
242 * Function used to always forbid an operation
247 xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED
,
248 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED
,
249 const char *value ATTRIBUTE_UNUSED
) {
253 /************************************************************************
255 * Internal interfaces *
257 ************************************************************************/
261 * @path: the path to check
263 * function checks to see if @path is a valid source
264 * (file, socket...) for XML.
266 * TODO: remove at some point !!!
267 * Local copy of xmlCheckFilename to avoid a hard dependency on
268 * a new version of libxml2
270 * if stat is not available on the target machine,
271 * returns 1. if stat fails, returns 0 (if calling
272 * stat on the filename fails, it can't be right).
273 * if stat succeeds and the file is a directory,
274 * returns 2. otherwise returns 1.
278 xsltCheckFilename (const char *path
)
281 struct stat stat_buffer
;
282 #if defined(WIN32) && !defined(__CYGWIN__)
285 dwAttrs
= GetFileAttributes(path
);
286 if (dwAttrs
!= INVALID_FILE_ATTRIBUTES
) {
287 if (dwAttrs
& FILE_ATTRIBUTE_DIRECTORY
) {
293 if (stat(path
, &stat_buffer
) == -1)
297 if (S_ISDIR(stat_buffer
.st_mode
)) {
306 xsltCheckWritePath(xsltSecurityPrefsPtr sec
,
307 xsltTransformContextPtr ctxt
,
311 xsltSecurityCheck check
;
314 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_WRITE_FILE
);
316 ret
= check(sec
, ctxt
, path
);
318 xsltTransformError(ctxt
, NULL
, NULL
,
319 "File write for %s refused\n", path
);
324 directory
= xmlParserGetDirectory (path
);
326 if (directory
!= NULL
) {
327 ret
= xsltCheckFilename(directory
);
330 * The directory doesn't exist check for creation
332 check
= xsltGetSecurityPrefs(sec
,
333 XSLT_SECPREF_CREATE_DIRECTORY
);
335 ret
= check(sec
, ctxt
, directory
);
337 xsltTransformError(ctxt
, NULL
, NULL
,
338 "Directory creation for %s refused\n",
344 ret
= xsltCheckWritePath(sec
, ctxt
, directory
);
346 ret
= mkdir(directory
, 0755);
358 * @sec: the security options
359 * @ctxt: an XSLT transformation context
360 * @URL: the resource to be written
362 * Check if the resource is allowed to be written, if necessary makes
363 * some preliminary work like creating directories
365 * Return 1 if write is allowed, 0 if not and -1 in case or error.
368 xsltCheckWrite(xsltSecurityPrefsPtr sec
,
369 xsltTransformContextPtr ctxt
, const xmlChar
*URL
) {
372 xsltSecurityCheck check
;
374 uri
= xmlParseURI((const char *)URL
);
376 uri
= xmlCreateURI();
378 xsltTransformError(ctxt
, NULL
, NULL
,
379 "xsltCheckWrite: out of memory for %s\n", URL
);
382 uri
->path
= (char *)xmlStrdup(URL
);
384 if ((uri
->scheme
== NULL
) ||
385 (xmlStrEqual(BAD_CAST uri
->scheme
, BAD_CAST
"file"))) {
387 #if defined(WIN32) && !defined(__CYGWIN__)
388 if ((uri
->path
)&&(uri
->path
[0]=='/')&&
389 (uri
->path
[1]!='\0')&&(uri
->path
[2]==':'))
390 ret
= xsltCheckWritePath(sec
, ctxt
, uri
->path
+1);
395 * Check if we are allowed to write this file
397 ret
= xsltCheckWritePath(sec
, ctxt
, uri
->path
);
404 * Check if we are allowed to write this network resource
406 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_WRITE_NETWORK
);
408 ret
= check(sec
, ctxt
, (const char *)URL
);
410 xsltTransformError(ctxt
, NULL
, NULL
,
411 "File write for %s refused\n", URL
);
424 * @sec: the security options
425 * @ctxt: an XSLT transformation context
426 * @URL: the resource to be read
428 * Check if the resource is allowed to be read
430 * Return 1 if read is allowed, 0 if not and -1 in case or error.
433 xsltCheckRead(xsltSecurityPrefsPtr sec
,
434 xsltTransformContextPtr ctxt
, const xmlChar
*URL
) {
437 xsltSecurityCheck check
;
439 uri
= xmlParseURI((const char *)URL
);
441 xsltTransformError(ctxt
, NULL
, NULL
,
442 "xsltCheckRead: URL parsing failed for %s\n",
446 if ((uri
->scheme
== NULL
) ||
447 (xmlStrEqual(BAD_CAST uri
->scheme
, BAD_CAST
"file"))) {
450 * Check if we are allowed to read this file
452 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_READ_FILE
);
454 ret
= check(sec
, ctxt
, uri
->path
);
456 xsltTransformError(ctxt
, NULL
, NULL
,
457 "Local file read for %s refused\n", URL
);
464 * Check if we are allowed to write this network resource
466 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_READ_NETWORK
);
468 ret
= check(sec
, ctxt
, (const char *)URL
);
470 xsltTransformError(ctxt
, NULL
, NULL
,
471 "Network file read for %s refused\n", URL
);