1 /* $OpenBSD: conflex.c,v 1.12 2013/12/05 22:31:35 krw Exp $ */ 2 3 /* Lexical scanner for dhcpd 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 int eol_token; 55 56 static char line1[81]; 57 static char line2[81]; 58 static int 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 static int intern(char *, int); 74 75 void 76 new_parse(char *name) 77 { 78 tlname = name; 79 lpos = line = 1; 80 cur_line = line1; 81 prev_line = line2; 82 token_line = cur_line; 83 cur_line[0] = prev_line[0] = 0; 84 warnings_occurred = 0; 85 } 86 87 static int 88 get_char(FILE *cfile) 89 { 90 int c = getc(cfile); 91 if (!ugflag) { 92 if (c == '\n') { 93 if (cur_line == line1) { 94 cur_line = line2; 95 prev_line = line1; 96 } else { 97 cur_line = line2; 98 prev_line = line1; 99 } 100 line++; 101 lpos = 1; 102 cur_line[0] = 0; 103 } else if (c != EOF) { 104 if (lpos < sizeof(line1)) { 105 cur_line[lpos - 1] = c; 106 cur_line[lpos] = 0; 107 } 108 lpos++; 109 } 110 } else 111 ugflag = 0; 112 return (c); 113 } 114 115 static int 116 get_token(FILE *cfile) 117 { 118 int c, ttok; 119 static char tb[2]; 120 int l, p; 121 122 do { 123 l = line; 124 p = lpos; 125 126 c = get_char(cfile); 127 128 if (!(c == '\n' && eol_token) && isascii(c) && isspace(c)) 129 continue; 130 if (c == '#') { 131 skip_to_eol(cfile); 132 continue; 133 } 134 if (c == '"') { 135 lexline = l; 136 lexchar = p; 137 ttok = read_string(cfile); 138 break; 139 } 140 if ((isascii(c) && isdigit(c)) || c == '-') { 141 lexline = l; 142 lexchar = p; 143 ttok = read_number(c, cfile); 144 break; 145 } else if (isascii(c) && isalpha(c)) { 146 lexline = l; 147 lexchar = p; 148 ttok = read_num_or_name(c, cfile); 149 break; 150 } else { 151 lexline = l; 152 lexchar = p; 153 tb[0] = c; 154 tb[1] = 0; 155 tval = tb; 156 ttok = c; 157 break; 158 } 159 } while (1); 160 return (ttok); 161 } 162 163 int 164 next_token(char **rval, FILE *cfile) 165 { 166 int rv; 167 168 if (token) { 169 if (lexline != tline) 170 token_line = cur_line; 171 lexchar = tlpos; 172 lexline = tline; 173 rv = token; 174 token = 0; 175 } else { 176 rv = get_token(cfile); 177 token_line = cur_line; 178 } 179 if (rval) 180 *rval = tval; 181 182 return (rv); 183 } 184 185 int 186 peek_token(char **rval, FILE *cfile) 187 { 188 int x; 189 190 if (!token) { 191 tlpos = lexchar; 192 tline = lexline; 193 token = get_token(cfile); 194 if (lexline != tline) 195 token_line = prev_line; 196 x = lexchar; 197 lexchar = tlpos; 198 tlpos = x; 199 x = lexline; 200 lexline = tline; 201 tline = x; 202 } 203 if (rval) 204 *rval = tval; 205 206 return (token); 207 } 208 209 static void 210 skip_to_eol(FILE *cfile) 211 { 212 int c; 213 214 do { 215 c = get_char(cfile); 216 if (c == EOF) 217 return; 218 if (c == '\n') 219 return; 220 } while (1); 221 } 222 223 static int 224 read_string(FILE *cfile) 225 { 226 int i, c, bs; 227 228 bs = i = 0; 229 do { 230 c = get_char(cfile); 231 if (bs) 232 bs = 0; 233 else if (c == '\\') 234 bs = 1; 235 236 if (c != '"' && c != EOF && bs == 0) 237 tokbuf[i++] = c; 238 239 } while (i < (sizeof(tokbuf) - 1) && c != EOF && c != '"'); 240 241 if (c == EOF) 242 parse_warn("eof in string constant"); 243 else if (c != '"') 244 parse_warn("string constant larger than internal buffer"); 245 246 tokbuf[i] = 0; 247 tval = tokbuf; 248 249 return (TOK_STRING); 250 } 251 252 static int 253 read_number(int c, FILE *cfile) 254 { 255 int seenx = 0, i = 0, token = TOK_NUMBER; 256 257 tokbuf[i++] = c; 258 for (; i < sizeof(tokbuf); i++) { 259 c = get_char(cfile); 260 if (!seenx && c == 'x') 261 seenx = 1; 262 else if (!isascii(c) || !isxdigit(c)) { 263 ungetc(c, cfile); 264 ugflag = 1; 265 break; 266 } 267 tokbuf[i] = c; 268 } 269 if (i == sizeof(tokbuf)) { 270 parse_warn("numeric token larger than internal buffer"); 271 i--; 272 } 273 tokbuf[i] = 0; 274 tval = tokbuf; 275 276 return (token); 277 } 278 279 static int 280 read_num_or_name(int c, FILE *cfile) 281 { 282 int i = 0; 283 int rv = TOK_NUMBER_OR_NAME; 284 285 tokbuf[i++] = c; 286 for (; i < sizeof(tokbuf); i++) { 287 c = get_char(cfile); 288 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { 289 ungetc(c, cfile); 290 ugflag = 1; 291 break; 292 } 293 if (!isxdigit(c)) 294 rv = TOK_NAME; 295 tokbuf[i] = c; 296 } 297 if (i == sizeof(tokbuf)) { 298 parse_warn("token larger than internal buffer"); 299 i--; 300 } 301 tokbuf[i] = 0; 302 tval = tokbuf; 303 304 return (intern(tval, rv)); 305 } 306 307 static const struct keywords { 308 const char *k_name; 309 int k_val; 310 } keywords[] = { 311 { "abandoned", TOK_ABANDONED }, 312 { "allow", TOK_ALLOW }, 313 { "always-reply-rfc1048", TOK_ALWAYS_REPLY_RFC1048 }, 314 { "authoritative", TOK_AUTHORITATIVE }, 315 { "booting", TOK_BOOTING }, 316 { "bootp", TOK_BOOTP }, 317 { "class", TOK_CLASS }, 318 { "client-hostname", TOK_CLIENT_HOSTNAME }, 319 { "default-lease-time", TOK_DEFAULT_LEASE_TIME }, 320 { "deny", TOK_DENY }, 321 { "domain", TOK_DOMAIN }, 322 { "dynamic-bootp", TOK_DYNAMIC_BOOTP }, 323 { "dynamic-bootp-lease-cutoff", TOK_DYNAMIC_BOOTP_LEASE_CUTOFF }, 324 { "dynamic-bootp-lease-length", TOK_DYNAMIC_BOOTP_LEASE_LENGTH }, 325 { "ends", TOK_ENDS }, 326 { "ethernet", TOK_ETHERNET }, 327 { "filename", TOK_FILENAME }, 328 { "fixed-address", TOK_FIXED_ADDR }, 329 { "get-lease-hostnames", TOK_GET_LEASE_HOSTNAMES }, 330 { "group", TOK_GROUP }, 331 { "hardware", TOK_HARDWARE }, 332 { "host", TOK_HOST }, 333 { "hostname", TOK_HOSTNAME }, 334 { "ipsec-tunnel", TOK_IPSEC_TUNNEL }, 335 { "lease", TOK_LEASE }, 336 { "max-lease-time", TOK_MAX_LEASE_TIME }, 337 { "netmask", TOK_NETMASK }, 338 { "next-server", TOK_NEXT_SERVER }, 339 { "not", TOK_TOKEN_NOT }, 340 { "option", TOK_OPTION }, 341 { "range", TOK_RANGE }, 342 { "server-identifier", TOK_SERVER_IDENTIFIER }, 343 { "server-name", TOK_SERVER_NAME }, 344 { "shared-network", TOK_SHARED_NETWORK }, 345 { "starts", TOK_STARTS }, 346 { "subnet", TOK_SUBNET }, 347 { "timeout", TOK_TIMEOUT }, 348 { "timestamp", TOK_TIMESTAMP }, 349 { "uid", TOK_UID }, 350 { "unknown-clients", TOK_UNKNOWN_CLIENTS }, 351 { "use-host-decl-names", TOK_USE_HOST_DECL_NAMES }, 352 { "use-lease-addr-for-default-route", TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE }, 353 { "user-class", TOK_USER_CLASS }, 354 { "vendor-class", TOK_VENDOR_CLASS } 355 }; 356 357 int 358 kw_cmp(const void *k, const void *e) 359 { 360 return (strcasecmp(k, ((const struct keywords *)e)->k_name)); 361 } 362 363 static int 364 intern(char *atom, int dfv) 365 { 366 const struct keywords *p; 367 368 p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]), 369 sizeof(keywords[0]), kw_cmp); 370 if (p) 371 return (p->k_val); 372 return (dfv); 373 } 374