new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_xml / os_xml_access.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 #include <stdlib.h>
13
14 #include "os_xml.h"
15 #include "os_xml_internal.h"
16
17 /* Prototypes */
18 static char **_GetElements(const OS_XML *_lxml, const char **element_name, XML_TYPE type) __attribute__((nonnull(1)));
19 static char **_GetElementContent(OS_XML *_lxml, const char **element_name, const char *attr) __attribute__((nonnull(1, 2)));
20
21
22 /* Check if a element exists
23  * The element_name must be NULL terminated (last char)
24  */
25 unsigned int OS_ElementExist(const OS_XML *_lxml, const char **element_name)
26 {
27     unsigned int i = 0, j = 0, matched = 0, totalmatch = 0;
28
29     if (element_name[0] == NULL) {
30         return (0);
31     }
32
33     for (i = 0, j = 0; i < _lxml->cur; i++) {
34         if (element_name[j] == NULL) {
35             j = 0;
36         }
37         if ((_lxml->tp[i] == XML_ELEM) && (_lxml->rl[i] == j)) {
38             if (strcmp(_lxml->el[i], element_name[j]) == 0) {
39                 j++;
40                 matched = 1;
41                 if (element_name[j] == NULL) {
42                     j = 0;
43                     totalmatch++;
44                 }
45                 continue;
46             }
47         }
48         if ((matched == 1) && (j > _lxml->rl[i]) &&
49                 (_lxml->tp[i] == XML_ELEM)) {
50             j = 0;
51             matched = 0;
52         }
53     }
54     return (totalmatch);
55 }
56
57 /* Check if a root element exists */
58 unsigned int OS_RootElementExist(const OS_XML *_lxml, const char *element_name)
59 {
60     const char *(elements[]) = {element_name, NULL};
61     return (OS_ElementExist(_lxml, elements));
62 }
63
64 /* Get the attributes of the element_name */
65 char **OS_GetAttributes(const OS_XML *_lxml, const char **element_name)
66 {
67     return (_GetElements(_lxml, element_name, XML_ATTR));
68 }
69
70 /* Get the elements children of the element_name */
71 char **OS_GetElements(const OS_XML *_lxml, const char **element_name)
72 {
73     return (_GetElements(_lxml, element_name, XML_ELEM));
74 }
75
76 /* Get the elements or attributes (internal use) */
77 static char **_GetElements(const OS_XML *_lxml, const char **element_name, XML_TYPE type)
78 {
79     unsigned i = 0, j = 0, k = 0, matched = 0, ready = 0;
80     char **ret = NULL;
81     char **ret_tmp = NULL;
82
83     if ((type == XML_ELEM) && (element_name == NULL)) {
84         ready = 1;
85     }
86
87     for (i = 0, j = 0; i < _lxml->cur; i++) {
88         if ((ready != 1) && (element_name[j] == NULL)) {
89             if (matched == 1) {
90                 ready = 1;
91             } else {
92                 break;
93             }
94         }
95
96         if (j > 16) {
97             return (ret);
98         }
99
100         if ((ready == 1) && (_lxml->tp[i] == type)) {
101             if (((type == XML_ATTR) && (_lxml->rl[i] == j - 1)
102                     && (_lxml->el[i] != NULL)) ||
103                     ((type == XML_ELEM) && (_lxml->rl[i] == j) &&
104                      (_lxml->el[i] != NULL))) {
105                 size_t el_size = strlen(_lxml->el[i]) + 1;
106                 ret_tmp = (char **)realloc(ret, (k + 2) * sizeof(char *));
107                 if (ret_tmp == NULL) {
108                     goto fail;
109                 }
110                 ret = ret_tmp;
111                 ret[k + 1] = NULL;
112                 ret[k] = (char *)calloc(el_size, sizeof(char));
113                 if (ret[k] == NULL) {
114                     goto fail;
115                 }
116                 strncpy(ret[k], _lxml->el[i], el_size - 1);
117                 k++;
118             }
119         }
120
121         else if ((_lxml->tp[i] == XML_ELEM) && (_lxml->rl[i] == j) &&
122                  (element_name[j] != NULL)) {
123             if (strcmp(_lxml->el[i], element_name[j]) == 0) {
124                 j++;
125                 matched = 1;
126                 continue;
127             }
128         }
129
130         if (matched == 1) {
131             if (((_lxml->tp[i] == XML_ATTR) && (j > _lxml->rl[i] + 1)) ||
132                     ((_lxml->tp[i] == XML_ELEM) && (j > _lxml->rl[i]))) {
133                 j = 0;
134                 matched = 0;
135                 if (element_name == NULL) {
136                     ready = 1;
137                 } else {
138                     ready = 0;
139                 }
140             }
141         }
142     }
143
144     return (ret);
145
146 fail:
147     i = 0;
148     if (ret) {
149         while (ret[i]) {
150             free(ret[i++]);
151         }
152         free(ret);
153     }
154     return (NULL);
155 }
156
157 /* Get one value for a specific element */
158 char *OS_GetOneContentforElement(OS_XML *_lxml, const char **element_name)
159 {
160     int i = 1;
161     char *uniqret = NULL;
162     char **ret = NULL;
163
164     _lxml->fol = 0;
165     ret = _GetElementContent(_lxml, element_name, NULL);
166     if (ret == NULL) {
167         return (NULL);
168     }
169
170     if (ret[0] != NULL) {
171         uniqret = ret[0];
172     }
173
174     /* Free memory */
175     while (ret[i]) {
176         free(ret[i]);
177         ret[i] = NULL;
178         i++;
179     }
180     free(ret);
181
182     return (uniqret);
183 }
184
185 /* Get all values for a specific element */
186 char **OS_GetElementContent(OS_XML *_lxml, const char **element_name)
187 {
188     _lxml->fol = 0;
189     return (_GetElementContent(_lxml, element_name, NULL));
190 }
191
192 /* Get the contents for a specific element
193  * Use element_name = NULL to start the state
194  */
195 char **OS_GetContents(OS_XML *_lxml, const char **element_name)
196 {
197     if (element_name == NULL) {
198         _lxml->fol = -1;
199         return (NULL);
200     }
201     return (_GetElementContent(_lxml, element_name, NULL));
202 }
203
204 /* Get one value for a specific attribute */
205 char *OS_GetAttributeContent(OS_XML *_lxml, const char **element_name,
206                              const char *attribute_name)
207 {
208     char *uniqret = NULL;
209     char **ret = NULL;
210
211     _lxml->fol = 0;
212
213     ret = _GetElementContent(_lxml, element_name, attribute_name);
214     if (ret == NULL) {
215         return (NULL);
216     }
217     if (ret[0] != NULL) {
218         uniqret = ret[0];
219     }
220
221     int i = 1;
222     while (ret[i] != NULL) {
223         free(ret[i++]);
224     }
225     free(ret);
226
227     return (uniqret);
228 }
229
230 /* Get the values for an element or attribute */
231 static char **_GetElementContent(OS_XML *_lxml, const char **element_name, const char *attr)
232 {
233     int i = 0;
234     unsigned int j = 0, k = 0, l = 0, matched = 0;
235     char **ret = NULL;
236     char **ret_tmp;
237
238     if (_lxml->fol >= 0 && (unsigned int)_lxml->fol == _lxml->cur) {
239         _lxml->fol = 0;
240         return (NULL);
241     }
242
243     if (_lxml->fol > 0) {
244         for (i = _lxml->fol; i >= 0; i--) {
245             _lxml->fol = i;
246             if (_lxml->rl[i] == 0) {
247                 break;
248             }
249         }
250         i = _lxml->fol;
251     } else {
252         i = 0;
253     }
254
255     /* Loop over all nodes */
256     for (j = 0, l = (unsigned int)i; l < _lxml->cur; l++) {
257         if (element_name[j] == NULL) {
258             if (matched != 1) {
259                 break;
260             }
261         }
262
263         /* Set maximum depth of 16 */
264         if (j > 16) {
265             goto fail;
266         }
267
268         /* If the type is not an element and the relation doesn't match,
269          * keep going
270          */
271         if ((_lxml->tp[l] != XML_ELEM) || (_lxml->rl[l] != j)) {
272             /* If the node relation is higher than the current xml
273              * node, zero the position and look at it again (i--).
274              */
275             if (j > _lxml->rl[l]) {
276                 j = 0;
277                 matched = 0;
278                 l--;
279             } else {
280                 continue;
281             }
282         }
283
284         /* If the element name matches what we are looking for */
285         else if (element_name[j] != NULL && strcmp(_lxml->el[l], element_name[j]) == 0) {
286             j++;
287             matched = 1;
288
289             /* Get content if we are at the end of the array */
290             if (element_name[j] == NULL) {
291                 /* If we have an attribute to match */
292                 if (attr != NULL) {
293                     unsigned int m = 0;
294                     for (m = l + 1; m < _lxml->cur; m++) {
295                         if (_lxml->tp[m] == XML_ELEM) {
296                             break;
297                         }
298
299                         if (strcmp(attr, _lxml->el[m]) == 0) {
300                             l = m;
301                             break;
302                         }
303                     }
304                 }
305
306                 if (_lxml->ct[l] != NULL) {
307                     /* Increase the size of the array */
308                     ret_tmp = (char **) realloc(ret, (k + 2) * sizeof(char *));
309                     if (ret_tmp == NULL) {
310                         goto fail;
311                     }
312                     ret = ret_tmp;
313
314                     /* Add new entry */
315                     ret[k] = strdup(_lxml->ct[l]);
316                     ret[k + 1] = NULL;
317                     if (ret[k] == NULL) {
318                         goto fail;
319                     }
320
321                     matched = 1;
322                     k++;
323
324                     if (attr != NULL) {
325                         break;
326                     }
327
328                     else if (_lxml->fol != 0) {
329                         _lxml->fol = (int) l + 1;
330                         break;
331                     }
332                 }
333
334                 /* Set new array pointer */
335                 if ((l < _lxml->cur - 1) && (_lxml->tp[l + 1] == XML_ELEM)) {
336                     j = _lxml->rl[l + 1];
337                 }
338             }
339             continue;
340         }
341
342         if (j > _lxml->rl[l]) {
343             j = 0;
344             matched = 0;
345         }
346     }
347
348     return (ret);
349
350 fail:
351     i = 0;
352     if (ret) {
353         while (ret[i]) {
354             free(ret[i++]);
355         }
356         free(ret);
357     }
358     return (NULL);
359 }
360