Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tinc package for pfSense 2.3 #149

Merged
merged 18 commits into from
Dec 14, 2016
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions security/pfSense-pkg-tinc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# $FreeBSD$

PORTNAME= pfSense-pkg-tinc
PORTVERSION= 1.0.28
CATEGORIES= security
MASTER_SITES= # empty
DISTFILES= # empty
EXTRACT_ONLY= # empty

MAINTAINER= dinoex@FreeBSD.org
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dinoex@FreeBSD.org will not maintain pfSense package, you can set maintainership to coreteam@pfsense.org

COMMENT= pfSense package tinc

LICENSE= GPLv3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is APACHE20 and not GPLv3


RUN_DEPENDS= ${LOCALBASE}/sbin/tincd:security/tinc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace spaces by TAB here to silence portlint warnings


NO_BUILD= yes
NO_MTREE= yes

SUB_FILES= pkg-install pkg-deinstall
SUB_LIST= PORTNAME=${PORTNAME}

do-extract:
${MKDIR} ${WRKSRC}

do-install:
${MKDIR} ${STAGEDIR}${PREFIX}/pkg
${MKDIR} ${STAGEDIR}/etc/inc/priv
${MKDIR} ${STAGEDIR}${PREFIX}/www
${MKDIR} ${STAGEDIR}${DATADIR}
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/tinc.inc \
${STAGEDIR}${PREFIX}/pkg
${INSTALL_DATA} ${FILESDIR}/etc/inc/priv/tinc.priv.inc \
${STAGEDIR}/etc/inc/priv
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/tinc.xml \
${STAGEDIR}${PREFIX}/pkg
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/tinc_hosts.xml \
${STAGEDIR}${PREFIX}/pkg
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/status_tinc.php \
${STAGEDIR}${PREFIX}/www
${INSTALL_DATA} ${FILESDIR}${DATADIR}/info.xml \
${STAGEDIR}${DATADIR}
@${REINPLACE_CMD} -i '' -e "s|%%PKGVERSION%%|${PKGVERSION}|" \
${STAGEDIR}${DATADIR}/info.xml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other XML files containing macro %%PKGVERSION%% should be added to this REINPLACE_CMD statement so version is automatically added to them


.include <bsd.port.mk>
44 changes: 44 additions & 0 deletions security/pfSense-pkg-tinc/files/etc/inc/priv/tinc.priv.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/*
tinc.priv.inc
part of pfSense (http://www.pfSense.org/)
Copyright (C) 2015 ESF, LLC
All rights reserved.

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

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

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

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We moved to APACHE20 license, please modify text accodingly. You can see an example at:
https://github.com/pfsense/FreeBSD-ports/blob/devel/security/pfSense-pkg-sudo/files/etc/inc/priv/sudo.priv.inc#L2

*/
global $priv_list;

$priv_list['page-vpn-tinc'] = array();
$priv_list['page-vpn-tinc']['name'] = "WebCfg - VPN: tinc package";
$priv_list['page-vpn-tinc']['descr'] = "Allow access to tinc package GUI";
$priv_list['page-vpn-tinc']['match'] = array();

$priv_list['page-vpn-tinc']['match'][] = "pkg.php?xml=tinc.xml*";
$priv_list['page-vpn-tinc']['match'][] = "pkg.php?xml=tinc_hosts.xml*";

$priv_list['page-vpn-tinc']['match'][] = "pkg_edit.php?xml=tinc.xml*";
$priv_list['page-vpn-tinc']['match'][] = "pkg_edit.php?xml=tinc_hosts.xml*";

$priv_list['page-vpn-tinc']['match'][] = "status_tinc.php*";

?>
3 changes: 3 additions & 0 deletions security/pfSense-pkg-tinc/files/pkg-deinstall.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

/usr/local/bin/php -f /etc/rc.packages %%PORTNAME%% ${2}
7 changes: 7 additions & 0 deletions security/pfSense-pkg-tinc/files/pkg-install.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

if [ "${2}" != "POST-INSTALL" ]; then
exit 0
fi

