From 56f69880ecab67ba23df54aa849d7f4e1d600da8 Mon Sep 17 00:00:00 2001
From: tbrehm <t.brehm@ispconfig.org>
Date: Fri, 19 Apr 2013 05:45:30 -0400
Subject: [PATCH] Add dkim support (Patch by Florian).
---
server/plugins-available/mail_plugin_dkim.inc.php | 286 ++++++++++++++++++++++++++++
interface/web/mail/form/mail_domain.tform.php | 29 ++
install/tpl/opensuse_amavisd_conf.master | 6
interface/web/admin/lib/lang/en_server_config.lng | 2
install/tpl/server.ini.master | 1
interface/web/admin/templates/server_config_mail_edit.htm | 6
interface/web/mail/mail_domain_dkim_create.php | 90 +++++++++
interface/web/admin/form/server_config.tform.php | 13 +
install/tpl/amavisd_user_config.master | 6
interface/web/mail/templates/mail_domain_edit.htm | 61 ++++++
interface/web/mail/lib/lang/en_mail_domain.lng | 8
install/sql/ispconfig3.sql | 9
install/sql/incremental/upd_0052.sql | 3
interface/lib/classes/validate_dkim.inc.php | 60 ++++++
14 files changed, 573 insertions(+), 7 deletions(-)
diff --git a/install/sql/incremental/upd_0052.sql b/install/sql/incremental/upd_0052.sql
new file mode 100644
index 0000000..b8e3829
--- /dev/null
+++ b/install/sql/incremental/upd_0052.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `mail_domain` ADD `dkim_public` MEDIUMTEXT NOT NULL AFTER `domain`;
+ALTER TABLE `mail_domain` ADD `dkim_private` MEDIUMTEXT NOT NULL AFTER `domain`;
+ALTER TABLE `mail_domain` ADD `dkim` ENUM( 'n', 'y' ) NOT NULL AFTER `domain`;
diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql
index 6eb264a..2a2d4a0 100644
--- a/install/sql/ispconfig3.sql
+++ b/install/sql/ispconfig3.sql
@@ -663,6 +663,9 @@
`sys_perm_other` varchar(5) NOT NULL default '',
`server_id` int(11) unsigned NOT NULL default '0',
`domain` varchar(255) NOT NULL default '',
+ `dkim` ENUM( 'n', 'y' ) NOT NULL default 'n',
+ `dkim_private` mediumtext NOT NULL default '',
+ `dkim_public` mediumtext NOT NULL default '',
`active` enum('n','y') NOT NULL,
PRIMARY KEY (`domain_id`),
KEY `server_id` (`server_id`,`domain`),
@@ -2169,7 +2172,7 @@
--
-- Dumping data for table `sys_config`
--
-
+
INSERT INTO sys_config VALUES ('1','db','db_version','3.0.5.2');
-
-SET FOREIGN_KEY_CHECKS = 1;
\ No newline at end of file
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/install/tpl/amavisd_user_config.master b/install/tpl/amavisd_user_config.master
index c89f875..f377955 100644
--- a/install/tpl/amavisd_user_config.master
+++ b/install/tpl/amavisd_user_config.master
@@ -75,6 +75,12 @@
# Set the log_level to 5 for debugging
$log_level = 0; # (defaults to 0)
+# DKIM
+
+$enable_dkim_verification = 1;
+$enable_dkim_signing = 1; # load DKIM signing code,
+@dkim_signature_options_bysender_maps = (
+{ '.' => { ttl => 21*24*3600, c => 'relaxed/simple' } } );
#------------ Do not modify anything below this line -------------
1; # insure a defined return
diff --git a/install/tpl/opensuse_amavisd_conf.master b/install/tpl/opensuse_amavisd_conf.master
index d0d8a87..5f9f867 100644
--- a/install/tpl/opensuse_amavisd_conf.master
+++ b/install/tpl/opensuse_amavisd_conf.master
@@ -778,5 +778,11 @@
$DO_SYSLOG = 1;
$LOGFILE = "/var/log/amavis.log"; # (defaults to empty, no log)
+# DKIM
+
+$enable_dkim_verification = 1;
+$enable_dkim_signing = 1; # load DKIM signing code,
+@dkim_signature_options_bysender_maps = (
+{ '.' => { ttl => 21*24*3600, c => 'relaxed/simple' } } );
1; # insure a defined return
diff --git a/install/tpl/server.ini.master b/install/tpl/server.ini.master
index 3f3dc36..007d51b 100644
--- a/install/tpl/server.ini.master
+++ b/install/tpl/server.ini.master
@@ -21,6 +21,7 @@
module=postfix_mysql
maildir_path=/var/vmail/[domain]/[localpart]
homedir_path=/var/vmail
+dkim_path=/etc/postfix/dkim
pop3_imap_daemon=courier
mail_filter_syntax=maildrop
mailuser_uid=5000
diff --git a/interface/lib/classes/validate_dkim.inc.php b/interface/lib/classes/validate_dkim.inc.php
new file mode 100644
index 0000000..fccd457
--- /dev/null
+++ b/interface/lib/classes/validate_dkim.inc.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+Copyright (c) 2007 - 2013, Till Brehm, projektfarm Gmbh
+Copyright (c) 2013, Florian Schaal, info@schaal-24.de
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of ISPConfig nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+*/
+
+class validate_dkim {
+
+ function get_error($errmsg) {
+ global $app;
+ if(isset($app->tform->wordbook[$errmsg])) {
+ return $app->tform->wordbook[$errmsg]."<br>\r\n";
+ } else {
+ return $errmsg."<br>\r\n";
+ }
+ }
+
+ /* Validator function for private DKIM-Key */
+ function check_private_key($field_name, $field_value, $validator) {
+ $dkim_enabled=$_POST['dkim'];
+ if ($dkim_enabled == 'y') {
+ if (empty($field_value)) return $this->get_error($validator['errmsg']);
+ exec('echo "'.$field_value.'"|openssl rsa -check',$output,$result);
+ if($result != 0) return $this->get_error($validator['errmsg']);
+ }
+ }
+
+ /* Validator function for DKIM Path */
+ function check_dkim_path($field_name, $field_value, $validator) {
+ if(empty($field_value)) return $this->get_error($validator['errmsg']);
+ if (substr(sprintf('%o', fileperms($field_value)),-3) <= 600)
+ return $this->get_error($validator['errmsg']);
+ }
+
+}
diff --git a/interface/web/admin/form/server_config.tform.php b/interface/web/admin/form/server_config.tform.php
index 0f0c38b..fb5bf87 100644
--- a/interface/web/admin/form/server_config.tform.php
+++ b/interface/web/admin/form/server_config.tform.php
@@ -211,6 +211,19 @@
'width' => '40',
'maxlength' => '255'
),
+ 'dkim_path' => array(
+ 'datatype' => 'VARCHAR',
+ 'formtype' => 'TEXT',
+ 'default' => '/var/db/dkim',
+ 'validators' => array ( 0 => array ('type' => 'CUSTOM',
+ 'class' => 'validate_dkim',
+ 'function' => 'check_dkim_path',
+ 'errmsg'=> 'dkim_path_error'),
+ ),
+ 'value' => '',
+ 'width' => '40',
+ 'maxlength' => '255'
+ ),
'pop3_imap_daemon' => array(
'datatype' => 'VARCHAR',
'formtype' => 'SELECT',
diff --git a/interface/web/admin/lib/lang/en_server_config.lng b/interface/web/admin/lib/lang/en_server_config.lng
index b39dd0e..b9f270e 100644
--- a/interface/web/admin/lib/lang/en_server_config.lng
+++ b/interface/web/admin/lib/lang/en_server_config.lng
@@ -30,6 +30,8 @@
$wb["module_txt"] = 'Module';
$wb["maildir_path_txt"] = 'Maildir Path';
$wb["homedir_path_txt"] = 'Homedir Path';
+$wb["dkim_path_txt"] = 'DKIM Path';
+$wb["dkim_path_error"] = 'DKIM Path not found or not writeable.';
$wb["mailuser_uid_txt"] = 'Mailuser UID';
$wb["mailuser_gid_txt"] = 'Mailuser GID';
$wb["mailuser_name_txt"] = 'Mailuser Name';
diff --git a/interface/web/admin/templates/server_config_mail_edit.htm b/interface/web/admin/templates/server_config_mail_edit.htm
index fba0bf7..0374931 100644
--- a/interface/web/admin/templates/server_config_mail_edit.htm
+++ b/interface/web/admin/templates/server_config_mail_edit.htm
@@ -20,6 +20,10 @@
<input name="homedir_path" id="homedir_path" value="{tmpl_var name='homedir_path'}" size="40" maxlength="255" type="text" class="textInput" />
</div>
<div class="ctrlHolder">
+ <label for="dkim_path">{tmpl_var name='dkim_path_txt'}</label>
+ <input name="dkim_path" id="dkim_path" value="{tmpl_var name='dkim_path'}" size="40" maxlength="255" type="text" class="textInput" />
+ </div>
+ <div class="ctrlHolder">
<p class="label">{tmpl_var name='pop3_imap_daemon_txt'}</p>
<div class="multiField">
<select name="pop3_imap_daemon" id="pop3_imap_daemon" class="selectInput">
@@ -95,4 +99,4 @@
</div>
</div>
-</div>
\ No newline at end of file
+</div>
diff --git a/interface/web/mail/form/mail_domain.tform.php b/interface/web/mail/form/mail_domain.tform.php
index 506f934..caf48d5 100644
--- a/interface/web/mail/form/mail_domain.tform.php
+++ b/interface/web/mail/form/mail_domain.tform.php
@@ -98,6 +98,33 @@
'maxlength' => '255',
'searchable' => 1
),
+ 'dkim' => array (
+ 'datatype' => 'VARCHAR',
+ 'formtype' => 'CHECKBOX',
+ 'default' => 'n',
+ 'value' => array(0 => 'n',1 => 'y')
+ ),
+ 'dkim_private' => array (
+ 'datatype' => 'TEXT',
+ 'formtype' => 'TEXTAREA',
+ 'default' => '',
+ 'value' => '',
+ 'cols' => '30',
+ 'rows' => '10',
+ 'validators' => array ( 0 => array ('type' => 'CUSTOM',
+ 'class' => 'validate_dkim',
+ 'function' => 'check_private_key',
+ 'errmsg'=> 'dkim_private_key_error'),
+ ),
+ ),
+ 'dkim_public' => array (
+ 'datatype' => 'TEXT',
+ 'formtype' => 'TEXTAREA',
+ 'default' => '',
+ 'value' => '',
+ 'cols' => '30',
+ 'rows' => '10'
+ ),
'active' => array (
'datatype' => 'VARCHAR',
'formtype' => 'CHECKBOX',
@@ -111,4 +138,4 @@
);
-?>
\ No newline at end of file
+?>
diff --git a/interface/web/mail/lib/lang/en_mail_domain.lng b/interface/web/mail/lib/lang/en_mail_domain.lng
index ad93100..00ddf33 100644
--- a/interface/web/mail/lib/lang/en_mail_domain.lng
+++ b/interface/web/mail/lib/lang/en_mail_domain.lng
@@ -3,11 +3,17 @@
$wb["domain_txt"] = 'Domain';
$wb["type_txt"] = 'Type';
$wb["active_txt"] = 'Active';
+$wb["dkim_txt"] = 'enable DKIM';
+$wb["dkim_private_txt"] = 'DKIM Private-key';
+$wb["dkim_generate_txt"] = 'Generate DKIM Private-key';
+$wb["dkim_dns_txt"] = 'DNS-Record (TYPE TXT)<br><br>add this record to your DNS';
+$wb["dkim_private_key_error"] = 'Invalid DKIM-Private key';
$wb["domain_error_empty"] = 'Domain is empty.';
$wb["domain_error_unique"] = 'Duplicate Domain.';
$wb["domain_error_regex"] = 'Invalid domain name.';
+$wb["dkim_settings_txt"] = 'DomainKeys Identified Mail (DKIM)';
$wb["client_txt"] = 'Client';
$wb["limit_maildomain_txt"] = 'The max. number of email domains for your account is reached.';
$wb["policy_txt"] = 'Spamfilter';
$wb["no_policy"] = '- not enabled -';
-?>
\ No newline at end of file
+?>
diff --git a/interface/web/mail/mail_domain_dkim_create.php b/interface/web/mail/mail_domain_dkim_create.php
new file mode 100644
index 0000000..758d3af
--- /dev/null
+++ b/interface/web/mail/mail_domain_dkim_create.php
@@ -0,0 +1,90 @@
+<?php
+/*
+Copyright (c) 2007 - 2013, Till Brehm, projektfarm Gmbh
+Copyright (c) 2013, Florian Schaal, info@schaal-24.de
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of ISPConfig nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+*/
+
+/*
+ This script is invoked by the java-script in interface/web/mail/templates/mail_domain_edit.htm
+ when generating the DKIM Private-key.
+
+ return DKIM Private-Key and DNS-record
+*/
+
+require_once('../../lib/config.inc.php');
+
+header('Content-Type: text/xml; charset=utf-8');
+header('Cache-Control: must-revalidate, pre-check=0, no-store, no-cache, max-age=0, post-check=0');
+
+/*
+ This function fix PHP's messing up POST input containing characters space, dot,
+ open square bracket and others to be compatible with with the deprecated register_globals
+*/
+function getRealPOST() {
+ $pairs = explode("&", file_get_contents("php://input"));
+ $vars = array();
+ foreach ($pairs as $pair) {
+ $nv = explode("=", $pair, 2);
+ $name = urldecode($nv[0]);
+ $value = $nv[1];
+ $vars[$name] = $value;
+ }
+ return $vars;
+}
+
+function dns_record() {
+ global $private_key;
+ $public_key='';
+ exec('echo "'.$private_key.'"|openssl rsa -pubout -outform PEM',$pubkey,$result);
+ $pubkey=array_diff($pubkey,array('-----BEGIN PUBLIC KEY-----','-----END PUBLIC KEY-----'));
+ foreach($pubkey as $values) $public_key=$public_key.$values."\n";
+ $dns_record="HOSTNAME: default._domainkey.".$_POST['domain'].".\n\nTEXT: v=DKIM1; t=s; p=".$public_key;
+ return $dns_record;
+}
+
+$_POST=getRealPOST();
+
+switch ($_POST['action']) {
+ case 'create': /* create DKIM Private-key */
+ exec("openssl rand -out /usr/local/ispconfig/server/temp/random-data.bin 4096",$output,$result);
+ exec("openssl genrsa -rand /usr/local/ispconfig/server/temp/random-data.bin 1024",$privkey,$result);
+ unlink("/usr/local/ispconfig/server/temp/random-data.bin");
+ $private_key='';
+ foreach($privkey as $values) $private_key=$private_key.$values."\n";
+ $dns_record=dns_record();
+ break;
+ case 'show': /* show the DNS-Record onLoad */
+ $private_key=$_POST['pkey'];
+ $dns_record=dns_record();
+ break;
+}
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+echo "<formatname>\n";
+echo "<privatekey>".$private_key."</privatekey>\n";
+echo "<dnsrecord>".$dns_record."</dnsrecord>\n";
+echo "</formatname>\n";
+?>
diff --git a/interface/web/mail/templates/mail_domain_edit.htm b/interface/web/mail/templates/mail_domain_edit.htm
index 5a1b613..81cdb73 100644
--- a/interface/web/mail/templates/mail_domain_edit.htm
+++ b/interface/web/mail/templates/mail_domain_edit.htm
@@ -59,6 +59,24 @@
{tmpl_var name='active'}
</div>
</div>
+ <div class="subsectiontoggle"><span></span>{tmpl_var name='dkim_settings_txt'}<em></em></div>
+ <div style="display:none;">
+ <div class="ctrlHolder">
+ <p class="label">{tmpl_var name='dkim_txt'}</p>
+ <div class="multiField">
+ {tmpl_var name='dkim'}
+ </div>
+ </div>
+ <div class="ctrlHolder">
+ <label for="dkim_private">{tmpl_var name='dkim_private_txt'}</label>
+ <textarea name="dkim_private" id="dkim_private" rows='10' cols='30'>{tmpl_var name='dkim_private'}</textarea>
+<a href="javascript:setRequest('create','{tmpl_var name='domain'}')">{tmpl_var name='dkim_generate_txt'}</a>
+ </div>
+ <div class="ctrlHolder">
+ <label for="dkim_dns">{tmpl_var name='dkim_dns_txt'}</label>
+ <textarea name="dkim_dns" id="dkim_dns" rows='10' cols='30'>{tmpl_var name='dkim_dns'}</textarea>
+ </div>
+ </div>
</fieldset>
<input type="hidden" name="id" value="{tmpl_var name='id'}">
@@ -70,4 +88,45 @@
</div>
</div>
-</div>
\ No newline at end of file
+</div>
+<script language="JavaScript" type="text/javascript">
+ var request = false;
+
+ function setRequest(action,value,privatekey) {
+ if (window.XMLHttpRequest) {request = new XMLHttpRequest();}
+ else if (window.ActiveXObject) {
+ try {request = new ActiveXObject('Msxml2.XMLHTTP');}
+ catch (e) {
+ try {request = new ActiveXObject('Microsoft.XMLHTTP');}
+ catch (e) {}
+ }
+ }
+ if (!request) {
+ alert("Error creating XMLHTTP-instance");
+ return false;
+ } else {
+ request.open('POST', '/mail/mail_domain_dkim_create.php', true);
+ request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ request.send('domain='+value+'&action='+action+'&pkey='+privatekey);
+ request.onreadystatechange = interpretRequest;
+ }
+ }
+
+ function interpretRequest() {
+ switch (request.readyState) {
+ case 4:
+ if (request.status != 200) {alert("Request done but NOK\nError:"+request.status);}
+ else {
+ document.getElementsByName('dkim_private')[0].value = request.responseXML.getElementsByTagName('privatekey')[0].firstChild.nodeValue;
+ document.getElementsByName('dkim_dns')[0].value = request.responseXML.getElementsByTagName('dnsrecord')[0].firstChild.nodeValue;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+var serverType = jQuery('#dkim_private').val();
+setRequest('show','{tmpl_var name="domain"}',serverType);
+</script>
+
diff --git a/server/plugins-available/mail_plugin_dkim.inc.php b/server/plugins-available/mail_plugin_dkim.inc.php
new file mode 100644
index 0000000..8b098cc
--- /dev/null
+++ b/server/plugins-available/mail_plugin_dkim.inc.php
@@ -0,0 +1,286 @@
+<?php
+
+/*
+todo:
+- DNS interaction
+*/
+/*
+Copyright (c) 2007 - 2013, Till Brehm, projektfarm Gmbh
+Copyright (c) 2013, Florian Schaal, info@schaal-24.de
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of ISPConfig nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+*/
+
+class mail_plugin_dkim {
+
+ var $plugin_name = 'mail_plugin_dkim';
+ var $class_name = 'mail_plugin_dkim';
+
+ // private variables
+ var $action = '';
+
+ /*
+ This function is called during ispconfig installation to determine
+ if a symlink shall be created for this plugin.
+ */
+ function onInstall() {
+ global $conf;
+
+ if($conf['services']['mail'] == true) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ /*
+ This function is called when the plugin is loaded
+ */
+ function onLoad() {
+ global $app,$conf;
+ /*
+ Register for the events
+ */
+ $app->plugins->registerEvent('mail_domain_delete',$this->plugin_name,'domain_dkim_delete');
+ $app->plugins->registerEvent('mail_domain_insert',$this->plugin_name,'domain_dkim_insert');
+ $app->plugins->registerEvent('mail_domain_update',$this->plugin_name,'domain_dkim_update');
+
+ // Register service
+ $app->services->registerService('amavisd','mail_module','restartAmavisd');
+ }
+
+ /*
+ This function gets the amavisd-config file
+ */
+ function get_amavis_config() {
+ $pos_config=array(
+ '/etc/amavisd.conf',
+ '/etc/amavisd.conf/50-user'
+ );
+ $amavis_configfile='';
+ foreach($pos_config as $conf) {
+ if (is_file($conf)) {
+ $amavis_configfile=$conf;
+ break;
+ }
+ }
+ return $amavis_configfile;
+ }
+
+ /*
+ This function checks the relevant configs and disables dkim for the domain
+ if the directory for dkim is not writeable or does not exist
+ */
+ function check_system($data) {
+ global $app,$mail_config;
+ $app->uses('getconf');
+ $check=true;
+ /* check for amavis-config */
+ if ( $this->get_amavis_config() == '' || !is_writeable($this->get_amavis_config()) ) {
+ $app->log('Amavis-config not found or not writeable.',LOGLEVEL_ERROR);
+ $check=false;
+ }
+ /* dir for dkim-keys writeable? */
+ $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail');
+ if (isset($mail_config['dkim_path']) && isset($data['new']['dkim_private']) && !empty($data['new']['dkim_private'])) {
+ if (!is_writeable($mail_config['dkim_path'])) {
+ $app->log('DKIM Path '.$mail_config['dkim_path'].' not found or not writeable.',LOGLEVEL_ERROR);
+ $check=false;
+ }
+ } else {
+ $app->log('Unable to write DKIM settings; Check your config!',LOGLEVEL_ERROR);
+ $check=false;
+ }
+ if (!$check) {
+ $app->db->query("UPDATE mail_domain SET dkim = 'n' WHERE domain = '".$data['new']['domain']."'");
+ $app->dbmaster->query("UPDATE mail_domain SET dkim = 'n' WHERE domain = '".$data['new']['domain']."'");
+ }
+ return $check;
+ }
+
+ /*
+ This function restarts amavis
+ */
+ function restart_amavis() {
+ global $app,$conf;
+ $initfile=$conf['init_scripts'].'/amavis';
+ $app->log('Restarting amavis.',LOGLEVEL_DEBUG);
+ exec($conf['init_scripts'].'/amavis restart',$output);
+ foreach($output as $logline) $app->log($logline,LOGLEVEL_DEBUG);
+ }
+
+ /*
+ This function writes the keyfiles (public and private)
+ The public-key is always created and stored into the db and local key-file
+ */
+ function write_dkim_key($key_file,$key_value,$key_domain) {
+ global $app,$mailconfig;
+ $success=false;
+ if (!file_put_contents($key_file.'.private',$key_value) === false) {
+ $app->log('Saved DKIM Private-key to '.$key_file.'.private',LOGLEVEL_DEBUG);
+ $success=true;
+ /* now we get the DKIM Public-key */
+ exec('cat "'.$key_file.'.private'.'"|openssl rsa -pubout',$pubkey,$result);
+ $public_key='';
+ foreach($pubkey as $values) $public_key=$public_key.$values."\n";
+ /* save the DKIM Public-key in dkim-dir */
+ if (!file_put_contents($key_file.'.public',$public_key) === false)
+ $app->log('Saved DKIM Public to '.$key_domain.'.',LOGLEVEL_DEBUG);
+ else $app->log('Unable to save DKIM Public to '.$key_domain.'.',LOGLEVEL_WARNING);
+ /* store the private-key to the databse(s) */
+ $app->log('Store the DKIM Public-key in database.',LOGLEVEL_DEBUG);
+ $app->db->query("UPDATE mail_domain SET dkim_public = '".$public_key."' WHERE domain = '".$ky_domain."'");
+ $app->dbmaster->query("UPDATE mail_domain SET dkim_public = '".$public_key."' WHERE domain = '".$key_domain."'");
+ }
+ return $success;
+ }
+
+ /*
+ This function removes the keyfiles
+ */
+ function remove_dkim_key($key_file,$key_domain) {
+ global $app;
+ if (file_exists($key_file.'.private')) {
+ exec('rm -f '.$key_file.'.private');
+ $app->log('Deleted the DKIM Private-key for '.$key_domain.'.',LOGLEVEL_DEBUG);
+ } else $app->log('Unable to delete the DKIM Private-key for '.$key_domain.' (not found).',LOGLEVEL_DEBUG);
+ if (file_exists($key_file.'.public')) {
+ exec('rm -f '.$key_file.'.public');
+ $app->log('Deleted the DKIM Public-key for '.$key_domain.'.',LOGLEVEL_DEBUG);
+ } else $app->log('Unable to delete the DKIM Public-key for '.$key_domain.' (not found).',LOGLEVEL_DEBUG);
+ }
+
+ /*
+ This function adds the entry to the amavisd-config
+ */
+ function add_to_amavis($key_domain) {
+ global $app,$mail_config;
+ $amavis_config = file_get_contents($this->get_amavis_config());
+ $key_value="dkim_key('".$key_domain."', 'default', '".$mail_config['dkim_path']."/".$key_domain.".private');\n";
+ if(strpos($amavis_config, $key_value) !== false) $amavis_config = str_replace($key_value, '', $amavis_config);
+ if (!file_put_contents($this->get_amavis_config(),$key_value,FILE_APPEND) === false) {
+ $app->log('Adding DKIM Private-key to amavis-config.',LOGLEVEL_DEBUG);
+ $this->restart_amavis();
+ }
+ }
+
+ /*
+ This function removes the entry from the amavisd-config
+ */
+ function remove_from_amavis($key_domain) {
+ global $app;
+ $amavis_config = file($this->get_amavis_config());
+ $i=0;$found=false;
+ foreach($amavis_config as $line) {
+ if (preg_match("/^\bdkim_key\b.*\b".$key_domain."\b/",$line)) {
+ unset($amavis_config[$i]);
+ $found=true;
+ }
+ $i++;
+ }
+ if ($found) {
+ file_put_contents($this->get_amavis_config(), $amavis_config);
+ $app->log('Deleted the DKIM settings from amavis-config for '.$key_domain.'.',LOGLEVEL_DEBUG);
+ $this->restart_amavis();
+ } else $app->log('Unable to delete the DKIM settings from amavis-config for '.$key_domain.'.',LOGLEVEL_ERROR);
+ }
+
+ /*
+ This function controlls new key-files and amavisd-entries
+ */
+ function add_dkim($data) {
+ global $app;
+ $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail');
+ if ( substr($mail_config['dkim_path'],strlen($mail_config['dkim_path'])-1) == '/' )
+ $mail_config['dkim_path'] = substr($mail_config['dkim_path'],0,strlen($mail_config['dkim_path'])-1);
+ if ($this->write_dkim_key($mail_config['dkim_path']."/".$data['new']['domain'],$data['new']['dkim_private'],$data['new']['domain'])) {
+ $this->add_to_amavis($data['new']['domain']);
+ } else {
+ $app->log('Error saving the DKIM Private-key for '.$data['new']['domain'].' - DKIM is now disabled for the domain.',LOGLEVEL_ERROR);
+ $app->db->query("UPDATE mail_domain SET dkim = 'n' WHERE domain = '".$data['new']['domain']."'");
+ $app->dbmaster->query("UPDATE mail_domain SET dkim = 'n' WHERE domain = '".$data['new']['domain']."'");
+ }
+ }
+
+ /*
+ This function controlls the removement of keyfiles (public and private)
+ and the entry in the amavisd-config
+ */
+ function remove_dkim($_data) {
+ global $app;
+ $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail');
+ if ( substr($mail_config['dkim_path'],strlen($mail_config['dkim_path'])-1) == '/' )
+ $mail_config['dkim_path'] = substr($mail_config['dkim_path'],0,strlen($mail_config['dkim_path'])-1);
+ $this->remove_dkim_key($mail_config['dkim_path']."/".$_data['domain'],$_data['domain']);
+ $this->remove_from_amavis($_data['domain']);
+ }
+
+ /*
+ Functions called by onLoad
+ */
+ function domain_dkim_delete($event_name,$data) {
+ if (isset($data['old']['dkim']) && $data['old']['dkim'] == 'y') $this->remove_dkim($data['old']);
+ }
+
+ function domain_dkim_insert($event_name,$data) {
+ if (isset($data['new']['dkim']) && $data['new']['dkim']=='y' && $this->check_system($data)) {
+ /* if the domain is already defined, remove from amavis */
+ $this->remove_from_amavis($data['new']['domain']);
+// $this->remove_from_amavis("dkim_key('".$data['new']['domain']."', 'default', '".$mail_config['dkim_path']."/".$data['new']['domain'].".private');\n",$data['new']['domain']);
+ $this->add_dkim($data);
+ }
+ }
+
+ function domain_dkim_update($event_name,$data) {
+ global $app;
+ /* get the config */
+ if (isset($data['new']['dkim']) && $data['new']['dkim']=='y') { /* DKIM enabled */
+ if ($this->check_system($data)) {
+ /* new domain-name */
+ if ($data['old']['domain'] != $data['new']['domain']) {
+ $this->remove_dkim($data['old']);
+ $this->add_dkim($data);
+ }
+ /* new key */
+ if (($data['old']['dkim_private'] != $data['new']['dkim_private']) || ($data['old']['dkim'] != $data['new']['dkim'])) {
+ if ($data['new']['dkim_private'] != $data['old']['dkim_private']) $this->remove_dkim($data['new']);
+ $this->add_dkim($data);
+ }
+ /* change active (on / off) */
+ if ($data['old']['active'] != $data['new']['active']) {
+ if ($data['new']['active'] == 'y') {
+ $this->add_dkim($data);
+ } else {
+ $this->remove_dkim($data['new']);
+ }
+ }
+ }
+ }
+ if (isset($data['new']['dkim']) && $data['old']['dkim'] != $data['new']['dkim'])
+ if ($this->check_system($data) && $data['new']['dkim'] == 'n') $this->remove_dkim($data['new']);
+ }
+}
+?>
--
Gitblit v1.9.1