xslt: Import upstream release 1.1.38.
[wine.git] / libs / xslt / libxslt / security.c
blob1f7187c7f944087481c8e255a3c8ac3c8de98b72
1 /*
2 * security.c: Implementation of the XSLT security framework
4 * See Copyright for the status of this software.
6 * daniel@veillard.com
7 */
9 #define IN_LIBXSLT
10 #include "libxslt.h"
12 #include <string.h>
14 #ifdef HAVE_SYS_TYPES_H
15 #include <sys/types.h>
16 #endif
17 #ifdef HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif
21 #if defined(_WIN32)
22 #include <windows.h>
23 #ifndef INVALID_FILE_ATTRIBUTES
24 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
25 #endif
26 #endif
28 #ifndef HAVE_STAT
29 # ifdef HAVE__STAT
30 /* MS C library seems to define stat and _stat. The definition
31 * is identical. Still, mapping them to each other causes a warning. */
32 # ifndef _MSC_VER
33 # define stat(x,y) _stat(x,y)
34 # endif
35 # define HAVE_STAT
36 # endif
37 #endif
39 #include <libxml/xmlmemory.h>
40 #include <libxml/tree.h>
41 #include <libxml/uri.h>
42 #include "xslt.h"
43 #include "xsltInternals.h"
44 #include "xsltutils.h"
45 #include "extensions.h"
46 #include "security.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 /************************************************************************
60 * *
61 * Module interfaces *
62 * *
63 ************************************************************************/
65 /**
66 * xsltNewSecurityPrefs:
68 * Create a new security preference block
70 * Returns a pointer to the new block or NULL in case of error
72 xsltSecurityPrefsPtr
73 xsltNewSecurityPrefs(void) {
74 xsltSecurityPrefsPtr ret;
76 xsltInitGlobals();
78 ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs));
79 if (ret == NULL) {
80 xsltTransformError(NULL, NULL, NULL,
81 "xsltNewSecurityPrefs : malloc failed\n");
82 return(NULL);
84 memset(ret, 0, sizeof(xsltSecurityPrefs));
85 return(ret);
88 /**
89 * xsltFreeSecurityPrefs:
90 * @sec: the security block to free
92 * Free up a security preference block
94 void
95 xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) {
96 if (sec == NULL)
97 return;
98 xmlFree(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) {
114 xsltInitGlobals();
115 if (sec == NULL)
116 return(-1);
117 switch (option) {
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);
129 return(-1);
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
141 xsltSecurityCheck
142 xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) {
143 if (sec == NULL)
144 return(NULL);
145 switch (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);
157 return(NULL);
161 * xsltSetDefaultSecurityPrefs:
162 * @sec: the security block to use
164 * Set the default security preference application-wide
166 void
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
179 xsltSecurityPrefsPtr
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) {
196 if (ctxt == NULL)
197 return(-1);
198 ctxt->sec = (void *) sec;
199 return(0);
204 * xsltSecurityAllow:
205 * @sec: the security block to use
206 * @ctxt: an XSLT transformation context
207 * @value: unused
209 * Function used to always allow an operation
211 * Returns 1 always
214 xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
215 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
216 const char *value ATTRIBUTE_UNUSED) {
217 return(1);
221 * xsltSecurityForbid:
222 * @sec: the security block to use
223 * @ctxt: an XSLT transformation context
224 * @value: unused
226 * Function used to always forbid an operation
228 * Returns 0 always
231 xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
232 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
233 const char *value ATTRIBUTE_UNUSED) {
234 return(0);
237 /************************************************************************
239 * Internal interfaces *
241 ************************************************************************/
244 * xsltCheckFilename
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.
261 static int
262 xsltCheckFilename (const char *path)
264 #ifdef HAVE_STAT
265 struct stat stat_buffer;
266 #if defined(_WIN32)
267 DWORD dwAttrs;
269 dwAttrs = GetFileAttributesA(path);
270 if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
271 if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) {
272 return 2;
275 #endif
277 if (stat(path, &stat_buffer) == -1)
278 return 0;
280 #ifdef S_ISDIR
281 if (S_ISDIR(stat_buffer.st_mode)) {
282 return 2;
284 #endif
285 #endif
286 return 1;
289 static int
290 xsltCheckWritePath(xsltSecurityPrefsPtr sec,
291 xsltTransformContextPtr ctxt,
292 const char *path)
294 int ret;
295 xsltSecurityCheck check;
296 char *directory;
298 check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE);
299 if (check != NULL) {
300 ret = check(sec, ctxt, path);
301 if (ret == 0) {
302 xsltTransformError(ctxt, NULL, NULL,
303 "File write for %s refused\n", path);
304 return(0);
308 directory = xmlParserGetDirectory (path);
310 if (directory != NULL) {
311 ret = xsltCheckFilename(directory);
312 if (ret == 0) {
314 * The directory doesn't exist check for creation
316 check = xsltGetSecurityPrefs(sec,
317 XSLT_SECPREF_CREATE_DIRECTORY);
318 if (check != NULL) {
319 ret = check(sec, ctxt, directory);
320 if (ret == 0) {
321 xsltTransformError(ctxt, NULL, NULL,
322 "Directory creation for %s refused\n",
323 path);
324 xmlFree(directory);
325 return(0);
328 ret = xsltCheckWritePath(sec, ctxt, directory);
329 if (ret == 1)
330 ret = mkdir(directory, 0755);
332 xmlFree(directory);
333 if (ret < 0)
334 return(ret);
337 return(1);
341 * xsltCheckWrite:
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) {
354 int ret;
355 xmlURIPtr uri;
356 xsltSecurityCheck check;
358 uri = xmlParseURI((const char *)URL);
359 if (uri == NULL) {
360 uri = xmlCreateURI();
361 if (uri == NULL) {
362 xsltTransformError(ctxt, NULL, NULL,
363 "xsltCheckWrite: out of memory for %s\n", URL);
364 return(-1);
366 uri->path = (char *)xmlStrdup(URL);
368 if ((uri->scheme == NULL) ||
369 (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
371 #if defined(_WIN32)
372 if ((uri->path)&&(uri->path[0]=='/')&&
373 (uri->path[1]!='\0')&&(uri->path[2]==':'))
374 ret = xsltCheckWritePath(sec, ctxt, uri->path+1);
375 else
376 #endif
379 * Check if we are allowed to write this file
381 ret = xsltCheckWritePath(sec, ctxt, uri->path);
384 if (ret <= 0) {
385 xmlFreeURI(uri);
386 return(ret);
388 } else {
390 * Check if we are allowed to write this network resource
392 check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK);
393 if (check != NULL) {
394 ret = check(sec, ctxt, (const char *)URL);
395 if (ret == 0) {
396 xsltTransformError(ctxt, NULL, NULL,
397 "File write for %s refused\n", URL);
398 xmlFreeURI(uri);
399 return(0);
403 xmlFreeURI(uri);
404 return(1);
409 * xsltCheckRead:
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) {
421 int ret;
422 xmlURIPtr uri;
423 xsltSecurityCheck check;
425 uri = xmlParseURI((const char *)URL);
426 if (uri == NULL) {
427 xsltTransformError(ctxt, NULL, NULL,
428 "xsltCheckRead: URL parsing failed for %s\n",
429 URL);
430 return(-1);
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);
439 if (check != NULL) {
440 ret = check(sec, ctxt, uri->path);
441 if (ret == 0) {
442 xsltTransformError(ctxt, NULL, NULL,
443 "Local file read for %s refused\n", URL);
444 xmlFreeURI(uri);
445 return(0);
448 } else {
450 * Check if we are allowed to write this network resource
452 check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK);
453 if (check != NULL) {
454 ret = check(sec, ctxt, (const char *)URL);
455 if (ret == 0) {
456 xsltTransformError(ctxt, NULL, NULL,
457 "Network file read for %s refused\n", URL);
458 xmlFreeURI(uri);
459 return(0);
463 xmlFreeURI(uri);
464 return(1);