a691f68b7fdc47cfad38cb695caaa74b38ca1dd4
[external/xmlsec1.git] / src / io.c
1 /** 
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  * Input uri transform and utility functions.
5  *
6  * This is free software; see Copyright file in the source
7  * distribution for preciese wording.
8  * 
9  * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
10  */
11 #include "globals.h"
12
13 #include <stdlib.h>
14 #include <string.h> 
15 #include <errno.h>
16
17 #include <libxml/uri.h>
18 #include <libxml/tree.h>
19 #include <libxml/xmlIO.h>
20
21 #ifdef LIBXML_HTTP_ENABLED
22 #include <libxml/nanohttp.h>
23 #endif /* LIBXML_HTTP_ENABLED */
24
25 #ifdef LIBXML_FTP_ENABLED 
26 #include <libxml/nanoftp.h>
27 #endif /* LIBXML_FTP_ENABLED */
28
29 #include <xmlsec/xmlsec.h>
30 #include <xmlsec/keys.h>
31 #include <xmlsec/transforms.h>
32 #include <xmlsec/keys.h>
33 #include <xmlsec/io.h>
34 #include <xmlsec/errors.h>
35
36 /*******************************************************************
37  *
38  * Input I/O callback sets
39  *
40  ******************************************************************/
41 typedef struct _xmlSecIOCallback {
42     xmlInputMatchCallback matchcallback;
43     xmlInputOpenCallback opencallback;
44     xmlInputReadCallback readcallback;
45     xmlInputCloseCallback closecallback;
46 } xmlSecIOCallback, *xmlSecIOCallbackPtr;
47
48 static xmlSecIOCallbackPtr      xmlSecIOCallbackCreate  (xmlInputMatchCallback matchFunc,
49                                                          xmlInputOpenCallback openFunc, 
50                                                          xmlInputReadCallback readFunc,
51                                                          xmlInputCloseCallback closeFunc);
52 static void                     xmlSecIOCallbackDestroy (xmlSecIOCallbackPtr callbacks);
53
54 static xmlSecIOCallbackPtr 
55 xmlSecIOCallbackCreate(xmlInputMatchCallback matchFunc, xmlInputOpenCallback openFunc, 
56                        xmlInputReadCallback readFunc, xmlInputCloseCallback closeFunc) {
57     xmlSecIOCallbackPtr callbacks;
58     
59     xmlSecAssert2(matchFunc != NULL, NULL);
60     
61     /* Allocate a new xmlSecIOCallback and fill the fields. */
62     callbacks = (xmlSecIOCallbackPtr)xmlMalloc(sizeof(xmlSecIOCallback));
63     if(callbacks == NULL) {
64         xmlSecError(XMLSEC_ERRORS_HERE,
65                     NULL,
66                     NULL,
67                     XMLSEC_ERRORS_R_MALLOC_FAILED,
68                     "sizeof(xmlSecIOCallback)=%d", 
69                     sizeof(xmlSecIOCallback));
70         return(NULL);
71     }
72     memset(callbacks, 0, sizeof(xmlSecIOCallback));    
73
74     callbacks->matchcallback = matchFunc;
75     callbacks->opencallback  = openFunc;
76     callbacks->readcallback  = readFunc;
77     callbacks->closecallback = closeFunc;
78     
79     return(callbacks);
80 }
81
82 static void 
83 xmlSecIOCallbackDestroy(xmlSecIOCallbackPtr callbacks) {
84     xmlSecAssert(callbacks != NULL);
85
86     memset(callbacks, 0, sizeof(xmlSecIOCallback));    
87     xmlFree(callbacks);    
88 }
89
90 /*******************************************************************
91  *
92  * Input I/O callback list
93  *
94  ******************************************************************/
95 static xmlSecPtrListKlass xmlSecIOCallbackPtrListKlass = {
96     BAD_CAST "io-callbacks-list",
97     NULL,                                               /* xmlSecPtrDuplicateItemMethod duplicateItem; */
98     (xmlSecPtrDestroyItemMethod)xmlSecIOCallbackDestroy,/* xmlSecPtrDestroyItemMethod destroyItem; */
99     NULL,                                               /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
100     NULL                                                /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
101 };
102
103 #define xmlSecIOCallbackPtrListId       xmlSecIOCallbackPtrListGetKlass ()
104 static xmlSecPtrListId                  xmlSecIOCallbackPtrListGetKlass (void);
105 static xmlSecIOCallbackPtr              xmlSecIOCallbackPtrListFind     (xmlSecPtrListPtr list,
106                                                                          const char* uri);
107
108 /**
109  * xmlSecIOCallbackPtrListGetKlass: 
110  *
111  * The keys list klass.
112  *
113  * Returns: keys list id.
114  */
115 static xmlSecPtrListId 
116 xmlSecIOCallbackPtrListGetKlass(void) {
117     return(&xmlSecIOCallbackPtrListKlass);
118 }
119
120 static xmlSecIOCallbackPtr 
121 xmlSecIOCallbackPtrListFind(xmlSecPtrListPtr list, const char* uri) {
122     xmlSecIOCallbackPtr callbacks;
123     xmlSecSize i, size;
124
125     xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecIOCallbackPtrListId), NULL);
126     xmlSecAssert2(uri != NULL, NULL);
127
128     size = xmlSecPtrListGetSize(list);
129     for(i = 0; i < size; ++i) {
130         callbacks = (xmlSecIOCallbackPtr)xmlSecPtrListGetItem(list, i);
131         xmlSecAssert2(callbacks != NULL, NULL); 
132         xmlSecAssert2(callbacks->matchcallback != NULL, NULL);  
133         
134         if((callbacks->matchcallback(uri)) != 0) {
135             return(callbacks);
136         }
137     }
138     return(NULL);
139 }
140
141 static xmlSecPtrList xmlSecAllIOCallbacks;
142
143 /**
144  * xmlSecIOInit:
145  *
146  * The IO initialization (called from #xmlSecInit function).
147  * Applications should not call this function directly.
148  *
149  * Returns: 0 on success or a negative value otherwise.
150  */ 
151 int
152 xmlSecIOInit(void) {    
153     int ret;
154     
155     ret = xmlSecPtrListInitialize(&xmlSecAllIOCallbacks, xmlSecIOCallbackPtrListId);
156     if(ret < 0) {
157         xmlSecError(XMLSEC_ERRORS_HERE,
158                     NULL,
159                     "xmlSecPtrListPtrInitialize",
160                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
161                     XMLSEC_ERRORS_NO_MESSAGE);
162         return(-1);
163     }
164
165 #ifdef LIBXML_HTTP_ENABLED
166     xmlNanoHTTPInit();
167 #endif /* LIBXML_HTTP_ENABLED */
168
169 #ifdef LIBXML_FTP_ENABLED       
170     xmlNanoFTPInit();
171 #endif /* LIBXML_FTP_ENABLED */ 
172
173     return(xmlSecIORegisterDefaultCallbacks());
174 }
175
176 /**
177  * xmlSecIOShutdown:
178  *
179  * The IO clenaup (called from #xmlSecShutdown function).
180  * Applications should not call this function directly.
181  */ 
182 void
183 xmlSecIOShutdown(void) {
184
185 #ifdef LIBXML_HTTP_ENABLED
186     xmlNanoHTTPCleanup();
187 #endif /* LIBXML_HTTP_ENABLED */
188
189 #ifdef LIBXML_FTP_ENABLED       
190     xmlNanoFTPCleanup();
191 #endif /* LIBXML_FTP_ENABLED */ 
192
193     xmlSecPtrListFinalize(&xmlSecAllIOCallbacks);
194 }
195
196 /**
197  * xmlSecIOCleanupCallbacks:
198  *
199  * Clears the entire input callback table. this includes the
200  * compiled-in I/O. 
201  */
202 void
203 xmlSecIOCleanupCallbacks(void) {
204     xmlSecPtrListEmpty(&xmlSecAllIOCallbacks);
205 }
206
207 /**
208  * xmlSecIORegisterCallbacks:
209  * @matchFunc:          the protocol match callback.
210  * @openFunc:           the open stream callback.
211  * @readFunc:           the read from stream callback.
212  * @closeFunc:          the close stream callback.
213  *
214  * Register a new set of I/O callback for handling parser input.
215  *
216  * Returns: the 0 on success or a negative value if an error occurs.
217  */
218 int
219 xmlSecIORegisterCallbacks(xmlInputMatchCallback matchFunc,
220         xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
221         xmlInputCloseCallback closeFunc) {
222     xmlSecIOCallbackPtr callbacks;
223     int ret;
224     
225     xmlSecAssert2(matchFunc != NULL, -1);
226     
227     callbacks = xmlSecIOCallbackCreate(matchFunc, openFunc, readFunc, closeFunc);
228     if(callbacks == NULL) {
229         xmlSecError(XMLSEC_ERRORS_HERE,
230                     NULL,
231                     "xmlSecIOCallbackCreate",
232                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
233                     XMLSEC_ERRORS_NO_MESSAGE);
234         return(-1);
235     }
236     
237     ret = xmlSecPtrListAdd(&xmlSecAllIOCallbacks, callbacks);
238     if(ret < 0) {
239         xmlSecError(XMLSEC_ERRORS_HERE,
240                     NULL,
241                     "xmlSecPtrListAdd",
242                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
243                     XMLSEC_ERRORS_NO_MESSAGE);
244         xmlSecIOCallbackDestroy(callbacks);
245         return(-1);
246     }
247     return(0);
248 }
249
250
251 /**
252  * xmlSecIORegisterDefaultCallbacks:
253  *
254  * Registers the default compiled-in I/O handlers.
255  *
256  * Returns: 0 on success or a negative value otherwise.
257  */
258 int
259 xmlSecIORegisterDefaultCallbacks(void) {
260     int ret;
261     
262 #ifdef LIBXML_HTTP_ENABLED
263     ret = xmlSecIORegisterCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
264                               xmlIOHTTPRead, xmlIOHTTPClose);
265     if(ret < 0) {
266         xmlSecError(XMLSEC_ERRORS_HERE,
267                     NULL,
268                     "xmlSecIORegisterCallbacks",
269                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
270                     "http");
271         return(-1);
272     }
273 #endif /* LIBXML_HTTP_ENABLED */
274
275 #ifdef LIBXML_FTP_ENABLED
276     ret = xmlSecIORegisterCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
277                               xmlIOFTPRead, xmlIOFTPClose);
278     if(ret < 0) {
279         xmlSecError(XMLSEC_ERRORS_HERE,
280                     NULL,
281                     "xmlSecIORegisterCallbacks",
282                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
283                     "ftp");
284         return(-1);
285     }
286 #endif /* LIBXML_FTP_ENABLED */
287
288     ret = xmlSecIORegisterCallbacks(xmlFileMatch, xmlFileOpen,
289                               xmlFileRead, xmlFileClose);
290     if(ret < 0) {
291         xmlSecError(XMLSEC_ERRORS_HERE,
292                     NULL,
293                     "xmlSecIORegisterCallbacks",
294                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
295                     "file");
296         return(-1);
297     }
298
299     return(0);
300 }
301
302
303
304                                                                 
305 /**************************************************************
306  *
307  * Input URI Transform
308  *
309  * xmlSecInputURICtx is located after xmlSecTransform
310  * 
311  **************************************************************/
312 typedef struct _xmlSecInputURICtx                               xmlSecInputURICtx,
313                                                                 *xmlSecInputURICtxPtr;
314 struct _xmlSecInputURICtx {
315     xmlSecIOCallbackPtr         clbks;
316     void*                       clbksCtx;
317 };
318 #define xmlSecTransformInputUriSize \
319         (sizeof(xmlSecTransform) + sizeof(xmlSecInputURICtx))
320 #define xmlSecTransformInputUriGetCtx(transform) \
321     ((xmlSecTransformCheckSize((transform), xmlSecTransformInputUriSize)) ? \
322         (xmlSecInputURICtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
323         (xmlSecInputURICtxPtr)NULL)
324
325 static int              xmlSecTransformInputURIInitialize       (xmlSecTransformPtr transform);
326 static void             xmlSecTransformInputURIFinalize         (xmlSecTransformPtr transform);
327 static int              xmlSecTransformInputURIPopBin           (xmlSecTransformPtr transform, 
328                                                                  xmlSecByte* data,
329                                                                  xmlSecSize maxDataSize,
330                                                                  xmlSecSize* dataSize,
331                                                                  xmlSecTransformCtxPtr transformCtx);
332
333 static xmlSecTransformKlass xmlSecTransformInputURIKlass = {
334     /* klass/object sizes */
335     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
336     xmlSecTransformInputUriSize,                /* xmlSecSize objSize */
337
338     BAD_CAST "input-uri",                       /* const xmlChar* name; */
339     NULL,                                       /* const xmlChar* href; */
340     0,                                          /* xmlSecAlgorithmUsage usage; */
341
342     xmlSecTransformInputURIInitialize,          /* xmlSecTransformInitializeMethod initialize; */
343     xmlSecTransformInputURIFinalize,            /* xmlSecTransformFinalizeMethod finalize; */
344     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
345     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
346     NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
347     NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
348     NULL,                                       /* xmlSecTransformValidateMethod validate; */
349     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
350     NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
351     xmlSecTransformInputURIPopBin,              /* xmlSecTransformPopBinMethod popBin; */
352     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
353     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
354     NULL,                                       /* xmlSecTransformExecuteMethod execute; */
355     
356     NULL,                                       /* void* reserved0; */
357     NULL,                                       /* void* reserved1; */
358 };
359
360 /**
361  * xmlSecTransformInputURIGetKlass:
362  *
363  * The input uri transform klass. Reads binary data from an uri.
364  *
365  * Returns: input URI transform id.
366  */
367 xmlSecTransformId 
368 xmlSecTransformInputURIGetKlass(void) {
369     return(&xmlSecTransformInputURIKlass);
370 }
371
372 /** 
373  * xmlSecTransformInputURIOpen:
374  * @transform:          the pointer to IO transform.
375  * @uri:                the URL to open.
376  *
377  * Opens the given @uri for reading.
378  *
379  * Returns: 0 on success or a negative value otherwise.
380  */
381 int
382 xmlSecTransformInputURIOpen(xmlSecTransformPtr transform, const xmlChar *uri) {
383     xmlSecInputURICtxPtr ctx;
384         
385     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId), -1);
386     xmlSecAssert2(uri != NULL, -1);
387
388     ctx = xmlSecTransformInputUriGetCtx(transform);
389     xmlSecAssert2(ctx != NULL, -1);
390     xmlSecAssert2(ctx->clbks == NULL, -1);
391     xmlSecAssert2(ctx->clbksCtx == NULL, -1);
392
393     /*
394      * Try to find one of the input accept method accepting that scheme
395      * Go in reverse to give precedence to user defined handlers.
396      * try with an unescaped version of the uri
397      */
398     if(ctx->clbks == NULL) {
399         char *unescaped;
400     
401         unescaped = xmlURIUnescapeString((char*)uri, 0, NULL);
402         if (unescaped != NULL) {
403             ctx->clbks = xmlSecIOCallbackPtrListFind(&xmlSecAllIOCallbacks, unescaped);
404             if(ctx->clbks != NULL) {
405                 ctx->clbksCtx = ctx->clbks->opencallback(unescaped);
406             }
407             xmlFree(unescaped);
408         }
409     }
410
411     /*
412      * If this failed try with a non-escaped uri this may be a strange
413      * filename
414      */
415     if (ctx->clbks == NULL) {
416         ctx->clbks = xmlSecIOCallbackPtrListFind(&xmlSecAllIOCallbacks, (char*)uri);
417         if(ctx->clbks != NULL) {
418             ctx->clbksCtx = ctx->clbks->opencallback((char*)uri);
419         }
420     }
421
422     if((ctx->clbks == NULL) || (ctx->clbksCtx == NULL)) {
423         xmlSecError(XMLSEC_ERRORS_HERE,
424                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
425                     "opencallback",
426                     XMLSEC_ERRORS_R_IO_FAILED,
427                     "uri=%s;errno=%d", 
428                     xmlSecErrorsSafeString(uri),
429                     errno);
430         return(-1);
431     }
432     
433     return(0);
434 }
435
436 static int
437 xmlSecTransformInputURIInitialize(xmlSecTransformPtr transform) {
438     xmlSecInputURICtxPtr ctx;
439
440     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId), -1);
441
442     ctx = xmlSecTransformInputUriGetCtx(transform);
443     xmlSecAssert2(ctx != NULL, -1);
444     
445     memset(ctx, 0, sizeof(xmlSecInputURICtx));
446     return(0);
447 }
448
449 static void
450 xmlSecTransformInputURIFinalize(xmlSecTransformPtr transform) {
451     xmlSecInputURICtxPtr ctx;
452
453     xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId));
454
455     ctx = xmlSecTransformInputUriGetCtx(transform);
456     xmlSecAssert(ctx != NULL);
457
458     if((ctx->clbksCtx != NULL) && (ctx->clbks != NULL) && (ctx->clbks->closecallback != NULL)) {
459         (ctx->clbks->closecallback)(ctx->clbksCtx);
460     }
461     memset(ctx, 0, sizeof(xmlSecInputURICtx));
462 }
463
464 static int 
465 xmlSecTransformInputURIPopBin(xmlSecTransformPtr transform, xmlSecByte* data,
466                               xmlSecSize maxDataSize, xmlSecSize* dataSize, 
467                               xmlSecTransformCtxPtr transformCtx) {
468     xmlSecInputURICtxPtr ctx;
469
470     int ret;
471                             
472     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId), -1);
473     xmlSecAssert2(data != NULL, -1);
474     xmlSecAssert2(dataSize != NULL, -1);
475     xmlSecAssert2(transformCtx != NULL, -1);
476
477     ctx = xmlSecTransformInputUriGetCtx(transform);
478     xmlSecAssert2(ctx != NULL, -1);
479     
480     if((ctx->clbksCtx != NULL) && (ctx->clbks != NULL) && (ctx->clbks->readcallback != NULL)) {
481         ret = (ctx->clbks->readcallback)(ctx->clbksCtx, (char*)data, (int)maxDataSize);
482         if(ret < 0) {
483             xmlSecError(XMLSEC_ERRORS_HERE,
484                         xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
485                         "readcallback",
486                         XMLSEC_ERRORS_R_IO_FAILED,
487                         "errno=%d", errno);
488             return(-1);
489         }
490         (*dataSize) = ret;
491     } else {
492         (*dataSize) = 0;
493     }
494     return(0);
495 }
496