CVE-2023-34967: mdssvc: add type checking to dalloc_value_for_key()
[samba.git] / source3 / rpc_server / mdssvc / dalloc.c
1 /*
2   Copyright (c) Ralph Boehme                    2012-2014
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 3 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "replace.h"
19 #include <talloc.h>
20 #include "dalloc.h"
21 #include "marshalling.h"
22 #include "lib/util/charset/charset.h"
23 #include "lib/util/talloc_stack.h"
24 #include "system/time.h"
25
26 /**
27  * Dynamic Datastore
28  **/
29 struct dalloc_ctx {
30         void **dd_talloc_array;
31 };
32
33 void *_dalloc_new(TALLOC_CTX *mem_ctx, const char *type)
34 {
35         void *p;
36
37         p = talloc_zero(mem_ctx, DALLOC_CTX);
38         if (p == NULL) {
39                 return NULL;
40         }
41         talloc_set_name_const(p, type);
42
43         return p;
44 }
45
46 int _dalloc_add_talloc_chunk(DALLOC_CTX *dd, void *obj, const char *type, size_t size)
47 {
48         size_t array_len = talloc_array_length(dd->dd_talloc_array);
49
50         dd->dd_talloc_array = talloc_realloc(dd,
51                                              dd->dd_talloc_array,
52                                              void *,
53                                              array_len + 1);
54         if (dd->dd_talloc_array == NULL) {
55                 return -1;
56         }
57
58         if (size != 0) {
59                 void *p;
60
61                 p = talloc_named_const(dd->dd_talloc_array, size, type);
62                 if (p == NULL) {
63                         return -1;
64                 }
65                 memcpy(p, obj, size);
66                 obj = p;
67         } else {
68                 _talloc_get_type_abort(obj, type, __location__);
69         }
70
71         dd->dd_talloc_array[array_len] = obj;
72
73         return 0;
74 }
75
76 /* Get number of elements, returns 0 if the structure is empty or not initialized */
77 size_t dalloc_size(const DALLOC_CTX *d)
78 {
79         if (d == NULL) {
80                 return 0;
81         }
82         return talloc_array_length(d->dd_talloc_array);
83 }
84
85 /* Return element at position */
86 void *dalloc_get_object(const DALLOC_CTX *d, int i)
87 {
88         size_t size = dalloc_size(d);
89
90         if (i >= size) {
91                 return NULL;
92         }
93
94         return d->dd_talloc_array[i];
95 }
96
97 /* Return typename of element at position */
98 const char *dalloc_get_name(const DALLOC_CTX *d, int i)
99 {
100         void *o = dalloc_get_object(d, i);
101
102         if (o == NULL) {
103                 return NULL;
104         }
105
106         return talloc_get_name(o);
107 }
108
109 /*
110  * Get pointer to value from a DALLOC object
111  *
112  * Returns pointer to object from a DALLOC object. Nested object interation
113  * is supported by using the type string "DALLOC_CTX". Any other type string
114  * designates the requested objects type.
115  */
116 void *dalloc_get(const DALLOC_CTX *d, ...)
117 {
118         int result = 0;
119         void *p = NULL;
120         va_list args;
121         const char *type;
122         int elem;
123
124         va_start(args, d);
125         type = va_arg(args, const char *);
126
127         while (strcmp(type, "DALLOC_CTX") == 0) {
128                 elem = va_arg(args, int);
129                 if (elem >= talloc_array_length(d->dd_talloc_array)) {
130                         result = -1;
131                         goto done;
132                 }
133                 d = d->dd_talloc_array[elem];
134                 type = va_arg(args, const char *);
135         }
136
137         elem = va_arg(args, int);
138         if (elem >= talloc_array_length(d->dd_talloc_array)) {
139                 result = -1;
140                 goto done;
141         }
142
143         p = talloc_check_name(d->dd_talloc_array[elem], type);
144         if (p == NULL) {
145                 result = -1;
146                 goto done;
147         }
148
149 done:
150         va_end(args);
151         if (result != 0) {
152                 p = NULL;
153         }
154         return p;
155 }
156
157 void *dalloc_value_for_key(const DALLOC_CTX *d, ...)
158 {
159         int result = 0;
160         void *p = NULL;
161         va_list args;
162         const char *type = NULL;
163         int elem;
164         size_t array_len;
165
166         va_start(args, d);
167         type = va_arg(args, const char *);
168
169         while (strcmp(type, "DALLOC_CTX") == 0) {
170                 array_len = talloc_array_length(d->dd_talloc_array);
171                 elem = va_arg(args, int);
172                 if (elem >= array_len) {
173                         result = -1;
174                         goto done;
175                 }
176                 d = d->dd_talloc_array[elem];
177                 type = va_arg(args, const char *);
178         }
179
180         array_len = talloc_array_length(d->dd_talloc_array);
181
182         for (elem = 0; elem + 1 < array_len; elem += 2) {
183                 if (strcmp(talloc_get_name(d->dd_talloc_array[elem]), "char *") != 0) {
184                         result = -1;
185                         goto done;
186                 }
187                 if (strcmp((char *)d->dd_talloc_array[elem],type) == 0) {
188                         p = d->dd_talloc_array[elem + 1];
189                         break;
190                 }
191         }
192         if (p == NULL) {
193                 goto done;
194         }
195
196         type = va_arg(args, const char *);
197         if (strcmp(talloc_get_name(p), type) != 0) {
198                 p = NULL;
199         }
200
201 done:
202         va_end(args);
203         if (result != 0) {
204                 p = NULL;
205         }
206         return p;
207 }
208
209 static char *dalloc_strdup(TALLOC_CTX *mem_ctx, const char *string)
210 {
211         char *p;
212
213         p = talloc_strdup(mem_ctx, string);
214         if (p == NULL) {
215                 return NULL;
216         }
217         talloc_set_name_const(p, "char *");
218         return p;
219 }
220
221 int dalloc_stradd(DALLOC_CTX *d, const char *string)
222 {
223         int result;
224         char *p;
225
226         p = dalloc_strdup(d, string);
227         if (p == NULL) {
228                 return -1;
229         }
230
231         result = dalloc_add(d, p, char *);
232         if (result != 0) {
233                 return -1;
234         }
235
236         return 0;
237 }
238
239 static char *tab_level(TALLOC_CTX *mem_ctx, int level)
240 {
241         int i;
242         char *string = talloc_array(mem_ctx, char, level + 1);
243
244         for (i = 0; i < level; i++) {
245                 string[i] = '\t';
246         }
247
248         string[i] = '\0';
249         return string;
250 }
251
252 char *dalloc_dump(DALLOC_CTX *dd, int nestinglevel)
253 {
254         const char *type;
255         int n, result;
256         uint64_t i;
257         sl_bool_t bl;
258         sl_time_t t;
259         struct tm *tm;
260         char datestring[256];
261         sl_cnids_t cnids;
262         char *logstring, *nested_logstring;
263         char *tab_string1, *tab_string2;
264         void *p;
265         bool ok;
266         char *utf8string;
267         size_t utf8len;
268
269         tab_string1 = tab_level(dd, nestinglevel);
270         if (tab_string1 == NULL) {
271                 return NULL;
272         }
273         tab_string2 = tab_level(dd, nestinglevel + 1);
274         if (tab_string2 == NULL) {
275                 return NULL;
276         }
277
278         logstring = talloc_asprintf(dd,
279                                     "%s%s(#%zu): {\n",
280                                     tab_string1,
281                                     talloc_get_name(dd),
282                                     dalloc_size(dd));
283         if (logstring == NULL) {
284                 return NULL;
285         }
286
287         for (n = 0; n < dalloc_size(dd); n++) {
288                 type = dalloc_get_name(dd, n);
289                 if (type == NULL) {
290                         return NULL;
291                 }
292                 p = dalloc_get_object(dd, n);
293                 if (p == NULL) {
294                         return NULL;
295                 }
296                 if (strcmp(type, "DALLOC_CTX") == 0
297                     || strcmp(type, "sl_array_t") == 0
298                     || strcmp(type, "sl_filemeta_t") == 0
299                     || strcmp(type, "sl_dict_t") == 0) {
300                         nested_logstring = dalloc_dump(p, nestinglevel + 1);
301                         if (nested_logstring == NULL) {
302                                 return NULL;
303                         }
304                         logstring = talloc_strdup_append(logstring,
305                                                          nested_logstring);
306                 } else if (strcmp(type, "uint64_t") == 0) {
307                         memcpy(&i, p, sizeof(uint64_t));
308                         logstring = talloc_asprintf_append(
309                                 logstring,
310                                 "%suint64_t: 0x%04jx\n",
311                                 tab_string2, (uintmax_t)i);
312                 } else if (strcmp(type, "char *") == 0) {
313                         logstring = talloc_asprintf_append(
314                                 logstring,
315                                 "%sstring: %s\n",
316                                 tab_string2,
317                                 (char *)p);
318                 } else if (strcmp(type, "smb_ucs2_t *") == 0) {
319                         ok = convert_string_talloc(talloc_tos(),
320                                                    CH_UTF16LE,
321                                                    CH_UTF8,
322                                                    p,
323                                                    talloc_get_size(p),
324                                                    &utf8string,
325                                                    &utf8len);
326                         if (!ok) {
327                                 return NULL;
328                         }
329                         logstring = talloc_asprintf_append(
330                                 logstring,
331                                 "%sUTF16-string: %s\n",
332                                 tab_string2,
333                                 utf8string);
334                         TALLOC_FREE(utf8string);
335                 } else if (strcmp(type, "sl_bool_t") == 0) {
336                         memcpy(&bl, p, sizeof(sl_bool_t));
337                         logstring = talloc_asprintf_append(
338                                 logstring,
339                                 "%sbool: %s\n",
340                                 tab_string2,
341                                 bl ? "true" : "false");
342                 } else if (strcmp(type, "sl_nil_t") == 0) {
343                         logstring = talloc_asprintf_append(
344                                 logstring,
345                                 "%snil\n",
346                                 tab_string2);
347                 } else if (strcmp(type, "sl_time_t") == 0) {
348                         memcpy(&t, p, sizeof(sl_time_t));
349                         tm = localtime(&t.tv_sec);
350                         if (tm == NULL) {
351                                 return NULL;
352                         }
353                         result = strftime(datestring,
354                                          sizeof(datestring),
355                                          "%Y-%m-%d %H:%M:%S", tm);
356                         if (result == 0) {
357                                 return NULL;
358                         }
359                         logstring = talloc_asprintf_append(
360                                 logstring,
361                                 "%ssl_time_t: %s.%06lu\n",
362                                 tab_string2,
363                                 datestring,
364                                 (unsigned long)t.tv_usec);
365                 } else if (strcmp(type, "sl_cnids_t") == 0) {
366                         memcpy(&cnids, p, sizeof(sl_cnids_t));
367                         logstring = talloc_asprintf_append(
368                                 logstring,
369                                 "%sCNIDs: unkn1: 0x%" PRIx16 ", unkn2: 0x%" PRIx32 "\n",
370                                 tab_string2,
371                                 cnids.ca_unkn1,
372                                 cnids.ca_context);
373                         if (logstring == NULL) {
374                                 return NULL;
375                         }
376                         if (cnids.ca_cnids) {
377                                 nested_logstring = dalloc_dump(
378                                         cnids.ca_cnids,
379                                         nestinglevel + 2);
380                                 if (!nested_logstring) {
381                                         return NULL;
382                                 }
383                                 logstring = talloc_strdup_append(logstring,
384                                                                  nested_logstring);
385                         }
386                 } else {
387                         logstring = talloc_asprintf_append(
388                                 logstring,
389                                 "%stype: %s\n",
390                                 tab_string2,
391                                 type);
392                 }
393                 if (logstring == NULL) {
394                         return NULL;
395                 }
396         }
397         logstring = talloc_asprintf_append(logstring,
398                                            "%s}\n",
399                                            tab_string1);
400         if (logstring == NULL) {
401                 return NULL;
402         }
403         return logstring;
404 }