Till Brehm
2014-08-14 c653844975fb13bf7aaf2cc0dc96c8c70906394e
commit | author | age
396f0e 1 <?php
T 2
3 /*
4 Copyright (c) 2007, 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 shelluser_jailkit_plugin {
7fe908 32
396f0e 33     //* $plugin_name and $class_name have to be the same then the name of this class
T 34     var $plugin_name = 'shelluser_jailkit_plugin';
35     var $class_name = 'shelluser_jailkit_plugin';
b79d24 36     var $min_uid = 499;
7fe908 37
396f0e 38     //* This function is called during ispconfig installation to determine
T 39     //  if a symlink shall be created for this plugin.
40     function onInstall() {
41         global $conf;
7fe908 42
396f0e 43         if($conf['services']['web'] == true) {
T 44             return true;
45         } else {
46             return false;
47         }
7fe908 48
396f0e 49     }
7fe908 50
MC 51
396f0e 52     /*
T 53          This function is called when the plugin is loaded
54     */
7fe908 55
396f0e 56     function onLoad() {
T 57         global $app;
7fe908 58
396f0e 59         /*
T 60         Register for the events
61         */
62
7fe908 63         $app->plugins->registerEvent('shell_user_insert', $this->plugin_name, 'insert');
MC 64         $app->plugins->registerEvent('shell_user_update', $this->plugin_name, 'update');
65         $app->plugins->registerEvent('shell_user_delete', $this->plugin_name, 'delete');
66
67
396f0e 68     }
7fe908 69
396f0e 70     //* This function is called, when a shell user is inserted in the database
7fe908 71     function insert($event_name, $data) {
396f0e 72         global $app, $conf;
7fe908 73
396f0e 74         $app->uses('system');
ff6a68 75         $web = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".$data['new']['parent_domain_id']);
7fe908 76
64ea56 77         if(!$app->system->is_allowed_user($data['new']['username'], false, false)
MC 78             || !$app->system->is_allowed_user($data['new']['puser'], true, true)
79             || !$app->system->is_allowed_group($data['new']['pgroup'], true, true)) {
80             $app->log('Shell user must not be root or in group root.',LOGLEVEL_WARN);
81             return false;
82         }
83
b79d24 84         if($app->system->is_user($data['new']['puser'])) {
FT 85             // Get the UID of the parent user
86             $uid = intval($app->system->getuid($data['new']['puser']));
87             if($uid > $this->min_uid) {
88             
89                 if($app->system->is_user($data['new']['username'])) {
7fe908 90
b79d24 91                     /**
FT 92                     * Setup Jailkit Chroot System If Enabled
93                     */
94
95                     if ($data['new']['chroot'] == "jailkit")
96                     {
7fe908 97
MC 98
b79d24 99                         // load the server configuration options
FT 100                         $app->uses("getconf");
101                         $this->data = $data;
102                         $this->app = $app;
103                         $this->jailkit_config = $app->getconf->get_server_config($conf["server_id"], 'jailkit');
7fe908 104
b79d24 105                         $this->_update_website_security_level();
7fe908 106
b79d24 107                         $app->system->web_folder_protection($web['document_root'], false);
7fe908 108
b79d24 109                         $this->_setup_jailkit_chroot();
7fe908 110
b79d24 111                         $this->_add_jailkit_user();
7fe908 112
b79d24 113                         //* call the ssh-rsa update function
FT 114                         $this->_setup_ssh_rsa();
7fe908 115
b79d24 116                         //$command .= 'usermod -s /usr/sbin/jk_chrootsh -U '.escapeshellcmd($data['new']['username']);
FT 117                         //exec($command);
118                         $app->system->usermod($data['new']['username'], 0, 0, '', '/usr/sbin/jk_chrootsh', '', '');
7fe908 119
b79d24 120                         //* Unlock user
FT 121                         $command = 'usermod -U '.escapeshellcmd($data['new']['username']).' 2>/dev/null';
122                         exec($command);
7fe908 123
b79d24 124                         $this->_update_website_security_level();
FT 125                         $app->system->web_folder_protection($web['document_root'], true);
126                     }
7fe908 127
b79d24 128                     $app->log("Jailkit Plugin -> insert username:".$data['new']['username'], LOGLEVEL_DEBUG);
7fe908 129
b79d24 130                 } else {
FT 131                     $app->log("Jailkit Plugin -> insert username:".$data['new']['username']." skipped, the user does not exist.", LOGLEVEL_WARN);
132                 }
133             } else {
134                 $app->log("UID = $uid for shelluser:".$data['new']['username']." not allowed.", LOGLEVEL_ERROR);
396f0e 135             }
T 136         } else {
b79d24 137             $app->log("Skipping insertion of user:".$data['new']['username'].", parent user ".$data['new']['puser']." does not exist.", LOGLEVEL_WARN);
396f0e 138         }
7fe908 139
396f0e 140     }
7fe908 141
396f0e 142     //* This function is called, when a shell user is updated in the database
7fe908 143     function update($event_name, $data) {
396f0e 144         global $app, $conf;
7fe908 145
396f0e 146         $app->uses('system');
ff6a68 147         $web = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".$data['new']['parent_domain_id']);
7fe908 148
64ea56 149         if(!$app->system->is_allowed_user($data['new']['username'], false, false)
MC 150             || !$app->system->is_allowed_user($data['new']['puser'], true, true)
151             || !$app->system->is_allowed_group($data['new']['pgroup'], true, true)) {
152             $app->log('Shell user must not be root or in group root.',LOGLEVEL_WARN);
153             return false;
154         }
155
b79d24 156         if($app->system->is_user($data['new']['puser'])) {
FT 157             // Get the UID of the parent user
158             $uid = intval($app->system->getuid($data['new']['puser']));
159             if($uid > $this->min_uid) {
160             
161             
162                 if($app->system->is_user($data['new']['username'])) {
7fe908 163
b79d24 164                     /**
FT 165                     * Setup Jailkit Chroot System If Enabled
166                     */
167                     if ($data['new']['chroot'] == "jailkit")
168                     {
7fe908 169
b79d24 170                         // load the server configuration options
FT 171                         $app->uses("getconf");
172                         $this->data = $data;
173                         $this->app = $app;
174                         $this->jailkit_config = $app->getconf->get_server_config($conf["server_id"], 'jailkit');
7fe908 175
b79d24 176                         $this->_update_website_security_level();
7fe908 177
b79d24 178                         $app->system->web_folder_protection($web['document_root'], false);
7fe908 179
b79d24 180                         $this->_setup_jailkit_chroot();
FT 181                         $this->_add_jailkit_user();
7fe908 182
b79d24 183                         //* call the ssh-rsa update function
FT 184                         $this->_setup_ssh_rsa();
7fe908 185
b79d24 186                         $this->_update_website_security_level();
7fe908 187
b79d24 188                         $app->system->web_folder_protection($web['document_root'], true);
FT 189                     }
7fe908 190
b79d24 191                     $app->log("Jailkit Plugin -> update username:".$data['new']['username'], LOGLEVEL_DEBUG);
7fe908 192
b79d24 193                 } else {
FT 194                     $app->log("Jailkit Plugin -> update username:".$data['new']['username']." skipped, the user does not exist.", LOGLEVEL_WARN);
195                 }
196             } else {
197                 $app->log("UID = $uid for shelluser:".$data['new']['username']." not allowed.", LOGLEVEL_ERROR);
396f0e 198             }
T 199         } else {
b79d24 200             $app->log("Skipping update for user:".$data['new']['username'].", parent user ".$data['new']['puser']." does not exist.", LOGLEVEL_WARN);
396f0e 201         }
7fe908 202
396f0e 203     }
7fe908 204
396f0e 205     //* This function is called, when a shell user is deleted in the database
T 206     /**
207      * TODO: Remove chroot user home and from the chroot passwd file
7fe908 208      */
MC 209     function delete($event_name, $data) {
396f0e 210         global $app, $conf;
7fe908 211
396f0e 212         $app->uses('system');
7fe908 213
ff6a68 214         $web = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".$data['old']['parent_domain_id']);
7fe908 215
396f0e 216         if ($data['old']['chroot'] == "jailkit")
T 217         {
218             $app->uses("getconf");
219             $this->jailkit_config = $app->getconf->get_server_config($conf["server_id"], 'jailkit');
7fe908 220
396f0e 221             $jailkit_chroot_userhome = $this->_get_home_dir($data['old']['username']);
7fe908 222
396f0e 223             //commented out proved to be dangerous on config errors
T 224             //exec('rm -rf '.$data['old']['dir'].$jailkit_chroot_userhome);
7fe908 225
MC 226             $app->system->web_folder_protection($web['document_root'], false);
227
396f0e 228             if(@is_dir($data['old']['dir'].$jailkit_chroot_userhome)) {
c65384 229                 $command = 'killall -u '.escapeshellcmd($data['old']['username']).' ; userdel -f';
526b99 230                 $command .= ' '.escapeshellcmd($data['old']['username']).' &> /dev/null';
396f0e 231                 exec($command);
7fe908 232                 $app->log("Jailkit Plugin -> delete chroot home:".$data['old']['dir'].$jailkit_chroot_userhome, LOGLEVEL_DEBUG);
396f0e 233             }
7fe908 234
MC 235             $app->system->web_folder_protection($web['document_root'], true);
236
396f0e 237         }
7fe908 238
MC 239         $app->log("Jailkit Plugin -> delete username:".$data['old']['username'], LOGLEVEL_DEBUG);
240
241
396f0e 242     }
7fe908 243
396f0e 244     function _setup_jailkit_chroot()
T 245     {
7fe908 246         global $app;
MC 247
248         //check if the chroot environment is created yet if not create it with a list of program sections from the config
249         if (!is_dir($this->data['new']['dir'].'/etc/jailkit'))
250         {
251             $command = '/usr/local/ispconfig/server/scripts/create_jailkit_chroot.sh';
252             $command .= ' '.escapeshellcmd($this->data['new']['dir']);
253             $command .= ' \''.$this->jailkit_config['jailkit_chroot_app_sections'].'\'';
254             exec($command.' 2>/dev/null');
255
256             $this->app->log("Added jailkit chroot with command: ".$command, LOGLEVEL_DEBUG);
257
258             $this->_add_jailkit_programs();
259
260             //add bash.bashrc script
261             //we need to collect the domain name to be used as the HOSTNAME in the bashrc script
262             $web = $this->app->db->queryOneRecord("SELECT domain FROM web_domain WHERE domain_id = ".intval($this->data['new']["parent_domain_id"]));
263
264             $this->app->load('tpl');
265
266             $tpl = new tpl();
267             $tpl->newTemplate("bash.bashrc.master");
268
269             $tpl->setVar('jailkit_chroot', true);
270             $tpl->setVar('domain', $web['domain']);
271             $tpl->setVar('home_dir', $this->_get_home_dir(""));
272
273             $bashrc = escapeshellcmd($this->data['new']['dir']).'/etc/bash.bashrc';
274             if(@is_file($bashrc) || @is_link($bashrc)) unlink($bashrc);
275
276             file_put_contents($bashrc, $tpl->grab());
277             unset($tpl);
278
279             $this->app->log("Added bashrc script : ".$bashrc, LOGLEVEL_DEBUG);
280
281             $tpl = new tpl();
282             $tpl->newTemplate("motd.master");
283
284             $tpl->setVar('domain', $web['domain']);
285
286             $motd = escapeshellcmd($this->data['new']['dir']).'/var/run/motd';
287             if(@is_file($motd) || @is_link($motd)) unlink($motd);
288
289             $app->system->file_put_contents($motd, $tpl->grab());
290
291         }
396f0e 292     }
7fe908 293
396f0e 294     function _add_jailkit_programs()
T 295     {
296         //copy over further programs and its libraries
297         $command = '/usr/local/ispconfig/server/scripts/create_jailkit_programs.sh';
298         $command .= ' '.escapeshellcmd($this->data['new']['dir']);
299         $command .= ' \''.$this->jailkit_config['jailkit_chroot_app_programs'].'\'';
526b99 300         exec($command.' 2>/dev/null');
7fe908 301
MC 302         $this->app->log("Added programs to jailkit chroot with command: ".$command, LOGLEVEL_DEBUG);
396f0e 303     }
7fe908 304
396f0e 305     function _get_home_dir($username)
T 306     {
7fe908 307         return str_replace("[username]", escapeshellcmd($username), $this->jailkit_config['jailkit_chroot_home']);
396f0e 308     }
7fe908 309
396f0e 310     function _add_jailkit_user()
T 311     {
7fe908 312         global $app;
MC 313
314         //add the user to the chroot
315         $jailkit_chroot_userhome = $this->_get_home_dir($this->data['new']['username']);
316         $jailkit_chroot_puserhome = $this->_get_home_dir($this->data['new']['puser']);
317
318         if(!is_dir($this->data['new']['dir'].'/etc')) mkdir($this->data['new']['dir'].'/etc', 0755);
319         if(!is_file($this->data['new']['dir'].'/etc/passwd')) touch($this->data['new']['dir'].'/etc/passwd', 0755);
320
321         // IMPORTANT!
322         // ALWAYS create the user. Even if the user was created before
323         // if we check if the user exists, then a update (no shell -> jailkit) will not work
324         // and the user has FULL ACCESS to the root of the server!
325         $command = '/usr/local/ispconfig/server/scripts/create_jailkit_user.sh';
326         $command .= ' '.escapeshellcmd($this->data['new']['username']);
327         $command .= ' '.escapeshellcmd($this->data['new']['dir']);
328         $command .= ' '.$jailkit_chroot_userhome;
329         $command .= ' '.escapeshellcmd($this->data['new']['shell']);
330         $command .= ' '.$this->data['new']['puser'];
331         $command .= ' '.$jailkit_chroot_puserhome;
332         exec($command.' 2>/dev/null');
333
334         //* Change the homedir of the shell user and parent user
335         //* We have to do this manually as the usermod command fails
336         //* when the user is logged in or a command is running under that user
337         /*
8cf78b 338             $passwd_file_array = file('/etc/passwd');
T 339             $passwd_out = '';
340             if(is_array($passwd_file_array)) {
341                 foreach($passwd_file_array as $line) {
342                     $line = trim($line);
343                     $parts = explode(':',$line);
344                     if($parts[0] == $this->data['new']['username']) {
345                         $parts[5] = escapeshellcmd($this->data['new']['dir'].'/.'.$jailkit_chroot_userhome);
346                         $parts[6] = escapeshellcmd('/usr/sbin/jk_chrootsh');
347                         $new_line = implode(':',$parts);
348                         copy('/etc/passwd','/etc/passwd~');
349                         chmod('/etc/passwd~',0600);
350                         $app->uses('system');
351                         $app->system->replaceLine('/etc/passwd',$line,$new_line,1,0);
352                     }
353                 }
ff6a68 354             }*/
7fe908 355
MC 356         $app->system->usermod($this->data['new']['username'], 0, 0, $this->data['new']['dir'].'/.'.$jailkit_chroot_userhome, '/usr/sbin/jk_chrootsh');
357         $app->system->usermod($this->data['new']['puser'], 0, 0, $this->data['new']['dir'].'/.'.$jailkit_chroot_userhome, '/usr/sbin/jk_chrootsh');
358
359         $this->app->log("Added jailkit user to chroot with command: ".$command, LOGLEVEL_DEBUG);
360
361         if(!is_dir($this->data['new']['dir'].$jailkit_chroot_userhome)) mkdir(escapeshellcmd($this->data['new']['dir'].$jailkit_chroot_userhome), 0755, true);
362         $app->system->chown(escapeshellcmd($this->data['new']['dir'].$jailkit_chroot_userhome), $this->data['new']['username']);
363         $app->system->chgrp(escapeshellcmd($this->data['new']['dir'].$jailkit_chroot_userhome), $this->data['new']['pgroup']);
364
365         $this->app->log("Added created jailkit user home in : ".$this->data['new']['dir'].$jailkit_chroot_userhome, LOGLEVEL_DEBUG);
366
367         if(!is_dir($this->data['new']['dir'].$jailkit_chroot_puserhome)) mkdir(escapeshellcmd($this->data['new']['dir'].$jailkit_chroot_puserhome), 0755, true);
368         $app->system->chown(escapeshellcmd($this->data['new']['dir'].$jailkit_chroot_puserhome), $this->data['new']['puser']);
369         $app->system->chgrp(escapeshellcmd($this->data['new']['dir'].$jailkit_chroot_puserhome), $this->data['new']['pgroup']);
370
371         $this->app->log("Added jailkit parent user home in : ".$this->data['new']['dir'].$jailkit_chroot_puserhome, LOGLEVEL_DEBUG);
372
8cf78b 373
396f0e 374     }
7fe908 375
8db8f3 376     //* Update the website root directory permissions depending on the security level
T 377     function _update_website_security_level() {
7fe908 378         global $app, $conf;
MC 379
8db8f3 380         // load the server configuration options
T 381         $app->uses("getconf");
382         $web_config = $app->getconf->get_server_config($conf["server_id"], 'web');
7fe908 383
8db8f3 384         // Get the parent website of this shell user
T 385         $web = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".$this->data['new']['parent_domain_id']);
7fe908 386
8db8f3 387         //* If the security level is set to high
ff6a68 388         if($web_config['security_level'] == 20 && is_array($web)) {
7fe908 389             $app->system->web_folder_protection($web["document_root"], false);
MC 390             $app->system->chmod($web["document_root"], 0755);
391             $app->system->chown($web["document_root"], 'root');
392             $app->system->chgrp($web["document_root"], 'root');
393             $app->system->web_folder_protection($web["document_root"], true);
8db8f3 394         }
7fe908 395
8db8f3 396     }
7fe908 397
07bdbd 398     //* Wrapper for exec function for easier debugging
T 399     private function _exec($command) {
400         global $app;
7fe908 401         $app->log('exec: '.$command, LOGLEVEL_DEBUG);
07bdbd 402         exec($command);
T 403     }
396f0e 404
00a055 405     private function _setup_ssh_rsa() {
8ab3cd 406         global $app;
7fe908 407         $this->app->log("ssh-rsa setup shelluser_jailkit", LOGLEVEL_DEBUG);
00a055 408         // Get the client ID, username, and the key
27c623 409         $domain_data = $this->app->db->queryOneRecord('SELECT sys_groupid FROM web_domain WHERE web_domain.domain_id = '.intval($this->data['new']['parent_domain_id']));
L 410         $sys_group_data = $this->app->db->queryOneRecord('SELECT * FROM sys_group WHERE sys_group.groupid = '.intval($domain_data['sys_groupid']));
00a055 411         $id = intval($sys_group_data['client_id']);
L 412         $username= $sys_group_data['name'];
27c623 413         $client_data = $this->app->db->queryOneRecord('SELECT * FROM client WHERE client.client_id = '.$id);
00a055 414         $userkey = $client_data['ssh_rsa'];
L 415         unset($domain_data);
416         unset($client_data);
7fe908 417
00a055 418         // ssh-rsa authentication variables
8ab3cd 419         $sshrsa = $this->data['new']['ssh_rsa'];
00a055 420         $usrdir = escapeshellcmd($this->data['new']['dir']).'/'.$this->_get_home_dir($this->data['new']['username']);
8ab3cd 421         $sshdir = $usrdir.'/.ssh';
T 422         $sshkeys= $usrdir.'/.ssh/authorized_keys';
7fe908 423
8ab3cd 424         $app->uses('file');
T 425         $sshrsa = $app->file->unix_nl($sshrsa);
7fe908 426         $sshrsa = $app->file->remove_blank_lines($sshrsa, 0);
MC 427
00a055 428         // If this user has no key yet, generate a pair
8ab3cd 429         if ($userkey == '' && $id > 0){
00a055 430             //Generate ssh-rsa-keys
L 431             exec('ssh-keygen -t rsa -C '.$username.'-rsa-key-'.time().' -f /tmp/id_rsa -N ""');
7fe908 432
8ab3cd 433             // use the public key that has been generated
4bd960 434             $userkey = $app->system->file_get_contents('/tmp/id_rsa.pub');
7fe908 435
00a055 436             // save keypair in client table
4bd960 437             $this->app->db->query("UPDATE client SET created_at = ".time().", id_rsa = '".$app->db->quote($app->system->file_get_contents('/tmp/id_rsa'))."', ssh_rsa = '".$app->db->quote($userkey)."' WHERE client_id = ".$id);
8ab3cd 438
4bd960 439             $app->system->unlink('/tmp/id_rsa');
T 440             $app->system->unlink('/tmp/id_rsa.pub');
7fe908 441             $this->app->log("ssh-rsa keypair generated for ".$username, LOGLEVEL_DEBUG);
00a055 442         };
7fe908 443
8ab3cd 444         if (!file_exists($sshkeys)){
00a055 445             // add root's key
8ab3cd 446             $app->file->mkdirs($sshdir, '0755');
4bd960 447             if(is_file('/root/.ssh/authorized_keys')) $app->system->file_put_contents($sshkeys, $app->system->file_get_contents('/root/.ssh/authorized_keys'));
7fe908 448
8ab3cd 449             // Remove duplicate keys
26c0fc 450             $existing_keys = @file($sshkeys);
8ab3cd 451             $new_keys = explode("\n", $userkey);
26c0fc 452             $final_keys_arr = @array_merge($existing_keys, $new_keys);
8ab3cd 453             $new_final_keys_arr = array();
T 454             if(is_array($final_keys_arr) && !empty($final_keys_arr)){
455                 foreach($final_keys_arr as $key => $val){
456                     $new_final_keys_arr[$key] = trim($val);
457                 }
458             }
459             $final_keys = implode("\n", array_flip(array_flip($new_final_keys_arr)));
7fe908 460
00a055 461             // add the user's key
8ab3cd 462             file_put_contents($sshkeys, $final_keys);
T 463             $app->file->remove_blank_lines($sshkeys);
7fe908 464             $this->app->log("ssh-rsa authorisation keyfile created in ".$sshkeys, LOGLEVEL_DEBUG);
00a055 465         }
8cf78b 466         //* Get the keys
T 467         $existing_keys = file($sshkeys);
468         $new_keys = explode("\n", $sshrsa);
7fe908 469         $old_keys = explode("\n", $this->data['old']['ssh_rsa']);
MC 470
8cf78b 471         //* Remove all old keys
T 472         if(is_array($old_keys)) {
473             foreach($old_keys as $key => $val) {
7fe908 474                 $k = array_search(trim($val), $existing_keys);
8cf78b 475                 unset($existing_keys[$k]);
T 476             }
00a055 477         }
7fe908 478
8cf78b 479         //* merge the remaining keys and the ones fom the ispconfig database.
T 480         if(is_array($new_keys)) {
481             $final_keys_arr = array_merge($existing_keys, $new_keys);
482         } else {
483             $final_keys_arr = $existing_keys;
484         }
7fe908 485
8cf78b 486         $new_final_keys_arr = array();
T 487         if(is_array($final_keys_arr) && !empty($final_keys_arr)){
488             foreach($final_keys_arr as $key => $val){
489                 $new_final_keys_arr[$key] = trim($val);
490             }
491         }
492         $final_keys = implode("\n", array_flip(array_flip($new_final_keys_arr)));
7fe908 493
MC 494         // add the custom key
4bd960 495         $app->system->file_put_contents($sshkeys, $final_keys);
8cf78b 496         $app->file->remove_blank_lines($sshkeys);
7fe908 497         $this->app->log("ssh-rsa key updated in ".$sshkeys, LOGLEVEL_DEBUG);
MC 498
00a055 499         // set proper file permissions
8cf78b 500         exec("chown -R ".escapeshellcmd($this->data['new']['puser']).":".escapeshellcmd($this->data['new']['pgroup'])." ".$sshdir);
T 501         exec("chmod 700 ".$sshdir);
00a055 502         exec("chmod 600 '$sshkeys'");
7fe908 503
00a055 504     }
7fe908 505
396f0e 506 } // end class
T 507
8e725d 508 ?>