1<?php 2/* 3 +-------------------------------------------------------------------------+ 4 | Copyright (C) 2004-2021 The Cacti Group | 5 | | 6 | This program is free software; you can redistribute it and/or | 7 | modify it under the terms of the GNU General Public License | 8 | as published by the Free Software Foundation; either version 2 | 9 | of the License, or (at your option) any later version. | 10 | | 11 | This program is distributed in the hope that it will be useful, | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | GNU General Public License for more details. | 15 +-------------------------------------------------------------------------+ 16 | Cacti: The Complete RRDtool-based Graphing Solution | 17 +-------------------------------------------------------------------------+ 18 | This code is designed, written, and maintained by the Cacti Group. See | 19 | about.php and/or the AUTHORS file for specific developer information. | 20 +-------------------------------------------------------------------------+ 21 | http://www.cacti.net/ | 22 +-------------------------------------------------------------------------+ 23*/ 24 25function do_hook($name) { 26 $data = func_get_args(); 27 $data = api_plugin_hook($name, $data); 28 return $data; 29} 30 31function do_hook_function($name,$parm=NULL) { 32 return api_plugin_hook_function($name, $parm); 33} 34 35function api_user_realm_auth($filename = '') { 36 return api_plugin_user_realm_auth($filename); 37} 38 39/** 40 * This function executes a hook. 41 * @param string $name Name of hook to fire 42 * @return mixed $data 43 */ 44function api_plugin_hook($name) { 45 global $config, $plugin_hooks, $plugins_integrated; 46 47 static $hook_cache = array(); 48 49 $args = func_get_args(); 50 $ret = ''; 51 52 if (defined('IN_CACTI_INSTALL') || !db_table_exists('plugin_hooks')) { 53 return $args; 54 } 55 56 if (!isset($hook_cache[$name])) { 57 /* order the plugins by order */ 58 $result = db_fetch_assoc_prepared('SELECT ph.name, ph.file, ph.function 59 FROM plugin_hooks AS ph 60 LEFT JOIN plugin_config AS pc 61 ON pc.directory = ph.name 62 WHERE ph.status = 1 63 AND hook = ? 64 ORDER BY pc.id ASC', 65 array($name), 66 true 67 ); 68 69 $hook_cache[$name] = $result; 70 } else { 71 $result = $hook_cache[$name]; 72 } 73 74 if (!empty($result)) { 75 foreach ($result as $hdata) { 76 if (!in_array($hdata['name'], $plugins_integrated)) { 77 if (file_exists($config['base_path'] . '/plugins/' . $hdata['name'] . '/' . $hdata['file'])) { 78 include_once($config['base_path'] . '/plugins/' . $hdata['name'] . '/' . $hdata['file']); 79 } 80 $function = $hdata['function']; 81 if (function_exists($function)) { 82 api_plugin_run_plugin_hook($name, $hdata['name'], $function, $args); 83 } 84 } 85 } 86 } 87 88 /* Variable-length argument lists have a slight problem when */ 89 /* passing values by reference. Pity. This is a workaround. */ 90 return $args; 91} 92 93function api_plugin_hook_function($name, $parm = NULL) { 94 global $config, $plugin_hooks, $plugins_integrated; 95 96 static $hook_cache = array(); 97 98 $ret = $parm; 99 100 if (defined('IN_CACTI_INSTALL') || !db_table_exists('plugin_hooks')) { 101 return $ret; 102 } 103 104 if (!isset($hook_cache[$name])) { 105 /* order the plugins by order */ 106 $result = db_fetch_assoc_prepared('SELECT ph.name, ph.file, ph.function 107 FROM plugin_hooks AS ph 108 LEFT JOIN plugin_config AS pc 109 ON pc.directory = ph.name 110 WHERE ph.status = 1 111 AND hook = ? 112 ORDER BY pc.id ASC', 113 array($name), 114 true 115 ); 116 117 $hook_cache[$name] = $result; 118 } else { 119 $result = $hook_cache[$name]; 120 } 121 122 if (empty($ret)) { 123 $null_ret = true; 124 } else { 125 $null_ret = false; 126 } 127 128 if (!empty($result)) { 129 foreach ($result as $hdata) { 130 if (!in_array($hdata['name'], $plugins_integrated)) { 131 $p[] = $hdata['name']; 132 133 if (file_exists($config['base_path'] . '/plugins/' . $hdata['name'] . '/' . $hdata['file'])) { 134 include_once($config['base_path'] . '/plugins/' . $hdata['name'] . '/' . $hdata['file']); 135 } 136 137 $function = $hdata['function']; 138 139 if (function_exists($function)) { 140 if (is_array($ret)) { 141 $is_array = true; 142 } else { 143 $is_array = false; 144 } 145 146 $ret = api_plugin_run_plugin_hook_function($name, $hdata['name'], $function, $ret); 147 148 if (($is_array && !is_array($ret)) || ($ret == null && $null_ret === false)) { 149 if (cacti_sizeof($result) > 1) { 150 cacti_log(sprintf("WARNING: Plugin hook '%s' from Plugin '%s' must return the calling array or variable, and it is not doing so. Please report this to the Plugin author.", $function, $hdata['name']), false); 151 } 152 } 153 } 154 } 155 } 156 } 157 158 /* Variable-length argument lists have a slight problem when */ 159 /* passing values by reference. Pity. This is a workaround. */ 160 return $ret; 161} 162 163function api_plugin_run_plugin_hook($hook, $plugin, $function, $args) { 164 global $config, $menu; 165 166 if ($config['poller_id'] > 1) { 167 // Let's control the menu 168 $orig_menu = $menu; 169 170 $required_capabilities = array( 171 // Poller related 172 'poller_top' => array('remote_collect'), // Poller Top 173 'poller_bottom' => array('remote_collect'), // Poller execution, api_plugin_hook 174 'update_host_status' => array('remote_collect'), // Processing poller output, api_plugin_hook 175 'poller_output' => array('remote_collect'), // Poller output activities 176 'poller_command_args' => array('remote_collect'), // Command line arguments 177 'cacti_stats_update' => array('remote_collect'), // Updating statistics 178 'poller_finishing' => array('remote_collect'), // Poller post processing 179 'poller_exiting' => array('remote_collect'), // Poller exception handling 180 181 // GUI Related 182 'page_head' => array('online_view', 'offline_view'), // Navigation, api_plugin_hook 183 'top_header_tabs' => array('online_view', 'offline_view'), // Top Tabs, api_plugin_hook 184 'top_graph_header_tabs' => array('online_view', 'offline_view'), // Top Tabs, api_plugin_hook 185 'graph_buttons' => array('online_view', 'offline_view'), // Buttons by graphs, api_plugin_hook 186 'graphs_new_top_links' => array('online_mgmt', 'offline_mgmt'), // Buttons by graphs, api_plugin_hook 187 'page_head' => array('online_view', 'offline_view') // Content, api_plugin_hook 188 ); 189 190 $plugin_capabilities = api_plugin_remote_capabilities($plugin); 191 192 if ($plugin_capabilities === false) { 193 $function($args); 194 } elseif (api_plugin_hook_is_remote_collect($hook, $plugin, $required_capabilities)) { 195 if (api_plugin_status_run($hook, $required_capabilities, $plugin_capabilities)) { 196 $function($args); 197 } 198 } elseif (isset($required_capabilities[$hook])) { 199 if (api_plugin_status_run($hook, $required_capabilities, $plugin_capabilities)) { 200 $function($args); 201 } 202 } else { 203 $function($args); 204 } 205 206 // See if we need to restore the menu to original 207 if (($hook == 'config_arrays' || 'config_insert') && $config['connection'] == 'offline') { 208 if (!api_plugin_has_capability($plugin, 'offline_mgmt')) { 209 if ($orig_menu !== $menu) { 210 $menu = $orig_menu; 211 } 212 } 213 } 214 } else { 215 $function($args); 216 } 217 218 return $args; 219} 220 221function api_plugin_run_plugin_hook_function($hook, $plugin, $function, $ret) { 222 global $config; 223 224 if ($config['poller_id'] > 1) { 225 $required_capabilities = array( 226 // Poller related 227 'poller_output' => array('remote_collect'), // Processing poller output, api_plugin_hook_function 228 229 // GUI Related 230 'top_header' => array('online_view', 'offline_view'), // Top Tabs, api_plugin_hook_function 231 'top_graph_header' => array('online_view', 'offline_view'), // Top Tabs, api_plugin_hook_function 232 'rrd_graph_graph_options' => array('online_view', 'offline_view'), // Buttons by graphs, api_plugin_hook_function 233 'data_sources_table' => array('online_mgmt', 'offline_mgmt'), // Buttons by graphs, api_plugin_hook_function 234 235 'device_action_array' => array('online_mgmt', 'offline_mgmt'), // Actions Dropdown, api_plugin_hook_function 236 'data_source_action_array' => array('online_mgmt', 'offline_mgmt'), // Actions Dropdown, api_plugin_hook_function 237 'graphs_action_array' => array('online_mgmt', 'offline_mgmt'), // Actions Dropdown, api_plugin_hook_function 238 ); 239 240 $plugin_capabilities = api_plugin_remote_capabilities($plugin); 241 242 // we will run if capabilities are not set 243 if ($plugin_capabilities === false) { 244 $ret = $function($ret); 245 // run if hooks is remote_collect and we support it 246 } elseif (api_plugin_hook_is_remote_collect($hook, $plugin, $required_capabilities)) { 247 if (api_plugin_status_run($hook, $required_capabilities, $plugin_capabilities)) { 248 $ret = $function($ret); 249 } 250 // run if hooks is remote_collect and we support it 251 } elseif (isset($required_capabilities[$hook])) { 252 if (api_plugin_status_run($hook, $required_capabilities, $plugin_capabilities)) { 253 $ret = $function($ret); 254 } 255 } else { 256 $ret = $function($ret); 257 } 258 } else { 259 $ret = $function($ret); 260 } 261 262 return $ret; 263} 264 265function api_plugin_hook_is_remote_collect($hook, $plugin, $required_capabilities) { 266 if (isset($required_capabilities[$hook])) { 267 foreach($required_capabilities[$hook] as $capability) { 268 if (strpos($capability, 'remote_collect') !== false) { 269 return true; 270 } 271 } 272 } 273 274 return false; 275} 276 277function api_plugin_get_dependencies($plugin) { 278 global $config; 279 280 $file = $config['base_path'] . '/plugins/' . $plugin . '/INFO'; 281 282 $returndeps = array(); 283 284 if (file_exists($file)) { 285 $info = parse_ini_file($file, true); 286 287 if (isset($info['info']['requires']) && trim($info['info']['requires']) != '') { 288 $parts = explode(' ', trim($info['info']['requires'])); 289 290 foreach ($parts as $p) { 291 $vparts = explode(':', $p); 292 if (isset($vparts[1])) { 293 $returndeps[$vparts[0]] = $vparts[1]; 294 } else { 295 $returndeps[$p] = true; 296 } 297 } 298 299 return $returndeps; 300 } 301 } 302 303 return false; 304} 305 306function api_plugin_minimum_version($plugin, $version) { 307 if (strlen($version)) { 308 $plugin_version = db_fetch_cell_prepared('SELECT version 309 FROM plugin_config 310 WHERE directory = ?', 311 array($plugin)); 312 313 $result = cacti_version_compare($version, $plugin_version, '<='); 314 } else { 315 $plugin_version = '<not read>'; 316 $result = true; 317 } 318 319 return $result; 320} 321 322function api_plugin_installed($plugin) { 323 $plugin_data = db_fetch_row_prepared('SELECT directory, status 324 FROM plugin_config 325 WHERE directory = ?', 326 array($plugin)); 327 328 if (cacti_sizeof($plugin_data)) { 329 if ($plugin_data['status'] >= 1) { 330 return true; 331 } 332 } 333 334 return false; 335} 336 337function api_plugin_remote_capabilities($plugin) { 338 global $config, $info_data; 339 340 if ($plugin == 'internal') { 341 return 'online_view:1 online_mgmt:1 offline_view:1 offline_mgmt:1 remote_collect:1'; 342 } 343 344 $file = $config['base_path'] . '/plugins/' . $plugin . '/INFO'; 345 346 if (!isset($info_data[$plugin])) { 347 if (file_exists($file)) { 348 $info = parse_ini_file($file, true); 349 350 if (cacti_sizeof($info)) { 351 $info_data[$plugin] = $info['info']; 352 } 353 } 354 } 355 356 if (isset($info_data[$plugin]) && isset($info_data[$plugin]['capabilities'])) { 357 return $info_data[$plugin]['capabilities']; 358 } else { 359 return 'online_view:0 online_mgmt:0 offline_view:0 offline_mgmt:0 remote_collect:0'; 360 } 361 362 return false; 363} 364 365function api_plugin_has_capability($plugin, $capability) { 366 $capabilities = api_plugin_remote_capabilities($plugin); 367 368 if (strpos($capabilities, "$capability:1") !== false) { 369 return true; 370 } else { 371 return false; 372 } 373} 374 375function api_plugin_status_run($hook, $required_capabilities, $plugin_capabilities) { 376 global $config; 377 378 $status = $config['connection']; 379 380 if (!isset($required_capabilities[$hook])) { 381 return true; 382 } 383 384 foreach($required_capabilities[$hook] as $capability) { 385 if ($status == 'online' && strpos($capability, 'online') === false) { 386 continue; 387 } elseif (($status == 'offline' || $status == 'recovery') && strpos($capability, 'offline') === false) { 388 continue; 389 } 390 391 if (strpos($plugin_capabilities, "$capability:1") !== false) { 392 return true; 393 } 394 395 switch($capability) { 396 case 'offline_view': // if the plugin has mgmt, it's assumed to have view 397 if (strpos($plugin_capabilities, "offline_mgmt:1") !== false) { 398 return true; 399 } 400 401 break; 402 case 'online_view': // if the plugin has mgmt, it's assumed to have view 403 if (strpos($plugin_capabilities, "offline_mgmt:1") !== false) { 404 return true; 405 } 406 407 break; 408 default: 409 break; 410 } 411 } 412 413 return false; 414} 415 416function api_plugin_db_table_create($plugin, $table, $data) { 417 global $config; 418 419 include_once($config['library_path'] . '/database.php'); 420 421 $result = db_fetch_assoc('SHOW TABLES'); 422 $tables = array(); 423 foreach($result as $index => $arr) { 424 foreach ($arr as $t) { 425 $tables[] = $t; 426 } 427 } 428 429 if (!in_array($table, $tables)) { 430 $c = 0; 431 $sql = 'CREATE TABLE `' . $table . "` (\n"; 432 foreach ($data['columns'] as $column) { 433 if (isset($column['name'])) { 434 if ($c > 0) { 435 $sql .= ",\n"; 436 } 437 438 $sql .= '`' . $column['name'] . '`'; 439 440 if (isset($column['type'])) { 441 $sql .= ' ' . $column['type']; 442 } 443 444 if (isset($column['unsigned'])) { 445 $sql .= ' unsigned'; 446 } 447 448 if (isset($column['NULL']) && $column['NULL'] == false) { 449 $sql .= ' NOT NULL'; 450 } 451 452 if (isset($column['NULL']) && $column['NULL'] == true && !isset($column['default'])) { 453 $sql .= ' default NULL'; 454 } 455 456 if (isset($column['default'])) { 457 if (strtolower($column['type']) == 'timestamp' && $column['default'] === 'CURRENT_TIMESTAMP') { 458 $sql .= ' default CURRENT_TIMESTAMP'; 459 } else { 460 $sql .= ' default ' . (is_numeric($column['default']) ? $column['default'] : "'" . $column['default'] . "'"); 461 } 462 } 463 464 if (isset($column['auto_increment'])) { 465 $sql .= ' auto_increment'; 466 } 467 468 $c++; 469 } 470 } 471 472 if (isset($data['primary'])) { 473 $sql .= ",\n PRIMARY KEY (`" . $data['primary'] . '`)'; 474 } 475 476 if (isset($data['keys']) && cacti_sizeof($data['keys'])) { 477 foreach ($data['keys'] as $key) { 478 if (isset($key['name'])) { 479 $sql .= ",\n INDEX `" . $key['name'] . '` (' . db_format_index_create($key['columns']) . ')'; 480 } 481 } 482 } 483 484 if (isset($data['unique_keys'])) { 485 foreach ($data['unique_keys'] as $key) { 486 if (isset($key['name'])) { 487 $sql .= ",\n UNIQUE INDEX `" . $key['name'] . '` (' . db_format_index_create($key['columns']) . ')'; 488 } 489 } 490 } 491 492 $sql .= ') ENGINE = ' . $data['type']; 493 494 if (isset($data['row_format']) && db_get_global_variable('innodb_file_format') == 'Barracuda') { 495 $sql .= ' ROW_FORMAT = ' . $data['row_format']; 496 } 497 498 if (isset($data['comment'])) { 499 $sql .= " COMMENT = '" . $data['comment'] . "'"; 500 } 501 502 if (db_execute($sql)) { 503 db_execute_prepared("REPLACE INTO plugin_db_changes 504 (plugin, `table`, `column`, `method`) 505 VALUES (?, ?, '', 'create')", 506 array($plugin, $table)); 507 508 if (isset($data['collate'])) { 509 db_execute("ALTER TABLE `$table` COLLATE = " . $data['collate']); 510 } 511 512 if (isset($data['charset'])) { 513 db_execute("ALTER TABLE `$table` CHARSET = " . $data['charset']); 514 } 515 } 516 } 517} 518 519function api_plugin_db_changes_remove($plugin) { 520 $tables = db_fetch_assoc_prepared("SELECT `table` 521 FROM plugin_db_changes 522 WHERE plugin = ? 523 AND method ='create'", 524 array($plugin), false); 525 526 if (cacti_count($tables)) { 527 foreach ($tables as $table) { 528 db_execute('DROP TABLE IF EXISTS `' . $table['table'] . '`;'); 529 } 530 531 db_execute_prepared("DELETE FROM plugin_db_changes 532 WHERE plugin = ? 533 AND method ='create'", 534 array($plugin), false); 535 } 536 537 $columns = db_fetch_assoc_prepared("SELECT `table`, `column` 538 FROM plugin_db_changes 539 WHERE plugin = ? 540 AND method ='addcolumn'", 541 array($plugin), false); 542 543 if (cacti_count($columns)) { 544 foreach ($columns as $column) { 545 db_execute('ALTER TABLE `' . $column['table'] . '` DROP `' . $column['column'] . '`'); 546 } 547 548 db_execute_prepared("DELETE FROM plugin_db_changes 549 WHERE plugin = ? 550 AND method = 'addcolumn'", 551 array($plugin), false); 552 } 553} 554 555function api_plugin_db_add_column ($plugin, $table, $column) { 556 global $config, $database_default; 557 558 // Example: api_plugin_db_add_column ('thold', 'plugin_config', 559 // array('name' => 'test' . rand(1, 200), 'type' => 'varchar (255)', 'NULL' => false)); 560 561 include_once($config['library_path'] . '/database.php'); 562 563 $result = db_fetch_assoc('SHOW COLUMNS FROM `' . $table . '`'); 564 $columns = array(); 565 foreach($result as $index => $arr) { 566 foreach ($arr as $t) { 567 $columns[] = $t; 568 } 569 } 570 571 if (isset($column['name']) && !in_array($column['name'], $columns)) { 572 $sql = 'ALTER TABLE `' . $table . '` ADD `' . $column['name'] . '`'; 573 574 if (isset($column['type'])) { 575 $sql .= ' ' . $column['type']; 576 } 577 578 if (isset($column['unsigned'])) { 579 $sql .= ' unsigned'; 580 } 581 582 if (isset($column['NULL']) && $column['NULL'] == false) { 583 $sql .= ' NOT NULL'; 584 } 585 586 if (isset($column['NULL']) && $column['NULL'] == true && !isset($column['default'])) { 587 $sql .= ' default NULL'; 588 } 589 590 if (isset($column['default'])) { 591 if (strtolower($column['type']) == 'timestamp' && $column['default'] === 'CURRENT_TIMESTAMP') { 592 $sql .= ' default CURRENT_TIMESTAMP'; 593 } else { 594 $sql .= ' default ' . (is_numeric($column['default']) ? $column['default'] : "'" . $column['default'] . "'"); 595 } 596 } 597 598 if (isset($column['auto_increment'])) { 599 $sql .= ' auto_increment'; 600 } 601 602 if (isset($column['after'])) { 603 $sql .= ' AFTER ' . $column['after']; 604 } 605 606 if (db_execute($sql)) { 607 db_execute_prepared("INSERT INTO plugin_db_changes 608 (plugin, `table`, `column`, `method`) 609 VALUES (?, ?, ?, 'addcolumn')", 610 array($plugin, $table, $column['name'])); 611 } 612 } 613} 614 615function api_plugin_can_install($plugin, &$message) { 616 $dependencies = api_plugin_get_dependencies($plugin); 617 $message = ''; 618 $proceed = true; 619 620 if (is_array($dependencies) && cacti_sizeof($dependencies)) { 621 foreach($dependencies as $dependency => $version) { 622 if (!api_plugin_minimum_version($dependency, $version)) { 623 $message .= __('%s Version %s or above is required for %s. ', ucwords($dependency), $version, ucwords($plugin)); 624 625 $proceed = false; 626 } else if (!api_plugin_installed($dependency)) { 627 $message .= __('%s is required for %s, and it is not installed. ', ucwords($dependency), ucwords($plugin)); 628 629 $proceed = false; 630 } 631 } 632 } 633 634 return $proceed; 635} 636 637function api_plugin_install($plugin) { 638 global $config; 639 640 if (!defined('IN_CACTI_INSTALL')) { 641 define('IN_CACTI_INSTALL', 1); 642 } 643 644 $dependencies = api_plugin_get_dependencies($plugin); 645 646 $proceed = api_plugin_can_install($plugin, $message); 647 648 if (!$proceed) { 649 $message .= '<br><br>' . __('Plugin cannot be installed.'); 650 651 raise_message($message, MESSAGE_LEVEL_ERROR); 652 653 header('Location: plugins.php?header=false'); 654 655 exit; 656 } 657 658 include_once($config['base_path'] . "/plugins/$plugin/setup.php"); 659 660 $exists = db_fetch_assoc_prepared('SELECT id 661 FROM plugin_config 662 WHERE directory = ?', 663 array($plugin), false); 664 665 if (cacti_sizeof($exists)) { 666 db_execute_prepared('DELETE FROM plugin_config 667 WHERE directory = ?', 668 array($plugin)); 669 } 670 671 $name = $author = $webpage = $version = ''; 672 $function = 'plugin_' . $plugin . '_version'; 673 674 if (function_exists($function)){ 675 $info = $function(); 676 $name = $info['longname']; 677 678 if (isset($info['homepage'])) { 679 $webpage = $info['homepage']; 680 } elseif (isset($info['webpage'])) { 681 $webpage = $info['webpage']; 682 } else { 683 $webpage = 'Not Stated'; 684 } 685 686 $author = $info['author']; 687 $version = $info['version']; 688 } 689 690 db_execute_prepared('INSERT INTO plugin_config 691 (directory, name, author, webpage, version) 692 VALUES (?, ?, ?, ?, ?)', 693 array($plugin, $name, $author, $webpage, $version)); 694 695 $function = 'plugin_' . $plugin . '_install'; 696 if (function_exists($function)){ 697 $function(); 698 $ready = api_plugin_check_config ($plugin); 699 if ($ready) { 700 // Set the plugin as "disabled" so it can go live 701 db_execute_prepared('UPDATE plugin_config 702 SET status = 4 703 WHERE directory = ?', 704 array($plugin)); 705 } else { 706 // Set the plugin as "needs configuration" 707 db_execute_prepared('UPDATE plugin_config 708 SET status = 2 709 WHERE directory = ?', 710 array($plugin)); 711 } 712 } 713} 714 715function api_plugin_uninstall_integrated() { 716 global $config, $plugin_hooks, $plugins_integrated; 717 718 foreach($plugins_integrated as $plugin) { 719 api_plugin_uninstall($plugin, false); 720 } 721} 722 723function api_plugin_uninstall($plugin, $tables = true) { 724 global $config; 725 726 if (file_exists($config['base_path'] . "/plugins/$plugin/setup.php")) { 727 include_once($config['base_path'] . "/plugins/$plugin/setup.php"); 728 729 // Run the Plugin's Uninstall Function first 730 $function = 'plugin_' . $plugin . '_uninstall'; 731 732 if (function_exists($function)) { 733 $function(); 734 } 735 } 736 737 api_plugin_remove_hooks($plugin); 738 api_plugin_remove_realms($plugin); 739 740 db_execute_prepared('DELETE FROM plugin_config 741 WHERE directory = ?', 742 array($plugin)); 743 744 if ($tables) { 745 api_plugin_db_changes_remove($plugin); 746 } else { 747 db_execute_prepared('DELETE FROM plugin_db_changes 748 WHERE plugin = ?', 749 array($plugin)); 750 } 751} 752 753function api_plugin_check_config($plugin) { 754 global $config; 755 756 clearstatcache(); 757 758 if (file_exists($config['base_path'] . "/plugins/$plugin/setup.php")) { 759 include_once($config['base_path'] . "/plugins/$plugin/setup.php"); 760 761 $function = 'plugin_' . $plugin . '_check_config'; 762 763 if (function_exists($function)) { 764 return $function(); 765 } 766 767 return true; 768 } 769 770 return false; 771} 772 773function api_plugin_enable($plugin) { 774 $ready = api_plugin_check_config($plugin); 775 776 if ($ready) { 777 api_plugin_enable_hooks($plugin); 778 779 db_execute_prepared('UPDATE plugin_config 780 SET status = 1 781 WHERE directory = ?', 782 array($plugin)); 783 } 784} 785 786function api_plugin_is_enabled($plugin) { 787 $status = db_fetch_cell_prepared('SELECT status 788 FROM plugin_config 789 WHERE directory = ?', 790 array($plugin), false); 791 792 if ($status == '1') { 793 return true; 794 } 795 796 return false; 797} 798 799function api_plugin_disable($plugin) { 800 api_plugin_disable_hooks($plugin); 801 802 db_execute_prepared('UPDATE plugin_config 803 SET status = 4 804 WHERE directory = ?', 805 array($plugin)); 806} 807 808function api_plugin_disable_all($plugin) { 809 api_plugin_disable_hooks_all($plugin); 810 811 db_execute_prepared('UPDATE plugin_config 812 SET status = 4 813 WHERE directory = ?', 814 array($plugin)); 815} 816 817function api_plugin_moveup($plugin) { 818 $id = db_fetch_cell_prepared('SELECT id 819 FROM plugin_config 820 WHERE directory = ?', 821 array($plugin)); 822 823 if (!empty($id)) { 824 $temp_id = db_fetch_cell('SELECT MAX(id) FROM plugin_config')+1; 825 826 $prior_id = db_fetch_cell_prepared('SELECT MAX(id) 827 FROM plugin_config 828 WHERE id < ?', 829 array($id)); 830 831 /* update the above plugin to the prior temp id */ 832 db_execute_prepared('UPDATE plugin_config SET id = ? WHERE id = ?', array($temp_id, $prior_id)); 833 db_execute_prepared('UPDATE plugin_config SET id = ? WHERE id = ?', array($prior_id, $id)); 834 db_execute_prepared('UPDATE plugin_config SET id = ? WHERE id = ?', array($id, $temp_id)); 835 } 836} 837 838function api_plugin_movedown($plugin) { 839 $id = db_fetch_cell_prepared('SELECT id FROM plugin_config WHERE directory = ?', array($plugin)); 840 $temp_id = db_fetch_cell('SELECT MAX(id) FROM plugin_config')+1; 841 $next_id = db_fetch_cell_prepared('SELECT MIN(id) FROM plugin_config WHERE id > ?', array($id)); 842 843 /* update the above plugin to the prior temp id */ 844 db_execute_prepared('UPDATE plugin_config SET id = ? WHERE id = ?', array($temp_id, $next_id)); 845 db_execute_prepared('UPDATE plugin_config SET id = ? WHERE id = ?', array($next_id, $id)); 846 db_execute_prepared('UPDATE plugin_config SET id = ? WHERE id = ?', array($id, $temp_id)); 847} 848 849function api_plugin_register_hook($plugin, $hook, $function, $file, $enable = false) { 850 $status = 0; 851 852 $exists = db_fetch_cell_prepared('SELECT COUNT(*) 853 FROM plugin_hooks 854 WHERE name = ? 855 AND hook = ?', 856 array($plugin, $hook), false); 857 858 if (!$exists) { 859 // enable the hooks if they are system level hooks to enable configuration 860 $settings = array('config_settings', 'config_arrays', 'config_form'); 861 $status = (!in_array($hook, $settings) ? 0 : 1); 862 863 if ($enable) { 864 $status = 1; 865 } 866 867 db_execute_prepared('INSERT INTO plugin_hooks 868 (name, hook, `function`, file, status) 869 VALUES (?, ?, ?, ?, ?)', 870 array($plugin, $hook, $function, $file, $status)); 871 } else { 872 if ($enable == true) { 873 $status = 1; 874 } 875 876 // enable the hook automatically if other hooks are already enabled 877 // for this plugin. 878 if (!$status) { 879 $exists = db_fetch_cell_prepared('SELECT COUNT(*) 880 FROM plugin_hooks 881 WHERE name = ? 882 AND status = 1', 883 array($plugin)); 884 885 if ($exists > 0) { 886 $status = 1; 887 } 888 } 889 890 db_execute_prepared("UPDATE plugin_hooks 891 SET `function` = ?, `status` = ?, 892 `file` = ? 893 WHERE `name` = ? 894 AND `hook` = ?", 895 array($function, $status, $file, $plugin, $hook)); 896 } 897} 898 899function api_plugin_remove_hooks($plugin) { 900 db_execute_prepared('DELETE FROM plugin_hooks 901 WHERE name = ?', 902 array($plugin)); 903} 904 905function api_plugin_enable_hooks($plugin) { 906 db_execute_prepared('UPDATE plugin_hooks 907 SET status = 1 908 WHERE name = ?', 909 array($plugin)); 910} 911 912function api_plugin_disable_hooks($plugin) { 913 db_execute_prepared("UPDATE plugin_hooks 914 SET status = 0 915 WHERE name = ? 916 AND hook != 'config_settings' 917 AND hook != 'config_arrays' 918 AND hook != 'config_form'", 919 array($plugin)); 920} 921 922function api_plugin_disable_hooks_all($plugin) { 923 db_execute_prepared("UPDATE plugin_hooks 924 SET status = 0 925 WHERE name = ?", 926 array($plugin)); 927} 928 929function api_plugin_register_realm($plugin, $file, $display, $admin = true) { 930 $files = explode(',', $file); 931 932 $i = 0; 933 $sql_where = '('; 934 foreach($files as $tfile) { 935 $sql_where .= ($sql_where != '(' ? ' OR ':'') . 936 ' (file = "' . $tfile . '" OR file LIKE "' . $tfile . ',%" OR file LIKE "%,' . $tfile . ',%" OR file LIKE "%,' . $tfile . '")'; 937 } 938 $sql_where .= ')'; 939 940 $realm_ids = db_fetch_assoc_prepared("SELECT id 941 FROM plugin_realms 942 WHERE plugin = ? 943 AND $sql_where", 944 array($plugin)); 945 946 if (cacti_sizeof($realm_ids) == 1) { 947 $realm_id = $realm_ids[0]['id']; 948 } elseif (cacti_sizeof($realm_ids) > 1) { 949 $realm_id = $realm_ids[0]['id']; 950 cacti_log('WARNING: Registering Realm for Plugin ' . $plugin . ' and Filenames ' . $file . ' is ambiguous. Using first matching Realm. Contact the plugin owner to resolve this issue.'); 951 952 unset($realm_ids[0]); 953 954 foreach ($realm_ids as $id) { 955 $realm_info = db_fetch_row_prepared('SELECT * 956 FROM plugin_realms 957 WHERE id = ?', 958 array($id['id'])); 959 960 if ($file == $realm_info['file']) { 961 db_execute_prepared('UPDATE IGNORE user_auth_realm 962 SET realm_id = ? 963 WHERE realm_id = ?', 964 array($realm_id+100, $realm_info['id']+100)); 965 966 db_execute_prepared('UPDATE IGNORE user_auth_group_realm 967 SET realm_id = ? 968 WHERE realm_id = ?', 969 array($realm_id+100, $realm_info['id']+100)); 970 971 db_execute_prepared('DELETE FROM plugin_realms 972 WHERE id = ?', 973 array($realm_info['id'])); 974 } elseif (strpos($realm_info['file'], $file)) { 975 if (substr($realm_info['file'], 0, strlen($file)) == $file) { 976 $file = substr($file, strlen($file)-1); 977 } else { 978 $file = str_replace(',' . $file, '', $realm_info['file']); 979 $file = str_replace(',,', ',', $file); 980 } 981 982 db_execute_prepared('UPDATE plugin_realms 983 SET file = ? 984 WHERE id = ?', 985 array($file, $realm_info['id'])); 986 } 987 } 988 } else { 989 $realm_id = false; 990 } 991 992 if ($realm_id === false) { 993 db_execute_prepared('REPLACE INTO plugin_realms 994 (plugin, file, display) 995 VALUES (?, ?, ?)', 996 array($plugin, $file, $display)); 997 998 if ($admin) { 999 $realm_id = db_fetch_cell_prepared('SELECT id 1000 FROM plugin_realms 1001 WHERE plugin = ? 1002 AND file = ?', 1003 array($plugin, $file), false); 1004 1005 $realm_id = $realm_id + 100; 1006 1007 $user_ids[] = read_config_option('admin_user'); 1008 if (isset($_SESSION['sess_user_id'])) { 1009 $user_ids[] = $_SESSION['sess_user_id']; 1010 } 1011 1012 if (cacti_sizeof($user_ids)) { 1013 foreach($user_ids as $user_id) { 1014 db_execute_prepared('REPLACE INTO user_auth_realm 1015 (user_id, realm_id) 1016 VALUES (?, ?)', 1017 array($user_id, $realm_id)); 1018 } 1019 } 1020 } 1021 } else { 1022 db_execute_prepared('UPDATE plugin_realms 1023 SET display = ?, 1024 file = ? 1025 WHERE id = ?', 1026 array($display, $file, $realm_id)); 1027 } 1028} 1029 1030function api_plugin_remove_realms($plugin) { 1031 $realms = db_fetch_assoc_prepared('SELECT id 1032 FROM plugin_realms 1033 WHERE plugin = ?', 1034 array($plugin), false); 1035 1036 foreach ($realms as $realm) { 1037 $id = $realm['id'] + 100; 1038 db_execute_prepared('DELETE FROM user_auth_realm 1039 WHERE realm_id = ?', 1040 array($id)); 1041 1042 db_execute_prepared('DELETE FROM user_auth_group_realm 1043 WHERE realm_id = ?', 1044 array($id)); 1045 } 1046 1047 db_execute_prepared('DELETE FROM plugin_realms 1048 WHERE plugin = ?', 1049 array($plugin)); 1050} 1051 1052function api_plugin_load_realms() { 1053 global $user_auth_realms, $user_auth_realm_filenames; 1054 1055 $plugin_realms = db_fetch_assoc('SELECT * 1056 FROM plugin_realms 1057 ORDER BY plugin, display'); 1058 1059 if (cacti_sizeof($plugin_realms)) { 1060 foreach ($plugin_realms as $plugin_realm) { 1061 $plugin_files = explode(',', $plugin_realm['file']); 1062 1063 foreach($plugin_files as $plugin_file) { 1064 $user_auth_realm_filenames[$plugin_file] = $plugin_realm['id'] + 100; 1065 } 1066 1067 $user_auth_realms[$plugin_realm['id'] + 100] = $plugin_realm['display']; 1068 } 1069 } 1070} 1071 1072function api_plugin_user_realm_auth($filename = '') { 1073 global $user_auth_realm_filenames; 1074 /* list all realms that this user has access to */ 1075 1076 if ($filename != '' && isset($user_auth_realm_filenames[basename($filename)])) { 1077 if (is_realm_allowed($user_auth_realm_filenames[basename($filename)])) { 1078 return true; 1079 } 1080 } 1081 1082 return false; 1083} 1084 1085function plugin_config_arrays() { 1086 global $config, $menu; 1087 1088 if ($config['poller_id'] == 1 || $config['connection'] == 'online') { 1089 $menu[__('Configuration')]['plugins.php'] = __('Plugins'); 1090 } 1091 1092 api_plugin_load_realms(); 1093} 1094 1095function plugin_draw_navigation_text($nav) { 1096 $nav['plugins.php:'] = array('title' => __('Plugins'), 'mapping' => 'index.php:', 'url' => 'plugins.php', 'level' => '1'); 1097 1098 return $nav; 1099} 1100 1101function plugin_is_compatible($plugin) { 1102 global $config; 1103 1104 $info = plugin_load_info_file($config['base_path'] . '/plugins/' . $plugin . '/INFO'); 1105 1106 if ($info !== false) { 1107 if (!isset($info['compat']) || cacti_version_compare(CACTI_VERSION, $info['compat'], '<')) { 1108 return array('compat' => false, 'requires' => __('Requires: Cacti >= %s', $info['compat'])); 1109 } 1110 } else { 1111 return array('compat' => false, 'requires' => __('Legacy Plugin')); 1112 } 1113 1114 return array('compat' => true, 'requires' => __('Requires: Cacti >= %s', $info['compat'])); 1115} 1116 1117function plugin_load_info_defaults($file, $info, $defaults = array()) { 1118 $result = $info; 1119 $dir = @basename(@dirname($file)); 1120 1121 if (!is_array($defaults)) { 1122 $defaults = array(); 1123 } 1124 1125 if (!is_array($result)) { 1126 $result = array(); 1127 } 1128 1129 $info_fields = array( 1130 'name' => ucfirst($dir), 1131 'requires' => '', 1132 'longname' => ucfirst($dir), 1133 'status' => file_exists($file) ? 0 : -4, 1134 'version' => __('Unknown'), 1135 'author' => __('Unknown'), 1136 'homepage' => isset($info['webpage']) ? $info['webpage'] : __('Not Stated'), 1137 'capabilities' => '', 1138 'directory' => $dir, 1139 ); 1140 1141 $info_fields = $info_fields + $defaults; 1142 foreach ($info_fields as $name => $value) { 1143 if (!array_key_exists($name, $result)) { 1144 $result[$name] = $value; 1145 } 1146 } 1147 1148 if (strstr($dir, ' ') !== false) { 1149 $result['status'] = -3; 1150 } elseif (strtolower($dir) != strtolower($result['name'])) { 1151 $result['status'] = -2; 1152 } elseif (!isset($result['compat']) || cacti_version_compare(CACTI_VERSION, $result['compat'], '<')) { 1153 $result['status'] = -1; 1154 } 1155 1156 return $result; 1157} 1158 1159function plugin_load_info_file($file) { 1160 $info = false; 1161 if (file_exists($file)) { 1162 if (is_readable($file)) { 1163 $info = parse_ini_file($file, true); 1164 if (cacti_sizeof($info) && array_key_exists('info', $info)) { 1165 $info = plugin_load_info_defaults($file, $info['info']); 1166 } else { 1167 cacti_log('WARNING: Loading plugin INFO file failed. Parsing INI file failed.', false, 'WEBUI'); 1168 } 1169 } else { 1170 cacti_log('WARNING: Loading plugin INFO file failed. INFO file not readable.', false, 'WEBUI'); 1171 } 1172 } else { 1173 cacti_log('WARNING: Loading plugin INFO file failed. INFO file does not exist.', false, 'WEBUI'); 1174 } 1175 1176 return $info; 1177} 1178 1179