]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/unbound/ldns/parse.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / unbound / ldns / parse.c
1 /*
2  * a generic (simple) parser. Use to parse rr's, private key
3  * information and /etc/resolv.conf files
4  *
5  * a Net::DNS like library for C
6  * LibDNS Team @ NLnet Labs
7  * (c) NLnet Labs, 2005-2006
8  * See the file LICENSE for the license
9  */
10 #include "config.h"
11 #include "ldns/parse.h"
12 #include "ldns/parseutil.h"
13 #include "ldns/sbuffer.h"
14
15 #include <limits.h>
16 #include <strings.h>
17
18 sldns_lookup_table sldns_directive_types[] = {
19         { LDNS_DIR_TTL, "$TTL" },
20         { LDNS_DIR_ORIGIN, "$ORIGIN" },
21         { LDNS_DIR_INCLUDE, "$INCLUDE" },
22         { 0, NULL }
23 };
24
25 /* add max_limit here? */
26 ssize_t
27 sldns_fget_token(FILE *f, char *token, const char *delim, size_t limit)
28 {
29         return sldns_fget_token_l(f, token, delim, limit, NULL);
30 }
31
32 ssize_t
33 sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
34 {
35         int c, prev_c;
36         int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
37         int com, quoted;
38         char *t;
39         size_t i;
40         const char *d;
41         const char *del;
42
43         /* standard delimeters */
44         if (!delim) {
45                 /* from isspace(3) */
46                 del = LDNS_PARSE_NORMAL;
47         } else {
48                 del = delim;
49         }
50
51         p = 0;
52         i = 0;
53         com = 0;
54         quoted = 0;
55         prev_c = 0;
56         t = token;
57         if (del[0] == '"') {
58                 quoted = 1;
59         }
60         while ((c = getc(f)) != EOF) {
61                 if (c == '\r') /* carriage return */
62                         c = ' ';
63                 if (c == '(' && prev_c != '\\' && !quoted) {
64                         /* this only counts for non-comments */
65                         if (com == 0) {
66                                 p++;
67                         }
68                         prev_c = c;
69                         continue;
70                 }
71
72                 if (c == ')' && prev_c != '\\' && !quoted) {
73                         /* this only counts for non-comments */
74                         if (com == 0) {
75                                 p--;
76                         }
77                         prev_c = c;
78                         continue;
79                 }
80
81                 if (p < 0) {
82                         /* more ) then ( - close off the string */
83                         *t = '\0';
84                         return 0;
85                 }
86
87                 /* do something with comments ; */
88                 if (c == ';' && quoted == 0) {
89                         if (prev_c != '\\') {
90                                 com = 1;
91                         }
92                 }
93                 if (c == '\"' && com == 0 && prev_c != '\\') {
94                         quoted = 1 - quoted;
95                 }
96
97                 if (c == '\n' && com != 0) {
98                         /* comments */
99                         com = 0;
100                         *t = ' ';
101                         if (line_nr) {
102                                 *line_nr = *line_nr + 1;
103                         }
104                         if (p == 0 && i > 0) {
105                                 goto tokenread;
106                         } else {
107                                 prev_c = c;
108                                 continue;
109                         }
110                 }
111
112                 if (com == 1) {
113                         *t = ' ';
114                         prev_c = c;
115                         continue;
116                 }
117
118                 if (c == '\n' && p != 0 && t > token) {
119                         /* in parentheses */
120                         if (line_nr) {
121                                 *line_nr = *line_nr + 1;
122                         }
123                         *t++ = ' ';
124                         prev_c = c;
125                         continue;
126                 }
127
128                 /* check if we hit the delim */
129                 for (d = del; *d; d++) {
130                         if (c == *d && i > 0 && prev_c != '\\' && p == 0) {
131                                 if (c == '\n' && line_nr) {
132                                         *line_nr = *line_nr + 1;
133                                 }
134                                 goto tokenread;
135                         }
136                 }
137                 if (c != '\0' && c != '\n') {
138                         i++;
139                 }
140                 if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
141                         *t = '\0';
142                         return -1;
143                 }
144                 if (c != '\0' && c != '\n') {
145                         *t++ = c;
146                 }
147                 if (c == '\\' && prev_c == '\\')
148                         prev_c = 0;
149                 else    prev_c = c;
150         }
151         *t = '\0';
152         if (c == EOF) {
153                 return (ssize_t)i;
154         }
155
156         if (i == 0) {
157                 /* nothing read */
158                 return -1;
159         }
160         if (p != 0) {
161                 return -1;
162         }
163         return (ssize_t)i;
164
165 tokenread:
166         if(*del == '"')
167                 /* do not skip over quotes after the string, they are part
168                  * of the next string.  But skip over whitespace (if needed)*/
169                 sldns_fskipcs_l(f, del+1, line_nr);
170         else    sldns_fskipcs_l(f, del, line_nr);
171         *t = '\0';
172         if (p != 0) {
173                 return -1;
174         }
175
176         return (ssize_t)i;
177 }
178
179 ssize_t
180 sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data,
181                const char *d_del, size_t data_limit)
182 {
183        return sldns_fget_keyword_data_l(f, keyword, k_del, data, d_del,
184                        data_limit, NULL);
185 }
186
187 ssize_t
188 sldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data,
189                const char *d_del, size_t data_limit, int *line_nr)
190 {
191        /* we assume: keyword|sep|data */
192        char *fkeyword;
193        ssize_t i;
194
195        if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
196                return -1;
197        fkeyword = (char*)malloc(LDNS_MAX_KEYWORDLEN);
198        if(!fkeyword)
199                return -1;
200
201        i = sldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN);
202        if(i==0 || i==-1) {
203                free(fkeyword);
204                return -1;
205        }
206
207        /* case??? i instead of strlen? */
208        if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) {
209                /* whee! */
210                /* printf("%s\n%s\n", "Matching keyword", fkeyword); */
211                i = sldns_fget_token_l(f, data, d_del, data_limit, line_nr);
212                free(fkeyword);
213                return i;
214        } else {
215                /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/
216                free(fkeyword);
217                return -1;
218        }
219 }
220
221 int
222 sldns_bgetc(sldns_buffer *buffer)
223 {
224         if (!sldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) {
225                 sldns_buffer_set_position(buffer, sldns_buffer_limit(buffer));
226                 /* sldns_buffer_rewind(buffer);*/
227                 return EOF;
228         }
229         return (int)sldns_buffer_read_u8(buffer);
230 }
231
232 ssize_t
233 sldns_bget_token(sldns_buffer *b, char *token, const char *delim, size_t limit)
234 {
235         return sldns_bget_token_par(b, token, delim, limit, NULL, NULL);
236 }
237
238 ssize_t
239 sldns_bget_token_par(sldns_buffer *b, char *token, const char *delim,
240         size_t limit, int* par, const char* skipw)
241 {
242         int c, lc;
243         int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
244         int com, quoted;
245         char *t;
246         size_t i;
247         const char *d;
248         const char *del;
249
250         /* standard delimiters */
251         if (!delim) {
252                 /* from isspace(3) */
253                 del = LDNS_PARSE_NORMAL;
254         } else {
255                 del = delim;
256         }
257
258         p = (par?*par:0);
259         i = 0;
260         com = 0;
261         quoted = 0;
262         t = token;
263         lc = 0;
264         if (del[0] == '"') {
265                 quoted = 1;
266         }
267
268         while ((c = sldns_bgetc(b)) != EOF) {
269                 if (c == '\r') /* carriage return */
270                         c = ' ';
271                 if (c == '(' && lc != '\\' && !quoted) {
272                         /* this only counts for non-comments */
273                         if (com == 0) {
274                                 if(par) (*par)++;
275                                 p++;
276                         }
277                         lc = c;
278                         continue;
279                 }
280
281                 if (c == ')' && lc != '\\' && !quoted) {
282                         /* this only counts for non-comments */
283                         if (com == 0) {
284                                 if(par) (*par)--;
285                                 p--;
286                         }
287                         lc = c;
288                         continue;
289                 }
290
291                 if (p < 0) {
292                         /* more ) then ( */
293                         *t = '\0';
294                         return 0;
295                 }
296
297                 /* do something with comments ; */
298                 if (c == ';' && quoted == 0) {
299                         if (lc != '\\') {
300                                 com = 1;
301                         }
302                 }
303                 if (c == '"' && com == 0 && lc != '\\') {
304                         quoted = 1 - quoted;
305                 }
306
307                 if (c == '\n' && com != 0) {
308                         /* comments */
309                         com = 0;
310                         *t = ' ';
311                         lc = c;
312                         continue;
313                 }
314
315                 if (com == 1) {
316                         *t = ' ';
317                         lc = c;
318                         continue;
319                 }
320
321                 if (c == '\n' && p != 0) {
322                         /* in parentheses */
323                         /* do not write ' ' if we want to skip spaces */
324                         if(!(skipw && (strchr(skipw, c)||strchr(skipw, ' '))))
325                                 *t++ = ' ';
326                         lc = c;
327                         continue;
328                 }
329
330                 /* check to skip whitespace at start, but also after ( */
331                 if(skipw && i==0 && !com && !quoted && lc != '\\') {
332                         if(strchr(skipw, c)) {
333                                 lc = c;
334                                 continue;
335                         }
336                 }
337
338                 /* check if we hit the delim */
339                 for (d = del; *d; d++) {
340                         /* we can only exit if no parens or user tracks them */
341                         if (c == *d && lc != '\\' && (p == 0 || par)) {
342                                 goto tokenread;
343                         }
344                 }
345
346                 i++;
347                 if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
348                         *t = '\0';
349                         return -1;
350                 }
351                 *t++ = c;
352
353                 if (c == '\\' && lc == '\\') {
354                         lc = 0;
355                 } else {
356                         lc = c;
357                 }
358         }
359         *t = '\0';
360         if (i == 0) {
361                 /* nothing read */
362                 return -1;
363         }
364         if (!par && p != 0) {
365                 return -1;
366         }
367         return (ssize_t)i;
368
369 tokenread:
370         if(*del == '"')
371                 /* do not skip over quotes after the string, they are part
372                  * of the next string.  But skip over whitespace (if needed)*/
373                 sldns_bskipcs(b, del+1);
374         else    sldns_bskipcs(b, del);
375         *t = '\0';
376
377         if (!par && p != 0) {
378                 return -1;
379         }
380         return (ssize_t)i;
381 }
382
383
384 void
385 sldns_bskipcs(sldns_buffer *buffer, const char *s)
386 {
387         int found;
388         char c;
389         const char *d;
390
391         while(sldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) {
392                 c = (char) sldns_buffer_read_u8_at(buffer, buffer->_position);
393                 found = 0;
394                 for (d = s; *d; d++) {
395                         if (*d == c) {
396                                 found = 1;
397                         }
398                 }
399                 if (found && buffer->_limit > buffer->_position) {
400                         buffer->_position += sizeof(char);
401                 } else {
402                         return;
403                 }
404         }
405 }
406
407 void
408 sldns_fskipcs(FILE *fp, const char *s)
409 {
410         sldns_fskipcs_l(fp, s, NULL);
411 }
412
413 void
414 sldns_fskipcs_l(FILE *fp, const char *s, int *line_nr)
415 {
416         int found;
417         int c;
418         const char *d;
419
420         while ((c = fgetc(fp)) != EOF) {
421                 if (line_nr && c == '\n') {
422                         *line_nr = *line_nr + 1;
423                 }
424                 found = 0;
425                 for (d = s; *d; d++) {
426                         if (*d == c) {
427                                 found = 1;
428                         }
429                 }
430                 if (!found) {
431                         /* with getc, we've read too far */
432                         ungetc(c, fp);
433                         return;
434                 }
435         }
436 }
437
438 ssize_t
439 sldns_bget_keyword_data(sldns_buffer *b, const char *keyword, const char *k_del, char
440 *data, const char *d_del, size_t data_limit)
441 {
442        /* we assume: keyword|sep|data */
443        char *fkeyword;
444        ssize_t i;
445
446        if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
447                return -1;
448        fkeyword = (char*)malloc(LDNS_MAX_KEYWORDLEN);
449        if(!fkeyword)
450                return -1; /* out of memory */
451
452        i = sldns_bget_token(b, fkeyword, k_del, data_limit);
453        if(i==0 || i==-1) {
454                free(fkeyword);
455                return -1; /* nothing read */
456        }
457
458        /* case??? */
459        if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) {
460                free(fkeyword);
461                /* whee, the match! */
462                /* retrieve it's data */
463                i = sldns_bget_token(b, data, d_del, 0);
464                return i;
465        } else {
466                free(fkeyword);
467                return -1;
468        }
469 }
470