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 = GetFileAttributesA(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);