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