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 if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { 122 *t = '\0'; 123 return -1; 124 } 125 *t++ = ' '; 126 prev_c = c; 127 continue; 128 } 129 130 /* check if we hit the delim */ 131 for (d = del; *d; d++) { 132 if (c == *d && i > 0 && prev_c != '\\' && p == 0) { 133 if (c == '\n' && line_nr) { 134 *line_nr = *line_nr + 1; 135 } 136 goto tokenread; 137 } 138 } 139 if (c != '\0' && c != '\n') { 140 i++; 141 } 142 if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { 143 *t = '\0'; 144 return -1; 145 } 146 if (c != '\0' && c != '\n') { 147 *t++ = c; 148 } 149 if (c == '\\' && prev_c == '\\') 150 prev_c = 0; 151 else prev_c = c; 152 } 153 *t = '\0'; 154 if (c == EOF) { 155 return (ssize_t)i; 156 } 157 158 if (i == 0) { 159 /* nothing read */ 160 return -1; 161 } 162 if (p != 0) { 163 return -1; 164 } 165 return (ssize_t)i; 166 167 tokenread: 168 if(*del == '"') /* do not skip over quotes, they are significant */ 169 ldns_fskipcs_l(f, del+1, line_nr); 170 else ldns_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 ldns_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 ldns_fget_keyword_data_l(f, keyword, k_del, data, d_del, 184 data_limit, NULL); 185 } 186 187 ssize_t 188 ldns_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 = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); 198 if(!fkeyword) 199 return -1; 200 201 i = ldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN); 202 if(i==0 || i==-1) { 203 LDNS_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 = ldns_fget_token_l(f, data, d_del, data_limit, line_nr); 212 LDNS_FREE(fkeyword); 213 return i; 214 } else { 215 /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/ 216 LDNS_FREE(fkeyword); 217 return -1; 218 } 219 } 220 221 222 ssize_t 223 ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit) 224 { 225 int c, lc; 226 int p; /* 0 -> no parenthese seen, >0 nr of ( seen */ 227 int com, quoted; 228 char *t; 229 size_t i; 230 const char *d; 231 const char *del; 232 233 /* standard delimiters */ 234 if (!delim) { 235 /* from isspace(3) */ 236 del = LDNS_PARSE_NORMAL; 237 } else { 238 del = delim; 239 } 240 241 p = 0; 242 i = 0; 243 com = 0; 244 quoted = 0; 245 t = token; 246 lc = 0; 247 if (del[0] == '"') { 248 quoted = 1; 249 } 250 251 while ((c = ldns_bgetc(b)) != EOF) { 252 if (c == '\r') /* carriage return */ 253 c = ' '; 254 if (c == '(' && lc != '\\' && !quoted) { 255 /* this only counts for non-comments */ 256 if (com == 0) { 257 p++; 258 } 259 lc = c; 260 continue; 261 } 262 263 if (c == ')' && lc != '\\' && !quoted) { 264 /* this only counts for non-comments */ 265 if (com == 0) { 266 p--; 267 } 268 lc = c; 269 continue; 270 } 271 272 if (p < 0) { 273 /* more ) then ( */ 274 *t = '\0'; 275 return 0; 276 } 277 278 /* do something with comments ; */ 279 if (c == ';' && quoted == 0) { 280 if (lc != '\\') { 281 com = 1; 282 } 283 } 284 if (c == '"' && com == 0 && lc != '\\') { 285 quoted = 1 - quoted; 286 } 287 288 if (c == '\n' && com != 0) { 289 /* comments */ 290 com = 0; 291 *t = ' '; 292 lc = c; 293 continue; 294 } 295 296 if (com == 1) { 297 *t = ' '; 298 lc = c; 299 continue; 300 } 301 302 if (c == '\n' && p != 0) { 303 /* in parentheses */ 304 *t++ = ' '; 305 lc = c; 306 continue; 307 } 308 309 /* check if we hit the delim */ 310 for (d = del; *d; d++) { 311 if (c == *d && lc != '\\' && p == 0) { 312 goto tokenread; 313 } 314 } 315 316 i++; 317 if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { 318 *t = '\0'; 319 return -1; 320 } 321 *t++ = c; 322 323 if (c == '\\' && lc == '\\') { 324 lc = 0; 325 } else { 326 lc = c; 327 } 328 } 329 *t = '\0'; 330 if (i == 0) { 331 /* nothing read */ 332 return -1; 333 } 334 if (p != 0) { 335 return -1; 336 } 337 return (ssize_t)i; 338 339 tokenread: 340 if(*del == '"') /* do not skip over quotes, they are significant */ 341 ldns_bskipcs(b, del+1); 342 else ldns_bskipcs(b, del); 343 *t = '\0'; 344 345 if (p != 0) { 346 return -1; 347 } 348 return (ssize_t)i; 349 } 350 351 352 void 353 ldns_bskipcs(ldns_buffer *buffer, const char *s) 354 { 355 bool found; 356 char c; 357 const char *d; 358 359 while(ldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) { 360 c = (char) ldns_buffer_read_u8_at(buffer, buffer->_position); 361 found = false; 362 for (d = s; *d; d++) { 363 if (*d == c) { 364 found = true; 365 } 366 } 367 if (found && buffer->_limit > buffer->_position) { 368 buffer->_position += sizeof(char); 369 } else { 370 return; 371 } 372 } 373 } 374 375 void 376 ldns_fskipcs(FILE *fp, const char *s) 377 { 378 ldns_fskipcs_l(fp, s, NULL); 379 } 380 381 void 382 ldns_fskipcs_l(FILE *fp, const char *s, int *line_nr) 383 { 384 bool found; 385 int c; 386 const char *d; 387 388 while ((c = fgetc(fp)) != EOF) { 389 if (line_nr && c == '\n') { 390 *line_nr = *line_nr + 1; 391 } 392 found = false; 393 for (d = s; *d; d++) { 394 if (*d == c) { 395 found = true; 396 } 397 } 398 if (!found) { 399 /* with getc, we've read too far */ 400 ungetc(c, fp); 401 return; 402 } 403 } 404 } 405 406 ssize_t 407 ldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char 408 *data, const char *d_del, size_t data_limit) 409 { 410 /* we assume: keyword|sep|data */ 411 char *fkeyword; 412 ssize_t i; 413 414 if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN) 415 return -1; 416 fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); 417 if(!fkeyword) 418 return -1; /* out of memory */ 419 420 i = ldns_bget_token(b, fkeyword, k_del, data_limit); 421 if(i==0 || i==-1) { 422 LDNS_FREE(fkeyword); 423 return -1; /* nothing read */ 424 } 425 426 /* case??? */ 427 if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) { 428 LDNS_FREE(fkeyword); 429 /* whee, the match! */ 430 /* retrieve it's data */ 431 i = ldns_bget_token(b, data, d_del, 0); 432 return i; 433 } else { 434 LDNS_FREE(fkeyword); 435 return -1; 436 } 437 } 438 439