source: trunk/libtransmission/variant-benc.c @ 14241

Last change on this file since 14241 was 14241, checked in by jordan, 8 years ago

Copyedit the license's revised text: (1) remove unnecessary repitition use of the word 'license' from the top of the header and source files (2) add the standard 'we hope it's useful, but no warranty' clause to COPYING (3) make explicit that linking OpenSSL is allowed (see https://people.gnome.org/~markmc/openssl-and-the-gpl.html for background) (4) sync the Qt and GTK+ clients' license popups with COPYING's revised text

  • Property svn:keywords set to Date Rev Author Id
File size: 7.7 KB
Line 
1/*
2 * This file Copyright (C) 2008-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: variant-benc.c 14241 2014-01-21 03:10:30Z jordan $
8 */
9
10#include <assert.h>
11#include <ctype.h> /* isdigit() */
12#include <errno.h>
13#include <stdlib.h> /* strtoul() */
14#include <string.h> /* strlen(), memchr() */
15
16#include <event2/buffer.h>
17
18#include "ConvertUTF.h"
19
20#define __LIBTRANSMISSION_VARIANT_MODULE___
21#include "transmission.h"
22#include "ptrarray.h"
23#include "utils.h" /* tr_snprintf() */
24#include "variant.h"
25#include "variant-common.h"
26
27/***
28****  tr_variantParse()
29****  tr_variantLoad()
30***/
31
32/**
33 * The initial i and trailing e are beginning and ending delimiters.
34 * You can have negative numbers such as i-3e. You cannot prefix the
35 * number with a zero such as i04e. However, i0e is valid.
36 * Example: i3e represents the integer "3"
37 * NOTE: The maximum number of bit of this integer is unspecified,
38 * but to handle it as a signed 64bit integer is mandatory to handle
39 * "large files" aka .torrent for more that 4Gbyte
40 */
41int
42tr_bencParseInt (const uint8_t  * buf,
43                 const uint8_t  * bufend,
44                 const uint8_t ** setme_end,
45                 int64_t        * setme_val)
46{
47  char * endptr;
48  const void * begin;
49  const void * end;
50  int64_t val;
51
52  if (buf >= bufend)
53    return EILSEQ;
54  if (*buf != 'i')
55    return EILSEQ;
56
57  begin = buf + 1;
58  end = memchr (begin, 'e', (bufend - buf) - 1);
59  if (end == NULL)
60    return EILSEQ;
61
62  errno = 0;
63  val = evutil_strtoll (begin, &endptr, 10);
64  if (errno || (endptr != end)) /* incomplete parse */
65    return EILSEQ;
66  if (val && * (const char*)begin == '0') /* no leading zeroes! */
67    return EILSEQ;
68
69  *setme_end = (const uint8_t*)end + 1;
70  *setme_val = val;
71  return 0;
72}
73
74/**
75 * Byte strings are encoded as follows:
76 * <string length encoded in base ten ASCII>:<string data>
77 * Note that there is no constant beginning delimiter, and no ending delimiter.
78 * Example: 4:spam represents the string "spam"
79 */
80int
81tr_bencParseStr (const uint8_t  * buf,
82                 const uint8_t  * bufend,
83                 const uint8_t ** setme_end,
84                 const uint8_t ** setme_str,
85                 size_t *         setme_strlen)
86{
87  size_t len;
88  const void * end;
89  char * endptr;
90
91  if (buf >= bufend)
92    return EILSEQ;
93
94  if (!isdigit (*buf))
95    return EILSEQ;
96
97  end = memchr (buf, ':', bufend - buf);
98  if (end == NULL)
99    return EILSEQ;
100
101  errno = 0;
102  len = strtoul ((const char*)buf, &endptr, 10);
103  if (errno || endptr != end)
104    return EILSEQ;
105
106  if ((const uint8_t*)end + 1 + len > bufend)
107    return EILSEQ;
108
109  *setme_end = (const uint8_t*)end + 1 + len;
110  *setme_str = (const uint8_t*)end + 1;
111  *setme_strlen = len;
112  return 0;
113}
114
115static tr_variant*
116get_node (tr_ptrArray * stack, tr_quark * key, tr_variant * top, int * err)
117{
118  tr_variant * node = NULL;
119
120  if (tr_ptrArrayEmpty (stack))
121    {
122      node = top;
123    }
124  else
125    {
126      tr_variant * parent = tr_ptrArrayBack (stack);
127
128      if (tr_variantIsList (parent))
129        {
130          node = tr_variantListAdd (parent);
131        }
132      else if (*key && tr_variantIsDict (parent))
133        {
134          node = tr_variantDictAdd (parent, *key);
135          *key = 0;
136        }
137      else
138        {
139          *err = EILSEQ;
140        }
141    }
142
143  return node;
144}
145
146/**
147 * This function's previous recursive implementation was
148 * easier to read, but was vulnerable to a smash-stacking
149 * attack via maliciously-crafted bencoded data. (#667)
150 */
151int
152tr_variantParseBenc (const void    * buf_in,
153                     const void    * bufend_in,
154                     tr_variant    * top,
155                     const char   ** setme_end)
156{
157  int err = 0;
158  const uint8_t * buf = buf_in;
159  const uint8_t * bufend = bufend_in;
160  tr_ptrArray stack = TR_PTR_ARRAY_INIT;
161  tr_quark key = 0;
162
163  tr_variantInit (top, 0);
164
165  while (buf != bufend)
166    {
167      if (buf > bufend) /* no more text to parse... */
168        err = EILSEQ;
169
170      if (err)
171        break;
172
173      if (*buf == 'i') /* int */
174        {
175          int64_t val;
176          const uint8_t * end;
177          tr_variant * v;
178
179          if ((err = tr_bencParseInt (buf, bufend, &end, &val)))
180            break;
181          buf = end;
182
183          if ((v = get_node (&stack, &key, top, &err)))
184            tr_variantInitInt (v, val);
185        }
186      else if (*buf == 'l') /* list */
187        {
188          tr_variant * v;
189
190          ++buf;
191
192          if ((v = get_node (&stack, &key, top, &err)))
193            {
194              tr_variantInitList (v, 0);
195              tr_ptrArrayAppend (&stack, v);
196            }
197        }
198      else if (*buf == 'd') /* dict */
199        {
200          tr_variant * v;
201
202          ++buf;
203
204          if ((v = get_node (&stack, &key, top, &err)))
205            {
206              tr_variantInitDict (v, 0);
207              tr_ptrArrayAppend (&stack, v);
208            }
209        }
210      else if (*buf == 'e') /* end of list or dict */
211        {
212          ++buf;
213
214          if (tr_ptrArrayEmpty (&stack) || (key != 0))
215            {
216              err = EILSEQ;
217              break;
218            }
219          else
220            {
221              tr_ptrArrayPop (&stack);
222              if (tr_ptrArrayEmpty (&stack))
223                break;
224            }
225        }
226      else if (isdigit (*buf)) /* string? */
227        {
228          tr_variant * v;
229          const uint8_t * end;
230          const uint8_t * str;
231          size_t str_len;
232
233          if ((err = tr_bencParseStr (buf, bufend, &end, &str, &str_len)))
234            break;
235          buf = end;
236
237          if (!key && !tr_ptrArrayEmpty(&stack) && tr_variantIsDict(tr_ptrArrayBack(&stack)))
238            key = tr_quark_new (str, str_len);
239          else if ((v = get_node (&stack, &key, top, &err)))
240            tr_variantInitStr (v, str, str_len);
241        }
242      else /* invalid bencoded text... march past it */
243        {
244          ++buf;
245        }
246
247      if (tr_ptrArrayEmpty (&stack))
248        break;
249    }
250
251  if (!err)
252    err = !top->type || !tr_ptrArrayEmpty(&stack);
253
254  if (!err && setme_end)
255    *setme_end = (const char*) buf;
256
257  tr_ptrArrayDestruct (&stack, NULL);
258  return err;
259}
260
261/****
262*****
263****/
264
265static void
266saveIntFunc (const tr_variant * val, void * evbuf)
267{
268  evbuffer_add_printf (evbuf, "i%" PRId64 "e", val->val.i);
269}
270
271static void
272saveBoolFunc (const tr_variant * val, void * evbuf)
273{
274  if (val->val.b)
275    evbuffer_add (evbuf, "i1e", 3);
276  else
277    evbuffer_add (evbuf, "i0e", 3);
278}
279
280static void
281saveRealFunc (const tr_variant * val, void * evbuf)
282{
283  int len;
284  char buf[128];
285
286  len = tr_snprintf (buf, sizeof (buf), "%f", val->val.d);
287  evbuffer_add_printf (evbuf, "%d:", len);
288  evbuffer_add (evbuf, buf, len);
289}
290
291static void
292saveStringFunc (const tr_variant * v, void * evbuf)
293{
294  size_t len;
295  const char * str;
296  tr_variantGetStr (v, &str, &len);
297  evbuffer_add_printf (evbuf, "%"TR_PRIuSIZE":", len);
298  evbuffer_add (evbuf, str, len);
299}
300
301static void
302saveDictBeginFunc (const tr_variant * val UNUSED, void * evbuf)
303{
304  evbuffer_add (evbuf, "d", 1);
305}
306
307static void
308saveListBeginFunc (const tr_variant * val UNUSED, void * evbuf)
309{
310  evbuffer_add (evbuf, "l", 1);
311}
312
313static void
314saveContainerEndFunc (const tr_variant * val UNUSED, void * evbuf)
315{
316  evbuffer_add (evbuf, "e", 1);
317}
318
319static const struct VariantWalkFuncs walk_funcs = { saveIntFunc,
320                                                    saveBoolFunc,
321                                                    saveRealFunc,
322                                                    saveStringFunc,
323                                                    saveDictBeginFunc,
324                                                    saveListBeginFunc,
325                                                    saveContainerEndFunc };
326
327void
328tr_variantToBufBenc (const tr_variant * top, struct evbuffer * buf)
329{
330  tr_variantWalk (top, &walk_funcs, buf, true);
331}
332
Note: See TracBrowser for help on using the repository browser.