1 /* $OpenBSD: conflex.c,v 1.13 2006/12/17 17:41:56 stevesk Exp $ */ 2 /* $DragonFly: src/sbin/dhclient/conflex.c,v 1.1 2008/08/30 16:07:58 hasso Exp $ */ 3 4 /* Lexical scanner for dhclient config file... */ 5 6 /* 7 * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of The Internet Software Consortium nor the names 20 * of its contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 24 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 31 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * This software has been written for the Internet Software Consortium 38 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 39 * Enterprises. To learn more about the Internet Software Consortium, 40 * see ``http://www.vix.com/isc''. To learn more about Vixie 41 * Enterprises, see ``http://www.vix.com''. 42 */ 43 44 #include <ctype.h> 45 46 #include "dhcpd.h" 47 #include "dhctoken.h" 48 49 int lexline; 50 int lexchar; 51 char *token_line; 52 char *prev_line; 53 char *cur_line; 54 char *tlname; 55 56 static char line1[81]; 57 static char line2[81]; 58 static uint lpos; 59 static int line; 60 static int tlpos; 61 static int tline; 62 static int token; 63 static int ugflag; 64 static char *tval; 65 static char tokbuf[1500]; 66 67 static int get_char(FILE *); 68 static int get_token(FILE *); 69 static void skip_to_eol(FILE *); 70 static int read_string(FILE *); 71 static int read_number(int, FILE *); 72 static int read_num_or_name(int, FILE *); 73 int kw_cmp(const void *, const void *); 74 static int intern(char *, int); 75 76 void 77 new_parse(char *name) 78 { 79 tlname = name; 80 lpos = line = 1; 81 cur_line = line1; 82 prev_line = line2; 83 token_line = cur_line; 84 cur_line[0] = prev_line[0] = 0; 85 warnings_occurred = 0; 86 } 87 88 static int 89 get_char(FILE *cfile) 90 { 91 int c = getc(cfile); 92 if (!ugflag) { 93 if (c == '\n') { 94 if (cur_line == line1) { 95 cur_line = line2; 96 prev_line = line1; 97 } else { 98 cur_line = line2; 99 prev_line = line1; 100 } 101 line++; 102 lpos = 1; 103 cur_line[0] = 0; 104 } else if (c != EOF) { 105 if (lpos < sizeof(line1)) { 106 cur_line[lpos - 1] = c; 107 cur_line[lpos] = 0; 108 } 109 lpos++; 110 } 111 } else 112 ugflag = 0; 113 return (c); 114 } 115 116 static int 117 get_token(FILE *cfile) 118 { 119 int c, ttok; 120 static char tb[2]; 121 int l, p; 122 123 do { 124 l = line; 125 p = lpos; 126 127 c = get_char(cfile); 128 129 if (isascii(c) && isspace(c)) 130 continue; 131 if (c == '#') { 132 skip_to_eol(cfile); 133 continue; 134 } 135 if (c == '"') { 136 lexline = l; 137 lexchar = p; 138 ttok = read_string(cfile); 139 break; 140 } 141 if ((isascii(c) && isdigit(c)) || c == '-') { 142 lexline = l; 143 lexchar = p; 144 ttok = read_number(c, cfile); 145 break; 146 } else if (isascii(c) && isalpha(c)) { 147 lexline = l; 148 lexchar = p; 149 ttok = read_num_or_name(c, cfile); 150 break; 151 } else { 152 lexline = l; 153 lexchar = p; 154 tb[0] = c; 155 tb[1] = 0; 156 tval = tb; 157 ttok = c; 158 break; 159 } 160 } while (1); 161 return (ttok); 162 } 163 164 int 165 next_token(char **rval, FILE *cfile) 166 { 167 int rv; 168 169 if (token) { 170 if (lexline != tline) 171 token_line = cur_line; 172 lexchar = tlpos; 173 lexline = tline; 174 rv = token; 175 token = 0; 176 } else { 177 rv = get_token(cfile); 178 token_line = cur_line; 179 } 180 if (rval) 181 *rval = tval; 182 183 return (rv); 184 } 185 186 int 187 peek_token(char **rval, FILE *cfile) 188 { 189 int x; 190 191 if (!token) { 192 tlpos = lexchar; 193 tline = lexline; 194 token = get_token(cfile); 195 if (lexline != tline) 196 token_line = prev_line; 197 x = lexchar; 198 lexchar = tlpos; 199 tlpos = x; 200 x = lexline; 201 lexline = tline; 202 tline = x; 203 } 204 if (rval) 205 *rval = tval; 206 207 return (token); 208 } 209 210 static void 211 skip_to_eol(FILE *cfile) 212 { 213 int c; 214 215 do { 216 c = get_char(cfile); 217 if (c == EOF) 218 return; 219 if (c == '\n') 220 return; 221 } while (1); 222 } 223 224 static int 225 read_string(FILE *cfile) 226 { 227 uint i; 228 int c, bs = 0; 229 230 for (i = 0; i < sizeof(tokbuf); i++) { 231 c = get_char(cfile); 232 if (c == EOF) { 233 parse_warn("eof in string constant"); 234 break; 235 } 236 if (bs) { 237 bs = 0; 238 tokbuf[i] = c; 239 } else if (c == '\\') 240 bs = 1; 241 else if (c == '"') 242 break; 243 else 244 tokbuf[i] = c; 245 } 246 /* 247 * Normally, I'd feel guilty about this, but we're talking about 248 * strings that'll fit in a DHCP packet here... 249 */ 250 if (i == sizeof(tokbuf)) { 251 parse_warn("string constant larger than internal buffer"); 252 i--; 253 } 254 tokbuf[i] = 0; 255 tval = tokbuf; 256 return (TOK_STRING); 257 } 258 259 static int 260 read_number(int c, FILE *cfile) 261 { 262 uint i = 0; 263 int seenx = 0, token = TOK_NUMBER; 264 265 tokbuf[i++] = c; 266 for (; i < sizeof(tokbuf); i++) { 267 c = get_char(cfile); 268 if (!seenx && c == 'x') 269 seenx = 1; 270 else if (!isascii(c) || !isxdigit(c)) { 271 ungetc(c, cfile); 272 ugflag = 1; 273 break; 274 } 275 tokbuf[i] = c; 276 } 277 if (i == sizeof(tokbuf)) { 278 parse_warn("numeric token larger than internal buffer"); 279 i--; 280 } 281 tokbuf[i] = 0; 282 tval = tokbuf; 283 284 return (token); 285 } 286 287 static int 288 read_num_or_name(int c, FILE *cfile) 289 { 290 uint i = 0; 291 int rv = TOK_NUMBER_OR_NAME; 292 293 tokbuf[i++] = c; 294 for (; i < sizeof(tokbuf); i++) { 295 c = get_char(cfile); 296 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { 297 ungetc(c, cfile); 298 ugflag = 1; 299 break; 300 } 301 if (!isxdigit(c)) 302 rv = TOK_NAME; 303 tokbuf[i] = c; 304 } 305 if (i == sizeof(tokbuf)) { 306 parse_warn("token larger than internal buffer"); 307 i--; 308 } 309 tokbuf[i] = 0; 310 tval = tokbuf; 311 312 return (intern(tval, rv)); 313 } 314 315 static const struct keywords { 316 const char *k_name; 317 int k_val; 318 } keywords[] = { 319 { "alias", TOK_ALIAS }, 320 { "append", TOK_APPEND }, 321 { "backoff-cutoff", TOK_BACKOFF_CUTOFF }, 322 { "bootp", TOK_BOOTP }, 323 { "default", TOK_DEFAULT }, 324 { "deny", TOK_DENY }, 325 { "ethernet", TOK_ETHERNET }, 326 { "expire", TOK_EXPIRE }, 327 { "fddi", TOK_FDDI }, 328 { "filename", TOK_FILENAME }, 329 { "fixed-address", TOK_FIXED_ADDR }, 330 { "hardware", TOK_HARDWARE }, 331 { "initial-interval", TOK_INITIAL_INTERVAL }, 332 { "interface", TOK_INTERFACE }, 333 { "lease", TOK_LEASE }, 334 { "link-timeout", TOK_LINK_TIMEOUT }, 335 { "media", TOK_MEDIA }, 336 { "medium", TOK_MEDIUM }, 337 { "option", TOK_OPTION }, 338 { "prepend", TOK_PREPEND }, 339 { "rebind", TOK_REBIND }, 340 { "reboot", TOK_REBOOT }, 341 { "reject", TOK_REJECT }, 342 { "renew", TOK_RENEW }, 343 { "request", TOK_REQUEST }, 344 { "require", TOK_REQUIRE }, 345 { "retry", TOK_RETRY }, 346 { "script", TOK_SCRIPT }, 347 { "select-timeout", TOK_SELECT_TIMEOUT }, 348 { "send", TOK_SEND }, 349 { "server-name", TOK_SERVER_NAME }, 350 { "supersede", TOK_SUPERSEDE }, 351 { "timeout", TOK_TIMEOUT }, 352 { "token-ring", TOK_TOKEN_RING } 353 }; 354 355 int 356 kw_cmp(const void *k, const void *e) 357 { 358 return (strcasecmp(k, ((const struct keywords *)e)->k_name)); 359 } 360 361 static int 362 intern(char *atom, int dfv) 363 { 364 const struct keywords *p; 365 366 p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]), 367 sizeof(keywords[0]), kw_cmp); 368 if (p) 369 return (p->k_val); 370 return (dfv); 371 } 372