2 * security.c: Implementation of the XSLT security framework
4 * See Copyright for the status of this software.
11 #ifdef HAVE_SYS_STAT_H
15 #if defined(WIN32) && !defined(__CYGWIN__)
16 #ifndef INVALID_FILE_ATTRIBUTES
17 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
23 /* MS C library seems to define stat and _stat. The definition
24 * is identical. Still, mapping them to each other causes a warning. */
26 # define stat(x,y) _stat(x,y)
32 struct _xsltSecurityPrefs
{
33 xsltSecurityCheck readFile
;
34 xsltSecurityCheck createFile
;
35 xsltSecurityCheck createDir
;
36 xsltSecurityCheck readNet
;
37 xsltSecurityCheck writeNet
;
40 static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs
= NULL
;
42 /************************************************************************
46 ************************************************************************/
49 * xsltNewSecurityPrefs:
51 * Create a new security preference block
53 * Returns a pointer to the new block or NULL in case of error
56 xsltNewSecurityPrefs(void) {
57 xsltSecurityPrefsPtr ret
;
61 ret
= (xsltSecurityPrefsPtr
) xmlMalloc(sizeof(xsltSecurityPrefs
));
63 xsltTransformError(NULL
, NULL
, NULL
,
64 "xsltNewSecurityPrefs : malloc failed\n");
67 memset(ret
, 0, sizeof(xsltSecurityPrefs
));
72 * xsltFreeSecurityPrefs:
73 * @sec: the security block to free
75 * Free up a security preference block
78 xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec
) {
85 * xsltSetSecurityPrefs:
86 * @sec: the security block to update
87 * @option: the option to update
88 * @func: the user callback to use for this option
90 * Update the security option to use the new callback checking function
92 * Returns -1 in case of error, 0 otherwise
95 xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec
, xsltSecurityOption option
,
96 xsltSecurityCheck func
) {
101 case XSLT_SECPREF_READ_FILE
:
102 sec
->readFile
= func
; return(0);
103 case XSLT_SECPREF_WRITE_FILE
:
104 sec
->createFile
= func
; return(0);
105 case XSLT_SECPREF_CREATE_DIRECTORY
:
106 sec
->createDir
= func
; return(0);
107 case XSLT_SECPREF_READ_NETWORK
:
108 sec
->readNet
= func
; return(0);
109 case XSLT_SECPREF_WRITE_NETWORK
:
110 sec
->writeNet
= func
; return(0);
116 * xsltGetSecurityPrefs:
117 * @sec: the security block to update
118 * @option: the option to lookup
120 * Lookup the security option to get the callback checking function
122 * Returns NULL if not found, the function otherwise
125 xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec
, xsltSecurityOption option
) {
129 case XSLT_SECPREF_READ_FILE
:
130 return(sec
->readFile
);
131 case XSLT_SECPREF_WRITE_FILE
:
132 return(sec
->createFile
);
133 case XSLT_SECPREF_CREATE_DIRECTORY
:
134 return(sec
->createDir
);
135 case XSLT_SECPREF_READ_NETWORK
:
136 return(sec
->readNet
);
137 case XSLT_SECPREF_WRITE_NETWORK
:
138 return(sec
->writeNet
);
144 * xsltSetDefaultSecurityPrefs:
145 * @sec: the security block to use
147 * Set the default security preference application-wide
150 xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec
) {
152 xsltDefaultSecurityPrefs
= sec
;
156 * xsltGetDefaultSecurityPrefs:
158 * Get the default security preference application-wide
160 * Returns the current xsltSecurityPrefsPtr in use or NULL if none
163 xsltGetDefaultSecurityPrefs(void) {
164 return(xsltDefaultSecurityPrefs
);
168 * xsltSetCtxtSecurityPrefs:
169 * @sec: the security block to use
170 * @ctxt: an XSLT transformation context
172 * Set the security preference for a specific transformation
174 * Returns -1 in case of error, 0 otherwise
177 xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec
,
178 xsltTransformContextPtr ctxt
) {
181 ctxt
->sec
= (void *) sec
;
188 * @sec: the security block to use
189 * @ctxt: an XSLT transformation context
192 * Function used to always allow an operation
197 xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED
,
198 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED
,
199 const char *value ATTRIBUTE_UNUSED
) {
204 * xsltSecurityForbid:
205 * @sec: the security block to use
206 * @ctxt: an XSLT transformation context
209 * Function used to always forbid an operation
214 xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED
,
215 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED
,
216 const char *value ATTRIBUTE_UNUSED
) {
220 /************************************************************************
222 * Internal interfaces *
224 ************************************************************************/
228 * @path: the path to check
230 * function checks to see if @path is a valid source
231 * (file, socket...) for XML.
233 * TODO: remove at some point !!!
234 * Local copy of xmlCheckFilename to avoid a hard dependency on
235 * a new version of libxml2
237 * if stat is not available on the target machine,
238 * returns 1. if stat fails, returns 0 (if calling
239 * stat on the filename fails, it can't be right).
240 * if stat succeeds and the file is a directory,
241 * returns 2. otherwise returns 1.
245 xsltCheckFilename (const char *path
)
248 struct stat stat_buffer
;
249 #if defined(_WIN32) && !defined(__CYGWIN__)
252 dwAttrs
= GetFileAttributes(path
);
253 if (dwAttrs
!= INVALID_FILE_ATTRIBUTES
) {
254 if (dwAttrs
& FILE_ATTRIBUTE_DIRECTORY
) {
260 if (stat(path
, &stat_buffer
) == -1)
264 if (S_ISDIR(stat_buffer
.st_mode
)) {
273 xsltCheckWritePath(xsltSecurityPrefsPtr sec
,
274 xsltTransformContextPtr ctxt
,
278 xsltSecurityCheck check
;
281 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_WRITE_FILE
);
283 ret
= check(sec
, ctxt
, path
);
285 xsltTransformError(ctxt
, NULL
, NULL
,
286 "File write for %s refused\n", path
);
291 directory
= xmlParserGetDirectory (path
);
293 if (directory
!= NULL
) {
294 ret
= xsltCheckFilename(directory
);
297 * The directory doesn't exist check for creation
299 check
= xsltGetSecurityPrefs(sec
,
300 XSLT_SECPREF_CREATE_DIRECTORY
);
302 ret
= check(sec
, ctxt
, directory
);
304 xsltTransformError(ctxt
, NULL
, NULL
,
305 "Directory creation for %s refused\n",
311 ret
= xsltCheckWritePath(sec
, ctxt
, directory
);
313 ret
= mkdir(directory
, 0755);
325 * @sec: the security options
326 * @ctxt: an XSLT transformation context
327 * @URL: the resource to be written
329 * Check if the resource is allowed to be written, if necessary makes
330 * some preliminary work like creating directories
332 * Return 1 if write is allowed, 0 if not and -1 in case or error.
335 xsltCheckWrite(xsltSecurityPrefsPtr sec
,
336 xsltTransformContextPtr ctxt
, const xmlChar
*URL
) {
339 xsltSecurityCheck check
;
341 uri
= xmlParseURI((const char *)URL
);
343 uri
= xmlCreateURI();
345 xsltTransformError(ctxt
, NULL
, NULL
,
346 "xsltCheckWrite: out of memory for %s\n", URL
);
349 uri
->path
= (char *)xmlStrdup(URL
);
351 if ((uri
->scheme
== NULL
) ||
352 (xmlStrEqual(BAD_CAST uri
->scheme
, BAD_CAST
"file"))) {
354 #if defined(_WIN32) && !defined(__CYGWIN__)
355 if ((uri
->path
)&&(uri
->path
[0]=='/')&&
356 (uri
->path
[1]!='\0')&&(uri
->path
[2]==':'))
357 ret
= xsltCheckWritePath(sec
, ctxt
, uri
->path
+1);
362 * Check if we are allowed to write this file
364 ret
= xsltCheckWritePath(sec
, ctxt
, uri
->path
);
371 * Check if we are allowed to write this network resource
373 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_WRITE_NETWORK
);
375 ret
= check(sec
, ctxt
, (const char *)URL
);
377 xsltTransformError(ctxt
, NULL
, NULL
,
378 "File write for %s refused\n", URL
);
391 * @sec: the security options
392 * @ctxt: an XSLT transformation context
393 * @URL: the resource to be read
395 * Check if the resource is allowed to be read
397 * Return 1 if read is allowed, 0 if not and -1 in case or error.
400 xsltCheckRead(xsltSecurityPrefsPtr sec
,
401 xsltTransformContextPtr ctxt
, const xmlChar
*URL
) {
404 xsltSecurityCheck check
;
406 uri
= xmlParseURI((const char *)URL
);
408 xsltTransformError(ctxt
, NULL
, NULL
,
409 "xsltCheckRead: URL parsing failed for %s\n",
413 if ((uri
->scheme
== NULL
) ||
414 (xmlStrEqual(BAD_CAST uri
->scheme
, BAD_CAST
"file"))) {
417 * Check if we are allowed to read this file
419 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_READ_FILE
);
421 ret
= check(sec
, ctxt
, uri
->path
);
423 xsltTransformError(ctxt
, NULL
, NULL
,
424 "Local file read for %s refused\n", URL
);
431 * Check if we are allowed to write this network resource
433 check
= xsltGetSecurityPrefs(sec
, XSLT_SECPREF_READ_NETWORK
);
435 ret
= check(sec
, ctxt
, (const char *)URL
);
437 xsltTransformError(ctxt
, NULL
, NULL
,
438 "Network file read for %s refused\n", URL
);