]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/protected/API/Class/Bconsole.php
baculum: Return bconsole disabled error if bconsole support isn't enabled
[bacula/bacula] / gui / baculum / protected / API / Class / Bconsole.php
1 <?php
2 /*
3  * Bacula(R) - The Network Backup Solution
4  * Baculum   - Bacula web interface
5  *
6  * Copyright (C) 2013-2016 Kern Sibbald
7  *
8  * The main author of Baculum is Marcin Haba.
9  * The original author of Bacula is Kern Sibbald, with contributions
10  * from many others, a complete list can be found in the file AUTHORS.
11  *
12  * You may use this file and others of this release according to the
13  * license defined in the LICENSE file, which includes the Affero General
14  * Public License, v3.0 ("AGPLv3") and some additional permissions and
15  * terms pursuant to its AGPLv3 Section 7.
16  *
17  * This notice must be preserved when any source code is
18  * conveyed and/or propagated.
19  *
20  * Bacula(R) is a registered trademark of Kern Sibbald.
21  */
22
23 Prado::using('Application.Common.Class.Errors');
24 Prado::using('Application.API.Class.BException');
25 Prado::using('Application.API.Class.APIModule');
26
27 class Bconsole extends APIModule {
28
29         const SUDO = 'sudo';
30
31         const BCONSOLE_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\n%s\nquit\nEND_OF_DATA";
32
33         const BCONSOLE_DIRECTORS_PATTERN = "%s%s -c %s -l 2>&1";
34
35         private $allowed_commands = array(
36                 'version',
37                 'status',
38                 'list',
39                 'messages',
40                 'show',
41                 'mount',
42                 'umount',
43                 'release',
44                 'prune',
45                 'purge',
46                 'update',
47                 'estimate',
48                 'run',
49                 '.bvfs_update',
50                 '.bvfs_lsdirs',
51                 '.bvfs_lsfiles',
52                 '.bvfs_versions',
53                 '.bvfs_get_jobids',
54                 '.bvfs_restore',
55                 '.bvfs_clear_cache',
56                 'restore',
57                 'cancel',
58                 'delete',
59                 '.jobs',
60                 'label',
61                 'reload',
62                 '.fileset',
63                 '.storage',
64                 '.client',
65                 '.pool'
66         );
67
68         private $config;
69
70         private $use_sudo;
71
72         private static $cmd_path;
73
74         private static $cfg_path;
75
76         public function init($param) {
77                 $this->config = $this->getModule('api_config')->getConfig('bconsole');
78                 if(count($this->config) > 0) {
79                         $use_sudo = ((integer)$this->config['use_sudo'] === 1);
80                         $cmd_path = $this->config['bin_path'];
81                         $custom_cfg_path = self::getCfgPath();
82                         $cfg_path = isset($custom_cfg_path) ? $custom_cfg_path : $this->config['cfg_path'];
83                         $this->setEnvironmentParams($cmd_path, $cfg_path, $use_sudo);
84                 }
85         }
86
87         public static function setCmdPath($path, $force = false) {
88                 // possible to set only once
89                 if (is_null(self::$cmd_path) || $force) {
90                          self::$cmd_path = $path;
91                 }
92         }
93
94         public static function getCmdPath() {
95                 return self::$cmd_path;
96         }
97
98         public static function setCfgPath($path, $force = false) {
99                 // possible to set only once
100                 if (is_null(self::$cfg_path) || $force) {
101                         self::$cfg_path = $path;
102                 }
103         }
104
105         public static function getCfgPath() {
106                 return self::$cfg_path;
107         }
108
109         public function setUseSudo($use_sudo, $force) {
110                 // possible to set only once
111                 if (is_null($this->use_sudo) || $force) {
112                         $this->use_sudo = $use_sudo;
113                 }
114         }
115
116         public function getUseSudo() {
117                 return $this->use_sudo;
118         }
119
120         private function setEnvironmentParams($cmd_path, $cfg_path, $use_sudo, $force = false) {
121                 self::setCmdPath($cmd_path, $force);
122                 self::setCfgPath($cfg_path, $force);
123                 $this->setUseSudo($use_sudo, $force);
124         }
125
126         private function isCommandValid($command) {
127                 $command = trim($command);
128                 return in_array($command, $this->allowed_commands);
129         }
130
131         private function prepareResult(array $output, $exitcode, $bconsole_command) {
132                 array_pop($output); // deleted 'quit' bconsole command
133                 for($i = 0; $i < count($output); $i++) {
134                         if(strstr($output[$i], $bconsole_command) == false) {
135                                 unset($output[$i]);
136                         } else {
137                                 break;
138                         }
139                 }
140                 $output = count($output) > 1 ? array_values($output) : array_shift($output);
141                 return (object)array('output' => $output, 'exitcode' => (integer)$exitcode);
142         }
143
144         public function bconsoleCommand($director, array $command, $user = null) {
145                 if (count($this->config) == 0 || $this->config['enabled'] !== '1') {
146                         throw new BConsoleException(
147                                 BconsoleError::MSG_ERROR_BCONSOLE_DISABLED,
148                                 BconsoleError::ERROR_BCONSOLE_DISABLED
149                         );
150                 }
151                 $base_command = count($command) > 0 ? $command[0] : null;
152                 if($this->isCommandValid($base_command) === true) {
153                         $result = $this->execCommand($director, $command, $user);
154                 } else {
155                         throw new BConsoleException(
156                                 BconsoleError::MSG_ERROR_INVALID_COMMAND,
157                                 BconsoleError::ERROR_INVALID_COMMAND
158                         );
159                 }
160                 return $result;
161         }
162
163         private function execCommand($director, array $command, $user) {
164                 $cmd = '';
165                 $result = null;
166                 if(!is_null($director) && $this->isValidDirector($director) === false) {
167                         throw new BConsoleException(
168                                 BconsoleError::MSG_ERROR_INVALID_DIRECTOR,
169                                 BconsoleError::ERROR_INVALID_DIRECTOR
170                         );
171                 } else {
172                         $dir = is_null($director) ? '': '-D ' . $director;
173                         $sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
174                         $bconsole_command = implode(' ', $command);
175                         $cmd = sprintf(
176                                 self::BCONSOLE_COMMAND_PATTERN,
177                                 $sudo,
178                                 self::getCmdPath(),
179                                 self::getCfgPath(),
180                                 $dir,
181                                 $bconsole_command
182                         );
183                         exec($cmd, $output, $exitcode);
184                         if($exitcode != 0) {
185                                 $emsg = ' Output=>' . implode("\n", $output) . ', Exitcode=>' . $exitcode;
186                                 throw new BConsoleException(
187                                         BconsoleError::MSG_ERROR_BCONSOLE_CONNECTION_PROBLEM . $emsg,
188                                         BconsoleError::ERROR_BCONSOLE_CONNECTION_PROBLEM
189                                 );
190                         } else {
191                                 $result = $this->prepareResult($output, $exitcode, $bconsole_command);
192                         }
193                 }
194                 $this->Application->getModule('logging')->log(
195                         $cmd,
196                         $output,
197                         Logging::CATEGORY_EXECUTE,
198                         __FILE__,
199                         __LINE__
200                 );
201
202                 return $result;
203         }
204
205         public function getDirectors() {
206                 $sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
207                 $cmd = sprintf(
208                         self::BCONSOLE_DIRECTORS_PATTERN,
209                         $sudo,
210                         self::getCmdPath(),
211                         self::getCfgPath()
212                 );
213                 exec($cmd, $output, $exitcode);
214                 if($exitcode != 0) {
215                         $emsg = ' Output=>' . implode("\n", $output) . ', Exitcode=>' . $exitcode;
216                         throw new BConsoleException(
217                                 BconsoleError::MSG_ERROR_BCONSOLE_CONNECTION_PROBLEM . $emsg,
218                                 BconsoleError::ERROR_BCONSOLE_CONNECTION_PROBLEM
219                         );
220                 }
221                 $result = (object)array('output' => $output, 'exitcode' => $exitcode);
222                 return $result;
223         }
224
225         private function isValidDirector($director) {
226                 return in_array($director, $this->getDirectors()->output);
227         }
228
229         public function testBconsoleCommand(array $command, $cmd_path, $cfg_path, $use_sudo) {
230                 $this->setEnvironmentParams($cmd_path, $cfg_path, $use_sudo, true);
231                 $director = '';
232                 $result = null;
233                 try {
234                         $director = array_shift($this->getDirectors()->output);
235                         $result = $this->bconsoleCommand($director, $command);
236                 } catch (BException $e) {
237                         $result = (object)array(
238                                 'output' => $e->getErrorMessage(),
239                                 'exitcode' => $e->getErrorCode()
240                         );
241                 }
242                 return $result;
243         }
244 }
245 ?>