novi upstream verzije 2.8.3
[ossec-hids.git] / src / os_xml / os_xml.c
1 /*      $OSSEC, os_xml.c, v0.3, 2005/02/11, Daniel B. Cid$      */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All rights reserved.
5  *
6  * This program is a free software; you can redistribute it
7  * and/or modify it under the terms of the GNU General Public
8  * License (version 2) as published by the FSF - Free Software
9  * Foundation
10  */
11
12 /* os_xml Library.
13  */
14
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20
21 #include "os_xml.h"
22 #include "os_xml_internal.h"
23
24
25 /* Internal functions */
26 static int _oscomment(FILE *fp) __attribute__((nonnull));
27 static int _writecontent(const char *str, size_t size, unsigned int parent, OS_XML *_lxml) __attribute__((nonnull));
28 static int _writememory(const char *str, XML_TYPE type, size_t size,
29                                         unsigned int parent, OS_XML *_lxml) __attribute__((nonnull));
30 static int _xml_fgetc(FILE *fp) __attribute__((nonnull));
31 static int _ReadElem(FILE *fp, unsigned int parent, OS_XML *_lxml) __attribute__((nonnull));
32 static int _getattributes(FILE *fp, unsigned int parent,OS_XML *_lxml) __attribute__((nonnull));
33 static void xml_error(OS_XML *_lxml, const char *msg,...) __attribute__((format(printf, 2, 3), nonnull));
34
35 /* Currently line */
36 static unsigned int _line;
37
38 /* Local fgetc */
39 static int _xml_fgetc(FILE *fp)
40 {
41     int c;
42     c = fgetc(fp);
43
44     if(c == '\n') /* add new line */
45         _line++;
46
47     return(c);
48 }
49
50 static void xml_error(OS_XML *_lxml, const char *msg,...)
51 {
52 #ifdef DEBUG
53     time_t tm;
54     struct tm *p;
55 #endif
56
57     va_list args;
58     va_start(args,msg);
59
60 #ifdef DEBUG
61     tm = time(NULL);
62     p = localtime(&tm);
63     fprintf(stderr,"%d/%d/%d %d:%d:%d (LINE: %u)",p->tm_year+1900,p->tm_mon,
64             p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec,_line);
65     vfprintf(stderr, msg, args);
66     fprintf(stderr, "\n\n");
67 #endif
68
69     memset(_lxml->err,'\0', XML_ERR_LENGTH);
70     vsnprintf(_lxml->err,XML_ERR_LENGTH-1,msg,args);
71     va_end(args);
72     _lxml->err_line = _line;
73 }
74
75
76
77 /* OS_ClearXML v0.1
78  * Clear the memory used by the XML
79  */
80 void OS_ClearXML(OS_XML *_lxml)
81 {
82     unsigned int i;
83     for(i=0;i<_lxml->cur;i++)
84     {
85         free(_lxml->el[i]);
86         free(_lxml->ct[i]);
87     }
88     _lxml->cur = 0;
89     _lxml->fol = 0;
90     _lxml->err_line = 0;
91
92     free(_lxml->el);
93     _lxml->el = NULL;
94
95     free(_lxml->ct);
96     _lxml->ct = NULL;
97
98     free(_lxml->rl);
99     _lxml->rl = NULL;
100
101     free(_lxml->tp);
102     _lxml->tp = NULL;
103
104     free(_lxml->ck);
105     _lxml->ck = NULL;
106
107     free(_lxml->ln);
108     _lxml->ln = NULL;
109
110     memset(_lxml->err,'\0', XML_ERR_LENGTH);
111 }
112
113
114 /* OS_ReadXML v0.1
115  * Read a XML file and generate the necessary structs.
116  */
117 int OS_ReadXML(const char *file, OS_XML *_lxml)
118 {
119     int r;
120     unsigned int i;
121     FILE *fp;
122
123     /* init xml strcuture */
124     _lxml->cur = 0;
125         _lxml->fol = 0;
126         _lxml->el = NULL;
127         _lxml->ct = NULL;
128         _lxml->tp = NULL;
129         _lxml->rl = NULL;
130         _lxml->ck = NULL;
131         _lxml->ln = NULL;
132
133         _lxml->err_line = 0;
134         memset(_lxml->err,'\0',XML_ERR_LENGTH);
135
136     fp = fopen(file,"r");
137     if(!fp)
138     {
139         xml_error(_lxml, "XMLERR: File '%s' not found.",file);
140         return(-2);
141     }
142
143     /* Zeroing the line */
144     _line = 1;
145
146     if((r = _ReadElem(fp,0,_lxml)) < 0) /* First position */
147     {
148         if(r != LEOF)
149         {
150             fclose(fp);
151             return(-1);
152         }
153     }
154
155     for(i=0;i<_lxml->cur;i++)
156     {
157         if(_lxml->ck[i] == 0)
158         {
159             xml_error(_lxml,"XMLERR: Element '%s' not closed.", _lxml->el[i]);
160             fclose(fp);
161             return(-1);
162         }
163     }
164
165     fclose(fp);
166     return(0);
167 }
168
169
170 static int _oscomment(FILE *fp)
171 {
172     int c;
173     if((c = fgetc(fp)) == _R_COM)
174     {
175         while((c=_xml_fgetc(fp)) != EOF)
176         {
177             if(c == _R_COM)
178             {
179                 if((c=fgetc(fp)) == _R_CONFE)
180                     return(1);
181                 ungetc(c,fp);
182             }
183             else if(c == '-')       /* W3C way of finish comments */
184             {
185                 if((c = _xml_fgetc(fp)) == '-')
186                 {
187                     if((c = fgetc(fp)) == _R_CONFE)
188                         return(1);
189                     ungetc(c,fp);
190                 }
191                 ungetc(c,fp);
192             }
193             else
194                 continue;
195         }
196         return(-1);
197     }
198     else
199         ungetc(c,fp);
200     return(0);
201 }
202
203
204 static int _ReadElem(FILE *fp, unsigned int parent, OS_XML *_lxml)
205 {
206     int c;
207     unsigned int count = 0;
208     unsigned int _currentlycont = 0;
209     short int location = -1;
210
211     int prevv = 0;
212     char elem[XML_MAXSIZE +1];
213     char cont[XML_MAXSIZE +1];
214     char closedelem[XML_MAXSIZE +1];
215
216
217
218     memset(elem,'\0',XML_MAXSIZE +1);
219     memset(cont,'\0',XML_MAXSIZE +1);
220     memset(closedelem,'\0',XML_MAXSIZE +1);
221
222     while((c=_xml_fgetc(fp)) != EOF)
223     {
224         if(c == '\\')
225             prevv = c;
226         else if(prevv == '\\')
227         {
228             if(c != _R_CONFS)
229                 prevv = 0;
230         }
231
232
233         /* Max size */
234         if(count >= XML_MAXSIZE)
235         {
236             xml_error(_lxml,"XMLERR: String overflow.");
237             return(-1);
238         }
239
240
241         /* Checking for comments */
242         if(c == _R_CONFS)
243         {
244             int r = 0;
245             if((r = _oscomment(fp)) < 0)
246             {
247                 xml_error(_lxml,"XMLERR: Comment not closed.");
248                 return(-1);
249             }
250             else if(r == 1)
251                 continue;
252         }
253
254         /* real checking */
255         if((location == -1) && (prevv == 0))
256         {
257             if(c == _R_CONFS)
258             {
259                 if((c=fgetc(fp)) == '/')
260                 {
261                     xml_error(_lxml,"XMLERR: Element not opened.");
262                     return(-1);
263                 }
264                 else
265                     ungetc(c,fp);
266                 location = 0;
267             }
268             else
269                 continue;
270         }
271
272         else if((location == 0) && ((c == _R_CONFE) || isspace(c)))
273         {
274             int _ge = 0;
275             int _ga = 0;
276             elem[count]='\0';
277
278             /* Removing the / at the end of the element name */
279             if(count > 0 && elem[count -1] == '/')
280             {
281                 _ge = '/';
282                 elem[count -1] = '\0';
283             }
284
285             if(_writememory(elem, XML_ELEM, count+1, parent, _lxml) < 0)
286             {
287                 return(-1);
288             }
289             _currentlycont=_lxml->cur-1;
290             if(isspace(c))
291             {
292                 if((_ga = _getattributes(fp,parent,_lxml)) < 0)
293                     return(-1);
294             }
295
296             /* If the element is closed already (finished in />) */
297             if((_ge == '/') || (_ga == '/'))
298             {
299                 if(_writecontent("\0", 2, _currentlycont,_lxml) < 0)
300                 {
301                     return(-1);
302                 }
303                 _lxml->ck[_currentlycont] = 1;
304                 _currentlycont = 0;
305                 count = 0;
306                 location = -1;
307
308                 memset(elem,'\0',XML_MAXSIZE);
309                 memset(closedelem,'\0',XML_MAXSIZE);
310                 memset(cont,'\0',XML_MAXSIZE);
311
312                 if(parent > 0)
313                     return(0);
314             }
315             else
316             {
317                 count = 0;
318                 location = 1;
319             }
320         }
321
322         else if((location == 2) &&(c == _R_CONFE))
323         {
324             closedelem[count]='\0';
325             if(strcmp(closedelem,elem) != 0)
326             {
327                 xml_error(_lxml,"XMLERR: Element '%s' not closed.",elem);
328                 return(-1);
329             }
330             if(_writecontent(cont,strlen(cont)+1,_currentlycont,_lxml) < 0)
331             {
332                 return(-1);
333             }
334             _lxml->ck[_currentlycont]=1;
335             memset(elem,'\0',XML_MAXSIZE);
336             memset(closedelem,'\0',XML_MAXSIZE);
337             memset(cont,'\0',XML_MAXSIZE);
338             _currentlycont = 0;
339             count = 0;
340             location = -1;
341             if(parent > 0)
342                 return(0);
343         }
344         else if((location == 1) && (c == _R_CONFS) && (prevv == 0))
345         {
346             if((c=fgetc(fp)) == '/')
347             {
348                 cont[count] = '\0';
349                 count = 0;
350                 location = 2;
351             }
352             else
353             {
354                 ungetc(c,fp);
355                 ungetc(_R_CONFS,fp);
356
357                 if(_ReadElem(fp,parent+1,_lxml)< 0)
358                 {
359                     return(-1);
360                 }
361                 count=0;
362             }
363         }
364         else
365         {
366             if(location == 0)
367                 elem[count++] = (char) c;
368             else if(location == 1)
369                 cont[count++] = (char) c;
370             else if(location == 2)
371                 closedelem[count++] = (char) c;
372
373             if((_R_CONFS == c) && (prevv != 0))
374             {
375                 prevv = 0;
376             }
377         }
378     }
379     if(location == -1)
380         return(LEOF);
381
382     xml_error(_lxml,"XMLERR: End of file and some elements were not closed.");
383     return(-1);
384 }
385
386 static int _writememory(const char *str, XML_TYPE type, size_t size,
387                                         unsigned int parent, OS_XML *_lxml)
388 {
389     char **tmp;
390     int *tmp2;
391     unsigned int *tmp3;
392     XML_TYPE *tmp4;
393
394     /* Allocating for the element */
395     tmp = (char **)realloc(_lxml->el,(_lxml->cur+1)*sizeof(char *));
396     if(tmp == NULL)
397     {
398         goto fail;
399     }
400     _lxml->el = tmp;
401     _lxml->el[_lxml->cur]=(char *)calloc(size,sizeof(char));
402     if(_lxml->el[_lxml->cur] == NULL)
403     {
404         goto fail;
405     }
406     strncpy(_lxml->el[_lxml->cur],str,size-1);
407
408     /* Allocating for the content */
409     tmp = (char **)realloc(_lxml->ct,(_lxml->cur+1)*sizeof(char *));
410     if(tmp == NULL)
411     {
412         goto fail;
413     }
414     _lxml->ct = tmp;
415     _lxml->ct[_lxml->cur] = NULL;
416
417     /* Allocating for the type */
418     tmp4 = (XML_TYPE *) realloc(_lxml->tp,(_lxml->cur+1)*sizeof(XML_TYPE));
419     if(tmp4 == NULL)
420     {
421         goto fail;
422     }
423     _lxml->tp = tmp4;
424     _lxml->tp[_lxml->cur] = type;
425
426     /* Allocating for the relation */
427     tmp3 = (unsigned int *) realloc(_lxml->rl,(_lxml->cur+1)*sizeof(unsigned int));
428     if(tmp3 == NULL)
429     {
430         goto fail;
431     }
432     _lxml->rl = tmp3;
433     _lxml->rl[_lxml->cur] = parent;
434
435     /* Allocating for the "check" */
436     tmp2 = (int *) realloc(_lxml->ck,(_lxml->cur+1)*sizeof(int));
437     if(tmp2 == NULL)
438     {
439         goto fail;
440     }
441     _lxml->ck = tmp2;
442     _lxml->ck[_lxml->cur] = 0;
443
444     /* Allocating for the line */
445     tmp3 = (unsigned int *) realloc(_lxml->ln,(_lxml->cur+1)*sizeof(unsigned int));
446     if(tmp3 == NULL)
447     {
448         goto fail;
449     }
450     _lxml->ln = tmp3;
451     _lxml->ln[_lxml->cur] = _line;
452
453     /* Attributes does not need to be closed */
454     if(type == XML_ATTR)
455         _lxml->ck[_lxml->cur] = 1;
456
457     /* Checking if it is a variable */
458     if(strcasecmp(XML_VAR,str) == 0)
459     {
460         _lxml->tp[_lxml->cur] = XML_VARIABLE_BEGIN;
461     }
462
463     _lxml->cur++;
464     return(0);
465
466     fail:
467     snprintf(_lxml->err, XML_ERR_LENGTH, "XMLERR: Memory error.");
468     return(-1);
469 }
470
471 static int _writecontent(const char *str, size_t size, unsigned int parent, OS_XML *_lxml)
472 {
473     _lxml->ct[parent]=(char *)calloc(size,sizeof(char));
474     if( _lxml->ct[parent] == NULL)
475     {
476         snprintf(_lxml->err, XML_ERR_LENGTH, "XMLERR: Memory error.");
477         return(-1);
478     }
479     strncpy(_lxml->ct[parent],str,size-1);
480
481     return(0);
482 }
483
484
485 /* getattributes (Internal function): v0.1: 2005/03/03
486  * Read the attributes of an element
487  */
488 static int _getattributes(FILE *fp, unsigned int parent,OS_XML *_lxml)
489 {
490     int location = 0;
491     unsigned int count = 0;
492     int c;
493     int c_to_match = 0;
494
495     char attr[XML_MAXSIZE+1];
496     char value[XML_MAXSIZE+1];
497
498     memset(attr,'\0',XML_MAXSIZE+1);
499     memset(value,'\0',XML_MAXSIZE+1);
500
501     while((c=_xml_fgetc(fp)) != EOF)
502     {
503         if(count >= XML_MAXSIZE)
504         {
505             attr[count-1] = '\0';
506             xml_error(_lxml,
507                     "XMLERR: Overflow attempt at attribute '%.20s'.",attr);
508             return(-1);
509         }
510
511         else if((c == _R_CONFE) || ((location == 0) && (c == '/')))
512         {
513             if(location == 1)
514             {
515                 xml_error(_lxml, "XMLERR: Attribute '%s' not closed.",
516                                  attr);
517                 return(-1);
518             }
519             else if((location == 0)&&(count > 0))
520             {
521                 xml_error(_lxml, "XMLERR: Attribute '%s' has no value.",
522                                                  attr);
523                                 return(-1);
524             }
525             else if(c == '/')
526                 return(c);
527             else
528                 return(0);
529         }
530         else if((location == 0)&&(c == '='))
531         {
532             attr[count]='\0';
533
534             /* check for already existent attribute with same name */
535             unsigned int i = _lxml->cur - 1;
536             /* search attributes backwards in same parent */
537             while(_lxml->rl[i] == parent && _lxml->tp[i] == XML_ATTR)
538             {
539                 if(strcmp(_lxml->el[i], attr) == 0)
540                 {
541                     xml_error(_lxml, "XMLERR: Attribute '%s' already defined.", attr);
542                     return(-1);
543                 }
544
545                 /* continue with previous element */
546                 if(i==0)
547                 {
548                     break;
549                 }
550                 i--;
551             }
552
553             c = _xml_fgetc(fp);
554             if((c != '"')&&(c != '\''))
555             {
556                 unsigned short int _err=1;
557                 if(isspace(c))
558                 {
559                     while((c=_xml_fgetc(fp))!= EOF)
560                     {
561                         if(isspace(c))
562                             continue;
563                         else if((c == '"')||(c == '\''))
564                         {
565                             _err = 0;
566                             break;
567                         }
568                         else
569                             break;
570                     }
571                 }
572                 if(_err != 0){
573                     xml_error(_lxml,
574                             "XMLERR: Attribute '%s' not followed by a \" or \'."
575                             ,attr);
576                     return(-1); }
577             }
578
579             c_to_match = c;
580             location = 1;
581             count = 0;
582         }
583         else if((location == 0)&&(isspace(c)))
584         {
585             if(count == 0)
586             {
587                 continue;
588             }
589             else
590             {
591                 xml_error(_lxml, "XMLERR: Attribute '%s' has no value.", attr);
592                 return(-1);
593             }
594         }
595         else if((location == 1)&&(c == c_to_match))
596         {
597             value[count]='\0';
598
599             /* dead code:
600              * location = 0;
601              * c_to_match = 0;
602              */
603
604             if(_writememory(attr, XML_ATTR, strlen(attr)+1,
605                     parent, _lxml) < 0)
606             {
607                 return(-1);
608             }
609             if(_writecontent(value,count+1,_lxml->cur-1,_lxml) < 0)
610             {
611                 return(-1);
612             }
613             c = _xml_fgetc(fp);
614             if(isspace(c))
615                 return(_getattributes(fp,parent,_lxml));
616             else if(c == _R_CONFE)
617                 return(0);
618             else if(c == '/')
619                 return (c);
620
621             xml_error(_lxml,
622                 "XMLERR: Bad attribute closing for '%s'='%s'.",
623                 attr,value);
624             return(-1);
625         }
626         else if(location == 0)
627             attr[count++] = (char) c;
628         else if(location == 1)
629             value[count++] = (char) c;
630
631     }
632
633     xml_error(_lxml, "XMLERR: End of file while reading an attribute.");
634     return(-1);
635 }
636
637 /* EOF */