]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/dhclient/conflex.c
MFV r326785: 8880 improve DTrace error checking
[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 char *tlname;
59 int eol_token;
60
61 static char line1[81];
62 static char line2[81];
63 static int lpos;
64 static int 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(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     i, c, bs = 0;
232
233         for (i = 0; i < sizeof(tokbuf); i++) {
234                 c = get_char(cfile);
235                 if (c == EOF) {
236                         parse_warn("eof in string constant");
237                         break;
238                 }
239                 if (bs) {
240                         bs = 0;
241                         i--;
242                         tokbuf[i] = c;
243                 } else if (c == '\\')
244                         bs = 1;
245                 else if (c == '"')
246                         break;
247                 else
248                         tokbuf[i] = c;
249         }
250         /*
251          * Normally, I'd feel guilty about this, but we're talking about
252          * strings that'll fit in a DHCP packet here...
253          */
254         if (i == sizeof(tokbuf)) {
255                 parse_warn("string constant larger than internal buffer");
256                 i--;
257         }
258         tokbuf[i] = 0;
259         tval = tokbuf;
260         return (STRING);
261 }
262
263 static int
264 read_number(int c, FILE *cfile)
265 {
266         int     seenx = 0, i = 0, token = NUMBER;
267
268         tokbuf[i++] = c;
269         for (; i < sizeof(tokbuf); i++) {
270                 c = get_char(cfile);
271                 if (!seenx && c == 'x')
272                         seenx = 1;
273                 else if (!isascii(c) || !isxdigit(c)) {
274                         ungetc(c, cfile);
275                         ugflag = 1;
276                         break;
277                 }
278                 tokbuf[i] = c;
279         }
280         if (i == sizeof(tokbuf)) {
281                 parse_warn("numeric token larger than internal buffer");
282                 i--;
283         }
284         tokbuf[i] = 0;
285         tval = tokbuf;
286
287         return (token);
288 }
289
290 static int
291 read_num_or_name(int c, FILE *cfile)
292 {
293         int     i = 0;
294         int     rv = NUMBER_OR_NAME;
295
296         tokbuf[i++] = c;
297         for (; i < sizeof(tokbuf); i++) {
298                 c = get_char(cfile);
299                 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
300                         ungetc(c, cfile);
301                         ugflag = 1;
302                         break;
303                 }
304                 if (!isxdigit(c))
305                         rv = NAME;
306                 tokbuf[i] = c;
307         }
308         if (i == sizeof(tokbuf)) {
309                 parse_warn("token larger than internal buffer");
310                 i--;
311         }
312         tokbuf[i] = 0;
313         tval = tokbuf;
314
315         return (intern(tval, rv));
316 }
317
318 static int
319 intern(char *atom, int dfv)
320 {
321         if (!isascii(atom[0]))
322                 return (dfv);
323
324         switch (tolower(atom[0])) {
325         case 'a':
326                 if (!strcasecmp(atom + 1, "lways-reply-rfc1048"))
327                         return (ALWAYS_REPLY_RFC1048);
328                 if (!strcasecmp(atom + 1, "ppend"))
329                         return (APPEND);
330                 if (!strcasecmp(atom + 1, "llow"))
331                         return (ALLOW);
332                 if (!strcasecmp(atom + 1, "lias"))
333                         return (ALIAS);
334                 if (!strcasecmp(atom + 1, "bandoned"))
335                         return (ABANDONED);
336                 if (!strcasecmp(atom + 1, "uthoritative"))
337                         return (AUTHORITATIVE);
338                 break;
339         case 'b':
340                 if (!strcasecmp(atom + 1, "ackoff-cutoff"))
341                         return (BACKOFF_CUTOFF);
342                 if (!strcasecmp(atom + 1, "ootp"))
343                         return (BOOTP);
344                 if (!strcasecmp(atom + 1, "ooting"))
345                         return (BOOTING);
346                 if (!strcasecmp(atom + 1, "oot-unknown-clients"))
347                         return (BOOT_UNKNOWN_CLIENTS);
348         case 'c':
349                 if (!strcasecmp(atom + 1, "lass"))
350                         return (CLASS);
351                 if (!strcasecmp(atom + 1, "iaddr"))
352                         return (CIADDR);
353                 if (!strcasecmp(atom + 1, "lient-identifier"))
354                         return (CLIENT_IDENTIFIER);
355                 if (!strcasecmp(atom + 1, "lient-hostname"))
356                         return (CLIENT_HOSTNAME);
357                 break;
358         case 'd':
359                 if (!strcasecmp(atom + 1, "omain"))
360                         return (DOMAIN);
361                 if (!strcasecmp(atom + 1, "eny"))
362                         return (DENY);
363                 if (!strncasecmp(atom + 1, "efault", 6)) {
364                         if (!atom[7])
365                                 return (DEFAULT);
366                         if (!strcasecmp(atom + 7, "-lease-time"))
367                                 return (DEFAULT_LEASE_TIME);
368                         break;
369                 }
370                 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) {
371                         if (!atom[13])
372                                 return (DYNAMIC_BOOTP);
373                         if (!strcasecmp(atom + 13, "-lease-cutoff"))
374                                 return (DYNAMIC_BOOTP_LEASE_CUTOFF);
375                         if (!strcasecmp(atom + 13, "-lease-length"))
376                                 return (DYNAMIC_BOOTP_LEASE_LENGTH);
377                         break;
378                 }
379                 break;
380         case 'e':
381                 if (!strcasecmp(atom + 1, "thernet"))
382                         return (ETHERNET);
383                 if (!strcasecmp(atom + 1, "nds"))
384                         return (ENDS);
385                 if (!strcasecmp(atom + 1, "xpire"))
386                         return (EXPIRE);
387                 break;
388         case 'f':
389                 if (!strcasecmp(atom + 1, "ilename"))
390                         return (FILENAME);
391                 if (!strcasecmp(atom + 1, "ixed-address"))
392                         return (FIXED_ADDR);
393                 if (!strcasecmp(atom + 1, "ddi"))
394                         return (FDDI);
395                 break;
396         case 'g':
397                 if (!strcasecmp(atom + 1, "iaddr"))
398                         return (GIADDR);
399                 if (!strcasecmp(atom + 1, "roup"))
400                         return (GROUP);
401                 if (!strcasecmp(atom + 1, "et-lease-hostnames"))
402                         return (GET_LEASE_HOSTNAMES);
403                 break;
404         case 'h':
405                 if (!strcasecmp(atom + 1, "ost"))
406                         return (HOST);
407                 if (!strcasecmp(atom + 1, "ardware"))
408                         return (HARDWARE);
409                 if (!strcasecmp(atom + 1, "ostname"))
410                         return (HOSTNAME);
411                 break;
412         case 'i':
413                 if (!strcasecmp(atom + 1, "nitial-interval"))
414                         return (INITIAL_INTERVAL);
415                 if (!strcasecmp(atom + 1, "nterface"))
416                         return (INTERFACE);
417                 break;
418         case 'l':
419                 if (!strcasecmp(atom + 1, "ease"))
420                         return (LEASE);
421                 break;
422         case 'm':
423                 if (!strcasecmp(atom + 1, "ax-lease-time"))
424                         return (MAX_LEASE_TIME);
425                 if (!strncasecmp(atom + 1, "edi", 3)) {
426                         if (!strcasecmp(atom + 4, "a"))
427                                 return (MEDIA);
428                         if (!strcasecmp(atom + 4, "um"))
429                                 return (MEDIUM);
430                         break;
431                 }
432                 break;
433         case 'n':
434                 if (!strcasecmp(atom + 1, "ameserver"))
435                         return (NAMESERVER);
436                 if (!strcasecmp(atom + 1, "etmask"))
437                         return (NETMASK);
438                 if (!strcasecmp(atom + 1, "ext-server"))
439                         return (NEXT_SERVER);
440                 if (!strcasecmp(atom + 1, "ot"))
441                         return (TOKEN_NOT);
442                 break;
443         case 'o':
444                 if (!strcasecmp(atom + 1, "ption"))
445                         return (OPTION);
446                 if (!strcasecmp(atom + 1, "ne-lease-per-client"))
447                         return (ONE_LEASE_PER_CLIENT);
448                 break;
449         case 'p':
450                 if (!strcasecmp(atom + 1, "repend"))
451                         return (PREPEND);
452                 if (!strcasecmp(atom + 1, "acket"))
453                         return (PACKET);
454                 break;
455         case 'r':
456                 if (!strcasecmp(atom + 1, "ange"))
457                         return (RANGE);
458                 if (!strcasecmp(atom + 1, "equest"))
459                         return (REQUEST);
460                 if (!strcasecmp(atom + 1, "equire"))
461                         return (REQUIRE);
462                 if (!strcasecmp(atom + 1, "etry"))
463                         return (RETRY);
464                 if (!strcasecmp(atom + 1, "enew"))
465                         return (RENEW);
466                 if (!strcasecmp(atom + 1, "ebind"))
467                         return (REBIND);
468                 if (!strcasecmp(atom + 1, "eboot"))
469                         return (REBOOT);
470                 if (!strcasecmp(atom + 1, "eject"))
471                         return (REJECT);
472                 break;
473         case 's':
474                 if (!strcasecmp(atom + 1, "earch"))
475                         return (SEARCH);
476                 if (!strcasecmp(atom + 1, "tarts"))
477                         return (STARTS);
478                 if (!strcasecmp(atom + 1, "iaddr"))
479                         return (SIADDR);
480                 if (!strcasecmp(atom + 1, "ubnet"))
481                         return (SUBNET);
482                 if (!strcasecmp(atom + 1, "hared-network"))
483                         return (SHARED_NETWORK);
484                 if (!strcasecmp(atom + 1, "erver-name"))
485                         return (SERVER_NAME);
486                 if (!strcasecmp(atom + 1, "erver-identifier"))
487                         return (SERVER_IDENTIFIER);
488                 if (!strcasecmp(atom + 1, "elect-timeout"))
489                         return (SELECT_TIMEOUT);
490                 if (!strcasecmp(atom + 1, "end"))
491                         return (SEND);
492                 if (!strcasecmp(atom + 1, "cript"))
493                         return (SCRIPT);
494                 if (!strcasecmp(atom + 1, "upersede"))
495                         return (SUPERSEDE);
496                 break;
497         case 't':
498                 if (!strcasecmp(atom + 1, "imestamp"))
499                         return (TIMESTAMP);
500                 if (!strcasecmp(atom + 1, "imeout"))
501                         return (TIMEOUT);
502                 if (!strcasecmp(atom + 1, "oken-ring"))
503                         return (TOKEN_RING);
504                 break;
505         case 'u':
506                 if (!strncasecmp(atom + 1, "se", 2)) {
507                         if (!strcasecmp(atom + 3, "r-class"))
508                                 return (USER_CLASS);
509                         if (!strcasecmp(atom + 3, "-host-decl-names"))
510                                 return (USE_HOST_DECL_NAMES);
511                         if (!strcasecmp(atom + 3,
512                                          "-lease-addr-for-default-route"))
513                                 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE);
514                         break;
515                 }
516                 if (!strcasecmp(atom + 1, "id"))
517                         return (UID);
518                 if (!strcasecmp(atom + 1, "nknown-clients"))
519                         return (UNKNOWN_CLIENTS);
520                 break;
521         case 'v':
522                 if (!strcasecmp(atom + 1, "endor-class"))
523                         return (VENDOR_CLASS);
524                 break;
525         case 'y':
526                 if (!strcasecmp(atom + 1, "iaddr"))
527                         return (YIADDR);
528                 break;
529         }
530         return (dfv);
531 }