Marius Cramer
2015-08-06 37b29231e47a0c4458dc1c15d98588f16f07e1e2
commit | author | age
a12b09 1 <?php
FS 2 /*
3 Copyright (c) 2014, Florian Schaal, info@schaal-24.de
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without modification,
7 are permitted provided that the following conditions are met:
8
9     * Redistributions of source code must retain the above copyright notice,
10       this list of conditions and the following disclaimer.
11     * Redistributions in binary form must reproduce the above copyright notice,
12       this list of conditions and the following disclaimer in the documentation
13       and/or other materials provided with the distribution.
14     * Neither the name of ISPConfig nor the names of its contributors
15       may be used to endorse or promote products derived from this software without
16       specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /******************************************
31 * Begin Form configuration
32 ******************************************/
33
34 $tform_def_file = "form/dns_dmarc.tform.php";
35
36 /******************************************
37 * End Form configuration
38 ******************************************/
39
40 require_once '../../lib/config.inc.php';
41 require_once '../../lib/app.inc.php';
42
43 //* Check permissions for module
44 $app->auth->check_module_permissions('dns');
45
46 // Loading classes
47 $app->uses('tpl,tform,tform_actions,validate_dns');
48 $app->load('tform_actions');
49
50 class page_action extends tform_actions {
51     function onShowNew() {
52         global $app, $conf;
53         // we will check only users, not admins
54         if($_SESSION["s"]["user"]["typ"] == 'user') {
55
56             // Get the limits of the client
57             $client_group_id = intval($_SESSION["s"]["user"]["default_group"]);
58             $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);
59
60             // Check if the user may add another mailbox.
61             if($client["limit_dns_record"] >= 0) {
62                 $tmp = $app->db->queryOneRecord("SELECT count(id) as number FROM dns_rr WHERE sys_groupid = ?", $client_group_id);
63                 if($tmp["number"] >= $client["limit_dns_record"]) {
64                     $app->error($app->tform->wordbook["limit_dns_record_txt"]);
65                 }
66             }
67         }
68
69         parent::onShowNew();
70     }
71
72     function onShowEnd() {
73         global $app, $conf;
74
75         $zone = $app->functions->intval($_GET['zone']);
76         // get domain-name
cc7a82 77         $sql = "SELECT * FROM dns_soa WHERE id = ? AND " . $app->tform->getAuthSQL('r');
MC 78         $rec = $app->db->queryOneRecord($sql, $zone);
a12b09 79         $domain_name = rtrim($rec['origin'], '.');
FS 80
81         // set defaults
82         $dmarc_policy = 'none';
83         $dmarc_adkim = 'r';
84         $dmarc_aspf = 'r';
85         $dmarc_rf = 'afrf';
86         $dmarc_pct = 100;
87         $dmarc_ri = 86400;
88         $dmarc_sp = 'same';
89
90         //* check for an existing dmarc-record
cc7a82 91         $sql = "SELECT data, active FROM dns_rr WHERE data LIKE 'v=DMARC1%' AND zone = ? AND name = ? AND " . $app->tform->getAuthSQL('r');
MC 92         $rec = $app->db->queryOneRecord($sql, $zone, '_dmarc.'.$domain_name.'.');
a12b09 93         if ( isset($rec) && !empty($rec) ) {
FS 94             $this->id = 1;
95             $old_data = strtolower($rec['data']);
96             $app->tpl->setVar("data", $old_data);
97             if ($rec['active'] == 'Y') $app->tpl->setVar("active", "CHECKED");
98             $dmarc_rua = '';
99             $dmarc_ruf = '';
100             $dmac_rf = '';
101             $dmac_rua = '';
102             $dmac_ruf = '';
103             // browse through data
104             $temp = explode('; ', $old_data);
105             foreach ($temp as $part) {
106                 if (preg_match("/^p=/", $part)) $dmarc_policy = str_replace('p=', '', $part);
21ae0c 107                 if (preg_match("/^rua=/", $part)) {
FS 108                     $dmarc_rua = str_replace(array('rua=','mailto:'), '', $part).' ';
109                     $dmarc_rua = str_replace(',', ' ', $dmarc_rua);
110                 }
111                 if (preg_match("/^ruf=/", $part)) {
112                     $dmarc_ruf = str_replace(array('ruf=','mailto:'), '', $part).' ';
113                     $dmarc_ruf = str_replace(',', ' ', $dmarc_ruf);
114                 }
115                 if (preg_match("/^fo=/", $part)) $dmarc_fo = str_replace('fo=', '', $part);
a12b09 116                 if (preg_match("/^adkim=/", $part)) $dmarc_adkim = str_replace('adkim=', '', $part);
FS 117                 if (preg_match("/^aspf=/", $part)) $dmarc_aspf = str_replace('aspf=', '', $part);
118                 if (preg_match("/^rf=/", $part)) $dmarc_rf = str_replace('rf=', '', $part);
119                 if (preg_match("/^(afrf:iodef|iodef:afrf)$/s", $dmarc_rf)) $dmarc_rf = str_replace(':', ' ', $dmarc_rf);
120                 if (preg_match("/^pct=/", $part)) $dmarc_pct = str_replace('pct=', '', $part);
121                 if (preg_match("/^ri=/", $part)) $dmarc_ri = str_replace('ri=', '', $part);
122             }
123         } 
124
125         //set html-values
126         $app->tpl->setVar('domain', $domain_name);
127
128         //create dmarc-policy-list
129         $dmarc_policy_value = array( 
130             'none' => 'dmarc_policy_none_txt',
131             'quarantine' => 'dmarc_policy_quarantine_txt',
132             'reject' => 'dmarc_policy_reject_txt',
133         );
134         $dmarc_policy_list='';
135         foreach($dmarc_policy_value as $value => $txt) {
136             $selected = @($dmarc_policy == $value)?' selected':'';
137             $dmarc_policy_list .= "<option value='$value'$selected>".$app->tform->wordbook[$txt]."</option>\r\n";
138         }
139         $app->tpl->setVar('dmarc_policy', $dmarc_policy_list);
140
141         if (!empty($dmarc_rua)) $app->tpl->setVar("dmarc_rua", $dmarc_rua);
142
143         if (!empty($dmarc_ruf)) $app->tpl->setVar("dmarc_ruf", $dmarc_ruf);
144
145         //set dmarc-fo-options
21ae0c 146         if (isset($dmarc_fo)) {
FS 147             $temp = explode(':', $dmarc_fo);
a12b09 148             foreach ($temp as $fo => $value) $app->tpl->setVar("dmarc_fo".$value, 'CHECKED');
21ae0c 149         } else
a12b09 150             $app->tpl->setVar("dmarc_fo0", 'CHECKED');
FS 151
152         unset($temp);
153
154         //create dmarc-adkim-list
155         $dmarc_adkim_value = array( 
156             'r' => 'dmarc_adkim_r_txt',
157             's' => 'dmarc_adkim_s_txt',
158         );
159         $dmarc_adkim_list='';
160         foreach($dmarc_adkim_value as $value => $txt) {
161             $selected = @($dmarc_adkim == $value)?' selected':'';
162             $dmarc_adkim_list .= "<option value='$value'$selected>".$app->tform->wordbook[$txt]."</option>\r\n";
163         }
164         $app->tpl->setVar('dmarc_adkim', $dmarc_adkim_list);
165
166         //create dmarc-aspf-list
167         $dmarc_aspf_value = array( 
168             'r' => 'dmarc_aspf_r_txt',
169             's' => 'dmarc_aspf_s_txt',
170         );
171         $dmarc_aspf_list='';
172         foreach($dmarc_aspf_value as $value => $txt) {
173             $selected = @($dmarc_aspf == $value)?' selected':'';
174             $dmarc_aspf_list .= "<option value='$value'$selected>".$app->tform->wordbook[$txt]."</option>\r\n";
175         }
176         $app->tpl->setVar('dmarc_aspf', $dmarc_aspf_list);
177
178         if ( strpos($dmarc_rf, 'afrf') !== false ) $app->tpl->setVar("dmarc_rf_afrf", 'CHECKED');
179         if ( strpos($dmarc_rf, 'iodef') !== false ) $app->tpl->setVar("dmarc_rf_iodef", 'CHECKED');
180
181         $app->tpl->setVar("dmarc_pct", $dmarc_pct);
182
183         $app->tpl->setVar("dmarc_ri", $dmarc_ri);
184
185         //create dmarc-sp-list
186         $dmarc_sp_value = array( 
187             'same' => 'dmarc_sp_same_txt',
188             'none' => 'dmarc_sp_none_txt',
189             'quarantine' => 'dmarc_sp_quarantine_txt',
190             'reject' => 'dmarc_sp_reject_txt',
191         );
192         $dmarc_sp_list='';
193         foreach($dmarc_sp_value as $value => $txt) {
194             $selected = @($dmarc_sp == $value)?' selected':'';
195             $dmarc_sp_list .= "<option value='$value'$selected>".$app->tform->wordbook[$txt]."</option>\r\n";
196         }
197         $app->tpl->setVar('dmarc_sp', $dmarc_sp_list);
198
199         parent::onShowEnd();
200
201     }
202
203     function onSubmit() {
204         global $app, $conf;
205
206         // Get the parent soa record of the domain
cc7a82 207         $soa = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ? AND " . $app->tform->getAuthSQL('r'), $_POST['zone']);
a12b09 208
FS 209         // Check if Domain belongs to user
210         if($soa["id"] != $_POST["zone"]) $app->tform->errorMessage .= $app->tform->wordbook["no_zone_perm"];
211
212         // Check the client limits, if user is not the admin
213         if($_SESSION["s"]["user"]["typ"] != 'admin') { // if user is not admin
214             // Get the limits of the client
215             $client_group_id = intval($_SESSION["s"]["user"]["default_group"]);
216             $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);
217
218             // Check if the user may add another mailbox.
219             if($this->id == 0 && $client["limit_dns_record"] >= 0) {
220                 $tmp = $app->db->queryOneRecord("SELECT count(id) as number FROM dns_rr WHERE sys_groupid = ?", $client_group_id);
221                 if($tmp["number"] >= $client["limit_dns_record"]) {
222                     $app->error($app->tform->wordbook["limit_dns_record_txt"]);
223                 }
224             }
225         } // end if user is not admin
226
227         $domain_name = rtrim($soa['origin'], '.');
228         // DMARC requieres at least one active dkim-record...
229         $sql = "SELECT * FROM dns_rr WHERE name LIKE ? AND type='TXT' AND data like 'v=DKIM1;%' AND active='Y'";
d84a2d 230         $temp = $app->db->queryAllRecords($sql, '%._domainkey.'.$domain_name.'.');
FS 231         if (empty($temp)) {
a12b09 232             if (isset($app->tform->errorMessage )) $app->tform->errorMessage = '<br/>' . $app->tform->errorMessage;
FS 233             $app->tform->errorMessage .= $app->tform->wordbook['dmarc_no_dkim_txt'].$email;
234         }
235
bde8b1 236         // ... and an active spf-record (this breaks the current draft but DMARC is useless if you use DKIM or SPF
d84a2d 237         $sql = "SELECT * FROM dns_rr WHERE name LIKE ? AND type='TXT' AND (data LIKE 'v=spf1%' AND active = 'y')";
a12b09 238         $temp = $app->db->queryAllRecords($sql, $domain_name.'.');
FS 239         // abort if more than 1 active spf-records (backward-compatibility)
240         if (is_array($temp[1])) {
241             if (isset($app->tform->errorMessage )) $app->tform->errorMessage = '<br/>' . $app->tform->errorMessage;
bde8b1 242             $app->tform->errorMessage .= $app->tform->wordbook['dmarc_more_spf_txt'];
a12b09 243         }
FS 244         if (empty($temp)) {
245             if (isset($app->tform->errorMessage )) $app->tform->errorMessage = '<br/>' . $app->tform->errorMessage;
bde8b1 246             $app->tform->errorMessage .= $app->tform->wordbook['dmarc_no_spf_txt'];
a12b09 247         }
FS 248         unset($temp);
bde8b1 249
a12b09 250         //validate dmarc_pct
FS 251         $this->dataRecord['dmarc_pct'] = $app->functions->intval($this->dataRecord['dmarc_pct']);
252         if ($this->dataRecord['dmarc_pct'] < 0) $this->dataRecord['dmarc_pct'] = 0;
253         if ($this->dataRecord['dmarc_pct'] > 100) $this->dataRecord['dmarc_pct'] = 100;
254         
255         //create dmarc-record
256         $dmarc_record[] = 'p='.$this->dataRecord['dmarc_policy'];
257
21ae0c 258         if (!empty($this->dataRecord['dmarc_rua'])) {
FS 259             $dmarc_rua = explode(' ', $this->dataRecord['dmarc_rua']);
260             $dmarc_rua = array_filter($dmarc_rua);
261             foreach ($dmarc_rua as $rec) {
262                 if (!filter_var($rec, FILTER_VALIDATE_EMAIL)) {
a12b09 263                     if (isset($app->tform->errorMessage )) $app->tform->errorMessage = '<br/>' . $app->tform->errorMessage;
bde8b1 264                     $app->tform->errorMessage .= $app->tform->wordbook['dmarc_invalid_email_txt'].': '.$dmarc_rua;
a12b09 265                 } else {
21ae0c 266                     $temp .= 'mailto:'.$rec.',';
a12b09 267                 }
FS 268             }
21ae0c 269             $dmarc_record[] = 'rua='.rtrim($temp, ',');
FS 270             unset ($dmarc_rua);
271             unset($temp);
a12b09 272         }
21ae0c 273         
FS 274         if (!empty($this->dataRecord['dmarc_ruf'])) {
275             $dmarc_ruf = explode(' ', $this->dataRecord['dmarc_ruf']);
276             $dmarc_ruf = array_filter($dmarc_ruf);
277             foreach ($dmarc_ruf as $rec) {
278                 if (!filter_var($rec, FILTER_VALIDATE_EMAIL)) {
a12b09 279                     if (isset($app->tform->errorMessage )) $app->tform->errorMessage = '<br/>' . $app->tform->errorMessage;
bde8b1 280                     $app->tform->errorMessage .= $app->tform->wordbook['dmarc_invalid_email_txt'].': '.$dmarc_rua;
a12b09 281                 } else {
21ae0c 282                     $temp .= 'mailto:'.$rec.',';
a12b09 283                 }
FS 284             }
21ae0c 285             $dmarc_record[] = 'ruf='.rtrim($temp, ',');
FS 286             unset ($dmarc_ruf);
287             unset($temp);
a12b09 288         }
FS 289         
290         $fo_rec = '';
291         if (isset($this->dataRecord['dmarc_fo0'])) $fo_rec[] = '0';
292         if (isset($this->dataRecord['dmarc_fo1'])) $fo_rec[] = '1';
293         if (isset($this->dataRecord['dmarc_fod'])) $fo_rec[] = 'd';
294         if (isset($this->dataRecord['dmarc_fos'])) $fo_rec[] = 's';
21ae0c 295         if (is_array($fo_rec) && !empty($fo_rec)) {
FS 296             $rec = 'fo='.implode(':', $fo_rec);
297             if ($rec != 'fo=0') $dmarc_record[] = 'fo='.implode(':', $fo_rec);
298             unset($rec);
299         }
a12b09 300
21ae0c 301         if ($this->dataRecord['dmarc_adkim'] != 'r' )
a12b09 302             $dmarc_record[] = 'adkim='.$this->dataRecord['dmarc_adkim'];
FS 303
21ae0c 304         if ($this->dataRecord['dmarc_aspf'] != 'r' )
a12b09 305             $dmarc_record[] = 'aspf='.$this->dataRecord['dmarc_aspf'];
FS 306
307         if (isset($this->dataRecord['dmarc_rf_afrf']) && isset($this->dataRecord['dmarc_rf_iodef']))
308             $dmarc_record[] = 'rf=afrf:iodef';
309         else {
310              if (isset($this->dataRecord['dmarc_rf_iodef']))
311                 $dmarc_record[] = 'rf=iodef';
312         }
313         unset($fo_rec);
314
315         if (!empty($this->dataRecord['dmarc_pct']) && $this->dataRecord['dmarc_pct'] != 100)
316             $dmarc_record[] = 'pct='.$this->dataRecord['dmarc_pct'];
317
318         if (!empty($this->dataRecord['dmarc_ri']) && $this->dataRecord['dmarc_ri'] != '86400')
319             $dmarc_record[] = 'ri='.$this->dataRecord['dmarc_ri'];
320
321         if (!empty($this->dataRecord['dmarc_sp']) && $this->dataRecord['dmarc_sp'] != 'same')
322             $dmarc_record[] = 'sp='.$this->dataRecord['dmarc_sp'];
323
324         $temp = implode('; ', $dmarc_record);
325         if (!empty($temp))
326             $this->dataRecord['data'] = 'v=DMARC1; ' . $temp;
327         else $app->tform->errorMessage .= $app->tform->wordbook["dmarc_empty_txt"];
328
329         $this->dataRecord['name'] = '_dmarc.' . $soa['origin'];
330         if (isset($this->dataRecord['active'])) $this->dataRecord['active'] = 'Y';
331         
332         // Set the server ID of the rr record to the same server ID as the parent record.
333         $this->dataRecord["server_id"] = $soa["server_id"];
334
335         // Update the serial number  and timestamp of the RR record
336         $soa = $app->db->queryOneRecord("SELECT serial FROM dns_rr WHERE id = ?", $this->id);
337         $this->dataRecord["serial"] = $app->validate_dns->increase_serial($soa["serial"]);
338         $this->dataRecord["stamp"] = date('Y-m-d H:i:s');
339
340         // always update an existing entry
341         $check=$app->db->queryOneRecord("SELECT * FROM dns_rr WHERE zone = ? AND type = ? AND data LIKE 'v=DMARC1%' AND name = ?", $this->dataRecord['zone'], $this->dataRecord['type'], $this->dataRecord['name']);
342         $this->id = $check['id'];
343         if (!isset($this->dataRecord['active'])) $this->dataRecord['active'] = 'N';
344
345         parent::onSubmit();
346     }
347
348     function onAfterInsert() {
349         global $app, $conf;
350
351         //* Set the sys_groupid of the rr record to be the same then the sys_groupid of the soa record
cc7a82 352         $soa = $app->db->queryOneRecord("SELECT sys_groupid,serial FROM dns_soa WHERE id = ? AND " . $app->tform->getAuthSQL('r'), $app->functions->intval($this->dataRecord["zone"]));
3a11d2 353         $app->db->datalogUpdate('dns_rr', array("sys_groupid" => $soa['sys_groupid']), 'id', $this->id);
a12b09 354
FS 355         //* Update the serial number of the SOA record
356         $soa_id = $app->functions->intval($_POST["zone"]);
357         $serial = $app->validate_dns->increase_serial($soa["serial"]);
3a11d2 358         $app->db->datalogUpdate('dns_soa', array("serial" => $serial), 'id', $soa_id);
a12b09 359
FS 360     }
361
362     function onAfterUpdate() {
363         global $app, $conf;
364
365         //* Update the serial number of the SOA record
cc7a82 366         $soa = $app->db->queryOneRecord("SELECT serial FROM dns_soa WHERE id = ? AND " . $app->tform->getAuthSQL('r'), $app->functions->intval($this->dataRecord["zone"]));
a12b09 367         $soa_id = $app->functions->intval($_POST["zone"]);
FS 368         $serial = $app->validate_dns->increase_serial($soa["serial"]);
3a11d2 369         $app->db->datalogUpdate('dns_soa', array("serial" => $serial), 'id', $soa_id);
a12b09 370     }
FS 371
372 }
373
374 $page = new page_action;
375 $page->onLoad();
376
377 ?>