Skip to content

Commit 48af7df

Browse files
committed
Updated dkim support.
1 parent 713d861 commit 48af7df

File tree

18 files changed

+827
-262
lines changed

18 files changed

+827
-262
lines changed
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
ALTER TABLE `mail_domain` ADD `dkim_public` MEDIUMTEXT NOT NULL AFTER `domain`;
2-
ALTER TABLE `mail_domain` ADD `dkim_private` MEDIUMTEXT NOT NULL AFTER `domain`;
3-
ALTER TABLE `mail_domain` ADD `dkim` ENUM( 'n', 'y' ) NOT NULL AFTER `domain`;
1+
ALTER TABLE `client_template` CHANGE `limit_aps` `limit_aps` INT( 11 ) NOT NULL DEFAULT '-1';
2+
ALTER TABLE `mail_domain` ADD `dkim_public` MEDIUMTEXT NOT NULL AFTER `domain`;
3+
ALTER TABLE `mail_domain` ADD `dkim_private` MEDIUMTEXT NOT NULL AFTER `domain`;
4+
ALTER TABLE `mail_domain` ADD `dkim` ENUM( 'n', 'y' ) NOT NULL AFTER `domain`;

interface/lib/classes/validate_dkim.inc.php

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,38 @@ function get_error($errmsg) {
4242

4343
/* Validator function for private DKIM-Key */
4444
function check_private_key($field_name, $field_value, $validator) {
45-
$dkim_enabled=$_POST['dkim'];
46-
if ($dkim_enabled == 'y') {
47-
if (empty($field_value)) return $this->get_error($validator['errmsg']);
48-
exec('echo "'.$field_value.'"|openssl rsa -check',$output,$result);
49-
if($result != 0) return $this->get_error($validator['errmsg']);
50-
}
51-
}
45+
$dkim_enabled=$_POST['dkim'];
46+
if ($dkim_enabled == 'y') {
47+
if (empty($field_value)) return $this->get_error($validator['errmsg']);
48+
exec('echo '.escapeshellarg($field_value).'|openssl rsa -check',$output,$result);
49+
if($result != 0) return $this->get_error($validator['errmsg']);
50+
}
51+
}
5252

