138518b4524d03b3e0f488dc3474cc3de63608ca
[dragonfly.git] / sbin / dhclient / parse.c
1 /*      $OpenBSD: src/sbin/dhclient/parse.c,v 1.19 2010/06/26 21:14:10 krw 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 "dhcpd.h"
44 #include "dhctoken.h"
45
46 /*
47  * Skip to the semicolon ending the current statement.   If we encounter
48  * braces, the matching closing brace terminates the statement.   If we
49  * encounter a right brace but haven't encountered a left brace, return
50  * leaving the brace in the token buffer for the caller.   If we see a
51  * semicolon and haven't seen a left brace, return.   This lets us skip
52  * over:
53  *
54  *      statement;
55  *      statement foo bar { }
56  *      statement foo bar { statement { } }
57  *      statement}
58  *
59  *      ...et cetera.
60  */
61 void
62 skip_to_semi(FILE *cfile)
63 {
64         int              token;
65         char            *val;
66         int              brace_count = 0;
67
68         do {
69                 token = peek_token(&val, cfile);
70                 if (token == '}') {
71                         if (brace_count) {
72                                 token = next_token(&val, cfile);
73                                 if (!--brace_count)
74                                         return;
75                         } else
76                                 return;
77                 } else if (token == '{') {
78                         brace_count++;
79                 } else if (token == ';' && !brace_count) {
80                         token = next_token(&val, cfile);
81                         return;
82                 } else if (token == '\n') {
83                         /*
84                          * EOL only happens when parsing
85                          * /etc/resolv.conf, and we treat it like a
86                          * semicolon because the resolv.conf file is
87                          * line-oriented.
88                          */
89                         token = next_token(&val, cfile);
90                         return;
91                 }
92                 token = next_token(&val, cfile);
93         } while (token != EOF);
94 }
95
96 int
97 parse_semi(FILE *cfile)
98 {
99         int token;
100         char *val;
101
102         token = next_token(&val, cfile);
103         if (token != ';') {
104                 parse_warn("semicolon expected.");
105                 skip_to_semi(cfile);
106                 return (0);
107         }
108         return (1);
109 }
110
111 /*
112  * string-parameter :== STRING SEMI
113  */
114 char *
115 parse_string(FILE *cfile)
116 {
117         char *val, *s;
118         int token;
119
120         token = next_token(&val, cfile);
121         if (token != TOK_STRING) {
122                 parse_warn("filename must be a string");
123                 skip_to_semi(cfile);
124                 return (NULL);
125         }
126         s = strdup(val);
127         if (!s)
128                 error("no memory for string %s.", val);
129
130         if (!parse_semi(cfile)) {
131                 free(s);
132                 return (NULL);
133         }
134         return (s);
135 }
136
137 int
138 parse_ip_addr(FILE *cfile, struct iaddr *addr)
139 {
140         addr->len = 4;
141         return (parse_numeric_aggregate(cfile, addr->iabuf, addr->len, '.',
142             10));
143 }
144
145 /*
146  * hardware-parameter :== HARDWARE ETHERNET csns SEMI
147  * csns :== NUMBER | csns COLON NUMBER
148  */
149 void
150 parse_hardware_param(FILE *cfile, struct hardware *hardware)
151 {
152         int token;
153         char *val;
154
155         token = next_token(&val, cfile);
156         switch (token) {
157         case TOK_ETHERNET:
158                 hardware->htype = HTYPE_ETHER;
159                 hardware->hlen = 6;
160                 break;
161         case TOK_TOKEN_RING:
162                 hardware->htype = HTYPE_IEEE802;
163                 hardware->hlen = 6;
164                 break;
165         case TOK_FDDI:
166                 hardware->htype = HTYPE_FDDI;
167                 hardware->hlen = 6;
168                 break;
169         default:
170                 parse_warn("expecting a network hardware type");
171                 skip_to_semi(cfile);
172                 return;
173         }
174
175         if (parse_numeric_aggregate(cfile, hardware->haddr, hardware->hlen,
176             ':', 16) == 0)
177                 return;
178
179         token = next_token(&val, cfile);
180         if (token != ';') {
181                 parse_warn("expecting semicolon.");
182                 skip_to_semi(cfile);
183         }
184 }
185
186 /*
187  * lease-time :== NUMBER SEMI
188  */
189 void
190 parse_lease_time(FILE *cfile, time_t *timep)
191 {
192         char *val;
193         int token;
194
195         token = next_token(&val, cfile);
196         if (token != TOK_NUMBER) {
197                 parse_warn("Expecting numeric lease time");
198                 skip_to_semi(cfile);
199                 return;
200         }
201         convert_num((unsigned char *)timep, val, 10, 32);
202         /* Unswap the number - convert_num returns stuff in NBO. */
203         *timep = ntohl(*timep); /* XXX */
204
205         parse_semi(cfile);
206 }
207
208 /*
209  * Parse a sequence of numbers separated by the token specified in separator.
210  * Exactly max numbers are expected.
211  */
212 int
213 parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int max, int separator,
214     int base)
215 {
216         char *val;
217         int token, count;
218
219         if (buf == NULL || max == 0)
220                 error("no space for numeric aggregate");
221
222         for (count = 0; count < max; count++, buf++) {
223                 if (count && (peek_token(&val, cfile) == separator))
224                         token = next_token(&val, cfile);
225
226                 token = next_token(&val, cfile);
227
228                 if (token == TOK_NUMBER || (base == 16 && token == TOK_NUMBER_OR_NAME))
229                         /* XXX Need to check if conversion was successful. */
230                         convert_num(buf, val, base, 8);
231                 else
232                         break;
233         }
234
235         if (count < max) {
236                 parse_warn("numeric aggregate too short.");
237                 return (0);
238         }
239
240         return (1);
241 }
242
243 void
244 convert_num(unsigned char *buf, char *str, int base, int size)
245 {
246         int negative = 0, tval, max;
247         u_int32_t val = 0;
248         char *ptr = str;
249
250         if (*ptr == '-') {
251                 negative = 1;
252                 ptr++;
253         }
254
255         /* If base wasn't specified, figure it out from the data. */
256         if (!base) {
257                 if (ptr[0] == '0') {
258                         if (ptr[1] == 'x') {
259                                 base = 16;
260                                 ptr += 2;
261                         } else if (isascii(ptr[1]) && isdigit(ptr[1])) {
262                                 base = 8;
263                                 ptr += 1;
264                         } else
265                                 base = 10;
266                 } else
267                         base = 10;
268         }
269
270         do {
271                 tval = *ptr++;
272                 /* XXX assumes ASCII... */
273                 if (tval >= 'a')
274                         tval = tval - 'a' + 10;
275                 else if (tval >= 'A')
276                         tval = tval - 'A' + 10;
277                 else if (tval >= '0')
278                         tval -= '0';
279                 else {
280                         warning("Bogus number: %s.", str);
281                         break;
282                 }
283                 if (tval >= base) {
284                         warning("Bogus number: %s: digit %d not in base %d",
285                             str, tval, base);
286                         break;
287                 }
288                 val = val * base + tval;
289         } while (*ptr);
290
291         if (negative)
292                 max = (1 << (size - 1));
293         else
294                 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
295         if (val > max) {
296                 switch (base) {
297                 case 8:
298                         warning("value %s%o exceeds max (%d) for precision.",
299                             negative ? "-" : "", val, max);
300                         break;
301                 case 16:
302                         warning("value %s%x exceeds max (%d) for precision.",
303                             negative ? "-" : "", val, max);
304                         break;
305                 default:
306                         warning("value %s%u exceeds max (%d) for precision.",
307                             negative ? "-" : "", val, max);
308                         break;
309                 }
310         }
311
312         if (negative)
313                 switch (size) {
314                 case 8:
315                         *buf = -(unsigned long)val;
316                         break;
317                 case 16:
318                         putShort(buf, -(unsigned long)val);
319                         break;
320                 case 32:
321                         putLong(buf, -(unsigned long)val);
322                         break;
323                 default:
324                         warning("Unexpected integer size: %d", size);
325                         break;
326                 }
327         else
328                 switch (size) {
329                 case 8:
330                         *buf = (u_int8_t)val;
331                         break;
332                 case 16:
333                         putUShort(buf, (u_int16_t)val);
334                         break;
335                 case 32:
336                         putULong(buf, val);
337                         break;
338                 default:
339                         warning("Unexpected integer size: %d", size);
340                         break;
341                 }
342 }
343
344 /*
345  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
346  *              NUMBER COLON NUMBER COLON NUMBER SEMI
347  *
348  * Dates are always in GMT; first number is day of week; next is
349  * year/month/day; next is hours:minutes:seconds on a 24-hour
350  * clock.
351  */
352 time_t
353 parse_date(FILE *cfile)
354 {
355         static int months[11] = { 31, 59, 90, 120, 151, 181,
356             212, 243, 273, 304, 334 };
357         int guess, token;
358         struct tm tm;
359         char *val;
360
361         /* Day of week... */
362         token = next_token(&val, cfile);
363         if (token != TOK_NUMBER) {
364                 parse_warn("numeric day of week expected.");
365                 if (token != ';')
366                         skip_to_semi(cfile);
367                 return (0);
368         }
369         tm.tm_wday = atoi(val);
370
371         /* Year... */
372         token = next_token(&val, cfile);
373         if (token != TOK_NUMBER) {
374                 parse_warn("numeric year expected.");
375                 if (token != ';')
376                         skip_to_semi(cfile);
377                 return (0);
378         }
379         tm.tm_year = atoi(val);
380         if (tm.tm_year > 1900)
381                 tm.tm_year -= 1900;
382
383         /* Slash separating year from month... */
384         token = next_token(&val, cfile);
385         if (token != '/') {
386                 parse_warn("expected slash separating year from month.");
387                 if (token != ';')
388                         skip_to_semi(cfile);
389                 return (0);
390         }
391
392         /* Month... */
393         token = next_token(&val, cfile);
394         if (token != TOK_NUMBER) {
395                 parse_warn("numeric month expected.");
396                 if (token != ';')
397                         skip_to_semi(cfile);
398                 return (0);
399         }
400         tm.tm_mon = atoi(val) - 1;
401
402         /* Slash separating month from day... */
403         token = next_token(&val, cfile);
404         if (token != '/') {
405                 parse_warn("expected slash separating month from day.");
406                 if (token != ';')
407                         skip_to_semi(cfile);
408                 return (0);
409         }
410
411         /* Day... */
412         token = next_token(&val, cfile);
413         if (token != TOK_NUMBER) {
414                 parse_warn("numeric day of month expected.");
415                 if (token != ';')
416                         skip_to_semi(cfile);
417                 return (0);
418         }
419         tm.tm_mday = atoi(val);
420
421         /* Hour... */
422         token = next_token(&val, cfile);
423         if (token != TOK_NUMBER) {
424                 parse_warn("numeric hour expected.");
425                 if (token != ';')
426                         skip_to_semi(cfile);
427                 return (0);
428         }
429         tm.tm_hour = atoi(val);
430
431         /* Colon separating hour from minute... */
432         token = next_token(&val, cfile);
433         if (token != ':') {
434                 parse_warn("expected colon separating hour from minute.");
435                 if (token != ';')
436                         skip_to_semi(cfile);
437                 return (0);
438         }
439
440         /* Minute... */
441         token = next_token(&val, cfile);
442         if (token != TOK_NUMBER) {
443                 parse_warn("numeric minute expected.");
444                 if (token != ';')
445                         skip_to_semi(cfile);
446                 return (0);
447         }
448         tm.tm_min = atoi(val);
449
450         /* Colon separating minute from second... */
451         token = next_token(&val, cfile);
452         if (token != ':') {
453                 parse_warn("expected colon separating minute from second.");
454                 if (token != ';')
455                         skip_to_semi(cfile);
456                 return (0);
457         }
458
459         /* Second... */
460         token = next_token(&val, cfile);
461         if (token != TOK_NUMBER) {
462                 parse_warn("numeric second expected.");
463                 if (token != ';')
464                         skip_to_semi(cfile);
465                 return (0);
466         }
467         tm.tm_sec = atoi(val);
468         tm.tm_isdst = 0;
469
470         /* XXX: We assume that mktime does not use tm_yday. */
471         tm.tm_yday = 0;
472
473         /* Make sure the date ends in a semicolon... */
474         token = next_token(&val, cfile);
475         if (token != ';') {
476                 parse_warn("semicolon expected.");
477                 skip_to_semi(cfile);
478                 return (0);
479         }
480
481         /* Guess the time value... */
482         guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */
483             (tm.tm_year - 69) / 4 +     /* Leap days since '70 */
484             (tm.tm_mon                  /* Days in months this year */
485             ? months[tm.tm_mon - 1] : 0) +
486             (tm.tm_mon > 1 &&           /* Leap day this year */
487             !((tm.tm_year - 72) & 3)) +
488             tm.tm_mday - 1) * 24) +     /* Day of month */
489             tm.tm_hour) * 60) + tm.tm_min) * 60) + tm.tm_sec;
490
491         /*
492          * This guess could be wrong because of leap seconds or other
493          * weirdness we don't know about that the system does.   For
494          * now, we're just going to accept the guess, but at some point
495          * it might be nice to do a successive approximation here to get
496          * an exact value.   Even if the error is small, if the server
497          * is restarted frequently (and thus the lease database is
498          * reread), the error could accumulate into something
499          * significant.
500          */
501         return (guess);
502 }