1238104Sdes/* 2238104Sdes * a generic (simple) parser. Use to parse rr's, private key 3238104Sdes * information and /etc/resolv.conf files 4238104Sdes * 5238104Sdes * a Net::DNS like library for C 6238104Sdes * LibDNS Team @ NLnet Labs 7238104Sdes * (c) NLnet Labs, 2005-2006 8238104Sdes * See the file LICENSE for the license 9238104Sdes */ 10238104Sdes#include <ldns/config.h> 11238104Sdes#include <ldns/ldns.h> 12238104Sdes 13238104Sdes#include <limits.h> 14238104Sdes#include <strings.h> 15238104Sdes 16238104Sdesldns_lookup_table ldns_directive_types[] = { 17238104Sdes { LDNS_DIR_TTL, "$TTL" }, 18238104Sdes { LDNS_DIR_ORIGIN, "$ORIGIN" }, 19238104Sdes { LDNS_DIR_INCLUDE, "$INCLUDE" }, 20238104Sdes { 0, NULL } 21238104Sdes}; 22238104Sdes 23238104Sdes/* add max_limit here? */ 24238104Sdesssize_t 25238104Sdesldns_fget_token(FILE *f, char *token, const char *delim, size_t limit) 26238104Sdes{ 27238104Sdes return ldns_fget_token_l(f, token, delim, limit, NULL); 28238104Sdes} 29238104Sdes 30238104Sdesssize_t 31238104Sdesldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr) 32238104Sdes{ 33238104Sdes int c, prev_c; 34238104Sdes int p; /* 0 -> no parenthese seen, >0 nr of ( seen */ 35238104Sdes int com, quoted; 36238104Sdes char *t; 37238104Sdes size_t i; 38238104Sdes const char *d; 39238104Sdes const char *del; 40238104Sdes 41238104Sdes /* standard delimeters */ 42238104Sdes if (!delim) { 43238104Sdes /* from isspace(3) */ 44238104Sdes del = LDNS_PARSE_NORMAL; 45238104Sdes } else { 46238104Sdes del = delim; 47238104Sdes } 48238104Sdes 49238104Sdes p = 0; 50238104Sdes i = 0; 51238104Sdes com = 0; 52238104Sdes quoted = 0; 53238104Sdes prev_c = 0; 54238104Sdes t = token; 55238104Sdes if (del[0] == '"') { 56238104Sdes quoted = 1; 57238104Sdes } 58238104Sdes while ((c = getc(f)) != EOF) { 59238104Sdes if (c == '\r') /* carriage return */ 60238104Sdes c = ' '; 61238104Sdes if (c == '(' && prev_c != '\\' && !quoted) { 62238104Sdes /* this only counts for non-comments */ 63238104Sdes if (com == 0) { 64238104Sdes p++; 65238104Sdes } 66238104Sdes prev_c = c; 67238104Sdes continue; 68238104Sdes } 69238104Sdes 70238104Sdes if (c == ')' && prev_c != '\\' && !quoted) { 71238104Sdes /* this only counts for non-comments */ 72238104Sdes if (com == 0) { 73238104Sdes p--; 74238104Sdes } 75238104Sdes prev_c = c; 76238104Sdes continue; 77238104Sdes } 78238104Sdes 79238104Sdes if (p < 0) { 80238104Sdes /* more ) then ( - close off the string */ 81238104Sdes *t = '\0'; 82238104Sdes return 0; 83238104Sdes } 84238104Sdes 85238104Sdes /* do something with comments ; */ 86238104Sdes if (c == ';' && quoted == 0) { 87238104Sdes if (prev_c != '\\') { 88238104Sdes com = 1; 89238104Sdes } 90238104Sdes } 91238104Sdes if (c == '\"' && com == 0 && prev_c != '\\') { 92238104Sdes quoted = 1 - quoted; 93238104Sdes } 94238104Sdes 95238104Sdes if (c == '\n' && com != 0) { 96238104Sdes /* comments */ 97238104Sdes com = 0; 98238104Sdes *t = ' '; 99238104Sdes if (line_nr) { 100238104Sdes *line_nr = *line_nr + 1; 101238104Sdes } 102238104Sdes if (p == 0 && i > 0) { 103238104Sdes goto tokenread; 104238104Sdes } else { 105238104Sdes prev_c = c; 106238104Sdes continue; 107238104Sdes } 108238104Sdes } 109238104Sdes 110238104Sdes if (com == 1) { 111238104Sdes *t = ' '; 112238104Sdes prev_c = c; 113238104Sdes continue; 114238104Sdes } 115238104Sdes 116238104Sdes if (c == '\n' && p != 0 && t > token) { 117238104Sdes /* in parentheses */ 118238104Sdes if (line_nr) { 119238104Sdes *line_nr = *line_nr + 1; 120238104Sdes } 121238104Sdes *t++ = ' '; 122238104Sdes prev_c = c; 123238104Sdes continue; 124238104Sdes } 125238104Sdes 126238104Sdes /* check if we hit the delim */ 127238104Sdes for (d = del; *d; d++) { 128238104Sdes if (c == *d && i > 0 && prev_c != '\\' && p == 0) { 129238104Sdes if (c == '\n' && line_nr) { 130238104Sdes *line_nr = *line_nr + 1; 131238104Sdes } 132238104Sdes goto tokenread; 133238104Sdes } 134238104Sdes } 135238104Sdes if (c != '\0' && c != '\n') { 136238104Sdes i++; 137238104Sdes } 138238104Sdes if (limit > 0 && i >= limit) { 139238104Sdes *t = '\0'; 140238104Sdes return -1; 141238104Sdes } 142238104Sdes if (c != '\0' && c != '\n') { 143238104Sdes *t++ = c; 144238104Sdes } 145238104Sdes if (c == '\\' && prev_c == '\\') 146238104Sdes prev_c = 0; 147238104Sdes else prev_c = c; 148238104Sdes } 149238104Sdes *t = '\0'; 150238104Sdes if (c == EOF) { 151238104Sdes return (ssize_t)i; 152238104Sdes } 153238104Sdes 154238104Sdes if (i == 0) { 155238104Sdes /* nothing read */ 156238104Sdes return -1; 157238104Sdes } 158238104Sdes if (p != 0) { 159238104Sdes return -1; 160238104Sdes } 161238104Sdes return (ssize_t)i; 162238104Sdes 163238104Sdestokenread: 164246854Sdes ldns_fskipcs_l(f, del, line_nr); 165238104Sdes *t = '\0'; 166238104Sdes if (p != 0) { 167238104Sdes return -1; 168238104Sdes } 169238104Sdes 170238104Sdes return (ssize_t)i; 171238104Sdes} 172238104Sdes 173238104Sdesssize_t 174238104Sdesldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, 175238104Sdes const char *d_del, size_t data_limit) 176238104Sdes{ 177238104Sdes return ldns_fget_keyword_data_l(f, keyword, k_del, data, d_del, 178238104Sdes data_limit, NULL); 179238104Sdes} 180238104Sdes 181238104Sdesssize_t 182238104Sdesldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data, 183238104Sdes const char *d_del, size_t data_limit, int *line_nr) 184238104Sdes{ 185238104Sdes /* we assume: keyword|sep|data */ 186238104Sdes char *fkeyword; 187238104Sdes ssize_t i; 188238104Sdes 189238104Sdes if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN) 190238104Sdes return -1; 191238104Sdes fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); 192238104Sdes if(!fkeyword) 193238104Sdes return -1; 194238104Sdes 195238104Sdes i = ldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN); 196238104Sdes if(i==0 || i==-1) { 197238104Sdes LDNS_FREE(fkeyword); 198238104Sdes return -1; 199238104Sdes } 200238104Sdes 201238104Sdes /* case??? i instead of strlen? */ 202238104Sdes if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) { 203238104Sdes /* whee! */ 204238104Sdes /* printf("%s\n%s\n", "Matching keyword", fkeyword); */ 205238104Sdes i = ldns_fget_token_l(f, data, d_del, data_limit, line_nr); 206238104Sdes LDNS_FREE(fkeyword); 207238104Sdes return i; 208238104Sdes } else { 209238104Sdes /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/ 210238104Sdes LDNS_FREE(fkeyword); 211238104Sdes return -1; 212238104Sdes } 213238104Sdes} 214238104Sdes 215238104Sdes 216238104Sdesssize_t 217238104Sdesldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit) 218238104Sdes{ 219238104Sdes int c, lc; 220238104Sdes int p; /* 0 -> no parenthese seen, >0 nr of ( seen */ 221238104Sdes int com, quoted; 222238104Sdes char *t; 223238104Sdes size_t i; 224238104Sdes const char *d; 225238104Sdes const char *del; 226238104Sdes 227238104Sdes /* standard delimiters */ 228238104Sdes if (!delim) { 229238104Sdes /* from isspace(3) */ 230238104Sdes del = LDNS_PARSE_NORMAL; 231238104Sdes } else { 232238104Sdes del = delim; 233238104Sdes } 234238104Sdes 235238104Sdes p = 0; 236238104Sdes i = 0; 237238104Sdes com = 0; 238238104Sdes quoted = 0; 239238104Sdes t = token; 240238104Sdes lc = 0; 241238104Sdes if (del[0] == '"') { 242238104Sdes quoted = 1; 243238104Sdes } 244238104Sdes 245238104Sdes while ((c = ldns_bgetc(b)) != EOF) { 246238104Sdes if (c == '\r') /* carriage return */ 247238104Sdes c = ' '; 248238104Sdes if (c == '(' && lc != '\\' && !quoted) { 249238104Sdes /* this only counts for non-comments */ 250238104Sdes if (com == 0) { 251238104Sdes p++; 252238104Sdes } 253238104Sdes lc = c; 254238104Sdes continue; 255238104Sdes } 256238104Sdes 257238104Sdes if (c == ')' && lc != '\\' && !quoted) { 258238104Sdes /* this only counts for non-comments */ 259238104Sdes if (com == 0) { 260238104Sdes p--; 261238104Sdes } 262238104Sdes lc = c; 263238104Sdes continue; 264238104Sdes } 265238104Sdes 266238104Sdes if (p < 0) { 267238104Sdes /* more ) then ( */ 268238104Sdes *t = '\0'; 269238104Sdes return 0; 270238104Sdes } 271238104Sdes 272238104Sdes /* do something with comments ; */ 273238104Sdes if (c == ';' && quoted == 0) { 274238104Sdes if (lc != '\\') { 275238104Sdes com = 1; 276238104Sdes } 277238104Sdes } 278238104Sdes if (c == '"' && com == 0 && lc != '\\') { 279238104Sdes quoted = 1 - quoted; 280238104Sdes } 281238104Sdes 282238104Sdes if (c == '\n' && com != 0) { 283238104Sdes /* comments */ 284238104Sdes com = 0; 285238104Sdes *t = ' '; 286238104Sdes lc = c; 287238104Sdes continue; 288238104Sdes } 289238104Sdes 290238104Sdes if (com == 1) { 291238104Sdes *t = ' '; 292238104Sdes lc = c; 293238104Sdes continue; 294238104Sdes } 295238104Sdes 296238104Sdes if (c == '\n' && p != 0) { 297238104Sdes /* in parentheses */ 298238104Sdes *t++ = ' '; 299238104Sdes lc = c; 300238104Sdes continue; 301238104Sdes } 302238104Sdes 303238104Sdes /* check if we hit the delim */ 304238104Sdes for (d = del; *d; d++) { 305238104Sdes if (c == *d && lc != '\\' && p == 0) { 306238104Sdes goto tokenread; 307238104Sdes } 308238104Sdes } 309238104Sdes 310238104Sdes i++; 311238104Sdes if (limit > 0 && i >= limit) { 312238104Sdes *t = '\0'; 313238104Sdes return -1; 314238104Sdes } 315238104Sdes *t++ = c; 316238104Sdes 317238104Sdes if (c == '\\' && lc == '\\') { 318238104Sdes lc = 0; 319238104Sdes } else { 320238104Sdes lc = c; 321238104Sdes } 322238104Sdes } 323238104Sdes *t = '\0'; 324238104Sdes if (i == 0) { 325238104Sdes /* nothing read */ 326238104Sdes return -1; 327238104Sdes } 328238104Sdes if (p != 0) { 329238104Sdes return -1; 330238104Sdes } 331238104Sdes return (ssize_t)i; 332238104Sdes 333238104Sdestokenread: 334246854Sdes ldns_bskipcs(b, del); 335238104Sdes *t = '\0'; 336238104Sdes 337238104Sdes if (p != 0) { 338238104Sdes return -1; 339238104Sdes } 340238104Sdes return (ssize_t)i; 341238104Sdes} 342238104Sdes 343238104Sdes 344238104Sdesvoid 345238104Sdesldns_bskipcs(ldns_buffer *buffer, const char *s) 346238104Sdes{ 347238104Sdes bool found; 348238104Sdes char c; 349238104Sdes const char *d; 350238104Sdes 351238104Sdes while(ldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) { 352238104Sdes c = (char) ldns_buffer_read_u8_at(buffer, buffer->_position); 353238104Sdes found = false; 354238104Sdes for (d = s; *d; d++) { 355238104Sdes if (*d == c) { 356238104Sdes found = true; 357238104Sdes } 358238104Sdes } 359238104Sdes if (found && buffer->_limit > buffer->_position) { 360238104Sdes buffer->_position += sizeof(char); 361238104Sdes } else { 362238104Sdes return; 363238104Sdes } 364238104Sdes } 365238104Sdes} 366238104Sdes 367238104Sdesvoid 368238104Sdesldns_fskipcs(FILE *fp, const char *s) 369238104Sdes{ 370238104Sdes ldns_fskipcs_l(fp, s, NULL); 371238104Sdes} 372238104Sdes 373238104Sdesvoid 374238104Sdesldns_fskipcs_l(FILE *fp, const char *s, int *line_nr) 375238104Sdes{ 376238104Sdes bool found; 377238104Sdes int c; 378238104Sdes const char *d; 379238104Sdes 380238104Sdes while ((c = fgetc(fp)) != EOF) { 381238104Sdes if (line_nr && c == '\n') { 382238104Sdes *line_nr = *line_nr + 1; 383238104Sdes } 384238104Sdes found = false; 385238104Sdes for (d = s; *d; d++) { 386238104Sdes if (*d == c) { 387238104Sdes found = true; 388238104Sdes } 389238104Sdes } 390238104Sdes if (!found) { 391238104Sdes /* with getc, we've read too far */ 392238104Sdes ungetc(c, fp); 393238104Sdes return; 394238104Sdes } 395238104Sdes } 396238104Sdes} 397238104Sdes 398238104Sdesssize_t 399238104Sdesldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char 400238104Sdes*data, const char *d_del, size_t data_limit) 401238104Sdes{ 402238104Sdes /* we assume: keyword|sep|data */ 403238104Sdes char *fkeyword; 404238104Sdes ssize_t i; 405238104Sdes 406238104Sdes if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN) 407238104Sdes return -1; 408238104Sdes fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN); 409238104Sdes if(!fkeyword) 410238104Sdes return -1; /* out of memory */ 411238104Sdes 412238104Sdes i = ldns_bget_token(b, fkeyword, k_del, data_limit); 413238104Sdes if(i==0 || i==-1) { 414238104Sdes LDNS_FREE(fkeyword); 415238104Sdes return -1; /* nothing read */ 416238104Sdes } 417238104Sdes 418238104Sdes /* case??? */ 419238104Sdes if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) { 420238104Sdes LDNS_FREE(fkeyword); 421238104Sdes /* whee, the match! */ 422238104Sdes /* retrieve it's data */ 423238104Sdes i = ldns_bget_token(b, data, d_del, 0); 424238104Sdes return i; 425238104Sdes } else { 426238104Sdes LDNS_FREE(fkeyword); 427238104Sdes return -1; 428238104Sdes } 429238104Sdes} 430238104Sdes 431