Imported Upstream version 2.7
[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
16
17 #include "shared.h"
18
19 #include "os_xml.h"
20
21 #define _R_CONFS        '<'
22 #define _R_CONFE        '>'
23 #define _R_EQUAL        '='
24 #define _R_COM          '!'
25 #define _R_VAR      '$'
26
27 #define OPEN            51
28 #define CLOSE           52
29
30 #define LEOF            -2
31
32 /* Internal functions */
33 int _oscomment(FILE *fp);
34 int _writecontent(char *str, unsigned int size, int parent, OS_XML *_lxml);
35 int _writememory(char *str, short int type, unsigned int size,
36                                         int parent, OS_XML *_lxml);
37 int _checkmemory(char *str,OS_XML *_lxml);
38 int _ReadElem(FILE *fp, int position, int parent, OS_XML *_lxml);
39 int _getattributes(FILE *fp,int parent,OS_XML *_lxml);
40
41 void xml_error(OS_XML *_lxml, const char *msg,...) __attribute__((format(printf, 2, 3)));
42
43 /* Currently line */
44 int _line;
45
46 /* Local fgetc */
47 int _xml_fgetc(FILE *fp)
48 {
49     int c;
50     c = fgetc(fp);
51
52     if(c == '\n') /* add new line */
53         _line++;
54
55     return(c);
56 }
57
58 #define FGETC(fp) _xml_fgetc(fp)
59
60 void xml_error(OS_XML *_lxml, const char *msg,...)
61 {
62 #ifdef DEBUG
63     time_t tm;
64     struct tm *p;
65 #endif
66
67     va_list args;
68     va_start(args,msg);
69
70 #ifdef DEBUG    
71     tm = time(NULL);
72     p = localtime(&tm);
73     fprintf(stderr,"%d/%d/%d %d:%d:%d (LINE: %d)",p->tm_year+1900,p->tm_mon,
74             p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec,_line);
75     vfprintf(stderr, msg, args);
76     fprintf(stderr, "\n\n");
77 #endif
78
79     memset(_lxml->err,'\0', 128);
80     vsnprintf(_lxml->err,127,msg,args);
81     va_end(args);
82     _lxml->err_line = _line;
83 }
84
85
86
87 /* OS_ClearXML v0.1
88  * Clear the memory used by the XML
89  */
90 void OS_ClearXML(OS_XML *_lxml)
91 {
92     int i;
93     for(i=0;i<_lxml->cur;i++)
94     {
95         if(_lxml->el[i])
96             free(_lxml->el[i]);
97         if(_lxml->ct[i])
98             free(_lxml->ct[i]);
99     }
100     _lxml->cur = 0;
101     _lxml->err_line = 0;
102     free(_lxml->el);
103     free(_lxml->ct);
104     free(_lxml->rl);
105     free(_lxml->tp);
106     free(_lxml->ck);
107     free(_lxml->ln);
108     memset(_lxml->err,'\0', 128);
109
110     return;     
111
112 }
113
114
115 /* OS_ReadXML v0.1
116  * Read a XML file and generate the necessary structs.
117  */
118 int OS_ReadXML(char *file, OS_XML *_lxml)
119 {
120     int r,i;
121     FILE *fp;
122
123     fp = fopen(file,"r");
124     if(!fp)
125     {
126         xml_error(_lxml, "XMLERR: File '%s' not found.",file);
127         return(-2);
128     }
129
130     _lxml->cur = 0;
131     _lxml->fol = 0;
132     _lxml->el = NULL;
133     _lxml->ct = NULL;
134     _lxml->tp = NULL;
135     _lxml->rl = NULL;
136     _lxml->ck = NULL;
137     _lxml->ln = NULL;
138
139     _lxml->err_line = 0;
140     memset(_lxml->err,'\0',128);
141
142     /* Zeroing the line */
143     _line = 1;
144
145     if((r = _ReadElem(fp,0,0,_lxml)) < 0) /* First position */
146     {
147         if(r != LEOF)
148         {
149             fclose(fp);
150             return(-1);
151         }
152     }
153
154     for(i=0;i<_lxml->cur;i++)
155     {
156         if(_lxml->ck[i] == 0)
157         {
158             xml_error(_lxml,"XMLERR: Element '%s' not closed\n", _lxml->el[i]);
159             fclose(fp);
160             return(-1);
161         }
162     }
163
164     fclose(fp);
165     return(0);
166 }
167
168
169 int _oscomment(FILE *fp)
170 {
171     int c;
172     if((c = fgetc(fp)) == _R_COM)
173     {
174         while((c=FGETC(fp)) != EOF)
175         {
176             if(c == _R_COM)
177             {
178                 if((c=fgetc(fp)) == _R_CONFE)
179                     return(1);
180                 ungetc(c,fp);
181             }
182             else if(c == '-')       /* W3C way of finish comments */
183             {
184                 if((c = FGETC(fp)) == '-')
185                 {
186                     if((c = fgetc(fp)) == _R_CONFE)
187                         return(1);
188                     ungetc(c,fp);
189                 }
190                 ungetc(c,fp);
191             }
192             else
193                 continue;
194         }
195         return(-1);
196     }
197     else
198         ungetc(c,fp);
199     return(0);
200 }
201
202
203 int _ReadElem(FILE *fp, int position, int parent, OS_XML *_lxml)
204 {
205     int c;
206     unsigned int count = 0;
207     unsigned int _currentlycont = 0;
208     short int location = -1;
209
210     char prevv = 0;
211     char elem[XML_MAXSIZE +1];
212     char cont[XML_MAXSIZE +1];
213     char closedelem[XML_MAXSIZE +1];
214
215
216
217     memset(elem,'\0',XML_MAXSIZE +1);
218     memset(cont,'\0',XML_MAXSIZE +1);
219     memset(closedelem,'\0',XML_MAXSIZE +1);
220
221     while((c=FGETC(fp)) != EOF)
222     {
223         if(c == '\\')
224             prevv = c;
225         else if(prevv == '\\')
226         {
227             if(c != _R_CONFS)
228                 prevv = 0;
229         }
230
231
232         /* Max size */
233         if(count >= XML_MAXSIZE)
234         {
235             xml_error(_lxml,"XML ERR: String overflow. Exiting.");
236             return(-1);
237         }
238
239
240         /* Checking for comments */
241         if(c == _R_CONFS)
242         {
243             int r = 0;
244             if((r = _oscomment(fp)) < 0)
245             {
246                 xml_error(_lxml,"XML ERR: Comment not closed. Bad XML.");
247                 return(-1);
248             }
249             else if(r == 1)
250                 continue;
251         }
252
253         /* real checking */
254         if((location == -1) && (prevv == 0))
255         {
256             if(c == _R_CONFS)
257             {
258                 if((c=fgetc(fp)) == '/')
259                 {
260                     xml_error(_lxml,"XML ERR: Bad formed XML. Element "
261                                     "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) || (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(elem[count -1] == '/')
280             {
281                 _ge = '/';
282                 elem[count -1] = '\0';
283             }
284
285             _writememory(elem, XML_ELEM, count+1, parent, _lxml);
286             _currentlycont=_lxml->cur-1;
287             if(c == ' ')
288             {
289                 if((_ga = _getattributes(fp,parent,_lxml)) < 0)
290                     return(-1);
291             }
292
293             /* If the element is closed already (finished in />) */
294             if((_ge == '/') || (_ga == '/'))
295             {
296                 _writecontent("\0", 2, _currentlycont,_lxml);
297                 _lxml->ck[_currentlycont] = 1;
298                 _currentlycont = 0;
299                 count = 0;
300                 location = -1;
301
302                 memset(elem,'\0',XML_MAXSIZE);
303                 memset(closedelem,'\0',XML_MAXSIZE);
304                 memset(cont,'\0',XML_MAXSIZE);
305
306                 if(parent > 0)
307                     return(0);
308             }
309             else
310             {
311                 count = 0;
312                 location = 1;
313             }
314         }
315
316         else if((location == 2) &&(c == _R_CONFE))
317         {
318             closedelem[count]='\0';
319             if(strcmp(closedelem,elem) != 0)
320             {
321                 xml_error(_lxml,"XML ERR: Element not closed: %s",elem);
322                 return(-1);
323             }
324             _writecontent(cont,strlen(cont)+1,_currentlycont,_lxml);
325             _lxml->ck[_currentlycont]=1;        
326             memset(elem,'\0',XML_MAXSIZE);
327             memset(closedelem,'\0',XML_MAXSIZE);
328             memset(cont,'\0',XML_MAXSIZE);
329             _currentlycont = 0;
330             count = 0;  
331             location = -1;
332             if(parent > 0)
333                 return(0);
334         }
335         else if((location == 1) && (c == _R_CONFS) && (prevv == 0))
336         {
337             if((c=fgetc(fp)) == '/')
338             {
339                 cont[count] = '\0';
340                 count = 0;
341                 location = 2;
342             }   
343             else
344             {
345                 ungetc(c,fp);
346                 ungetc(_R_CONFS,fp);
347
348                 if(_ReadElem(fp,position+1,parent+1,_lxml)< 0)
349                 {
350                     return(-1);
351                 }
352                 count=0;
353             }
354         }
355         else
356         {
357             if(location == 0)
358                 elem[count++] = c;
359             else if(location == 1)
360                 cont[count++] = c;
361             else if(location == 2)
362                 closedelem[count++] = c;
363
364             if((_R_CONFS == c) && (prevv != 0))
365             {
366                 prevv = 0;
367             }
368         }
369     }
370     if(location == -1)
371         return(LEOF);
372
373     xml_error(_lxml,"XML ERR: End of file and some elements were not closed");
374     return(-1);
375 }                               
376
377 int _writememory(char *str, short int type, unsigned int size,
378                                         int parent, OS_XML *_lxml)
379 {
380     /* Allocating for the element */
381     _lxml->el = (char **)realloc(_lxml->el,(_lxml->cur+1)*sizeof(char *));
382     _lxml->el[_lxml->cur]=(char *)calloc(size,sizeof(char));
383     strncpy(_lxml->el[_lxml->cur],str,size-1);
384
385     /* Allocating for the content */    
386     _lxml->ct = (char **)realloc(_lxml->ct,(_lxml->cur+1)*sizeof(char *));
387
388     /* Allocating for the type */
389     _lxml->tp = realloc(_lxml->tp,(_lxml->cur+1)*sizeof(int));
390     _lxml->tp[_lxml->cur] = type;       
391
392     /* Allocating for the relation */
393     _lxml->rl = realloc(_lxml->rl,(_lxml->cur+1)*sizeof(int));
394     _lxml->rl[_lxml->cur] = parent;
395
396     /* Allocating for the "check" */
397     _lxml->ck = realloc(_lxml->ck,(_lxml->cur+1)*sizeof(int));
398     _lxml->ck[_lxml->cur] = 0;
399
400     /* Allocating for the line */
401     _lxml->ln = realloc(_lxml->ln,(_lxml->cur+1)*sizeof(int));
402     _lxml->ln[_lxml->cur] = _line;
403
404     /* Attributes does not need to be closed */
405     if(type == XML_ATTR)
406         _lxml->ck[_lxml->cur] = 1;
407
408     /* Checking if it is a variable */
409     if(strcasecmp(XML_VAR,str) == 0)
410     {
411         _lxml->tp[_lxml->cur] = XML_VARIABLE_BEGIN;
412     }
413
414     _lxml->cur++;
415     return(0);
416 }
417
418 int _writecontent(char *str, unsigned int size, int parent, OS_XML *_lxml)
419 {
420     _lxml->ct[parent]=(char *)calloc(size,sizeof(char));
421     strncpy(_lxml->ct[parent],str,size-1);
422
423     return(0);
424 }
425
426
427 int _checkmemory(char *str,OS_XML *_lxml)
428 {
429     int i;
430     for(i=0;i<_lxml->cur;i++)
431     {
432         if(_lxml->ck[i] == 0)
433         {
434             if(strcmp(str,_lxml->el[i]) == 0)
435             {
436                 _lxml->ck[i] = 1;
437                 return(0);
438             }
439             else
440                 continue;
441         }
442     }
443     return(-1);
444 }
445
446 /* getattributes (Internal function): v0.1: 2005/03/03
447  * Read the attributes of an element
448  */
449 int _getattributes(FILE *fp,int parent,OS_XML *_lxml)
450 {
451     int location = 0;
452     int count = 0;
453     int c;
454     int c_to_match = 0;
455
456     char attr[XML_MAXSIZE+1];
457     char value[XML_MAXSIZE+1];
458
459     memset(attr,'\0',XML_MAXSIZE+1);
460     memset(value,'\0',XML_MAXSIZE+1);
461
462     while((c=FGETC(fp)) != EOF)
463     {
464         if(count >= XML_MAXSIZE)
465         {
466             attr[count-1] = '\0';
467             xml_error(_lxml,
468                     "XMLERR: Overflow attempt at attribute '%s'.",attr);
469             return(-1);
470         }
471
472         else if((c == _R_CONFE) || (c == '/'))
473         {
474             if((location == 1)||((location == 0)&&(count > 0)))
475             {
476                 xml_error(_lxml, "XMLERR: Attribute '%s' not closed.",
477                                  attr);
478                 return(-1);
479             }
480             else if(c == '/')
481                 return(c);
482             else
483                 return(0);
484         }       
485         else if((location == 0)&&(c == '='))
486         {
487             attr[count]='\0';
488             c = FGETC(fp);
489             if((c != '"')&&(c != '\''))
490             {
491                 unsigned short int _err=1;
492                 if(c == ' ')
493                 {
494                     while((c=FGETC(fp))!= EOF)
495                     {
496                         if(c == ' ')
497                             continue;
498                         else if((c == '"')||(c == '\''))
499                         {
500                             _err = 0;
501                             break;
502                         }
503                         else
504                             break;
505                     }
506                 }
507                 if(_err != 0){
508                     xml_error(_lxml,
509                             "XMLERR: Attribute '%s' not followed by a \" or \'."
510                             ,attr);
511                     return(-1); }
512             }
513
514             c_to_match = c;
515             location = 1;
516             count = 0;
517         }
518         else if((location == 0)&&(c == ' '))
519             continue;
520
521         else if((location == 1)&&(c == c_to_match))
522         {
523             value[count]='\0';
524
525             location = 0;
526             c_to_match = 0;
527
528             _writememory(attr, XML_ATTR, strlen(attr)+1,
529                     parent, _lxml);     
530             _writecontent(value,count+1,_lxml->cur-1,_lxml);
531             c = FGETC(fp);
532             if(c == ' ')
533                 return(_getattributes(fp,parent,_lxml));
534             else if(c == _R_CONFE)
535                 return(0);
536             else
537             {
538                 xml_error(_lxml,
539                         "XMLERR: Bad attribute closing for '%s'='%s'.",
540                         attr,value);
541                 return(-1);
542             }
543             count = 0;
544         }
545         else if(location == 0)
546             attr[count++]=c;
547         else if(location == 1)
548             value[count++]=c;
549
550     }
551
552     xml_error(_lxml, "XMLERR: End of file while reading an attribute.");
553     return(-1);
554 }
555
556 /* EOF */