]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/dhclient/conflex.c
Upgrade Unbound to 1.7.1.
[FreeBSD/FreeBSD.git] / sbin / dhclient / conflex.c
1 /*      $OpenBSD: conflex.c,v 1.7 2004/09/15 19:02:38 deraadt Exp $     */
2
3 /* Lexical scanner for dhcpd config file... */
4
5 /*-
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of The Internet Software Consortium nor the names
21  *    of its contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
25  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
32  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * This software has been written for the Internet Software Consortium
39  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
40  * Enterprises.  To learn more about the Internet Software Consortium,
41  * see ``http://www.vix.com/isc''.  To learn more about Vixie
42  * Enterprises, see ``http://www.vix.com''.
43  */
44
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47
48 #include <ctype.h>
49
50 #include "dhcpd.h"
51 #include "dhctoken.h"
52
53 int lexline;
54 int lexchar;
55 char *token_line;
56 char *prev_line;
57 char *cur_line;
58 const char *tlname;
59 int eol_token;
60
61 static char line1[81];
62 static char line2[81];
63 static unsigned lpos;
64 static unsigned line;
65 static int tlpos;
66 static int tline;
67 static int token;
68 static int ugflag;
69 static char *tval;
70 static char tokbuf[1500];
71
72 static int get_char(FILE *);
73 static int get_token(FILE *);
74 static void skip_to_eol(FILE *);
75 static int read_string(FILE *);
76 static int read_number(int, FILE *);
77 static int read_num_or_name(int, FILE *);
78 static int intern(char *, int);
79
80 void
81 new_parse(const char *name)
82 {
83         tlname = name;
84         lpos = line = 1;
85         cur_line = line1;
86         prev_line = line2;
87         token_line = cur_line;
88         cur_line[0] = prev_line[0] = 0;
89         warnings_occurred = 0;
90 }
91
92 static int
93 get_char(FILE *cfile)
94 {
95         int c = getc(cfile);
96         if (!ugflag) {
97                 if (c == '\n') {
98                         if (cur_line == line1) {
99                                 cur_line = line2;
100                                 prev_line = line1;
101                         } else {
102                                 cur_line = line1;
103                                 prev_line = line2;
104                         }
105                         line++;
106                         lpos = 1;
107                         cur_line[0] = 0;
108                 } else if (c != EOF) {
109                         if (lpos < sizeof(line1)) {
110                                 cur_line[lpos - 1] = c;
111                                 cur_line[lpos] = 0;
112                         }
113                         lpos++;
114                 }
115         } else
116                 ugflag = 0;
117         return (c);
118 }
119
120 static int
121 get_token(FILE *cfile)
122 {
123         int             c, ttok;
124         static char     tb[2];
125         int             l, p;
126
127         do {
128                 l = line;
129                 p = lpos;
130
131                 c = get_char(cfile);
132
133                 if (!(c == '\n' && eol_token) && isascii(c) && isspace(c))
134                         continue;
135                 if (c == '#') {
136                         skip_to_eol(cfile);
137                         continue;
138                 }
139                 if (c == '"') {
140                         lexline = l;
141                         lexchar = p;
142                         ttok = read_string(cfile);
143                         break;
144                 }
145                 if ((isascii(c) && isdigit(c)) || c == '-') {
146                         lexline = l;
147                         lexchar = p;
148                         ttok = read_number(c, cfile);
149                         break;
150                 } else if (isascii(c) && isalpha(c)) {
151                         lexline = l;
152                         lexchar = p;
153                         ttok = read_num_or_name(c, cfile);
154                         break;
155                 } else {
156                         lexline = l;
157                         lexchar = p;
158                         tb[0] = c;
159                         tb[1] = 0;
160                         tval = tb;
161                         ttok = c;
162                         break;
163                 }
164         } while (1);
165         return (ttok);
166 }
167
168 int
169 next_token(char **rval, FILE *cfile)
170 {
171         int     rv;
172
173         if (token) {
174                 if (lexline != tline)
175                         token_line = cur_line;
176                 lexchar = tlpos;
177                 lexline = tline;
178                 rv = token;
179                 token = 0;
180         } else {
181                 rv = get_token(cfile);
182                 token_line = cur_line;
183         }
184         if (rval)
185                 *rval = tval;
186
187         return (rv);
188 }
189
190 int
191 peek_token(char **rval, FILE *cfile)
192 {
193         int     x;
194
195         if (!token) {
196                 tlpos = lexchar;
197                 tline = lexline;
198                 token = get_token(cfile);
199                 if (lexline != tline)
200                         token_line = prev_line;
201                 x = lexchar;
202                 lexchar = tlpos;
203                 tlpos = x;
204                 x = lexline;
205                 lexline = tline;
206                 tline = x;
207         }
208         if (rval)
209                 *rval = tval;
210
211         return (token);
212 }
213
214 static void
215 skip_to_eol(FILE *cfile)
216 {
217         int     c;
218
219         do {
220                 c = get_char(cfile);
221                 if (c == EOF)
222                         return;
223                 if (c == '\n')
224                         return;
225         } while (1);
226 }
227
228 static int
229 read_string(FILE *cfile)
230 {
231         int     c, bs = 0;
232         unsigned i;
233
234         for (i = 0; i < sizeof(tokbuf); i++) {
235                 c = get_char(cfile);
236                 if (c == EOF) {
237                         parse_warn("eof in string constant");
238                         break;
239                 }
240                 if (bs) {
241                         bs = 0;
242                         i--;
243                         tokbuf[i] = c;
244                 } else if (c == '\\')
245                         bs = 1;
246                 else if (c == '"')
247                         break;
248                 else
249                         tokbuf[i] = c;
250         }
251         /*
252          * Normally, I'd feel guilty about this, but we're talking about
253          * strings that'll fit in a DHCP packet here...
254          */
255         if (i == sizeof(tokbuf)) {
256                 parse_warn("string constant larger than internal buffer");
257                 i--;
258         }
259         tokbuf[i] = 0;
260         tval = tokbuf;
261         return (STRING);
262 }
263
264 static int
265 read_number(int c, FILE *cfile)
266 {
267         int     seenx = 0, _token = NUMBER;
268         unsigned i = 0;
269
270         tokbuf[i++] = c;
271         for (; i < sizeof(tokbuf); i++) {
272                 c = get_char(cfile);
273                 if (!seenx && c == 'x')
274                         seenx = 1;
275                 else if (!isascii(c) || !isxdigit(c)) {
276                         ungetc(c, cfile);
277                         ugflag = 1;
278                         break;
279                 }
280                 tokbuf[i] = c;
281         }
282         if (i == sizeof(tokbuf)) {
283                 parse_warn("numeric token larger than internal buffer");
284                 i--;
285         }
286         tokbuf[i] = 0;
287         tval = tokbuf;
288
289         return (_token);
290 }
291
292 static int
293 read_num_or_name(int c, FILE *cfile)
294 {
295         unsigned i = 0;
296         int     rv = NUMBER_OR_NAME;
297
298         tokbuf[i++] = c;
299         for (; i < sizeof(tokbuf); i++) {
300                 c = get_char(cfile);
301                 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
302                         ungetc(c, cfile);
303                         ugflag = 1;
304                         break;
305                 }
306                 if (!isxdigit(c))
307                         rv = NAME;
308                 tokbuf[i] = c;
309         }
310         if (i == sizeof(tokbuf)) {
311                 parse_warn("token larger than internal buffer");
312                 i--;
313         }
314         tokbuf[i] = 0;
315         tval = tokbuf;
316
317         return (intern(tval, rv));
318 }
319
320 static int
321 intern(char *atom, int dfv)
322 {
323         if (!isascii(atom[0]))
324                 return (dfv);
325
326         switch (tolower(atom[0])) {
327         case 'a':
328                 if (!strcasecmp(atom + 1, "lways-reply-rfc1048"))
329                         return (ALWAYS_REPLY_RFC1048);
330                 if (!strcasecmp(atom + 1, "ppend"))
331                         return (APPEND);
332                 if (!strcasecmp(atom + 1, "llow"))
333                         return (ALLOW);
334                 if (!strcasecmp(atom + 1, "lias"))
335                         return (ALIAS);
336                 if (!strcasecmp(atom + 1, "bandoned"))
337                         return (ABANDONED);
338                 if (!strcasecmp(atom + 1, "uthoritative"))
339                         return (AUTHORITATIVE);
340                 break;
341         case 'b':
342                 if (!strcasecmp(atom + 1, "ackoff-cutoff"))
343                         return (BACKOFF_CUTOFF);
344                 if (!strcasecmp(atom + 1, "ootp"))
345                         return (BOOTP);
346                 if (!strcasecmp(atom + 1, "ooting"))
347                         return (BOOTING);
348                 if (!strcasecmp(atom + 1, "oot-unknown-clients"))
349                         return (BOOT_UNKNOWN_CLIENTS);
350         case 'c':
351                 if (!strcasecmp(atom + 1, "lass"))
352                         return (CLASS);
353                 if (!strcasecmp(atom + 1, "iaddr"))
354                         return (CIADDR);
355                 if (!strcasecmp(atom + 1, "lient-identifier"))
356                         return (CLIENT_IDENTIFIER);
357                 if (!strcasecmp(atom + 1, "lient-hostname"))
358                         return (CLIENT_HOSTNAME);
359                 break;
360         case 'd':
361                 if (!strcasecmp(atom + 1, "omain"))
362                         return (DOMAIN);
363                 if (!strcasecmp(atom + 1, "eny"))
364                         return (DENY);
365                 if (!strncasecmp(atom + 1, "efault", 6)) {
366                         if (!atom[7])
367                                 return (DEFAULT);
368                         if (!strcasecmp(atom + 7, "-lease-time"))
369                                 return (DEFAULT_LEASE_TIME);
370                         break;
371                 }
372                 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) {
373                         if (!atom[13])
374                                 return (DYNAMIC_BOOTP);
375                         if (!strcasecmp(atom + 13, "-lease-cutoff"))
376                                 return (DYNAMIC_BOOTP_LEASE_CUTOFF);
377                         if (!strcasecmp(atom + 13, "-lease-length"))
378                                 return (DYNAMIC_BOOTP_LEASE_LENGTH);
379                         break;
380                 }
381                 break;
382         case 'e':
383                 if (!strcasecmp(atom + 1, "thernet"))
384                         return (ETHERNET);
385                 if (!strcasecmp(atom + 1, "nds"))
386                         return (ENDS);
387                 if (!strcasecmp(atom + 1, "xpire"))
388                         return (EXPIRE);
389                 break;
390         case 'f':
391                 if (!strcasecmp(atom + 1, "ilename"))
392                         return (FILENAME);
393                 if (!strcasecmp(atom + 1, "ixed-address"))
394                         return (FIXED_ADDR);
395                 if (!strcasecmp(atom + 1, "ddi"))
396                         return (FDDI);
397                 break;
398         case 'g':
399                 if (!strcasecmp(atom + 1, "iaddr"))
400                         return (GIADDR);
401                 if (!strcasecmp(atom + 1, "roup"))
402                         return (GROUP);
403                 if (!strcasecmp(atom + 1, "et-lease-hostnames"))
404                         return (GET_LEASE_HOSTNAMES);
405                 break;
406         case 'h':
407                 if (!strcasecmp(atom + 1, "ost"))
408                         return (HOST);
409                 if (!strcasecmp(atom + 1, "ardware"))
410                         return (HARDWARE);
411                 if (!strcasecmp(atom + 1, "ostname"))
412                         return (HOSTNAME);
413                 break;
414         case 'i':
415                 if (!strcasecmp(atom + 1, "nitial-interval"))
416                         return (INITIAL_INTERVAL);
417                 if (!strcasecmp(atom + 1, "nterface"))
418                         return (INTERFACE);
419                 break;
420         case 'l':
421                 if (!strcasecmp(atom + 1, "ease"))
422                         return (LEASE);
423                 break;
424         case 'm':
425                 if (!strcasecmp(atom + 1, "ax-lease-time"))
426                         return (MAX_LEASE_TIME);
427                 if (!strncasecmp(atom + 1, "edi", 3)) {
428                         if (!strcasecmp(atom + 4, "a"))
429                                 return (MEDIA);
430                         if (!strcasecmp(atom + 4, "um"))
431                                 return (MEDIUM);
432                         break;
433                 }
434                 break;
435         case 'n':
436                 if (!strcasecmp(atom + 1, "ameserver"))
437                         return (NAMESERVER);
438                 if (!strcasecmp(atom + 1, "etmask"))
439                         return (NETMASK);
440                 if (!strcasecmp(atom + 1, "ext-server"))
441                         return (NEXT_SERVER);
442                 if (!strcasecmp(atom + 1, "ot"))
443                         return (TOKEN_NOT);
444                 break;
445         case 'o':
446                 if (!strcasecmp(atom + 1, "ption"))
447                         return (OPTION);
448                 if (!strcasecmp(atom + 1, "ne-lease-per-client"))
449                         return (ONE_LEASE_PER_CLIENT);
450                 break;
451         case 'p':
452                 if (!strcasecmp(atom + 1, "repend"))
453                         return (PREPEND);
454                 if (!strcasecmp(atom + 1, "acket"))
455                         return (PACKET);
456                 break;
457         case 'r':
458                 if (!strcasecmp(atom + 1, "ange"))
459                         return (RANGE);
460                 if (!strcasecmp(atom + 1, "equest"))
461                         return (REQUEST);
462                 if (!strcasecmp(atom + 1, "equire"))
463                         return (REQUIRE);
464                 if (!strcasecmp(atom + 1, "etry"))
465                         return (RETRY);
466                 if (!strcasecmp(atom + 1, "enew"))
467                         return (RENEW);
468                 if (!strcasecmp(atom + 1, "ebind"))
469                         return (REBIND);
470                 if (!strcasecmp(atom + 1, "eboot"))
471                         return (REBOOT);
472                 if (!strcasecmp(atom + 1, "eject"))
473                         return (REJECT);
474                 break;
475         case 's':
476                 if (!strcasecmp(atom + 1, "earch"))
477                         return (SEARCH);
478                 if (!strcasecmp(atom + 1, "tarts"))
479                         return (STARTS);
480                 if (!strcasecmp(atom + 1, "iaddr"))
481                         return (SIADDR);
482                 if (!strcasecmp(atom + 1, "ubnet"))
483                         return (SUBNET);
484                 if (!strcasecmp(atom + 1, "hared-network"))
485                         return (SHARED_NETWORK);
486                 if (!strcasecmp(atom + 1, "erver-name"))
487                         return (SERVER_NAME);
488                 if (!strcasecmp(atom + 1, "erver-identifier"))
489                         return (SERVER_IDENTIFIER);
490                 if (!strcasecmp(atom + 1, "elect-timeout"))
491                         return (SELECT_TIMEOUT);
492                 if (!strcasecmp(atom + 1, "end"))
493                         return (SEND);
494                 if (!strcasecmp(atom + 1, "cript"))
495                         return (SCRIPT);
496                 if (!strcasecmp(atom + 1, "upersede"))
497                         return (SUPERSEDE);
498                 break;
499         case 't':
500                 if (!strcasecmp(atom + 1, "imestamp"))
501                         return (TIMESTAMP);
502                 if (!strcasecmp(atom + 1, "imeout"))
503                         return (TIMEOUT);
504                 if (!strcasecmp(atom + 1, "oken-ring"))
505                         return (TOKEN_RING);
506                 break;
507         case 'u':
508                 if (!strncasecmp(atom + 1, "se", 2)) {
509                         if (!strcasecmp(atom + 3, "r-class"))
510                                 return (USER_CLASS);
511                         if (!strcasecmp(atom + 3, "-host-decl-names"))
512                                 return (USE_HOST_DECL_NAMES);
513                         if (!strcasecmp(atom + 3,
514                                          "-lease-addr-for-default-route"))
515                                 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE);
516                         break;
517                 }
518                 if (!strcasecmp(atom + 1, "id"))
519                         return (UID);
520                 if (!strcasecmp(atom + 1, "nknown-clients"))
521                         return (UNKNOWN_CLIENTS);
522                 break;
523         case 'v':
524                 if (!strcasecmp(atom + 1, "endor-class"))
525                         return (VENDOR_CLASS);
526                 break;
527         case 'y':
528                 if (!strcasecmp(atom + 1, "iaddr"))
529                         return (YIADDR);
530                 break;
531         }
532         return (dfv);
533 }