Project

General

Profile

Download (8.93 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
require('config.inc');
3

    
4
/* $Id$ */
5
/*
6
	openvpn.inc
7
	part of pfSense (www.pfSense.com)
8
	(C)2006 Fernando Lemos
9
	All rights reserved.
10

    
11
	Redistribution and use in source and binary forms, with or without
12
	modification, are permitted provided that the following conditions are met:
13

    
14
	1. Redistributions of source code must retain the above copyright notice,
15
	   this list of conditions and the following disclaimer.
16

    
17
	2. Redistributions in binary form must reproduce the above copyright
18
	   notice, this list of conditions and the following disclaimer in the
19
	   documentation and/or other materials provided with the distribution.
20

    
21
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
	POSSIBILITY OF SUCH DAMAGE.
31
*/
32

    
33
// Return the list of ciphers OpenVPN supports
34
function openvpn_get_ciphers($pkg) {
35
                foreach ($pkg['fields']['field'] as $i => $field) {
36
                        if ($field['fieldname'] == 'crypto') break;
37
                }
38
                $option_array = &$pkg['fields']['field'][$i]['options']['option'];
39
                $ciphers_out = shell_exec('openvpn --show-ciphers | grep "default key" | awk \'{print $1, "(" $2 "-" $3 ")";}\'');
40
                $ciphers = explode("\n", trim($ciphers_out));
41
		sort($ciphers);
42
                foreach ($ciphers as $cipher) {
43
                        $value = explode(' ', $cipher);
44
                        $value = $value[0];
45
                        $option_array[] = array('value' => $value, 'name' => $cipher);
46
                }
47
}
48

    
49

    
50
// Do the input validation
51
function openvpn_validate_input($mode, $post, $input_errors) {
52
	$Mode = ucfirst($mode);
53

    
54
	$port = trim($post['port']);
55
	if ($port && (!is_numeric($port) || ($port < 0) || ($port > 65535)))
56
		$input_errors[] = 'The field \'Port\' should contain a valid port number, between 1 and 65536.';
57
	if ($mode == 'client') {
58
		$server_port = trim($post['serverport']);
59
		if ($server_port && (!is_numeric($server_port) || ($server_port < 0) || ($port > 65535)))
60
			$input_errors[] = 'The field \'Server port\' should contain a valid port number, between 1 and 65536.';
61
	}
62
												
63
	$reqfields = array('local_ip', 'remote_ip');
64
	$reqfieldsn = array('Local IP', 'Remote IP');
65
	foreach($reqfields as $i => $field) {
66
		$value = trim($post[$field]);
67
		if ($value and (!is_ipaddr($value)))
68
			$input_errors[] = "The field '{$reqfieldsn[$i]}' must contain a valid IP address";
69
	}
70

    
71
	if ($mode == 'client') {
72
		$server_addr = trim($post['serveraddr']);
73
		if ($value && !(is_domain($server_addr) || is_ipaddr($server_addr)))
74
			$input_errors[] = 'The field \'Server address\' must contain a valid IP address or domain name.';
75
	}
76

    
77
	$value = trim($post['ipblock']);
78
	if ($value) {
79
		list($ip, $mask) = explode('/', $value);
80
		if (!is_ipaddr($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0))
81
			$input_errors[] = "The field 'IP block' must contain a valid CIDR range.";
82
	}
83

    
84
	if ($_POST['auth_method'] == 'shared_key') {
85
		$reqfields[] = 'shared_key';
86
		$reqfieldsn[] = 'Shared key';
87
	}
88
	else {
89
		$req = explode(' ', "ca_cert {$mode}_cert {$mode}_key");
90
		$reqn = array(	'CA certificate',
91
				ucfirst($mode) . ' certificate',
92
				ucfirst($mode) . ' key');
93
		$reqfields = array_merge($reqfields, $req);
94
		$reqfieldsn = array_merge($reqfieldsn, $reqn);
95
		if ($mode == 'server') {
96
			$reqfields[] = 'dh_params';
97
			$reqfieldsn[] = 'DH parameters';
98
		}
99
	}
100
	do_input_validation($post, $reqfields, $reqfieldsn, &$input_errors);
101

    
102
	$value = trim($post['shared_key']);
103
	$items = array();
104
	if ($_POST['auth_method'] == 'shared_key') {
105
		$items[] = array(	'field' => 'shared_key',
106
					'string' => 'OpenVPN Static key V1',
107
					'name' => 'Shared key');
108
	}
109
	else {
110
		$items[] = array(	'field' => 'ca_cert',
111
					'string' => 'CERTIFICATE',
112
					'name' => 'CA certificate');
113
		$items[] = array(	'field' => "{$mode}_cert",
114
					'string' => 'CERTIFICATE',
115
					'name' => "$Mode certificate");
116
		$items[] = array(	'field' => "{$mode}_key",
117
					'string' => 'RSA PRIVATE KEY',
118
					'name' => "$Mode key");
119
		if ($mode == 'server') {
120
			$items[] = array(	'field' => 'dh_params',
121
						'string' => 'DH PARAMETERS',
122
						'name' => 'DH parameters');
123
			$items[] = array(	'field' => 'crl',
124
						'string' => 'X509 CRL',
125
						'name' => 'CRL');
126
		}
127
	}
128
	foreach ($items as $item) {
129
		$value = trim($_POST[$item['field']]);
130
		$string = $item['string'];
131
		if ($value && (!strstr($value, "-----BEGIN {$string}-----") || !strstr($value, "-----END {$string}-----")))
132
			$input_errors[] = "The field '{$item['name']}' does not appear to be valid";
133
	}
134
}
135

    
136

    
137
// Rewrite the settings
138
function openvpn_reconfigure($mode, $id) {
139
	global $g, $config;
140

    
141
	$settings = $config['installedpackages']["openvpn$mode"]['config'][$id];
142
	if ($settings['disable']) return;
143

    
144
	// Set up the keys
145
	// Note that the keys' extension is the directive that goes to the config file
146
	$base_file = $g['varetc_path'] . "/openvpn_{$mode}{$id}.";
147
	$keys = array();
148
	if ($settings['auth_method'] == 'shared_key')
149
		$keys[] = array('field' => 'shared_key', 'ext'  => 'secret', 'directive' => 'secret');
150
	else {
151
		$keys[] = array('field' => 'ca_cert', 'ext' => 'ca', 'directive' => 'ca');
152
		$keys[] = array('field' => "{$mode}_cert", 'ext' => 'cert', 'directive' => 'cert');
153
		$keys[] = array('field' => "{$mode}_key", 'ext' => 'key', 'directive' => 'key');
154
		if ($mode == 'server')
155
			$keys[] = array('field' => 'dh_params', 'ext' => 'dh', 'directive' => 'dh');
156
		if ($settings['crl'])
157
			$keys[] = array('field' => 'crl', 'ext' => 'crl', 'directive' => 'crl-verify');
158
	}
159
	foreach($keys as $key) {
160
		$filename = $base_file . $key['ext'];
161
		file_put_contents($filename, base64_decode($settings[$key['field']]));
162
		chown($filename, 'nobody');
163
		chgrp($filename, 'nobody');
164
	}
165

    
166
	$proto = ($settings['protocol'] == 'UDP' ? 'udp' : "tcp-{$mode}");
167
	$port = $settings['port'];
168
	$ifconfig = $settings['local_ip'] . ' ' . $settings['remote_ip'];
169
	list($route_ip, $route_mask) = explode('/', $settings['ipblock']);
170
	$route_mask = gen_subnet_mask($route_mask);
171
	$cipher = $settings['crypto'];
172
	$openvpn_conf = <<<EOD
173
user nobody
174
group nobody
175
daemon
176
keepalive 10 60
177
ping-timer-rem
178
persist-tun
179
persist-key
180
dev tun
181
proto $proto
182
port $port
183
ifconfig $ifconfig
184
route $route_ip $route_mask
185
cipher $cipher
186

    
187
EOD;
188
	if ($settings['auth_method'] == 'pki')
189
		$openvpn_conf .= "tls-$mode\n";
190

    
191
	// Write the settings for the keys
192
	foreach ($keys as $key)
193
		$openvpn_conf .= $key['directive'] . ' ' . $base_file . $key['ext'] . "\n";
194

    
195
	if ($mode == 'client') $openvpn_conf .= 'remote ' . $settings['serveraddr'] . ' ' .$settings['serverport'] . "\n";
196
	if ($settings['use_lzo']) $openvpn_conf .= "comp-lzo\n";
197
	if ($settings['dynamic_ip']) $openvpn_conf .= "persist-remote-ip\n";
198

    
199
	file_put_contents($g['varetc_path'] . "/openvpn_{$mode}{$id}.conf", $openvpn_conf);
200
}
201

    
202

    
203
function openvpn_restart($mode, $id) {
204
	global $g, $config;
205

    
206
	$pidfile = $g['varrun_path'] . "/openvpn_{$mode}{$id}.pid";
207
	killbypid($pidfile);
208
	sleep(2);
209

    
210
	$settings = $config['installedpackages']["openvpn$mode"]['config'][$id];
211
	if ($settings['disable']) return;
212

    
213
	$configfile = $g['varetc_path'] . "/openvpn_{$mode}{$id}.conf";
214
	mwexec("openvpn --config $configfile --writepid $pidfile");
215
}
216

    
217

    
218
// Resync the configuration and restart the VPN 
219
function openvpn_resync($mode, $id) {
220
	openvpn_reconfigure($mode, $id);
221
	openvpn_restart($mode, $id);
222
}
223

    
224

    
225
// Resync and restart all VPNs
226
function openvpn_resync_all() {
227
	global $config;
228

    
229
	foreach (array('server', 'client') as $mode) {
230
		if (is_array($config['installedpackages']["openvpn$mode"]['config'])) {
231
			foreach ($config['installedpackages']["openvpn$mode"]['config'] as $id => $settings)
232
				openvpn_resync($mode, $id);
233
		}
234
	}
235
}
236

    
237

    
238
function openvpn_print_javascript($mode) {
239
	$javascript = <<<EOD
240
<script language="JavaScript">
241
<!--
242
function onAuthMethodChanged() {
243
	var method = document.iform.auth_method;
244
	var endis = (method.options[method.selectedIndex].value == 'shared_key');
245

    
246
	document.iform.shared_key.disabled = !endis;
247
	document.iform.ca_cert.disabled = endis;
248
	document.iform.{$mode}_cert.disabled = endis;
249
	document.iform.{$mode}_key.disabled = endis;
250

    
251
EOD;
252
	if ($mode == 'server') {
253
		$javascript .= "\tdocument.iform.dh_params.disabled = endis;\n";
254
		$javascript .= "\tdocument.iform.crl.disabled = endis;\n";
255
	}
256
	$javascript .= <<<EOD
257
}
258
//-->
259
</script>
260

    
261
EOD;
262
	print($javascript);
263
}
264

    
265

    
266
function openvpn_print_javascript2() {
267
	$javascript = <<<EOD
268
<script language="JavaScript">
269
<!--
270
	onAuthMethodChanged();
271
//-->
272
</script>
273

    
274
EOD;
275
	print($javascript);
276
}
277
?>
(13-13/27)