/usr/local/bin/php -f /etc/rc.packages %%PORTNAME%% ${2}
275 changes: 275 additions & 0 deletions security/pfSense-pkg-tinc/files/usr/local/pkg/tinc.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
<?php
/*
tinc.inc
part of pfSense (https://www.pfSense.org/)
Copyright (C) 2012-2015 ESF, LLC
All rights reserved.

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

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

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

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix license text

*/
require_once('config.inc');
require_once('service-utils.inc');
require_once('util.inc');
/* include_once('guiconfig.inc'); is needed for clear_log_file() during package installation while booting.
* However, guiconfig.inc includes authgui.inc which requires a valid php session_auth() and exits when not found.
* So we include the function here.
*/
if (!function_exists('clear_log_file')) {

function clear_log_file($logfile = "/var/log/system.log", $restart_syslogd = true) {
require_once('system.inc');
global $config;
if ($restart_syslogd) {
exec("/usr/bin/killall syslogd");
}
if (isset($config['system']['disablesyslogclog'])) {
unlink($logfile);
touch($logfile);
} else {
$log_size = isset($config['syslog']['logfilesize']) ? $config['syslog']['logfilesize'] : "511488";
if (isset($config['system']['usefifolog'])) {
exec("/usr/sbin/fifolog_create -s {$log_size} " . escapeshellarg($logfile));
} else {
exec("/usr/local/sbin/clog -i -s {$log_size} " . escapeshellarg($logfile));
}
}
if ($restart_syslogd) {
system_syslogd_start();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove clear_log_file() copy from here and require_once system.inc, this function is available there

}

function tinc_save() {
global $config, $configpath;
$configpath = '/usr/local/etc/tinc';

conf_mount_rw();

rename("{$configpath}", "{$configpath}.old");
safe_mkdir("{$configpath}");
safe_mkdir("{$configpath}/hosts");
touch("{$configpath}/WARNING-ENTIRE_DIRECTORY_ERASED_ON_SAVE_FROM_GUI");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't thing this is necessary, users shoudn't touch config files manually on pfSense at all

if (is_array($config['installedpackages']['tinc']['config'])) {
$tincconf = &$config['installedpackages']['tinc']['config'][0];
} else {
$tincconf = array();
}

// No proper config, bail out.
if (!isset($tincconf['name']) || empty($tincconf['name'])) {
log_error("[tinc] Cannot configure (name not set). Check your configuration.");
return;
}

$fout = fopen("{$configpath}/tinc.conf", "w");
fwrite($fout, "name=" . $tincconf['name'] . "\n");
fwrite($fout, "AddressFamily=" . $tincconf['addressfamily'] . "\n");

if (!is_array($config['installedpackages']['tinchosts']['config'])) {
$config['installedpackages']['tinchosts']['config'] = array();
}
foreach ($config['installedpackages']['tinchosts']['config'] as $host) {
if ($host['connect']) {
fwrite($fout, "ConnectTo=" . $host['name'] . "\n");
}

$_output = "Address=" . $host['address'] . "\n";
$_output .= "Subnet=" . $host['subnet'] . "\n";
$_output .= base64_decode($host['extra']) . "\n";
$_output .= base64_decode($host['cert_pub']) . "\n";
file_put_contents("{$configpath}/hosts/" . $host['name'], $_output);
if ($host['host_up']) {
file_put_contents("{$configpath}/hosts/" . $host['name'] . '-up', str_replace("\r", "", base64_decode($host['host_up'])) . "\n");
chmod("{$configpath}/hosts/" . $host['name'] . '-up', 0744);
}
if ($host['host_down']) {
file_put_contents("{$configpath}/hosts/" . $host['name'] . '-down', str_replace("\r", "", base64_decode($host['host_down'])) . "\n");
chmod("{$configpath}/hosts/" . $host['name'] . '-down', 0744);
}
}
fwrite($fout, base64_decode($tincconf['extra']) . "\n");
fclose($fout);

// Check if we need to generate a new RSA key pair.
if ($tincconf['gen_rsa']) {
safe_mkdir("{$configpath}/tmp");
exec("/usr/local/sbin/tincd -c {$configpath}/tmp -K");
$tincconf['cert_pub'] = base64_encode(file_get_contents("{$configpath}/tmp/rsa_key.pub"));
$tincconf['cert_key'] = base64_encode(file_get_contents("{$configpath}/tmp/rsa_key.priv"));
$tincconf['gen_rsa'] = false;
$config['installedpackages']['tinc']['config'][0]['cert_pub'] = $tincconf['cert_pub'];
$config['installedpackages']['tinc']['config'][0]['cert_key'] = $tincconf['cert_key'];
$config['installedpackages']['tinc']['config'][0]['gen_rsa'] = $tincconf['gen_rsa'];
rmdir_recursive("{$configpath}/tmp");
write_config("[tinc] New RSA key pair generated.");
}

$_output = "Subnet=" . $tincconf['localsubnet'] . "\n";
$_output .= base64_decode($tincconf['host_extra']) . "\n";
$_output .= base64_decode($tincconf['cert_pub']) . "\n";
file_put_contents("{$configpath}/hosts/" . $tincconf['name'], $_output);
file_put_contents("{$configpath}/rsa_key.priv", base64_decode($tincconf['cert_key']) . "\n");
chmod("{$configpath}/rsa_key.priv", 0600);
if ($tincconf['tinc_up']) {
$_output = base64_decode($tincconf['tinc_up']) . "\n";
} else {
$_output = "ifconfig \$INTERFACE " . $tincconf['localip'] . " netmask " . $tincconf['vpnnetmask'] . "\n";
$_output .= "ifconfig \$INTERFACE group tinc\n";
}
file_put_contents("{$configpath}/tinc-up", $_output);
chmod("{$configpath}/tinc-up", 0744);
if ($tincconf['tinc_down']) {
file_put_contents("{$configpath}/tinc-down", str_replace("\r", "", base64_decode($tincconf['tinc_down'])) . "\n");
chmod("{$configpath}/tinc-down", 0744);
}
if ($tincconf['host_up']) {
file_put_contents("{$configpath}/host-up", str_replace("\r", "", base64_decode($tincconf['host_up'])) . "\n");
chmod("{$configpath}/host-up", 0744);
}
if ($tincconf['host_down']) {
file_put_contents("{$configpath}/host-down", str_replace("\r", "", base64_decode($tincconf['host_down'])) . "\n");
chmod("{$configpath}/host-down", 0744);
}
if ($tincconf['subnet_up']) {
file_put_contents("{$configpath}/subnet-up", str_replace("\r", "", base64_decode($tincconf['subnet_up'])) . "\n");
chmod("{$configpath}/subnet-up", 0744);
}
if ($tincconf['subnet_down']) {
file_put_contents("{$configpath}/subnet-down", str_replace("\r", "", base64_decode($tincconf['subnet_down'])) . "\n");
chmod("{$configpath}/subnet-down", 0744);
}

$pfs_version = substr(trim(file_get_contents("/etc/version")), 0, 3);
if ($pfs_version == "2.2") {
$pbietcpath = '/usr/pbi/tinc-' . php_uname("m") . '/local/etc';
unlink_if_exists("{$pbietcpath}/tinc");
symlink($configpath, "{$pbietcpath}/tinc");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole block can be removed


if ($tincconf['enable'] != "") {
tinc_write_rcfile();
if (is_service_running("tinc")) {
restart_service("tinc");
} else {
start_service("tinc");
}
} else {
if (is_process_running("tincd")) {
stop_service("tinc");
}
unlink_if_exists("/usr/local/etc/rc.d/tinc.sh");
}

rmdir_recursive("/usr/local/etc/tinc.old");
conf_mount_ro();
}

function tinc_write_rcfile() {
$rc['file'] = 'tinc.sh';
$rc['start'] .= "/usr/local/sbin/tincd --config=/usr/local/etc/tinc\n\t";
$rc['stop'] .= "/usr/local/sbin/tincd --kill \n\t";
write_rcfile($rc);
}

function tinc_install() {
global $config;

safe_mkdir("/usr/local/etc/tinc");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line can be removed, next safe_mkdir will create it

safe_mkdir("/usr/local/etc/tinc/hosts");
tinc_write_rcfile();
unlink_if_exists("/usr/local/etc/rc.d/tincd");
clear_log_file("/var/log/tinc.log");

/* Create Interface Group */
if (!is_array($config['ifgroups']['ifgroupentry'])) {
$config['ifgroups']['ifgroupentry'] = array();
}

$a_ifgroups = &$config['ifgroups']['ifgroupentry'];
$ifgroupentry = array();
$ifgroupentry['members'] = '';
$ifgroupentry['descr'] = 'tinc mesh VPN interface group';
$ifgroupentry['ifname'] = 'tinc';
$a_ifgroups[] = $ifgroupentry;

/* XXX: Do not remove this. WTH?! */
mwexec("/bin/rm -f /tmp/config.cache");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good opportunity to understand why it's being done here and if it's really necessary


write_config("[tinc] Package installed.");
}

function tinc_deinstall() {
global $config;

/* Remove Interface Group */
if (!is_array($config['ifgroups']['ifgroupentry'])) {
$config['ifgroups']['ifgroupentry'] = array();
}

$a_ifgroups = &$config['ifgroups']['ifgroupentry'];

$myid = -1;
$i = 0;
foreach ($a_ifgroups as $ifgroupentry) {
if ($ifgroupentry['ifname'] == 'tinc') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit dangerous, if user create a interface group called tinc things can go bad. This logic need to be re-designed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the same file, later we concatenate the following command to the tinc-up script (which is executed at the time of interface startup):
ifconfig $INTERFACE group tinc

For example, we add the tap0 interface to the interface group named "tinc". So technically, this is hardcoded here.

The only solution which comes to my mind at first is to create an interface group with a random enough name which won't likely overlap with any user defined stuff; then we're safe to remove the group at the time of tinc uninstall.
I agree this is very far from elegant, but could solve the problem.

Another solution we could do: check if there are still any user-defined interfaces assigned to this group; if yes, don't remove the group, just skip this step, otherwise we can say it's safe to remove because no one is using this group anymore.
@rbgarga What do you think of this proposal? Or how about merging the two above mentioned solutions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if other packages are using interface groups today, but it can happen in the future. So I was considering to have a prefix for these groups, used by packages, (e.g. pkg-) and add a conditional at https://github.com/pfsense/pfsense/blob/master/src/usr/local/www/interfaces_groups_edit.php#L69 preventing users to define interface groups that begins with it. Then you could change this package to use group pkg-tinc.

Does it sound like a good plan to you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this absolutely sounds feasible. Do you want me to do this change now or wait for upstream first to prevent users creating these names themselves?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm working on Interfaces group page now and will add this rule. Today users cannot use - in group name so it won't conflict. Please go ahead and fix the name on tinc package and then I can test it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmegyesi done. I've pushed a fix on Interfaces Groups to block the use of group names starting with 'pkg-'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rbgarga I have pushed the requested modification. Thank you for your help!

$myid = $i;
break;
}
$i++;
}

if ($myid >= 0 && $a_ifgroups[$myid]) {
$members = explode(" ", $a_ifgroups[$_GET['id']]['members']);
foreach ($members as $ifs) {
$realif = get_real_interface($ifs);
if ($realif) {
mwexec("/sbin/ifconfig {$realif} -group " . escapeshellarg($a_ifgroups[$_GET['id']]['ifname']));
}
}
unset($a_ifgroups[$myid]);
/* WTH?! */
mwexec("/bin/rm -f /tmp/config.cache");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, why?

Copy link
Contributor

@doktornotor doktornotor Dec 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rbgarga - I recall touching this package back in 2.2.x where it got completely broken. Got it somehow working, but never figured this out, so I left it there with proper comment 👅 I think it had something to do with the GUI not picking up the config.xml changes on save, or god knows... I'd comment the code out for the time being and see what happens.

write_config("[tinc] Package uninstalled.");
}
rmdir_recursive("/var/tmp/tinc");
rmdir_recursive("/usr/local/etc/tinc*");
}

function tinc_validate_input($post, &$input_errors) {
if ($post['localip']) {
if ((!is_ipaddr($post['localip'])) && (!is_hostname($post['localip']))) {
$input_errors[] = gettext("'Local IP' must be a valid IP address or hostname.");
}
}
if ($post['address']) {
if ((!is_ipaddr($post['address'])) && (!is_hostname($post['address']))) {
$input_errors[] = gettext("'Host Address' must be a valid IP address or hostname.");
}
}
if (($post['localsubnet']) && (!is_subnet($post['localsubnet']))) {
$input_errors[] = gettext("'Local Subnet' must be a valid subnet.");
}
if (($post['subnet']) && (!is_subnet($post['subnet']))) {
$input_errors[] = gettext("'Subnet' must be a valid subnet.");
}
}
?>
Loading