]> git.meshlink.io Git - catta/blob - avahi-common/strlst.c
fix a local DoS (by hitting an assert) when passing empty TXT strings to the avahi...
[catta] / avahi-common / strlst.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <stdarg.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "strlst.h"
33 #include "malloc.h"
34 #include "defs.h"
35
36 AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) {
37     AvahiStringList *n;
38
39     if (!(n = avahi_malloc(sizeof(AvahiStringList) + size)))
40         return NULL;
41     
42     n->next = l;
43     n->size = size;
44
45     /* NUL terminate strings, just to make sure */
46     n->text[size] = 0;
47
48     return n;
49 }
50
51 AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const uint8_t*text, size_t size) {
52     AvahiStringList *n;
53
54     assert(size == 0 || text);
55
56     if (!(n = avahi_string_list_add_anonymous(l, size)))
57         return NULL;
58
59     if (size > 0)
60         memcpy(n->text, text, size);
61
62     return n;
63 }
64
65 AvahiStringList *avahi_string_list_add(AvahiStringList *l, const char *text) {
66     assert(text);
67
68     return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
69 }
70
71 int avahi_string_list_parse(const void* data, size_t size, AvahiStringList **ret) {
72     const uint8_t *c;
73     AvahiStringList *r = NULL;
74     
75     assert(data);
76     assert(ret);
77
78     c = data;
79     while (size > 0) {
80         size_t k;
81         
82         k = *(c++);
83         size--;
84
85         if (k > size)
86             goto fail; /* Overflow */
87
88         if (k > 0) { /* Ignore empty strings */
89             AvahiStringList *n;
90
91             if (!(n = avahi_string_list_add_arbitrary(r, c, k)))  
92                 goto fail; /* OOM */
93
94             r = n;
95         }
96             
97         c += k;
98         size -= k;
99     }
100
101     *ret = r;
102     
103     return 0;
104
105 fail:
106     avahi_string_list_free(r);
107     return -1;
108 }
109
110 void avahi_string_list_free(AvahiStringList *l) {
111     AvahiStringList *n;
112
113     while (l) {
114         n = l->next;
115         avahi_free(l);
116         l = n;
117     }
118 }
119
120 AvahiStringList* avahi_string_list_reverse(AvahiStringList *l) {
121     AvahiStringList *r = NULL, *n;
122
123     while (l) {
124         n = l->next;
125         l->next = r;
126         r = l;
127         l = n;
128     }
129
130     return r;
131 }
132
133 char* avahi_string_list_to_string(AvahiStringList *l) {
134     AvahiStringList *n;
135     size_t s = 0;
136     char *t, *e;
137
138     for (n = l; n; n = n->next) {
139         if (n != l)
140             s ++;
141
142         s += n->size+2;
143     }
144
145     if (!(t = e = avahi_new(char, s+1)))
146         return NULL;
147
148     l = avahi_string_list_reverse(l);
149     
150     for (n = l; n; n = n->next) {
151         if (n != l)
152             *(e++) = ' ';
153
154         *(e++) = '"';
155         strncpy(e, (char*) n->text, n->size);
156         e[n->size] = 0;
157         e = strchr(e, 0);
158         *(e++) = '"';
159
160         assert(e);
161     }
162
163     l = avahi_string_list_reverse(l);
164     
165     *e = 0;
166
167     return t;
168 }
169
170 size_t avahi_string_list_serialize(AvahiStringList *l, void *data, size_t size) {
171     size_t used = 0;
172
173     if (data) {
174         AvahiStringList *n;
175         uint8_t *c;
176
177         l = avahi_string_list_reverse(l);
178         c = data;
179         
180         for (n = l; size > 1 && n; n = n->next) {
181             size_t k;
182
183             if ((k = n->size) == 0)
184                 /* Skip empty strings */
185                 continue;
186             
187             if (k > 255)
188                 /* Truncate strings at 255 characters */
189                 k = 255;
190             
191             if (k > size-1)
192                 /* Make sure this string fits in */
193                 k = size-1;
194
195             *(c++) = (uint8_t) k;
196             memcpy(c, n->text, k);
197             c += k;
198             
199             used += 1 + k;
200             size -= 1 + k;
201         }
202         
203         l = avahi_string_list_reverse(l);
204
205         if (used == 0 && size > 0) {
206         
207             /* Empty lists are treated specially. To comply with
208              * section 6.1 of the DNS-SD spec, we return a single
209              * empty string (i.e. a NUL byte)*/
210
211             *(uint8_t*) data = 0;
212             used = 1;
213         }
214             
215     } else {
216         AvahiStringList *n;
217
218         for (n = l; n; n = n->next) {
219             size_t k;
220             
221             if ((k = n->size) == 0)
222                 continue;
223             
224             if (k > 255)
225                 k = 255;
226             
227             used += 1+k;
228         }
229
230         if (used == 0)
231             used = 1;
232     }
233
234     return used;
235 }
236
237 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
238
239     for (;;) {
240         if (!a && !b)
241             return 1;
242
243         if (!a || !b)
244             return 0;
245
246         if (a->size != b->size)
247             return 0;
248
249         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
250             return 0;
251
252         a = a->next;
253         b = b->next;
254     }
255 }
256
257 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
258     va_list va;
259
260     va_start(va, r);
261     r = avahi_string_list_add_many_va(r, va);
262     va_end(va);
263     
264     return r;
265 }
266
267 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
268     const char *txt;
269
270     while ((txt = va_arg(va, const char*)))
271         r = avahi_string_list_add(r, txt);
272
273     return r;
274 }
275
276 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
277     va_list va;
278     AvahiStringList *r = NULL;
279
280     if (txt) {
281         r = avahi_string_list_add(r, txt);
282
283         va_start(va, txt);
284         r = avahi_string_list_add_many_va(r, va);
285         va_end(va);
286     }
287
288     return r;
289 }
290
291 AvahiStringList *avahi_string_list_new_va(va_list va) {
292     return avahi_string_list_add_many_va(NULL, va);
293 }
294
295 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
296     AvahiStringList *r = NULL;
297
298     for (; l; l = l->next)
299         if (!(r = avahi_string_list_add_arbitrary(r, l->text, l->size))) {
300             avahi_string_list_free(r);
301             return NULL;
302         }
303
304     return avahi_string_list_reverse(r);
305 }
306
307 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
308     AvahiStringList *r = NULL;
309     int i;
310
311     assert(array);
312
313     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
314         r = avahi_string_list_add(r, array[i]);
315
316     return r;
317 }
318
319 unsigned avahi_string_list_length(const AvahiStringList *l) {
320     unsigned n = 0;
321
322     for (; l; l = l->next)
323         n++;
324
325     return n;
326 }
327
328 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
329     size_t len = 80;
330     AvahiStringList *r;
331     
332     assert(format);
333
334     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
335         return NULL;
336
337     for (;;) {
338         int n;
339         AvahiStringList *nr;
340         
341         n = vsnprintf((char*) r->text, len+1, format, va);
342
343         if (n >= 0 && n < (int) len)
344             break;
345
346         if (n >= 0)
347             len = n+1;
348         else
349             len *= 2;
350
351         if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
352             avahi_free(r);
353             return NULL;
354         }
355
356         r = nr;
357     }
358
359     
360     r->next = l;
361     r->size = strlen((char*) r->text); 
362
363     return r;
364 }
365
366 AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
367     va_list va;
368     
369     assert(format);
370
371     va_start(va, format);
372     l  = avahi_string_list_add_vprintf(l, format, va);
373     va_end(va);
374
375     return l;    
376 }
377
378 AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
379     size_t n;
380     
381     assert(key);
382     n = strlen(key);
383
384     for (; l; l = l->next) {
385         if (strcasecmp((char*) l->text, key) == 0)
386             return l;
387
388         if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
389             return l;
390     }
391
392     return NULL;
393 }
394
395 AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
396     assert(key);
397
398     if (value)
399         return avahi_string_list_add_printf(l, "%s=%s", key, value);
400     else
401         return avahi_string_list_add(l, key);
402 }
403
404 AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
405     size_t n;
406     assert(key);
407
408     if (!value)
409         return avahi_string_list_add(l, key);
410
411     n = strlen(key);
412     
413     if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
414         return NULL;
415
416     memcpy(l->text, key, n);
417     l->text[n] = '=';
418     memcpy(l->text + n + 1, value, size);
419
420     return l;
421 }
422
423 int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
424     char *e;
425     
426     assert(l);
427
428     if (!(e = memchr(l->text, '=', l->size))) {
429
430         if (key) 
431             if (!(*key = avahi_strdup((char*) l->text)))
432                 return -1;
433
434         if (value)
435             *value = NULL;
436
437         if (size)
438             *size = 0;
439
440     } else {
441         size_t n;
442
443         if (key)
444             if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
445                 return -1;
446
447         e++; /* Advance after '=' */
448         
449         n = l->size - (e - (char*) l->text);
450         
451         if (value) {
452
453             if (!(*value = avahi_memdup(e, n+1))) {
454                 if (key)
455                     avahi_free(*key);
456                 return -1;
457             }
458
459             (*value)[n] = 0;
460         }
461
462         if (size)
463             *size = n;
464     }
465
466     return 0;
467 }
468
469 AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
470     assert(l);
471     return l->next;
472 }
473
474 uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
475     assert(l);
476     return l->text;
477 }
478
479 size_t avahi_string_list_get_size(AvahiStringList *l) {
480     assert(l);
481     return l->size;
482 }
483
484 uint32_t avahi_string_list_get_service_cookie(AvahiStringList *l) {
485     AvahiStringList *f;
486     char *value = NULL, *end = NULL;
487     uint32_t ret;
488     
489     if (!(f = avahi_string_list_find(l, AVAHI_SERVICE_COOKIE)))
490         return AVAHI_SERVICE_COOKIE_INVALID;
491
492     if (avahi_string_list_get_pair(f, NULL, &value, NULL) < 0 || !value)
493         return AVAHI_SERVICE_COOKIE_INVALID;
494
495     ret = (uint32_t) strtoll(value, &end, 0);
496
497     if (*value && end && *end != 0) {
498         avahi_free(value);
499         return AVAHI_SERVICE_COOKIE_INVALID;
500     }
501
502     avahi_free(value);
503     
504     return ret;
505 }