xref: /dragonfly/sbin/dhclient/conflex.c (revision 04e4af026e4eda810ab1bdfeb37cba72b3c713e4)
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
new_parse(char * name)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
get_char(FILE * cfile)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
get_token(FILE * cfile)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
next_token(char ** rval,FILE * cfile)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
peek_token(char ** rval,FILE * cfile)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
skip_to_eol(FILE * cfile)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
read_string(FILE * cfile)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
read_number(int c,FILE * cfile)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
read_num_or_name(int c,FILE * cfile)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
kw_cmp(const void * k,const void * e)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
intern(char * atom,int dfv)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