]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/dhclient/conflex.c
Fix ure device driver susceptible to packet-in-packet attack.
[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  * 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/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include <ctype.h>
47
48 #include "dhcpd.h"
49 #include "dhctoken.h"
50
51 int lexline;
52 int lexchar;
53 char *token_line;
54 char *prev_line;
55 char *cur_line;
56 const char *tlname;
57 int eol_token;
58
59 static char line1[81];
60 static char line2[81];
61 static unsigned lpos;
62 static unsigned line;
63 static int tlpos;
64 static int tline;
65 static int token;
66 static int ugflag;
67 static char *tval;
68 static char tokbuf[1500];
69
70 static int get_char(FILE *);
71 static int get_token(FILE *);
72 static void skip_to_eol(FILE *);
73 static int read_string(FILE *);
74 static int read_number(int, FILE *);
75 static int read_num_or_name(int, FILE *);
76 static int intern(char *, int);
77
78 void
79 new_parse(const char *name)
80 {
81         tlname = name;
82         lpos = line = 1;
83         cur_line = line1;
84         prev_line = line2;
85         token_line = cur_line;
86         cur_line[0] = prev_line[0] = 0;
87         warnings_occurred = 0;
88 }
89
90 static int
91 get_char(FILE *cfile)
92 {
93         int c = getc(cfile);
94         if (!ugflag) {
95                 if (c == '\n') {
96                         if (cur_line == line1) {
97                                 cur_line = line2;
98                                 prev_line = line1;
99                         } else {
100                                 cur_line = line1;
101                                 prev_line = line2;
102                         }
103                         line++;
104                         lpos = 1;
105                         cur_line[0] = 0;
106                 } else if (c != EOF) {
107                         if (lpos < sizeof(line1)) {
108                                 cur_line[lpos - 1] = c;
109                                 cur_line[lpos] = 0;
110                         }
111                         lpos++;
112                 }
113         } else
114                 ugflag = 0;
115         return (c);
116 }
117
118 static int
119 get_token(FILE *cfile)
120 {
121         int             c, ttok;
122         static char     tb[2];
123         int             l, p;
124
125         do {
126                 l = line;
127                 p = lpos;
128
129                 c = get_char(cfile);
130
131                 if (!(c == '\n' && eol_token) && isascii(c) && isspace(c))
132                         continue;
133                 if (c == '#') {
134                         skip_to_eol(cfile);
135                         continue;
136                 }
137                 if (c == '"') {
138                         lexline = l;
139                         lexchar = p;
140                         ttok = read_string(cfile);
141                         break;
142                 }
143                 if ((isascii(c) && isdigit(c)) || c == '-') {
144                         lexline = l;
145                         lexchar = p;
146                         ttok = read_number(c, cfile);
147                         break;
148                 } else if (isascii(c) && isalpha(c)) {
149                         lexline = l;
150                         lexchar = p;
151                         ttok = read_num_or_name(c, cfile);
152                         break;
153                 } else {
154                         lexline = l;
155                         lexchar = p;
156                         tb[0] = c;
157                         tb[1] = 0;
158                         tval = tb;
159                         ttok = c;
160                         break;
161                 }
162         } while (1);
163         return (ttok);
164 }
165
166 int
167 next_token(char **rval, FILE *cfile)
168 {
169         int     rv;
170
171         if (token) {
172                 if (lexline != tline)
173                         token_line = cur_line;
174                 lexchar = tlpos;
175                 lexline = tline;
176                 rv = token;
177                 token = 0;
178         } else {
179                 rv = get_token(cfile);
180                 token_line = cur_line;
181         }
182         if (rval)
183                 *rval = tval;
184
185         return (rv);
186 }
187
188 int
189 peek_token(char **rval, FILE *cfile)
190 {
191         int     x;
192
193         if (!token) {
194                 tlpos = lexchar;
195                 tline = lexline;
196                 token = get_token(cfile);
197                 if (lexline != tline)
198                         token_line = prev_line;
199                 x = lexchar;
200                 lexchar = tlpos;
201                 tlpos = x;
202                 x = lexline;
203                 lexline = tline;
204                 tline = x;
205         }
206         if (rval)
207                 *rval = tval;
208
209         return (token);
210 }
211
212 static void
213 skip_to_eol(FILE *cfile)
214 {
215         int     c;
216
217         do {
218                 c = get_char(cfile);
219                 if (c == EOF)
220                         return;
221                 if (c == '\n')
222                         return;
223         } while (1);
224 }
225
226 static int
227 read_string(FILE *cfile)
228 {
229         int     c, bs = 0;
230         unsigned i;
231
232         for (i = 0; i < sizeof(tokbuf); i++) {
233                 c = get_char(cfile);
234                 if (c == EOF) {
235                         parse_warn("eof in string constant");
236                         break;
237                 }
238                 if (bs) {
239                         bs = 0;
240                         i--;
241                         tokbuf[i] = c;
242                 } else if (c == '\\')
243                         bs = 1;
244                 else if (c == '"')
245                         break;
246                 else
247                         tokbuf[i] = c;
248         }
249         /*
250          * Normally, I'd feel guilty about this, but we're talking about
251          * strings that'll fit in a DHCP packet here...
252          */
253         if (i == sizeof(tokbuf)) {
254                 parse_warn("string constant larger than internal buffer");
255                 i--;
256         }
257         tokbuf[i] = 0;
258         tval = tokbuf;
259         return (STRING);
260 }
261
262 static int
263 read_number(int c, FILE *cfile)
264 {
265         int     seenx = 0, _token = NUMBER;
266         unsigned i = 0;
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         unsigned 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 }