1919612c5027c1cf076ac3a5fbfc1a8d45249afa
[ossec-hids.git] / os_xml_writer.c
1 /* @(#) $Id: ./src/os_xml/os_xml_writer.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All rights reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13 /* os_xml Library.
14  * Available at http://www.ossec.net/
15  */
16
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "os_xml.h"
21 #include "os_xml_internal.h"
22
23 /* Internal functions */
24 static int _oswcomment(FILE *fp_in, FILE *fp_out) __attribute__((nonnull));
25 static int _WReadElem(FILE *fp_in, FILE *fp_out, unsigned int position, unsigned int parent,
26                 const char **node, const char *value, unsigned int node_pos) __attribute__((nonnull));
27 static int _xml_wfgetc(FILE *fp_in, FILE *fp_out) __attribute__((nonnull));
28
29 /* Local fgetc */
30 static int _xml_wfgetc(FILE *fp_in, FILE *fp_out)
31 {
32     int c;
33
34     /* Putting on fp_out, whatever we read */
35     c = fgetc(fp_in);
36     if(c != EOF)
37     {
38         fputc(c, fp_out);
39     }
40
41     return(c);
42 }
43
44 /* OS_WriteXML
45  * Write an XML file, based on the input and values to change.
46  */
47 int OS_WriteXML(const char *infile, const char *outfile, const char **nodes,
48                 const char *oldval, const char *newval)
49 {
50     int r = 0;
51     FILE *fp_in;
52     FILE *fp_out;
53
54
55     /* Opening infile */
56     fp_in = fopen(infile,"r");
57     if(!fp_in)
58     {
59         return(XMLW_NOIN);
60     }
61
62
63     /* Opening out file */
64     fp_out = fopen(outfile,"w");
65     if(!fp_out)
66     {
67         fclose(fp_in);
68         return(XMLW_NOOUT);
69     }
70
71
72     if((r = _WReadElem(fp_in, fp_out, 0, 0,
73                        nodes, newval, 0)) < 0) /* First position */
74     {
75         fclose(fp_in);
76         fclose(fp_out);
77         return(XMLW_ERROR);
78     }
79
80     /* We didn't find an entry, add at the end. */
81     if(!oldval && r == 0)
82     {
83         int s = 0;
84         int rwidth = 0;
85
86         fseek(fp_out, 0, SEEK_END);
87         fprintf(fp_out, "\n");
88
89         /* Printing each node. */
90         while(nodes[s])
91         {
92             fprintf(fp_out, "%*c<%s>", rwidth, ' ', nodes[s]);
93             s++;
94             rwidth += 3;
95
96             if(nodes[s])
97                 fprintf(fp_out, "\n");
98         }
99
100         /* Printing val. */
101         s--;
102         rwidth -=6;
103         fprintf(fp_out, "%s</%s>\n", newval, nodes[s]);
104         s--;
105
106
107         /* Closing each node. */
108         while(s >= 0)
109         {
110             fprintf(fp_out, "%*c</%s>\n", rwidth, ' ', nodes[s]);
111             s--;
112             rwidth -= 3;
113         }
114     }
115
116     fclose(fp_in);
117     fclose(fp_out);
118     return(0);
119 }
120
121
122
123 /* Getting comments */
124 static int _oswcomment(FILE *fp_in, FILE *fp_out)
125 {
126     int c;
127     if((c = fgetc(fp_in)) == _R_COM)
128     {
129         fputc(c, fp_out);
130         while((c = _xml_wfgetc(fp_in, fp_out)) != EOF)
131         {
132             if(c == _R_COM)
133             {
134                 if((c=fgetc(fp_in)) == _R_CONFE)
135                 {
136                     fputc(c, fp_out);
137                     return(1);
138                 }
139                 ungetc(c,fp_in);
140             }
141             else if(c == '-')       /* W3C way of finish comments */
142             {
143                 if((c = fgetc(fp_in)) == '-')
144                 {
145                     fputc(c, fp_out);
146                     if((c = fgetc(fp_in)) == _R_CONFE)
147                     {
148                         fputc(c, fp_out);
149                         return(1);
150                     }
151                     ungetc(c,fp_in);
152                 }
153                 else
154                 {
155                     ungetc(c,fp_in);
156                 }
157             }
158             else
159             {
160                 continue;
161             }
162         }
163         return(-1);
164     }
165     else
166     {
167         ungetc(c,fp_in);
168     }
169
170     return(0);
171 }
172
173
174
175 static int _WReadElem(FILE *fp_in, FILE *fp_out,
176               unsigned int position, unsigned int parent, const char **nodes, const char *val, unsigned int node_pos)
177 {
178     int c;
179     int ret_code = 0;
180     unsigned int count = 0;
181     short int location = -1;
182
183     char elem[XML_MAXSIZE +1];
184     char cont[XML_MAXSIZE +1];
185     char closedelem[XML_MAXSIZE +1];
186
187     memset(elem,'\0',XML_MAXSIZE +1);
188     memset(cont,'\0',XML_MAXSIZE +1);
189     memset(closedelem,'\0',XML_MAXSIZE +1);
190
191
192     while((c = _xml_wfgetc(fp_in, fp_out)) != EOF)
193     {
194         /* Max size */
195         if(count >= XML_MAXSIZE)
196         {
197             return(-1);
198         }
199
200         /* Checking for comments */
201         if(c == _R_CONFS)
202         {
203             int r = 0;
204             if((r = _oswcomment(fp_in, fp_out)) < 0)
205             {
206                 return(-1);
207             }
208             else if(r == 1)
209             {
210                 continue;
211             }
212         }
213
214
215         /* Real checking */
216         if(location == -1)
217         {
218             /* Must be the opening element */
219             if(c == _R_CONFS)
220             {
221                 if((c = fgetc(fp_in)) == '/')
222                 {
223                     return(-1);
224                 }
225                 else
226                 {
227                     ungetc(c,fp_in);
228                 }
229                 location = 0;
230             }
231             else
232             {
233                 continue;
234             }
235         }
236
237
238         /* Looking for the closure */
239         else if((location == 0) && ((c == _R_CONFE) || (c == ' ')))
240         {
241             int _ge = 0;
242             elem[count] = '\0';
243
244
245             /* Removing the / at the end of the element name */
246             if(count > 0 && elem[count -1] == '/')
247             {
248                 _ge = '/';
249                 elem[count -1] = '\0';
250             }
251
252
253             /* If we may have more attributes */
254             if(c == ' ')
255             {
256                 /* Writing the attributes */
257                 while((c = _xml_wfgetc(fp_in, fp_out)) != EOF)
258                 {
259                     if(c == _R_CONFE)
260                     {
261                         break;
262                     }
263                 }
264             }
265
266
267             /* If the element is closed already (finished in />) */
268             if(_ge == '/')
269             {
270                 count = 0;
271                 location = -1;
272
273                 memset(elem,'\0',XML_MAXSIZE);
274                 memset(closedelem,'\0',XML_MAXSIZE);
275                 memset(cont,'\0',XML_MAXSIZE);
276
277                 if(parent > 0)
278                 {
279                     return(ret_code);
280                 }
281             }
282             /* Location == means we are getting the content */
283             else
284             {
285                 count = 0;
286                 location = 1;
287             }
288
289
290             /* Checking position of the node */
291             if(node_pos > position)
292             {
293                 node_pos = 0;
294             }
295
296             /* Checking if the element name matches */
297             if(node_pos == position &&
298                nodes[node_pos] && strcmp(elem, nodes[node_pos]) == 0)
299             {
300                 node_pos++;
301
302                 /* Latest node, printint value */
303                 if(!nodes[node_pos])
304                 {
305                     ret_code = 1;
306                     fprintf(fp_out, "%s", val);
307
308                     while((c = fgetc(fp_in)) != EOF)
309                     {
310                         if(c == _R_CONFS)
311                         {
312                             ungetc(c,fp_in);
313                             break;
314                         }
315                     }
316                 }
317             }
318         }
319
320         else if((location == 2) &&(c == _R_CONFE))
321         {
322             closedelem[count]='\0';
323             if(strcmp(closedelem,elem) != 0)
324             {
325                 return(-1);
326             }
327
328             memset(elem,'\0',XML_MAXSIZE);
329             memset(closedelem,'\0',XML_MAXSIZE);
330             memset(cont,'\0',XML_MAXSIZE);
331
332             count = 0;
333             location = -1;
334             if(parent > 0)
335             {
336                 return(ret_code);
337             }
338         }
339
340         /* If we are reading the element */
341         else if((location == 1) &&(c == _R_CONFS))
342         {
343             if((c=fgetc(fp_in)) == '/')
344             {
345                 fputc(c, fp_out);
346
347                 cont[count] = '\0';
348                 count = 0;
349                 location = 2;
350             }
351             else
352             {
353                 int wret_code;
354                 ungetc(c,fp_in);
355                 ungetc(_R_CONFS,fp_in);
356                 fseek(fp_out, -1, SEEK_CUR);
357
358                 if((wret_code = _WReadElem(fp_in, fp_out, position+1, parent+1,
359                              nodes, val, node_pos))< 0)
360                 {
361                     return(-1);
362                 }
363
364                 /* Setting final return code. */
365                 if(wret_code == 1)
366                 {
367                     ret_code = 1;
368                 }
369
370                 count = 0;
371             }
372         }
373         else
374         {
375             if(location == 0)
376             {
377                 elem[count++] = (char) c;
378             }
379             else if(location == 1)
380             {
381                 cont[count++] = (char) c;
382             }
383             else if(location == 2)
384             {
385                 closedelem[count++] = (char) c;
386             }
387         }
388     }
389
390     if(location == -1)
391     {
392         return(ret_code);
393     }
394
395
396     return(-1);
397 }
398
399
400
401
402 /* EOF */