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