1/* $Id: options.c,v 1.28 2013/12/13 14:07:08 nanard Exp $ */
2/* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * author: Ryan Wagoner
5 * (c) 2006-2014 Thomas Bernard
6 * This software is subject to the conditions detailed
7 * in the LICENCE file provided within the distribution */
8
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <ctype.h>
13#include <syslog.h>
14#include "config.h"
15#include "options.h"
16#include "upnppermissions.h"
17#ifdef PCP_SADSCP
18#include "pcplearndscp.h"
19#endif /* PCP_SADSPC */
20#include "upnpglobalvars.h"
21
22#ifndef DISABLE_CONFIG_FILE
23struct option * ary_options = NULL;
24static char * string_repo = NULL;
25unsigned int num_options = 0;
26
27static const struct {
28	enum upnpconfigoptions id;
29	const char * name;
30} optionids[] = {
31	{ UPNPEXT_IFNAME, "ext_ifname" },
32	{ UPNPEXT_IP,	"ext_ip" },
33	{ UPNPLISTENING_IP, "listening_ip" },
34#ifdef ENABLE_IPV6
35	{ UPNPIPV6_LISTENING_IP, "ipv6_listening_ip" },
36#endif /* ENABLE_IPV6 */
37	{ UPNPPORT, "port" },
38	{ UPNPPORT, "http_port" },	/* "port" and "http_port" are synonims */
39#ifdef ENABLE_HTTPS
40	{ UPNPHTTPSPORT, "https_port" },
41#endif /* ENABLE_HTTPS */
42	{ UPNPBITRATE_UP, "bitrate_up" },
43	{ UPNPBITRATE_DOWN, "bitrate_down" },
44	{ UPNPPRESENTATIONURL, "presentation_url" },
45#ifdef ENABLE_MANUFACTURER_INFO_CONFIGURATION
46	{ UPNPFRIENDLY_NAME, "friendly_name" },
47	{ UPNPMANUFACTURER_NAME, "manufacturer_name" },
48	{ UPNPMANUFACTURER_URL, "manufacturer_url" },
49	{ UPNPMODEL_NAME, "model_name" },
50	{ UPNPMODEL_DESCRIPTION, "model_description" },
51	{ UPNPMODEL_URL, "model_url" },
52#endif
53	{ UPNPNOTIFY_INTERVAL, "notify_interval" },
54	{ UPNPSYSTEM_UPTIME, "system_uptime" },
55	{ UPNPPACKET_LOG, "packet_log" },
56	{ UPNPUUID, "uuid"},
57	{ UPNPSERIAL, "serial"},
58	{ UPNPMODEL_NUMBER, "model_number"},
59	{ UPNPCLEANTHRESHOLD, "clean_ruleset_threshold"},
60	{ UPNPCLEANINTERVAL, "clean_ruleset_interval"},
61#ifdef USE_NETFILTER
62	{ UPNPFORWARDCHAIN, "upnp_forward_chain"},
63	{ UPNPNATCHAIN, "upnp_nat_chain"},
64#endif
65#ifdef ENABLE_NATPMP
66	{ UPNPENABLENATPMP, "enable_natpmp"},
67#endif
68#ifdef ENABLE_PCP
69	{ UPNPPCPMINLIFETIME, "min_lifetime"},
70	{ UPNPPCPMAXLIFETIME, "max_lifetime"},
71	{ UPNPPCPALLOWTHIRDPARTY, "pcp_allow_thirdparty"},
72#endif
73	{ UPNPENABLE, "enable_upnp"},
74#ifdef USE_PF
75	{ UPNPANCHOR, "anchor"},
76	{ UPNPQUEUE, "queue"},
77	{ UPNPTAG, "tag"},
78#endif
79#ifdef PF_ENABLE_FILTER_RULES
80	{ UPNPQUICKRULES, "quickrules" },
81#endif
82#ifdef ENABLE_LEASEFILE
83	{ UPNPLEASEFILE, "lease_file"},
84#endif
85	{ UPNPMINISSDPDSOCKET, "minissdpdsocket"},
86	{ UPNPSECUREMODE, "secure_mode"}
87};
88
89int
90readoptionsfile(const char * fname)
91{
92	FILE *hfile = NULL;
93	char buffer[1024];
94	char *equals;
95	char *name;
96	char *value;
97	char *t;
98	int linenum = 0;
99	unsigned int i;
100	enum upnpconfigoptions id;
101	size_t string_repo_len = 0;
102	size_t len;
103	void *tmp;
104
105	if(!fname || (strlen(fname) == 0))
106		return -1;
107
108	memset(buffer, 0, sizeof(buffer));
109
110#ifdef DEBUG
111	printf("Reading configuration from file %s\n", fname);
112#endif
113
114	if(!(hfile = fopen(fname, "r")))
115		return -1;
116
117	if(ary_options != NULL)
118	{
119		free(ary_options);
120		num_options = 0;
121	}
122
123	while(fgets(buffer, sizeof(buffer), hfile))
124	{
125		linenum++;
126		t = strchr(buffer, '\n');
127		if(t)
128		{
129			*t = '\0';
130			t--;
131			/* remove spaces at the end of the line */
132			while((t >= buffer) && isspace(*t))
133			{
134				*t = '\0';
135				t--;
136			}
137		}
138
139		/* skip leading whitespaces */
140		name = buffer;
141		while(isspace(*name))
142			name++;
143
144		/* check for comments or empty lines */
145		if(name[0] == '#' || name[0] == '\0') continue;
146
147		len = strlen(name); /* length of the whole line excluding leading
148		                     * and ending white spaces */
149		/* check for UPnP permissions rule */
150		if((len > 6) && (0 == memcmp(name, "allow", 5) || 0 == memcmp(name, "deny", 4)))
151		{
152			tmp = realloc(upnppermlist, sizeof(struct upnpperm) * (num_upnpperm+1));
153			if(tmp == NULL)
154			{
155				fprintf(stderr, "memory allocation error. Permission line in file %s line %d\n",
156				        fname, linenum);
157			}
158			else
159			{
160				upnppermlist = tmp;
161				/* parse the rule */
162				if(read_permission_line(upnppermlist + num_upnpperm, name) >= 0)
163				{
164					num_upnpperm++;
165				}
166				else
167				{
168					fprintf(stderr, "parsing error file %s line %d : %s\n",
169					        fname, linenum, name);
170				}
171			}
172			continue;
173		}
174#ifdef PCP_SADSCP
175		/* check for DSCP values configuration */
176		if((len > 15) && 0 == memcmp(name, "set_learn_dscp", sizeof("set_learn_dscp")-1) )
177		{
178			tmp = realloc(dscp_values_list, sizeof(struct dscp_values) * (num_dscp_values+1));
179			if(tmp == NULL)
180			{
181				fprintf(stderr, "memory allocation error. DSCP line in file %s line %d\n",
182				        fname, linenum);
183			}
184			else
185			{
186				dscp_values_list = tmp;
187				/* parse the rule */
188				if(read_learn_dscp_line(dscp_values_list + num_dscp_values, name) >= 0)
189				{
190					num_dscp_values++;
191				}
192				else
193				{
194					fprintf(stderr, "parsing error file %s line %d : %s\n",
195					        fname, linenum, name);
196				}
197			}
198			continue;
199		}
200#endif /* PCP_SADSCP */
201		if(!(equals = strchr(name, '=')))
202		{
203			fprintf(stderr, "parsing error file %s line %d : %s\n",
204			        fname, linenum, name);
205			continue;
206		}
207
208		/* remove ending whitespaces */
209		for(t=equals-1; t>name && isspace(*t); t--)
210			*t = '\0';
211
212		*equals = '\0';
213		value = equals+1;
214
215		/* skip leading whitespaces */
216		while(isspace(*value))
217			value++;
218
219		id = UPNP_INVALID;
220		for(i=0; i<sizeof(optionids)/sizeof(optionids[0]); i++)
221		{
222			/*printf("%2d %2d %s %s\n", i, optionids[i].id, name,
223			       optionids[i].name); */
224
225			if(0 == strcmp(name, optionids[i].name))
226			{
227				id = optionids[i].id;
228				break;
229			}
230		}
231
232		if(id == UPNP_INVALID)
233		{
234			fprintf(stderr, "invalid option in file %s line %d : %s=%s\n",
235			        fname, linenum, name, value);
236		}
237		else
238		{
239			tmp = realloc(ary_options, (num_options + 1) * sizeof(struct option));
240			if(tmp == NULL)
241			{
242				fprintf(stderr, "memory allocation error. Option in file %s line %d.\n",
243				        fname, linenum);
244			}
245			else
246			{
247				ary_options = tmp;
248				len = strlen(value) + 1;	/* +1 for terminating '\0' */
249				tmp = realloc(string_repo, string_repo_len + len);
250				if(tmp == NULL)
251				{
252					fprintf(stderr, "memory allocation error, Option value in file %s line %d : %s=%s\n",
253					        fname, linenum, name, value);
254				}
255				else
256				{
257					string_repo = tmp;
258					memcpy(string_repo + string_repo_len, value, len);
259					ary_options[num_options].id = id;
260					/* save the offset instead of the absolute address because realloc() could
261					 * change it */
262					ary_options[num_options].value = (const char *)string_repo_len;
263					num_options += 1;
264					string_repo_len += len;
265				}
266			}
267		}
268
269	}
270
271	fclose(hfile);
272
273	for(i = 0; i < num_options; i++)
274	{
275		/* add start address of string_repo to get right pointer */
276		ary_options[i].value = string_repo + (size_t)ary_options[i].value;
277	}
278
279	return 0;
280}
281
282void
283freeoptions(void)
284{
285	if(ary_options)
286	{
287		free(ary_options);
288		ary_options = NULL;
289		num_options = 0;
290	}
291	if(string_repo)
292	{
293		free(string_repo);
294		string_repo = NULL;
295	}
296	if(upnppermlist)
297	{
298		free(upnppermlist);
299		upnppermlist = NULL;
300		num_upnpperm = 0;
301	}
302#ifdef PCP_SADSCP
303	if(dscp_values_list)
304	{
305	    unsigned int i;
306		for (i = 0; i < num_dscp_values; i++) {
307			if (dscp_values_list[i].app_name) {
308				free(dscp_values_list[i].app_name);
309				dscp_values_list[i].app_name = NULL;
310			}
311		}
312		free(dscp_values_list);
313		dscp_values_list = NULL;
314		num_dscp_values = 0;
315	}
316#endif /* PCP_SADSCP */
317}
318
319#endif /* DISABLE_CONFIG_FILE */
320