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 <ldns/config.h> 11 #include <ldns/ldns.h> 12 13 #include <limits.h> 14 #include <strings.h> 15 16 ldns_lookup_table ldns_directive_types[] = { 17 { LDNS_DIR_TTL, "$TTL" }, 18 { LDNS_DIR_ORIGIN, "$ORIGIN" }, 19 { LDNS_DIR_INCLUDE, "$INCLUDE" }, 20 { 0, NULL } 21 }; 22 23 /* add max_limit here? */ 24 ssize_t 25 ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit) 26 { 27 return ldns_fget_token_l(f, token, delim, limit, NULL); 28 } 29 30 ssize_t 31 ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr) 32 { 33 int c, prev_c; 34 int p; /* 0 -> no parenthese seen, >0 nr of ( seen */ 35 int com, quoted; 36 char *t; 37 size_t i; 38 const char *d; 39 const char *del; 40 41 /* standard delimeters */ 42 if (!delim) { 43 /* from isspace(3) */ 44 del = LDNS_PARSE_NORMAL; 45 } else { 46 del = delim; 47 } 48 49 p = 0; 50 i = 0; 51 com = 0; 52 quoted = 0; 53 prev_c = 0; 54 t = token; 55 if (del[0] == '"') { 56 quoted = 1; 57 } 58 while ((c = getc(f)) != EOF) { 59 if (c == '\r') /* carriage return */ 60 c = ' '; 61 if (c == '(' && prev_c != '\\' && !quoted) { 62 /* this only counts for non-comments */ 63 if (com == 0) { 64 p++; 65 } 66 prev_c = c; 67 continue; 68 } 69 70 if (c == ')' && prev_c != '\\' && !quoted) { 71 /* this only counts for non-comments */ 72 if (com == 0) { 73 p--; 74 } 75 prev_c = c; 76 continue; 77 } 78 79 if (p < 0) { 80 /* more ) then ( - close off the string */ 81 *t = '\0'; 82 return 0; 83 } 84 85 /* do something with comments ; */ 86 if (c == ';' && quoted == 0) { 87 if (prev_c != '\\') { 88 com = 1; 89 } 90 } 91 if (c == '\"' && com == 0 && prev_c != '\\') { 92 quoted = 1 - quoted; 93 } 94 95 if (c == '\n' && com != 0) { 96 /* comments */ 97 com = 0; 98 *t = ' '; 99 if (line_nr) { 100 *line_nr = *line_nr + 1; 101 } 102 if (p == 0 && i > 0) { 103 goto tokenread; 104 } else { 105 prev_c = c; 106 continue; 107 } 108 } 109 110 if (com == 1) { 111 *t = ' '; 112 prev_c = c; 113 continue; 114 } 115 116 if (c == '\n' && p != 0 && t > token) { 117 /* in parentheses */ 118 if (line_nr) { 119 *line_nr = *line_nr + 1; 120 } 121 *t++ = ' '; 122 prev_c = c; 123 continue; 124 } 125 126 /* check if we hit the delim */ 127 for (d = del; *d; d++) { 128 if (c == *d && i > 0 && prev_c != '\\' && p == 0) { 129 if (c == '\n' && line_nr) { 130 *line_nr = *line_nr + 1; 131 } 132 goto tokenread; 133 } 134 } 135 if (c != '\0' && c != '\n') { 136 i++; 137 } 138 if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { 139 *t = '\0'; 140 return -1; 141 } 142 if (c != '\0' && c != '\n') { 143 *t++ = c; 144 } 145 if (c == '\\' && prev_c == '\\') 146 prev_c = 0; 147 else prev_c = c; 148 } 149 *t = '\0'; 150 if (c == EOF) { 151 return (ssize_t)i; 152 } 153 154 if (i == 0) { 155 /* nothing read */ 156 return -1; 157 } 158 if (p != 0) { 159 return -1; 160 } 161 return (ssize_t)i; 162 163 tokenread: 164 if(*del == '"') /* do not skip over quotes, they are significant */ 165 ldns_fskipcs_l(f, del+1, line_nr); 166 else ldns_fskipcs_l(f, del, line_nr); 167 *t = '\0'; 168 if (p != 0) { 169 return -1; 170 } 171 172 return (ssize_t)i; 173 } 174 175 ssize_t 176 ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, 177 const char *d_del, size_t data_limit) 178 { 179 return ldns_fget_keyword_data_l(f, keyword, k_del, data, d_del, 180 data_limit, NULL); 181 } 182 183 ssize_t 184 ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data, 185 const char *d_del, size_t data_limit, int *line_nr) 186 { 187 /* we assume: keyword|sep|data */ 188 char *fkeyword; 189 ssize_t i; 190 191 if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN) 192 return -1; 193 fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); 194 if(!fkeyword) 195 return -1; 196 197 i = ldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN); 198 if(i==0 || i==-1) { 199 LDNS_FREE(fkeyword); 200 return -1; 201 } 202 203 /* case??? i instead of strlen? */ 204 if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) { 205 /* whee! */ 206 /* printf("%s\n%s\n", "Matching keyword", fkeyword); */ 207 i = ldns_fget_token_l(f, data, d_del, data_limit, line_nr); 208 LDNS_FREE(fkeyword); 209 return i; 210 } else { 211 /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/ 212 LDNS_FREE(fkeyword); 213 return -1; 214 } 215 } 216 217 218 ssize_t 219 ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit) 220 { 221 int c, lc; 222 int p; /* 0 -> no parenthese seen, >0 nr of ( seen */ 223 int com, quoted; 224 char *t; 225 size_t i; 226 const char *d; 227 const char *del; 228 229 /* standard delimiters */ 230 if (!delim) { 231 /* from isspace(3) */ 232 del = LDNS_PARSE_NORMAL; 233 } else { 234 del = delim; 235 } 236 237 p = 0; 238 i = 0; 239 com = 0; 240 quoted = 0; 241 t = token; 242 lc = 0; 243 if (del[0] == '"') { 244 quoted = 1; 245 } 246 247 while ((c = ldns_bgetc(b)) != EOF) { 248 if (c == '\r') /* carriage return */ 249 c = ' '; 250 if (c == '(' && lc != '\\' && !quoted) { 251 /* this only counts for non-comments */ 252 if (com == 0) { 253 p++; 254 } 255 lc = c; 256 continue; 257 } 258 259 if (c == ')' && lc != '\\' && !quoted) { 260 /* this only counts for non-comments */ 261 if (com == 0) { 262 p--; 263 } 264 lc = c; 265 continue; 266 } 267 268 if (p < 0) { 269 /* more ) then ( */ 270 *t = '\0'; 271 return 0; 272 } 273 274 /* do something with comments ; */ 275 if (c == ';' && quoted == 0) { 276 if (lc != '\\') { 277 com = 1; 278 } 279 } 280 if (c == '"' && com == 0 && lc != '\\') { 281 quoted = 1 - quoted; 282 } 283 284 if (c == '\n' && com != 0) { 285 /* comments */ 286 com = 0; 287 *t = ' '; 288 lc = c; 289 continue; 290 } 291 292 if (com == 1) { 293 *t = ' '; 294 lc = c; 295 continue; 296 } 297 298 if (c == '\n' && p != 0) { 299 /* in parentheses */ 300 *t++ = ' '; 301 lc = c; 302 continue; 303 } 304 305 /* check if we hit the delim */ 306 for (d = del; *d; d++) { 307 if (c == *d && lc != '\\' && p == 0) { 308 goto tokenread; 309 } 310 } 311 312 i++; 313 if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { 314 *t = '\0'; 315 return -1; 316 } 317 *t++ = c; 318 319 if (c == '\\' && lc == '\\') { 320 lc = 0; 321 } else { 322 lc = c; 323 } 324 } 325 *t = '\0'; 326 if (i == 0) { 327 /* nothing read */ 328 return -1; 329 } 330 if (p != 0) { 331 return -1; 332 } 333 return (ssize_t)i; 334 335 tokenread: 336 if(*del == '"') /* do not skip over quotes, they are significant */ 337 ldns_bskipcs(b, del+1); 338 else ldns_bskipcs(b, del); 339 *t = '\0'; 340 341 if (p != 0) { 342 return -1; 343 } 344 return (ssize_t)i; 345 } 346 347 348 void 349 ldns_bskipcs(ldns_buffer *buffer, const char *s) 350 { 351 bool found; 352 char c; 353 const char *d; 354 355 while(ldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) { 356 c = (char) ldns_buffer_read_u8_at(buffer, buffer->_position); 357 found = false; 358 for (d = s; *d; d++) { 359 if (*d == c) { 360 found = true; 361 } 362 } 363 if (found && buffer->_limit > buffer->_position) { 364 buffer->_position += sizeof(char); 365 } else { 366 return; 367 } 368 } 369 } 370 371 void 372 ldns_fskipcs(FILE *fp, const char *s) 373 { 374 ldns_fskipcs_l(fp, s, NULL); 375 } 376 377 void 378 ldns_fskipcs_l(FILE *fp, const char *s, int *line_nr) 379 { 380 bool found; 381 int c; 382 const char *d; 383 384 while ((c = fgetc(fp)) != EOF) { 385 if (line_nr && c == '\n') { 386 *line_nr = *line_nr + 1; 387 } 388 found = false; 389 for (d = s; *d; d++) { 390 if (*d == c) { 391 found = true; 392 } 393 } 394 if (!found) { 395 /* with getc, we've read too far */ 396 ungetc(c, fp); 397 return; 398 } 399 } 400 } 401 402 ssize_t 403 ldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char 404 *data, const char *d_del, size_t data_limit) 405 { 406 /* we assume: keyword|sep|data */ 407 char *fkeyword; 408 ssize_t i; 409 410 if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN) 411 return -1; 412 fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); 413 if(!fkeyword) 414 return -1; /* out of memory */ 415 416 i = ldns_bget_token(b, fkeyword, k_del, data_limit); 417 if(i==0 || i==-1) { 418 LDNS_FREE(fkeyword); 419 return -1; /* nothing read */ 420 } 421 422 /* case??? */ 423 if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) { 424 LDNS_FREE(fkeyword); 425 /* whee, the match! */ 426 /* retrieve it's data */ 427 i = ldns_bget_token(b, data, d_del, 0); 428 return i; 429 } else { 430 LDNS_FREE(fkeyword); 431 return -1; 432 } 433 } 434 435