PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/admin/models/system.php

https://github.com/Excito/bubba-frontend
PHP | 488 lines | 444 code | 40 blank | 4 comment | 49 complexity | 83968719ae1016a9c72e19459dcfaf26 MD5 | raw file
  1. <?php
  2. require_once 'HTTP/Request2.php';
  3. class System extends CI_Model {
  4. private $version;
  5. public function __construct() {
  6. parent::__construct();
  7. }
  8. public function set_timezone($timezone) {
  9. $target = "/usr/share/zoneinfo/$timezone";
  10. if(!file_exists($target)) {
  11. throw new Exception("Timezone $timezone doesn't exists");
  12. }
  13. unlink('/etc/localtime');
  14. symlink($target, '/etc/localtime');
  15. file_put_contents('/etc/timezone', $timezone);
  16. }
  17. public function get_timezone() {
  18. return trim(file_get_contents('/etc/timezone'));
  19. }
  20. # Lists all timezones with region, UTC has region false
  21. public function list_timezones() {
  22. $timezones = array();
  23. foreach(DateTimeZone::listIdentifiers() as $ts) {
  24. if(strpos($ts,'/')) {
  25. list($region, $country) = explode('/', $ts);
  26. $timezones[$country] = $region;
  27. } else {
  28. $timezones[$ts] = false;
  29. }
  30. }
  31. ksort($timezones);
  32. return $timezones;
  33. }
  34. public function get_raw_uptime() {
  35. $upt=file("/proc/uptime");
  36. sscanf($upt[0],"%d",$secs_tot);
  37. return $secs_tot;
  38. }
  39. public function get_uptime() {
  40. $start = new DateTime();
  41. $start->sub(DateInterval::createFromDateString("{$this->get_raw_uptime()} seconds"));
  42. return $start->diff(new DateTime());
  43. }
  44. public function get_system_version() {
  45. if(!$this->version) {
  46. $this->version = file_get_contents(BUBBA_VERSION);
  47. }
  48. return $this->version;
  49. }
  50. public function get_hardware_id() {
  51. return getHWType();
  52. }
  53. public function list_printers() {
  54. $json = _system('cups-list-printers');
  55. return json_decode(implode($json),true);
  56. }
  57. const accounts_file = '/etc/bubba/remote_accounts.yml';
  58. const remote_jobs_file = '/etc/bubba/remote_backup_jobs.yml';
  59. const fstab_file = '/etc/fstab';
  60. const webdav_secrets_file = '/etc/davfs2/secrets';
  61. const ssh_keydir = '/etc/bubba/ssh-keys';
  62. # faithfully stolen from http://stackoverflow.com/questions/2040240/php-function-to-generate-v4-uuid
  63. private function gen_uuid() {
  64. return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
  65. // 32 bits for "time_low"
  66. mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
  67. // 16 bits for "time_mid"
  68. mt_rand( 0, 0xffff ),
  69. // 16 bits for "time_hi_and_version",
  70. // four most significant bits holds version number 4
  71. mt_rand( 0, 0x0fff ) | 0x4000,
  72. // 16 bits, 8 bits for "clk_seq_hi_res",
  73. // 8 bits for "clk_seq_low",
  74. // two most significant bits holds zero and one for variant DCE1.1
  75. mt_rand( 0, 0x3fff ) | 0x8000,
  76. // 48 bits for "node"
  77. mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
  78. );
  79. }
  80. private function create_ssh_key($uuid) {
  81. $priv_path = implode(DIRECTORY_SEPARATOR, array(self::ssh_keydir, $uuid));
  82. if(file_exists($priv_path)) {
  83. # XXX forcefully removing old key
  84. @unlink($priv_path);
  85. @unlink($priv_path.".pub");
  86. }
  87. _system("ssh-keygen", '-f', $priv_path, '-N', '', '-q');
  88. $pubkey = file_get_contents($priv_path.'.pub');
  89. return $pubkey;
  90. }
  91. public function get_pubkey($uuid) {
  92. $priv_path = implode(DIRECTORY_SEPARATOR, array(self::ssh_keydir, $uuid));
  93. $pub_path = $priv_path.'.pub';
  94. $pubkey = file_get_contents($pub_path);
  95. return $pubkey;
  96. }
  97. private function upload_sshkey($host, $username, $password, $uuid) {
  98. $priv_path = implode(DIRECTORY_SEPARATOR, array(self::ssh_keydir, $uuid));
  99. $pub_path = $priv_path.'.pub';
  100. $descriptorspec = array(
  101. 13 => array('pipe', 'r')
  102. );
  103. $process = proc_open("sshpass-copy-id -i $pub_path $username@$host", $descriptorspec, $pipes);
  104. fwrite($pipes[13], $password);
  105. fclose($pipes[13]);
  106. $ret = proc_close($process);
  107. error_log("sshpass-copy-id returned $ret!");
  108. }
  109. private $hidrive_token = null;
  110. private $hidrive_api = 'https://api.hidrive.strato.com/1.0/';
  111. public function get_hidrive_token($username, $password, $force = false) {
  112. if($this->hidrive_token && !$force) {
  113. return $this->hidrive_token;
  114. }
  115. $request = new HTTP_Request2($this->hidrive_api."auth.getToken", HTTP_Request2::METHOD_GET, array('ssl_verify_peer' => false));
  116. $request->setAuth($username, $password);
  117. $response = $request->send();
  118. if($response->getStatus() == 200) {
  119. $data = json_decode($response->getBody(), true);
  120. if(isset($data['status']['code']) && $data['status']['code'] == 0) {
  121. $this->hidrive_token = $data['data']['token'];
  122. return $this->hidrive_token;
  123. } else {
  124. return false;
  125. }
  126. }
  127. }
  128. public function verify_hidrive_protocols($token) {
  129. $request = new HTTP_Request2($this->hidrive_api."space.getFeatures", HTTP_Request2::METHOD_GET, array('ssl_verify_peer' => false));
  130. $request->setHeader('X-Auth-Token', $token);
  131. $response = $request->send();
  132. if($response->getStatus() == 200) {
  133. $data = json_decode($response->getBody(), true);
  134. if(isset($data['status']['code']) && $data['status']['code'] == 0) {
  135. $protocols = $data['data']['protocols'];
  136. return $protocols['rsync'] && $protocols['webdav'];
  137. }
  138. }
  139. }
  140. public function verify_hidrive_space($token, $required) {
  141. $request = new HTTP_Request2($this->hidrive_api."quota.list", HTTP_Request2::METHOD_GET, array('ssl_verify_peer' => false));
  142. $request->setHeader('X-Auth-Token', $token);
  143. $response = $request->send();
  144. if($response->getStatus() == 200) {
  145. $data = json_decode($response->getBody(), true);
  146. if(isset($data['status']['code']) && $data['status']['code'] == 0) {
  147. $root = $data['data']['root'];
  148. return $required < $root['available'];
  149. }
  150. }
  151. }
  152. public function add_remote_account($type, $username, $password, $host) {
  153. # Check HiDrive for permissions
  154. # https://api.freemium.stg.rzone.de/ contains incomplete api spec
  155. if($type == 'HiDrive') {
  156. $token = $this->get_hidrive_token($username, $password);
  157. if(!$token) {
  158. throw new Exception(_("Unable to verify credentials"));
  159. }
  160. if(!$this->verify_hidrive_protocols($token)) {
  161. throw new Exception(_("Selected HiDrive account doesn't have the stuff required for this system"));
  162. }
  163. }
  164. $accounts = array();
  165. if(file_exists(self::accounts_file)) {
  166. $accounts = spyc_load_file(self::accounts_file);
  167. }
  168. $arr = array(
  169. 'type' => $type,
  170. 'username' => $username,
  171. 'password' => $password
  172. );
  173. if($host) {
  174. $arr['host'] = $host;
  175. $key = "$type|$host|$username";
  176. } else {
  177. $key = "$type|$username";
  178. }
  179. if(isset($accounts[$key])) {
  180. throw new Exception(_('Account allready defined'));
  181. }
  182. $uuid = $this->gen_uuid();
  183. $pubkey = $this->create_ssh_key($uuid);
  184. $arr['uuid'] = $uuid;
  185. $accounts[$key] = $arr;
  186. file_put_contents(self::accounts_file,Spyc::YAMLDump($accounts));
  187. if($type == 'ssh') {
  188. $this->upload_sshkey($host, $username, $password, $uuid);
  189. }
  190. return array('key' => $key, 'uuid' => $uuid, 'pubkey' => $pubkey);
  191. }
  192. public function remove_remote_account($type, $username, $host) {
  193. if($host) {
  194. $target = "$type|$host|$username";
  195. } else {
  196. $target = "$type|$username";
  197. }
  198. $jobs = array();
  199. if(file_exists(self::remote_jobs_file)) {
  200. $jobs = spyc_load_file(self::remote_jobs_file);
  201. }
  202. unset($jobs[$target]);
  203. file_put_contents(self::remote_jobs_file,Spyc::YAMLDump($jobs));
  204. $accounts = array();
  205. if(file_exists(self::accounts_file)) {
  206. $accounts = spyc_load_file(self::accounts_file);
  207. }
  208. unset($accounts[$target]);
  209. file_put_contents(self::accounts_file,Spyc::YAMLDump($accounts));
  210. return true;
  211. }
  212. public function ssh_edit_remote_account($key, $username, $host) {
  213. $jobs = array();
  214. if(file_exists(self::remote_jobs_file)) {
  215. $jobs = spyc_load_file(self::remote_jobs_file);
  216. }
  217. $job = $jobs[$key];
  218. unset($jobs[$key]);
  219. $accounts = array();
  220. if(file_exists(self::accounts_file)) {
  221. $accounts = spyc_load_file(self::accounts_file);
  222. }
  223. $account = $accounts[$key];
  224. unset($accounts[$key]);
  225. $account['username'] = $username;
  226. $account['host'] = $host;
  227. $newkey = "ssh|$host|$username";
  228. $accounts[$newkey] = $account;
  229. $jobs[$newkey] = $job;
  230. file_put_contents(self::accounts_file,Spyc::YAMLDump($accounts));
  231. file_put_contents(self::remote_jobs_file,Spyc::YAMLDump($jobs));
  232. return $newkey;
  233. }
  234. public function get_remote_accounts() {
  235. $targets = array();
  236. if(file_exists(self::accounts_file)) {
  237. $accounts = spyc_load_file(self::accounts_file);
  238. foreach($accounts as $id => $account) {
  239. $target = array(
  240. 'id' => $id,
  241. 'uuid' => $account['uuid'],
  242. 'type' => $account['type'],
  243. 'username' => $account['username'],
  244. );
  245. if(isset($account['host'])) {
  246. $target['host'] = $account['host'];
  247. }
  248. $targets[] = $target;
  249. }
  250. }
  251. return $targets;
  252. }
  253. public function get_remote_account($key) {
  254. $target = array();
  255. if(file_exists(self::accounts_file)) {
  256. $accounts = spyc_load_file(self::accounts_file);
  257. foreach($accounts as $id => $account) {
  258. if($id != $key) {
  259. continue;
  260. }
  261. $target = array(
  262. 'id' => $id,
  263. 'type' => $account['type'],
  264. 'username' => $account['username'],
  265. 'uuid' => $account['uuid'],
  266. );
  267. if(isset($account['host'])) {
  268. $target['host'] = $account['host'];
  269. }
  270. }
  271. }
  272. return $target;
  273. }
  274. public function get_webdav_path($type, $username) {
  275. return "/home/admin/$type/$username";
  276. }
  277. public function create_webdav_path($type, $username) {
  278. $path = "/home/admin/$type";
  279. if(! file_exists($path) ) {
  280. mkdir($path, 0700);
  281. chown($path, 'admin');
  282. chgrp($path, 'admin');
  283. }
  284. $path = "/home/admin/$type/$username";
  285. if(! file_exists($path) ) {
  286. mkdir($path, 0700);
  287. chown($path, 'admin');
  288. chgrp($path, 'admin');
  289. }
  290. }
  291. public function get_webdav_url($type) {
  292. switch($type) {
  293. case 'HiDrive':
  294. return 'http://webdav.hidrive.strato.com';
  295. }
  296. }
  297. private function is_mounted($path) {
  298. exec("mountpoint -q " . escapeshellarg($path), $out, $ret);
  299. return $ret == 0;
  300. }
  301. public function add_webdav($type, $username, $password) {
  302. $url = $this->get_webdav_url($type);
  303. $path = $this->get_webdav_path($type, $username);
  304. if($this->is_mounted($path)) {
  305. _system("umount", '-f', $path);
  306. }
  307. $oldsecrets = file_get_contents(self::webdav_secrets_file);
  308. # Remove old path if allready there
  309. $secrets = preg_replace("#^".preg_quote($path).".*#m", "", $oldsecrets);
  310. $secrets .= sprintf("\n%s\t\"%s\"\t\"%s\"\n", addslashes($path), addslashes($username), addslashes($password));
  311. if($oldsecrets != $secrets) {
  312. file_put_contents(self::webdav_secrets_file, $secrets);
  313. }
  314. $oldfstab = file_get_contents(self::fstab_file);
  315. $fstab = preg_replace("#^".preg_quote($url)."\s+".preg_quote($path).".*#m", "", $oldfstab);
  316. $fstab .= "$url $path davfs defaults,gid=users,dir_mode=775,file_mode=664,_netdev 0 0\n";
  317. if(! file_exists($path) ) {
  318. $this->create_webdav_path($type, $username);
  319. }
  320. if($fstab != $oldfstab) {
  321. file_put_contents(self::fstab_file, $fstab);
  322. _system("mount", "-a");
  323. }
  324. }
  325. public function remove_webdav($type, $username) {
  326. $url = $this->get_webdav_url($type);
  327. $path = $this->get_webdav_path($type, $username);
  328. if($this->is_mounted($path)) {
  329. _system("umount", '-f', $path);
  330. }
  331. $oldsecrets = file_get_contents(self::webdav_secrets_file);
  332. # Remove old path if allready there
  333. $secrets = preg_replace("#^".preg_quote($path).".*#m", "", $oldsecrets);
  334. file_put_contents(self::webdav_secrets_file, $secrets);
  335. $oldfstab = file_get_contents(self::fstab_file);
  336. $fstab = preg_replace("#^".preg_quote($url)."\s+".preg_quote($path).".*#m", "", $oldfstab);
  337. if($fstab != $oldfstab) {
  338. file_put_contents(self::fstab_file, $fstab);
  339. _system("mount", "-a");
  340. }
  341. if( file_exists($path) ) {
  342. @rmdir($path);
  343. }
  344. }
  345. public function edit_webdav($type, $username, $password) {
  346. $this->remove_webdav($type, $username);
  347. $this->add_webdav($type, $username, $password);
  348. }
  349. public function get_sshfs_path($host, $username) {
  350. return "/home/admin/ssh/${username}@${host}";
  351. }
  352. public function create_sshfs_path($host, $username) {
  353. $path = "/home/admin/ssh";
  354. if(! file_exists($path) ) {
  355. @mkdir($path, 0700);
  356. chown($path, 'admin');
  357. chgrp($path, 'admin');
  358. }
  359. $path = $this->get_sshfs_path($host,$username);
  360. if(! file_exists($path) ) {
  361. @mkdir($path, 0700);
  362. chown($path, 'admin');
  363. chgrp($path, 'admin');
  364. }
  365. }
  366. public function move_sshfs($old_host, $old_username, $new_host, $new_username, $uuid) {
  367. if( $old_host == $new_host && $old_username == $new_username ) {
  368. return;
  369. }
  370. $this->remove_sshfs($old_hostm, $old_username);
  371. $this->add_sshfs($new_username, $new_host, $uuid);
  372. }
  373. public function add_sshfs($host, $username, $uuid) {
  374. $sshkey = implode(DIRECTORY_SEPARATOR, array(self::ssh_keydir, $uuid));
  375. $oldfstab = file_get_contents(self::fstab_file);
  376. $fstab = preg_replace("#^sshfs\#".preg_quote($username)."@".preg_quote($host).".*#m", "", $oldfstab);
  377. $path = $this->get_sshfs_path($host, $username);
  378. if($this->is_mounted($path)) {
  379. _system("umount", '-f', $path);
  380. }
  381. $fstab .= "sshfs#$username@$host: $path fuse identityfile=$sshkey,defaults,allow_other,_netdev,gid=users 0 0\n";
  382. if(! file_exists($path) ) {
  383. $this->create_sshfs_path($host, $username);
  384. }
  385. if($fstab != $oldfstab) {
  386. file_put_contents(self::fstab_file, $fstab);
  387. sleep(5);
  388. _system("mount", "-a");
  389. }
  390. }
  391. public function remove_sshfs($host, $username) {
  392. $path = $this->get_sshfs_path($host, $username);
  393. if($this->is_mounted($path)) {
  394. _system("umount", '-f', $path);
  395. }
  396. $oldfstab = file_get_contents(self::fstab_file);
  397. $fstab = preg_replace("#^sshfs\#".preg_quote($username)."@".preg_quote($host).".*#m", "", $oldfstab);
  398. if($fstab != $oldfstab) {
  399. file_put_contents(self::fstab_file, $fstab);
  400. _system("mount", "-a");
  401. }
  402. if( file_exists($path) ) {
  403. @rmdir($path);
  404. }
  405. }
  406. }