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