conffile.c revision 1.2
1/* $NetBSD: conffile.c,v 1.2 2010/12/30 21:26:00 christos Exp $ */
2
3/*
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mihai Chelaru <kefren@NetBSD.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <arpa/inet.h>
33#include <netinet/in.h>
34
35#include <ctype.h>
36#include <fcntl.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#include "conffile.h"
42#include "ldp_errors.h"
43
44#define NextCommand(x) strsep(&x, " ")
45#define LINEMAXSIZE 1024
46
47extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
48	min_label, max_label;
49int confh;
50struct in_addr conf_ldp_id;
51
52static int conf_dispatch(char*);
53static int conf_readline(char*, size_t);
54static int checkeol(char*);
55static int Fhellotime(char*);
56static int Fport(char*);
57static int Fholddown(char*);
58static int Fkeepalive(char*);
59static int Fmaxlabel(char*);
60static int Fminlabel(char*);
61static int Fldpid(char*);
62static int Fneighbour(char*);
63static int Gneighbour(struct conf_neighbour *, char *);
64
65struct conf_func {
66	char com[64];
67	int (* func)(char *);
68};
69
70struct conf_func main_commands[] = {
71	{ "hello-time", Fhellotime },
72	{ "keepalive-time", Fkeepalive },
73	{ "holddown-time", Fholddown },
74	{ "command-port", Fport },
75	{ "min-label", Fminlabel },
76	{ "max-label", Fmaxlabel },
77	{ "LDP-ID", Fldpid },
78	{ "neighbor", Fneighbour },
79	{ "neighbour", Fneighbour },
80	{ "", NULL },
81};
82
83/*
84 * Parses config file
85 */
86int
87conf_parsefile(char *fname)
88{
89	int i;
90	char buf[LINEMAXSIZE + 1];
91
92	SLIST_INIT(&conei_head);
93	conf_ldp_id.s_addr = 0;
94
95	confh = open(fname, O_RDONLY, 0);
96
97	if (confh == -1)
98		return E_CONF_IO;
99
100	for (i = 1; conf_readline(buf, sizeof(buf)) >= 0; i++)
101		if (conf_dispatch(buf) != 0) {
102			close(confh);
103			return i;
104		}
105
106	close(confh);
107	return 0;
108}
109
110/*
111 * Reads a line from config file
112 */
113int
114conf_readline(char *buf, size_t bufsize)
115{
116	size_t i;
117
118	for (i = 0; i < bufsize; i++) {
119		if (read(confh, &buf[i], 1) != 1) {
120			if (i == 0)
121				return E_CONF_IO;
122			break;
123		}
124		if (buf[i] == '\n')
125			break;
126		if (i == 0 && isspace((unsigned char)buf[i]) != 0) {
127			i--;
128			continue;
129		}
130	}
131	if (i == bufsize)
132		return E_CONF_MEM;
133	buf[i] = '\0';
134	return i;
135}
136
137/*
138 * Looks for a matching command on a line
139 */
140int
141conf_dispatch(char *line)
142{
143	int i, last_match = -1, matched = 0;
144	char *command, *nline = line;
145
146	if (strlen(line) == 0 || line[0] == '#')
147		return E_CONF_OK;
148	command = NextCommand(nline);
149	for (i = 0; main_commands[i].func != NULL; i++)
150		if (strncasecmp(main_commands[i].com, command,
151		    strlen(command)) == 0) {
152			matched++;
153			last_match = i;
154		}
155	if (matched == 0)
156		return E_CONF_NOMATCH;
157	else if (matched > 1)
158		return E_CONF_AMBIGUOUS;
159
160	if (checkeol(nline) != 0)
161		return E_CONF_PARAM;
162	return main_commands[last_match].func(nline);
163}
164
165/*
166 * Checks if a line is terminated or else if it contains
167 * a start block bracket. If it's semicolon terminated
168 * then trim it.
169 */
170int
171checkeol(char *line)
172{
173	size_t len = strlen(line);
174	if (len > 0 && line[len - 1] == ';') {
175		line[len - 1] = '\0';
176		return 0;
177	}
178	for (size_t i = 0; i < len; i++)
179		if (line[i] == '{')
180			return 0;
181	return -1;
182}
183
184/*
185 * Sets hello time
186 */
187int
188Fhellotime(char *line)
189{
190	int ht = atoi(line);
191	if (ht <= 0)
192		return E_CONF_PARAM;
193	ldp_hello_time = ht;
194	return 0;
195}
196
197/*
198 * Sets command port
199 */
200int
201Fport(char *line)
202{
203	int cp = atoi(line);
204	if (cp <= 0 || cp > 65535)
205		return E_CONF_PARAM;
206	command_port = cp;
207	return 0;
208}
209
210/*
211 * Sets neighbour keepalive
212 */
213int
214Fkeepalive(char *line)
215{
216	int kt = atoi(line);
217	if (kt <= 0)
218		return E_CONF_PARAM;
219	ldp_keepalive_time = kt;
220	return 0;
221}
222
223/*
224 * Sets neighbour holddown timer
225 */
226int
227Fholddown(char *line)
228{
229	int hdt = atoi(line);
230	if (hdt <= 0)
231		return E_CONF_PARAM;
232	ldp_holddown_time = hdt;
233	return 0;
234}
235
236int
237Fminlabel(char *line)
238{
239	int ml = atoi(line);
240	if (ml <= 0)
241		return E_CONF_PARAM;
242	min_label = ml;
243	return 0;
244}
245
246int
247Fmaxlabel(char *line)
248{
249	int ml = atoi(line);
250	if (ml <= 0)
251		return E_CONF_PARAM;
252	max_label = ml;
253	return 0;
254}
255
256int
257Fldpid(char *line)
258{
259	if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
260		return E_CONF_PARAM;
261	return 0;
262}
263
264int
265Fneighbour(char *line)
266{
267	char *peer;
268	struct conf_neighbour *nei;
269	struct in_addr ad;
270	char buf[1024];
271
272	peer = NextCommand(line);
273	if (inet_pton(AF_INET, peer, &ad) != 1)
274		return E_CONF_PARAM;
275
276	nei = calloc(1, sizeof(*nei));
277	if (nei == NULL)
278		return E_CONF_MEM;
279	nei->address.s_addr = ad.s_addr;
280	SLIST_INSERT_HEAD(&conei_head, nei, neilist);
281
282	while (conf_readline(buf, sizeof(buf)) >= 0) {
283		if (buf[0] == '}')
284			return 0;
285		if (Gneighbour(nei, buf) == -1)
286			return -1;
287	}
288	return -1;
289}
290
291/*
292 * neighbour { } sub-commands
293 */
294int
295Gneighbour(struct conf_neighbour *nei, char *line)
296{
297	if (strncasecmp("authenticate", line, 12) == 0) {
298		nei->authenticate = 1;
299		return 0;
300	}
301	return -1;
302}
303