new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_xml / os_xml_writer.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12
13 #include "os_xml.h"
14 #include "os_xml_internal.h"
15
16 /* Prototypes */
17 static int _oswcomment(FILE *fp_in, FILE *fp_out) __attribute__((nonnull));
18 static int _WReadElem(FILE *fp_in, FILE *fp_out, unsigned int position, unsigned int parent,
19                       const char **node, const char *value, unsigned int node_pos) __attribute__((nonnull));
20 static int _xml_wfgetc(FILE *fp_in, FILE *fp_out) __attribute__((nonnull));
21
22
23 /* Local wfgetc */
24 static int _xml_wfgetc(FILE *fp_in, FILE *fp_out)
25 {
26     int c;
27
28     /* Putting on fp_out, whatever we read */
29     c = fgetc(fp_in);
30     if (c != EOF) {
31         fputc(c, fp_out);
32     }
33
34     return (c);
35 }
36
37 /* Write an XML file, based on the input and values to change */
38 int OS_WriteXML(const char *infile, const char *outfile, const char **nodes,
39                 const char *oldval, const char *newval)
40 {
41     int r = 0;
42     FILE *fp_in;
43     FILE *fp_out;
44
45     /* Open infile */
46     fp_in = fopen(infile, "r");
47     if (!fp_in) {
48         return (XMLW_NOIN);
49     }
50
51     /* Open outfile */
52     fp_out = fopen(outfile, "w");
53     if (!fp_out) {
54         fclose(fp_in);
55         return (XMLW_NOOUT);
56     }
57
58     if ((r = _WReadElem(fp_in, fp_out, 0, 0,
59                         nodes, newval, 0)) < 0) { /* First position */
60         fclose(fp_in);
61         fclose(fp_out);
62         return (XMLW_ERROR);
63     }
64
65     /* We didn't find an entry, add at the end */
66     if (!oldval && r == 0) {
67         int s = 0;
68         int rwidth = 0;
69
70         fseek(fp_out, 0, SEEK_END);
71         fprintf(fp_out, "\n");
72
73         /* Print each node */
74         while (nodes[s]) {
75             fprintf(fp_out, "%*c<%s>", rwidth, ' ', nodes[s]);
76             s++;
77             rwidth += 3;
78
79             if (nodes[s]) {
80                 fprintf(fp_out, "\n");
81             }
82         }
83
84         /* Print val */
85         s--;
86         rwidth -= 6;
87         fprintf(fp_out, "%s</%s>\n", newval, nodes[s]);
88         s--;
89
90         /* Close each node */
91         while (s >= 0) {
92             fprintf(fp_out, "%*c</%s>\n", rwidth, ' ', nodes[s]);
93             s--;
94             rwidth -= 3;
95         }
96     }
97
98     fclose(fp_in);
99     fclose(fp_out);
100     return (0);
101 }
102
103 /* Get comments */
104 static int _oswcomment(FILE *fp_in, FILE *fp_out)
105 {
106     int c;
107     if ((c = fgetc(fp_in)) == _R_COM) {
108         fputc(c, fp_out);
109         while ((c = _xml_wfgetc(fp_in, fp_out)) != EOF) {
110             if (c == _R_COM) {
111                 if ((c = fgetc(fp_in)) == _R_CONFE) {
112                     fputc(c, fp_out);
113                     return (1);
114                 }
115                 ungetc(c, fp_in);
116             } else if (c == '-') {  /* W3C way of finishing comments */
117                 if ((c = fgetc(fp_in)) == '-') {
118                     fputc(c, fp_out);
119                     if ((c = fgetc(fp_in)) == _R_CONFE) {
120                         fputc(c, fp_out);
121                         return (1);
122                     }
123                     ungetc(c, fp_in);
124                 } else {
125                     ungetc(c, fp_in);
126                 }
127             } else {
128                 continue;
129             }
130         }
131         return (-1);
132     } else {
133         ungetc(c, fp_in);
134     }
135
136     return (0);
137 }
138
139 static int _WReadElem(FILE *fp_in, FILE *fp_out, unsigned int position,
140                       unsigned int parent, const char **nodes,
141                       const char *val, unsigned int node_pos)
142 {
143     int c;
144     int ret_code = 0;
145     unsigned int count = 0;
146     short int location = -1;
147
148     char elem[XML_MAXSIZE + 1];
149     char cont[XML_MAXSIZE + 1];
150     char closedelim[XML_MAXSIZE + 1];
151
152     memset(elem, '\0', XML_MAXSIZE + 1);
153     memset(cont, '\0', XML_MAXSIZE + 1);
154     memset(closedelim, '\0', XML_MAXSIZE + 1);
155
156     while ((c = _xml_wfgetc(fp_in, fp_out)) != EOF) {
157         /* Max size */
158         if (count >= XML_MAXSIZE) {
159             return (-1);
160         }
161
162         /* Check for comments */
163         if (c == _R_CONFS) {
164             int r = 0;
165             if ((r = _oswcomment(fp_in, fp_out)) < 0) {
166                 return (-1);
167             } else if (r == 1) {
168                 continue;
169             }
170         }
171
172         /* Real checking */
173         if (location == -1) {
174             /* Must be the opening element */
175             if (c == _R_CONFS) {
176                 if ((c = fgetc(fp_in)) == '/') {
177                     return (-1);
178                 } else {
179                     ungetc(c, fp_in);
180                 }
181                 location = 0;
182             } else {
183                 continue;
184             }
185         }
186
187         /* Look for the closure */
188         else if ((location == 0) && ((c == _R_CONFE) || (c == ' '))) {
189             int _ge = 0;
190             elem[count] = '\0';
191
192             /* Remove the / at the end of the element name */
193             if (count > 0 && elem[count - 1] == '/') {
194                 _ge = '/';
195                 elem[count - 1] = '\0';
196             }
197
198             /* If we may have more attributes */
199             if (c == ' ') {
200                 /* Write the attributes */
201                 while ((c = _xml_wfgetc(fp_in, fp_out)) != EOF) {
202                     if (c == _R_CONFE) {
203                         break;
204                     }
205                 }
206             }
207
208             /* If the element is closed already (finished in />) */
209             if (_ge == '/') {
210                 count = 0;
211                 location = -1;
212
213                 memset(elem, '\0', XML_MAXSIZE);
214                 memset(closedelim, '\0', XML_MAXSIZE);
215                 memset(cont, '\0', XML_MAXSIZE);
216
217                 if (parent > 0) {
218                     return (ret_code);
219                 }
220             }
221             /* Location == means we are getting the content */
222             else {
223                 count = 0;
224                 location = 1;
225             }
226
227             /* Check position of the node */
228             if (node_pos > position) {
229                 node_pos = 0;
230             }
231
232             /* Check if the element name matches */
233             if (node_pos == position &&
234                     nodes[node_pos] && strcmp(elem, nodes[node_pos]) == 0) {
235                 node_pos++;
236
237                 /* Latest node, print value */
238                 if (!nodes[node_pos]) {
239                     ret_code = 1;
240                     fprintf(fp_out, "%s", val);
241
242                     while ((c = fgetc(fp_in)) != EOF) {
243                         if (c == _R_CONFS) {
244                             ungetc(c, fp_in);
245                             break;
246                         }
247                     }
248                 }
249             }
250         }
251
252         else if ((location == 2) && (c == _R_CONFE)) {
253             closedelim[count] = '\0';
254             if (strcmp(closedelim, elem) != 0) {
255                 return (-1);
256             }
257
258             memset(elem, '\0', XML_MAXSIZE);
259             memset(closedelim, '\0', XML_MAXSIZE);
260             memset(cont, '\0', XML_MAXSIZE);
261
262             count = 0;
263             location = -1;
264             if (parent > 0) {
265                 return (ret_code);
266             }
267         }
268
269         /* If we are reading the element */
270         else if ((location == 1) && (c == _R_CONFS)) {
271             if ((c = fgetc(fp_in)) == '/') {
272                 fputc(c, fp_out);
273
274                 cont[count] = '\0';
275                 count = 0;
276                 location = 2;
277             } else {
278                 int wret_code;
279                 ungetc(c, fp_in);
280                 ungetc(_R_CONFS, fp_in);
281                 if (fseek(fp_out, -1, SEEK_CUR)) {
282                     return (-1);
283                 }
284
285                 if ((wret_code = _WReadElem(fp_in, fp_out, position + 1, parent + 1,
286                                             nodes, val, node_pos)) < 0) {
287                     return (-1);
288                 }
289
290                 /* Set final return code */
291                 if (wret_code == 1) {
292                     ret_code = 1;
293                 }
294
295                 count = 0;
296             }
297         } else {
298             if (location == 0) {
299                 elem[count++] = (char) c;
300             } else if (location == 1) {
301                 cont[count++] = (char) c;
302             } else if (location == 2) {
303                 closedelim[count++] = (char) c;
304             }
305         }
306     }
307
308     if (location == -1) {
309         return (ret_code);
310     }
311
312     return (-1);
313 }
314