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