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
23 #ifndef INVALID_FILE_ATTRIBUTES
24 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
30 /* MS C library seems to define stat and _stat. The definition
31 * is identical. Still, mapping them to each other causes a warning. */
33 # define stat(x,y) _stat(x,y)
39 #include <libxml/xmlmemory.h>
40 #include <libxml/tree.h>
41 #include <libxml/uri.h>
43 #include "xsltInternals.h"
44 #include "xsltutils.h"
45 #include "extensions.h"
49 struct _xsltSecurityPrefs
{
50 xsltSecurityCheck readFile
;
51 xsltSecurityCheck createFile
;
52 xsltSecurityCheck createDir
;
53 xsltSecurityCheck readNet
;
54 xsltSecurityCheck writeNet
;
57 static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs
= NULL
;
59 /************************************************************************
63 ************************************************************************/
66 * xsltNewSecurityPrefs:
68 * Create a new security preference block
70 * Returns a pointer to the new block or NULL in case of error
73 xsltNewSecurityPrefs(void) {
74 xsltSecurityPrefsPtr ret
;
78 ret
= (xsltSecurityPrefsPtr
) xmlMalloc(sizeof(xsltSecurityPrefs
));
80 xsltTransformError(NULL
, NULL
, NULL
,
81 "xsltNewSecurityPrefs : malloc failed\n");
84 memset(ret
, 0, sizeof(xsltSecurityPrefs
));
89 * xsltFreeSecurityPrefs:
90 * @sec: the security block to free
92 * Free up a security preference block
95 xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec
) {
102 * xsltSetSecurityPrefs:
103 * @sec: the security block to update
104 * @option: the option to update
105 * @func: the user callback to use for this option
107 * Update the security option to use the new callback checking function
109 * Returns -1 in case of error, 0 otherwise
112 xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec
, xsltSecurityOption option
,
113 xsltSecurityCheck func
) {
118 case XSLT_SECPREF_READ_FILE
:
119 sec
->readFile
= func
; return(0);
120 case XSLT_SECPREF_WRITE_FILE
:
121 sec
->createFile
= func
; return(0);
122 case XSLT_SECPREF_CREATE_DIRECTORY
:
123 sec
->createDir
= func
; return(0);
124 case XSLT_SECPREF_READ_NETWORK
:
125 sec
->readNet
= func
; return(0);
126 case XSLT_SECPREF_WRITE_NETWORK
:
127 sec
->writeNet
= func
; return(0);
133 * xsltGetSecurityPrefs:
134 * @sec: the security block to update
135 * @option: the option to lookup
137 * Lookup the security option to get the callback checking function
139 * Returns NULL if not found, the function otherwise
142 xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec
, xsltSecurityOption option
) {
146 case XSLT_SECPREF_READ_FILE
:
147 return(sec
->readFile
);
148 case XSLT_SECPREF_WRITE_FILE
:
149 return(sec
->createFile
);
150 case XSLT_SECPREF_CREATE_DIRECTORY
:
151 return(sec
->createDir
);
152 case XSLT_SECPREF_READ_NETWORK
:
153 return(sec
->readNet
);
154 case XSLT_SECPREF_WRITE_NETWORK
:
155 return(sec
->writeNet
);
161 * xsltSetDefaultSecurityPrefs:
162 * @sec: the security block to use
164 * Set the default security preference application-wide
167 xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec
) {
169 xsltDefaultSecurityPrefs
= sec
;
173 * xsltGetDefaultSecurityPrefs:
175 * Get the default security preference application-wide
177 * Returns the current xsltSecurityPrefsPtr in use or NULL if none
180 xsltGetDefaultSecurityPrefs(void) {
181 return(xsltDefaultSecurityPrefs
);
185 * xsltSetCtxtSecurityPrefs:
186 * @sec: the security block to use
187 * @ctxt: an XSLT transformation context
189 * Set the security preference for a specific transformation
191 * Returns -1 in case of error, 0 otherwise
194 xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec
,
195 xsltTransformContextPtr ctxt
) {
198 ctxt
->sec
= (void *) sec
;
205 * @sec: the security block to use
206 * @ctxt: an XSLT transformation context
209 * Function used to always allow an operation
214 xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED
,
215 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED
,
216 const char *value ATTRIBUTE_UNUSED
) {
221 * xsltSecurityForbid:
222 * @sec: the security block to use
223 * @ctxt: an XSLT transformation context
226 * Function used to always forbid an operation
231 xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED
,
232 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED
,
233 const char *value ATTRIBUTE_UNUSED
) {
237 /************************************************************************
239 * Internal interfaces *
241 ************************************************************************/
245 * @path: the path to check
247 * function checks to see if @path is a valid source
248 * (file, socket...) for XML.
250 * TODO: remove at some point !!!
251 * Local copy of xmlCheckFilename to avoid a hard dependency on
252 * a new version of libxml2
254 * if stat is not available on the target machine,
255 * returns 1. if stat fails, returns 0 (if calling
256 * stat on the filename fails, it can't be right).
257 * if stat succeeds and the file is a directory,
258 * returns 2. otherwise returns 1.
262 xsltCheckFilename (const char *path
)
265 struct stat stat_buffer
;
269 dwAttrs
= GetFileAttributesA(path
);
270 if (dwAttrs
!= INVALID_FILE_ATTRIBUTES
) {
271 if (dwAttrs
& FILE_ATTRIBUTE_DIRECTORY
) {
277 if (stat(path
, &stat_buffer
) == -1)
281 if (S_ISDIR(stat_buffer
.st_mode
)) {
290 xsltCheckWritePath(xsltSecurityPrefsPtr sec
,
291 xsltTransformContextPtr ctxt
,
295 xsltSecurityCheck check
;
298 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_WRITE_FILE
);
300 ret
= check(sec
, ctxt
, path
);
302 xsltTransformError(ctxt
, NULL
, NULL
,
303 "File write for %s refused\n", path
);
308 directory
= xmlParserGetDirectory (path
);
310 if (directory
!= NULL
) {
311 ret
= xsltCheckFilename(directory
);
314 * The directory doesn't exist check for creation
316 check
= xsltGetSecurityPrefs(sec
,
317 XSLT_SECPREF_CREATE_DIRECTORY
);
319 ret
= check(sec
, ctxt
, directory
);
321 xsltTransformError(ctxt
, NULL
, NULL
,
322 "Directory creation for %s refused\n",
328 ret
= xsltCheckWritePath(sec
, ctxt
, directory
);
330 ret
= mkdir(directory
, 0755);
342 * @sec: the security options
343 * @ctxt: an XSLT transformation context
344 * @URL: the resource to be written
346 * Check if the resource is allowed to be written, if necessary makes
347 * some preliminary work like creating directories
349 * Return 1 if write is allowed, 0 if not and -1 in case or error.
352 xsltCheckWrite(xsltSecurityPrefsPtr sec
,
353 xsltTransformContextPtr ctxt
, const xmlChar
*URL
) {
356 xsltSecurityCheck check
;
358 uri
= xmlParseURI((const char *)URL
);
360 uri
= xmlCreateURI();
362 xsltTransformError(ctxt
, NULL
, NULL
,
363 "xsltCheckWrite: out of memory for %s\n", URL
);
366 uri
->path
= (char *)xmlStrdup(URL
);
368 if ((uri
->scheme
== NULL
) ||
369 (xmlStrEqual(BAD_CAST uri
->scheme
, BAD_CAST
"file"))) {
372 if ((uri
->path
)&&(uri
->path
[0]=='/')&&
373 (uri
->path
[1]!='\0')&&(uri
->path
[2]==':'))
374 ret
= xsltCheckWritePath(sec
, ctxt
, uri
->path
+1);
379 * Check if we are allowed to write this file
381 ret
= xsltCheckWritePath(sec
, ctxt
, uri
->path
);
390 * Check if we are allowed to write this network resource
392 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_WRITE_NETWORK
);
394 ret
= check(sec
, ctxt
, (const char *)URL
);
396 xsltTransformError(ctxt
, NULL
, NULL
,
397 "File write for %s refused\n", URL
);
410 * @sec: the security options
411 * @ctxt: an XSLT transformation context
412 * @URL: the resource to be read
414 * Check if the resource is allowed to be read
416 * Return 1 if read is allowed, 0 if not and -1 in case or error.
419 xsltCheckRead(xsltSecurityPrefsPtr sec
,
420 xsltTransformContextPtr ctxt
, const xmlChar
*URL
) {
423 xsltSecurityCheck check
;
425 uri
= xmlParseURI((const char *)URL
);
427 xsltTransformError(ctxt
, NULL
, NULL
,
428 "xsltCheckRead: URL parsing failed for %s\n",
432 if ((uri
->scheme
== NULL
) ||
433 (xmlStrEqual(BAD_CAST uri
->scheme
, BAD_CAST
"file"))) {
436 * Check if we are allowed to read this file
438 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_READ_FILE
);
440 ret
= check(sec
, ctxt
, uri
->path
);
442 xsltTransformError(ctxt
, NULL
, NULL
,
443 "Local file read for %s refused\n", URL
);
450 * Check if we are allowed to write this network resource
452 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_READ_NETWORK
);
454 ret
= check(sec
, ctxt
, (const char *)URL
);
456 xsltTransformError(ctxt
, NULL
, NULL
,
457 "Network file read for %s refused\n", URL
);