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