tbrehm
2012-06-05 bf356a4021ee40e79392cb0c670bdfb192d2c529
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
88273a 645                 //* Check if there is a jailkit user for this site
T 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'");
647                 if($tmp['number'] > 0) {
648                     $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root']));
649                     $this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root']));
650                 }
651                 unset($tmp);
ac933e 652
88273a 653                 // If the security Level is set to medium
T 654             } else {
655
fb3339 656                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root']));
e942cf 657                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/cgi-bin'));
T 658                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/log'));
659                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/ssl'));
660                 $this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/web'));
661                 
88273a 662                 // make temp directory writable for Apache and the website users
T 663                 $this->_exec('chmod 777 '.escapeshellcmd($data['new']['document_root'].'/tmp'));
e942cf 664                 
T 665                 $this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root']));
666                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/cgi-bin'));
667                 $this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root'].'/log'));
668                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/tmp'));
669                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/ssl'));
670                 $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/web'));
8db8f3 671             }
6b029a 672         }
ac933e 673
fb3339 674         // Change the ownership of the error log to the owner of the website
J 675         if(!@is_file($data['new']['document_root'].'/log/error.log')) exec('touch '.escapeshellcmd($data['new']['document_root']).'/log/error.log');
676         $this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root']).'/log/error.log');
ac933e 677
V 678
bf356a 679         //* Write the custom php.ini file, if custom_php_ini fieled is not empty
fb3339 680         $custom_php_ini_dir = $web_config['website_basedir'].'/conf/'.$data['new']['system_user'];
7fddfe 681         if(!is_dir($web_config['website_basedir'].'/conf')) mkdir($web_config['website_basedir'].'/conf');
bf356a 682         
T 683         //* add open_basedir restriction to custom php.ini content, required for suphp only
684         if(!stristr($data['new']['custom_php_ini'],'open_basedir') && $data['new']['php'] == 'suphp') {
685             $data['new']['custom_php_ini'] .= "\nopen_basedir = '".$data['new']['php_open_basedir']."'\n";
686         }
687         //* Create custom php.ini
fb3339 688         if(trim($data['new']['custom_php_ini']) != '') {
7fddfe 689             $has_custom_php_ini = true;
T 690             if(!is_dir($custom_php_ini_dir)) mkdir($custom_php_ini_dir);
691             $php_ini_content = '';
fb3339 692             if($data['new']['php'] == 'mod') {
7fddfe 693                 $master_php_ini_path = $web_config['php_ini_path_apache'];
T 694             } else {
9f56bd 695                 if($data["new"]['php'] == 'fast-cgi' && file_exists($fastcgi_config["fastcgi_phpini_path"])) {
T 696                     $master_php_ini_path = $fastcgi_config["fastcgi_phpini_path"];
697                 } else {
698                     $master_php_ini_path = $web_config['php_ini_path_cgi'];
699                 }
7fddfe 700             }
T 701             if($master_php_ini_path != '' && substr($master_php_ini_path,-7) == 'php.ini' && is_file($master_php_ini_path)) {
702                 $php_ini_content .= file_get_contents($master_php_ini_path)."\n";
703             }
8008bb 704             $php_ini_content .= str_replace("\r",'',trim($data['new']['custom_php_ini']));
7fddfe 705             file_put_contents($custom_php_ini_dir.'/php.ini',$php_ini_content);
T 706         } else {
707             $has_custom_php_ini = false;
708             if(is_file($custom_php_ini_dir.'/php.ini')) unlink($custom_php_ini_dir.'/php.ini');
709         }
710
711
712         //* Create the vhost config file
46c683 713         $app->load('tpl');
ac933e 714
46c683 715         $tpl = new tpl();
fb3339 716         $tpl->newTemplate('vhost.conf.master');
ac933e 717
fb3339 718         $vhost_data = $data['new'];
a7bdf8 719         //unset($vhost_data['ip_address']);
fb3339 720         $vhost_data['web_document_root'] = $data['new']['document_root'].'/web';
J 721         $vhost_data['web_document_root_www'] = $web_config['website_basedir'].'/'.$data['new']['domain'].'/web';
722         $vhost_data['web_basedir'] = $web_config['website_basedir'];
723         $vhost_data['security_level'] = $web_config['security_level'];
724         $vhost_data['allow_override'] = ($data['new']['allow_override'] == '')?'All':$data['new']['allow_override'];
725         $vhost_data['php_open_basedir'] = ($data['new']['php_open_basedir'] == '')?$data['new']['document_root']:$data['new']['php_open_basedir'];
726         $vhost_data['ssl_domain'] = $data['new']['ssl_domain'];
727         $vhost_data['has_custom_php_ini'] = $has_custom_php_ini;
728         $vhost_data['custom_php_ini_dir'] = escapeshellcmd($custom_php_ini_dir);
accfe5 729         
F 730         // Custom Apache directives
731         // Make sure we only have Unix linebreaks
732         $vhost_data['apache_directives'] = str_replace("\r\n", "\n", $vhost_data['apache_directives']);
733         $vhost_data['apache_directives'] = str_replace("\r", "\n", $vhost_data['apache_directives']);
ac933e 734
46c683 735         // Check if a SSL cert exists
fb3339 736         $ssl_dir = $data['new']['document_root'].'/ssl';
J 737         $domain = $data['new']['ssl_domain'];
738         $key_file = $ssl_dir.'/'.$domain.'.key';
739         $crt_file = $ssl_dir.'/'.$domain.'.crt';
740         $bundle_file = $ssl_dir.'/'.$domain.'.bundle';
ac933e 741
a7bdf8 742         /*
1a2310 743         if($domain!='' && $data['new']['ssl'] == 'y' && @is_file($crt_file) && @is_file($key_file) && (@filesize($crt_file)>0)  && (@filesize($key_file)>0)) {
fb3339 744             $vhost_data['ssl_enabled'] = 1;
J 745             $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
46c683 746         } else {
fb3339 747             $vhost_data['ssl_enabled'] = 0;
1a2310 748             $app->log('SSL Disabled. '.$domain,LOGLEVEL_DEBUG);
46c683 749         }
a7bdf8 750         */
ac933e 751
46c683 752         if(@is_file($bundle_file)) $vhost_data['has_bundle_cert'] = 1;
ac933e 753
fb3339 754         //$vhost_data['document_root'] = $data['new']['document_root'].'/web';
e64fbb 755         
F 756         // Set SEO Redirect
757         if($data['new']['seo_redirect'] != '' && ($data['new']['subdomain'] == 'www' || $data['new']['subdomain'] == '*')){
758             $vhost_data['seo_redirect_enabled'] = 1;
759             if($data['new']['seo_redirect'] == 'non_www_to_www'){
760                 $vhost_data['seo_redirect_origin_domain'] = $data['new']['domain'];
761                 $vhost_data['seo_redirect_target_domain'] = 'www.'.$data['new']['domain'];
762             }
763             if($data['new']['seo_redirect'] == 'www_to_non_www'){
764                 $vhost_data['seo_redirect_origin_domain'] = 'www.'.$data['new']['domain'];
765                 $vhost_data['seo_redirect_target_domain'] = $data['new']['domain'];
766             }
767         } else {
768             $vhost_data['seo_redirect_enabled'] = 0;
769         }
770         
46c683 771         $tpl->setVar($vhost_data);
ac933e 772
46c683 773         // Rewrite rules
T 774         $rewrite_rules = array();
790cb8 775         if($data['new']['redirect_type'] != '' && $data['new']['redirect_path'] != '') {
fb3339 776             if(substr($data['new']['redirect_path'],-1) != '/') $data['new']['redirect_path'] .= '/';
45ee67 777             if(substr($data['new']['redirect_path'],0,8) == '[scheme]'){
F 778                 $rewrite_target = 'http'.substr($data['new']['redirect_path'],8);
779                 $rewrite_target_ssl = 'https'.substr($data['new']['redirect_path'],8);
780             } else {
781                 $rewrite_target = $data['new']['redirect_path'];
782                 $rewrite_target_ssl = $data['new']['redirect_path'];
783             }
bc2c3e 784             /* Disabled path extension
fb3339 785             if($data['new']['redirect_type'] == 'no' && substr($data['new']['redirect_path'],0,4) != 'http') {
J 786                 $data['new']['redirect_path'] = $data['new']['document_root'].'/web'.realpath($data['new']['redirect_path']).'/';
8388ae 787             }
bc2c3e 788             */
ac933e 789
fb3339 790             switch($data['new']['subdomain']) {
ac933e 791                 case 'www':
e64fbb 792                     $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$data['new']['domain'],
F 793                         'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
794                         'rewrite_target'     => $rewrite_target,
795                         'rewrite_target_ssl' => $rewrite_target_ssl);
796                     $rewrite_rules[] = array(    'rewrite_domain'     => '^www.'.$data['new']['domain'],
fb3339 797                             'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
e64fbb 798                             'rewrite_target'     => $rewrite_target,
F 799                             'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 800                     break;
V 801                 case '*':
876d67 802                     $rewrite_rules[] = array(    'rewrite_domain'     => '(^|\.)'.$data['new']['domain'],
e64fbb 803                         'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
F 804                         'rewrite_target'     => $rewrite_target,
805                         'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 806                     break;
e64fbb 807                 default:
F 808                     $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$data['new']['domain'],
809                         'rewrite_type'         => ($data['new']['redirect_type'] == 'no')?'':'['.$data['new']['redirect_type'].']',
810                         'rewrite_target'     => $rewrite_target,
811                         'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 812             }
46c683 813         }
ac933e 814
46c683 815         // get alias domains (co-domains and subdomains)
fb3339 816         $aliases = $app->db->queryAllRecords('SELECT * FROM web_domain WHERE parent_domain_id = '.$data['new']['domain_id']." AND active = 'y'");
ac933e 817         $server_alias = array();
fb3339 818         switch($data['new']['subdomain']) {
ac933e 819             case 'www':
fb3339 820                 $server_alias[] .= 'www.'.$data['new']['domain'].' ';
ac933e 821                 break;
V 822             case '*':
fb3339 823                 $server_alias[] .= '*.'.$data['new']['domain'].' ';
ac933e 824                 break;
V 825         }
46c683 826         if(is_array($aliases)) {
T 827             foreach($aliases as $alias) {
fb3339 828                 switch($alias['subdomain']) {
ac933e 829                     case 'www':
fb3339 830                         $server_alias[] .= 'www.'.$alias['domain'].' '.$alias['domain'].' ';
ac933e 831                         break;
V 832                     case '*':
fb3339 833                         $server_alias[] .= '*.'.$alias['domain'].' '.$alias['domain'].' ';
ac933e 834                         break;
V 835                     default:
fb3339 836                         $server_alias[] .= $alias['domain'].' ';
ac933e 837                         break;
V 838                 }
fb3339 839                 $app->log('Add server alias: '.$alias['domain'],LOGLEVEL_DEBUG);
46c683 840                 // Rewriting
790cb8 841                 if($alias['redirect_type'] != '' && $alias['redirect_path'] != '') {
e64fbb 842                     if(substr($alias['redirect_path'],-1) != '/') $alias['redirect_path'] .= '/';
F 843                     if(substr($alias['redirect_path'],0,8) == '[scheme]'){
844                         $rewrite_target = 'http'.substr($alias['redirect_path'],8);
845                         $rewrite_target_ssl = 'https'.substr($alias['redirect_path'],8);
846                     } else {
847                         $rewrite_target = $alias['redirect_path'];
848                         $rewrite_target_ssl = $alias['redirect_path'];
849                     }
bc2c3e 850                     /* Disabled the path extension
fb3339 851                     if($data['new']['redirect_type'] == 'no' && substr($data['new']['redirect_path'],0,4) != 'http') {
J 852                         $data['new']['redirect_path'] = $data['new']['document_root'].'/web'.realpath($data['new']['redirect_path']).'/';
8388ae 853                     }
bc2c3e 854                     */
e64fbb 855                     
fb3339 856                     switch($alias['subdomain']) {
ac933e 857                         case 'www':
e64fbb 858                             $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$alias['domain'],
F 859                                 'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
860                                 'rewrite_target'     => $rewrite_target,
861                                 'rewrite_target_ssl' => $rewrite_target_ssl);
862                             $rewrite_rules[] = array(    'rewrite_domain'     => '^www.'.$alias['domain'],
fb3339 863                                     'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
e64fbb 864                                     'rewrite_target'     => $rewrite_target,
F 865                                     'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 866                             break;
V 867                         case '*':
876d67 868                             $rewrite_rules[] = array(    'rewrite_domain'     => '(^|\.)'.$alias['domain'],
e64fbb 869                                 'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
F 870                                 'rewrite_target'     => $rewrite_target,
871                                 'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 872                             break;
e64fbb 873                         default:
F 874                             $rewrite_rules[] = array(    'rewrite_domain'     => '^'.$alias['domain'],
875                                 'rewrite_type'         => ($alias['redirect_type'] == 'no')?'':'['.$alias['redirect_type'].']',
876                                 'rewrite_target'     => $rewrite_target,
877                                 'rewrite_target_ssl' => $rewrite_target_ssl);
ac933e 878                     }
46c683 879                 }
T 880             }
881         }
ac933e 882
47cca9 883         //* If we have some alias records
T 884         if(count($server_alias) > 0) {
885             $server_alias_str = '';
886             $n = 0;
ac933e 887
47cca9 888             // begin a new ServerAlias line after 30 alias domains
T 889             foreach($server_alias as $tmp_alias) {
890                 if($n % 30 == 0) $server_alias_str .= "\n    ServerAlias ";
891                 $server_alias_str .= $tmp_alias;
892             }
893             unset($tmp_alias);
ac933e 894
47cca9 895             $tpl->setVar('alias',trim($server_alias_str));
T 896         } else {
897             $tpl->setVar('alias','');
898         }
ac933e 899
af4864 900         if(count($rewrite_rules) > 0 || $vhost_data['seo_redirect_enabled'] > 0) {
46c683 901             $tpl->setVar('rewrite_enabled',1);
T 902         } else {
903             $tpl->setVar('rewrite_enabled',0);
904         }
af4864 905
F 906         //$tpl->setLoop('redirects',$rewrite_rules);
ac933e 907
V 908         /**
909          * install fast-cgi starter script and add script aliasd config
46c683 910          * first we create the script directory if not already created, then copy over the starter script
T 911          * settings are copied over from the server ini config for now
912          * TODO: Create form for fastcgi configs per site.
913          */
ac933e 914
fb3339 915         if ($data['new']['php'] == 'fast-cgi') {
J 916             $fastcgi_config = $app->getconf->get_server_config($conf['server_id'], 'fastcgi');
ac933e 917
fb3339 918             $fastcgi_starter_path = str_replace('[system_user]',$data['new']['system_user'],$fastcgi_config['fastcgi_starter_path']);
J 919             $fastcgi_starter_path = str_replace('[client_id]',$client_id,$fastcgi_starter_path);
ac933e 920
V 921             if (!is_dir($fastcgi_starter_path)) {
fb3339 922                 exec('mkdir -p '.escapeshellcmd($fastcgi_starter_path));
J 923                 //exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.escapeshellcmd($fastcgi_starter_path));
ac933e 924
V 925
fb3339 926                 $app->log('Creating fastcgi starter script directory: '.$fastcgi_starter_path,LOGLEVEL_DEBUG);
46c683 927             }
ac933e 928
fb3339 929             exec('chown -R '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.escapeshellcmd($fastcgi_starter_path));
ac933e 930
46c683 931             $fcgi_tpl = new tpl();
fb3339 932             $fcgi_tpl->newTemplate('php-fcgi-starter.master');
7fddfe 933             
T 934             if($has_custom_php_ini) {
935                 $fcgi_tpl->setVar('php_ini_path',escapeshellcmd($custom_php_ini_dir));
936             } else {
fb3339 937                 $fcgi_tpl->setVar('php_ini_path',escapeshellcmd($fastcgi_config['fastcgi_phpini_path']));
7fddfe 938             }
fb3339 939             $fcgi_tpl->setVar('document_root',escapeshellcmd($data['new']['document_root']));
J 940             $fcgi_tpl->setVar('php_fcgi_children',escapeshellcmd($fastcgi_config['fastcgi_children']));
941             $fcgi_tpl->setVar('php_fcgi_max_requests',escapeshellcmd($fastcgi_config['fastcgi_max_requests']));
942             $fcgi_tpl->setVar('php_fcgi_bin',escapeshellcmd($fastcgi_config['fastcgi_bin']));
943             $fcgi_tpl->setVar('security_level',intval($web_config['security_level']));
ac933e 944
fb3339 945             $php_open_basedir = ($data['new']['php_open_basedir'] == '')?$data['new']['document_root']:$data['new']['php_open_basedir'];
ff7075 946             $fcgi_tpl->setVar('open_basedir', escapeshellcmd($php_open_basedir));
ac933e 947
fb3339 948             $fcgi_starter_script = escapeshellcmd($fastcgi_starter_path.$fastcgi_config['fastcgi_starter_script']);
46c683 949             file_put_contents($fcgi_starter_script,$fcgi_tpl->grab());
T 950             unset($fcgi_tpl);
ac933e 951
fb3339 952             $app->log('Creating fastcgi starter script: '.$fcgi_starter_script,LOGLEVEL_DEBUG);
ac933e 953
V 954
fb3339 955             exec('chmod 755 '.$fcgi_starter_script);
J 956             exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.$fcgi_starter_script);
46c683 957
fb3339 958             $tpl->setVar('fastcgi_alias',$fastcgi_config['fastcgi_alias']);
46c683 959             $tpl->setVar('fastcgi_starter_path',$fastcgi_starter_path);
fb3339 960             $tpl->setVar('fastcgi_starter_script',$fastcgi_config['fastcgi_starter_script']);
824780 961             $tpl->setVar('fastcgi_config_syntax',$fastcgi_config['fastcgi_config_syntax']);
ac933e 962
46c683 963         }
ac933e 964
46c683 965         /**
T 966          * install cgi starter script and add script alias to config.
967          * This is needed to allow cgi with suexec (to do so, we need a bin in the document-path!)
968          * first we create the script directory if not already created, then copy over the starter script.
969          * TODO: we have to fetch the data from the server-settings.
970          */
971
fb3339 972         if ($data['new']['php'] == 'cgi') {
J 973             //$cgi_config = $app->getconf->get_server_config($conf['server_id'], 'cgi');
46c683 974
fb3339 975             $cgi_config['cgi_starter_path'] = $web_config['website_basedir'].'/php-cgi-scripts/[system_user]/';
J 976             $cgi_config['cgi_starter_script'] = 'php-cgi-starter';
977             $cgi_config['cgi_bin'] = '/usr/bin/php-cgi';
46c683 978
fb3339 979             $cgi_starter_path = str_replace('[system_user]',$data['new']['system_user'],$cgi_config['cgi_starter_path']);
J 980             $cgi_starter_path = str_replace('[client_id]',$client_id,$cgi_starter_path);
46c683 981
ac933e 982             if (!is_dir($cgi_starter_path)) {
fb3339 983                 exec('mkdir -p '.escapeshellcmd($cgi_starter_path));
J 984                 exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.escapeshellcmd($cgi_starter_path));
46c683 985
fb3339 986                 $app->log('Creating cgi starter script directory: '.$cgi_starter_path,LOGLEVEL_DEBUG);
46c683 987             }
T 988
989             $cgi_tpl = new tpl();
fb3339 990             $cgi_tpl->newTemplate('php-cgi-starter.master');
46c683 991
fb3339 992             // This works because PHP "rewrites" a symlink to the physical path
J 993             $php_open_basedir = ($data['new']['php_open_basedir'] == '')?$data['new']['document_root']:$data['new']['php_open_basedir'];
ac933e 994             $cgi_tpl->setVar('open_basedir', escapeshellcmd($php_open_basedir));
fb3339 995             $cgi_tpl->setVar('document_root', escapeshellcmd($data['new']['document_root']));
ac933e 996
46c683 997             // This will NOT work!
fb3339 998             //$cgi_tpl->setVar('open_basedir', '/var/www/' . $data['new']['domain']);
J 999             $cgi_tpl->setVar('php_cgi_bin',$cgi_config['cgi_bin']);
1000             $cgi_tpl->setVar('security_level',$web_config['security_level']);
7fddfe 1001             
T 1002             $cgi_tpl->setVar('has_custom_php_ini',$has_custom_php_ini);
1003             if($has_custom_php_ini) {
1004                 $cgi_tpl->setVar('php_ini_path',escapeshellcmd($custom_php_ini_dir));
1005             } else {
fb3339 1006                 $cgi_tpl->setVar('php_ini_path',escapeshellcmd($fastcgi_config['fastcgi_phpini_path']));
7fddfe 1007             }
46c683 1008
fb3339 1009             $cgi_starter_script = escapeshellcmd($cgi_starter_path.$cgi_config['cgi_starter_script']);
46c683 1010             file_put_contents($cgi_starter_script,$cgi_tpl->grab());
T 1011             unset($cgi_tpl);
1012
fb3339 1013             $app->log('Creating cgi starter script: '.$cgi_starter_script,LOGLEVEL_DEBUG);
46c683 1014
T 1015
fb3339 1016             exec('chmod 755 '.$cgi_starter_script);
J 1017             exec('chown '.$data['new']['system_user'].':'.$data['new']['system_group'].' '.$cgi_starter_script);
46c683 1018
T 1019             $tpl->setVar('cgi_starter_path',$cgi_starter_path);
fb3339 1020             $tpl->setVar('cgi_starter_script',$cgi_config['cgi_starter_script']);
46c683 1021
T 1022         }
1023
fb3339 1024         $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/'.$data['new']['domain'].'.vhost');
7ed741 1025         //* Make a backup copy of vhost file
083dc0 1026         if(file_exists($vhost_file)) copy($vhost_file,$vhost_file.'~');
7ed741 1027         
a7bdf8 1028         //* create empty vhost array
T 1029         $vhosts = array();
1030         
af4864 1031         //* Add vhost for ipv4 IP    
F 1032         if(count($rewrite_rules) > 0){
1033             $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 0, 'port' => 80, 'redirects' => $rewrite_rules);
1034         } else {
1035             $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 0, 'port' => 80);
1036         }
a7bdf8 1037         
T 1038         //* Add vhost for ipv4 IP with SSL
1039         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 1040             if(count($rewrite_rules) > 0){
F 1041                 $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 1, 'port' => '443', 'redirects' => $rewrite_rules);
1042             } else {
1043                 $vhosts[] = array('ip_address' => $data['new']['ip_address'], 'ssl_enabled' => 1, 'port' => '443');
1044             }
a7bdf8 1045             $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
T 1046         }
1047         
1048         //* Add vhost for IPv6 IP
1049         if($data['new']['ipv6_address'] != '') {
af4864 1050             if(count($rewrite_rules) > 0){
F 1051                 $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80, 'redirects' => $rewrite_rules);
1052             } else {
1053                 $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80);
1054             }
a7bdf8 1055         
T 1056             //* Add vhost for ipv6 IP with SSL
1057             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 1058                 
F 1059                 if(count($rewrite_rules) > 0){
1060                     $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 1, 'port' => '443', 'redirects' => $rewrite_rules);
1061                 } else {
1062                     $vhosts[] = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 1, 'port' => '443');
1063                 }
a7bdf8 1064                 $app->log('Enable SSL for IPv6: '.$domain,LOGLEVEL_DEBUG);
T 1065             }
1066         }
1067         
1068         //* Set the vhost loop
1069         $tpl->setLoop('vhosts',$vhosts);
1070         
7ed741 1071         //* Write vhost file
46c683 1072         file_put_contents($vhost_file,$tpl->grab());
fb3339 1073         $app->log('Writing the vhost file: '.$vhost_file,LOGLEVEL_DEBUG);
46c683 1074         unset($tpl);
ac933e 1075
V 1076         /*
1077          * maybe we have some webdav - user. If so, add them...
1078         */
fb3339 1079         $this->_patchVhostWebdav($vhost_file, $data['new']['document_root'] . '/webdav');
ac933e 1080
c6a89c 1081         //* Set the symlink to enable the vhost
T 1082         //* First we check if there is a old type of symlink and remove it
fb3339 1083         $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/'.$data['new']['domain'].'.vhost');
c6a89c 1084         if(is_link($vhost_symlink)) unlink($vhost_symlink);
T 1085         
1086         //* Remove old or changed symlinks
1087         if($data['new']['subdomain'] != $data['old']['subdomain'] or $data['new']['active'] == 'n') {
1088             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['new']['domain'].'.vhost');
1089             if(is_link($vhost_symlink)) {
1090                 unlink($vhost_symlink);
1091                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1092             }
1093             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['new']['domain'].'.vhost');
1094             if(is_link($vhost_symlink)) {
1095                 unlink($vhost_symlink);
1096                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1097             }
1098         }
1099         
1100         //* New symlink
1101         if($data['new']['subdomain'] == '*') {
1102             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['new']['domain'].'.vhost');
1103         } else {
1104             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['new']['domain'].'.vhost');
1105         }
fb3339 1106         if($data['new']['active'] == 'y' && !is_link($vhost_symlink)) {
46c683 1107             symlink($vhost_file,$vhost_symlink);
fb3339 1108             $app->log('Creating symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
46c683 1109         }
ac933e 1110
46c683 1111         // remove old symlink and vhost file, if domain name of the site has changed
fb3339 1112         if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
c6a89c 1113             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['old']['domain'].'.vhost');
T 1114             if(is_link($vhost_symlink)) {
1115                 unlink($vhost_symlink);
1116                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1117             }
1118             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['old']['domain'].'.vhost');
1119             if(is_link($vhost_symlink)) {
1120                 unlink($vhost_symlink);
1121                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1122             }
276324 1123             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/'.$data['old']['domain'].'.vhost');
T 1124             if(is_link($vhost_symlink)) {
1125                 unlink($vhost_symlink);
1126                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1127             }
fb3339 1128             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/'.$data['old']['domain'].'.vhost');
46c683 1129             unlink($vhost_file);
fb3339 1130             $app->log('Removing file: '.$vhost_file,LOGLEVEL_DEBUG);
46c683 1131         }
ac933e 1132
46c683 1133         //* Create .htaccess and .htpasswd file for website statistics
fb3339 1134         if(!is_file($data['new']['document_root'].'/web/stats/.htaccess') or $data['old']['document_root'] != $data['new']['document_root']) {
J 1135             if(!is_dir($data['new']['document_root'].'/web/stats')) mkdir($data['new']['document_root'].'/web/stats');
1136             $ht_file = "AuthType Basic\nAuthName \"Members Only\"\nAuthUserFile ".$data['new']['document_root']."/.htpasswd_stats\nrequire valid-user";
1137             file_put_contents($data['new']['document_root'].'/web/stats/.htaccess',$ht_file);
1138             chmod($data['new']['document_root'].'/web/stats/.htaccess',0755);
46c683 1139             unset($ht_file);
T 1140         }
ac933e 1141
fb3339 1142         if(!is_file($data['new']['document_root'].'/.htpasswd_stats') || $data['new']['stats_password'] != $data['old']['stats_password']) {
J 1143             if(trim($data['new']['stats_password']) != '') {
1144                 $htp_file = 'admin:'.trim($data['new']['stats_password']);
1145                 file_put_contents($data['new']['document_root'].'/.htpasswd_stats',$htp_file);
1146                 chmod($data['new']['document_root'].'/.htpasswd_stats',0755);
46c683 1147                 unset($htp_file);
T 1148             }
1149         }
58c210 1150         
T 1151         //* Create awstats configuration
fb3339 1152         if($data['new']['stats_type'] == 'awstats' && $data['new']['type'] == 'vhost') {
58c210 1153             $this->awstats_update($data,$web_config);
T 1154         }
7ed741 1155         
T 1156         if($web_config['check_apache_config'] == 'y') {
1157             //* Test if apache starts with the new configuration file
1158             $apache_online_status_before_restart = $this->_checkTcp('localhost',80);
fb3339 1159             $app->log('Apache status is: '.$apache_online_status_before_restart,LOGLEVEL_DEBUG);
ac933e 1160
7ed741 1161             $app->services->restartService('httpd','restart');
9f56bd 1162             
T 1163             // wait a few seconds, before we test the apache status again
1164             sleep(2);
7ed741 1165         
T 1166             //* Check if apache restarted successfully if it was online before
1167             $apache_online_status_after_restart = $this->_checkTcp('localhost',80);
fb3339 1168             $app->log('Apache online status after restart is: '.$apache_online_status_after_restart,LOGLEVEL_DEBUG);
7ed741 1169             if($apache_online_status_before_restart && !$apache_online_status_after_restart) {
fb3339 1170                 $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 1171                 copy($vhost_file,$vhost_file.'.err');
84710d 1172                 if(is_file($vhost_file.'~')) {
T 1173                     //* Copy back the last backup file
1174                     copy($vhost_file.'~',$vhost_file);
1175                 } else {
1176                     //* There is no backup file, so we create a empty vhost file with a warning message inside
1177                     file_put_contents($vhost_file,"# Apache did not start after modifying this vhost file.\n# Please check file $vhost_file.err for syntax errors.");
1178                 }
7ed741 1179                 $app->services->restartService('httpd','restart');
T 1180             }
c82dc7 1181         } else {
7ed741 1182             //* We do not check the apache config after changes (is faster)
T 1183             if($apache_chrooted) {
1184                 $app->services->restartServiceDelayed('httpd','restart');
1185             } else {
1186                 // request a httpd reload when all records have been processed
1187                 $app->services->restartServiceDelayed('httpd','reload');
1188             }
c82dc7 1189         }
7ed741 1190         
T 1191         // Remove the backup copy of the config file.
9f56bd 1192         if(@is_file($vhost_file.'~')) unlink($vhost_file.'~');
7ed741 1193         
ac933e 1194
da1a7c 1195         //* Unset action to clean it for next processed vhost.
T 1196         $this->action = '';
ac933e 1197
46c683 1198     }
ac933e 1199
46c683 1200     function delete($event_name,$data) {
T 1201         global $app, $conf;
ac933e 1202
46c683 1203         // load the server configuration options
fb3339 1204         $app->uses('getconf');
J 1205         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
ac933e 1206
2bbc4c 1207         //* Check if this is a chrooted setup
4b72c5 1208         if($web_config['website_basedir'] != '' && @is_file($web_config['website_basedir'].'/etc/passwd')) {
2bbc4c 1209             $apache_chrooted = true;
T 1210         } else {
1211             $apache_chrooted = false;
1212         }
ac933e 1213
fb3339 1214         if($data['old']['type'] != 'vhost' && $data['old']['parent_domain_id'] > 0) {
46c683 1215             //* This is a alias domain or subdomain, so we have to update the website instead
fb3339 1216             $parent_domain_id = intval($data['old']['parent_domain_id']);
J 1217             $tmp = $app->db->queryOneRecord('SELECT * FROM web_domain WHERE domain_id = '.$parent_domain_id." AND active = 'y'");
1218             $data['new'] = $tmp;
1219             $data['old'] = $tmp;
46c683 1220             $this->action = 'update';
T 1221             // just run the update function
1222             $this->update($event_name,$data);
ac933e 1223
46c683 1224         } else {
T 1225             //* This is a website
1226             // Deleting the vhost file, symlink and the data directory
fb3339 1227             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/'.$data['old']['domain'].'.vhost');
f3b669 1228             
F 1229             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/'.$data['old']['domain'].'.vhost');
1230             if(is_link($vhost_symlink)){
1231                 unlink($vhost_symlink);
1232                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1233             }
1234             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/900-'.$data['old']['domain'].'.vhost');
1235             if(is_link($vhost_symlink)){
1236                 unlink($vhost_symlink);
1237                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1238             }
1239             $vhost_symlink = escapeshellcmd($web_config['vhost_conf_enabled_dir'].'/100-'.$data['old']['domain'].'.vhost');
1240             if(is_link($vhost_symlink)){
1241                 unlink($vhost_symlink);
1242                 $app->log('Removing symlink: '.$vhost_symlink.'->'.$vhost_file,LOGLEVEL_DEBUG);
1243             }
1244             
46c683 1245             unlink($vhost_file);
fb3339 1246             $app->log('Removing vhost file: '.$vhost_file,LOGLEVEL_DEBUG);
ac933e 1247
fb3339 1248             $docroot = escapeshellcmd($data['old']['document_root']);
J 1249             if($docroot != '' && !stristr($docroot,'..')) exec('rm -rf '.$docroot);
ac933e 1250
V 1251
46c683 1252             //remove the php fastgi starter script if available
fb3339 1253             if ($data['old']['php'] == 'fast-cgi') {
J 1254                 $fastcgi_starter_path = str_replace('[system_user]',$data['old']['system_user'],$web_config['fastcgi_starter_path']);
ac933e 1255                 if (is_dir($fastcgi_starter_path)) {
fb3339 1256                     exec('rm -rf '.$fastcgi_starter_path);
46c683 1257                 }
T 1258             }
ac933e 1259
46c683 1260             //remove the php cgi starter script if available
fb3339 1261             if ($data['old']['php'] == 'cgi') {
46c683 1262                 // TODO: fetch the date from the server-settings
fb3339 1263                 $web_config['cgi_starter_path'] = $web_config['website_basedir'].'/php-cgi-scripts/[system_user]/';
46c683 1264
fb3339 1265                 $cgi_starter_path = str_replace('[system_user]',$data['old']['system_user'],$web_config['cgi_starter_path']);
ac933e 1266                 if (is_dir($cgi_starter_path)) {
fb3339 1267                     exec('rm -rf '.$cgi_starter_path);
46c683 1268                 }
T 1269             }
1270
fb3339 1271             $app->log('Removing website: '.$docroot,LOGLEVEL_DEBUG);
ac933e 1272
46c683 1273             // Delete the symlinks for the sites
fb3339 1274             $client = $app->db->queryOneRecord('SELECT client_id FROM sys_group WHERE sys_group.groupid = '.intval($data['old']['sys_groupid']));
J 1275             $client_id = intval($client['client_id']);
46c683 1276             unset($client);
fb3339 1277             $tmp_symlinks_array = explode(':',$web_config['website_symlinks']);
46c683 1278             if(is_array($tmp_symlinks_array)) {
T 1279                 foreach($tmp_symlinks_array as $tmp_symlink) {
fb3339 1280                     $tmp_symlink = str_replace('[client_id]',$client_id,$tmp_symlink);
J 1281                     $tmp_symlink = str_replace('[website_domain]',$data['old']['domain'],$tmp_symlink);
46c683 1282                     // Remove trailing slash
T 1283                     if(substr($tmp_symlink, -1, 1) == '/') $tmp_symlink = substr($tmp_symlink, 0, -1);
1284                     // create the symlinks, if not exist
1285                     if(is_link($tmp_symlink)) {
1286                         unlink($tmp_symlink);
fb3339 1287                         $app->log('Removing symlink: '.$tmp_symlink,LOGLEVEL_DEBUG);
46c683 1288                     }
T 1289                 }
1290             }
1291             // end removing symlinks
ac933e 1292
46c683 1293             // Delete the log file directory
fb3339 1294             $vhost_logfile_dir = escapeshellcmd('/var/log/ispconfig/httpd/'.$data['old']['domain']);
J 1295             if($data['old']['domain'] != '' && !stristr($vhost_logfile_dir,'..')) exec('rm -rf '.$vhost_logfile_dir);
1296             $app->log('Removing website logfile directory: '.$vhost_logfile_dir,LOGLEVEL_DEBUG);
ac933e 1297
46c683 1298             //delete the web user
T 1299             $command = 'userdel';
fb3339 1300             $command .= ' '.$data['old']['system_user'];
46c683 1301             exec($command);
fb3339 1302             if($apache_chrooted) $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' '.$command);
58c210 1303             
T 1304             //* Remove the awstats configuration file
fb3339 1305             if($data['old']['stats_type'] == 'awstats') {
58c210 1306                 $this->awstats_delete($data,$web_config);
T 1307             }
f3b669 1308             
F 1309             if($apache_chrooted) {
1310                 $app->services->restartServiceDelayed('httpd','restart');
1311             } else {
1312                 // request a httpd reload when all records have been processed
1313                 $app->services->restartServiceDelayed('httpd','reload');
1314             }
ac933e 1315
46c683 1316         }
T 1317     }
ac933e 1318
46c683 1319     //* This function is called when a IP on the server is inserted, updated or deleted
T 1320     function server_ip($event_name,$data) {
1321         global $app, $conf;
ac933e 1322
46c683 1323         // load the server configuration options
fb3339 1324         $app->uses('getconf');
J 1325         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
ac933e 1326
46c683 1327         $app->load('tpl');
ac933e 1328
46c683 1329         $tpl = new tpl();
fb3339 1330         $tpl->newTemplate('apache_ispconfig.conf.master');
J 1331         $records = $app->db->queryAllRecords('SELECT * FROM server_ip WHERE server_id = '.$conf['server_id']." AND virtualhost = 'y'");
a2156e 1332         
T 1333         $records_out= array();
1334         if(is_array($records)) {
1335             foreach($records as $rec) {
1336                 if($rec['ip_type'] == 'IPv6') {
1337                     $ip_address = '['.$rec['ip_address'].']';
1338                 } else {
1339                     $ip_address = $rec['ip_address'];
1340                 }
1341                 $ports = explode(',',$rec['virtualhost_port']);
1342                 if(is_array($ports)) {
1343                     foreach($ports as $port) {
1344                         $port = intval($port);
1345                         if($port > 0 && $port < 65536 && $ip_address != '') {
1346                             $records_out[] = array('ip_address' => $ip_address, 'port' => $port);
1347                         }
1348                     }
1349                 }
1350             }
1351         }
1352         
1353         
1354         if(count($records_out) > 0) {
1355             $tpl->setLoop('ip_adresses',$records_out);
46c683 1356         }
ac933e 1357
fb3339 1358         $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'].'/ispconfig.conf');
46c683 1359         file_put_contents($vhost_file,$tpl->grab());
fb3339 1360         $app->log('Writing the conf file: '.$vhost_file,LOGLEVEL_DEBUG);
46c683 1361         unset($tpl);
ac933e 1362
46c683 1363     }
524077 1364     
T 1365     //* Create or update the .htaccess folder protection
1366     function web_folder_user($event_name,$data) {
1367         global $app, $conf;
c69439 1368
524077 1369         $app->uses('system');
T 1370         
1371         if($event_name == 'web_folder_user_delete') {
1372             $folder_id = $data['old']['web_folder_id'];
1373         } else {
1374             $folder_id = $data['new']['web_folder_id'];
1375         }
1376         
1377         $folder = $app->db->queryOneRecord("SELECT * FROM web_folder WHERE web_folder_id = ".intval($folder_id));
1378         $website = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".intval($folder['parent_domain_id']));
1379         
1380         if(!is_array($folder) or !is_array($website)) {
1381             $app->log('Not able to retrieve folder or website record.',LOGLEVEL_DEBUG);
1382             return false;
1383         }
1384         
1385         //* Get the folder path.
c69439 1386         if(substr($folder['path'],0,1) == '/') $folder['path'] = substr($folder['path'],1);
T 1387         if(substr($folder['path'],-1) == '/') $folder['path'] = substr($folder['path'],0,-1);
1388         $folder_path = escapeshellcmd($website['document_root'].'/web/'.$folder['path']);
8f08b5 1389         if(substr($folder_path,-1) != '/') $folder_path .= '/';
524077 1390         
T 1391         //* Check if the resulting path is inside the docroot
c69439 1392         if(stristr($folder_path,'..') || stristr($folder_path,'./') || stristr($folder_path,'\\')) {
T 1393             $app->log('Folder path "'.$folder_path.'" contains .. or ./.',LOGLEVEL_DEBUG);
524077 1394             return false;
T 1395         }
1396         
1397         //* Create the folder path, if it does not exist
053547 1398         if(!is_dir($folder_path)) {
T 1399             exec('mkdir -p '.$folder_path);
1400             chown($folder_path,$website['system_user']);
1401             chgrp($folder_path,$website['system_group']);
1402         }
524077 1403         
T 1404         //* Create empty .htpasswd file, if it does not exist
1405         if(!is_file($folder_path.'.htpasswd')) {
1406             touch($folder_path.'.htpasswd');
1407             chmod($folder_path.'.htpasswd',0755);
053547 1408             chown($folder_path.'.htpasswd',$website['system_user']);
T 1409             chgrp($folder_path.'.htpasswd',$website['system_group']);
900a38 1410             $app->log('Created file '.$folder_path.'.htpasswd',LOGLEVEL_DEBUG);
524077 1411         }
T 1412         
0ea045 1413         /*
F 1414         $auth_users = $app->db->queryAllRecords("SELECT * FROM web_folder_user WHERE active = 'y' AND web_folder_id = ".intval($folder_id));
1415         $htpasswd_content = '';
1416         if(is_array($auth_users) && !empty($auth_users)){
1417             foreach($auth_users as $auth_user){
1418                 $htpasswd_content .= $auth_user['username'].':'.$auth_user['password']."\n";
1419             }
1420         }
1421         $htpasswd_content = trim($htpasswd_content);
1422         @file_put_contents($folder_path.'.htpasswd', $htpasswd_content);
1423         $app->log('Changed .htpasswd file: '.$folder_path.'.htpasswd',LOGLEVEL_DEBUG);
1424         */
1425         
1426         if(($data['new']['username'] != $data['old']['username'] || $data['new']['active'] == 'n') && $data['old']['username'] != '') {
c69439 1427             $app->system->removeLine($folder_path.'.htpasswd',$data['old']['username'].':');
T 1428             $app->log('Removed user: '.$data['old']['username'],LOGLEVEL_DEBUG);
1429         }
1430         
524077 1431         //* Add or remove the user from .htpasswd file
T 1432         if($event_name == 'web_folder_user_delete') {
c69439 1433             $app->system->removeLine($folder_path.'.htpasswd',$data['old']['username'].':');
T 1434             $app->log('Removed user: '.$data['old']['username'],LOGLEVEL_DEBUG);
524077 1435         } else {
c69439 1436             if($data['new']['active'] == 'y') {
T 1437                 $app->system->replaceLine($folder_path.'.htpasswd',$data['new']['username'].':',$data['new']['username'].':'.$data['new']['password'],0,1);
1438                 $app->log('Added or updated user: '.$data['new']['username'],LOGLEVEL_DEBUG);
1439             }
524077 1440         }
T 1441         
0ea045 1442         
524077 1443         //* Create the .htaccess file
0ea045 1444         //if(!is_file($folder_path.'.htaccess')) {
524077 1445             $ht_file = "AuthType Basic\nAuthName \"Members Only\"\nAuthUserFile ".$folder_path.".htpasswd\nrequire valid-user";
T 1446             file_put_contents($folder_path.'.htaccess',$ht_file);
053547 1447             chmod($folder_path.'.htaccess',0755);
T 1448             chown($folder_path.'.htaccess',$website['system_user']);
1449             chgrp($folder_path.'.htaccess',$website['system_group']);
900a38 1450             $app->log('Created file '.$folder_path.'.htaccess',LOGLEVEL_DEBUG);
0ea045 1451         //}
524077 1452         
T 1453     }
1454     
1455     //* Remove .htaccess and .htpasswd file, when folder protection is removed
1456     function web_folder_delete($event_name,$data) {
1457         global $app, $conf;
1458         
1459         $folder_id = $data['old']['web_folder_id'];
1460         
219bb4 1461         $folder = $data['old'];
524077 1462         $website = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".intval($folder['parent_domain_id']));
T 1463         
1464         if(!is_array($folder) or !is_array($website)) {
1465             $app->log('Not able to retrieve folder or website record.',LOGLEVEL_DEBUG);
1466             return false;
1467         }
1468         
1469         //* Get the folder path.
0ea045 1470         if(substr($folder['path'],0,1) == '/') $folder['path'] = substr($folder['path'],1);
F 1471         if(substr($folder['path'],-1) == '/') $folder['path'] = substr($folder['path'],0,-1);
524077 1472         $folder_path = realpath($website['document_root'].'/web/'.$folder['path']);
8f08b5 1473         if(substr($folder_path,-1) != '/') $folder_path .= '/';
524077 1474         
T 1475         //* Check if the resulting path is inside the docroot
1476         if(substr($folder_path,0,strlen($website['document_root'])) != $website['document_root']) {
1477             $app->log('Folder path is outside of docroot.',LOGLEVEL_DEBUG);
1478             return false;
1479         }
1480         
1481         //* Remove .htpasswd file
1482         if(is_file($folder_path.'.htpasswd')) {
1483             unlink($folder_path.'.htpasswd');
900a38 1484             $app->log('Removed file '.$folder_path.'.htpasswd',LOGLEVEL_DEBUG);
524077 1485         }
T 1486         
1487         //* Remove .htaccess file
1488         if(is_file($folder_path.'.htaccess')) {
1489             unlink($folder_path.'.htaccess');
900a38 1490             $app->log('Removed file '.$folder_path.'.htaccess',LOGLEVEL_DEBUG);
524077 1491         }
2023a7 1492     }
T 1493     
1494     //* Update folder protection, when path has been changed
1495     function web_folder_update($event_name,$data) {
1496         global $app, $conf;
1497         
1498         $website = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".intval($data['new']['parent_domain_id']));
1499     
1500         if(!is_array($website)) {
1501             $app->log('Not able to retrieve folder or website record.',LOGLEVEL_DEBUG);
1502             return false;
1503         }
1504         
1505         //* Get the folder path.
0ea045 1506         if(substr($data['old']['path'],0,1) == '/') $data['old']['path'] = substr($data['old']['path'],1);
F 1507         if(substr($data['old']['path'],-1) == '/') $data['old']['path'] = substr($data['old']['path'],0,-1);
2023a7 1508         $old_folder_path = realpath($website['document_root'].'/web/'.$data['old']['path']);
8f08b5 1509         if(substr($old_folder_path,-1) != '/') $old_folder_path .= '/';
2023a7 1510             
0ea045 1511         if(substr($data['new']['path'],0,1) == '/') $data['new']['path'] = substr($data['new']['path'],1);
F 1512         if(substr($data['new']['path'],-1) == '/') $data['new']['path'] = substr($data['new']['path'],0,-1);
2023a7 1513         $new_folder_path = escapeshellcmd($website['document_root'].'/web/'.$data['new']['path']);
8f08b5 1514         if(substr($new_folder_path,-1) != '/') $new_folder_path .= '/';
2023a7 1515         
T 1516         //* Check if the resulting path is inside the docroot
1517         if(stristr($new_folder_path,'..') || stristr($new_folder_path,'./') || stristr($new_folder_path,'\\')) {
1518             $app->log('Folder path "'.$new_folder_path.'" contains .. or ./.',LOGLEVEL_DEBUG);
1519             return false;
1520         }
1521         if(stristr($old_folder_path,'..') || stristr($old_folder_path,'./') || stristr($old_folder_path,'\\')) {
1522             $app->log('Folder path "'.$old_folder_path.'" contains .. or ./.',LOGLEVEL_DEBUG);
1523             return false;
1524         }
1525         
1526         //* Check if the resulting path is inside the docroot
1527         if(substr($old_folder_path,0,strlen($website['document_root'])) != $website['document_root']) {
1528             $app->log('Old folder path '.$old_folder_path.' is outside of docroot.',LOGLEVEL_DEBUG);
1529             return false;
1530         }
1531         if(substr($new_folder_path,0,strlen($website['document_root'])) != $website['document_root']) {
1532             $app->log('New folder path '.$new_folder_path.' is outside of docroot.',LOGLEVEL_DEBUG);
1533             return false;
1534         }
1535             
1536         //* Create the folder path, if it does not exist
1537         if(!is_dir($new_folder_path)) exec('mkdir -p '.$new_folder_path);
1538         
1539         if($data['old']['path'] != $data['new']['path']) {
1540
1541         
1542             //* move .htpasswd file
1543             if(is_file($old_folder_path.'.htpasswd')) {
1544                 rename($old_folder_path.'.htpasswd',$new_folder_path.'.htpasswd');
0ea045 1545                 $app->log('Moved file '.$old_folder_path.'.htpasswd to '.$new_folder_path.'.htpasswd',LOGLEVEL_DEBUG);
2023a7 1546             }
T 1547             
0ea045 1548             //* delete old .htaccess file
2023a7 1549             if(is_file($old_folder_path.'.htaccess')) {
0ea045 1550                 unlink($old_folder_path.'.htaccess');
F 1551                 $app->log('Deleted file '.$old_folder_path.'.htaccess',LOGLEVEL_DEBUG);
2023a7 1552             }
T 1553         
1554         }
1555         
1556         //* Create the .htaccess file
0ea045 1557         if($data['new']['active'] == 'y') {
F 1558             $ht_file = "AuthType Basic\nAuthName \"Members Only\"\nAuthUserFile ".$new_folder_path.".htpasswd\nrequire valid-user";
2023a7 1559             file_put_contents($new_folder_path.'.htaccess',$ht_file);
T 1560             chmod($new_folder_path.'.htpasswd',0755);
053547 1561             chown($folder_path.'.htpasswd',$website['system_user']);
T 1562             chgrp($folder_path.'.htpasswd',$website['system_group']);
1563             $app->log('Created file '.$new_folder_path.'.htpasswd',LOGLEVEL_DEBUG);
2023a7 1564         }
T 1565         
1566         //* Remove .htaccess file
1567         if($data['new']['active'] == 'n' && is_file($new_folder_path.'.htaccess')) {
1568             unlink($new_folder_path.'.htaccess');
900a38 1569             $app->log('Removed file '.$new_folder_path.'.htaccess',LOGLEVEL_DEBUG);
2023a7 1570         }
524077 1571         
T 1572         
1573     }
ac933e 1574
V 1575     /**
1576      * This function is called when a Webdav-User is inserted, updated or deleted.
1577      *
1578      * @author Oliver Vogel
1579      * @param string $event_name
1580      * @param array $data
1581      */
1582     public function webdav($event_name,$data) {
1583         global $app, $conf;
52a04e 1584         
T 1585         /*
1586          * load the server configuration options
1587         */
fb3339 1588         $app->uses('getconf');
J 1589         $web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
ac933e 1590
V 1591         if (($event_name == 'webdav_user_insert') || ($event_name == 'webdav_user_update')) {
1592
1593             /*
1594              * Get additional informations
1595             */
fb3339 1596             $sitedata = $app->db->queryOneRecord('SELECT document_root, domain, system_user, system_group FROM web_domain WHERE domain_id = ' . $data['new']['parent_domain_id']);
ac933e 1597             $documentRoot = $sitedata['document_root'];
V 1598             $domain = $sitedata['domain'];
ca14fe 1599             $user = $sitedata['system_user'];
V 1600             $group = $sitedata['system_group'];
835c5d 1601             $webdav_user_dir = $documentRoot . '/webdav/' . $data['new']['dir'];
ac933e 1602
V 1603             /* Check if this is a chrooted setup */
1604             if($web_config['website_basedir'] != '' && @is_file($web_config['website_basedir'].'/etc/passwd')) {
1605                 $apache_chrooted = true;
fb3339 1606                 $app->log('Info: Apache is chrooted.',LOGLEVEL_DEBUG);
ac933e 1607             } else {
V 1608                 $apache_chrooted = false;
1609             }
835c5d 1610             
T 1611             //* We dont want to have relative paths here
1612             if(stristr($webdav_user_dir,'..')  || stristr($webdav_user_dir,'./')) {
1613                 $app->log('Folder path '.$webdav_user_dir.' contains ./ or .. '.$documentRoot,LOGLEVEL_WARN);
1614                 return false;
1615             }
1616             
1617             //* Check if the resulting path exists if yes, if it is inside the docroot
1618             if(is_dir($webdav_user_dir) && substr(realpath($webdav_user_dir),0,strlen($documentRoot)) != $documentRoot) {
1619                 $app->log('Folder path '.$webdav_user_dir.' is outside of docroot '.$documentRoot,LOGLEVEL_WARN);
1620                 return false;
1621             }
ac933e 1622
V 1623             /*
1624              * First the webdav-root - folder has to exist
1625             */
835c5d 1626             if(!is_dir($webdav_user_dir)) {
T 1627                 $app->log('Webdav User directory '.$webdav_user_dir.' does not exist. Creating it now.',LOGLEVEL_DEBUG);
1628                 exec('mkdir -p '.escapeshellcmd($webdav_user_dir));
ac933e 1629             }
V 1630
1631             /*
ca14fe 1632              * The webdav - Root needs the group/user as owner and the apache as read and write
ac933e 1633             */
fb3339 1634             $this->_exec('chown ' . $user . ':' . $group . ' ' . escapeshellcmd($documentRoot . '/webdav/'));
J 1635             $this->_exec('chmod 770 ' . escapeshellcmd($documentRoot . '/webdav/'));
ac933e 1636
V 1637             /*
ca14fe 1638              * The webdav folder (not the webdav-root!) needs the same (not in ONE step, because the
V 1639              * pwd-files are owned by root)
ac933e 1640             */
835c5d 1641             $this->_exec('chown ' . $user . ':' . $group . ' ' . escapeshellcmd($webdav_user_dir.' -R'));
T 1642             $this->_exec('chmod 770 ' . escapeshellcmd($webdav_user_dir.' -R'));
ca14fe 1643
V 1644             /*
1645              * if the user is active, we have to write/update the password - file
1646              * if the user is inactive, we have to inactivate the user by removing the user from the file
1647             */
1648             if ($data['new']['active'] == 'y') {
835c5d 1649                 $this->_writeHtDigestFile( $webdav_user_dir . '.htdigest', $data['new']['username'], $data['new']['dir'], $data['new']['password']);
ca14fe 1650             }
V 1651             else {
1652                 /* empty pwd removes the user! */
835c5d 1653                 $this->_writeHtDigestFile( $webdav_user_dir . '.htdigest', $data['new']['username'], $data['new']['dir'], '');
ca14fe 1654             }
ac933e 1655
V 1656             /*
1657              * Next step, patch the vhost - file
1658             */
fb3339 1659             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'] . '/' . $domain . '.vhost');
ac933e 1660             $this->_patchVhostWebdav($vhost_file, $documentRoot . '/webdav');
ca14fe 1661
ac933e 1662             /*
V 1663              * Last, restart apache
1664             */
1665             if($apache_chrooted) {
1666                 $app->services->restartServiceDelayed('httpd','restart');
1667             } else {
1668                 // request a httpd reload when all records have been processed
1669                 $app->services->restartServiceDelayed('httpd','reload');
1670             }
1671
1672         }
1673
1674         if ($event_name == 'webdav_user_delete') {
1675             /*
1676              * Get additional informations
1677             */
fb3339 1678             $sitedata = $app->db->queryOneRecord('SELECT document_root, domain FROM web_domain WHERE domain_id = ' . $data['old']['parent_domain_id']);
ac933e 1679             $documentRoot = $sitedata['document_root'];
52a04e 1680             $domain = $sitedata['domain'];
ac933e 1681
V 1682             /*
1683              * We dont't want to destroy any (transfer)-Data. So we do NOT delete any dir.
1684              * So the only thing, we have to do, is to delete the user from the password-file
ca14fe 1685             */
ac933e 1686             $this->_writeHtDigestFile( $documentRoot . '/webdav/' . $data['old']['dir'] . '.htdigest', $data['old']['username'], $data['old']['dir'], '');
52a04e 1687             
T 1688             /*
1689              * Next step, patch the vhost - file
1690             */
fb3339 1691             $vhost_file = escapeshellcmd($web_config['vhost_conf_dir'] . '/' . $domain . '.vhost');
52a04e 1692             $this->_patchVhostWebdav($vhost_file, $documentRoot . '/webdav');
T 1693             
1694             /*
1695              * Last, restart apache
1696             */
1697             if($apache_chrooted) {
1698                 $app->services->restartServiceDelayed('httpd','restart');
1699             } else {
1700                 // request a httpd reload when all records have been processed
1701                 $app->services->restartServiceDelayed('httpd','reload');
1702             }
ac933e 1703         }
V 1704     }
1705
1706
1707     /**
1708      * This function writes the htdigest - files used by webdav and digest
ca14fe 1709      * more info: see http://riceball.com/d/node/424
ac933e 1710      * @author Oliver Vogel
V 1711      * @param string $filename The name of the digest-file
1712      * @param string $username The name of the webdav-user
1713      * @param string $authname The name of the realm
ca14fe 1714      * @param string $pwd      The password-hash of the user
ac933e 1715      */
ca14fe 1716     private function _writeHtDigestFile($filename, $username, $authname, $pwdhash ) {
ac933e 1717         $changed = false;
0ff3f1 1718         if(is_file($filename)) {
T 1719             $in = fopen($filename, 'r');
1720             $output = '';
1721             /*
1722             * read line by line and search for the username and authname
1723             */
1724             while (preg_match("/:/", $line = fgets($in))) {
1725                 $line = rtrim($line);
1726                 $tmp = explode(':', $line);
1727                 if ($tmp[0] == $username && $tmp[1] == $authname) {
1728                     /*
1729                     * found the user. delete or change it?
1730                     */
1731                     if ($pwdhash != '') {
1732                         $output .= $tmp[0] . ':' . $tmp[1] . ':' . $pwdhash . "\n";
1733                         }
1734                     $changed = true;
1735                 }
1736                 else {
1737                     $output .= $line . "\n";
1738                 }
ac933e 1739             }
0ff3f1 1740             fclose($in);
ac933e 1741         }
V 1742         /*
1743          * if we didn't change anything, we have to add the new user at the end of the file
1744         */
1745         if (!$changed) {
f17dab 1746             $output .= $username . ':' . $authname . ':' . $pwdhash . "\n";
ac933e 1747         }
0ff3f1 1748         
ac933e 1749
V 1750         /*
1751          * Now lets write the new file
1752         */
52a04e 1753         if(trim($output) == '') {
T 1754             unlink($filename);
1755         } else {
1756             file_put_contents($filename, $output);
1757         }
ac933e 1758     }
V 1759
1760     /**
1761      * This function patches the vhost-file and adds all webdav - user.
1762      * This function is written, because the creation of the vhost - file is sophisticated and
1763      * i don't want to make it more "heavy" by also adding this code too...
1764      * @author Oliver Vogel
1765      * @param string $fileName The Name of the .vhost-File (path included)
1766      * @param string $webdavRoot The root of the webdav-folder
1767      */
1768     private function _patchVhostWebdav($fileName, $webdavRoot) {
1769         $in = fopen($fileName, 'r');
1770         $output = '';
1771         $inWebdavSection = false;
1772
1773         /*
1774          * read line by line and search for the username and authname
1775         */
1776         while ($line = fgets($in)) {
1777             /*
1778              *  is the "replace-comment" found...
1779             */
1780             if (trim($line) == '# WEBDAV BEGIN') {
1781                 /*
1782                  * The begin of the webdav - section is found, so ignore all lines til the end  is found
1783                 */
1784                 $inWebdavSection = true;
1785
1786                 $output .= "      # WEBDAV BEGIN\n";
1787
1788                 /*
1789                  * add all the webdav-dirs to the webdav-section
1790                 */
fb3a98 1791                 $files = @scandir($webdavRoot);
T 1792                 if(is_array($files)) {
ac933e 1793                 foreach($files as $file) {
V 1794                     if (substr($file, strlen($file) - strlen('.htdigest')) == '.htdigest') {
1795                         /*
1796                          * found a htdigest - file, so add it to webdav
1797                         */
1798                         $fn = substr($file, 0, strlen($file) - strlen('.htdigest'));
1799                         $output .= "\n";
dd1afa 1800                         // $output .= "      Alias /" . $fn . ' ' . $webdavRoot . '/' . $fn . "\n";
T 1801                         // $output .= "      <Location /" . $fn . ">\n";
9f56bd 1802                         $output .= "      Alias /webdav/" . $fn . ' ' . $webdavRoot . '/' . $fn . "\n";
T 1803                         $output .= "      <Location /webdav/" . $fn . ">\n";
ac933e 1804                         $output .= "        DAV On\n";
91aaaf 1805                         $output .= '        BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On'."\n";
ac933e 1806                         $output .= "        AuthType Digest\n";
V 1807                         $output .= "        AuthName \"" . $fn . "\"\n";
fb3339 1808                         $output .= "        AuthUserFile " . $webdavRoot . '/' . $file . "\n";
ac933e 1809                         $output .= "        Require valid-user \n";
V 1810                         $output .= "        Options +Indexes \n";
1811                         $output .= "        Order allow,deny \n";
1812                         $output .= "        Allow from all \n";
1813                         $output .= "      </Location> \n";
1814                     }
1815                 }
fb3a98 1816                 }
ac933e 1817             }
V 1818             /*
1819              *  is the "replace-comment-end" found...
1820             */
1821             if (trim($line) == '# WEBDAV END') {
1822                 /*
1823                  * The end of the webdav - section is found, so stop ignoring
1824                 */
1825                 $inWebdavSection = false;
1826             }
1827
1828             /*
1829              * Write the line to the output, if it is not in the section
1830             */
1831             if (!$inWebdavSection) {
1832                 $output .= $line;
1833             }
1834         }
1835         fclose($in);
1836
1837         /*
1838          * Now lets write the new file
1839         */
1840         file_put_contents($fileName, $output);
1841
1842     }
58c210 1843     
T 1844     //* Update the awstats configuration file
1845     private function awstats_update ($data,$web_config) {
1846         global $app;
1847         
2a6eac 1848         $awstats_conf_dir = $web_config['awstats_conf_dir'];
T 1849         
b10f96 1850         if(!is_dir($data['new']['document_root']."/web/stats/")) mkdir($data['new']['document_root']."/web/stats");
fb3339 1851         if(!@is_file($awstats_conf_dir.'/awstats.'.$data['new']['domain'].'.conf') || ($data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain'])) {
J 1852             if ( @is_file($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf') ) {
1853                 unlink($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf');
58c210 1854             }
T 1855             
1856             $content = '';
2a6eac 1857             $content .= "Include \"".$awstats_conf_dir."/awstats.conf\"\n";
fb3339 1858             $content .= "LogFile=\"/var/log/ispconfig/httpd/".$data['new']['domain']."/access.log\"\n";
J 1859             $content .= "SiteDomain=\"".$data['new']['domain']."\"\n";
1860             $content .= "HostAliases=\"www.".$data['new']['domain']."  localhost 127.0.0.1\"\n";
58c210 1861             
fb3339 1862             file_put_contents($awstats_conf_dir.'/awstats.'.$data['new']['domain'].'.conf',$content);
J 1863             $app->log('Created AWStats config file: '.$awstats_conf_dir.'/awstats.'.$data['new']['domain'].'.conf',LOGLEVEL_DEBUG);
58c210 1864         }
d81a4c 1865         
3498f7 1866         if(is_file($data['new']['document_root']."/web/stats/index.html")) unlink($data['new']['document_root']."/web/stats/index.html");
d81a4c 1867         copy("/usr/local/ispconfig/server/conf/awstats_index.php.master",$data['new']['document_root']."/web/stats/index.php");
58c210 1868     }
T 1869     
1870     //* Delete the awstats configuration file
1871     private function awstats_delete ($data,$web_config) {
1872         global $app;
1873         
1874         $awstats_conf_dir = $web_config['awstats_conf_dir'];
1875         
fb3339 1876         if ( @is_file($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf') ) {
J 1877             unlink($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf');
1878             $app->log('Removed AWStats config file: '.$awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf',LOGLEVEL_DEBUG);
58c210 1879         }
T 1880     }
1ca823 1881     
T 1882     function client_delete($event_name,$data) {
1883         global $app, $conf;
1884         
1885         $app->uses("getconf");
1886         $web_config = $app->getconf->get_server_config($conf["server_id"], 'web');
1887         
1888         $client_id = intval($data['old']['client_id']);
1889         if($client_id > 0) {
1890             
1891             $client_dir = $web_config['website_basedir'].'/clients/client'.$client_id;
1892             if(is_dir($client_dir) && !stristr($client_dir,'..')) {
1893                 @rmdir($client_dir);
1894                 $app->log('Removed client directory: '.$client_dir,LOGLEVEL_DEBUG);
1895             }
1896             
1897             $this->_exec('groupdel client'.$client_id);
1898             $app->log('Removed group client'.$client_id,LOGLEVEL_DEBUG);
1899         }
1900         
1901     }
ac933e 1902
1c40af 1903     //* Wrapper for exec function for easier debugging
T 1904     private function _exec($command) {
1905         global $app;
fb3339 1906         $app->log('exec: '.$command,LOGLEVEL_DEBUG);
1c40af 1907         exec($command);
T 1908     }
7ed741 1909     
T 1910     private function _checkTcp ($host,$port) {
1911
1912         $fp = @fsockopen ($host, $port, $errno, $errstr, 2);
1913
1914         if ($fp) {
1915             fclose($fp);
1916             return true;
1917         } else {
1918             return false;
1919         }
1920     }
ac933e 1921
552178 1922     public function create_relative_link($f, $t) {
M 1923         // $from already exists
1924         $from = realpath($f);
1925
1926         // realpath requires the traced file to exist - so, lets touch it first, then remove
1927         @unlink($t); touch($t);
1928         $to = realpath($t);
1929         @unlink($t);
1930
1931         // Remove from the left side matching path elements from $from and $to
1932         // and get path elements counts
1933         $a1 = explode('/', $from); $a2 = explode('/', $to);
1934         for ($c = 0; $a1[$c] == $a2[$c]; $c++) {
1935             unset($a1[$c]); unset($a2[$c]);
1936         }
1937         $cfrom = implode('/', $a1);
1938
1939         // Check if a path is fully a subpath of another - no way to create symlink in the case
1940         if (count($a1) == 0 || count($a2) == 0) return false;
1941
1942         // Add ($cnt_to-1) number of "../" elements to left side of $cfrom
1943         for ($c = 0; $c < (count($a2)-1); $c++) { $cfrom = '../'.$cfrom; }
1944
1945         return symlink($cfrom, $to);
1946     }
46c683 1947
T 1948 } // end class
1949
1c711c 1950 ?>