1#include <stdio.h>
2#include <stdlib.h>
3#include <stdbool.h>
4#include <ctype.h>
5#include <string.h>
6#include <stdarg.h>
7#include <unistd.h>
8
9#include <shared.h>
10#include "httpd.h"
11#include "openvpn_options.h"
12#define TYPEDEF_BOOL
13#include <bcmnvram.h>
14#include <shared.h>
15#include "shutils.h"
16
17struct buffer
18alloc_buf (size_t size)
19{
20	struct buffer buf;
21
22	if (!buf_size_valid (size))
23		buf_size_error (size);
24	buf.capacity = (int)size;
25	buf.offset = 0;
26	buf.len = 0;
27	buf.data = calloc (1, size);
28
29	return buf;
30}
31
32void
33buf_size_error (const size_t size)
34{
35	logmessage ("OVPN", "fatal buffer size error, size=%lu", (unsigned long)size);
36}
37
38bool
39buf_printf (struct buffer *buf, const char *format, ...)
40{
41	int ret = false;
42	if (buf_defined (buf))
43	{
44		va_list arglist;
45		uint8_t *ptr = buf_bend (buf);
46		int cap = buf_forward_capacity (buf);
47
48		if (cap > 0)
49		{
50			int stat;
51			va_start (arglist, format);
52			stat = vsnprintf ((char *)ptr, cap, format, arglist);
53			va_end (arglist);
54			*(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
55			buf->len += (int) strlen ((char *)ptr);
56			if (stat >= 0 && stat < cap)
57				ret = true;
58		}
59	}
60	return ret;
61}
62
63bool
64buf_parse (struct buffer *buf, const int delim, char *line, const int size)
65{
66	bool eol = false;
67	int n = 0;
68	int c;
69
70	do
71	{
72		c = buf_read_u8 (buf);
73		if (c < 0)
74			eol = true;
75		if (c <= 0 || c == delim)
76			c = 0;
77		if (n >= size)
78			break;
79		line[n++] = c;
80	}
81	while (c);
82
83	line[size-1] = '\0';
84	return !(eol && !strlen (line));
85}
86
87void
88buf_clear (struct buffer *buf)
89{
90	if (buf->capacity > 0)
91		memset (buf->data, 0, buf->capacity);
92	buf->len = 0;
93	buf->offset = 0;
94}
95
96void
97free_buf (struct buffer *buf)
98{
99	if (buf->data)
100		free (buf->data);
101	CLEAR (*buf);
102}
103
104char *
105string_alloc (const char *str)
106{
107	if (str)
108	{
109		const int n = strlen (str) + 1;
110		char *ret;
111
112		ret = calloc(n, 1);
113		if(!ret)
114			return NULL;
115
116		memcpy (ret, str, n);
117		return ret;
118	}
119	else
120		return NULL;
121}
122
123static inline bool
124space (unsigned char c)
125{
126	return c == '\0' || isspace (c);
127}
128
129int
130parse_line (const char *line, char *p[], const int n, const int line_num)
131{
132	const int STATE_INITIAL = 0;
133	const int STATE_READING_QUOTED_PARM = 1;
134	const int STATE_READING_UNQUOTED_PARM = 2;
135	const int STATE_DONE = 3;
136	const int STATE_READING_SQUOTED_PARM = 4;
137
138	int ret = 0;
139	const char *c = line;
140	int state = STATE_INITIAL;
141	bool backslash = false;
142	char in, out;
143
144	char parm[OPTION_PARM_SIZE];
145	unsigned int parm_len = 0;
146
147	do
148	{
149		in = *c;
150		out = 0;
151
152		if (!backslash && in == '\\' && state != STATE_READING_SQUOTED_PARM)
153		{
154			backslash = true;
155		}
156		else
157		{
158			if (state == STATE_INITIAL)
159			{
160				if (!space (in))
161				{
162					if (in == ';' || in == '#') /* comment */
163						break;
164					if (!backslash && in == '\"')
165						state = STATE_READING_QUOTED_PARM;
166					else if (!backslash && in == '\'')
167						state = STATE_READING_SQUOTED_PARM;
168					else
169					{
170						out = in;
171						state = STATE_READING_UNQUOTED_PARM;
172					}
173				}
174			}
175			else if (state == STATE_READING_UNQUOTED_PARM)
176			{
177				if (!backslash && space (in))
178					state = STATE_DONE;
179				else
180					out = in;
181			}
182			else if (state == STATE_READING_QUOTED_PARM)
183			{
184				if (!backslash && in == '\"')
185					state = STATE_DONE;
186				else
187					out = in;
188			}
189			else if (state == STATE_READING_SQUOTED_PARM)
190			{
191				if (in == '\'')
192					state = STATE_DONE;
193				else
194					out = in;
195			}
196
197			if (state == STATE_DONE)
198			{
199				p[ret] = calloc (parm_len + 1, 1);
200				memcpy (p[ret], parm, parm_len);
201				p[ret][parm_len] = '\0';
202				state = STATE_INITIAL;
203				parm_len = 0;
204				++ret;
205			}
206
207			if (backslash && out)
208			{
209				if (!(out == '\\' || out == '\"' || space (out)))
210				{
211					logmessage ("OVPN", "Options warning: Bad backslash ('\\') usage in %d", line_num);
212					return 0;
213				}
214			}
215			backslash = false;
216		}
217
218		/* store parameter character */
219		if (out)
220		{
221			if (parm_len >= SIZE (parm))
222			{
223				parm[SIZE (parm) - 1] = 0;
224				logmessage ("OVPN", "Options error: Parameter at %d is too long (%d chars max): %s",
225					line_num, (int) SIZE (parm), parm);
226				return 0;
227			}
228			parm[parm_len++] = out;
229		}
230
231		/* avoid overflow if too many parms in one config file line */
232		if (ret >= n)
233			break;
234
235	} while (*c++ != '\0');
236
237
238	if (state == STATE_READING_QUOTED_PARM)
239	{
240		logmessage ("OVPN", "Options error: No closing quotation (\") in %d", line_num);
241		return 0;
242	}
243	if (state == STATE_READING_SQUOTED_PARM)
244	{
245		logmessage ("OVPN", "Options error: No closing single quotation (\') in %d", line_num);
246		return 0;
247	}
248	if (state != STATE_INITIAL)
249	{
250		logmessage ("OVPN", "Options error: Residual parse state (%d) in %d", line_num);
251		return 0;
252	}
253
254	return ret;
255}
256
257static void
258bypass_doubledash (char **p)
259{
260	if (strlen (*p) >= 3 && !strncmp (*p, "--", 2))
261		*p += 2;
262}
263
264static bool
265in_src_get (const struct in_src *is, char *line, const int size)
266{
267	if (is->type == IS_TYPE_FP)
268	{
269		return BOOL_CAST (fgets (line, size, is->u.fp));
270	}
271	else if (is->type == IS_TYPE_BUF)
272	{
273		bool status = buf_parse (is->u.multiline, '\n', line, size);
274		if ((int) strlen (line) + 1 < size)
275			strcat (line, "\n");
276		return status;
277	}
278	else
279	{
280		return false;
281	}
282}
283
284static char *
285read_inline_file (struct in_src *is, const char *close_tag)
286{
287	char line[OPTION_LINE_SIZE];
288	struct buffer buf = alloc_buf (10000);
289	char *ret;
290	while (in_src_get (is, line, sizeof (line)))
291	{
292		if (!strncmp (line, close_tag, strlen (close_tag)))
293			break;
294		buf_printf (&buf, "%s", line);
295	}
296	ret = string_alloc (buf_str (&buf));
297	buf_clear (&buf);
298	free_buf (&buf);
299	CLEAR (line);
300	return ret;
301}
302
303static bool
304check_inline_file (struct in_src *is, char *p[])
305{
306	bool ret = false;
307	if (p[0] && !p[1])
308	{
309		char *arg = p[0];
310		if (arg[0] == '<' && arg[strlen(arg)-1] == '>')
311		{
312			struct buffer close_tag;
313			arg[strlen(arg)-1] = '\0';
314			p[0] = string_alloc (arg+1);
315			p[1] = string_alloc (INLINE_FILE_TAG);
316			close_tag = alloc_buf (strlen(p[0]) + 4);
317			buf_printf (&close_tag, "</%s>", p[0]);
318			p[2] = read_inline_file (is, buf_str (&close_tag));
319			p[3] = NULL;
320			free_buf (&close_tag);
321			ret = true;
322		}
323	}
324	return ret;
325}
326
327static bool
328check_inline_file_via_fp (FILE *fp, char *p[])
329{
330	struct in_src is;
331	is.type = IS_TYPE_FP;
332	is.u.fp = fp;
333	return check_inline_file (&is, p);
334}
335
336void
337add_custom(char *nv, char *p[])
338{
339	char *custom = nvram_safe_get(nv);
340	char *param = NULL;
341	char *final_custom = NULL;
342	int i = 0, size = 0;
343
344	if(!p[0])
345		return;
346
347	while(p[i]) {
348		size += strlen(p[i]) + 1;
349		i++;
350	}
351
352	param = (char*)calloc(size, sizeof(char));
353
354	if(!param)
355		return;
356
357	i = 0;
358	while(p[i]) {
359		if(*param)
360			strcat(param, " ");
361		strcat(param, p[i]);
362		i++;
363	}
364
365	if(custom) {
366		final_custom = calloc(strlen(custom) + strlen(param) + 2, sizeof(char));
367		if(final_custom) {
368			if(*custom) {
369				strcat(final_custom, custom);
370				strcat(final_custom, "\n");
371			}
372			strcat(final_custom, param);
373			nvram_set(nv, final_custom);
374			free(final_custom);
375		}
376	}
377	else
378		nvram_set(nv, param);
379
380	free(param);
381}
382
383static int
384add_option (char *p[], int line, int unit)
385{
386	char buf[32] = {0};
387	FILE *fp;
388	char file_path[128] ={0};
389
390	if  (streq (p[0], "dev") && p[1])
391	{
392		sprintf(buf, "vpn_client%d_if", unit);
393		if(!strncmp(p[1], "tun", 3))
394			nvram_set(buf, "tun");
395		else if(!strncmp(p[1], "tap", 3))
396			nvram_set(buf, "tap");
397	}
398	else if  (streq (p[0], "proto") && p[1])
399	{
400		sprintf(buf, "vpn_client%d_proto", unit);
401		nvram_set(buf, p[1]);
402	}
403	else if  (streq (p[0], "remote") && p[1])
404	{
405		sprintf(buf, "vpn_client%d_addr", unit);
406		nvram_set(buf, p[1]);
407
408		sprintf(buf, "vpn_client%d_port", unit);
409		if(p[2])
410			nvram_set(buf, p[2]);
411		else
412			nvram_set(buf, "1194");
413	}
414	else if (streq (p[0], "resolv-retry") && p[1])
415	{
416		sprintf(buf, "vpn_client%d_retry", unit);
417		if (streq (p[1], "infinite"))
418			nvram_set(buf, "-1");
419		else
420			nvram_set(buf, p[1]);
421	}
422	else if (streq (p[0], "comp-lzo"))
423	{
424		sprintf(buf, "vpn_client%d_comp", unit);
425		if(p[1])
426			nvram_set(buf, p[1]);
427		else
428			nvram_set(buf, "adaptive");
429	}
430	else if (streq (p[0], "cipher") && p[1])
431	{
432		sprintf(buf, "vpn_client%d_cipher", unit);
433		nvram_set(buf, p[1]);
434	}
435	else if (streq (p[0], "verb") && p[1])
436	{
437		nvram_set("vpn_loglevel", p[1]);
438	}
439	else if  (streq (p[0], "ca") && p[1])
440	{
441		sprintf(buf, "vpn_client%d_crypt", unit);
442		nvram_set(buf, "tls");
443		if (streq (p[1], INLINE_FILE_TAG) && p[2])
444		{
445			sprintf(buf, "vpn_crt_client%d_ca", unit);
446#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
447			snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, buf);
448			fp = fopen(file_path, "w");
449			if(fp) {
450				fprintf(fp, "%s", strstr(p[2], "-----BEGIN"));
451				fclose(fp);
452			}
453			else
454#endif
455				nvram_set(buf, strstr(p[2], "-----BEGIN"));
456		}
457		else
458		{
459			return VPN_UPLOAD_NEED_CA_CERT;
460		}
461	}
462	else if  (streq (p[0], "cert") && p[1])
463	{
464		if (streq (p[1], INLINE_FILE_TAG) && p[2])
465		{
466			sprintf(buf, "vpn_crt_client%d_crt", unit);
467#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
468			snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, buf);
469			fp = fopen(file_path, "w");
470			if(fp) {
471				fprintf(fp, "%s", strstr(p[2], "-----BEGIN"));
472				fclose(fp);
473			}
474			else
475#endif
476				nvram_set(buf, strstr(p[2], "-----BEGIN"));
477		}
478		else
479		{
480			return VPN_UPLOAD_NEED_CERT;
481		}
482	}
483	else if  (streq (p[0], "key") && p[1])
484	{
485		if (streq (p[1], INLINE_FILE_TAG) && p[2])
486		{
487			sprintf(buf, "vpn_crt_client%d_key", unit);
488#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
489			snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, buf);
490			fp = fopen(file_path, "w");
491			if(fp) {
492				fprintf(fp, "%s", strstr(p[2], "-----BEGIN"));
493				fclose(fp);
494			}
495			else
496#endif
497				nvram_set(buf, strstr(p[2], "-----BEGIN"));
498		}
499		else
500		{
501			return VPN_UPLOAD_NEED_KEY;
502		}
503	}
504	else if (streq (p[0], "tls-auth") && p[1])
505	{
506		if (streq (p[1], INLINE_FILE_TAG) && p[2])
507		{
508			sprintf(buf, "vpn_crt_client%d_static", unit);
509#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
510			snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, buf);
511			fp = fopen(file_path, "w");
512			if(fp) {
513				fprintf(fp, "%s", strstr(p[2], "-----BEGIN"));
514				fclose(fp);
515			}
516			else
517#endif
518				nvram_set(buf, strstr(p[2], "-----BEGIN"));
519			//key-direction
520			sprintf(buf, "vpn_crt_client%d_hmac", unit);
521			if(nvram_match(buf, "-1"))	//default, disable
522				nvram_set(buf, "2");	//openvpn default value: KEY_DIRECTION_BIDIRECTIONAL
523		}
524		else
525		{
526			if(p[2]) {
527				sprintf(buf, "vpn_client%d_hmac", unit);
528				nvram_set(buf, p[2]);
529			}
530			return VPN_UPLOAD_NEED_STATIC;
531		}
532	}
533	else if (streq (p[0], "secret") && p[1])
534	{
535		sprintf(buf, "vpn_client%d_crypt", unit);
536		nvram_set(buf, "secret");
537		if (streq (p[1], INLINE_FILE_TAG) && p[2])
538		{
539			sprintf(buf, "vpn_crt_client%d_static", unit);
540#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
541			snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, buf);
542			fp = fopen(file_path, "w");
543			if(fp) {
544				fprintf(fp, "%s", strstr(p[2], "-----BEGIN"));
545				fclose(fp);
546			}
547			else
548#endif
549				nvram_set(buf, strstr(p[2], "-----BEGIN"));
550		}
551		else
552		{
553			return VPN_UPLOAD_NEED_STATIC;
554		}
555	}
556	else if (streq (p[0], "auth-user-pass"))
557	{
558		sprintf(buf, "vpn_client%d_userauth", unit);
559		nvram_set(buf, "1");
560	}
561	else if (streq (p[0], "tls-remote") && p[1])
562	{
563		sprintf(buf, "vpn_client%d_tlsremote", unit);
564		nvram_set(buf, "1");
565		sprintf(buf, "vpn_client%d_cn", unit);
566		nvram_set(buf, p[1]);
567	}
568	else if (streq (p[0], "key-direction") && p[1])
569	{
570		sprintf(buf, "vpn_client%d_hmac", unit);
571		nvram_set(buf, p[1]);
572	}
573	else if (streq (p[0], "crl-verify") && p[1])
574	{
575		if (p[2] && streq(p[2], "dir"))
576			;//TODO: not support?
577		return VPN_UPLOAD_NEED_CRL;
578	}
579	else
580	{
581		sprintf(buf, "vpn_client%d_custom", unit);
582		add_custom(buf, p);
583	}
584	return 0;
585}
586
587int
588read_config_file (const char *file, int unit)
589{
590	FILE *fp;
591	int line_num;
592	char line[OPTION_LINE_SIZE];
593	char *p[MAX_PARMS];
594	int ret = 0;
595
596	fp = fopen (file, "r");
597	if (fp)
598	{
599		line_num = 0;
600		while (fgets(line, sizeof (line), fp))
601		{
602			int offset = 0;
603			CLEAR (p);
604			++line_num;
605			/* Ignore UTF-8 BOM at start of stream */
606			if (line_num == 1 && strncmp (line, "\xEF\xBB\xBF", 3) == 0)
607				offset = 3;
608			if (parse_line (line + offset, p, SIZE (p), line_num))
609			{
610				bypass_doubledash (&p[0]);
611				check_inline_file_via_fp (fp, p);
612				ret |= add_option (p, line_num, unit);
613			}
614		}
615		fclose (fp);
616	}
617	else
618	{
619		logmessage ("OVPN", "Error opening configuration file");
620	}
621
622	CLEAR (line);
623	CLEAR (p);
624
625	return ret;
626}
627
628void reset_client_setting(int unit){
629	char nv[32];
630	char file_path[128] ={0};
631
632	sprintf(nv, "vpn_client%d_custom", unit);
633	nvram_set(nv, "");
634	sprintf(nv, "vpn_client%d_comp", unit);
635	nvram_set(nv, "-1");
636	sprintf(nv, "vpn_client%d_reneg", unit);
637	nvram_set(nv, "-1");
638	sprintf(nv, "vpn_client%d_hmac", unit);
639	nvram_set(nv, "-1");
640	sprintf(nv, "vpn_client%d_retry", unit);
641	nvram_set(nv, "-1");
642	sprintf(nv, "vpn_client%d_cipher", unit);
643	nvram_set(nv, "default");
644	sprintf(nv, "vpn_client%d_tlsremote", unit);
645	nvram_set(nv, "0");
646	sprintf(nv, "vpn_client%d_cn", unit);
647	nvram_set(nv, "");
648	sprintf(nv, "vpn_client%d_userauth", unit);
649	nvram_set(nv, "0");
650	sprintf(nv, "vpn_client%d_username", unit);
651	nvram_set(nv, "");
652	sprintf(nv, "vpn_client%d_password", unit);
653	nvram_set(nv, "");
654	sprintf(nv, "vpn_crt_client%d_ca", unit);
655	nvram_set(nv, "");
656#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
657	snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, nv);
658	unlink(file_path);
659#endif
660	sprintf(nv, "vpn_crt_client%d_crt", unit);
661	nvram_set(nv, "");
662#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
663	snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, nv);
664	unlink(file_path);
665#endif
666	sprintf(nv, "vpn_crt_client%d_key", unit);
667	nvram_set(nv, "");
668#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
669	snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, nv);
670	unlink(file_path);
671#endif
672	sprintf(nv, "vpn_crt_client%d_static", unit);
673	nvram_set(nv, "");
674#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
675	snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, nv);
676	unlink(file_path);
677#endif
678	sprintf(nv, "vpn_crt_client%d_crl", unit);
679	nvram_set(nv, "");
680#if defined(RTCONFIG_JFFS2) || defined(RTCONFIG_BRCM_NAND_JFFS2) || defined(RTCONFIG_UBIFS)
681	snprintf(file_path, sizeof(file_path) -1, "%s/%s", OVPN_FS_PATH, nv);
682	unlink(file_path);
683#endif
684}
685
686void parse_openvpn_status(int unit){
687	FILE *fpi, *fpo;
688	char buf[512];
689	char *token;
690	char nv_name[32] = "";
691	char prefix_vpn[] = "vpn_serverXX_";
692
693	sprintf(buf, "/etc/openvpn/server%d/status", unit);
694	fpi = fopen(buf, "r");
695
696	sprintf(buf, "/etc/openvpn/server%d/client_status", unit);
697	fpo = fopen(buf, "w");
698
699	snprintf(prefix_vpn, sizeof(prefix_vpn), "vpn_server%d_", unit);
700
701	if(fpi && fpo) {
702		while(!feof(fpi)){
703			CLEAR(buf);
704			if (!fgets(buf, sizeof(buf), fpi))
705				break;
706			if(!strncmp(buf, "CLIENT_LIST", 11)) {
707				//printf("%s", buf);
708				token = strtok(buf, ",");	//CLIENT_LIST
709				token = strtok(NULL, ",");	//Common Name
710				token = strtok(NULL, ",");	//Real Address
711				if(token)
712					fprintf(fpo, "%s ", token);
713				else
714					fprintf(fpo, "NoRealAddress ");
715				snprintf(nv_name, sizeof(nv_name) -1, "vpn_server%d_if", unit);
716
717				if(nvram_match(strcat_r(prefix_vpn, "if", nv_name), "tap")
718					&& nvram_match(strcat_r(prefix_vpn, "dhcp", nv_name), "1")) {
719					fprintf(fpo, "VirtualAddressAssignedByDhcp ");
720				}
721				else {
722					token = strtok(NULL, ",");	//Virtual Address
723					if(token)
724						fprintf(fpo, "%s ", token);
725					else
726						fprintf(fpo, "NoVirtualAddress ");
727				}
728				token = strtok(NULL, ",");	//Bytes Received
729				token = strtok(NULL, ",");	//Bytes Sent
730				token = strtok(NULL, ",");	//Connected Since
731				token = strtok(NULL, ",");	//Connected Since (time_t)
732				token = strtok(NULL, ",");	//Username, include'\n'
733				if(token)
734					fprintf(fpo, "%s", token);
735				else
736					fprintf(fpo, "NoUsername");
737			}
738		}
739		fclose(fpi);
740		fclose(fpo);
741	}
742}
743