Marius Burkard
2016-07-08 9bcd2fd54728b9e634442f584268da03acaea633
commit | author | age
0b0dc9 1 <?php
M 2
3 /*
4 Copyright (c) 2007 - 2009, Till Brehm, projektfarm Gmbh
5 Modified 2009, Marius Cramer, pixcept KG
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 class cron_plugin {
b1a6a5 33
0b0dc9 34     var $plugin_name = 'cron_plugin';
M 35     var $class_name = 'cron_plugin';
b1a6a5 36
0b0dc9 37     // private variables
M 38     var $action = '';
b1a6a5 39
0b0dc9 40     //* This function is called during ispconfig installation to determine
M 41     //  if a symlink shall be created for this plugin.
42     function onInstall() {
43         global $conf;
b1a6a5 44
0b0dc9 45         if($conf['services']['web'] == true) {
M 46             return true;
47         } else {
48             return false;
49         }
b1a6a5 50
0b0dc9 51     }
b1a6a5 52
MC 53
0b0dc9 54     /*
M 55          This function is called when the plugin is loaded
56     */
b1a6a5 57
0b0dc9 58     function onLoad() {
M 59         global $app;
b1a6a5 60
0b0dc9 61         /*
M 62         Register for the events
63         */
b1a6a5 64
MC 65         $app->plugins->registerEvent('cron_insert', $this->plugin_name, 'insert');
66         $app->plugins->registerEvent('cron_update', $this->plugin_name, 'update');
67         $app->plugins->registerEvent('cron_delete', $this->plugin_name, 'delete');
68
0b0dc9 69     }
b1a6a5 70
MC 71     function insert($event_name, $data) {
0b0dc9 72         global $app, $conf;
b1a6a5 73
0b0dc9 74         $this->action = 'insert';
M 75         // just run the update function
b1a6a5 76         $this->update($event_name, $data);
MC 77
0b0dc9 78     }
b1a6a5 79
MC 80
81     function update($event_name, $data) {
0b0dc9 82         global $app, $conf;
b1a6a5 83
0b0dc9 84         if($this->action != 'insert') $this->action = 'update';
b1a6a5 85
0b0dc9 86         // load the server configuration options
M 87         $app->uses("getconf");
b1a6a5 88
0b0dc9 89         if($data["new"]["parent_domain_id"] == '') {
b1a6a5 90             $app->log("Parent domain not set", LOGLEVEL_WARN);
0b0dc9 91             return 0;
M 92         }
b1a6a5 93
MC 94         //* get data from web
cc7a82 95         $parent_domain = $app->db->queryOneRecord("SELECT `domain_id`, `system_user`, `system_group`, `document_root`, `hd_quota` FROM `web_domain` WHERE `domain_id` = ?", $data["new"]["parent_domain_id"]);
b1a6a5 96         if(!$parent_domain["domain_id"]) {
MC 97             $app->log("Parent domain not found", LOGLEVEL_WARN);
98             return 0;
0b0dc9 99         }
b1a6a5 100
64ea56 101         if(!$app->system->is_allowed_user($parent_domain['system_user'], true, true)
MC 102             || !$app->system->is_allowed_group($parent_domain['system_group'], true, true)) {
103             $app->log("Websites (and Crons) cannot be owned by the root user or group.", LOGLEVEL_WARN);
104             return false;
105         }
106         
0b0dc9 107         // Get the client ID
cc7a82 108         $client = $app->dbmaster->queryOneRecord("SELECT client_id FROM sys_group WHERE sys_group.groupid = ?", $data["new"]["sys_groupid"]);
0b0dc9 109         $client_id = intval($client["client_id"]);
M 110         unset($client);
b1a6a5 111
0b0dc9 112         // Create group and user, if not exist
M 113         $app->uses("system");
b1a6a5 114
0b0dc9 115         $groupname = escapeshellcmd($parent_domain["system_group"]);
M 116         if($parent_domain["system_group"] != '' && !$app->system->is_group($parent_domain["system_group"])) {
117             exec("groupadd $groupname");
b1a6a5 118             $app->log("Adding the group: $groupname", LOGLEVEL_DEBUG);
0b0dc9 119         }
b1a6a5 120
0b0dc9 121         $username = escapeshellcmd($parent_domain["system_user"]);
M 122         if($parent_domain["system_user"] != '' && !$app->system->is_user($parent_domain["system_user"])) {
123             exec("useradd -d ".escapeshellcmd($parent_domain["document_root"])." -g $groupname $username -s /bin/false");
b1a6a5 124             $app->log("Adding the user: $username", LOGLEVEL_DEBUG);
0b0dc9 125         }
e14c6e 126         
D 127         // Set the quota for the user
128         if($username != '' && $app->system->is_user($username)) {
129            if($parent_domain['hd_quota'] > 0) {
130               $blocks_soft = $parent_domain['hd_quota'] * 1024;
131               $mb_soft = $parent_domain['hd_quota'];
132               $blocks_hard = $blocks_soft + 1024;
133               $mb_hard = $mb_soft + 1;
134             } else {
135               $mb_soft = $mb_hard = $blocks_soft = $blocks_hard = 0;
136             }
b1a6a5 137
e14c6e 138             // get the primitive folder for document_root and the filesystem, will need it later.
e8dda4 139             $df_output=explode(" ", exec("df -T " . escapeshellarg($parent_domain["document_root"]) . "|awk 'END{print \$2,\$NF}'"));
7de9c4 140             $file_system = $df_output[0];
TB 141             $primitive_root = $df_output[1];
e14c6e 142
14ab93 143             if ( in_array($file_system , array('ext2','ext3','ext4'),true) ) {
e14c6e 144               exec('setquota -u '. $username . ' ' . $blocks_soft . ' ' . $blocks_hard . ' 0 0 -a &> /dev/null');
D 145               exec('setquota -T -u '.$username.' 604800 604800 -a &> /dev/null');
146             } elseif ($file_system == 'xfs') {
147                 
148               exec("xfs_quota -x -c 'limit -g bsoft=$mb_soft" . 'm'. " bhard=$mb_hard" . 'm'. " $username' $primitive_root");
149
150               // xfs only supports timers globally, not per user.
151               exec("xfs_quota -x -c 'timer -bir -i 604800'");
152
153               unset($project_uid, $username_position, $xfs_projects);
154               unset($primitive_root, $df_output, $mb_hard, $mb_soft);
155             }
156         }
b1a6a5 157
4b88c2 158         //TODO : change this when distribution information has been integrated into server record
b1a6a5 159         //* Gentoo requires a user to be part of the crontab group.
MC 160         if (file_exists('/etc/gentoo-release')) {
161             if (strpos($app->system->get_user_groups($username), 'crontab') === false) {
162                 $app->system->add_user_to_group('crontab', $username);
163             }
164         }
165
4a6aed 166         // make temp directory writable for the apache and website users
4bd960 167         $app->system->chmod(escapeshellcmd($parent_domain["document_root"].'/tmp'), 0777);
b1a6a5 168
MC 169         /** TODO READ CRON MASTER **/
170
171
172         $this->parent_domain = $parent_domain;
0b0dc9 173         $this->_write_crontab();
b1a6a5 174
da1a7c 175         $this->action = '';
b1a6a5 176
0b0dc9 177     }
b1a6a5 178
MC 179     function delete($event_name, $data) {
0b0dc9 180         global $app, $conf;
b1a6a5 181
MC 182         //* get data from web
cc7a82 183         $parent_domain = $app->db->queryOneRecord("SELECT `domain_id`, `system_user`, `system_group`, `document_root`, `hd_quota` FROM `web_domain` WHERE `domain_id` = ?", $data["old"]["parent_domain_id"]);
b1a6a5 184         if(!$parent_domain["domain_id"]) {
MC 185             $app->log("Parent domain not found", LOGLEVEL_WARN);
186             return 0;
187         }
188
189         // Get the client ID
cc7a82 190         $client = $app->dbmaster->queryOneRecord("SELECT client_id FROM sys_group WHERE sys_group.groupid = ?", $data["old"]["sys_groupid"]);
b1a6a5 191         $client_id = intval($client["client_id"]);
MC 192         unset($client);
193
194         $this->parent_domain = $parent_domain;
195         $this->_write_crontab();
0b0dc9 196     }
b1a6a5 197
MC 198     function _write_crontab() {
199         global $app, $conf;
200
201         //* load the server configuration options
202         $app->uses("getconf");
203
204         $cron_config = $app->getconf->get_server_config($conf["server_id"], 'cron');
205
206         //* try to find customer's mail address
207
208         /** TODO: add possibility for client to choose mail notification! **/
209         $cron_content = "MAILTO=''\n";
b67344 210         $cron_content .= "SHELL='/bin/sh'\n\n";
b1a6a5 211         $chr_cron_content = "MAILTO=''\n";
MC 212         $chr_cron_content .= "SHELL='/usr/sbin/jk_chrootsh'\n\n";
213
214         $cmd_count = 0;
215         $chr_cmd_count = 0;
216
217         //* read all active cron jobs from database and write them to file
cc7a82 218         $cron_jobs = $app->db->queryAllRecords("SELECT c.`run_min`, c.`run_hour`, c.`run_mday`, c.`run_month`, c.`run_wday`, c.`command`, c.`type`, c.`log`, `web_domain`.`domain` as `domain` FROM `cron` as c INNER JOIN `web_domain` ON `web_domain`.`domain_id` = c.`parent_domain_id` WHERE c.`parent_domain_id` = ? AND c.`active` = 'y'", $this->parent_domain["domain_id"]);
b1a6a5 219         if($cron_jobs && count($cron_jobs) > 0) {
MC 220             foreach($cron_jobs as $job) {
d3687a 221                 if($job['run_month'] == '@reboot') {
T 222                     $command = "@reboot";
223                 } else {
13bfc7 224                     $command = str_replace(" ", "", $job['run_min']) . "\t" . str_replace(" ", "", $job['run_hour']) . "\t" . str_replace(" ", "", $job['run_mday']) . "\t" . str_replace(" ", "", $job['run_month']) . "\t" . str_replace(" ", "", $job['run_wday']);
b1a6a5 225                 }
46236c 226                 
MC 227                 $log_target = ">/dev/null 2>&1";
b26653 228                 $log_wget_target = '/dev/null';
MC 229                 $log_root = '';
46236c 230                 if($job['log'] == 'y') {
b26653 231                     if($job['type'] != 'chrooted') $log_root = $this->parent_domain['document_root'];
8b49ff 232                     $log_root .= '/private';
46236c 233                     
b26653 234                     $log_target = '>>' . $log_root . '/cron.log 2>>' . $log_root . '/cron_error.log';
MC 235                     $log_wget_target = $log_root . '/cron_wget.log';
46236c 236                 }
MC 237                 
d3687a 238                 $command .= "\t{$this->parent_domain['system_user']}"; //* running as user
b1a6a5 239                 if($job['type'] == 'url') {
b26653 240                     $command .= "\t{$cron_config['wget']} -q -t 1 -T 7200 -O " . $log_wget_target . " " . escapeshellarg($job['command']) . " " . $log_target;
b1a6a5 241                 } else {
0a02ee 242                     $web_root = '';
b1a6a5 243                     if($job['type'] == 'chrooted') {
MC 244                         if(substr($job['command'], 0, strlen($this->parent_domain['document_root'])) == $this->parent_domain['document_root']) {
245                             //* delete the unneeded path part
246                             $job['command'] = substr($job['command'], strlen($this->parent_domain['document_root']));
247                         }
0a02ee 248                     } else {
MC 249                         $web_root = $this->parent_domain['document_root'];
b1a6a5 250                     }
46236c 251                     
0a02ee 252                     $web_root .= '/web';
MC 253                     $job['command'] = str_replace('[web_root]', $web_root, $job['command']);
b1a6a5 254
MC 255                     $command .= "\t";
558b54 256                     //if($job['type'] != 'chrooted' && substr($job['command'], 0, 1) != "/") $command .= $this->parent_domain['document_root'].'/';
46236c 257                     $command .= $job['command'] . " " . $log_target;
b1a6a5 258                 }
MC 259
260                 if($job['type'] == 'chrooted') {
261                     $chr_cron_content .= $command . " #{$job['domain']}\n";
262                     $chr_cmd_count++;
263                 } else {
264                     $cron_content .= $command . " #{$job['domain']}\n";
265                     $cmd_count++;
266                 }
267             }
268         }
269
270         $cron_file = escapeshellcmd($cron_config["crontab_dir"].'/ispc_'.$this->parent_domain["system_user"]);
271         //TODO : change this when distribution information has been integrated into server record
272         //* Gentoo vixie-cron requires files to end with .cron in the cron.d directory
273         if (file_exists('/etc/gentoo-release')) {
274             $cron_file .= '.cron';
275         }
276
277         if($cmd_count > 0) {
278             $app->system->file_put_contents($cron_file, $cron_content);
279             $app->log("Wrote Cron file $cron_file with content:\n$cron_content", LOGLEVEL_DEBUG);
280         } else {
281             $app->system->unlink($cron_file);
282             $app->log("Deleted Cron file $cron_file", LOGLEVEL_DEBUG);
283         }
284
285         $cron_file = escapeshellcmd($cron_config["crontab_dir"].'/ispc_chrooted_'.$this->parent_domain["system_user"]);
286         if($chr_cmd_count > 0) {
287             $app->system->file_put_contents($cron_file, $chr_cron_content);
288             $app->log("Wrote Cron file $cron_file with content:\n$chr_cron_content", LOGLEVEL_DEBUG);
289         } else {
290             $app->system->unlink($cron_file);
291             $app->log("Deleted Cron file $cron_file", LOGLEVEL_DEBUG);
292         }
293
294         return 0;
295     }
0b0dc9 296
M 297 } // end class
298
4a6aed 299 ?>