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