Contents of /trunk/mkinitrd-magellan/busybox/networking/udhcp/files.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 10011 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 10011 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * files.c -- DHCP server file manipulation * |
4 | * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 |
5 | */ |
6 | |
7 | #include <netinet/ether.h> |
8 | |
9 | #include "common.h" |
10 | #include "dhcpd.h" |
11 | #include "options.h" |
12 | |
13 | |
14 | /* |
15 | * Domain names may have 254 chars, and string options can be 254 |
16 | * chars long. However, 80 bytes will be enough for most, and won't |
17 | * hog up memory. If you have a special application, change it |
18 | */ |
19 | #define READ_CONFIG_BUF_SIZE 80 |
20 | |
21 | /* on these functions, make sure you datatype matches */ |
22 | static int read_ip(const 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 | host = gethostbyname(line); |
30 | if (host) |
31 | addr->s_addr = *((unsigned long *) host->h_addr_list[0]); |
32 | else retval = 0; |
33 | } |
34 | return retval; |
35 | } |
36 | |
37 | static int read_mac(const char *line, void *arg) |
38 | { |
39 | uint8_t *mac_bytes = arg; |
40 | struct ether_addr *temp_ether_addr; |
41 | int retval = 1; |
42 | |
43 | temp_ether_addr = ether_aton(line); |
44 | |
45 | if (temp_ether_addr == NULL) |
46 | retval = 0; |
47 | else |
48 | memcpy(mac_bytes, temp_ether_addr, 6); |
49 | |
50 | return retval; |
51 | } |
52 | |
53 | |
54 | static int read_str(const char *line, void *arg) |
55 | { |
56 | char **dest = arg; |
57 | |
58 | free(*dest); |
59 | *dest = xstrdup(line); |
60 | |
61 | return 1; |
62 | } |
63 | |
64 | |
65 | static int read_u32(const char *line, void *arg) |
66 | { |
67 | *((uint32_t*)arg) = bb_strtou32(line, NULL, 10); |
68 | return errno == 0; |
69 | } |
70 | |
71 | |
72 | static int read_yn(const char *line, void *arg) |
73 | { |
74 | char *dest = arg; |
75 | int retval = 1; |
76 | |
77 | if (!strcasecmp("yes", line)) |
78 | *dest = 1; |
79 | else if (!strcasecmp("no", line)) |
80 | *dest = 0; |
81 | else retval = 0; |
82 | |
83 | return retval; |
84 | } |
85 | |
86 | |
87 | /* find option 'code' in opt_list */ |
88 | struct option_set *find_option(struct option_set *opt_list, char code) |
89 | { |
90 | while (opt_list && opt_list->data[OPT_CODE] < code) |
91 | opt_list = opt_list->next; |
92 | |
93 | if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list; |
94 | else return NULL; |
95 | } |
96 | |
97 | |
98 | /* add an option to the opt_list */ |
99 | static void attach_option(struct option_set **opt_list, |
100 | const struct dhcp_option *option, char *buffer, int length) |
101 | { |
102 | struct option_set *existing, *new, **curr; |
103 | |
104 | /* add it to an existing option */ |
105 | existing = find_option(*opt_list, option->code); |
106 | if (existing) { |
107 | DEBUG("Attaching option %s to existing member of list", option->name); |
108 | if (option->flags & OPTION_LIST) { |
109 | if (existing->data[OPT_LEN] + length <= 255) { |
110 | existing->data = realloc(existing->data, |
111 | existing->data[OPT_LEN] + length + 2); |
112 | memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); |
113 | existing->data[OPT_LEN] += length; |
114 | } /* else, ignore the data, we could put this in a second option in the future */ |
115 | } /* else, ignore the new data */ |
116 | } else { |
117 | DEBUG("Attaching option %s to list", option->name); |
118 | |
119 | /* make a new option */ |
120 | new = xmalloc(sizeof(struct option_set)); |
121 | new->data = xmalloc(length + 2); |
122 | new->data[OPT_CODE] = option->code; |
123 | new->data[OPT_LEN] = length; |
124 | memcpy(new->data + 2, buffer, length); |
125 | |
126 | curr = opt_list; |
127 | while (*curr && (*curr)->data[OPT_CODE] < option->code) |
128 | curr = &(*curr)->next; |
129 | |
130 | new->next = *curr; |
131 | *curr = new; |
132 | } |
133 | } |
134 | |
135 | |
136 | /* read a dhcp option and add it to opt_list */ |
137 | static int read_opt(const char *const_line, void *arg) |
138 | { |
139 | struct option_set **opt_list = arg; |
140 | char *opt, *val, *endptr; |
141 | const struct dhcp_option *option; |
142 | int retval = 0, length; |
143 | char buffer[8]; |
144 | char *line; |
145 | uint16_t *result_u16 = (uint16_t *) buffer; |
146 | uint32_t *result_u32 = (uint32_t *) buffer; |
147 | |
148 | /* Cheat, the only const line we'll actually get is "" */ |
149 | line = (char *) const_line; |
150 | opt = strtok(line, " \t="); |
151 | if (!opt) return 0; |
152 | |
153 | option = dhcp_options; |
154 | while (1) { |
155 | if (!option->code) |
156 | return 0; |
157 | if (!strcasecmp(option->name, opt)) |
158 | break; |
159 | option++; |
160 | } |
161 | |
162 | do { |
163 | val = strtok(NULL, ", \t"); |
164 | if (!val) break; |
165 | length = option_lengths[option->flags & TYPE_MASK]; |
166 | retval = 0; |
167 | opt = buffer; /* new meaning for variable opt */ |
168 | switch (option->flags & TYPE_MASK) { |
169 | case OPTION_IP: |
170 | retval = read_ip(val, buffer); |
171 | break; |
172 | case OPTION_IP_PAIR: |
173 | retval = read_ip(val, buffer); |
174 | if (!(val = strtok(NULL, ", \t/-"))) retval = 0; |
175 | if (retval) retval = read_ip(val, buffer + 4); |
176 | break; |
177 | case OPTION_STRING: |
178 | length = strlen(val); |
179 | if (length > 0) { |
180 | if (length > 254) length = 254; |
181 | opt = val; |
182 | retval = 1; |
183 | } |
184 | break; |
185 | case OPTION_BOOLEAN: |
186 | retval = read_yn(val, buffer); |
187 | break; |
188 | case OPTION_U8: |
189 | buffer[0] = strtoul(val, &endptr, 0); |
190 | retval = (endptr[0] == '\0'); |
191 | break; |
192 | case OPTION_U16: |
193 | *result_u16 = htons(strtoul(val, &endptr, 0)); |
194 | retval = (endptr[0] == '\0'); |
195 | break; |
196 | case OPTION_S16: |
197 | *result_u16 = htons(strtol(val, &endptr, 0)); |
198 | retval = (endptr[0] == '\0'); |
199 | break; |
200 | case OPTION_U32: |
201 | *result_u32 = htonl(strtoul(val, &endptr, 0)); |
202 | retval = (endptr[0] == '\0'); |
203 | break; |
204 | case OPTION_S32: |
205 | *result_u32 = htonl(strtol(val, &endptr, 0)); |
206 | retval = (endptr[0] == '\0'); |
207 | break; |
208 | default: |
209 | break; |
210 | } |
211 | if (retval) |
212 | attach_option(opt_list, option, opt, length); |
213 | } while (retval && option->flags & OPTION_LIST); |
214 | return retval; |
215 | } |
216 | |
217 | static int read_staticlease(const char *const_line, void *arg) |
218 | { |
219 | char *line; |
220 | char *mac_string; |
221 | char *ip_string; |
222 | uint8_t *mac_bytes; |
223 | uint32_t *ip; |
224 | |
225 | |
226 | /* Allocate memory for addresses */ |
227 | mac_bytes = xmalloc(sizeof(unsigned char) * 8); |
228 | ip = xmalloc(sizeof(uint32_t)); |
229 | |
230 | /* Read mac */ |
231 | line = (char *) const_line; |
232 | mac_string = strtok(line, " \t"); |
233 | read_mac(mac_string, mac_bytes); |
234 | |
235 | /* Read ip */ |
236 | ip_string = strtok(NULL, " \t"); |
237 | read_ip(ip_string, ip); |
238 | |
239 | addStaticLease(arg, mac_bytes, ip); |
240 | |
241 | if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg); |
242 | |
243 | return 1; |
244 | } |
245 | |
246 | |
247 | static const struct config_keyword keywords[] = { |
248 | /* keyword handler variable address default */ |
249 | {"start", read_ip, &(server_config.start), "192.168.0.20"}, |
250 | {"end", read_ip, &(server_config.end), "192.168.0.254"}, |
251 | {"interface", read_str, &(server_config.interface), "eth0"}, |
252 | {"option", read_opt, &(server_config.options), ""}, |
253 | {"opt", read_opt, &(server_config.options), ""}, |
254 | {"max_leases", read_u32, &(server_config.max_leases), "254"}, |
255 | {"remaining", read_yn, &(server_config.remaining), "yes"}, |
256 | {"auto_time", read_u32, &(server_config.auto_time), "7200"}, |
257 | {"decline_time",read_u32, &(server_config.decline_time),"3600"}, |
258 | {"conflict_time",read_u32,&(server_config.conflict_time),"3600"}, |
259 | {"offer_time", read_u32, &(server_config.offer_time), "60"}, |
260 | {"min_lease", read_u32, &(server_config.min_lease), "60"}, |
261 | {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE}, |
262 | {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"}, |
263 | {"notify_file", read_str, &(server_config.notify_file), ""}, |
264 | {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"}, |
265 | {"sname", read_str, &(server_config.sname), ""}, |
266 | {"boot_file", read_str, &(server_config.boot_file), ""}, |
267 | {"static_lease",read_staticlease, &(server_config.static_leases), ""}, |
268 | /*ADDME: static lease */ |
269 | {"", NULL, NULL, ""} |
270 | }; |
271 | |
272 | |
273 | int read_config(const char *file) |
274 | { |
275 | FILE *in; |
276 | char buffer[READ_CONFIG_BUF_SIZE], *token, *line; |
277 | int i, lm = 0; |
278 | |
279 | for (i = 0; keywords[i].keyword[0]; i++) |
280 | if (keywords[i].def[0]) |
281 | keywords[i].handler(keywords[i].def, keywords[i].var); |
282 | |
283 | in = fopen(file, "r"); |
284 | if (!in) { |
285 | bb_error_msg("cannot open config file: %s", file); |
286 | return 0; |
287 | } |
288 | |
289 | while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) { |
290 | char debug_orig[READ_CONFIG_BUF_SIZE]; |
291 | char *p; |
292 | |
293 | lm++; |
294 | p = strchr(buffer, '\n'); |
295 | if (p) *p = '\0'; |
296 | if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer); |
297 | p = strchr(buffer, '#'); |
298 | if (p) *p = '\0'; |
299 | |
300 | if (!(token = strtok(buffer, " \t"))) continue; |
301 | if (!(line = strtok(NULL, ""))) continue; |
302 | |
303 | /* eat leading whitespace */ |
304 | line = skip_whitespace(line); |
305 | /* eat trailing whitespace */ |
306 | i = strlen(line) - 1; |
307 | while (i >= 0 && isspace(line[i])) |
308 | line[i--] = '\0'; |
309 | |
310 | for (i = 0; keywords[i].keyword[0]; i++) |
311 | if (!strcasecmp(token, keywords[i].keyword)) |
312 | if (!keywords[i].handler(line, keywords[i].var)) { |
313 | bb_error_msg("cannot parse line %d of %s", lm, file); |
314 | if (ENABLE_FEATURE_UDHCP_DEBUG) |
315 | bb_error_msg("cannot parse '%s'", debug_orig); |
316 | /* reset back to the default value */ |
317 | keywords[i].handler(keywords[i].def, keywords[i].var); |
318 | } |
319 | } |
320 | fclose(in); |
321 | return 1; |
322 | } |
323 | |
324 | |
325 | void write_leases(void) |
326 | { |
327 | int fp; |
328 | unsigned i; |
329 | time_t curr = time(0); |
330 | unsigned long tmp_time; |
331 | |
332 | fp = open(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666); |
333 | if (fp < 0) { |
334 | bb_error_msg("cannot open %s for writing", server_config.lease_file); |
335 | return; |
336 | } |
337 | |
338 | for (i = 0; i < server_config.max_leases; i++) { |
339 | if (leases[i].yiaddr != 0) { |
340 | |
341 | /* screw with the time in the struct, for easier writing */ |
342 | tmp_time = leases[i].expires; |
343 | |
344 | if (server_config.remaining) { |
345 | if (lease_expired(&(leases[i]))) |
346 | leases[i].expires = 0; |
347 | else leases[i].expires -= curr; |
348 | } /* else stick with the time we got */ |
349 | leases[i].expires = htonl(leases[i].expires); |
350 | // FIXME: error check?? |
351 | full_write(fp, &leases[i], sizeof(leases[i])); |
352 | |
353 | /* then restore it when done */ |
354 | leases[i].expires = tmp_time; |
355 | } |
356 | } |
357 | close(fp); |
358 | |
359 | if (server_config.notify_file) { |
360 | char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file); |
361 | system(cmd); |
362 | free(cmd); |
363 | } |
364 | } |
365 | |
366 | |
367 | void read_leases(const char *file) |
368 | { |
369 | int fp; |
370 | unsigned int i = 0; |
371 | struct dhcpOfferedAddr lease; |
372 | |
373 | fp = open(file, O_RDONLY); |
374 | if (fp < 0) { |
375 | bb_error_msg("cannot open %s for reading", file); |
376 | return; |
377 | } |
378 | |
379 | while (i < server_config.max_leases |
380 | && full_read(fp, &lease, sizeof(lease)) == sizeof(lease) |
381 | ) { |
382 | /* ADDME: is it a static lease */ |
383 | if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) { |
384 | lease.expires = ntohl(lease.expires); |
385 | if (!server_config.remaining) lease.expires -= time(0); |
386 | if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) { |
387 | bb_error_msg("too many leases while loading %s", file); |
388 | break; |
389 | } |
390 | i++; |
391 | } |
392 | } |
393 | DEBUG("Read %d leases", i); |
394 | close(fp); |
395 | } |