1/*
2 * pptp.c
3 *
4 * Copyright (C) 2007 Sebastian Gottschall <gottschall@dd-wrt.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 *
20 * $Id:
21 */
22
23#include <rc.h>
24#include <stdlib.h>
25#include <bcmnvram.h>
26#include <shutils.h>
27#include <utils.h>
28#include <syslog.h>
29#include <errno.h>
30#include <sys/stat.h>
31
32void get_broadcast(char *ipaddr, char *netmask)
33{
34        int ip2[4], mask2[4];
35        unsigned char ip[4], mask[4];
36
37        if (!ipaddr || !netmask)
38                return;
39
40        sscanf(ipaddr, "%d.%d.%d.%d", &ip2[0], &ip2[1], &ip2[2], &ip2[3]);
41        sscanf(netmask, "%d.%d.%d.%d", &mask2[0], &mask2[1], &mask2[2],
42               &mask2[3]);
43        int i = 0;
44
45        for (i = 0; i < 4; i++) {
46                ip[i] = ip2[i];
47                mask[i] = mask2[i];
48                ip[i] = (ip[i] & mask[i]) | (0xff & ~mask[i]);
49        }
50
51        sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
52
53        //fprintf(stderr, "get_broadcast return %s\n", value);
54}
55
56char *pptp_encode(char *str, char *output)
57{
58	int i;
59	int j;
60
61	i=j=0;
62
63	while(*(str+i)) {
64		if(*(str+i)==' ' || *(str+i)=='\\' || *(str+i)=='*' || *(str+i)=='\'' || *(str+i)=='"' || *(str+i)=='#') {
65			*(output+j++)='\\';
66			*(output+j++)=*(str+i);
67		}
68		else *(output+j++) = *(str+i);
69		i++;
70	}
71
72	*(output+j)=0;
73
74	return output;
75}
76
77void write_chap_secret(char *file)
78{
79        FILE *fp;
80        char *nv, *nvp, *b;
81        char *username, *passwd;
82        char namebuf[256], passwdbuf[256];
83
84        fp=fopen(file, "w");
85
86        if (fp==NULL) return;
87
88        nv = nvp = strdup(nvram_safe_get("pptpd_clientlist"));
89
90        if(nv) {
91            	while ((b = strsep(&nvp, "<")) != NULL) {
92                	if((vstrsep(b, ">", &username, &passwd)!=2)) continue;
93	                if(strlen(username)==0||strlen(passwd)==0) continue;
94        	        fprintf(fp, "%s * %s *\n", pptp_encode(username, namebuf), pptp_encode(passwd, passwdbuf));
95            	}
96            	free(nv);
97        }
98        fclose(fp);
99}
100
101void start_pptpd(void)
102{
103	int ret = 0, mss = 0, manual_dns = 0, pptpd_opt = 0;
104	FILE *fp;
105
106	int pid = getpid();
107	_dprintf("start_pptpd: getpid= %d\n", pid);
108
109	if(getpid() != 1) {
110		notify_rc("start_pptpd");
111		return;
112	}
113
114	if (!nvram_match("pptpd_enable", "1")) {
115		return;
116	}
117
118	// cprintf("stop vpn modules\n");
119	// stop_vpn_modules ();
120
121	// Create directory for use by pptpd daemon and its supporting files
122	mkdir("/tmp/pptpd", 0744);
123	//cprintf("open options file\n");
124	// Create options file that will be unique to pptpd to avoid interference
125	// with pppoe and pptp
126	fp = fopen("/tmp/pptpd/options.pptpd", "w");
127	fprintf(fp, "logfile /var/log/pptpd-pppd.log\n");
128	//fprintf(fp, "debug dump logfd 2 nodetach\n");
129	if (nvram_match("pptpd_radius", "1"))
130		fprintf(fp, "plugin radius.so\nplugin radattr.so\n"
131			"radius-config-file /tmp/pptpd/radius/radiusclient.conf\n");
132
133	fprintf(fp, "lock\n"
134		"name *\n"
135		"proxyarp\n"
136//		"ipcp-accept-local\n"
137//		"ipcp-accept-remote\n"
138		"lcp-echo-failure 10\n"
139		"lcp-echo-interval 6\n"
140		"deflate 0\n" "auth\n" "-chap\n"
141		"nomppe-stateful\n");
142
143	pptpd_opt = nvram_get_int("pptpd_chap");
144	fprintf(fp, "%smschap\n", (pptpd_opt == 0 || pptpd_opt & 1) ? "+" : "-");
145	fprintf(fp, "%smschap-v2\n", (pptpd_opt == 0 || pptpd_opt & 2) ? "+" : "-");
146
147	pptpd_opt = nvram_get_int("pptpd_mppe");
148	if (pptpd_opt == 0)
149		pptpd_opt = 1 | 4 | 8;
150	if (pptpd_opt & (1 | 2 | 4)) {
151		fprintf(fp, "%s", (pptpd_opt & 8) ? "" : "require-mppe\n");
152  		fprintf(fp, "%smppe-128\n", (pptpd_opt & 1) ? "require-" : "no");
153  		fprintf(fp, "%smppe-56\n", (pptpd_opt & 2) ? "require-" : "no");
154  		fprintf(fp, "%smppe-40\n", (pptpd_opt & 4) ? "require-" : "no");
155	} else
156  		fprintf(fp, "nomppe nomppc\n");
157
158	fprintf(fp, "chapms-strip-domain\n"
159		"chap-secrets /tmp/pptpd/chap-secrets\n"
160		"ip-up-script /tmp/pptpd/ip-up\n"
161		"ip-down-script /tmp/pptpd/ip-down\n"
162		"mtu %s\n" "mru %s\n",
163		nvram_get("pptpd_mtu") ? nvram_get("pptpd_mtu") : "1450",
164		nvram_get("pptpd_mru") ? nvram_get("pptpd_mru") : "1450");
165        //WINS Server
166	int wins_count = 0;
167        if (nvram_match("pptpd_ms_network", "1") && nvram_match("smbd_enable", "1"))
168                wins_count += fprintf(fp, "ms-wins %s\n", nvram_safe_get("lan_ipaddr")) > 0 ? 1 : 0;
169        if (strlen(nvram_safe_get("pptpd_wins1")) && (wins_count < 2))
170                wins_count += fprintf(fp,"ms-wins %s\n", nvram_safe_get("pptpd_wins1")) > 0 ? 1 : 0;
171        if (strlen(nvram_safe_get("pptpd_wins2")) && (wins_count < 2))
172                wins_count += fprintf(fp,"ms-wins %s\n", nvram_safe_get("pptpd_wins2")) > 0 ? 1 : 0;
173
174	//DNS Server
175	if (strlen(nvram_safe_get("pptpd_dns1"))) {
176		fprintf(fp, "ms-dns %s\n", nvram_safe_get("pptpd_dns1"));
177		manual_dns=1;
178	}
179	if (strlen(nvram_safe_get("pptpd_dns2"))) {
180		fprintf(fp, "ms-dns %s\n", nvram_safe_get("pptpd_dns2"));
181		manual_dns=1;
182	}
183	if(!manual_dns && !nvram_match("lan_ipaddr", ""))
184                fprintf(fp, "ms-dns %s\n", nvram_safe_get("lan_ipaddr"));
185
186	// force ppp interface starting from 10
187	fprintf(fp, "minunit 10\n");
188
189	// Following is all crude and need to be revisited once testing confirms
190	// that it does work
191	// Should be enough for testing..
192	if (nvram_match("pptpd_radius", "1")) {
193		if (nvram_get("pptpd_radserver") != NULL
194		    && nvram_get("pptpd_radpass") != NULL) {
195
196			fclose(fp);
197
198			mkdir("/tmp/pptpd/radius", 0744);
199
200			fp = fopen("/tmp/pptpd/radius/radiusclient.conf", "w");
201			fprintf(fp, "auth_order radius\n"
202				"login_tries 4\n"
203				"login_timeout 60\n"
204				"radius_timeout 10\n"
205				"nologin /etc/nologin\n"
206				"servers /tmp/pptpd/radius/servers\n"
207				"dictionary /etc/dictionary\n"
208				"seqfile /var/run/radius.seq\n"
209				"mapfile /etc/port-id-map\n"
210				"radius_retries 3\n"
211				"authserver %s:%s\n",
212				nvram_get("pptpd_radserver"),
213				nvram_get("pptpd_radport") ?
214				nvram_get("pptpd_radport") : "radius");
215
216			if (nvram_get("pptpd_radserver") != NULL
217			    && nvram_get("pptpd_acctport") != NULL)
218				fprintf(fp, "acctserver %s:%s\n",
219					nvram_get("pptpd_radserver"),
220					nvram_get("pptpd_acctport") ?
221					nvram_get("pptpd_acctport") :
222					"radacct");
223			fclose(fp);
224
225			fp = fopen("/tmp/pptpd/radius/servers", "w");
226			fprintf(fp, "%s\t%s\n", nvram_get("pptpd_radserver"),
227				nvram_get("pptpd_radpass"));
228			fclose(fp);
229
230		} else
231			fclose(fp);
232	} else
233		fclose(fp);
234
235	// Create pptpd.conf options file for pptpd daemon
236	fp = fopen("/tmp/pptpd/pptpd.conf", "w");
237	fprintf(fp, "localip %s\n"
238		"remoteip %s\n", nvram_safe_get("lan_ipaddr"),
239		nvram_safe_get("pptpd_clients"));
240	if (nvram_invmatch("pptpd_broadcast", "") &&
241	    nvram_invmatch("pptpd_broadcast", "disable")) {
242		fprintf(fp, "bcrelay %s,%s\n",
243			nvram_safe_get("lan_ifname"), "ppp1[0-9].*");
244	}
245
246	fclose(fp);
247
248	// Create ip-up and ip-down scripts that are unique to pptpd to avoid
249	// interference with pppoe and pptp
250	/*
251	 * adjust for tunneling overhead (mtu - 40 byte IP - 108 byte tunnel
252	 * overhead)
253	 */
254	if (nvram_match("mtu_enable", "1"))
255		mss = nvram_get_int("wan_mtu") - 40 - 108;
256	else
257		mss = 1500 - 40 - 108;
258	char bcast[32];
259
260	strcpy(bcast, nvram_safe_get("lan_ipaddr"));
261	get_broadcast(bcast, nvram_safe_get("lan_netmask"));
262
263	fp = fopen("/tmp/pptpd/ip-up", "w");
264	fprintf(fp, "#!/bin/sh\n" "startservice set_routes\n"	// reinitialize
265		"echo $PPPD_PID $1 $5 $6 $PEERNAME >> /tmp/pptp_connected\n"
266		"iptables -I INPUT -i $1 -j ACCEPT\n" "iptables -I FORWARD -i $1 -j ACCEPT\n"
267		"iptables -I FORWARD -i $1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu\n"
268		"iptables -t nat -I PREROUTING -i $1 -p udp -m udp --sport 9 -j DNAT --to-destination %s "	// rule for wake on lan over pptp tunnel
269		"%s\n", bcast,
270		nvram_get("pptpd_ipup_script") ? nvram_get("pptpd_ipup_script") : "");
271
272#if defined(CONFIG_BCMWL5) || defined(RTCONFIG_BCMWL6) || defined(RTCONFIG_BCMARM)
273        /* mark connect to bypass CTF */
274        if(nvram_match("ctf_disable", "0"))
275		fprintf(fp, "iptables -t mangle -A FORWARD -i $1 -m state --state NEW -j MARK --set-mark 0x01/0x7\n");
276#endif
277
278        //Add static router for vpn client
279        char *nv, *nvp, *b;
280        char *pptpd_client, *vpn_network, *vpn_netmask;
281
282        nv = nvp = strdup(nvram_safe_get("pptpd_sr_rulelist"));
283        if(nv) {
284                while ((b = strsep(&nvp, "<")) != NULL) {
285                        if((vstrsep(b, ">", &pptpd_client, &vpn_network, &vpn_netmask)!=3)) continue;
286                        if(strlen(pptpd_client)==0||strlen(vpn_network)==0||strlen(vpn_netmask)==0) continue;
287                        fprintf(fp, "if[ \"$PEERNAME\" == \"%s\" ] then;\n", pptpd_client);
288                        fprintf(fp, "route del -net %s netmask %s\n", vpn_network, vpn_netmask);
289                        fprintf(fp, "route add -net %s netmask %s dev $1\n", vpn_network, vpn_netmask);
290                        fprintf(fp, "fi\n");
291                }
292                free(nv);
293        }
294	fclose(fp);
295	fp = fopen("/tmp/pptpd/ip-down", "w");
296	fprintf(fp, "#!/bin/sh\n" "grep -v $1  /tmp/pptp_connected > /tmp/pptp_connected.new\n"
297		"mv /tmp/pptp_connected.new /tmp/pptp_connected\n"
298		"iptables -D FORWARD -i $1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu\n"
299		"iptables -D INPUT -i $1 -j ACCEPT\n"
300		"iptables -D FORWARD -i $1 -j ACCEPT\n"
301		"iptables -t nat -D PREROUTING -i $1 -p udp -m udp --sport 9 -j DNAT --to-destination %s "	// rule for wake on lan over pptp tunnel
302		"%s\n", bcast,
303		nvram_get("pptpd_ipdown_script") ? nvram_get("pptpd_ipdown_script") : "");
304#if defined(CONFIG_BCMWL5) || defined(RTCONFIG_BCMWL6) || defined(RTCONFIG_BCMARM)
305        /* mark connect to bypass CTF */
306        if(nvram_match("ctf_disable", "0"))
307		fprintf(fp, "iptables -t mangle -D FORWARD -i $1 -m state --state NEW -j MARK --set-mark 0x01/0x7\n");
308#endif
309	fclose(fp);
310	chmod("/tmp/pptpd/ip-up", 0744);
311	chmod("/tmp/pptpd/ip-down", 0744);
312
313	// Exctract chap-secrets from nvram
314	write_chap_secret("/tmp/pptpd/chap-secrets");
315
316	chmod("/tmp/pptpd/chap-secrets", 0600);
317
318	// Execute pptpd daemon
319	ret =
320	    eval("pptpd", "-c", "/tmp/pptpd/pptpd.conf", "-o",
321		 "/tmp/pptpd/options.pptpd");
322
323	_dprintf("start_pptpd: ret= %d\n", ret);
324	//dd_syslog(LOG_INFO, "pptpd : pptp daemon successfully started\n");
325	return;
326}
327
328void stop_pptpd(void)
329{
330	if (getpid() != 1) {
331		notify_rc("stop_pptpd");
332	}
333
334	killall_tk("pptpd");
335	killall_tk("bcrelay");
336	return;
337}
338
339