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