tar -Z, uncompress support
[oweals/busybox.git] / networking / udhcp / files.c
1 /* 
2  * files.c -- DHCP server file manipulation *
3  * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
4  */
5  
6 #include <sys/socket.h>
7 #include <arpa/inet.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include <ctype.h>
12
13 #include "dhcpd.h"
14 #include "files.h"
15 #include "options.h"
16 #include "common.h"
17
18 /* on these functions, make sure you datatype matches */
19 static int read_ip(const char *line, void *arg)
20 {
21         struct in_addr *addr = arg;
22         struct hostent *host;
23         int retval = 1;
24
25         if (!inet_aton(line, addr)) {
26                 if ((host = gethostbyname(line))) 
27                         addr->s_addr = *((unsigned long *) host->h_addr_list[0]);
28                 else retval = 0;
29         }
30         return retval;
31 }
32
33
34 static int read_str(const char *line, void *arg)
35 {
36         char **dest = arg;
37         
38         if (*dest) free(*dest);
39         *dest = strdup(line);
40         
41         return 1;
42 }
43
44
45 static int read_u32(const char *line, void *arg)
46 {
47         u_int32_t *dest = arg;
48         char *endptr;
49         *dest = strtoul(line, &endptr, 0);
50         return endptr[0] == '\0';
51 }
52
53
54 static int read_yn(const char *line, void *arg)
55 {
56         char *dest = arg;
57         int retval = 1;
58
59         if (!strcasecmp("yes", line))
60                 *dest = 1;
61         else if (!strcasecmp("no", line))
62                 *dest = 0;
63         else retval = 0;
64         
65         return retval;
66 }
67
68 #define READ_CONFIG_BUF_SIZE 512        /* domainname may have 254 chars */
69
70 /* read a dhcp option and add it to opt_list */
71 static int read_opt(const char *const_line, void *arg)
72 {
73     char line[READ_CONFIG_BUF_SIZE];
74         struct option_set **opt_list = arg;
75         char *opt, *val, *endptr;
76     struct dhcp_option *option;
77     int retval = 0, length;
78     char buffer[256];                       /* max opt length */
79         u_int16_t result_u16;
80         u_int32_t result_u32;
81     void *valptr;
82         
83     if ((opt = strtok(strcpy(line, const_line), " \t="))) {
84                 
85         for (option = options; option->code; option++)
86                 if (!strcasecmp(option->name, opt))
87                         break;
88         
89         if (option->code) do {
90                 val = strtok(NULL, ", \t");
91                 if(!val)
92                         break;
93                         length = option_lengths[option->flags & TYPE_MASK];
94                 valptr = NULL;
95                         switch (option->flags & TYPE_MASK) {
96                         case OPTION_IP:
97                                 retval = read_ip(val, buffer);
98                                 break;
99                         case OPTION_IP_PAIR:
100                                 retval = read_ip(val, buffer);
101                                 if (!(val = strtok(NULL, ", \t/-"))) retval = 0;
102                                 if (retval) retval = read_ip(val, buffer + 4);
103                                 break;
104                         case OPTION_STRING:
105                                 length = strlen(val);
106                                 if (length > 0) {
107                                         if (length > 254) length = 254;
108                                 endptr = buffer + length;
109                                 endptr[0] = 0;
110                                 valptr = val;
111                                 }
112                                 break;
113                         case OPTION_BOOLEAN:
114                                 retval = read_yn(val, buffer);
115                                 break;
116                         case OPTION_U8:
117                                 buffer[0] = strtoul(val, &endptr, 0);
118                         valptr = buffer;
119                                 break;
120                         case OPTION_U16:
121                                 result_u16 = htons(strtoul(val, &endptr, 0));
122                         valptr = &result_u16;
123                                 break;
124                         case OPTION_S16:
125                                 result_u16 = htons(strtol(val, &endptr, 0));
126                         valptr = &result_u16;
127                                 break;
128                         case OPTION_U32:
129                                 result_u32 = htonl(strtoul(val, &endptr, 0));
130                         valptr = &result_u32;
131                                 break;
132                         case OPTION_S32:
133                                 result_u32 = htonl(strtol(val, &endptr, 0));    
134                         valptr = &result_u32;
135                                 break;
136                         default:
137                         retval = 0;
138                                 break;
139                         }
140                 if(valptr) {
141                         memcpy(buffer, valptr, length);
142                         retval = (endptr[0] == '\0');
143                 }
144                         if (retval) 
145                                 attach_option(opt_list, option, buffer, length);
146                 else
147                         break;
148         } while (option->flags & OPTION_LIST);
149     }
150         return retval;
151 }
152
153
154 static const struct config_keyword keywords[] = {
155         /* keyword      handler   variable address              default     */
156         {"start",       read_ip,  &(server_config.start),       "192.168.0.20"},
157         {"end",         read_ip,  &(server_config.end),         "192.168.0.254"},
158         {"interface",   read_str, &(server_config.interface),   "eth0"},
159         {"option",      read_opt, &(server_config.options),     ""},
160         {"opt",         read_opt, &(server_config.options),     ""},
161         {"max_leases",  read_u32, &(server_config.max_leases),  "254"},
162         {"remaining",   read_yn,  &(server_config.remaining),   "yes"},
163         {"auto_time",   read_u32, &(server_config.auto_time),   "7200"},
164         {"decline_time",read_u32, &(server_config.decline_time),"3600"},
165         {"conflict_time",read_u32,&(server_config.conflict_time),"3600"},
166         {"offer_time",  read_u32, &(server_config.offer_time),  "60"},
167         {"min_lease",   read_u32, &(server_config.min_lease),   "60"},
168         {"lease_file",  read_str, &(server_config.lease_file),  leases_file},
169         {"pidfile",     read_str, &(server_config.pidfile),     "/var/run/udhcpd.pid"},
170         {"notify_file", read_str, &(server_config.notify_file), ""},
171         {"siaddr",      read_ip,  &(server_config.siaddr),      "0.0.0.0"},
172         {"sname",       read_str, &(server_config.sname),       ""},
173         {"boot_file",   read_str, &(server_config.boot_file),   ""},
174         /*ADDME: static lease */
175         {"",            NULL,     NULL,                         ""}
176 };
177
178
179 int read_config(const char *file)
180 {
181         FILE *in;
182         char buffer[READ_CONFIG_BUF_SIZE], orig[READ_CONFIG_BUF_SIZE];
183         char *token, *line;
184         int i;
185
186         for (i = 0; keywords[i].keyword[0]; i++)
187                 if (keywords[i].def[0])
188                         keywords[i].handler(keywords[i].def, keywords[i].var);
189
190         if (!(in = fopen(file, "r"))) {
191                 LOG(LOG_ERR, "unable to open config file: %s", file);
192                 return 0;
193         }
194         
195         while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {
196                 if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0';
197                 strcpy(orig, buffer);
198                 if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0';
199                 token = strtok(buffer, " \t");
200                 if(!token)
201                         continue;
202                 line = strtok(NULL, "");
203                 if(!line)
204                         continue;
205                 while(*line == '=' || isspace(*line))
206                 line++;
207                 /* eat trailing whitespace */
208                 for (i = strlen(line); i > 0 && isspace(line[i - 1]); i--);
209                 line[i] = '\0';
210                 if (*line == '\0')
211                         continue;
212                 
213                 for (i = 0; keywords[i].keyword[0]; i++)
214                         if (!strcasecmp(token, keywords[i].keyword))
215                                 if (!keywords[i].handler(line, keywords[i].var)) {
216                                         LOG(LOG_ERR, "unable to parse '%s'", orig);
217                                         /* reset back to the default value */
218                                         keywords[i].handler(keywords[i].def, keywords[i].var);
219                                 }
220         }
221         fclose(in);
222         return 1;
223 }
224
225
226 void write_leases(void)
227 {
228         FILE *fp;
229         unsigned int i;
230         char buf[255];
231         time_t curr = time(0);
232         unsigned long lease_time;
233         
234         if (!(fp = fopen(server_config.lease_file, "w"))) {
235                 LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);
236                 return;
237         }
238         
239         for (i = 0; i < server_config.max_leases; i++) {
240                 struct dhcpOfferedAddr lease;
241                 if (leases[i].yiaddr != 0) {
242                         if (server_config.remaining) {
243                                 if (lease_expired(&(leases[i])))
244                                         lease_time = 0;
245                                 else lease_time = leases[i].expires - curr;
246                         } else lease_time = leases[i].expires;
247                         lease.expires = htonl(lease_time);
248                         memcpy(lease.chaddr, leases[i].chaddr, 16);
249                         lease.yiaddr = leases[i].yiaddr;
250                         fwrite(leases, sizeof(lease), 1, fp);
251                 }
252         }
253         fclose(fp);
254         
255         if (server_config.notify_file) {
256                 sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file);
257                 system(buf);
258         }
259 }
260
261
262 void read_leases(const char *file)
263 {
264         FILE *fp;
265         unsigned int i = 0;
266         struct dhcpOfferedAddr lease;
267         
268         if (!(fp = fopen(file, "r"))) {
269                 LOG(LOG_ERR, "Unable to open %s for reading", file);
270                 return;
271         }
272         
273         while (i < server_config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) {
274                 /* ADDME: is it a static lease */
275                 if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) {
276                         lease.expires = ntohl(lease.expires);
277                         if (!server_config.remaining) lease.expires -= time(0);
278                         if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
279                                 LOG(LOG_WARNING, "Too many leases while loading %s\n", file);
280                                 break;
281                         }                               
282                         i++;
283                 }
284         }
285         DEBUG(LOG_INFO, "Read %d leases", i);
286         fclose(fp);
287 }