Merge branch 'vendor/PAM_PASSWDQC'
[dragonfly.git] / sbin / dhclient / conflex.c
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 }