[LIBXSLT] Update to version 1.1.32. CORE-14291
[reactos.git] / dll / 3rdparty / libxslt / security.c
1 /*
2 * security.c: Implementation of the XSLT security framework
3 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9 #include "precomp.h"
10
11 #ifdef HAVE_SYS_STAT_H
12 #include <sys/stat.h>
13 #endif
14
15 #if defined(WIN32) && !defined(__CYGWIN__)
16 #ifndef INVALID_FILE_ATTRIBUTES
17 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
18 #endif
19 #endif
20
21 #ifndef HAVE_STAT
22 # ifdef HAVE__STAT
23 /* MS C library seems to define stat and _stat. The definition
24 * is identical. Still, mapping them to each other causes a warning. */
25 # ifndef _MSC_VER
26 # define stat(x,y) _stat(x,y)
27 # endif
28 # define HAVE_STAT
29 # endif
30 #endif
31
32 struct _xsltSecurityPrefs {
33 xsltSecurityCheck readFile;
34 xsltSecurityCheck createFile;
35 xsltSecurityCheck createDir;
36 xsltSecurityCheck readNet;
37 xsltSecurityCheck writeNet;
38 };
39
40 static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs = NULL;
41
42 /************************************************************************
43 * *
44 * Module interfaces *
45 * *
46 ************************************************************************/
47
48 /**
49 * xsltNewSecurityPrefs:
50 *
51 * Create a new security preference block
52 *
53 * Returns a pointer to the new block or NULL in case of error
54 */
55 xsltSecurityPrefsPtr
56 xsltNewSecurityPrefs(void) {
57 xsltSecurityPrefsPtr ret;
58
59 xsltInitGlobals();
60
61 ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs));
62 if (ret == NULL) {
63 xsltTransformError(NULL, NULL, NULL,
64 "xsltNewSecurityPrefs : malloc failed\n");
65 return(NULL);
66 }
67 memset(ret, 0, sizeof(xsltSecurityPrefs));
68 return(ret);
69 }
70
71 /**
72 * xsltFreeSecurityPrefs:
73 * @sec: the security block to free
74 *
75 * Free up a security preference block
76 */
77 void
78 xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) {
79 if (sec == NULL)
80 return;
81 xmlFree(sec);
82 }
83
84 /**
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
89 *
90 * Update the security option to use the new callback checking function
91 *
92 * Returns -1 in case of error, 0 otherwise
93 */
94 int
95 xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option,
96 xsltSecurityCheck func) {
97 xsltInitGlobals();
98 if (sec == NULL)
99 return(-1);
100 switch (option) {
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);
111 }
112 return(-1);
113 }
114
115 /**
116 * xsltGetSecurityPrefs:
117 * @sec: the security block to update
118 * @option: the option to lookup
119 *
120 * Lookup the security option to get the callback checking function
121 *
122 * Returns NULL if not found, the function otherwise
123 */
124 xsltSecurityCheck
125 xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) {
126 if (sec == NULL)
127 return(NULL);
128 switch (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);
139 }
140 return(NULL);
141 }
142
143 /**
144 * xsltSetDefaultSecurityPrefs:
145 * @sec: the security block to use
146 *
147 * Set the default security preference application-wide
148 */
149 void
150 xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) {
151
152 xsltDefaultSecurityPrefs = sec;
153 }
154
155 /**
156 * xsltGetDefaultSecurityPrefs:
157 *
158 * Get the default security preference application-wide
159 *
160 * Returns the current xsltSecurityPrefsPtr in use or NULL if none
161 */
162 xsltSecurityPrefsPtr
163 xsltGetDefaultSecurityPrefs(void) {
164 return(xsltDefaultSecurityPrefs);
165 }
166
167 /**
168 * xsltSetCtxtSecurityPrefs:
169 * @sec: the security block to use
170 * @ctxt: an XSLT transformation context
171 *
172 * Set the security preference for a specific transformation
173 *
174 * Returns -1 in case of error, 0 otherwise
175 */
176 int
177 xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec,
178 xsltTransformContextPtr ctxt) {
179 if (ctxt == NULL)
180 return(-1);
181 ctxt->sec = (void *) sec;
182 return(0);
183 }
184
185
186 /**
187 * xsltSecurityAllow:
188 * @sec: the security block to use
189 * @ctxt: an XSLT transformation context
190 * @value: unused
191 *
192 * Function used to always allow an operation
193 *
194 * Returns 1 always
195 */
196 int
197 xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
198 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
199 const char *value ATTRIBUTE_UNUSED) {
200 return(1);
201 }
202
203 /**
204 * xsltSecurityForbid:
205 * @sec: the security block to use
206 * @ctxt: an XSLT transformation context
207 * @value: unused
208 *
209 * Function used to always forbid an operation
210 *
211 * Returns 0 always
212 */
213 int
214 xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
215 xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
216 const char *value ATTRIBUTE_UNUSED) {
217 return(0);
218 }
219
220 /************************************************************************
221 * *
222 * Internal interfaces *
223 * *
224 ************************************************************************/
225
226 /**
227 * xsltCheckFilename
228 * @path: the path to check
229 *
230 * function checks to see if @path is a valid source
231 * (file, socket...) for XML.
232 *
233 * TODO: remove at some point !!!
234 * Local copy of xmlCheckFilename to avoid a hard dependency on
235 * a new version of libxml2
236 *
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.
242 */
243
244 static int
245 xsltCheckFilename (const char *path)
246 {
247 #ifdef HAVE_STAT
248 struct stat stat_buffer;
249 #if defined(_WIN32) && !defined(__CYGWIN__)
250 DWORD dwAttrs;
251
252 dwAttrs = GetFileAttributes(path);
253 if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
254 if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) {
255 return 2;
256 }
257 }
258 #endif
259
260 if (stat(path, &stat_buffer) == -1)
261 return 0;
262
263 #ifdef S_ISDIR
264 if (S_ISDIR(stat_buffer.st_mode)) {
265 return 2;
266 }
267 #endif
268 #endif
269 return 1;
270 }
271
272 static int
273 xsltCheckWritePath(xsltSecurityPrefsPtr sec,
274 xsltTransformContextPtr ctxt,
275 const char *path)
276 {
277 int ret;
278 xsltSecurityCheck check;
279 char *directory;
280
281 check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE);
282 if (check != NULL) {
283 ret = check(sec, ctxt, path);
284 if (ret == 0) {
285 xsltTransformError(ctxt, NULL, NULL,
286 "File write for %s refused\n", path);
287 return(0);
288 }
289 }
290
291 directory = xmlParserGetDirectory (path);
292
293 if (directory != NULL) {
294 ret = xsltCheckFilename(directory);
295 if (ret == 0) {
296 /*
297 * The directory doesn't exist check for creation
298 */
299 check = xsltGetSecurityPrefs(sec,
300 XSLT_SECPREF_CREATE_DIRECTORY);
301 if (check != NULL) {
302 ret = check(sec, ctxt, directory);
303 if (ret == 0) {
304 xsltTransformError(ctxt, NULL, NULL,
305 "Directory creation for %s refused\n",
306 path);
307 xmlFree(directory);
308 return(0);
309 }
310 }
311 ret = xsltCheckWritePath(sec, ctxt, directory);
312 if (ret == 1)
313 ret = mkdir(directory, 0755);
314 }
315 xmlFree(directory);
316 if (ret < 0)
317 return(ret);
318 }
319
320 return(1);
321 }
322
323 /**
324 * xsltCheckWrite:
325 * @sec: the security options
326 * @ctxt: an XSLT transformation context
327 * @URL: the resource to be written
328 *
329 * Check if the resource is allowed to be written, if necessary makes
330 * some preliminary work like creating directories
331 *
332 * Return 1 if write is allowed, 0 if not and -1 in case or error.
333 */
334 int
335 xsltCheckWrite(xsltSecurityPrefsPtr sec,
336 xsltTransformContextPtr ctxt, const xmlChar *URL) {
337 int ret;
338 xmlURIPtr uri;
339 xsltSecurityCheck check;
340
341 uri = xmlParseURI((const char *)URL);
342 if (uri == NULL) {
343 uri = xmlCreateURI();
344 if (uri == NULL) {
345 xsltTransformError(ctxt, NULL, NULL,
346 "xsltCheckWrite: out of memory for %s\n", URL);
347 return(-1);
348 }
349 uri->path = (char *)xmlStrdup(URL);
350 }
351 if ((uri->scheme == NULL) ||
352 (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
353
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);
358 else
359 #endif
360
361 /*
362 * Check if we are allowed to write this file
363 */
364 ret = xsltCheckWritePath(sec, ctxt, uri->path);
365 if (ret <= 0) {
366 xmlFreeURI(uri);
367 return(ret);
368 }
369 } else {
370 /*
371 * Check if we are allowed to write this network resource
372 */
373 check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK);
374 if (check != NULL) {
375 ret = check(sec, ctxt, (const char *)URL);
376 if (ret == 0) {
377 xsltTransformError(ctxt, NULL, NULL,
378 "File write for %s refused\n", URL);
379 xmlFreeURI(uri);
380 return(0);
381 }
382 }
383 }
384 xmlFreeURI(uri);
385 return(1);
386 }
387
388
389 /**
390 * xsltCheckRead:
391 * @sec: the security options
392 * @ctxt: an XSLT transformation context
393 * @URL: the resource to be read
394 *
395 * Check if the resource is allowed to be read
396 *
397 * Return 1 if read is allowed, 0 if not and -1 in case or error.
398 */
399 int
400 xsltCheckRead(xsltSecurityPrefsPtr sec,
401 xsltTransformContextPtr ctxt, const xmlChar *URL) {
402 int ret;
403 xmlURIPtr uri;
404 xsltSecurityCheck check;
405
406 uri = xmlParseURI((const char *)URL);
407 if (uri == NULL) {
408 xsltTransformError(ctxt, NULL, NULL,
409 "xsltCheckRead: URL parsing failed for %s\n",
410 URL);
411 return(-1);
412 }
413 if ((uri->scheme == NULL) ||
414 (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
415
416 /*
417 * Check if we are allowed to read this file
418 */
419 check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE);
420 if (check != NULL) {
421 ret = check(sec, ctxt, uri->path);
422 if (ret == 0) {
423 xsltTransformError(ctxt, NULL, NULL,
424 "Local file read for %s refused\n", URL);
425 xmlFreeURI(uri);
426 return(0);
427 }
428 }
429 } else {
430 /*
431 * Check if we are allowed to write this network resource
432 */
433 check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK);
434 if (check != NULL) {
435 ret = check(sec, ctxt, (const char *)URL);
436 if (ret == 0) {
437 xsltTransformError(ctxt, NULL, NULL,
438 "Network file read for %s refused\n", URL);
439 xmlFreeURI(uri);
440 return(0);
441 }
442 }
443 }
444 xmlFreeURI(uri);
445 return(1);
446 }
447