<?php
set_include_path(get_include_path() . PATH_SEPARATOR . '../../app');
include_once "base_controller.php";
include_once "utils.php";
class OpenVPNController extends BaseController {
protected function signinRequired() {
return true;
}
protected function adminRequired() {
return true;
}
protected function platformControl() {
return array('white_list' => ['FS']);
}
protected function parseServerConf() {
$config = array();
$content = file_get_contents("/etc/openvpn/server.conf");
$lines = explode(PHP_EOL, $content);
foreach($lines as $line) {
//remove trailing comment
$comment_start = strpos($line, '#');
if ($comment_start)
$line = substr($line, 0, $comment_start);
$parts = explode(' ', $line, 2);
if (count($parts) != 2)
continue;
$config[trim($parts[0])] = trim($parts[1]);
}
return $config;
}
protected function doesCertFileExist($file) {
if (!isset($file))
return false;
return file_exists(build_file_path("/etc/openvpn", $file));
}
public function doAjaxGet() {
$response = array();
$config = $this->parseServerConf();
$data = array();
$keys = array('port', 'proto', 'server');
foreach($keys as $key) {
if (!isset($config[$key]))
continue;
$data[$key] = $config[$key];
}
$data['ca'] = $this->doesCertFileExist($config['ca']);
$data['serverCert'] = $this->doesCertFileExist($config['cert']) && $this->doesCertFileExist($config['key']);
$response['data'] = $data;
$this->renderAjaxSuccess2($response);
}
protected function saveServerConfig() {
$response = array();
$config = $this->parseServerConf();
if (!$this->doesCertFileExist($config['ca']))
$this->renderAjaxError($response, "Please generate CA first");
if (!$this->doesCertFileExist($config['cert']) && $this->doesCertFileExist($config['key']))
$this->renderAjaxError($response, "Please generate server certificate first");
if (!isset($_POST['server']))
$this->renderAjaxError($response, "'server' config is missing");
if (!isset($_POST['proto']) || ($_POST['proto'] != 'tcp' && $_POST['proto'] != 'udp'))
$this->renderAjaxError($response, "'proto' config is invalid");
if (!isset($_POST['port']) || preg_match('/^[0-9]{1,5}$/', $_POST['port'])!=1 )
$this->renderAjaxError($response, "'port' config is invalid");
$args = array();
$args['proto'] = $_POST['proto'];
$args['port'] = $_POST['port'];
$args['server'] = $_POST['server'];
$args['cert'] = $config['cert'];
$args['key'] = $config['key'];
file_put_contents("/etc/openvpn/server.conf",
render_template("server_conf_template.php", $args));
execCmd("/etc/init.d/S60openvpn restart");
$this->renderAjaxSuccess2($response);
}
protected function generateCA() {
$response = array();
if (!isset($_POST['cn']))
$this->renderAjaxError($response, "'Common Name' of CA is missing");
$common_name = $_POST['cn'];
if (preg_match('/^[a-zA-Z0-9-_]{1,64}$/', $common_name) != 1)
$this->renderAjaxError($response, "'Common Name' is invalid");
//prepare pki
// 1. init pki folder
// 2. generate CA
// 3. generate dh.pem (slow, ~13s)
// 4. generate ta.key
$output = shell_exec('cd /etc/openvpn && easyrsa --batch init-pki && easyrsa --batch --req-cn="' . escapeshellarg($common_name) . '" --days=3650 build-ca nopass && openssl dhparam -dsaparam -out pki/dh.pem 2048 && openvpn --genkey --secret ta.key && echo "SUCCESS"')
if (is_null($output))
$this->renderAjaxError($response, "failed to create CA");
if (preg_match("/SUCCESS\s*$/", $output) != 1)
$this->renderAjaxError($response, "failed to create CA");
$this->renderAjaxSuccess2($response);
}
protected function generateServerCert() {
$response = array();
if (!isset($_POST['cn']))
$this->renderAjaxError($response, "'Common Name' of sever certificate is missing");
$common_name = $_POST['cn'];
if (preg_match('/^[a-zA-Z0-9-_]{1,64}$/', $common_name) != 1)
$this->renderAjaxError($response, "'Common Name' is invalid");
if (!$this->doesCertFileExist("pki/ca.crt"))
$this->renderAjaxError($response, "can not create server certificate without CA");
$output = shell_exec('cd /etc/openvpn && easyrsa --batch --days=3650 build-server-full ' . escapeshellarg($common_name) .' nopass && echo "SUCCESS"')
if (is_null($output))
$this->renderAjaxError($response, "failed to create server certificate");
if (preg_match("/SUCCESS\s*$/", $output) != 1)
$this->renderAjaxError($response, "failed to create server certificate");
//update server.conf with new openvpn server keypair
$config = $this->parseServerConf();
$args = array();
$args['proto'] = $config['proto'];
$args['port'] = $config['port'];
$args['server'] = $config['server'];
$args['cert'] = "pki/issued/" . $common_name . ".crt";
$args['key'] = "pki/private/" . $common_name . ".key";
file_put_contents("/etc/openvpn/server.conf",
render_template("server_conf_template.php", $args));
$this->renderAjaxSuccess2($response);
}
protected function generateClientCert() {
$response = array();
if (!isset($_POST['cn']))
$this->renderAjaxError($response, "'Common Name' of client certificate is missing");
$common_name = $_POST['cn'];
if (preg_match('/^[a-zA-Z0-9-_]{1,64}$/', $common_name) != 1)
$this->renderAjaxError($response, "'Common Name' is invalid");
if (!isset($_POST['remote']))
$this->renderAjaxError($response, "'remote' parameter is missing");
//prevent possible duplicate client cert
if ($this->doesCertFileExist('pki/issued/'.$common_name.'.crt'))
$this->renderAjaxError($response, "client certificate '".$common_name."' already exists.");
if (!$this->doesCertFileExist("pki/ca.crt"))
$this->renderAjaxError($response, "can not create client certificate without CA");
$output = shell_exec('cd /etc/openvpn && easyrsa --batch --days=3650 build-client-full ' . escapeshellarg($common_name) . ' nopass && echo "SUCCESS"')
if (is_null($output))
$this->renderAjaxError($response, "failed to create client certificate");
if (preg_match("/SUCCESS\s*$/", $output) != 1)
$this->renderAjaxError($response, "failed to create client certificate");
$url = 'openvpn_controller.php?action=dlClientCert&cn=' . urlencode($common_name) . '&remote=' . urlencode($_POST['remote']);
$this->redirect($url)
}
public function doAjaxPost() {
$response = array();
if (!isset($_POST['action']))
$this->renderAjaxError($response, "'action' parameter is missing");
$action = $_POST['action'];
if ($action == 'saveConfig')
$this->saveServerConfig();
else if ($action == 'genCA')
$this->generateCA();
else if ($action == 'genServerCert')
$this->generateServerCert();
else if ($action == 'genClientCert')
$this->generateClientCert();
else
$this->renderAjaxError($response, "'action' parameter is invalid");
}
public function doGet() {
if (!isset($_GET['cn']))
die("'cn' parameter is missing");
$common_name = $_GET['cn'];
if (preg_match('/^[a-zA-Z0-9-_]{1,64}$/', $common_name) != 1)
die("'Common Name' is invalid");
if (!isset($_GET['remote']))
die("'remote' parameter is missing");
//generate client.ovpn
$server_config = $this->parseServerConf();
$args = array();
$args['proto'] = $server_config['proto'];
$args['remote'] = $_GET['remote'];
$args['cn'] = $common_name;
$client_config_str = render_template("client_ovpn_template.php", $args);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'. $common_name . '.ovpn"')
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . strlen($client_config_str))
print $client_config_str;
}
}
$controller = new OpenVPNController();
$controller->run();
?>