tbrehm
2012-06-05 fa2806bddf4ce838d30d7fab1b5300e8632c586d
commit | author | age
46c683 1 <?php
T 2
3 /*
4 Copyright (c) 2007 - 2009, Till Brehm, projektfarm Gmbh
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 class apache2_plugin {
ac933e 32
46c683 33     var $plugin_name = 'apache2_plugin';
T 34     var $class_name = 'apache2_plugin';
ac933e 35
46c683 36     // private variables
T 37     var $action = '';
ac933e 38
46c683 39     //* This function is called during ispconfig installation to determine
T 40     //  if a symlink shall be created for this plugin.
41     function onInstall() {
42         global $conf;
ac933e 43
46c683 44         if($conf['services']['web'] == true) {
T 45             return true;
46         } else {
47             return false;
48         }
ac933e 49
46c683 50     }
ac933e 51
V 52
46c683 53     /*
T 54          This function is called when the plugin is loaded
55     */
ac933e 56
46c683 57     function onLoad() {
T 58         global $app;
ac933e 59
46c683 60         /*
T 61         Register for the events
62         */
63         $app->plugins->registerEvent('web_domain_insert',$this->plugin_name,'ssl');
64         $app->plugins->registerEvent('web_domain_update',$this->plugin_name,'ssl');
65         $app->plugins->registerEvent('web_domain_delete',$this->plugin_name,'ssl');
ac933e 66
46c683 67         $app->plugins->registerEvent('web_domain_insert',$this->plugin_name,'insert');
T 68         $app->plugins->registerEvent('web_domain_update',$this->plugin_name,'update');
69         $app->plugins->registerEvent('web_domain_delete',$this->plugin_name,'delete');
ac933e 70
46c683 71         $app->plugins->registerEvent('server_ip_insert',$this->plugin_name,'server_ip');
T 72         $app->plugins->registerEvent('server_ip_update',$this->plugin_name,'server_ip');
73         $app->plugins->registerEvent('server_ip_delete',$this->plugin_name,'server_ip');
ac933e 74
V 75         $app->plugins->registerEvent('webdav_user_insert',$this->plugin_name,'webdav');
76         $app->plugins->registerEvent('webdav_user_update',$this->plugin_name,'webdav');
77         $app->plugins->registerEvent('webdav_user_delete',$this->plugin_name,'webdav');
1ca823 78         
T 79         $app->plugins->registerEvent('client_delete',$this->plugin_name,'client_delete');
524077 80         
T 81         $app->plugins->registerEvent('web_folder_user_insert',$this->plugin_name,'web_folder_user');
82         $app->plugins->registerEvent('web_folder_user_update',$this->plugin_name,'web_folder_user');
83         $app->plugins->registerEvent('web_folder_user_delete',$this->plugin_name,'web_folder_user');
84         
2023a7 85         $app->plugins->registerEvent('web_folder_update',$this->plugin_name,'web_folder_update');
524077 86         $app->plugins->registerEvent('web_folder_delete',$this->plugin_name,'web_folder_delete');
T 87         
46c683 88     }
ac933e 89
46c683 90     // Handle the creation of SSL certificates
T 91     function ssl($event_name,$data) {
92         global $app, $conf;
1a2310 93
L 94         // load the server configuration options
95         $app->uses('getconf');
96         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
97         if ($web_config['CA_path']!='' && !file_exists($web_config['CA_path'].'/openssl.cnf'))
98             $app->log("CA path error, file does not exist:".$web_config['CA_path'].'/openssl.conf',LOGLEVEL_ERROR);    
1ca823 99         
T 100         //* Only vhosts can have a ssl cert
101         if($data["new"]["type"] != "vhost") return;
ac933e 102
fb3339 103         if(!is_dir($data['new']['document_root'].'/ssl')) exec('mkdir -p '.$data['new']['document_root'].'/ssl');
J 104         $ssl_dir = $data['new']['document_root'].'/ssl';
105         $domain = $data['new']['ssl_domain'];
106         $key_file = $ssl_dir.'/'.$domain.'.key.org';
107         $key_file2 = $ssl_dir.'/'.$domain.'.key';
108         $csr_file = $ssl_dir.'/'.$domain.'.csr';
109         $crt_file = $ssl_dir.'/'.$domain.'.crt';
ac933e 110
46c683 111         //* Create a SSL Certificate
fb3339 112         if($data['new']['ssl_action'] == 'create') {
668ba0 113             
T 114             //* Rename files if they exist
115             if(file_exists($key_file)) rename($key_file,$key_file.'.bak');
116             if(file_exists($key_file2)) rename($key_file2,$key_file2.'.bak');
117             if(file_exists($csr_file)) rename($csr_file,$csr_file.'.bak');
118             if(file_exists($crt_file)) rename($crt_file,$crt_file.'.bak');
119             
fb3339 120             $rand_file = $ssl_dir.'/random_file';
ac933e 121             $rand_data = md5(uniqid(microtime(),1));
V 122             for($i=0; $i<1000; $i++) {
123                 $rand_data .= md5(uniqid(microtime(),1));
124                 $rand_data .= md5(uniqid(microtime(),1));
125                 $rand_data .= md5(uniqid(microtime(),1));
126                 $rand_data .= md5(uniqid(microtime(),1));
127             }
128             file_put_contents($rand_file, $rand_data);
46c683 129
ac933e 130             $ssl_password = substr(md5(uniqid(microtime(),1)), 0, 15);
V 131
46c683 132             $ssl_cnf = "        RANDFILE               = $rand_file
T 133
134         [ req ]
6d80f5 135         default_bits           = 2048
46c683 136         default_keyfile        = keyfile.pem
T 137         distinguished_name     = req_distinguished_name
138         attributes             = req_attributes
139         prompt                 = no
140         output_password        = $ssl_password
141
142         [ req_distinguished_name ]
668ba0 143         C                      = ".trim($data['new']['ssl_country'])."
T 144         ST                     = ".trim($data['new']['ssl_state'])."
145         L                      = ".trim($data['new']['ssl_locality'])."
146         O                      = ".trim($data['new']['ssl_organisation'])."
147         OU                     = ".trim($data['new']['ssl_organisation_unit'])."
46c683 148         CN                     = $domain
T 149         emailAddress           = webmaster@".$data['new']['domain']."
150
151         [ req_attributes ]
152         challengePassword              = A challenge password";
ac933e 153
fb3339 154             $ssl_cnf_file = $ssl_dir.'/openssl.conf';
46c683 155             file_put_contents($ssl_cnf_file,$ssl_cnf);
ac933e 156
46c683 157             $rand_file = escapeshellcmd($rand_file);
T 158             $key_file = escapeshellcmd($key_file);
159             $key_file2 = escapeshellcmd($key_file2);
160             $ssl_days = 3650;
161             $csr_file = escapeshellcmd($csr_file);
162             $config_file = escapeshellcmd($ssl_cnf_file);
163             $crt_file = escapeshellcmd($crt_file);
164
ac933e 165             if(is_file($ssl_cnf_file)) {
1a2310 166                 
5c4d55 167                 exec("openssl genrsa -des3 -rand $rand_file -passout pass:$ssl_password -out $key_file 2048");
L 168                 exec("openssl req -new -passin pass:$ssl_password -passout pass:$ssl_password -key $key_file -out $csr_file -days $ssl_days -config $config_file");
1a2310 169                 exec("openssl rsa -passin pass:$ssl_password -in $key_file -out $key_file2");
L 170
171                 if(file_exists($web_config['CA_path'].'/openssl.cnf'))
5c4d55 172                 {
1a2310 173                     exec("openssl ca -batch -out $crt_file -config ".$web_config['CA_path']."/openssl.cnf -passin pass:".$web_config['CA_pass']." -in $csr_file");
5c4d55 174                     $app->log("Creating CA-signed SSL Cert for: $domain",LOGLEVEL_DEBUG);
1a2310 175                     if (filesize($crt_file)==0 || !file_exists($crt_file)) $app->log("CA-Certificate signing failed.  openssl ca -out $crt_file -config ".$web_config['CA_path']."/openssl.cnf -passin pass:".$web_config['CA_pass']." -in $csr_file",LOGLEVEL_ERROR);
L 176                 };
f442da 177                 if (@filesize($crt_file)==0 || !file_exists($crt_file)){
5c4d55 178                     exec("openssl req -x509 -passin pass:$ssl_password -passout pass:$ssl_password -key $key_file -in $csr_file -out $crt_file -days $ssl_days -config $config_file ");
L 179                     $app->log("Creating self-signed SSL Cert for: $domain",LOGLEVEL_DEBUG);
180                 };
1a2310 181             
ac933e 182             }
46c683 183
fb3339 184             exec('chmod 400 '.$key_file2);
ac933e 185             @unlink($config_file);
V 186             @unlink($rand_file);
187             $ssl_request = $app->db->quote(file_get_contents($csr_file));
188             $ssl_cert = $app->db->quote(file_get_contents($crt_file));
d1086f 189             /* Update the DB of the (local) Server */
fb3339 190             $app->db->query("UPDATE web_domain SET ssl_request = '$ssl_request', ssl_cert = '$ssl_cert' WHERE domain = '".$data['new']['domain']."'");
J 191             $app->db->query("UPDATE web_domain SET ssl_action = '' WHERE domain = '".$data['new']['domain']."'");
d1086f 192             /* Update also the master-DB of the Server-Farm */
fb3339 193             $app->dbmaster->query("UPDATE web_domain SET ssl_request = '$ssl_request', ssl_cert = '$ssl_cert' WHERE domain = '".$data['new']['domain']."'");
J 194             $app->dbmaster->query("UPDATE web_domain SET ssl_action = '' WHERE domain = '".$data['new']['domain']."'");
46c683 195         }
ac933e 196
46c683 197         //* Save a SSL certificate to disk
9f56bd 198         if($data["new"]["ssl_action"] == 'save') {
T 199             $ssl_dir = $data["new"]["document_root"]."/ssl";
662d4c 200             $domain = ($data["new"]["ssl_domain"] != '')?$data["new"]["ssl_domain"]:$data["new"]["domain"];
9f56bd 201             $csr_file = $ssl_dir.'/'.$domain.".csr";
T 202             $crt_file = $ssl_dir.'/'.$domain.".crt";
203             $bundle_file = $ssl_dir.'/'.$domain.".bundle";
204             if(trim($data["new"]["ssl_request"]) != '') file_put_contents($csr_file,$data["new"]["ssl_request"]);
205             if(trim($data["new"]["ssl_cert"]) != '') file_put_contents($crt_file,$data["new"]["ssl_cert"]);
206             if(trim($data["new"]["ssl_bundle"]) != '') file_put_contents($bundle_file,$data["new"]["ssl_bundle"]);
d1086f 207             /* Update the DB of the (local) Server */
fb3339 208             $app->db->query("UPDATE web_domain SET ssl_action = '' WHERE domain = '".$data['new']['domain']."'");
d1086f 209             /* Update also the master-DB of the Server-Farm */
fb3339 210             $app->dbmaster->query("UPDATE web_domain SET ssl_action = '' WHERE domain = '".$data['new']['domain']."'");
J 211             $app->log('Saving SSL Cert for: '.$domain,LOGLEVEL_DEBUG);
46c683 212         }
ac933e 213
46c683 214         //* Delete a SSL certificate
fb3339 215         if($data['new']['ssl_action'] == 'del') {
J 216             $ssl_dir = $data['new']['document_root'].'/ssl';
662d4c 217             $domain = ($data["new"]["ssl_domain"] != '')?$data["new"]["ssl_domain"]:$data["new"]["domain"];
fb3339 218             $csr_file = $ssl_dir.'/'.$domain.'.csr';
J 219             $crt_file = $ssl_dir.'/'.$domain.'.crt';
220             $bundle_file = $ssl_dir.'/'.$domain.'.bundle';
1a2310 221             if(file_exists($web_config['CA_path'].'/openssl.cnf'))
5c4d55 222                 {
1a2310 223                     exec("openssl ca -batch -config ".$web_config['CA_path']."/openssl.cnf -passin pass:".$web_config['CA_pass']." -revoke $crt_file");
5c4d55 224                     $app->log("Revoking CA-signed SSL Cert for: $domain",LOGLEVEL_DEBUG);
L 225                 };
46c683 226             unlink($csr_file);
T 227             unlink($crt_file);
228             unlink($bundle_file);
d1086f 229             /* Update the DB of the (local) Server */
fb3339 230             $app->db->query("UPDATE web_domain SET ssl_request = '', ssl_cert = '' WHERE domain = '".$data['new']['domain']."'");
J 231             $app->db->query("UPDATE web_domain SET ssl_action = '' WHERE domain = '".$data['new']['domain']."'");
d1086f 232             /* Update also the master-DB of the Server-Farm */
fb3339 233             $app->dbmaster->query("UPDATE web_domain SET ssl_request = '', ssl_cert = '' WHERE domain = '".$data['new']['domain']."'");
J 234             $app->dbmaster->query("UPDATE web_domain SET ssl_action = '' WHERE domain = '".$data['new']['domain']."'");
235             $app->log('Deleting SSL Cert for: '.$domain,LOGLEVEL_DEBUG);
46c683 236         }
ac933e 237
46c683 238     }
ac933e 239
V 240
46c683 241     function insert($event_name,$data) {
T 242         global $app, $conf;
ac933e 243
46c683 244         $this->action = 'insert';
T 245         // just run the update function
246         $this->update($event_name,$data);
ac933e 247
V 248
46c683 249     }
ac933e 250
V 251
46c683 252     function update($event_name,$data) {
T 253         global $app, $conf;
ac933e 254
46c683 255         if($this->action != 'insert') $this->action = 'update';
ac933e 256
fb3339 257         if($data['new']['type'] != 'vhost' && $data['new']['parent_domain_id'] > 0) {
ac933e 258
fb3339 259             $old_parent_domain_id = intval($data['old']['parent_domain_id']);
J 260             $new_parent_domain_id = intval($data['new']['parent_domain_id']);
ac933e 261
1ca823 262             // If the parent_domain_id has been changed, we will have to update the old site as well.
fb3339 263             if($this->action == 'update' && $data['new']['parent_domain_id'] != $data['old']['parent_domain_id']) {
J 264                 $tmp = $app->db->queryOneRecord('SELECT * FROM web_domain WHERE domain_id = '.$old_parent_domain_id." AND active = 'y'");
265                 $data['new'] = $tmp;
266                 $data['old'] = $tmp;
46c683 267                 $this->action = 'update';
T 268                 $this->update($event_name,$data);
269             }
ac933e 270
46c683 271             // This is not a vhost, so we need to update the parent record instead.
fb3339 272             $tmp = $app->db->queryOneRecord('SELECT * FROM web_domain WHERE domain_id = '.$new_parent_domain_id." AND active = 'y'");
J 273             $data['new'] = $tmp;
274             $data['old'] = $tmp;
46c683 275             $this->action = 'update';
T 276         }
ac933e 277
46c683 278         // load the server configuration options
fb3339 279         $app->uses('getconf');
J 280         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
ac933e 281
2bbc4c 282         //* Check if this is a chrooted setup
155cc0 283         if($web_config['website_basedir'] != '' && @is_file($web_config['website_basedir'].'/etc/passwd')) {
2bbc4c 284             $apache_chrooted = true;
fb3339 285             $app->log('Info: Apache is chrooted.',LOGLEVEL_DEBUG);
2bbc4c 286         } else {
T 287             $apache_chrooted = false;
288         }
ac933e 289
fb3339 290         if($data['new']['document_root'] == '') {
J 291             $app->log('document_root not set',LOGLEVEL_WARN);
46c683 292             return 0;
T 293         }
fb3339 294         if($data['new']['system_user'] == 'root' or $data['new']['system_group'] == 'root') {
J 295             $app->log('Websites cannot be owned by the root user or group.',LOGLEVEL_WARN);
46c683 296             return 0;
T 297         }
9add99 298         if(trim($data['new']['domain']) == '') {
T 299             $app->log('domain is empty',LOGLEVEL_WARN);
300             return 0;
301         }
dba68f 302         
T 303         // Create group and user, if not exist
304         $app->uses('system');
8d49ef 305         
T 306         if($web_config['connect_userid_to_webid'] == 'y') {
9de299 307             //* Calculate the uid and gid
8d49ef 308             $connect_userid_to_webid_start = ($web_config['connect_userid_to_webid_start'] < 1000)?1000:intval($web_config['connect_userid_to_webid_start']);
T 309             $fixed_uid_gid = intval($connect_userid_to_webid_start + $data['new']['domain_id']);
310             $fixed_uid_param = '--uid '.$fixed_uid_gid;
311             $fixed_gid_param = '--gid '.$fixed_uid_gid;
9de299 312             
T 313             //* Check if a ispconfigend user and group exists and create them
314             if(!$app->system->is_group('ispconfigend')) {
315                 exec('groupadd --gid '.($connect_userid_to_webid_start + 10000).' ispconfigend');
316             }
317             if(!$app->system->is_user('ispconfigend')) {
318                 exec('useradd -g ispconfigend -d /usr/local/ispconfig --uid '.($connect_userid_to_webid_start + 10000).' ispconfigend');
319             }
8d49ef 320         } else {
T 321             $fixed_uid_param = '';
322             $fixed_gid_param = '';
323         }
dba68f 324
T 325         $groupname = escapeshellcmd($data['new']['system_group']);
326         if($data['new']['system_group'] != '' && !$app->system->is_group($data['new']['system_group'])) {
8d49ef 327             exec('groupadd '.$fixed_gid_param.' '.$groupname);
dba68f 328             if($apache_chrooted) $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' groupadd '.$groupname);
T 329             $app->log('Adding the group: '.$groupname,LOGLEVEL_DEBUG);
330         }
331
332         $username = escapeshellcmd($data['new']['system_user']);
333         if($data['new']['system_user'] != '' && !$app->system->is_user($data['new']['system_user'])) {
8d49ef 334             if($web_config['add_web_users_to_sshusers_group'] == 'y') {
T 335                 exec('useradd -d '.escapeshellcmd($data['new']['document_root'])." -g $groupname $fixed_uid_param -G sshusers $username -s /bin/false");
336                 if($apache_chrooted) $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' useradd -d '.escapeshellcmd($data['new']['document_root'])." -g $groupname $fixed_uid_param -G sshusers $username -s /bin/false");
337             } else {
338                 exec('useradd -d '.escapeshellcmd($data['new']['document_root'])." -g $groupname $fixed_uid_param $username -s /bin/false");
339                 if($apache_chrooted) $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' useradd -d '.escapeshellcmd($data['new']['document_root'])." -g $groupname $fixed_uid_param $username -s /bin/false");
340             }
dba68f 341             $app->log('Adding the user: '.$username,LOGLEVEL_DEBUG);
T 342         }
ac933e 343
46c683 344         //* If the client of the site has been changed, we have a change of the document root
fb3339 345         if($this->action == 'update' && $data['new']['document_root'] != $data['old']['document_root']) {
ac933e 346
46c683 347             //* Get the old client ID
fb3339 348             $old_client = $app->dbmaster->queryOneRecord('SELECT client_id FROM sys_group WHERE sys_group.groupid = '.intval($data['old']['sys_groupid']));
J 349             $old_client_id = intval($old_client['client_id']);
46c683 350             unset($old_client);
ac933e 351
46c683 352             //* Remove the old symlinks
fb3339 353             $tmp_symlinks_array = explode(':',$web_config['website_symlinks']);
46c683 354             if(is_array($tmp_symlinks_array)) {
T 355                 foreach($tmp_symlinks_array as $tmp_symlink) {
fb3339 356                     $tmp_symlink = str_replace('[client_id]',$old_client_id,$tmp_symlink);
J 357                     $tmp_symlink = str_replace('[website_domain]',$data['old']['domain'],$tmp_symlink);
46c683 358                     // Remove trailing slash
T 359                     if(substr($tmp_symlink, -1, 1) == '/') $tmp_symlink = substr($tmp_symlink, 0, -1);
360                     // create the symlinks, if not exist
436975 361                     if(is_link($tmp_symlink)) {
fb3339 362                         exec('rm -f '.escapeshellcmd($tmp_symlink));
J 363                         $app->log('Removed symlink: rm -f '.$tmp_symlink,LOGLEVEL_DEBUG);
46c683 364                     }
T 365                 }
366             }
ac933e 367
46c683 368             //* Move the site data
fb3339 369             $tmp_docroot = explode('/',$data['new']['document_root']);
46c683 370             unset($tmp_docroot[count($tmp_docroot)-1]);
T 371             $new_dir = implode('/',$tmp_docroot);
ac933e 372
fb3339 373             $tmp_docroot = explode('/',$data['old']['document_root']);
46c683 374             unset($tmp_docroot[count($tmp_docroot)-1]);
T 375             $old_dir = implode('/',$tmp_docroot);
ac933e 376
0d8022 377             //* Check if there is already some data in the new docroot and rename it as we need a clean path to move the existing site to the new path
T 378             if(@is_dir($data['new']['document_root'])) {
379                 rename($data['new']['document_root'],$data['new']['document_root'].'_bak_'.date('Y_m_d'));
380                 $app->log('Renaming existing directory in new docroot location. mv '.$data['new']['document_root'].' '.$data['new']['document_root'].'_bak_'.date('Y_m_d'),LOGLEVEL_DEBUG);
381             }
382             
383             //* Create new base directory, if it does not exist yet
46c683 384             if(!is_dir($new_dir)) exec('mkdir -p '.$new_dir);
fb3339 385             exec('mv '.$data['old']['document_root'].' '.$new_dir);
J 386             $app->log('Moving site to new document root: mv '.$data['old']['document_root'].' '.$new_dir,LOGLEVEL_DEBUG);
ac933e 387
0930f5 388             // Handle the change in php_open_basedir
L 389             $data['new']['php_open_basedir'] = str_replace($data['old']['document_root'],$data['new']['document_root'],$data['old']['php_open_basedir']);
390
fda480 391             //* Change the owner of the website files to the new website owner
fb3339 392             exec('chown --recursive --from='.escapeshellcmd($data['old']['system_user']).':'.escapeshellcmd($data['old']['system_group']).' '.escapeshellcmd($data['new']['system_user']).':'.escapeshellcmd($data['new']['system_group']).' '.$new_dir);
ac933e 393
46c683 394             //* Change the home directory and group of the website user
T 395             $command = 'usermod';
fb3339 396             $command .= ' --home '.escapeshellcmd($data['new']['document_root']);
46c683 397             $command .= ' --gid '.escapeshellcmd($data['new']['system_group']);
fb3339 398             $command .= ' '.escapeshellcmd($data['new']['system_user']);
46c683 399             exec($command);
ac933e 400
fb3339 401             if($apache_chrooted) $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' '.$command);
ac933e 402
V 403
46c683 404         }
ac933e 405
46c683 406         //print_r($data);
ac933e 407
fb3339 408         // Check if the directories are there and create them if necessary.
J 409         if(!is_dir($data['new']['document_root'].'/web')) exec('mkdir -p '.$data['new']['document_root'].'/web');
410         if(!is_dir($data['new']['document_root'].'/web/error') and $data['new']['errordocs']) exec('mkdir -p '.$data['new']['document_root'].'/web/error');
411         //if(!is_dir($data['new']['document_root'].'/log')) exec('mkdir -p '.$data['new']['document_root'].'/log');
412         if(!is_dir($data['new']['document_root'].'/ssl')) exec('mkdir -p '.$data['new']['document_root'].'/ssl');
413         if(!is_dir($data['new']['document_root'].'/cgi-bin')) exec('mkdir -p '.$data['new']['document_root'].'/cgi-bin');
414         if(!is_dir($data['new']['document_root'].'/tmp')) exec('mkdir -p '.$data['new']['document_root'].'/tmp');
ac933e 415
46c683 416         // Remove the symlink for the site, if site is renamed
fb3339 417         if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
J 418             if(is_dir('/var/log/ispconfig/httpd/'.$data['old']['domain'])) exec('rm -rf /var/log/ispconfig/httpd/'.$data['old']['domain']);
419             if(is_link($data['old']['document_root'].'/log')) unlink($data['old']['document_root'].'/log');
46c683 420         }
ac933e 421
46c683 422         // Create the symlink for the logfiles
fb3339 423         if(!is_dir('/var/log/ispconfig/httpd/'.$data['new']['domain'])) exec('mkdir -p /var/log/ispconfig/httpd/'.$data['new']['domain']);
J 424         if(!is_link($data['new']['document_root'].'/log')) {
552178 425 //            exec("ln -s /var/log/ispconfig/httpd/".$data["new"]["domain"]." ".$data["new"]["document_root"]."/log");
M 426             if ($web_config["website_symlinks_rel"] == 'y') {
427                 $this->create_relative_link("/var/log/ispconfig/httpd/".$data["new"]["domain"], $data["new"]["document_root"]."/log");
428             } else {
429                 exec("ln -s /var/log/ispconfig/httpd/".$data["new"]["domain"]." ".$data["new"]["document_root"]."/log");
430             }
431
fb3339 432             $app->log('Creating symlink: ln -s /var/log/ispconfig/httpd/'.$data['new']['domain'].' '.$data['new']['document_root'].'/log',LOGLEVEL_DEBUG);
46c683 433         }
T 434         /*
435         // Create the symlink for the logfiles
fb3339 436         // This does not work as vlogger cannot log trough symlinks.
J 437         if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
438             if(is_dir($data['old']['document_root'].'/log')) exec('rm -rf '.$data['old']['document_root'].'/log');
439             if(is_link('/var/log/ispconfig/httpd/'.$data['old']['domain'])) unlink('/var/log/ispconfig/httpd/'.$data['old']['domain']);
46c683 440         }
T 441         
442         // Create the symlink for the logfiles
fb3339 443         if(!is_dir($data['new']['document_root'].'/log')) exec('mkdir -p '.$data['new']['document_root'].'/log');
J 444         if(!is_link('/var/log/ispconfig/httpd/'.$data['new']['domain'])) {
445             exec('ln -s '.$data['new']['document_root'].'/log /var/log/ispconfig/httpd/'.$data['new']['domain']);
446             $app->log('Creating symlink: ln -s '.$data['new']['document_root'].'/log /var/log/ispconfig/httpd/'.$data['new']['domain'],LOGLEVEL_DEBUG);
46c683 447         }
T 448         */
ac933e 449
46c683 450         // Get the client ID
fb3339 451         $client = $app->dbmaster->queryOneRecord('SELECT client_id FROM sys_group WHERE sys_group.groupid = '.intval($data['new']['sys_groupid']));
J 452         $client_id = intval($client['client_id']);
46c683 453         unset($client);
ac933e 454
46c683 455         // Remove old symlinks, if site is renamed
fb3339 456         if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
J 457             $tmp_symlinks_array = explode(':',$web_config['website_symlinks']);
46c683 458             if(is_array($tmp_symlinks_array)) {
T 459                 foreach($tmp_symlinks_array as $tmp_symlink) {
fb3339 460                     $tmp_symlink = str_replace('[client_id]',$client_id,$tmp_symlink);
J 461                     $tmp_symlink = str_replace('[website_domain]',$data['old']['domain'],$tmp_symlink);
46c683 462                     // Remove trailing slash
T 463                     if(substr($tmp_symlink, -1, 1) == '/') $tmp_symlink = substr($tmp_symlink, 0, -1);
464                     // remove the symlinks, if not exist
465                     if(is_link($tmp_symlink)) {
fb3339 466                         exec('rm -f '.escapeshellcmd($tmp_symlink));
J 467                         $app->log('Removed symlink: rm -f '.$tmp_symlink,LOGLEVEL_DEBUG);
46c683 468                     }
T 469                 }
470             }
471         }
ac933e 472
46c683 473         // Create the symlinks for the sites
fb3339 474         $tmp_symlinks_array = explode(':',$web_config['website_symlinks']);
46c683 475         if(is_array($tmp_symlinks_array)) {
T 476             foreach($tmp_symlinks_array as $tmp_symlink) {
fb3339 477                 $tmp_symlink = str_replace('[client_id]',$client_id,$tmp_symlink);
J 478                 $tmp_symlink = str_replace('[website_domain]',$data['new']['domain'],$tmp_symlink);
46c683 479                 // Remove trailing slash
T 480                 if(substr($tmp_symlink, -1, 1) == '/') $tmp_symlink = substr($tmp_symlink, 0, -1);
481                 //* Remove symlink if target folder has been changed.
fb3339 482                 if($data['old']['document_root'] != '' && $data['old']['document_root'] != $data['new']['document_root'] && is_link($tmp_symlink)) {
46c683 483                     unlink($tmp_symlink);
T 484                 }
485                 // create the symlinks, if not exist
486                 if(!is_link($tmp_symlink)) {
552178 487 //                    exec("ln -s ".escapeshellcmd($data["new"]["document_root"])."/ ".escapeshellcmd($tmp_symlink));
M 488                     if ($web_config["website_symlinks_rel"] == 'y') {
489                         $this->create_relative_link(escapeshellcmd($data["new"]["document_root"]), escapeshellcmd($tmp_symlink));
490                     } else {
491                         exec("ln -s ".escapeshellcmd($data["new"]["document_root"])."/ ".escapeshellcmd($tmp_symlink));
492                     }
493
fb3339 494                     $app->log('Creating symlink: ln -s '.$data['new']['document_root'].'/ '.$tmp_symlink,LOGLEVEL_DEBUG);
46c683 495                 }
T 496             }
497         }
ac933e 498
V 499
3e41e8 500
L 501         // Install the Standard or Custom Error, Index and other related files
502         // /usr/local/ispconfig/server/conf is for the standard files
503         // /usr/local/ispconfig/server/conf-custom is for the custom files
504         // setting a local var here
505            
506         // normally $conf['templates'] = "/usr/local/ispconfig/server/conf";
507
fb3339 508         if($this->action == 'insert' && $data['new']['type'] == 'vhost') {
46c683 509             // Copy the error pages
fb3339 510             if($data['new']['errordocs']) {
J 511                 $error_page_path = escapeshellcmd($data['new']['document_root']).'/web/error/';
4ffb51 512                 if (file_exists($conf['rootpath'] . '/conf-custom/error/'.substr(escapeshellcmd($conf['language']),0,2))) {
F 513                     exec('cp ' . $conf['rootpath'] . '/conf-custom/error/'.substr(escapeshellcmd($conf['language']),0,2).'/* '.$error_page_path);
46c683 514                 }
T 515                 else {
4ffb51 516                     if (file_exists($conf['rootpath'] . '/conf-custom/error/400.html')) {
F 517                         exec('cp '. $conf['rootpath'] . '/conf-custom/error/*.html '.$error_page_path);
46c683 518                     }
T 519                     else {
4ffb51 520                         exec('cp ' . $conf['rootpath'] . '/conf/error/'.substr(escapeshellcmd($conf['language']),0,2).'/* '.$error_page_path);
46c683 521                     }
T 522                 }
fb3339 523                 exec('chmod -R a+r '.$error_page_path);
46c683 524             }
T 525
4ffb51 526             if (file_exists($conf['rootpath'] . '/conf-custom/index/standard_index.html_'.substr(escapeshellcmd($conf['language']),0,2))) {
F 527                 exec('cp ' . $conf['rootpath'] . '/conf-custom/index/standard_index.html_'.substr(escapeshellcmd($conf['language']),0,2).' '.escapeshellcmd($data['new']['document_root']).'/web/index.html');
3e41e8 528             
4ffb51 529             if(is_file($conf['rootpath'] . '/conf-custom/index/favicon.ico')) {
F 530                 exec('cp ' . $conf['rootpath'] . '/conf-custom/index/favicon.ico '.escapeshellcmd($data['new']['document_root']).'/web/');
3e41e8 531             }
4ffb51 532             if(is_file($conf['rootpath'] . '/conf-custom/index/robots.txt')) {
F 533                 exec('cp ' . $conf['rootpath'] . '/conf-custom/index/robots.txt '.escapeshellcmd($data['new']['document_root']).'/web/');
3e41e8 534                 }
4ffb51 535                 if(is_file($conf['rootpath'] . '/conf-custom/index/.htaccess')) {
F 536                     exec('cp ' . $conf['rootpath'] . '/conf-custom/index/.htaccess '.escapeshellcmd($data['new']['document_root']).'/web/');
3e41e8 537                 }
L 538             }
46c683 539             else {
4ffb51 540                 if (file_exists($conf['rootpath'] . '/conf-custom/index/standard_index.html')) {
F 541                     exec('cp ' . $conf['rootpath'] . '/conf-custom/index/standard_index.html '.escapeshellcmd($data['new']['document_root']).'/web/index.html');
46c683 542                 }
T 543                 else {
4ffb51 544                     exec('cp ' . $conf['rootpath'] . '/conf/index/standard_index.html_'.substr(escapeshellcmd($conf['language']),0,2).' '.escapeshellcmd($data['new']['document_root']).'/web/index.html');
F 545                     if(is_file($conf['rootpath'] . '/conf/index/favicon.ico')) exec('cp ' . $conf['rootpath'] . '/conf/index/favicon.ico '.escapeshellcmd($data['new']['document_root']).'/web/');
546                     if(is_file($conf['rootpath'] . '/conf/index/robots.txt')) exec('cp ' . $conf['rootpath'] . '/conf/index/robots.txt '.escapeshellcmd($data['new']['document_root']).'/web/');
547                     if(is_file($conf['rootpath'] . '/conf/index/.htaccess')) exec('cp ' . $conf['rootpath'] . '/conf/index/.htaccess '.escapeshellcmd($data['new']['document_root']).'/web/');
46c683 548                 }
T 549             }
fb3339 550             exec('chmod -R a+r '.escapeshellcmd($data['new']['document_root']).'/web/');
ac933e 551
V 552             //** Copy the error documents on update when the error document checkbox has been activated and was deactivated before
fb3339 553         } elseif ($this->action == 'update' && $data['new']['type'] == 'vhost' && $data['old']['errordocs'] == 0 && $data['new']['errordocs'] == 1) {
ac933e 554
fb3339 555             $error_page_path = escapeshellcmd($data['new']['document_root']).'/web/error/';
4ffb51 556             if (file_exists($conf['rootpath'] . '/conf-custom/error/'.substr(escapeshellcmd($conf['language']),0,2))) {
F 557                 exec('cp ' . $conf['rootpath'] . '/conf-custom/error/'.substr(escapeshellcmd($conf['language']),0,2).'/* '.$error_page_path);
46c683 558             }
T 559             else {
4ffb51 560                 if (file_exists($conf['rootpath'] . '/conf-custom/error/400.html')) {
F 561                     exec('cp ' . $conf['rootpath'] . '/conf-custom/error/*.html '.$error_page_path);
46c683 562                 }
T 563                 else {
4ffb51 564                     exec('cp ' . $conf['rootpath'] . '/conf/error/'.substr(escapeshellcmd($conf['language']),0,2).'/* '.$error_page_path);
46c683 565                 }
T 566             }
fb3339 567             exec('chmod -R a+r '.$error_page_path);
5d5d88 568             exec('chown -R '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.$error_page_path);
46c683 569         }  // end copy error docs
ac933e 570
46c683 571         // Set the quota for the user
T 572         if($username != '' && $app->system->is_user($username)) {
fb3339 573             if($data['new']['hd_quota'] > 0) {
J 574                 $blocks_soft = $data['new']['hd_quota'] * 1024;
ac933e 575                 $blocks_hard = $blocks_soft + 1024;
V 576             } else {
577                 $blocks_soft = $blocks_hard = 0;
578             }
46c683 579             exec("setquota -u $username $blocks_soft $blocks_hard 0 0 -a &> /dev/null");
fb3339 580             exec('setquota -T -u '.$username.' 604800 604800 -a &> /dev/null');
46c683 581         }
ac933e 582
1ca823 583         if($this->action == 'insert' || $data["new"]["system_user"] != $data["old"]["system_user"]) {
46c683 584             // Chown and chmod the directories below the document root
88273a 585             $this->_exec('chown -R '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root']).'/web');
8db8f3 586             // The document root itself has to be owned by root in normal level and by the web owner in security level 20
T 587             if($web_config['security_level'] == 20) {
88273a 588                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root']).'/web');
8db8f3 589             } else {
88273a 590                 $this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root']).'/web');
8db8f3 591             }
46c683 592         }
ac933e 593
V 594
595
8db8f3 596         //* If the security level is set to high
49a4eb 597         if(($this->action == 'insert' && $data['new']['type'] == 'vhost') or ($web_config['set_folder_permissions_on_update'] == 'y' && $data['new']['type'] == 'vhost')) {
88273a 598             if($web_config['security_level'] == 20) {
ac933e 599
88273a 600                 $this->_exec('chmod 751 '.escapeshellcmd($data['new']['document_root']));
T 601                 $this->_exec('chmod 751 '.escapeshellcmd($data['new']['document_root']).'/*');
602                 $this->_exec('chmod 710 '.escapeshellcmd($data['new']['document_root'].'/web'));
ac933e 603
88273a 604                 // make tmp directory writable for Apache and the website users
T 605                 $this->_exec('chmod 777 '.escapeshellcmd($data['new']['document_root'].'/tmp'));
1ca823 606             
88273a 607                 // Set Log symlink to 755 to make the logs accessible by the FTP user
T 608                 $this->_exec("chmod 755 ".escapeshellcmd($data["new"]["document_root"])."/log");
8d49ef 609                 
T 610                 if($web_config['add_web_users_to_sshusers_group'] == 'y') {
611                     $command = 'usermod';
612                     $command .= ' --groups sshusers';
613                     $command .= ' '.escapeshellcmd($data['new']['system_user']);
614                     $this->_exec($command);
615                 }
ac933e 616
88273a 617                 //* if we have a chrooted Apache environment
T 618                 if($apache_chrooted) {
619                     $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' '.$command);
ac933e 620
88273a 621                     //* add the apache user to the client group in the chroot environment
T 622                     $tmp_groupfile = $app->system->server_conf['group_datei'];
623                     $app->system->server_conf['group_datei'] = $web_config['website_basedir'].'/etc/group';
624                     $app->system->add_user_to_group($groupname, escapeshellcmd($web_config['user']));
625                     $app->system->server_conf['group_datei'] = $tmp_groupfile;
626                     unset($tmp_groupfile);
627                 }
628
629                 //* add the Apache user to the client group
2bbc4c 630                 $app->system->add_user_to_group($groupname, escapeshellcmd($web_config['user']));
49a4eb 631                 
T 632                 //* Chown all default directories
e942cf 633                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root']));
49a4eb 634                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/cgi-bin'));
T 635                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/log'));
636                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/ssl'));
637                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/tmp'));
638                 $this->_exec('chown -R '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/web'));
ac933e 639
88273a 640                 /*
T 641                 * Workaround for jailkit: If jailkit is enabled for the site, the 
642                 * website root has to be owned by the root user and we have to chmod it to 755 then
643                 */
ac933e 644
fa2806 645                 //* Check if there is a jailkit user or cronjob for this site
88273a 646                 $tmp = $app->db->queryOneRecord('SELECT count(shell_user_id) as number FROM shell_user WHERE parent_domain_id = '.$data['new']['domain_id']." AND chroot = 'jailkit'");
fa2806 647                 $tmp2 = $app->db->queryOneRecord('SELECT count(id) as number FROM cron WHERE parent_domain_id = '.$data['new']['domain_id']." AND `type` = 'chrooted'");
T 648                 if($tmp['number'] > 0 || $tmp2['number'] > 0) {
88273a 649                     $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root']));
T 650                     $this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root']));
651                 }
652                 unset($tmp);
ac933e 653
88273a 654                 // If the security Level is set to medium
T 655             } else {
656
fb3339 657                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root']));
e942cf 658                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/cgi-bin'));
T 659                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/log'));
660                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/ssl'));
661                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/web'));
662                 
88273a 663                 // make temp directory writable for Apache and the website users
T 664                 $this->_exec('chmod 777 '.escapeshellcmd($data['new']['document_root'].'/tmp'));
e942cf 665                 
T 666                 $this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root']));
667                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/cgi-bin'));
668                 $this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root'].'/log'));
669                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/tmp'));
670                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/ssl'));
671                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/web'));
8db8f3 672             }
6b029a 673         }
ac933e 674
fb3339 675         // Change the ownership of the error log to the owner of the website
J 676         if(!@is_file($data['new']['document_root'].'/log/error.log')) exec('touch '.escapeshellcmd($data['new']['document_root']).'/log/error.log');
677         $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root']).'/log/error.log');
ac933e 678
V 679
bf356a 680         //* Write the custom php.ini file, if custom_php_ini fieled is not empty
fb3339 681         $custom_php_ini_dir = $web_config['website_basedir'].'/conf/'.$data['new']['system_user'];
7fddfe 682         if(!is_dir($web_config['website_basedir'].'/conf')) mkdir($web_config['website_basedir'].'/conf');
bf356a 683         
T 684         //* add open_basedir restriction to custom php.ini content, required for suphp only
685         if(!stristr($data['new']['custom_php_ini'],'open_basedir') && $data['new']['php'] == 'suphp') {
686             $data['new']['custom_php_ini'] .= "\nopen_basedir = '".$data['new']['php_open_basedir']."'\n";
687         }
688         //* Create custom php.ini
fb3339 689         if(trim($data['new']['custom_php_ini']) != '') {
7fddfe 690             $has_custom_php_ini = true;
T 691             if(!is_dir($custom_php_ini_dir)) mkdir($custom_php_ini_dir);
692             $php_ini_content = '';
fb3339 693             if($data['new']['php'] == 'mod') {
7fddfe 694                 $master_php_ini_path = $web_config['php_ini_path_apache'];
T 695             } else {
9f56bd 696                 if($data["new"]['php'] == 'fast-cgi' && file_exists($fastcgi_config["fastcgi_phpini_path"])) {
T 697                     $master_php_ini_path = $fastcgi_config["fastcgi_phpini_path"];
698                 } else {
699                     $master_php_ini_path = $web_config['php_ini_path_cgi'];
700                 }
7fddfe 701             }
T 702             if($master_php_ini_path != '' && substr($master_php_ini_path,-7) == 'php.ini' && is_file($master_php_ini_path)) {
703                 $php_ini_content .= file_get_contents($master_php_ini_path)."\n";
704             }
8008bb 705             $php_ini_content .= str_replace("\r",'',trim($data['new']['custom_php_ini']));
7fddfe 706             file_put_contents($custom_php_ini_dir.'/php.ini',$php_ini_content);
T 707         } else {
708             $has_custom_php_ini = false;
709             if(is_file($custom_php_ini_dir.'/php.ini')) unlink($custom_php_ini_dir.'/php.ini');
710         }
711
712
713         //* Create the vhost config file
46c683 714         $app->load('tpl');
ac933e 715
46c683 716         $tpl = new tpl();
fb3339 717         $tpl->newTemplate('vhost.conf.master');
ac933e 718
fb3339 719         $vhost_data = $data['new'];
a7bdf8 720         //unset($vhost_data['ip_address']);
fb3339 721         $vhost_data['web_document_root'] = $data['new']['document_root'].'/web';
J 722         $vhost_data['web_document_root_www'] = $web_config['website_basedir'].'/'.$data['new']['domain'].'/web';
723         $vhost_data['web_basedir'] = $web_config['website_basedir'];
724         $vhost_data['security_level'] = $web_config['security_level'];
725         $vhost_data['allow_override'] = ($data['new']['allow_override'] == '')?'All':$data['new']['allow_override'];
726         $vhost_data['php_open_basedir'] = ($data['new']['php_open_basedir'] == '')?$data['new']['document_root']:$data['new']['php_open_basedir'];
727         $vhost_data['ssl_domain'] = $data['new']['ssl_domain'];
728         $vhost_data['has_custom_php_ini'] = $has_custom_php_ini;
729         $vhost_data['custom_php_ini_dir'] = escapeshellcmd($custom_php_ini_dir);
accfe5 730         
F 731         // Custom Apache directives
732         // Make sure we only have Unix linebreaks
733         $vhost_data['apache_directives'] = str_replace("\r\n", "\n", $vhost_data['apache_directives']);
734         $vhost_data['apache_directives'] = str_replace("\r", "\n", $vhost_data['apache_directives']);
ac933e 735
46c683 736         // Check if a SSL cert exists
fb3339 737         $ssl_dir = $data['new']['document_root'].'/ssl';
J 738         $domain = $data['new']['ssl_domain'];
739         $key_file = $ssl_dir.'/'.$domain.'.key';
740         $crt_file = $ssl_dir.'/'.$domain.'.crt';
741         $bundle_file = $ssl_dir.'/'.$domain.'.bundle';
ac933e 742
a7bdf8 743         /*
1a2310 744         if($domain!='' && $data['new']['ssl'] == 'y' && @is_file($crt_file) && @is_file($key_file) && (@filesize($crt_file)>0)  && (@filesize($key_file)>0)) {
fb3339 745             $vhost_data['ssl_enabled'] = 1;
J 746             $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
46c683 747         } else {
fb3339 748             $vhost_data['ssl_enabled'] = 0;
1a2310 749             $app->log('SSL Disabled. '.$domain,LOGLEVEL_DEBUG);
46c683 750         }
a7bdf8 751         */
ac933e 752
46c683 753         if(@is_file($bundle_file)) $vhost_data['has_bundle_cert'] = 1;
ac933e 754
fb3339 755         //$vhost_data['document_root'] = $data['new']['document_root'].'/web';
e64fbb 756         
F 757         // Set SEO Redirect
758         if($data['new']['seo_redirect'] != '' && ($data['new']['subdomain'] == 'www' || $data['new']['subdomain'] == '*')){
759             $vhost_data['seo_redirect_enabled'] = 1;
760             if($data['new']['seo_redirect'] == 'non_www_to_www'){
761                 $vhost_data['seo_redirect_origin_domain'] = $data['new']['domain'];
762                 $vhost_data['seo_redirect_target_domain'] = 'www.'.$data['new']['domain'];
763             }
764             if($data['new']['seo_redirect'] == 'www_to_non_www'){
765                 $vhost_data['seo_redirect_origin_domain'] = 'www.'.$data['new']['domain'];
766                 $vhost_data['seo_redirect_target_domain'] = $data['new']['domain'];
767             }
768         } else {
769             $vhost_data['seo_redirect_enabled'] = 0;
770         }
771         
46c683 772         $tpl->setVar($vhost_data);
ac933e 773
46c683 774         // Rewrite rules
T 775         $rewrite_rules = array();
790cb8 776         if($data['new']['redirect_type'] != '' && $data['new']['redirect_path'] != '') {
fb3339 777             if(substr($data['new']['redirect_path'],-1) != '/') $data['new']['redirect_path'] .= '/';
45ee67 778             if(substr($data['new']['redirect_path'],0,8) == '[scheme]'){
F 779                 $rewrite_target = 'http'.substr($data['new']['redirect_path'],8);
780                 $rewrite_target_ssl = 'https'.substr($data['new']['redirect_path'],8);
781             } else {
782                 $rewrite_target = $data['new']['redirect_path'];
783                 $rewrite_target_ssl = $data['new']['redirect_path'];
784             }
bc2c3e 785             /* Disabled path extension
fb3339 786             if($data['new']['redirect_type'] == 'no' && substr($data['new']['redirect_path'],0,4) != 'http') {
J 787                 $data['new']['redirect_path'] = $data['new']['document_root'].'/web'.realpath($data['new']['redirect_path']).'/';
8388ae 788             }
bc2c3e 789             */
ac933e 790
fb3339 791             switch($data['new']['subdomain']) {
ac933e 792                 case 'www':
e64fbb 793                     $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$data['new']['domain'],
F 794                         'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
795                         'rewrite_target'     => $rewrite_target,
796                         'rewrite_target_ssl' => $rewrite_target_ssl);
797                     $rewrite_rules[] = array(    'rewrite_domain'     => '^www.'.$data['new']['domain'],
fb3339 798                             'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
e64fbb 799                             'rewrite_target'     => $rewrite_target,
F 800                             'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 801                     break;
V 802                 case '*':
876d67 803                     $rewrite_rules[] = array(    'rewrite_domain'     => '(^|\.)'.$data['new']['domain'],
e64fbb 804                         'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
F 805                         'rewrite_target'     => $rewrite_target,
806                         'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 807                     break;
e64fbb 808                 default:
F 809                     $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$data['new']['domain'],
810                         'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
811                         'rewrite_target'     => $rewrite_target,
812                         'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 813             }
46c683 814         }
ac933e 815
46c683 816         // get alias domains (co-domains and subdomains)
fb3339 817         $aliases = $app->db->queryAllRecords('SELECT * FROM web_domain WHERE parent_domain_id = '.$data['new']['domain_id']." AND active = 'y'");
ac933e 818         $server_alias = array();
fb3339 819         switch($data['new']['subdomain']) {
ac933e 820             case 'www':
fb3339 821                 $server_alias[] .= 'www.'.$data['new']['domain'].' ';
ac933e 822                 break;
V 823             case '*':
fb3339 824                 $server_alias[] .= '*.'.$data['new']['domain'].' ';
ac933e 825                 break;
V 826         }
46c683 827         if(is_array($aliases)) {
T 828             foreach($aliases as $alias) {
fb3339 829                 switch($alias['subdomain']) {
ac933e 830                     case 'www':
fb3339 831                         $server_alias[] .= 'www.'.$alias['domain'].' '.$alias['domain'].' ';
ac933e 832                         break;
V 833                     case '*':
fb3339 834                         $server_alias[] .= '*.'.$alias['domain'].' '.$alias['domain'].' ';
ac933e 835                         break;
V 836                     default:
fb3339 837                         $server_alias[] .= $alias['domain'].' ';
ac933e 838                         break;
V 839                 }
fb3339 840                 $app->log('Add server alias: '.$alias['domain'],LOGLEVEL_DEBUG);
46c683 841                 // Rewriting
790cb8 842                 if($alias['redirect_type'] != '' && $alias['redirect_path'] != '') {
e64fbb 843                     if(substr($alias['redirect_path'],-1) != '/') $alias['redirect_path'] .= '/';
F 844                     if(substr($alias['redirect_path'],0,8) == '[scheme]'){
845                         $rewrite_target = 'http'.substr($alias['redirect_path'],8);
846                         $rewrite_target_ssl = 'https'.substr($alias['redirect_path'],8);
847                     } else {
848                         $rewrite_target = $alias['redirect_path'];
849                         $rewrite_target_ssl = $alias['redirect_path'];
850                     }
bc2c3e 851                     /* Disabled the path extension
fb3339 852                     if($data['new']['redirect_type'] == 'no' && substr($data['new']['redirect_path'],0,4) != 'http') {
J 853                         $data['new']['redirect_path'] = $data['new']['document_root'].'/web'.realpath($data['new']['redirect_path']).'/';
8388ae 854                     }
bc2c3e 855                     */
e64fbb 856                     
fb3339 857                     switch($alias['subdomain']) {
ac933e 858                         case 'www':
e64fbb 859                             $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$alias['domain'],
F 860                                 'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
861                                 'rewrite_target'     => $rewrite_target,
862                                 'rewrite_target_ssl' => $rewrite_target_ssl);
863                             $rewrite_rules[] = array(    'rewrite_domain'     => '^www.'.$alias['domain'],
fb3339 864                                     'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
e64fbb 865                                     'rewrite_target'     => $rewrite_target,
F 866                                     'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 867                             break;
V 868                         case '*':
876d67 869                             $rewrite_rules[] = array(    'rewrite_domain'     => '(^|\.)'.$alias['domain'],
e64fbb 870                                 'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
F 871                                 'rewrite_target'     => $rewrite_target,
872                                 'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 873                             break;
e64fbb 874                         default:
F 875                             $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$alias['domain'],
876                                 'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
877                                 'rewrite_target'     => $rewrite_target,
878                                 'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 879                     }
46c683 880                 }
T 881             }
882         }
ac933e 883
47cca9 884         //* If we have some alias records
T 885         if(count($server_alias) > 0) {
886             $server_alias_str = '';
887             $n = 0;
ac933e 888
47cca9 889             // begin a new ServerAlias line after 30 alias domains
T 890             foreach($server_alias as $tmp_alias) {
891                 if($n % 30 == 0) $server_alias_str .= "\n    ServerAlias ";
892                 $server_alias_str .= $tmp_alias;
893             }
894             unset($tmp_alias);
ac933e 895
47cca9 896             $tpl->setVar('alias',trim($server_alias_str));
T 897         } else {
898             $tpl->setVar('alias','');
899         }
ac933e 900
af4864 901         if(count($rewrite_rules) > 0 || $vhost_data['seo_redirect_enabled'] > 0) {
46c683 902             $tpl->setVar('rewrite_enabled',1);
T 903         } else {
904             $tpl->setVar('rewrite_enabled',0);
905         }
af4864 906
F 907         //$tpl->setLoop('redirects',$rewrite_rules);
ac933e 908
V 909         /**
910          * install fast-cgi starter script and add script aliasd config
46c683 911          * first we create the script directory if not already created, then copy over the starter script
T 912          * settings are copied over from the server ini config for now
913          * TODO: Create form for fastcgi configs per site.
914          */
ac933e 915
fb3339 916         if ($data['new']['php'] == 'fast-cgi') {
J 917             $fastcgi_config = $app->getconf->get_server_config($conf['server_id'], 'fastcgi');
ac933e 918
fb3339 919             $fastcgi_starter_path = str_replace('[system_user]',$data['new']['system_user'],$fastcgi_config['fastcgi_starter_path']);
J 920             $fastcgi_starter_path = str_replace('[client_id]',$client_id,$fastcgi_starter_path);
ac933e 921
V 922             if (!is_dir($fastcgi_starter_path)) {
fb3339 923                 exec('mkdir -p '.escapeshellcmd($fastcgi_starter_path));
J 924                 //exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.escapeshellcmd($fastcgi_starter_path));
ac933e 925
V 926
fb3339 927                 $app->log('Creating fastcgi starter script directory: '.$fastcgi_starter_path,LOGLEVEL_DEBUG);
46c683 928             }
ac933e 929
fb3339 930             exec('chown -R '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.escapeshellcmd($fastcgi_starter_path));
ac933e 931
46c683 932             $fcgi_tpl = new tpl();
fb3339 933             $fcgi_tpl->newTemplate('php-fcgi-starter.master');
7fddfe 934             
T 935             if($has_custom_php_ini) {
936                 $fcgi_tpl->setVar('php_ini_path',escapeshellcmd($custom_php_ini_dir));
937             } else {
fb3339 938                 $fcgi_tpl->setVar('php_ini_path',escapeshellcmd($fastcgi_config['fastcgi_phpini_path']));
7fddfe 939             }
fb3339 940             $fcgi_tpl->setVar('document_root',escapeshellcmd($data['new']['document_root']));
J 941             $fcgi_tpl->setVar('php_fcgi_children',escapeshellcmd($fastcgi_config['fastcgi_children']));
942             $fcgi_tpl->setVar('php_fcgi_max_requests',escapeshellcmd($fastcgi_config['fastcgi_max_requests']));
943             $fcgi_tpl->setVar('php_fcgi_bin',escapeshellcmd($fastcgi_config['fastcgi_bin']));
944             $fcgi_tpl->setVar('security_level',intval($web_config['security_level']));
ac933e 945
fb3339 946             $php_open_basedir = ($data['new']['php_open_basedir'] == '')?$data['new']['document_root']:$data['new']['php_open_basedir'];
ff7075 947             $fcgi_tpl->setVar('open_basedir', escapeshellcmd($php_open_basedir));
ac933e 948
fb3339 949             $fcgi_starter_script = escapeshellcmd($fastcgi_starter_path.$fastcgi_config['fastcgi_starter_script']);
46c683 950             file_put_contents($fcgi_starter_script,$fcgi_tpl->grab());
T 951             unset($fcgi_tpl);
ac933e 952
fb3339 953             $app->log('Creating fastcgi starter script: '.$fcgi_starter_script,LOGLEVEL_DEBUG);
ac933e 954
V 955
fb3339 956             exec('chmod 755 '.$fcgi_starter_script);
J 957             exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.$fcgi_starter_script);
46c683 958
fb3339 959             $tpl->setVar('fastcgi_alias',$fastcgi_config['fastcgi_alias']);
46c683 960             $tpl->setVar('fastcgi_starter_path',$fastcgi_starter_path);
fb3339 961             $tpl->setVar('fastcgi_starter_script',$fastcgi_config['fastcgi_starter_script']);
824780 962             $tpl->setVar('fastcgi_config_syntax',$fastcgi_config['fastcgi_config_syntax']);
ac933e 963
46c683 964         }
ac933e 965
46c683 966         /**
T 967          * install cgi starter script and add script alias to config.
968          * This is needed to allow cgi with suexec (to do so, we need a bin in the document-path!)
969          * first we create the script directory if not already created, then copy over the starter script.
970          * TODO: we have to fetch the data from the server-settings.
971          */
972
fb3339 973         if ($data['new']['php'] == 'cgi') {
J 974             //$cgi_config = $app->getconf->get_server_config($conf['server_id'], 'cgi');
46c683 975
fb3339 976             $cgi_config['cgi_starter_path'] = $web_config['website_basedir'].'/php-cgi-scripts/[system_user]/';
J 977             $cgi_config['cgi_starter_script'] = 'php-cgi-starter';
978             $cgi_config['cgi_bin'] = '/usr/bin/php-cgi';
46c683 979
fb3339 980             $cgi_starter_path = str_replace('[system_user]',$data['new']['system_user'],$cgi_config['cgi_starter_path']);
J 981             $cgi_starter_path = str_replace('[client_id]',$client_id,$cgi_starter_path);
46c683 982
ac933e 983             if (!is_dir($cgi_starter_path)) {
fb3339 984                 exec('mkdir -p '.escapeshellcmd($cgi_starter_path));
J 985                 exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.escapeshellcmd($cgi_starter_path));
46c683 986
fb3339 987                 $app->log('Creating cgi starter script directory: '.$cgi_starter_path,LOGLEVEL_DEBUG);
46c683 988             }
T 989
990             $cgi_tpl = new tpl();
fb3339 991             $cgi_tpl->newTemplate('php-cgi-starter.master');
46c683 992
fb3339 993             // This works because PHP "rewrites" a symlink to the physical path
J 994             $php_open_basedir = ($data['new']['php_open_basedir'] == '')?$data['new']['document_root']:$data['new']['php_open_basedir'];
ac933e 995             $cgi_tpl->setVar('open_basedir', escapeshellcmd($php_open_basedir));
fb3339 996             $cgi_tpl->setVar('document_root', escapeshellcmd($data['new']['document_root']));
ac933e 997
46c683 998             // This will NOT work!
fb3339 999             //$cgi_tpl->setVar('open_basedir', '/var/www/' . $data['new']['domain']);
J 1000             $cgi_tpl->setVar('php_cgi_bin',$cgi_config['cgi_bin']);
1001             $cgi_tpl->setVar('security_level',$web_config['security_level']);
7fddfe 1002             
T 1003             $cgi_tpl->setVar('has_custom_php_ini',$has_custom_php_ini);
1004             if($has_custom_php_ini) {
1005                 $cgi_tpl->setVar('php_ini_path',escapeshellcmd($custom_php_ini_dir));
1006             } else {
fb3339 1007                 $cgi_tpl->setVar('php_ini_path',escapeshellcmd($fastcgi_config['fastcgi_phpini_path']));
7fddfe 1008             }
46c683 1009
fb3339 1010             $cgi_starter_script = escapeshellcmd($cgi_starter_path.$cgi_config['cgi_starter_script']);
46c683 1011             file_put_contents($cgi_starter_script,$cgi_tpl->grab());
T 1012             unset($cgi_tpl);
1013
fb3339 1014             $app->log('Creating cgi starter script: '.$cgi_starter_script,LOGLEVEL_DEBUG);
46c683 1015
T 1016
fb3339 1017             exec('chmod 755 '.$cgi_starter_script);
J 1018             exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.$cgi_starter_script);
46c683 1019
T 1020             $tpl->setVar('cgi_starter_path',$cgi_starter_path);
fb3339 1021             $tpl->setVar('cgi_starter_script',$cgi_config['cgi_starter_script']);
46c683 1022
T 1023         }
1024
fb3339 1025         $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/'.$data['new']['domain'].'.vhost');
7ed741 1026         //* Make a backup copy of vhost file
083dc0 1027         if(file_exists($vhost_file)) copy($vhost_file,$vhost_file.'~');
7ed741 1028         
a7bdf8 1029         //* create empty vhost array
T 1030         $vhosts = array();
1031         
af4864 1032         //* Add vhost for ipv4 IP    
F 1033         if(count($rewrite_rules) > 0){
1034             $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 0, 'port' => 80, 'redirects' => $rewrite_rules);
1035         } else {
1036             $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 0, 'port' => 80);
1037         }
a7bdf8 1038         
T 1039         //* Add vhost for ipv4 IP with SSL
1040         if($data['new']['ssl_domain'] != '' && $data['new']['ssl'] == 'y' && @is_file($crt_file) && @is_file($key_file) && (@filesize($crt_file)>0)  && (@filesize($key_file)>0)) {
af4864 1041             if(count($rewrite_rules) > 0){
F 1042                 $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 1, 'port' => '443', 'redirects' => $rewrite_rules);
1043             } else {
1044                 $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 1, 'port' => '443');
1045             }
a7bdf8 1046             $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
T 1047         }
1048         
1049         //* Add vhost for IPv6 IP
1050         if($data['new']['ipv6_address'] != '') {
af4864 1051             if(count($rewrite_rules) > 0){
F 1052                 $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80, 'redirects' => $rewrite_rules);
1053             } else {
1054                 $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80);
1055             }
a7bdf8 1056         
T 1057             //* Add vhost for ipv6 IP with SSL
1058             if($data['new']['ssl_domain'] != '' && $data['new']['ssl'] == 'y' && @is_file($crt_file) && @is_file($key_file) && (@filesize($crt_file)>0)  && (@filesize($key_file)>0)) {
af4864 1059                 
F 1060                 if(count($rewrite_rules) > 0){
1061                     $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 1, 'port' => '443', 'redirects' => $rewrite_rules);
1062                 } else {
1063                     $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 1, 'port' => '443');
1064                 }
a7bdf8 1065                 $app->log('Enable SSL for IPv6: '.$domain,LOGLEVEL_DEBUG);
T 1066             }
1067         }
1068         
1069         //* Set the vhost loop
1070         $tpl->setLoop('vhosts',$vhosts);
1071         
7ed741 1072         //* Write vhost file
46c683 1073         file_put_contents($vhost_file,$tpl->grab());
fb3339 1074         $app->log('Writing the vhost file: '.$vhost_file,LOGLEVEL_DEBUG);
46c683 1075         unset($tpl);
ac933e 1076
V 1077         /*
1078          * maybe we have some webdav - user. If so, add them...
1079         */
fb3339 1080         $this->_patchVhostWebdav($vhost_file, $data['new']['document_root'] . '/webdav');
ac933e 1081
c6a89c 1082         //* Set the symlink to enable the vhost
T 1083         //* First we check if there is a old type of symlink and remove it
fb3339 1084         $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/'.$data['new']['domain'].'.vhost');
c6a89c 1085         if(is_link($vhost_symlink)) unlink($vhost_symlink);
T 1086         
1087         //* Remove old or changed symlinks
1088         if($data['new']['subdomain'] != $data['old']['subdomain'] or $data['new']['active'] == 'n') {
1089             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['new']['domain'].'.vhost');
1090             if(is_link($vhost_symlink)) {
1091                 unlink($vhost_symlink);
1092                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1093             }
1094             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['new']['domain'].'.vhost');
1095             if(is_link($vhost_symlink)) {
1096                 unlink($vhost_symlink);
1097                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1098             }
1099         }
1100         
1101         //* New symlink
1102         if($data['new']['subdomain'] == '*') {
1103             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['new']['domain'].'.vhost');
1104         } else {
1105             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['new']['domain'].'.vhost');
1106         }
fb3339 1107         if($data['new']['active'] == 'y' && !is_link($vhost_symlink)) {
46c683 1108             symlink($vhost_file,$vhost_symlink);
fb3339 1109             $app->log('Creating symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
46c683 1110         }
ac933e 1111
46c683 1112         // remove old symlink and vhost file, if domain name of the site has changed
fb3339 1113         if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
c6a89c 1114             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['old']['domain'].'.vhost');
T 1115             if(is_link($vhost_symlink)) {
1116                 unlink($vhost_symlink);
1117                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1118             }
1119             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['old']['domain'].'.vhost');
1120             if(is_link($vhost_symlink)) {
1121                 unlink($vhost_symlink);
1122                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1123             }
276324 1124             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/'.$data['old']['domain'].'.vhost');
T 1125             if(is_link($vhost_symlink)) {
1126                 unlink($vhost_symlink);
1127                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1128             }
fb3339 1129             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/'.$data['old']['domain'].'.vhost');
46c683 1130             unlink($vhost_file);
fb3339 1131             $app->log('Removing file: '.$vhost_file,LOGLEVEL_DEBUG);
46c683 1132         }
ac933e 1133
46c683 1134         //* Create .htaccess and .htpasswd file for website statistics
fb3339 1135         if(!is_file($data['new']['document_root'].'/web/stats/.htaccess') or $data['old']['document_root'] != $data['new']['document_root']) {
J 1136             if(!is_dir($data['new']['document_root'].'/web/stats')) mkdir($data['new']['document_root'].'/web/stats');
1137             $ht_file = "AuthType Basic\nAuthName \"Members Only\"\nAuthUserFile ".$data['new']['document_root']."/.htpasswd_stats\nrequire valid-user";
1138             file_put_contents($data['new']['document_root'].'/web/stats/.htaccess',$ht_file);
1139             chmod($data['new']['document_root'].'/web/stats/.htaccess',0755);
46c683 1140             unset($ht_file);
T 1141         }
ac933e 1142
fb3339 1143         if(!is_file($data['new']['document_root'].'/.htpasswd_stats') || $data['new']['stats_password'] != $data['old']['stats_password']) {
J 1144             if(trim($data['new']['stats_password']) != '') {
1145                 $htp_file = 'admin:'.trim($data['new']['stats_password']);
1146                 file_put_contents($data['new']['document_root'].'/.htpasswd_stats',$htp_file);
1147                 chmod($data['new']['document_root'].'/.htpasswd_stats',0755);
46c683 1148                 unset($htp_file);
T 1149             }
1150         }
58c210 1151         
T 1152         //* Create awstats configuration
fb3339 1153         if($data['new']['stats_type'] == 'awstats' && $data['new']['type'] == 'vhost') {
58c210 1154             $this->awstats_update($data,$web_config);
T 1155         }
7ed741 1156         
T 1157         if($web_config['check_apache_config'] == 'y') {
1158             //* Test if apache starts with the new configuration file
1159             $apache_online_status_before_restart = $this->_checkTcp('localhost',80);
fb3339 1160             $app->log('Apache status is: '.$apache_online_status_before_restart,LOGLEVEL_DEBUG);
ac933e 1161
7ed741 1162             $app->services->restartService('httpd','restart');
9f56bd 1163             
T 1164             // wait a few seconds, before we test the apache status again
1165             sleep(2);
7ed741 1166         
T 1167             //* Check if apache restarted successfully if it was online before
1168             $apache_online_status_after_restart = $this->_checkTcp('localhost',80);
fb3339 1169             $app->log('Apache online status after restart is: '.$apache_online_status_after_restart,LOGLEVEL_DEBUG);
7ed741 1170             if($apache_online_status_before_restart && !$apache_online_status_after_restart) {
fb3339 1171                 $app->log('Apache did not restart after the configuration change for website '.$data['new']['domain'].' Reverting the configuration. Saved non-working config as '.$vhost_file.'.err',LOGLEVEL_WARN);
7ed741 1172                 copy($vhost_file,$vhost_file.'.err');
84710d 1173                 if(is_file($vhost_file.'~')) {
T 1174                     //* Copy back the last backup file
1175                     copy($vhost_file.'~',$vhost_file);
1176                 } else {
1177                     //* There is no backup file, so we create a empty vhost file with a warning message inside
1178                     file_put_contents($vhost_file,"# Apache did not start after modifying this vhost file.\n# Please check file $vhost_file.err for syntax errors.");
1179                 }
7ed741 1180                 $app->services->restartService('httpd','restart');
T 1181             }
c82dc7 1182         } else {
7ed741 1183             //* We do not check the apache config after changes (is faster)
T 1184             if($apache_chrooted) {
1185                 $app->services->restartServiceDelayed('httpd','restart');
1186             } else {
1187                 // request a httpd reload when all records have been processed
1188                 $app->services->restartServiceDelayed('httpd','reload');
1189             }
c82dc7 1190         }
7ed741 1191         
T 1192         // Remove the backup copy of the config file.
9f56bd 1193         if(@is_file($vhost_file.'~')) unlink($vhost_file.'~');
7ed741 1194         
ac933e 1195
da1a7c 1196         //* Unset action to clean it for next processed vhost.
T 1197         $this->action = '';
ac933e 1198
46c683 1199     }
ac933e 1200
46c683 1201     function delete($event_name,$data) {
T 1202         global $app, $conf;
ac933e 1203
46c683 1204         // load the server configuration options
fb3339 1205         $app->uses('getconf');
J 1206         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
ac933e 1207
2bbc4c 1208         //* Check if this is a chrooted setup
4b72c5 1209         if($web_config['website_basedir'] != '' && @is_file($web_config['website_basedir'].'/etc/passwd')) {
2bbc4c 1210             $apache_chrooted = true;
T 1211         } else {
1212             $apache_chrooted = false;
1213         }
ac933e 1214
fb3339 1215         if($data['old']['type'] != 'vhost' && $data['old']['parent_domain_id'] > 0) {
46c683 1216             //* This is a alias domain or subdomain, so we have to update the website instead
fb3339 1217             $parent_domain_id = intval($data['old']['parent_domain_id']);
J 1218             $tmp = $app->db->queryOneRecord('SELECT * FROM web_domain WHERE domain_id = '.$parent_domain_id." AND active = 'y'");
1219             $data['new'] = $tmp;
1220             $data['old'] = $tmp;
46c683 1221             $this->action = 'update';
T 1222             // just run the update function
1223             $this->update($event_name,$data);
ac933e 1224
46c683 1225         } else {
T 1226             //* This is a website
1227             // Deleting the vhost file, symlink and the data directory
fb3339 1228             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/'.$data['old']['domain'].'.vhost');
f3b669 1229             
F 1230             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/'.$data['old']['domain'].'.vhost');
1231             if(is_link($vhost_symlink)){
1232                 unlink($vhost_symlink);
1233                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1234             }
1235             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['old']['domain'].'.vhost');
1236             if(is_link($vhost_symlink)){
1237                 unlink($vhost_symlink);
1238                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1239             }
1240             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['old']['domain'].'.vhost');
1241             if(is_link($vhost_symlink)){
1242                 unlink($vhost_symlink);
1243                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1244             }
1245             
46c683 1246             unlink($vhost_file);
fb3339 1247             $app->log('Removing vhost file: '.$vhost_file,LOGLEVEL_DEBUG);
ac933e 1248
fb3339 1249             $docroot = escapeshellcmd($data['old']['document_root']);
J 1250             if($docroot != '' && !stristr($docroot,'..')) exec('rm -rf '.$docroot);
ac933e 1251
V 1252
46c683 1253             //remove the php fastgi starter script if available
fb3339 1254             if ($data['old']['php'] == 'fast-cgi') {
J 1255                 $fastcgi_starter_path = str_replace('[system_user]',$data['old']['system_user'],$web_config['fastcgi_starter_path']);
ac933e 1256                 if (is_dir($fastcgi_starter_path)) {
fb3339 1257                     exec('rm -rf '.$fastcgi_starter_path);
46c683 1258                 }
T 1259             }
ac933e 1260
46c683 1261             //remove the php cgi starter script if available
fb3339 1262             if ($data['old']['php'] == 'cgi') {
46c683 1263                 // TODO: fetch the date from the server-settings
fb3339 1264                 $web_config['cgi_starter_path'] = $web_config['website_basedir'].'/php-cgi-scripts/[system_user]/';
46c683 1265
fb3339 1266                 $cgi_starter_path = str_replace('[system_user]',$data['old']['system_user'],$web_config['cgi_starter_path']);
ac933e 1267                 if (is_dir($cgi_starter_path)) {
fb3339 1268                     exec('rm -rf '.$cgi_starter_path);
46c683 1269                 }
T 1270             }
1271
fb3339 1272             $app->log('Removing website: '.$docroot,LOGLEVEL_DEBUG);
ac933e 1273
46c683 1274             // Delete the symlinks for the sites
fb3339 1275             $client = $app->db->queryOneRecord('SELECT client_id FROM sys_group WHERE sys_group.groupid = '.intval($data['old']['sys_groupid']));
J 1276             $client_id = intval($client['client_id']);
46c683 1277             unset($client);
fb3339 1278             $tmp_symlinks_array = explode(':',$web_config['website_symlinks']);
46c683 1279             if(is_array($tmp_symlinks_array)) {
T 1280                 foreach($tmp_symlinks_array as $tmp_symlink) {
fb3339 1281                     $tmp_symlink = str_replace('[client_id]',$client_id,$tmp_symlink);
J 1282                     $tmp_symlink = str_replace('[website_domain]',$data['old']['domain'],$tmp_symlink);
46c683 1283                     // Remove trailing slash
T 1284                     if(substr($tmp_symlink, -1, 1) == '/') $tmp_symlink = substr($tmp_symlink, 0, -1);
1285                     // create the symlinks, if not exist
1286                     if(is_link($tmp_symlink)) {
1287                         unlink($tmp_symlink);
fb3339 1288                         $app->log('Removing symlink: '.$tmp_symlink,LOGLEVEL_DEBUG);
46c683 1289                     }
T 1290                 }
1291             }
1292             // end removing symlinks
ac933e 1293
46c683 1294             // Delete the log file directory
fb3339 1295             $vhost_logfile_dir = escapeshellcmd('/var/log/ispconfig/httpd/'.$data['old']['domain']);
J 1296             if($data['old']['domain'] != '' && !stristr($vhost_logfile_dir,'..')) exec('rm -rf '.$vhost_logfile_dir);
1297             $app->log('Removing website logfile directory: '.$vhost_logfile_dir,LOGLEVEL_DEBUG);
ac933e 1298
46c683 1299             //delete the web user
T 1300             $command = 'userdel';
fb3339 1301             $command .= ' '.$data['old']['system_user'];
46c683 1302             exec($command);
fb3339 1303             if($apache_chrooted) $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' '.$command);
58c210 1304             
T 1305             //* Remove the awstats configuration file
fb3339 1306             if($data['old']['stats_type'] == 'awstats') {
58c210 1307                 $this->awstats_delete($data,$web_config);
T 1308             }
f3b669 1309             
F 1310             if($apache_chrooted) {
1311                 $app->services->restartServiceDelayed('httpd','restart');
1312             } else {
1313                 // request a httpd reload when all records have been processed
1314                 $app->services->restartServiceDelayed('httpd','reload');
1315             }
ac933e 1316
46c683 1317         }
T 1318     }
ac933e 1319
46c683 1320     //* This function is called when a IP on the server is inserted, updated or deleted
T 1321     function server_ip($event_name,$data) {
1322         global $app, $conf;
ac933e 1323
46c683 1324         // load the server configuration options
fb3339 1325         $app->uses('getconf');
J 1326         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
ac933e 1327
46c683 1328         $app->load('tpl');
ac933e 1329
46c683 1330         $tpl = new tpl();
fb3339 1331         $tpl->newTemplate('apache_ispconfig.conf.master');
J 1332         $records = $app->db->queryAllRecords('SELECT * FROM server_ip WHERE server_id = '.$conf['server_id']." AND virtualhost = 'y'");
a2156e 1333         
T 1334         $records_out= array();
1335         if(is_array($records)) {
1336             foreach($records as $rec) {
1337                 if($rec['ip_type'] == 'IPv6') {
1338                     $ip_address = '['.$rec['ip_address'].']';
1339                 } else {
1340                     $ip_address = $rec['ip_address'];
1341                 }
1342                 $ports = explode(',',$rec['virtualhost_port']);
1343                 if(is_array($ports)) {
1344                     foreach($ports as $port) {
1345                         $port = intval($port);
1346                         if($port > 0 && $port < 65536 && $ip_address != '') {
1347                             $records_out[] = array('ip_address' => $ip_address, 'port' => $port);
1348                         }
1349                     }
1350                 }
1351             }
1352         }
1353         
1354         
1355         if(count($records_out) > 0) {
1356             $tpl->setLoop('ip_adresses',$records_out);
46c683 1357         }
ac933e 1358
fb3339 1359         $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/ispconfig.conf');
46c683 1360         file_put_contents($vhost_file,$tpl->grab());
fb3339 1361         $app->log('Writing the conf file: '.$vhost_file,LOGLEVEL_DEBUG);
46c683 1362         unset($tpl);
ac933e 1363
46c683 1364     }
524077 1365     
T 1366     //* Create or update the .htaccess folder protection
1367     function web_folder_user($event_name,$data) {
1368         global $app, $conf;
c69439 1369
524077 1370         $app->uses('system');
T 1371         
1372         if($event_name == 'web_folder_user_delete') {
1373             $folder_id = $data['old']['web_folder_id'];
1374         } else {
1375             $folder_id = $data['new']['web_folder_id'];
1376         }
1377         
1378         $folder = $app->db->queryOneRecord("SELECT * FROM web_folder WHERE web_folder_id = ".intval($folder_id));
1379         $website = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".intval($folder['parent_domain_id']));
1380         
1381         if(!is_array($folder) or !is_array($website)) {
1382             $app->log('Not able to retrieve folder or website record.',LOGLEVEL_DEBUG);
1383             return false;
1384         }
1385         
1386         //* Get the folder path.
c69439 1387         if(substr($folder['path'],0,1) == '/') $folder['path'] = substr($folder['path'],1);
T 1388         if(substr($folder['path'],-1) == '/') $folder['path'] = substr($folder['path'],0,-1);
1389         $folder_path = escapeshellcmd($website['document_root'].'/web/'.$folder['path']);
8f08b5 1390         if(substr($folder_path,-1) != '/') $folder_path .= '/';
524077 1391         
T 1392         //* Check if the resulting path is inside the docroot
c69439 1393         if(stristr($folder_path,'..') || stristr($folder_path,'./') || stristr($folder_path,'\\')) {
T 1394             $app->log('Folder path "'.$folder_path.'" contains .. or ./.',LOGLEVEL_DEBUG);
524077 1395             return false;
T 1396         }
1397         
1398         //* Create the folder path, if it does not exist
053547 1399         if(!is_dir($folder_path)) {
T 1400             exec('mkdir -p '.$folder_path);
1401             chown($folder_path,$website['system_user']);
1402             chgrp($folder_path,$website['system_group']);
1403         }
524077 1404         
T 1405         //* Create empty .htpasswd file, if it does not exist
1406         if(!is_file($folder_path.'.htpasswd')) {
1407             touch($folder_path.'.htpasswd');
1408             chmod($folder_path.'.htpasswd',0755);
053547 1409             chown($folder_path.'.htpasswd',$website['system_user']);
T 1410             chgrp($folder_path.'.htpasswd',$website['system_group']);
900a38 1411             $app->log('Created file '.$folder_path.'.htpasswd',LOGLEVEL_DEBUG);
524077 1412         }
T 1413         
0ea045 1414         /*
F 1415         $auth_users = $app->db->queryAllRecords("SELECT * FROM web_folder_user WHERE active = 'y' AND web_folder_id = ".intval($folder_id));
1416         $htpasswd_content = '';
1417         if(is_array($auth_users) && !empty($auth_users)){
1418             foreach($auth_users as $auth_user){
1419                 $htpasswd_content .= $auth_user['username'].':'.$auth_user['password']."\n";
1420             }
1421         }
1422         $htpasswd_content = trim($htpasswd_content);
1423         @file_put_contents($folder_path.'.htpasswd', $htpasswd_content);
1424         $app->log('Changed .htpasswd file: '.$folder_path.'.htpasswd',LOGLEVEL_DEBUG);
1425         */
1426         
1427         if(($data['new']['username'] != $data['old']['username'] || $data['new']['active'] == 'n') && $data['old']['username'] != '') {
c69439 1428             $app->system->removeLine($folder_path.'.htpasswd',$data['old']['username'].':');
T 1429             $app->log('Removed user: '.$data['old']['username'],LOGLEVEL_DEBUG);
1430         }
1431         
524077 1432         //* Add or remove the user from .htpasswd file
T 1433         if($event_name == 'web_folder_user_delete') {
c69439 1434             $app->system->removeLine($folder_path.'.htpasswd',$data['old']['username'].':');
T 1435             $app->log('Removed user: '.$data['old']['username'],LOGLEVEL_DEBUG);
524077 1436         } else {
c69439 1437             if($data['new']['active'] == 'y') {
T 1438                 $app->system->replaceLine($folder_path.'.htpasswd',$data['new']['username'].':',$data['new']['username'].':'.$data['new']['password'],0,1);
1439                 $app->log('Added or updated user: '.$data['new']['username'],LOGLEVEL_DEBUG);
1440             }
524077 1441         }
T 1442         
0ea045 1443         
524077 1444         //* Create the .htaccess file
0ea045 1445         //if(!is_file($folder_path.'.htaccess')) {
524077 1446             $ht_file = "AuthType Basic\nAuthName \"Members Only\"\nAuthUserFile ".$folder_path.".htpasswd\nrequire valid-user";
T 1447             file_put_contents($folder_path.'.htaccess',$ht_file);
053547 1448             chmod($folder_path.'.htaccess',0755);
T 1449             chown($folder_path.'.htaccess',$website['system_user']);
1450             chgrp($folder_path.'.htaccess',$website['system_group']);
900a38 1451             $app->log('Created file '.$folder_path.'.htaccess',LOGLEVEL_DEBUG);
0ea045 1452         //}
524077 1453         
T 1454     }
1455     
1456     //* Remove .htaccess and .htpasswd file, when folder protection is removed
1457     function web_folder_delete($event_name,$data) {
1458         global $app, $conf;
1459         
1460         $folder_id = $data['old']['web_folder_id'];
1461         
219bb4 1462         $folder = $data['old'];
524077 1463         $website = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".intval($folder['parent_domain_id']));
T 1464         
1465         if(!is_array($folder) or !is_array($website)) {
1466             $app->log('Not able to retrieve folder or website record.',LOGLEVEL_DEBUG);
1467             return false;
1468         }
1469         
1470         //* Get the folder path.
0ea045 1471         if(substr($folder['path'],0,1) == '/') $folder['path'] = substr($folder['path'],1);
F 1472         if(substr($folder['path'],-1) == '/') $folder['path'] = substr($folder['path'],0,-1);
524077 1473         $folder_path = realpath($website['document_root'].'/web/'.$folder['path']);
8f08b5 1474         if(substr($folder_path,-1) != '/') $folder_path .= '/';
524077 1475         
T 1476         //* Check if the resulting path is inside the docroot
1477         if(substr($folder_path,0,strlen($website['document_root'])) != $website['document_root']) {
1478             $app->log('Folder path is outside of docroot.',LOGLEVEL_DEBUG);
1479             return false;
1480         }
1481         
1482         //* Remove .htpasswd file
1483         if(is_file($folder_path.'.htpasswd')) {
1484             unlink($folder_path.'.htpasswd');
900a38 1485             $app->log('Removed file '.$folder_path.'.htpasswd',LOGLEVEL_DEBUG);
524077 1486         }
T 1487         
1488         //* Remove .htaccess file
1489         if(is_file($folder_path.'.htaccess')) {
1490             unlink($folder_path.'.htaccess');
900a38 1491             $app->log('Removed file '.$folder_path.'.htaccess',LOGLEVEL_DEBUG);
524077 1492         }
2023a7 1493     }
T 1494     
1495     //* Update folder protection, when path has been changed
1496     function web_folder_update($event_name,$data) {
1497         global $app, $conf;
1498         
1499         $website = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".intval($data['new']['parent_domain_id']));
1500     
1501         if(!is_array($website)) {
1502             $app->log('Not able to retrieve folder or website record.',LOGLEVEL_DEBUG);
1503             return false;
1504         }
1505         
1506         //* Get the folder path.
0ea045 1507         if(substr($data['old']['path'],0,1) == '/') $data['old']['path'] = substr($data['old']['path'],1);
F 1508         if(substr($data['old']['path'],-1) == '/') $data['old']['path'] = substr($data['old']['path'],0,-1);
2023a7 1509         $old_folder_path = realpath($website['document_root'].'/web/'.$data['old']['path']);
8f08b5 1510         if(substr($old_folder_path,-1) != '/') $old_folder_path .= '/';
2023a7 1511             
0ea045 1512         if(substr($data['new']['path'],0,1) == '/') $data['new']['path'] = substr($data['new']['path'],1);
F 1513         if(substr($data['new']['path'],-1) == '/') $data['new']['path'] = substr($data['new']['path'],0,-1);
2023a7 1514         $new_folder_path = escapeshellcmd($website['document_root'].'/web/'.$data['new']['path']);
8f08b5 1515         if(substr($new_folder_path,-1) != '/') $new_folder_path .= '/';
2023a7 1516         
T 1517         //* Check if the resulting path is inside the docroot
1518         if(stristr($new_folder_path,'..') || stristr($new_folder_path,'./') || stristr($new_folder_path,'\\')) {
1519             $app->log('Folder path "'.$new_folder_path.'" contains .. or ./.',LOGLEVEL_DEBUG);
1520             return false;
1521         }
1522         if(stristr($old_folder_path,'..') || stristr($old_folder_path,'./') || stristr($old_folder_path,'\\')) {
1523             $app->log('Folder path "'.$old_folder_path.'" contains .. or ./.',LOGLEVEL_DEBUG);
1524             return false;
1525         }
1526         
1527         //* Check if the resulting path is inside the docroot
1528         if(substr($old_folder_path,0,strlen($website['document_root'])) != $website['document_root']) {
1529             $app->log('Old folder path '.$old_folder_path.' is outside of docroot.',LOGLEVEL_DEBUG);
1530             return false;
1531         }
1532         if(substr($new_folder_path,0,strlen($website['document_root'])) != $website['document_root']) {
1533             $app->log('New folder path '.$new_folder_path.' is outside of docroot.',LOGLEVEL_DEBUG);
1534             return false;
1535         }
1536             
1537         //* Create the folder path, if it does not exist
1538         if(!is_dir($new_folder_path)) exec('mkdir -p '.$new_folder_path);
1539         
1540         if($data['old']['path'] != $data['new']['path']) {
1541
1542         
1543             //* move .htpasswd file
1544             if(is_file($old_folder_path.'.htpasswd')) {
1545                 rename($old_folder_path.'.htpasswd',$new_folder_path.'.htpasswd');
0ea045 1546                 $app->log('Moved file '.$old_folder_path.'.htpasswd to '.$new_folder_path.'.htpasswd',LOGLEVEL_DEBUG);
2023a7 1547             }
T 1548             
0ea045 1549             //* delete old .htaccess file
2023a7 1550             if(is_file($old_folder_path.'.htaccess')) {
0ea045 1551                 unlink($old_folder_path.'.htaccess');
F 1552                 $app->log('Deleted file '.$old_folder_path.'.htaccess',LOGLEVEL_DEBUG);
2023a7 1553             }
T 1554         
1555         }
1556         
1557         //* Create the .htaccess file
0ea045 1558         if($data['new']['active'] == 'y') {
F 1559             $ht_file = "AuthType Basic\nAuthName \"Members Only\"\nAuthUserFile ".$new_folder_path.".htpasswd\nrequire valid-user";
2023a7 1560             file_put_contents($new_folder_path.'.htaccess',$ht_file);
T 1561             chmod($new_folder_path.'.htpasswd',0755);
053547 1562             chown($folder_path.'.htpasswd',$website['system_user']);
T 1563             chgrp($folder_path.'.htpasswd',$website['system_group']);
1564             $app->log('Created file '.$new_folder_path.'.htpasswd',LOGLEVEL_DEBUG);
2023a7 1565         }
T 1566         
1567         //* Remove .htaccess file
1568         if($data['new']['active'] == 'n' && is_file($new_folder_path.'.htaccess')) {
1569             unlink($new_folder_path.'.htaccess');
900a38 1570             $app->log('Removed file '.$new_folder_path.'.htaccess',LOGLEVEL_DEBUG);
2023a7 1571         }
524077 1572         
T 1573         
1574     }
ac933e 1575
V 1576     /**
1577      * This function is called when a Webdav-User is inserted, updated or deleted.
1578      *
1579      * @author Oliver Vogel
1580      * @param string $event_name
1581      * @param array $data
1582      */
1583     public function webdav($event_name,$data) {
1584         global $app, $conf;
52a04e 1585         
T 1586         /*
1587          * load the server configuration options
1588         */
fb3339 1589         $app->uses('getconf');
J 1590         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
ac933e 1591
V 1592         if (($event_name == 'webdav_user_insert') || ($event_name == 'webdav_user_update')) {
1593
1594             /*
1595              * Get additional informations
1596             */
fb3339 1597             $sitedata = $app->db->queryOneRecord('SELECT document_root, domain, system_user, system_group FROM web_domain WHERE domain_id = ' . $data['new']['parent_domain_id']);
ac933e 1598             $documentRoot = $sitedata['document_root'];
V 1599             $domain = $sitedata['domain'];
ca14fe 1600             $user = $sitedata['system_user'];
V 1601             $group = $sitedata['system_group'];
835c5d 1602             $webdav_user_dir = $documentRoot . '/webdav/' . $data['new']['dir'];
ac933e 1603
V 1604             /* Check if this is a chrooted setup */
1605             if($web_config['website_basedir'] != '' && @is_file($web_config['website_basedir'].'/etc/passwd')) {
1606                 $apache_chrooted = true;
fb3339 1607                 $app->log('Info: Apache is chrooted.',LOGLEVEL_DEBUG);
ac933e 1608             } else {
V 1609                 $apache_chrooted = false;
1610             }
835c5d 1611             
T 1612             //* We dont want to have relative paths here
1613             if(stristr($webdav_user_dir,'..')  || stristr($webdav_user_dir,'./')) {
1614                 $app->log('Folder path '.$webdav_user_dir.' contains ./ or .. '.$documentRoot,LOGLEVEL_WARN);
1615                 return false;
1616             }
1617             
1618             //* Check if the resulting path exists if yes, if it is inside the docroot
1619             if(is_dir($webdav_user_dir) && substr(realpath($webdav_user_dir),0,strlen($documentRoot)) != $documentRoot) {
1620                 $app->log('Folder path '.$webdav_user_dir.' is outside of docroot '.$documentRoot,LOGLEVEL_WARN);
1621                 return false;
1622             }
ac933e 1623
V 1624             /*
1625              * First the webdav-root - folder has to exist
1626             */
835c5d 1627             if(!is_dir($webdav_user_dir)) {
T 1628                 $app->log('Webdav User directory '.$webdav_user_dir.' does not exist. Creating it now.',LOGLEVEL_DEBUG);
1629                 exec('mkdir -p '.escapeshellcmd($webdav_user_dir));
ac933e 1630             }
V 1631
1632             /*
ca14fe 1633              * The webdav - Root needs the group/user as owner and the apache as read and write
ac933e 1634             */
fb3339 1635             $this->_exec('chown ' . $user . ':' . $group . ' ' . escapeshellcmd($documentRoot . '/webdav/'));
J 1636             $this->_exec('chmod 770 ' . escapeshellcmd($documentRoot . '/webdav/'));
ac933e 1637
V 1638             /*
ca14fe 1639              * The webdav folder (not the webdav-root!) needs the same (not in ONE step, because the
V 1640              * pwd-files are owned by root)
ac933e 1641             */
835c5d 1642             $this->_exec('chown ' . $user . ':' . $group . ' ' . escapeshellcmd($webdav_user_dir.' -R'));
T 1643             $this->_exec('chmod 770 ' . escapeshellcmd($webdav_user_dir.' -R'));
ca14fe 1644
V 1645             /*
1646              * if the user is active, we have to write/update the password - file
1647              * if the user is inactive, we have to inactivate the user by removing the user from the file
1648             */
1649             if ($data['new']['active'] == 'y') {
835c5d 1650                 $this->_writeHtDigestFile( $webdav_user_dir . '.htdigest', $data['new']['username'], $data['new']['dir'], $data['new']['password']);
ca14fe 1651             }
V 1652             else {
1653                 /* empty pwd removes the user! */
835c5d 1654                 $this->_writeHtDigestFile( $webdav_user_dir . '.htdigest', $data['new']['username'], $data['new']['dir'], '');
ca14fe 1655             }
ac933e 1656
V 1657             /*
1658              * Next step, patch the vhost - file
1659             */
fb3339 1660             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'] . '/' . $domain . '.vhost');
ac933e 1661             $this->_patchVhostWebdav($vhost_file, $documentRoot . '/webdav');
ca14fe 1662
ac933e 1663             /*
V 1664              * Last, restart apache
1665             */
1666             if($apache_chrooted) {
1667                 $app->services->restartServiceDelayed('httpd','restart');
1668             } else {
1669                 // request a httpd reload when all records have been processed
1670                 $app->services->restartServiceDelayed('httpd','reload');
1671             }
1672
1673         }
1674
1675         if ($event_name == 'webdav_user_delete') {
1676             /*
1677              * Get additional informations
1678             */
fb3339 1679             $sitedata = $app->db->queryOneRecord('SELECT document_root, domain FROM web_domain WHERE domain_id = ' . $data['old']['parent_domain_id']);
ac933e 1680             $documentRoot = $sitedata['document_root'];
52a04e 1681             $domain = $sitedata['domain'];
ac933e 1682
V 1683             /*
1684              * We dont't want to destroy any (transfer)-Data. So we do NOT delete any dir.
1685              * So the only thing, we have to do, is to delete the user from the password-file
ca14fe 1686             */
ac933e 1687             $this->_writeHtDigestFile( $documentRoot . '/webdav/' . $data['old']['dir'] . '.htdigest', $data['old']['username'], $data['old']['dir'], '');
52a04e 1688             
T 1689             /*
1690              * Next step, patch the vhost - file
1691             */
fb3339 1692             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'] . '/' . $domain . '.vhost');
52a04e 1693             $this->_patchVhostWebdav($vhost_file, $documentRoot . '/webdav');
T 1694             
1695             /*
1696              * Last, restart apache
1697             */
1698             if($apache_chrooted) {
1699                 $app->services->restartServiceDelayed('httpd','restart');
1700             } else {
1701                 // request a httpd reload when all records have been processed
1702                 $app->services->restartServiceDelayed('httpd','reload');
1703             }
ac933e 1704         }
V 1705     }
1706
1707
1708     /**
1709      * This function writes the htdigest - files used by webdav and digest
ca14fe 1710      * more info: see http://riceball.com/d/node/424
ac933e 1711      * @author Oliver Vogel
V 1712      * @param string $filename The name of the digest-file
1713      * @param string $username The name of the webdav-user
1714      * @param string $authname The name of the realm
ca14fe 1715      * @param string $pwd      The password-hash of the user
ac933e 1716      */
ca14fe 1717     private function _writeHtDigestFile($filename, $username, $authname, $pwdhash ) {
ac933e 1718         $changed = false;
0ff3f1 1719         if(is_file($filename)) {
T 1720             $in = fopen($filename, 'r');
1721             $output = '';
1722             /*
1723             * read line by line and search for the username and authname
1724             */
1725             while (preg_match("/:/", $line = fgets($in))) {
1726                 $line = rtrim($line);
1727                 $tmp = explode(':', $line);
1728                 if ($tmp[0] == $username && $tmp[1] == $authname) {
1729                     /*
1730                     * found the user. delete or change it?
1731                     */
1732                     if ($pwdhash != '') {
1733                         $output .= $tmp[0] . ':' . $tmp[1] . ':' . $pwdhash . "\n";
1734                         }
1735                     $changed = true;
1736                 }
1737                 else {
1738                     $output .= $line . "\n";
1739                 }
ac933e 1740             }
0ff3f1 1741             fclose($in);
ac933e 1742         }
V 1743         /*
1744          * if we didn't change anything, we have to add the new user at the end of the file
1745         */
1746         if (!$changed) {
f17dab 1747             $output .= $username . ':' . $authname . ':' . $pwdhash . "\n";
ac933e 1748         }
0ff3f1 1749         
ac933e 1750
V 1751         /*
1752          * Now lets write the new file
1753         */
52a04e 1754         if(trim($output) == '') {
T 1755             unlink($filename);
1756         } else {
1757             file_put_contents($filename, $output);
1758         }
ac933e 1759     }
V 1760
1761     /**
1762      * This function patches the vhost-file and adds all webdav - user.
1763      * This function is written, because the creation of the vhost - file is sophisticated and
1764      * i don't want to make it more "heavy" by also adding this code too...
1765      * @author Oliver Vogel
1766      * @param string $fileName The Name of the .vhost-File (path included)
1767      * @param string $webdavRoot The root of the webdav-folder
1768      */
1769     private function _patchVhostWebdav($fileName, $webdavRoot) {
1770         $in = fopen($fileName, 'r');
1771         $output = '';
1772         $inWebdavSection = false;
1773
1774         /*
1775          * read line by line and search for the username and authname
1776         */
1777         while ($line = fgets($in)) {
1778             /*
1779              *  is the "replace-comment" found...
1780             */
1781             if (trim($line) == '# WEBDAV BEGIN') {
1782                 /*
1783                  * The begin of the webdav - section is found, so ignore all lines til the end  is found
1784                 */
1785                 $inWebdavSection = true;
1786
1787                 $output .= "      # WEBDAV BEGIN\n";
1788
1789                 /*
1790                  * add all the webdav-dirs to the webdav-section
1791                 */
fb3a98 1792                 $files = @scandir($webdavRoot);
T 1793                 if(is_array($files)) {
ac933e 1794                 foreach($files as $file) {
V 1795                     if (substr($file, strlen($file) - strlen('.htdigest')) == '.htdigest') {
1796                         /*
1797                          * found a htdigest - file, so add it to webdav
1798                         */
1799                         $fn = substr($file, 0, strlen($file) - strlen('.htdigest'));
1800                         $output .= "\n";
dd1afa 1801                         // $output .= "      Alias /" . $fn . ' ' . $webdavRoot . '/' . $fn . "\n";
T 1802                         // $output .= "      <Location /" . $fn . ">\n";
9f56bd 1803                         $output .= "      Alias /webdav/" . $fn . ' ' . $webdavRoot . '/' . $fn . "\n";
T 1804                         $output .= "      <Location /webdav/" . $fn . ">\n";
ac933e 1805                         $output .= "        DAV On\n";
91aaaf 1806                         $output .= '        BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On'."\n";
ac933e 1807                         $output .= "        AuthType Digest\n";
V 1808                         $output .= "        AuthName \"" . $fn . "\"\n";
fb3339 1809                         $output .= "        AuthUserFile " . $webdavRoot . '/' . $file . "\n";
ac933e 1810                         $output .= "        Require valid-user \n";
V 1811                         $output .= "        Options +Indexes \n";
1812                         $output .= "        Order allow,deny \n";
1813                         $output .= "        Allow from all \n";
1814                         $output .= "      </Location> \n";
1815                     }
1816                 }
fb3a98 1817                 }
ac933e 1818             }
V 1819             /*
1820              *  is the "replace-comment-end" found...
1821             */
1822             if (trim($line) == '# WEBDAV END') {
1823                 /*
1824                  * The end of the webdav - section is found, so stop ignoring
1825                 */
1826                 $inWebdavSection = false;
1827             }
1828
1829             /*
1830              * Write the line to the output, if it is not in the section
1831             */
1832             if (!$inWebdavSection) {
1833                 $output .= $line;
1834             }
1835         }
1836         fclose($in);
1837
1838         /*
1839          * Now lets write the new file
1840         */
1841         file_put_contents($fileName, $output);
1842
1843     }
58c210 1844     
T 1845     //* Update the awstats configuration file
1846     private function awstats_update ($data,$web_config) {
1847         global $app;
1848         
2a6eac 1849         $awstats_conf_dir = $web_config['awstats_conf_dir'];
T 1850         
b10f96 1851         if(!is_dir($data['new']['document_root']."/web/stats/")) mkdir($data['new']['document_root']."/web/stats");
fb3339 1852         if(!@is_file($awstats_conf_dir.'/awstats.'.$data['new']['domain'].'.conf') || ($data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain'])) {
J 1853             if ( @is_file($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf') ) {
1854                 unlink($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf');
58c210 1855             }
T 1856             
1857             $content = '';
2a6eac 1858             $content .= "Include \"".$awstats_conf_dir."/awstats.conf\"\n";
fb3339 1859             $content .= "LogFile=\"/var/log/ispconfig/httpd/".$data['new']['domain']."/access.log\"\n";
J 1860             $content .= "SiteDomain=\"".$data['new']['domain']."\"\n";
1861             $content .= "HostAliases=\"www.".$data['new']['domain']."  localhost 127.0.0.1\"\n";
58c210 1862             
fb3339 1863             file_put_contents($awstats_conf_dir.'/awstats.'.$data['new']['domain'].'.conf',$content);
J 1864             $app->log('Created AWStats config file: '.$awstats_conf_dir.'/awstats.'.$data['new']['domain'].'.conf',LOGLEVEL_DEBUG);
58c210 1865         }
d81a4c 1866         
3498f7 1867         if(is_file($data['new']['document_root']."/web/stats/index.html")) unlink($data['new']['document_root']."/web/stats/index.html");
d81a4c 1868         copy("/usr/local/ispconfig/server/conf/awstats_index.php.master",$data['new']['document_root']."/web/stats/index.php");
58c210 1869     }
T 1870     
1871     //* Delete the awstats configuration file
1872     private function awstats_delete ($data,$web_config) {
1873         global $app;
1874         
1875         $awstats_conf_dir = $web_config['awstats_conf_dir'];
1876         
fb3339 1877         if ( @is_file($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf') ) {
J 1878             unlink($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf');
1879             $app->log('Removed AWStats config file: '.$awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf',LOGLEVEL_DEBUG);
58c210 1880         }
T 1881     }
1ca823 1882     
T 1883     function client_delete($event_name,$data) {
1884         global $app, $conf;
1885         
1886         $app->uses("getconf");
1887         $web_config = $app->getconf->get_server_config($conf["server_id"], 'web');
1888         
1889         $client_id = intval($data['old']['client_id']);
1890         if($client_id > 0) {
1891             
1892             $client_dir = $web_config['website_basedir'].'/clients/client'.$client_id;
1893             if(is_dir($client_dir) && !stristr($client_dir,'..')) {
1894                 @rmdir($client_dir);
1895                 $app->log('Removed client directory: '.$client_dir,LOGLEVEL_DEBUG);
1896             }
1897             
1898             $this->_exec('groupdel client'.$client_id);
1899             $app->log('Removed group client'.$client_id,LOGLEVEL_DEBUG);
1900         }
1901         
1902     }
ac933e 1903
1c40af 1904     //* Wrapper for exec function for easier debugging
T 1905     private function _exec($command) {
1906         global $app;
fb3339 1907         $app->log('exec: '.$command,LOGLEVEL_DEBUG);
1c40af 1908         exec($command);
T 1909     }
7ed741 1910     
T 1911     private function _checkTcp ($host,$port) {
1912
1913         $fp = @fsockopen ($host, $port, $errno, $errstr, 2);
1914
1915         if ($fp) {
1916             fclose($fp);
1917             return true;
1918         } else {
1919             return false;
1920         }
1921     }
ac933e 1922
552178 1923     public function create_relative_link($f, $t) {
M 1924         // $from already exists
1925         $from = realpath($f);
1926
1927         // realpath requires the traced file to exist - so, lets touch it first, then remove
1928         @unlink($t); touch($t);
1929         $to = realpath($t);
1930         @unlink($t);
1931
1932         // Remove from the left side matching path elements from $from and $to
1933         // and get path elements counts
1934         $a1 = explode('/', $from); $a2 = explode('/', $to);
1935         for ($c = 0; $a1[$c] == $a2[$c]; $c++) {
1936             unset($a1[$c]); unset($a2[$c]);
1937         }
1938         $cfrom = implode('/', $a1);
1939
1940         // Check if a path is fully a subpath of another - no way to create symlink in the case
1941         if (count($a1) == 0 || count($a2) == 0) return false;
1942
1943         // Add ($cnt_to-1) number of "../" elements to left side of $cfrom
1944         for ($c = 0; $c < (count($a2)-1); $c++) { $cfrom = '../'.$cfrom; }
1945
1946         return symlink($cfrom, $to);
1947     }
46c683 1948
T 1949 } // end class
1950
1c711c 1951 ?>