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