]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/dhclient/parse.c
Import tzdata 2017c
[FreeBSD/FreeBSD.git] / sbin / dhclient / parse.c
1 /*      $OpenBSD: parse.c,v 1.11 2004/05/05 23:07:47 deraadt Exp $      */
2
3 /* Common parser code for dhcpd and dhclient. */
4
5 /*
6  * Copyright (c) 1995, 1996, 1997, 1998 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 "dhcpd.h"
47 #include "dhctoken.h"
48
49 /* Skip to the semicolon ending the current statement.   If we encounter
50  * braces, the matching closing brace terminates the statement.   If we
51  * encounter a right brace but haven't encountered a left brace, return
52  * leaving the brace in the token buffer for the caller.   If we see a
53  * semicolon and haven't seen a left brace, return.   This lets us skip
54  * over:
55  *
56  *      statement;
57  *      statement foo bar { }
58  *      statement foo bar { statement { } }
59  *      statement}
60  *
61  *      ...et cetera.
62  */
63 void
64 skip_to_semi(FILE *cfile)
65 {
66         int brace_count = 0, token;
67         char *val;
68
69         do {
70                 token = peek_token(&val, cfile);
71                 if (token == RBRACE) {
72                         if (brace_count) {
73                                 token = next_token(&val, cfile);
74                                 if (!--brace_count)
75                                         return;
76                         } else
77                                 return;
78                 } else if (token == LBRACE) {
79                         brace_count++;
80                 } else if (token == SEMI && !brace_count) {
81                         token = next_token(&val, cfile);
82                         return;
83                 } else if (token == '\n') {
84                         /*
85                          * EOL only happens when parsing
86                          * /etc/resolv.conf, and we treat it like a
87                          * semicolon because the resolv.conf file is
88                          * line-oriented.
89                          */
90                         token = next_token(&val, cfile);
91                         return;
92                 }
93                 token = next_token(&val, cfile);
94         } while (token != EOF);
95 }
96
97 int
98 parse_semi(FILE *cfile)
99 {
100         int token;
101         char *val;
102
103         token = next_token(&val, cfile);
104         if (token != SEMI) {
105                 parse_warn("semicolon expected.");
106                 skip_to_semi(cfile);
107                 return (0);
108         }
109         return (1);
110 }
111
112 /*
113  * string-parameter :== STRING SEMI
114  */
115 char *
116 parse_string(FILE *cfile)
117 {
118         char *val, *s;
119         size_t valsize;
120         int token;
121
122         token = next_token(&val, cfile);
123         if (token != STRING) {
124                 parse_warn("filename must be a string");
125                 skip_to_semi(cfile);
126                 return (NULL);
127         }
128         valsize = strlen(val) + 1;
129         s = malloc(valsize);
130         if (!s)
131                 error("no memory for string %s.", val);
132         memcpy(s, val, valsize);
133
134         if (!parse_semi(cfile)) {
135                 free(s);
136                 return (NULL);
137         }
138         return (s);
139 }
140
141 int
142 parse_ip_addr(FILE *cfile, struct iaddr *addr)
143 {
144         addr->len = 4;
145         if (parse_numeric_aggregate(cfile, addr->iabuf,
146             &addr->len, DOT, 10, 8))
147                 return (1);
148         return (0);
149 }
150
151 /*
152  * hardware-parameter :== HARDWARE ETHERNET csns SEMI
153  * csns :== NUMBER | csns COLON NUMBER
154  */
155 void
156 parse_hardware_param(FILE *cfile, struct hardware *hardware)
157 {
158         unsigned char *t;
159         int token, hlen;
160         char *val;
161
162         token = next_token(&val, cfile);
163         switch (token) {
164         case ETHERNET:
165                 hardware->htype = HTYPE_ETHER;
166                 break;
167         case TOKEN_RING:
168                 hardware->htype = HTYPE_IEEE802;
169                 break;
170         case FDDI:
171                 hardware->htype = HTYPE_FDDI;
172                 break;
173         default:
174                 parse_warn("expecting a network hardware type");
175                 skip_to_semi(cfile);
176                 return;
177         }
178
179         /*
180          * Parse the hardware address information.   Technically, it
181          * would make a lot of sense to restrict the length of the data
182          * we'll accept here to the length of a particular hardware
183          * address type.   Unfortunately, there are some broken clients
184          * out there that put bogus data in the chaddr buffer, and we
185          * accept that data in the lease file rather than simply failing
186          * on such clients.   Yuck.
187          */
188         hlen = 0;
189         t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
190         if (!t)
191                 return;
192         if (hlen > sizeof(hardware->haddr)) {
193                 free(t);
194                 parse_warn("hardware address too long");
195         } else {
196                 hardware->hlen = hlen;
197                 memcpy((unsigned char *)&hardware->haddr[0], t,
198                     hardware->hlen);
199                 if (hlen < sizeof(hardware->haddr))
200                         memset(&hardware->haddr[hlen], 0,
201                             sizeof(hardware->haddr) - hlen);
202                 free(t);
203         }
204
205         token = next_token(&val, cfile);
206         if (token != SEMI) {
207                 parse_warn("expecting semicolon.");
208                 skip_to_semi(cfile);
209         }
210 }
211
212 /*
213  * lease-time :== NUMBER SEMI
214  */
215 void
216 parse_lease_time(FILE *cfile, time_t *timep)
217 {
218         char *val;
219         int token;
220
221         token = next_token(&val, cfile);
222         if (token != NUMBER) {
223                 parse_warn("Expecting numeric lease time");
224                 skip_to_semi(cfile);
225                 return;
226         }
227         convert_num((unsigned char *)timep, val, 10, 32);
228         /* Unswap the number - convert_num returns stuff in NBO. */
229         *timep = ntohl(*timep); /* XXX */
230
231         parse_semi(cfile);
232 }
233
234 /*
235  * No BNF for numeric aggregates - that's defined by the caller.  What
236  * this function does is to parse a sequence of numbers separated by the
237  * token specified in separator.  If max is zero, any number of numbers
238  * will be parsed; otherwise, exactly max numbers are expected.  Base
239  * and size tell us how to internalize the numbers once they've been
240  * tokenized.
241  */
242 unsigned char *
243 parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
244     int separator, int base, int size)
245 {
246         unsigned char *bufp = buf, *s = NULL;
247         int token, count = 0;
248         char *val, *t;
249         size_t valsize;
250         pair c = NULL;
251         unsigned char *lbufp = NULL;
252
253         if (!bufp && *max) {
254                 lbufp = bufp = malloc(*max * size / 8);
255                 if (!bufp)
256                         error("can't allocate space for numeric aggregate");
257         } else
258                 s = bufp;
259
260         do {
261                 if (count) {
262                         token = peek_token(&val, cfile);
263                         if (token != separator) {
264                                 if (!*max)
265                                         break;
266                                 if (token != RBRACE && token != LBRACE)
267                                         token = next_token(&val, cfile);
268                                 parse_warn("too few numbers.");
269                                 if (token != SEMI)
270                                         skip_to_semi(cfile);
271                                 free(lbufp);
272                                 return (NULL);
273                         }
274                         token = next_token(&val, cfile);
275                 }
276                 token = next_token(&val, cfile);
277
278                 if (token == EOF) {
279                         parse_warn("unexpected end of file");
280                         break;
281                 }
282
283                 /* Allow NUMBER_OR_NAME if base is 16. */
284                 if (token != NUMBER &&
285                     (base != 16 || token != NUMBER_OR_NAME)) {
286                         parse_warn("expecting numeric value.");
287                         skip_to_semi(cfile);
288                         free(lbufp);
289                         return (NULL);
290                 }
291                 /*
292                  * If we can, convert the number now; otherwise, build a
293                  * linked list of all the numbers.
294                  */
295                 if (s) {
296                         convert_num(s, val, base, size);
297                         s += size / 8;
298                 } else {
299                         valsize = strlen(val) + 1;
300                         t = malloc(valsize);
301                         if (!t)
302                                 error("no temp space for number.");
303                         memcpy(t, val, valsize);
304                         c = cons(t, c);
305                 }
306         } while (++count != *max);
307
308         /* If we had to cons up a list, convert it now. */
309         if (c) {
310                 free(lbufp);
311                 bufp = malloc(count * size / 8);
312                 if (!bufp)
313                         error("can't allocate space for numeric aggregate.");
314                 s = bufp + count - size / 8;
315                 *max = count;
316         }
317         while (c) {
318                 pair cdr = c->cdr;
319                 convert_num(s, (char *)c->car, base, size);
320                 s -= size / 8;
321                 /* Free up temp space. */
322                 free(c->car);
323                 free(c);
324                 c = cdr;
325         }
326         return (bufp);
327 }
328
329 void
330 convert_num(unsigned char *buf, char *str, int base, int size)
331 {
332         int negative = 0, tval, max;
333         u_int32_t val = 0;
334         char *ptr = str;
335
336         if (*ptr == '-') {
337                 negative = 1;
338                 ptr++;
339         }
340
341         /* If base wasn't specified, figure it out from the data. */
342         if (!base) {
343                 if (ptr[0] == '0') {
344                         if (ptr[1] == 'x') {
345                                 base = 16;
346                                 ptr += 2;
347                         } else if (isascii(ptr[1]) && isdigit(ptr[1])) {
348                                 base = 8;
349                                 ptr += 1;
350                         } else
351                                 base = 10;
352                 } else
353                         base = 10;
354         }
355
356         do {
357                 tval = *ptr++;
358                 /* XXX assumes ASCII... */
359                 if (tval >= 'a')
360                         tval = tval - 'a' + 10;
361                 else if (tval >= 'A')
362                         tval = tval - 'A' + 10;
363                 else if (tval >= '0')
364                         tval -= '0';
365                 else {
366                         warning("Bogus number: %s.", str);
367                         break;
368                 }
369                 if (tval >= base) {
370                         warning("Bogus number: %s: digit %d not in base %d",
371                             str, tval, base);
372                         break;
373                 }
374                 val = val * base + tval;
375         } while (*ptr);
376
377         if (negative)
378                 max = (1 << (size - 1));
379         else
380                 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
381         if (val > max) {
382                 switch (base) {
383                 case 8:
384                         warning("value %s%o exceeds max (%d) for precision.",
385                             negative ? "-" : "", val, max);
386                         break;
387                 case 16:
388                         warning("value %s%x exceeds max (%d) for precision.",
389                             negative ? "-" : "", val, max);
390                         break;
391                 default:
392                         warning("value %s%u exceeds max (%d) for precision.",
393                             negative ? "-" : "", val, max);
394                         break;
395                 }
396         }
397
398         if (negative)
399                 switch (size) {
400                 case 8:
401                         *buf = -(unsigned long)val;
402                         break;
403                 case 16:
404                         putShort(buf, -(unsigned long)val);
405                         break;
406                 case 32:
407                         putLong(buf, -(unsigned long)val);
408                         break;
409                 default:
410                         warning("Unexpected integer size: %d", size);
411                         break;
412                 }
413         else
414                 switch (size) {
415                 case 8:
416                         *buf = (u_int8_t)val;
417                         break;
418                 case 16:
419                         putUShort(buf, (u_int16_t)val);
420                         break;
421                 case 32:
422                         putULong(buf, val);
423                         break;
424                 default:
425                         warning("Unexpected integer size: %d", size);
426                         break;
427                 }
428 }
429
430 /*
431  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
432  *              NUMBER COLON NUMBER COLON NUMBER SEMI
433  *
434  * Dates are always in GMT; first number is day of week; next is
435  * year/month/day; next is hours:minutes:seconds on a 24-hour
436  * clock.
437  */
438 time_t
439 parse_date(FILE *cfile)
440 {
441         static int months[11] = { 31, 59, 90, 120, 151, 181,
442             212, 243, 273, 304, 334 };
443         int guess, token;
444         struct tm tm;
445         char *val;
446
447         /* Day of week... */
448         token = next_token(&val, cfile);
449         if (token != NUMBER) {
450                 parse_warn("numeric day of week expected.");
451                 if (token != SEMI)
452                         skip_to_semi(cfile);
453                 return (0);
454         }
455         tm.tm_wday = atoi(val);
456
457         /* Year... */
458         token = next_token(&val, cfile);
459         if (token != NUMBER) {
460                 parse_warn("numeric year expected.");
461                 if (token != SEMI)
462                         skip_to_semi(cfile);
463                 return (0);
464         }
465         tm.tm_year = atoi(val);
466         if (tm.tm_year > 1900)
467                 tm.tm_year -= 1900;
468
469         /* Slash separating year from month... */
470         token = next_token(&val, cfile);
471         if (token != SLASH) {
472                 parse_warn("expected slash separating year from month.");
473                 if (token != SEMI)
474                         skip_to_semi(cfile);
475                 return (0);
476         }
477
478         /* Month... */
479         token = next_token(&val, cfile);
480         if (token != NUMBER) {
481                 parse_warn("numeric month expected.");
482                 if (token != SEMI)
483                         skip_to_semi(cfile);
484                 return (0);
485         }
486         tm.tm_mon = atoi(val) - 1;
487
488         /* Slash separating month from day... */
489         token = next_token(&val, cfile);
490         if (token != SLASH) {
491                 parse_warn("expected slash separating month from day.");
492                 if (token != SEMI)
493                         skip_to_semi(cfile);
494                 return (0);
495         }
496
497         /* Month... */
498         token = next_token(&val, cfile);
499         if (token != NUMBER) {
500                 parse_warn("numeric day of month expected.");
501                 if (token != SEMI)
502                         skip_to_semi(cfile);
503                 return (0);
504         }
505         tm.tm_mday = atoi(val);
506
507         /* Hour... */
508         token = next_token(&val, cfile);
509         if (token != NUMBER) {
510                 parse_warn("numeric hour expected.");
511                 if (token != SEMI)
512                         skip_to_semi(cfile);
513                 return (0);
514         }
515         tm.tm_hour = atoi(val);
516
517         /* Colon separating hour from minute... */
518         token = next_token(&val, cfile);
519         if (token != COLON) {
520                 parse_warn("expected colon separating hour from minute.");
521                 if (token != SEMI)
522                         skip_to_semi(cfile);
523                 return (0);
524         }
525
526         /* Minute... */
527         token = next_token(&val, cfile);
528         if (token != NUMBER) {
529                 parse_warn("numeric minute expected.");
530                 if (token != SEMI)
531                         skip_to_semi(cfile);
532                 return (0);
533         }
534         tm.tm_min = atoi(val);
535
536         /* Colon separating minute from second... */
537         token = next_token(&val, cfile);
538         if (token != COLON) {
539                 parse_warn("expected colon separating hour from minute.");
540                 if (token != SEMI)
541                         skip_to_semi(cfile);
542                 return (0);
543         }
544
545         /* Minute... */
546         token = next_token(&val, cfile);
547         if (token != NUMBER) {
548                 parse_warn("numeric minute expected.");
549                 if (token != SEMI)
550                         skip_to_semi(cfile);
551                 return (0);
552         }
553         tm.tm_sec = atoi(val);
554         tm.tm_isdst = 0;
555
556         /* XXX: We assume that mktime does not use tm_yday. */
557         tm.tm_yday = 0;
558
559         /* Make sure the date ends in a semicolon... */
560         token = next_token(&val, cfile);
561         if (token != SEMI) {
562                 parse_warn("semicolon expected.");
563                 skip_to_semi(cfile);
564                 return (0);
565         }
566
567         /* Guess the time value... */
568         guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */
569                     (tm.tm_year - 69) / 4 +     /* Leap days since '70 */
570                     (tm.tm_mon                  /* Days in months this year */
571                     ? months[tm.tm_mon - 1]
572                     : 0) +
573                     (tm.tm_mon > 1 &&           /* Leap day this year */
574                     !((tm.tm_year - 72) & 3)) +
575                     tm.tm_mday - 1) * 24) +     /* Day of month */
576                     tm.tm_hour) * 60) +
577                     tm.tm_min) * 60) + tm.tm_sec;
578
579         /*
580          * This guess could be wrong because of leap seconds or other
581          * weirdness we don't know about that the system does.   For
582          * now, we're just going to accept the guess, but at some point
583          * it might be nice to do a successive approximation here to get
584          * an exact value.   Even if the error is small, if the server
585          * is restarted frequently (and thus the lease database is
586          * reread), the error could accumulate into something
587          * significant.
588          */
589         return (guess);
590 }