1 /*
2  * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "../burp.h"
18 #include "api/yajl_parse.h"
19 #include "yajl_lex.h"
20 #include "yajl_parser.h"
21 #include "yajl_encode.h"
22 #include "yajl_bytestack.h"
23 
24 #include <stdlib.h>
25 #include <limits.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <assert.h>
31 #include <math.h>
32 
33 #define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10))
34 
35  /* same semantics as strtol */
36 long long
yajl_parse_integer(const unsigned char * number,unsigned int length)37 yajl_parse_integer(const unsigned char *number, unsigned int length)
38 {
39     long long ret  = 0;
40     long sign = 1;
41     const unsigned char *pos = number;
42     if (*pos == '-') { pos++; sign = -1; }
43     if (*pos == '+') { pos++; }
44 
45     while (pos < number + length) {
46         if ( ret > MAX_VALUE_TO_MULTIPLY ) {
47             errno = ERANGE;
48             return sign == 1 ? LLONG_MAX : LLONG_MIN;
49         }
50         ret *= 10;
51         if (LLONG_MAX - ret < (*pos - '0')) {
52             errno = ERANGE;
53             return sign == 1 ? LLONG_MAX : LLONG_MIN;
54         }
55         if (*pos < '0' || *pos > '9') {
56             errno = ERANGE;
57             return sign == 1 ? LLONG_MAX : LLONG_MIN;
58         }
59         ret += (*pos++ - '0');
60     }
61 
62     return sign * ret;
63 }
64 
65 unsigned char *
yajl_render_error_string(yajl_handle hand,const unsigned char * jsonText,size_t jsonTextLen,int verbose)66 yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
67                          size_t jsonTextLen, int verbose)
68 {
69     size_t offset = hand->bytesConsumed;
70     unsigned char * str;
71     const char * errorType = NULL;
72     const char * errorText = NULL;
73     char text[72];
74     const char * arrow = "                     (right here) ------^\n";
75 
76     if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) {
77         errorType = "parse";
78         errorText = hand->parseError;
79     } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) {
80         errorType = "lexical";
81         errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer));
82     } else {
83         errorType = "unknown";
84     }
85 
86     {
87         size_t memneeded = 0;
88         memneeded += strlen(errorType);
89         memneeded += strlen(" error");
90         if (errorText != NULL) {
91             memneeded += strlen(": ");
92             memneeded += strlen(errorText);
93         }
94         str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2);
95         if (!str) return NULL;
96         str[0] = 0;
97         strcat((char *) str, errorType);
98         strcat((char *) str, " error");
99         if (errorText != NULL) {
100             strcat((char *) str, ": ");
101             strcat((char *) str, errorText);
102         }
103         strcat((char *) str, "\n");
104     }
105 
106     /* now we append as many spaces as needed to make sure the error
107      * falls at char 41, if verbose was specified */
108     if (verbose) {
109         size_t start, end, i;
110         size_t spacesNeeded;
111 
112         spacesNeeded = (offset < 30 ? 40 - offset : 10);
113         start = (offset >= 30 ? offset - 30 : 0);
114         end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30);
115 
116         for (i=0;i<spacesNeeded;i++) text[i] = ' ';
117 
118         for (;start < end;start++, i++) {
119             if (jsonText[start] != '\n' && jsonText[start] != '\r')
120             {
121                 text[i] = jsonText[start];
122             }
123             else
124             {
125                 text[i] = ' ';
126             }
127         }
128         assert(i <= 71);
129         text[i++] = '\n';
130         text[i] = 0;
131         {
132             char * newStr = (char *)
133                 YA_MALLOC(&(hand->alloc), (unsigned int)(strlen((char *) str) +
134                                                          strlen((char *) text) +
135                                                          strlen(arrow) + 1));
136             if (newStr) {
137                 newStr[0] = 0;
138                 strcat((char *) newStr, (char *) str);
139                 strcat((char *) newStr, text);
140                 strcat((char *) newStr, arrow);
141             }
142             YA_FREE(&(hand->alloc), str);
143             str = (unsigned char *) newStr;
144         }
145     }
146     return str;
147 }
148 
149 /* check for client cancelation */
150 #define _CC_CHK(x)                                                \
151     if (!(x)) {                                                   \
152         yajl_bs_set(hand->stateStack, yajl_state_parse_error);    \
153         hand->parseError =                                        \
154             "client cancelled parse via callback return value";   \
155         return yajl_status_client_canceled;                       \
156     }
157 
158 
159 yajl_status
yajl_do_finish(yajl_handle hand)160 yajl_do_finish(yajl_handle hand)
161 {
162     yajl_status stat;
163     stat = yajl_do_parse(hand,(const unsigned char *) " ",1);
164 
165     if (stat != yajl_status_ok) return stat;
166 
167     switch(yajl_bs_current(hand->stateStack))
168     {
169         case yajl_state_parse_error:
170         case yajl_state_lexical_error:
171             return yajl_status_error;
172         case yajl_state_got_value:
173         case yajl_state_parse_complete:
174             return yajl_status_ok;
175         default:
176             if (!(hand->flags & yajl_allow_partial_values))
177             {
178                 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
179                 hand->parseError = "premature EOF";
180                 return yajl_status_error;
181             }
182             return yajl_status_ok;
183     }
184 }
185 
186 yajl_status
yajl_do_parse(yajl_handle hand,const unsigned char * jsonText,size_t jsonTextLen)187 yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
188               size_t jsonTextLen)
189 {
190     yajl_tok tok;
191     const unsigned char * buf;
192     size_t bufLen;
193     size_t * offset = &(hand->bytesConsumed);
194 
195     *offset = 0;
196 
197   around_again:
198     switch (yajl_bs_current(hand->stateStack)) {
199         case yajl_state_parse_complete:
200             if (hand->flags & yajl_allow_multiple_values) {
201                 yajl_bs_set(hand->stateStack, yajl_state_got_value);
202                 goto around_again;
203             }
204             if (!(hand->flags & yajl_allow_trailing_garbage)) {
205                 if (*offset != jsonTextLen) {
206                     tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
207                                        offset, &buf, &bufLen);
208                     if (tok != yajl_tok_eof) {
209                         yajl_bs_set(hand->stateStack, yajl_state_parse_error);
210                         hand->parseError = "trailing garbage";
211                     }
212                     goto around_again;
213                 }
214             }
215             return yajl_status_ok;
216         case yajl_state_lexical_error:
217         case yajl_state_parse_error:
218             return yajl_status_error;
219         case yajl_state_start:
220         case yajl_state_got_value:
221         case yajl_state_map_need_val:
222         case yajl_state_array_need_val:
223         case yajl_state_array_start:  {
224             /* for arrays and maps, we advance the state for this
225              * depth, then push the state of the next depth.
226              * If an error occurs during the parsing of the nesting
227              * enitity, the state at this level will not matter.
228              * a state that needs pushing will be anything other
229              * than state_start */
230 
231             yajl_state stateToPush = yajl_state_start;
232 
233             tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
234                                offset, &buf, &bufLen);
235 
236             switch (tok) {
237                 case yajl_tok_eof:
238                     return yajl_status_ok;
239                 case yajl_tok_error:
240                     yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
241                     goto around_again;
242                 case yajl_tok_string:
243                     if (hand->callbacks && hand->callbacks->yajl_string) {
244                         _CC_CHK(hand->callbacks->yajl_string(hand->ctx,
245                                                              buf, bufLen));
246                     }
247                     break;
248                 case yajl_tok_string_with_escapes:
249                     if (hand->callbacks && hand->callbacks->yajl_string) {
250                         yajl_buf_clear(hand->decodeBuf);
251                         yajl_string_decode(hand->decodeBuf, buf, bufLen);
252                         _CC_CHK(hand->callbacks->yajl_string(
253                                     hand->ctx, yajl_buf_data(hand->decodeBuf),
254                                     yajl_buf_len(hand->decodeBuf)));
255                     }
256                     break;
257                 case yajl_tok_bool:
258                     if (hand->callbacks && hand->callbacks->yajl_boolean) {
259                         _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx,
260                                                               *buf == 't'));
261                     }
262                     break;
263                 case yajl_tok_null:
264                     if (hand->callbacks && hand->callbacks->yajl_null) {
265                         _CC_CHK(hand->callbacks->yajl_null(hand->ctx));
266                     }
267                     break;
268                 case yajl_tok_left_bracket:
269                     if (hand->callbacks && hand->callbacks->yajl_start_map) {
270                         _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx));
271                     }
272                     stateToPush = yajl_state_map_start;
273                     break;
274                 case yajl_tok_left_brace:
275                     if (hand->callbacks && hand->callbacks->yajl_start_array) {
276                         _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx));
277                     }
278                     stateToPush = yajl_state_array_start;
279                     break;
280                 case yajl_tok_integer:
281                     if (hand->callbacks) {
282                         if (hand->callbacks->yajl_number) {
283                             _CC_CHK(hand->callbacks->yajl_number(
284                                         hand->ctx,(const char *) buf, bufLen));
285                         } else if (hand->callbacks->yajl_integer) {
286                             long long int i = 0;
287                             errno = 0;
288                             i = yajl_parse_integer(buf, bufLen);
289                             if ((i == LLONG_MIN || i == LLONG_MAX) &&
290                                 errno == ERANGE)
291                             {
292                                 yajl_bs_set(hand->stateStack,
293                                             yajl_state_parse_error);
294                                 hand->parseError = "integer overflow" ;
295                                 /* try to restore error offset */
296                                 if (*offset >= bufLen) *offset -= bufLen;
297                                 else *offset = 0;
298                                 goto around_again;
299                             }
300                             _CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
301                                                                   i));
302                         }
303                     }
304                     break;
305                 case yajl_tok_double:
306                     if (hand->callbacks) {
307                         if (hand->callbacks->yajl_number) {
308                             _CC_CHK(hand->callbacks->yajl_number(
309                                         hand->ctx, (const char *) buf, bufLen));
310                         } else if (hand->callbacks->yajl_double) {
311                             double d = 0.0;
312                             yajl_buf_clear(hand->decodeBuf);
313                             yajl_buf_append(hand->decodeBuf, buf, bufLen);
314                             buf = yajl_buf_data(hand->decodeBuf);
315                             errno = 0;
316                             d = strtod((char *) buf, NULL);
317                             if ((d == HUGE_VAL || d == -HUGE_VAL) &&
318                                 errno == ERANGE)
319                             {
320                                 yajl_bs_set(hand->stateStack,
321                                             yajl_state_parse_error);
322                                 hand->parseError = "numeric (floating point) "
323                                     "overflow";
324                                 /* try to restore error offset */
325                                 if (*offset >= bufLen) *offset -= bufLen;
326                                 else *offset = 0;
327                                 goto around_again;
328                             }
329                             _CC_CHK(hand->callbacks->yajl_double(hand->ctx,
330                                                                  d));
331                         }
332                     }
333                     break;
334                 case yajl_tok_right_brace: {
335                     if (yajl_bs_current(hand->stateStack) ==
336                         yajl_state_array_start)
337                     {
338                         if (hand->callbacks &&
339                             hand->callbacks->yajl_end_array)
340                         {
341                             _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
342                         }
343                         yajl_bs_pop(hand->stateStack);
344                         goto around_again;
345                     }
346                     /* intentional fall-through */
347                 }
348                 case yajl_tok_colon:
349                 case yajl_tok_comma:
350                 case yajl_tok_right_bracket:
351                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
352                     hand->parseError =
353                         "unallowed token at this point in JSON text";
354                     goto around_again;
355                 default:
356                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
357                     hand->parseError = "invalid token, internal error";
358                     goto around_again;
359             }
360             /* got a value.  transition depends on the state we're in. */
361             {
362                 yajl_state s = (yajl_state)yajl_bs_current(hand->stateStack);
363                 if (s == yajl_state_start || s == yajl_state_got_value) {
364                     yajl_bs_set(hand->stateStack, yajl_state_parse_complete);
365                 } else if (s == yajl_state_map_need_val) {
366                     yajl_bs_set(hand->stateStack, yajl_state_map_got_val);
367                 } else {
368                     yajl_bs_set(hand->stateStack, yajl_state_array_got_val);
369                 }
370             }
371             if (stateToPush != yajl_state_start) {
372                 yajl_bs_push(hand->stateStack, stateToPush);
373             }
374 
375             goto around_again;
376         }
377         case yajl_state_map_start:
378         case yajl_state_map_need_key: {
379             /* only difference between these two states is that in
380              * start '}' is valid, whereas in need_key, we've parsed
381              * a comma, and a string key _must_ follow */
382             tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
383                                offset, &buf, &bufLen);
384             switch (tok) {
385                 case yajl_tok_eof:
386                     return yajl_status_ok;
387                 case yajl_tok_error:
388                     yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
389                     goto around_again;
390                 case yajl_tok_string_with_escapes:
391                     if (hand->callbacks && hand->callbacks->yajl_map_key) {
392                         yajl_buf_clear(hand->decodeBuf);
393                         yajl_string_decode(hand->decodeBuf, buf, bufLen);
394                         buf = yajl_buf_data(hand->decodeBuf);
395                         bufLen = yajl_buf_len(hand->decodeBuf);
396                     }
397                     /* intentional fall-through */
398                 case yajl_tok_string:
399                     if (hand->callbacks && hand->callbacks->yajl_map_key) {
400                         _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf,
401                                                               bufLen));
402                     }
403                     yajl_bs_set(hand->stateStack, yajl_state_map_sep);
404                     goto around_again;
405                 case yajl_tok_right_bracket:
406                     if (yajl_bs_current(hand->stateStack) ==
407                         yajl_state_map_start)
408                     {
409                         if (hand->callbacks && hand->callbacks->yajl_end_map) {
410                             _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
411                         }
412                         yajl_bs_pop(hand->stateStack);
413                         goto around_again;
414                     }
415                 default:
416                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
417                     hand->parseError =
418                         "invalid object key (must be a string)";
419                     goto around_again;
420             }
421         }
422         case yajl_state_map_sep: {
423             tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
424                                offset, &buf, &bufLen);
425             switch (tok) {
426                 case yajl_tok_colon:
427                     yajl_bs_set(hand->stateStack, yajl_state_map_need_val);
428                     goto around_again;
429                 case yajl_tok_eof:
430                     return yajl_status_ok;
431                 case yajl_tok_error:
432                     yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
433                     goto around_again;
434                 default:
435                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
436                     hand->parseError = "object key and value must "
437                         "be separated by a colon (':')";
438                     goto around_again;
439             }
440         }
441         case yajl_state_map_got_val: {
442             tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
443                                offset, &buf, &bufLen);
444             switch (tok) {
445                 case yajl_tok_right_bracket:
446                     if (hand->callbacks && hand->callbacks->yajl_end_map) {
447                         _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
448                     }
449                     yajl_bs_pop(hand->stateStack);
450                     goto around_again;
451                 case yajl_tok_comma:
452                     yajl_bs_set(hand->stateStack, yajl_state_map_need_key);
453                     goto around_again;
454                 case yajl_tok_eof:
455                     return yajl_status_ok;
456                 case yajl_tok_error:
457                     yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
458                     goto around_again;
459                 default:
460                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
461                     hand->parseError = "after key and value, inside map, "
462                                        "I expect ',' or '}'";
463                     /* try to restore error offset */
464                     if (*offset >= bufLen) *offset -= bufLen;
465                     else *offset = 0;
466                     goto around_again;
467             }
468         }
469         case yajl_state_array_got_val: {
470             tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
471                                offset, &buf, &bufLen);
472             switch (tok) {
473                 case yajl_tok_right_brace:
474                     if (hand->callbacks && hand->callbacks->yajl_end_array) {
475                         _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
476                     }
477                     yajl_bs_pop(hand->stateStack);
478                     goto around_again;
479                 case yajl_tok_comma:
480                     yajl_bs_set(hand->stateStack, yajl_state_array_need_val);
481                     goto around_again;
482                 case yajl_tok_eof:
483                     return yajl_status_ok;
484                 case yajl_tok_error:
485                     yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
486                     goto around_again;
487                 default:
488                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
489                     hand->parseError =
490                         "after array element, I expect ',' or ']'";
491                     goto around_again;
492             }
493         }
494     }
495 
496     abort();
497     return yajl_status_error;
498 }
499 
500