source: trunk/third/libxslt/libxslt/security.c @ 19102

Revision 19102, 9.7 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19101, which included commits to RCS files with non-trunk default branches.
Line 
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#include <libxml/xmlmemory.h>
38#include <libxml/tree.h>
39#include <libxml/uri.h>
40#include "xslt.h"
41#include "xsltInternals.h"
42#include "xsltutils.h"
43#include "security.h"
44
45
46struct _xsltSecurityPrefs {
47    xsltSecurityCheck readFile;
48    xsltSecurityCheck createFile;
49    xsltSecurityCheck createDir;
50    xsltSecurityCheck readNet;
51    xsltSecurityCheck writeNet;
52};
53
54static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs = NULL;
55
56/************************************************************************
57 *                                                                      *
58 *                      Module interfaces                               *
59 *                                                                      *
60 ************************************************************************/
61
62/**
63 * xsltNewSecurityPrefs:
64 *
65 * Create a new security preference block
66 *
67 * Returns a pointer to the new block or NULL in case of error
68 */
69xsltSecurityPrefsPtr
70xsltNewSecurityPrefs(void) {
71    xsltSecurityPrefsPtr ret;
72
73    ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs));
74    if (ret == NULL) {
75        xsltTransformError(NULL, NULL, NULL,
76                "xsltNewSecurityPrefs : malloc failed\n");
77        return(NULL);
78    }
79    memset(ret, 0, sizeof(xsltSecurityPrefs));
80    return(ret);
81}
82
83/**
84 * xsltFreeSecurityPrefs:
85 * @sec:  the security block to free
86 *
87 * Free up a security preference block
88 */
89void
90xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) {
91    if (sec == NULL)
92        return;
93    xmlFree(sec);
94}
95
96/**
97 * xsltSetSecurityPrefs:
98 * @sec:  the security block to update
99 * @option:  the option to update
100 * @func:  the user callback to use for this option
101 *
102 * Update the security option to use the new callback checking function
103 *
104 * Returns -1 in case of error, 0 otherwise
105 */
106int
107xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option,
108                     xsltSecurityCheck func) {
109    if (sec == NULL)
110        return(-1);
111    switch (option) {
112        case XSLT_SECPREF_READ_FILE:
113            sec->readFile = func; return(0);
114        case XSLT_SECPREF_WRITE_FILE:
115            sec->createFile = func; return(0);
116        case XSLT_SECPREF_CREATE_DIRECTORY:
117            sec->createDir = func; return(0);
118        case XSLT_SECPREF_READ_NETWORK:
119            sec->readNet = func; return(0);
120        case XSLT_SECPREF_WRITE_NETWORK:
121            sec->writeNet = func; return(0);
122    }
123    return(-1);
124}
125
126/**
127 * xsltGetSecurityPrefs:
128 * @sec:  the security block to update
129 * @option:  the option to lookup
130 *
131 * Lookup the security option to get the callback checking function
132 *
133 * Returns NULL if not found, the function otherwise
134 */
135xsltSecurityCheck
136xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) {
137    if (sec == NULL)
138        return(NULL);
139    switch (option) {
140        case XSLT_SECPREF_READ_FILE:
141            return(sec->readFile);
142        case XSLT_SECPREF_WRITE_FILE:
143            return(sec->createFile);
144        case XSLT_SECPREF_CREATE_DIRECTORY:
145            return(sec->createDir);
146        case XSLT_SECPREF_READ_NETWORK:
147            return(sec->readNet);
148        case XSLT_SECPREF_WRITE_NETWORK:
149            return(sec->writeNet);
150    }
151    return(NULL);
152}
153
154/**
155 * xsltSetDefaultSecurityPrefs:
156 * @sec:  the security block to use
157 *
158 * Set the default security preference application-wide
159 */
160void
161xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) {
162    xsltDefaultSecurityPrefs = sec;
163}
164
165/**
166 * xsltGetDefaultSecurityPrefs:
167 *
168 * Get the default security preference application-wide
169 *
170 * Returns the current xsltSecurityPrefsPtr in use or NULL if none
171 */
172xsltSecurityPrefsPtr
173xsltGetDefaultSecurityPrefs(void) {
174    return(xsltDefaultSecurityPrefs);
175}
176
177/**
178 * xsltSetCtxtSecurityPrefs:
179 * @sec:  the security block to use
180 * @ctxt:  an XSLT transformation context
181 *
182 * Set the security preference for a specific transformation
183 *
184 * Returns -1 in case of error, 0 otherwise
185 */
186int                   
187xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec,
188                         xsltTransformContextPtr ctxt) {
189    if (ctxt == NULL)
190        return(-1);
191    ctxt->sec = (void *) sec;
192    return(0);
193}
194
195
196/**
197 * xsltSecurityAllow:
198 * @sec:  the security block to use
199 * @ctxt:  an XSLT transformation context
200 * @value:  unused
201 *
202 * Function used to always allow an operation
203 *
204 * Returns 1 always
205 */
206int
207xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
208                  xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
209                  const char *value ATTRIBUTE_UNUSED) {
210    return(1);
211}
212
213/**
214 * xsltSecurityForbid:
215 * @sec:  the security block to use
216 * @ctxt:  an XSLT transformation context
217 * @value:  unused
218 *
219 * Function used to always forbid an operation
220 *
221 * Returns 0 always
222 */
223int
224xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
225                  xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
226                  const char *value ATTRIBUTE_UNUSED) {
227    return(0);
228}
229
230/************************************************************************
231 *                                                                      *
232 *                      Internal interfaces                             *
233 *                                                                      *
234 ************************************************************************/
235
236/**
237 * xsltCheckFilename
238 * @path:  the path to check
239 *
240 * function checks to see if @path is a valid source
241 * (file, socket...) for XML.
242 *
243 * TODO: remove at some point !!!
244 * Local copy of xmlCheckFilename to avoid a hard dependency on
245 * a new version of libxml2
246 *
247 * if stat is not available on the target machine,
248 * returns 1.  if stat fails, returns 0 (if calling
249 * stat on the filename fails, it can't be right).
250 * if stat succeeds and the file is a directory,
251 * returns 2.  otherwise returns 1.
252 */
253
254static int
255xsltCheckFilename (const char *path)
256{
257#ifdef HAVE_STAT
258    struct stat stat_buffer;
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/**
273 * xsltCheckWrite:
274 * @sec:  the security options
275 * @ctxt:  an XSLT transformation context
276 * @URL:  the resource to be written
277 *
278 * Check if the resource is allowed to be written, if necessary makes
279 * some preliminary work like creating directories
280 *
281 * Return 1 if write is allowed, 0 if not and -1 in case or error.
282 */
283int
284xsltCheckWrite(xsltSecurityPrefsPtr sec,
285               xsltTransformContextPtr ctxt, const xmlChar *URL) {
286    int ret;
287    xmlURIPtr uri;
288    xsltSecurityCheck check;
289
290    uri = xmlParseURI((const char *)URL);
291    if (uri == NULL) {
292        xsltTransformError(ctxt, NULL, NULL,
293         "xsltDocumentElem: URL parsing failed for %s\n",
294                         URL);
295        return(-1);
296    }
297    if ((uri->scheme == NULL) ||
298        (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
299        char *directory;
300
301        /*
302         * Check if we are allowed to write this file
303         */
304        check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE);
305        if (check != NULL) {
306            ret = check(sec, ctxt, uri->path);
307            if (ret == 0) {
308                xsltTransformError(ctxt, NULL, NULL,
309                             "File write for %s refused\n", URL);
310                xmlFreeURI(uri);
311                return(0);
312            }
313        }
314
315        directory = xmlParserGetDirectory (uri->path);
316        if (directory != NULL) {
317            ret = xsltCheckFilename(directory);
318            if (ret == 0) {
319                /*
320                 * The directory doesn't exist check for creation
321                 */
322                check = xsltGetSecurityPrefs(sec,
323                                 XSLT_SECPREF_CREATE_DIRECTORY);
324                if (check != NULL) {
325                    ret = check(sec, ctxt, directory);
326                    if (ret == 0) {
327                        xsltTransformError(ctxt, NULL, NULL,
328                                         "Directory creation for %s refused\n",
329                                         URL);
330                        xmlFree(directory);
331                        xmlFreeURI(uri);
332                        return(0);
333                    }
334                }
335                ret = xsltCheckWrite(sec, ctxt, (const xmlChar *)directory);
336                if (ret == 1)
337                    ret = mkdir(directory, 0755);
338                if (ret < 0)
339                    return(ret);
340            }
341            xmlFree(directory);
342        }
343    } else {
344        /*
345         * Check if we are allowed to write this network resource
346         */
347        check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK);
348        if (check != NULL) {
349            ret = check(sec, ctxt, uri->path);
350            if (ret == 0) {
351                xsltTransformError(ctxt, NULL, NULL,
352                             "File write for %s refused\n", URL);
353                xmlFreeURI(uri);
354                return(0);
355            }
356        }
357    }
358    xmlFreeURI(uri);
359    return(1);
360}
361
362
363/**
364 * xsltCheckRead:
365 * @sec:  the security options
366 * @ctxt: an XSLT transformation context
367 * @URL:  the resource to be read
368 *
369 * Check if the resource is allowed to be read
370 *
371 * Return 1 if read is allowed, 0 if not and -1 in case or error.
372 */
373int
374xsltCheckRead(xsltSecurityPrefsPtr sec,
375              xsltTransformContextPtr ctxt, const xmlChar *URL) {
376    int ret;
377    xmlURIPtr uri;
378    xsltSecurityCheck check;
379
380    uri = xmlParseURI((const char *)URL);
381    if (uri == NULL) {
382        xsltTransformError(ctxt, NULL, NULL,
383         "xsltCheckRead: URL parsing failed for %s\n",
384                         URL);
385        return(-1);
386    }
387    if ((uri->scheme == NULL) ||
388        (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
389
390        /*
391         * Check if we are allowed to read this file
392         */
393        check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE);
394        if (check != NULL) {
395            ret = check(sec, ctxt, uri->path);
396            if (ret == 0) {
397                xsltTransformError(ctxt, NULL, NULL,
398                             "Local file read for %s refused\n", URL);
399                xmlFreeURI(uri);
400                return(0);
401            }
402        }
403    } else {
404        /*
405         * Check if we are allowed to write this network resource
406         */
407        check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK);
408        if (check != NULL) {
409            ret = check(sec, ctxt, uri->path);
410            if (ret == 0) {
411                xsltTransformError(ctxt, NULL, NULL,
412                             "Network file read for %s refused\n", URL);
413                xmlFreeURI(uri);
414                return(0);
415            }
416        }
417    }
418    xmlFreeURI(uri);
419    return(1);
420}
421
Note: See TracBrowser for help on using the repository browser.