5353
/* Validator function for DKIM Path */
5454
function check_dkim_path($field_name, $field_value, $validator) {
5555
if(empty($field_value)) return $this->get_error($validator['errmsg']);
5656
if (substr(sprintf('%o', fileperms($field_value)),-3) <= 600)
57-
return $this->get_error($validator['errmsg']);
58-
}
59-
60-
}
57+
return $this->get_error($validator['errmsg']);
58+
}
59+
60+
/* Check function for DNS-Template */
61+
function check_template($field_name, $field_value, $validator) {
62+
$dkim=false;
63+
foreach($field_value as $field ) { if($field == 'DKIM') $dkim=true; }
64+
if ($dkim && $field_value[0]!='DOMAIN') return $this->get_error($validator['errmsg']);
65+
}
66+
67+
/* Validator function for $_POST */
68+
function validate_post($key,$value) {
69+
switch ($key) {
70+
case 'public':
71+
if (preg_match("/(^-----BEGIN PUBLIC KEY-----)[a-zA-Z0-9\r\n\/\+=]{1,221}(-----END PUBLIC KEY-----(\n|\r)$)/",$value) === 1) { return true; } else { return false; }
72+
break;
73+
case 'private':
74+
if (preg_match("/(^-----BEGIN RSA PRIVATE KEY-----)[a-zA-Z0-9\r\n\/\+=]{1,850}(-----END RSA PRIVATE KEY-----(\n|\r)$)/",$value) === 1) { return true; } else { return false; }
75+
break;
76+
}
77+
}
78+
}
79+
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
/*
4+
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
5+
Copyright (c) 2013, Florian Schaal, info@schaal-24.de
6+
All rights reserved.
7+
8+
Redistribution and use in source and binary forms, with or without modification,
9+
are permitted provided that the following conditions are met:
10+
11+
* Redistributions of source code must retain the above copyright notice,
12+
this list of conditions and the following disclaimer.
13+
* Redistributions in binary form must reproduce the above copyright notice,
14+
this list of conditions and the following disclaimer in the documentation
15+
and/or other materials provided with the distribution.
16+
* Neither the name of ISPConfig nor the names of its contributors
17+
may be used to endorse or promote products derived from this software without
18+
specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23+
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
32+
/******************************************
33+
* Begin Form configuration
34+
******************************************/
35+
36+
$tform_def_file = "form/dns_dkim.tform.php";
37+
38+
/******************************************
39+
* End Form configuration
40+
******************************************/
41+
42+
require_once('../../lib/config.inc.php');
43+
require_once('../../lib/app.inc.php');
44+
45+
//* Check permissions for module
46+
$app->auth->check_module_permissions('dns');
47+
48+
// Loading classes
49+
$app->uses('tpl,tform,tform_actions,validate_dns');
50+
$app->load('tform_actions');
51+
52+
class page_action extends tform_actions {
53+
54+
function onShowNew() {
55+
global $app, $conf;
56+
// we will check only users, not admins
57+
if($_SESSION["s"]["user"]["typ"] == 'user') {
58+
59+
// Get the limits of the client
60+
$client_group_id = $_SESSION["s"]["user"]["default_group"];
61+
$client = $app->db->queryOneRecord("SELECT limit_dns_record FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
62+
63+
// Check if the user may add another record.
64+
if($client["limit_dns_record"] >= 0) {
65+
$tmp = $app->db->queryOneRecord("SELECT count(id) as number FROM dns_rr WHERE sys_groupid = $client_group_id");
66+
if($tmp["number"] >= $client["limit_dns_record"]) {
67+
$app->error($app->tform->wordbook["limit_dns_record_txt"]);
68+
}
69+
}
70+
}
71+
72+
parent::onShowNew();
73+
}
74+
75+
function onSubmit() {
76+
global $app, $conf;
77+
// Get the parent soa record of the domain
78+
$soa = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = '".$app->functions->intval($_POST["zone"])."' AND ".$app->tform->getAuthSQL('r'));
79+
// Check if Domain belongs to user
80+
if($soa["id"] != $_POST["zone"]) $app->tform->errorMessage .= $app->tform->wordbook["no_zone_perm"];
81+
82+
// Check the client limits, if user is not the admin
83+
if($_SESSION["s"]["user"]["typ"] != 'admin') { // if user is not admin
84+
// Get the limits of the client
85+
$client_group_id = $_SESSION["s"]["user"]["default_group"];
86+
$client = $app->db->queryOneRecord("SELECT limit_dns_record FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
87+
// Check if the user may add another record.
88+
if($this->id == 0 && $client["limit_dns_record"] >= 0) {
89+
$tmp = $app->db->queryOneRecord("SELECT count(id) as number FROM dns_rr WHERE sys_groupid = $client_group_id");
90+
if($tmp["number"] >= $client["limit_dns_record"]) {
91+
$app->error($app->tform->wordbook["limit_dns_record_txt"]);
92+
}
93+
}
94+
} // end if user is not admin
95+
96+
// Set the server ID of the rr record to the same server ID as the parent record.
97+
$this->dataRecord["server_id"] = $soa["server_id"];
98+
99+
// add dkim-settings to the public-key in the txt-record
100+
$this->dataRecord['data']='v=DKIM1; t=s; p='.$this->dataRecord['data'];
101+
$this->dataRecord['name']='default._domainkey.'.$this->dataRecord['name'];
102+
103+
// Update the serial number and timestamp of the RR record
104+
$soa = $app->db->queryOneRecord("SELECT serial FROM dns_rr WHERE id = ".$this->id);
105+
$this->dataRecord["serial"] = $app->validate_dns->increase_serial($soa["serial"]);
106+
$this->dataRecord["stamp"] = date('Y-m-d H:i:s');
107+
108+
// check for duplicate entry
109+
$check=$app->db->queryOneRecord("SELECT * FROM dns_rr WHERE zone = ".$this->dataRecord["zone"]." AND type = '".$this->dataRecord["type"]."' AND data ='".$this->dataRecord["data"]."' AND name = '".$this->dataRecord['name']."'");
110+
if ($check!='') $app->tform->errorMessage .= $app->tform->wordbook["record_exists_txt"];
111+
112+
parent::onSubmit();
113+
}
114+
115+
function onAfterInsert() {
116+
global $app, $conf;
117+
118+
//* Set the sys_groupid of the rr record to be the same then the sys_groupid of the soa record
119+
$soa = $app->db->queryOneRecord("SELECT sys_groupid,serial FROM dns_soa WHERE id = '".$app->functions->intval($this->dataRecord["zone"])."' AND ".$app->tform->getAuthSQL('r'));
120+
$app->db->datalogUpdate('dns_rr', "sys_groupid = ".$soa['sys_groupid'], 'id', $this->id);
121+
122+
//* Update the serial number of the SOA record
123+
$soa_id = $app->functions->intval($_POST["zone"]);
124+
$serial = $app->validate_dns->increase_serial($soa["serial"]);
125+
$app->db->datalogUpdate('dns_soa', "serial = $serial", 'id', $soa_id);
126+
}
127+
128+
function onAfterUpdate() {
129+
global $app, $conf;
130+
131+
//* Update the serial number of the SOA record
132+
$soa = $app->db->queryOneRecord("SELECT serial FROM dns_soa WHERE id = '".$app->functions->intval($this->dataRecord["zone"])."' AND ".$app->tform->getAuthSQL('r'));
133+
$soa_id = $app->functions->intval($_POST["zone"]);
134+
$serial = $app->validate_dns->increase_serial($soa["serial"]);
135+
$app->db->datalogUpdate('dns_soa', "serial = $serial", 'id', $soa_id);
136+
}
137+
}
138+
139+
$page = new page_action;
140+
$page->onLoad();
141+
142+
?>

interface/web/dns/dns_dkim_get.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
/*
3+
Copyright (c) 2007 - 2013, Till Brehm, projektfarm Gmbh
4+
Copyright (c) 2013, Florian Schaal, info@schaal-24.de
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without modification,
8+
are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice,
11+
this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
* Neither the name of ISPConfig nor the names of its contributors
16+
may be used to endorse or promote products derived from this software without
17+
specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
/*
32+
This script is invoked by interface/web/dns/templates/dns_dkim_edit.htm
33+
when generating the DKIM Private-key.
34+
35+
return DKIM Public-Key for the DNS-record
36+
*/
37+
38+
require_once('../../lib/config.inc.php');
39+
require_once('../../lib/app.inc.php');
40+
41+
//* Check permissions for module
42+
$app->auth->check_module_permissions('dns');
43+
44+
global $app, $conf;
45+
46+
// Loading classes
47+
$app->uses('tform,tform_actions');
48+
49+
header('Content-Type: text/xml; charset=utf-8');
50+
header('Cache-Control: must-revalidate, pre-check=0, no-store, no-cache, max-age=0, post-check=0');
51+
52+
/*
53+
This function fix PHP's messing up POST input containing characters space, dot,
54+
open square bracket and others to be compatible with with the deprecated register_globals
55+
*/
56+
function getRealPOST() {
57+
$pairs = explode("&", file_get_contents("php://input"));
58+
$vars = array();
59+
foreach ($pairs as $pair) {
60+
$nv = explode("=", $pair, 2);
61+
$name = urldecode($nv[0]);
62+
$value = $nv[1];
63+
$vars[$name] = $value;
64+
}
65+
return $vars;
66+
}
67+
function pub_key($pubkey) {
68+
$public_key='';
69+
foreach($pubkey as $values) $public_key=$public_key.$values;
70+
return $public_key;
71+
}
72+
73+
$_POST=getRealPost();
74+
75+
if (ctype_digit($_POST['zone'])) {
76+
// Get the parent soa record of the domain
77+
$soa = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = '".$app->db->quote($_POST['zone'])."' AND ".$app->tform->getAuthSQL('r'));
78+
79+
$public_key=$app->db->queryOneRecord("SELECT dkim_public FROM mail_domain WHERE domain = '".substr_replace($soa['origin'],'',-1)."' AND ".$app->tform->getAuthSQL('r'));
80+
81+
$public_key=pub_key($public_key);
82+
83+
$public_key=str_replace(array('-----BEGIN PUBLIC KEY-----','-----END PUBLIC KEY-----',"\r","\n"),'',$public_key);
84+
85+
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
86+
echo "<formatname>\n";
87+
echo "<data>".$public_key."</data>\n";
88+
echo "<name>".$soa['origin']."</name>\n";
89+
echo "</formatname>\n";
90+
}
91+
?>

interface/web/dns/dns_wizard.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,20 @@
173173
$tpl_content = $template_record['template'];
174174
if($_POST['domain'] != '') $tpl_content = str_replace('{DOMAIN}',$_POST['domain'],$tpl_content);
175175
if($_POST['ip'] != '') $tpl_content = str_replace('{IP}',$_POST['ip'],$tpl_content);
176-
if($_POST['ns1'] != '') $tpl_content = str_replace('{NS1}',$_POST['ns1'],$tpl_content);
177-
if($_POST['ns2'] != '') $tpl_content = str_replace('{NS2}',$_POST['ns2'],$tpl_content);
178-
if($_POST['email'] != '') $tpl_content = str_replace('{EMAIL}',$_POST['email'],$tpl_content);
179-
180-
// Parse the template
181-
$tpl_rows = explode("\n",$tpl_content);
176+
if($_POST['ns1'] != '') $tpl_content = str_replace('{NS1}',$_POST['ns1'],$tpl_content);
177+
if($_POST['ns2'] != '') $tpl_content = str_replace('{NS2}',$_POST['ns2'],$tpl_content);
178+
if($_POST['email'] != '') $tpl_content = str_replace('{EMAIL}',$_POST['email'],$tpl_content);
179+
if(isset($_POST['dkim']) && preg_match('/^[\w\.\-\/]{2,255}\.[a-zA-Z0-9\-]{2,30}[\.]{0,1}$/',$_POST['domain'])) {
180+
$public_key=$app->db->queryOneRecord("SELECT dkim_public FROM mail_domain WHERE domain = '".$app->db->quote($_POST['domain'])."' AND dkim = 'y' AND ".$app->tform->getAuthSQL('r'));
181+
if ($public_key!='') {
182+
$dns_record=str_replace(array("\r\n", "\n", "\r","-----BEGIN PUBLIC KEY-----","-----END PUBLIC KEY-----"),'',$public_key['dkim_public']);
183+
$tpl_content = str_replace('{DKIM}','TXT|default._domainkey.'.$_POST['domain'].'.|v=DKIM1; t=s; p='.$dns_record,$tpl_content);
184+
}
185+
}
186+
187+
188+
// Parse the template
189+
$tpl_rows = explode("\n",$tpl_content);
182190
$section = '';
183191
$vars = array();
184192
$dns_rr = array();
@@ -273,7 +281,7 @@
273281
$app->tpl->setVar($wb);
274282

275283
$app->tpl_defaults();
276-
$app->tpl->pparse();
277-
278-
279-
?>
284+
$app->tpl->pparse();
285+
286+
287+
?>

0 commit comments

Comments
 (0)