From 895b7c74032bc4b04e3b05a424b629c59514cc5e Mon Sep 17 00:00:00 2001 From: alejandro Date: Mon, 23 Jan 2023 18:17:05 +0100 Subject: [PATCH 001/100] added exchange mail plugin --- .../Exchange_mail/exchange_mail.py | 451 ++++++++++++++++++ 1 file changed, 451 insertions(+) create mode 100644 pandora_plugins/Exchange_mail/exchange_mail.py diff --git a/pandora_plugins/Exchange_mail/exchange_mail.py b/pandora_plugins/Exchange_mail/exchange_mail.py new file mode 100644 index 0000000000..638c00d07e --- /dev/null +++ b/pandora_plugins/Exchange_mail/exchange_mail.py @@ -0,0 +1,451 @@ +# -*- coding: utf-8 -*- +from exchangelib import DELEGATE, Account, Credentials, Configuration,Message, Mailbox +from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter +from exchangelib import EWSTimeZone, EWSDateTime +BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter + +import urllib3 +urllib3.disable_warnings() + +import argparse,sys,re,json,os,traceback +from datetime import datetime,timedelta,timezone + + +__author__ = "Alejandro Sánchez Carrion" +__copyright__ = "Copyright 2022, PandoraFMS" +__maintainer__ = "Operations department" +__status__ = "Production" +__version__= '1.0' + +info = f""" +Pandora FMS Exchange Mail +Version = {__version__} +Description = This plugin can search for matches in your mail and find the number of matches, as well as list them. + +Manual execution + +./exchange_mail --server --username --password [ --subject ] [ --sender ] [ --date_start ] [ --date_end ] [ --agent_name ] [ --as_agent_plugin ] [ --tentacle_port ] [ --tentacle_address ] [ -g ] [ --data_dir ] + +there are four parameters with which to filter the mails + +subject +email +date + +You can use only one and filter from that or use the following combinations: + +subject +subject + sender +subject + sender + date +""" + +parser = argparse.ArgumentParser(description= info, formatter_class=argparse.RawTextHelpFormatter) +parser.add_argument('--server', help="Server name") +parser.add_argument('--username', help="User name") +parser.add_argument('--password', help="Password") +parser.add_argument('--smtp_address', help="SMTP address") +parser.add_argument('--subject', help="Select match in subjects") +parser.add_argument('--sender', help="Select coincidences from email") +parser.add_argument('--date_start', help="Search for matches from a certain date,Each date must be separated by a hyphen and in quotation marks, with the following format: 'year-month-day-hour-minute'. example: '2021-1-12-0-0'") +parser.add_argument('--date_end', help="Search for matches from a certain date,Each date must be separated by a hyphen and in quotation marks, with the following format: 'year-month-day-hour-minute'. example: '2021-6-12-0-0'") +parser.add_argument('--mail_list', help='List mail coincidences',type=int,default=0) + +parser.add_argument('--agent_name', help='agent name', default= "Exchange") +parser.add_argument('--module_prefix', help='module prefix', default= "Exchange") +parser.add_argument('-g', '--group', help='PandoraFMS destination group (default exchange)', default='exchange') +parser.add_argument('--data_dir', help='PandoraFMS data dir (default: /var/spool/pandora/data_in/)', default='/var/spool/pandora/data_in/') +parser.add_argument('--as_agent_plugin', help='mode plugin', default=0,type=int) +parser.add_argument('--tentacle_port', help='tentacle port', default=41121) +parser.add_argument('--tentacle_address', help='tentacle adress', default=None) + + +args = parser.parse_args() + +username,password,server,smtp_address=args.username,args.password,args.server,args.smtp_address + + +### Pandora Tools ###------------------------------------------------------------------------------------------------------- +modules = [] + +configuration = { + "data_in": args.data_dir, + "group" : args.group +} + +######################################################################################### +# print_agent +######################################################################################### +def print_agent(agent, modules, data_dir="/var/spool/pandora/data_in/", log_modules= None, print_flag = None): + """Prints agent XML. Requires agent conf (dict) and modules (list) as arguments. + - Use print_flag to show modules' XML in STDOUT. + - Returns a tuple (xml, data_file). + """ + data_file=None + + header = "\n" + header += "\n" + "\t\n" + "\t" + str(data["type"]) + "\n" + ) + + if type(data["type"]) is not str and "string" not in data["type"]: #### Strip spaces if module not generic_data_string + data["value"] = data["value"].strip() + if isinstance(data["value"], list): # Checks if value is a list + module_xml += "\t\n" + for value in data["value"]: + if type(value) is dict and "value" in value: + module_xml += "\t\n" + module_xml += "\t\t\n" + if "timestamp" in value: + module_xml += "\t\t\n" + module_xml += "\t\n" + module_xml += "\t\n" + else: + module_xml += "\t\n" + if "desc" in data: + module_xml += "\t\n" + if "unit" in data: + module_xml += "\t\n" + if "interval" in data: + module_xml += "\t\n" + if "tags" in data: + module_xml += "\t" + str(data["tags"]) + "\n" + if "module_group" in data: + module_xml += "\t" + str(data["module_group"]) + "\n" + if "module_parent" in data: + module_xml += "\t" + str(data["module_parent"]) + "\n" + if "min_warning" in data: + module_xml += "\t\n" + if "min_warning_forced" in data: + module_xml += "\t\n" + if "max_warning" in data: + module_xml += "\t\n" + if "max_warning_forced" in data: + module_xml += "\t\n" + if "min_critical" in data: + module_xml += "\t\n" + if "min_critical_forced" in data: + module_xml += "\t\n" + if "max_critical" in data: + module_xml += "\t\n" + if "max_critical_forced" in data: + module_xml += "\t\n" + if "str_warning" in data: + module_xml += "\t\n" + if "str_warning_forced" in data: + module_xml += "\t\n" + if "str_critical" in data: + module_xml += "\t\n" + if "str_critical_forced" in data: + module_xml += "\t\n" + if "critical_inverse" in data: + module_xml += "\t\n" + if "warning_inverse" in data: + module_xml += "\t\n" + if "max" in data: + module_xml += "\t\n" + if "min" in data: + module_xml += "\t\n" + if "post_process" in data: + module_xml += "\t\n" + if "disabled" in data: + module_xml += "\t\n" + if "min_ff_event" in data: + module_xml += "\t\n" + if "status" in data: + module_xml += "\t\n" + if "timestamp" in data: + module_xml += "\t\n" + if "custom_id" in data: + module_xml += "\t\n" + if "critical_instructions" in data: + module_xml += "\t\n" + if "warning_instructions" in data: + module_xml += "\t\n" + if "unknown_instructions" in data: + module_xml += "\t\n" + if "quiet" in data: + module_xml += "\t\n" + if "module_ff_interval" in data: + module_xml += "\t\n" + if "crontab" in data: + module_xml += "\t\n" + if "min_ff_event_normal" in data: + module_xml += "\t\n" + if "min_ff_event_warning" in data: + module_xml += "\t\n" + if "min_ff_event_critical" in data: + module_xml += "\t\n" + if "ff_type" in data: + module_xml += "\t\n" + if "ff_timeout" in data: + module_xml += "\t\n" + if "each_ff" in data: + module_xml += "\t\n" + if "module_parent_unlink" in data: + module_xml += "\t\n" + if "global_alerts" in data: + for alert in data["alert"]: + module_xml += "\t\n" + module_xml += "\n" + + if print_flag: + print (module_xml) + + return (module_xml) + +######################################################################################### +# write_xml +######################################################################################### + +def write_xml(xml, agent_name, data_dir="/var/spool/pandora/data_in/"): + """Creates a agent .data file in the specified data_dir folder\n + Args: + - xml (str): XML string to be written in the file. + - agent_name (str): agent name for the xml and file name. + - data_dir (str): folder in which the file will be created.""" + Utime = datetime.now().strftime('%s') + data_file = "%s/%s.%s.data" %(str(data_dir),agent_name,str(Utime)) + try: + with open(data_file, 'x') as data: + data.write(xml) + except OSError as o: + sys.exit(f"ERROR - Could not write file: {o}, please check directory permissions") + except Exception as e: + sys.exit(f"{type(e).__name__}: {e}") + return (data_file) + +# # default agent +def clean_agent() : + global agent + agent = { + "agent_name" : "", + "agent_alias" : "", + "parent_agent_name" : "", + "description" : "", + "version" : "", + "os_name" : "", + "os_version" : "", + "timestamp" : datetime.today().strftime('%Y/%m/%d %H:%M:%S'), + #"utimestamp" : int(datetime.timestamp(datetime.today())), + "address" : "", + "group" : configuration["group"], + "interval" : "", + "agent_mode" : "1", + } + return agent + +# default module +def clean_module() : + global modulo + modulo = { + "name" : "", + "type" : "generic_data_string", + "desc" : "", + "value" : "", + } + return modulo + +######################################################################################### +# tentacle_xml +######################################################################################### +def tentacle_xml(file, tentacle_ops,tentacle_path='', debug=0): + """Sends file using tentacle protocol\n + - Only works with one file at time. + - file variable needs full file path. + - tentacle_opts should be a dict with tentacle options (address [password] [port]). + - tentacle_path allows to define a custom path for tentacle client in case is not in sys path). + - if debug is enabled, the data file will not be removed after being sent. + + Returns 0 for OK and 1 for errors. + """ + + if file is None : + sys.stderr.write("Tentacle error: file path is required.") + else : + data_file = file + + if tentacle_ops['address'] is None : + sys.stderr.write("Tentacle error: No address defined") + return 1 + + try : + with open(data_file, 'r') as data: + data.read() + data.close() + except Exception as e : + sys.stderr.write(f"Tentacle error: {type(e).__name__} {e}") + return 1 + + tentacle_cmd = f"{tentacle_path}tentacle_client -v -a {tentacle_ops['address']} " + if "port" in tentacle_ops: + tentacle_cmd += f"-p {tentacle_ops['port']} " + if "password" in tentacle_ops: + tentacle_cmd += f"-x {tentacle_ops['password']} " + tentacle_cmd += f"{data_file} " + + tentacle_exe=Popen(tentacle_cmd, stdout=PIPE, shell=True) + rc=tentacle_exe.wait() + + if rc != 0 : + sys.stderr.write("Tentacle error") + return 1 + elif debug == 0 : + os.remove(file) + + return 0 + +## funcion agent +def agentplugin(modules,agent,plugin_type="server",data_dir="/var/spool/pandora/data_in/",tentacle=False,tentacle_conf=None) : + if plugin_type == "server": + for modulo in modules: + print_module(modulo,1) + + elif tentacle == True and tentacle_conf is not None: + agent_file=print_agent(agent, modules,data_dir) + if agent_file[1] is not None: + tentacle_xml(agent_file[1],tentacle_conf) + print ("1") + else: + print_agent(agent, modules,data_dir) + print ("1") + +def parse_result(list_email,sep="")-> list: + """ + + Return list containing each line as element + """ + + result=[] + + for line in list_email: + str_line=sep.join(str(elem) for elem in line) + str_dict={"value":str_line} + result.append(str_dict) + + return result + +# Create agent +clean_agent() +agent.update( + agent_name = args.agent_name , + agent_alias =args.agent_name , + description ="" +) + + +def connect(username,password,server,smtp_address): + creds = Credentials( + username=args.username, + password=args.password + ) + + try: + config = Configuration(server=args.server, credentials=creds) + + account = Account( + primary_smtp_address=args.smtp_address, + autodiscover=False, + config=config, + access_type=DELEGATE + ) + return account + except Exception as e: + sys.exit(f"{type(e).__name__}: {e}") + #print(account.root.tree()) + +account=connect(args.username,args.password,args.server,args.smtp_address) + +## Only one parameter +if args.subject and args.sender==None and args.date_start==None and args.date_end == None: + filtered_items = account.inbox.filter(subject__contains=args.subject) +if args.subject==None and args.sender and args.date_start==None and args.date_end == None: + filtered_items = account.inbox.filter(sender__icontains=args.sender) +if args.subject==None and args.sender==None and args.date_start and args.date_end : + date_start=args.date_start.split("-") + date_end=args.date_end.split("-") + filtered_items = account.inbox.filter(datetime_received__range=(datetime(int(date_start[0].strip()), int(date_start[1].strip()), int(date_start[2].strip()), int(date_start[3].strip()), int(date_start[4].strip())).replace(tzinfo=timezone.utc),datetime(int(date_end[0].strip()), int(date_end[1].strip()), int(date_end[2].strip()), int(date_end[3].strip()), int(date_end[4].strip())).replace(tzinfo=timezone.utc))) + +## Subject + sender +if args.subject and args.sender and args.date_start==None and args.date_end==None : + filtered_items = account.inbox.filter(sender__icontains=args.sender,subject__contains=args.subject) + +## All parameters +if args.subject and args.sender and args.date_start and args.date_end : + date_start=args.date_start.split("-") + date_end=args.date_end.split("-") + filtered_items = account.inbox.filter(datetime_received__range=(datetime(int(date_start[0].strip()), int(date_start[1].strip()), int(date_start[2].strip()), int(date_start[3].strip()), int(date_start[4].strip())).replace(tzinfo=timezone.utc),datetime(int(date_end[0].strip()), int(date_end[1].strip()), int(date_end[2].strip()), int(date_end[3].strip()), int(date_end[4].strip())).replace(tzinfo=timezone.utc)),sender__icontains=args.sender,subject__contains=args.subject) + +# List Number email coincidences +list_email=[] +# Count number messages coincidences +count=0 + +for item in filtered_items: + + count=count+1 + + list_email.append("("+str(item.datetime_received) + ") - "+str(item.subject)+" - "+str(item.sender)) + + #print(item.subject, item.sender, item.datetime_received) + +list_email = parse_result(list_email) + +clean_module() +modulo.update( + name = f"{args.module_prefix}.Coincidences_count", + type = "generic_data", + desc = "Number of mails matching the filter used in the run", + value = count +) +modules.append(modulo) + +if args.mail_list: + clean_module() + modulo.update( + name = f"{args.module_prefix}.Coincidences_list", + type = "generic_data_string", + desc = "List of mails matching the filter used in the run", + timestamp=datetime.today().strftime('%Y/%m/%d %H:%M:%S'), + value = list_email + ) + modules.append(modulo) + + +if args.tentacle_address is not None: + tentacle_conf={"address":args.tentacle_address,"port":args.tentacle_port} + agentplugin(modules,agent,"agent",configuration["data_in"],True,tentacle_conf) +elif args.as_agent_plugin!=1: + agentplugin(modules,agent,"agent",configuration["data_in"]) +else: + agentplugin(modules,agent) From a85a7eccf8c212f854dd9af6cc1cf561aa7b3dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Su=C3=A1rez?= Date: Sun, 4 Jun 2023 10:34:33 -0600 Subject: [PATCH 002/100] Modifications to accept spaces in agent alias CLI --- pandora_server/util/pandora_manage.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index 07c7bf6ad1..b11e862790 100755 --- a/pandora_server/util/pandora_manage.pl +++ b/pandora_server/util/pandora_manage.pl @@ -5389,6 +5389,8 @@ sub cli_get_agents_id_name_by_alias() { my @agents; my $where_value; + $agent_alias =~ s/ / /g; + if($strict eq 'strict') { $where_value = $agent_alias; } else { @@ -5404,14 +5406,14 @@ sub cli_get_agents_id_name_by_alias() { print "[ERROR] No agents retrieved.\n\n"; } else { if(is_metaconsole($conf) == 1) { - print "alias, id_agente, id_tagente, id_server, server_name\n"; + print "id_agente, alias, id_tagente, id_server, server_name\n"; foreach my $agent (@agents) { - print safe_output($agent->{'alias'}).", ".$agent->{'id_agente'}.", ".$agent->{'id_tagente'}.", ".$agent->{'id_server'}.", ".$agent->{'server_name'}."\n"; + print safe_output($agent->{'id_agente'}).", ".$agent->{'alias'}.", ".$agent->{'id_tagente'}.", ".$agent->{'id_server'}.", ".$agent->{'server_name'}."\n"; } } else { - print "alias, id_agente\n"; + print "id_agente, alias\n"; foreach my $agent (@agents) { print $agent->{'id_agente'}.",".safe_output($agent->{'alias'})."\n"; From b7a6c8f7301eea6145e1a1eef2094493ed512dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Su=C3=A1rez?= Date: Mon, 5 Jun 2023 08:41:10 -0600 Subject: [PATCH 003/100] Validate entities with safe input. --- pandora_server/util/pandora_manage.pl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index b11e862790..a7cc0af873 100755 --- a/pandora_server/util/pandora_manage.pl +++ b/pandora_server/util/pandora_manage.pl @@ -5384,13 +5384,11 @@ sub cli_get_agent_status() { ############################################################################## sub cli_get_agents_id_name_by_alias() { - my $agent_alias = @ARGV[2]; + my $agent_alias = safe_input(@ARGV[2]); my $strict = @ARGV[3]; my @agents; my $where_value; - $agent_alias =~ s/ / /g; - if($strict eq 'strict') { $where_value = $agent_alias; } else { From 86671c721193b5bc4e202e3ae5d49937a724ed32 Mon Sep 17 00:00:00 2001 From: Daniel Maya Date: Mon, 11 Dec 2023 11:36:34 +0100 Subject: [PATCH 004/100] #12350 added agent name editing --- .../godmode/agentes/agent_manager.php | 69 ++++++++++++++++++- .../godmode/agentes/configurar_agente.php | 18 ++++- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/pandora_console/godmode/agentes/agent_manager.php b/pandora_console/godmode/agentes/agent_manager.php index 26bae75929..a6e0d7e987 100644 --- a/pandora_console/godmode/agentes/agent_manager.php +++ b/pandora_console/godmode/agentes/agent_manager.php @@ -357,7 +357,18 @@ if ($new_agent === false) { $tableAgent->data['caption_name'][0] = __('Agent name'); $tableAgent->rowclass['name'] = 'w540px'; $tableAgent->cellstyle['name'][0] = 'width: 100%;'; - $tableAgent->data['name'][0] = html_print_input_text('agente', $nombre_agente, '', 76, 100, true, false, false, '', 'w100p'); + $tableAgent->data['name'][0] = html_print_input_text( + 'agente', + $nombre_agente, + '', + 76, + 100, + true, + true, + false, + '', + 'w100p' + ); $tableAgent->data['name'][0] .= html_print_div( [ 'class' => 'moduleIdBox', @@ -365,6 +376,28 @@ if ($new_agent === false) { ], true ); + + // Other than Linux, Solaris, AIX, BSD, HPUX, MacOs, and Windows. + if ($id_os !== '1' && $id_os !== '2' && $id_os !== '3' && $id_os !== '4' + && $id_os !== '5' && $id_os !== '7' && $id_os !== '8' + ) { + $tableAgent->data['name'][0] .= html_print_anchor( + [ + 'content' => html_print_image( + 'images/edit.svg', + true, + [ + 'border' => 0, + 'title' => __('Edit agent name'), + 'class' => 'main_menu_icon invert_filter after_input_icon forced_title clickable', + 'onclick' => 'editAgent()', + ] + ), + ], + true + ); + } + // Agent options for QR code. $agent_options_update = 'agent_options_update'; } @@ -1429,7 +1462,6 @@ ui_require_jquery_file('bgiframe'); 128 ); } - $("#text-agente").prop('readonly', true); // Disable fixed ip button if empty. @@ -1458,4 +1490,37 @@ ui_require_jquery_file('bgiframe'); $('#basic_options').addClass('invisible'); } } + + function editAgent() { + $(`#text-agente`).attr(`readonly`, false); + const title = ''; + const text = ''; + const id = uniqId(); + $("body").append('
'); + $("#" + id).empty(); + $("#" + id).append(text); + $("#" + id).dialog({ + height: 150, + width: 528, + opacity: 1, + modal: true, + position: { + my: "center", + at: "center", + of: window, + collision: "fit" + }, + title: title, + closeOnEscape: true, + buttons: [{ + text: "OK", + click: function() { + $(this).dialog("close"); + } + }], + open: function(event, ui) { + $(".ui-dialog-titlebar-close").hide(); + }, + }).show(); + } diff --git a/pandora_console/godmode/agentes/configurar_agente.php b/pandora_console/godmode/agentes/configurar_agente.php index b4abfa1ad7..673919908e 100644 --- a/pandora_console/godmode/agentes/configurar_agente.php +++ b/pandora_console/godmode/agentes/configurar_agente.php @@ -956,6 +956,13 @@ if ($update_agent) { $mssg_warning = 0; $id_agente = (int) get_parameter_post('id_agente'); $nombre_agente = str_replace('`', '‘', (string) get_parameter_post('agente', '')); + $repeated_name = db_get_row_sql( + sprintf( + 'SELECT nombre FROM tagente WHERE id_agente <> %s AND nombre like "%s"', + $id_agente, + $nombre_agente + ) + ); $alias_safe_output = strip_tags(io_safe_output(get_parameter('alias', ''))); $alias = io_safe_input(trim(preg_replace('/[\/\\\|%#&$]/', '', $alias_safe_output))); $alias_as_name = (int) get_parameter_post('alias_as_name', 0); @@ -1084,14 +1091,17 @@ if ($update_agent) { } } + // Verify if there is another agent with the same name but different ID. + if (empty($repeated_name) === false) { + ui_print_error_message(__('Agent with repeated name')); + } + if ($mssg_warning) { ui_print_warning_message(__('The ip or dns name entered cannot be resolved')); } - // Verify if there is another agent with the same name but different ID. if ($alias == '') { ui_print_error_message(__('No agent alias specified')); - // If there is an agent with the same name, but a different ID. } if ($direccion_agente !== $address_list && (bool) $unique_ip === true && $direccion_agente != '') { @@ -1152,6 +1162,10 @@ if ($update_agent) { 'vul_scan_enabled' => $vul_scan_enabled, ]; + if (empty($repeated_name) === true) { + $values['nombre'] = $nombre_agente; + } + if ($config['metaconsole_agent_cache'] == 1) { $values['update_module_count'] = 1; // Force an update of the agent cache. From bb8c55bf78b8cee73111a268a232df15367b42ef Mon Sep 17 00:00:00 2001 From: daniel Date: Wed, 20 Dec 2023 11:06:37 +0100 Subject: [PATCH 005/100] not show servers in metaconsole pandora_enterprise#12178 --- pandora_console/include/functions_servers.php | 58 ++++++++++++++----- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/pandora_console/include/functions_servers.php b/pandora_console/include/functions_servers.php index ff6fab73c6..d95e23494d 100644 --- a/pandora_console/include/functions_servers.php +++ b/pandora_console/include/functions_servers.php @@ -615,7 +615,7 @@ function servers_get_rate($avg_interval, $num_modules) * This function will get all the server information in an array * or a specific server. * - * @param integer $id_server An optional integer or array of integers + * @param integer|array $id_server An optional integer or array of integers * to select specific servers. * * @return mixed False in case the server doesn't exist or an array with info. @@ -624,28 +624,56 @@ function servers_get_info($id_server=-1, $sql_limit=-1) { global $config; - if (is_array($id_server)) { - $select_id = ' WHERE id_server IN ('.implode(',', $id_server).')'; + $select_id = ''; + if (is_array($id_server) === true) { + $select_id = ' AND id_server IN ('.implode(',', $id_server).')'; } else if ($id_server > 0) { - $select_id = ' WHERE id_server IN ('.(int) $id_server.')'; - } else { - $select_id = ''; + $select_id = ' AND id_server IN ('.(int) $id_server.')'; } - $sql = ' - SELECT * - FROM tserver '.$select_id.' - ORDER BY server_type'; + $types_sql = ''; + if (is_metaconsole() === true && isset($config['ndbh']) === false) { + $types_sql = sprintf( + ' AND ( + `server_type` = %d OR + `server_type` = %d OR + `server_type` = %d OR + `server_type` = %d + )', + SERVER_TYPE_AUTOPROVISION, + SERVER_TYPE_EVENT, + SERVER_TYPE_MIGRATION, + SERVER_TYPE_PREDICTION + ); + } + + $sql = sprintf( + 'SELECT * + FROM tserver + WHERE 1=1 + %s + %s + ORDER BY server_type', + $select_id, + $types_sql + ); if ($sql_limit !== -1) { - $sql = ' - SELECT * - FROM tserver '.$select_id.' - ORDER BY server_type'.$sql_limit; + $sql = sprintf( + 'SELECT * + FROM tserver + WHERE 1=1 + %s + %s + ORDER BY server_type + %s', + $select_id, + $types_sql, + $sql_limit + ); } $result = db_get_all_rows_sql($sql); - $time = get_system_time(); if (empty($result)) { return false; From 95f8519d5d3cab5b34e92b362b1820eb7f293575 Mon Sep 17 00:00:00 2001 From: Daniel Maya Date: Mon, 22 Jan 2024 17:22:23 +0100 Subject: [PATCH 006/100] #12687 Added import/export prd --- pandora_console/godmode/menu.php | 3 + .../resources/resources_export_import.php | 160 ++++++++++ .../include/ajax/resources.ajax.php | 74 +++++ pandora_console/include/class/Prd.class.php | 281 ++++++++++++++++++ 4 files changed, 518 insertions(+) create mode 100644 pandora_console/godmode/resources/resources_export_import.php create mode 100644 pandora_console/include/ajax/resources.ajax.php create mode 100644 pandora_console/include/class/Prd.class.php diff --git a/pandora_console/godmode/menu.php b/pandora_console/godmode/menu.php index a77e63b95b..4f116502e3 100644 --- a/pandora_console/godmode/menu.php +++ b/pandora_console/godmode/menu.php @@ -208,6 +208,9 @@ if ($access_console_node === true) { $sub['godmode/setup/os']['text'] = __('Operating systems'); $sub['godmode/setup/os']['id'] = 'edit_OS'; + + $sub['godmode/resources/resources_export_import']['text'] = __('Resources export/import'); + $sub['godmode/resources/resources_export_import']['id'] = 'resources_export_import'; } if ((bool) check_acl($config['id_user'], 0, 'AW') === true) { diff --git a/pandora_console/godmode/resources/resources_export_import.php b/pandora_console/godmode/resources/resources_export_import.php new file mode 100644 index 0000000000..569c854278 --- /dev/null +++ b/pandora_console/godmode/resources/resources_export_import.php @@ -0,0 +1,160 @@ +id = 'import_data_table'; +$table->class = 'databox filter-table-adv'; +$table->width = '100%'; +$table->data = []; +$table->style = []; +$table->size = []; + +$table->data[0][0] = html_print_label_input_block( + __('Resource importation'), + html_print_input_file('resource_import', true) +); + +$table->data[0][1] = html_print_label_input_block( + __('Group filter'), + html_print_select_groups(false, 'AW', true, 'group', '', '', __('All'), 0, true) +); + +html_print_table($table); + +$table = new stdClass(); +$table->id = 'export_data_table'; +$table->class = 'databox filter-table-adv'; +$table->width = '100%'; +$table->data = []; +$table->style = []; +$table->size = []; +$table->size[0] = '50%'; +$table->size[1] = '50%'; + +// Instance of the prd class. +$prd = new Prd(); + +$export_type = $prd->getTypesPrd(); + +$table->data[0][0] = html_print_label_input_block( + __('Export type'), + html_print_select( + $export_type, + 'export_type', + '', + '', + __('None'), + 0, + true, + false, + true, + 'w40p' + ) +); + +$table->data[1][0] = ''; + +$table->data[2][0] = html_print_button( + __('Export'), + 'export_button', + false, + '', + ['class' => 'flex_justify invisible_important'], + true +); + +html_print_table($table); + +?> + \ No newline at end of file diff --git a/pandora_console/include/ajax/resources.ajax.php b/pandora_console/include/ajax/resources.ajax.php new file mode 100644 index 0000000000..5c6c8ed02d --- /dev/null +++ b/pandora_console/include/ajax/resources.ajax.php @@ -0,0 +1,74 @@ +getOnePrdData($type); + if (empty($check) === false) { + switch ($type) { + case 'visual_console': + $result = html_print_label_input_block( + __('Visual console'), + io_safe_output( + html_print_select_from_sql( + 'SELECT id, name FROM tlayout', + 'select_value', + '', + '', + '', + 0, + true, + false, + true, + false, + false, + false, + GENERIC_SIZE_TEXT, + 'w40p', + ), + ) + ); + break; + + default: + // TODO. + break; + } + } + + echo $result; + return; + } + + if ($exportPrd === true) { + $type = (string) get_parameter('type', ''); + $value = (int) get_parameter('value', 0); + $name = (string) get_parameter('name', ''); + + $prd->exportPrd($type, $value, $name); + } +} diff --git a/pandora_console/include/class/Prd.class.php b/pandora_console/include/class/Prd.class.php new file mode 100644 index 0000000000..faf4a13c28 --- /dev/null +++ b/pandora_console/include/class/Prd.class.php @@ -0,0 +1,281 @@ +prdData = [ + 'visual_console' => [ + 'label' => __('Visual console'), + 'items' => [ + 'table' => 'tlayout', + 'value' => 'id', + 'show' => 'name', + ], + 'data' => [ + [ + 'table' => 'tlayout', + 'ref' => 'id', + ], + [ + 'table' => 'tlayout_data', + 'ref' => 'id_layout', + ], + ], + ], + ]; + + $this->columnRefs = [ + 'tlayout_data' => [ + 'id_agent' => [ + 'table' => 'tagente', + 'id' => 'id_agente', + 'column' => 'nombre', + ], + 'id_agente_modulo' => [ + 'table' => 'tagente_modulo', + 'id' => 'id_agente_modulo', + 'column' => 'nombre', + 'join' => [ + 'id_agente' => [ + 'table' => 'tagente', + 'id' => 'id_agente', + 'column' => 'nombre', + ], + ], + ], + ], + ]; + + $this->jsonRefs = [ + 'twidget_dashboard' => [ + 'options' => [ + 'agent' => [ + 'array' => false, + 'table' => 'tagente', + 'id' => 'id_agente', + 'column' => 'nombre', + ], + 'module' => [ + 'array' => false, + 'table' => 'tagente_modulo', + 'id' => 'id_agente_modulo', + 'column' => 'nombre', + 'join' => [ + 'id_agente' => [ + 'table' => 'tagente', + 'id' => 'id_agente', + 'column' => 'nombre', + ], + ], + ], + ], + ], + ]; + + $this->message = ''; + } + + + /** + * Generates a JSON error. + * + * @param string $msg Error message. + * + * @return void + */ + public function error(string $msg) + { + echo json_encode( + ['error' => $msg] + ); + } + + + /** + * Get $prdData. + * + * @return array + */ + public function getPrdData(): array + { + return $this->prdData; + } + + + /** + * Get one $prdData. + * + * @param string $item Item to be searched in array. + * + * @return boolean|array + */ + public function getOnePrdData(string $item): bool|array + { + if (isset($this->prdData[$item]) === false) { + return false; + } + + return $this->prdData[$item]; + } + + + /** + * Get $columnRefs. + * + * @return array + */ + public function getColumnRefs(): array + { + return $this->columnRefs; + } + + + /** + * Get one $columnRefs. + * + * @param string $item Item to be searched in array. + * + * @return boolean|array + */ + public function getOneColumnRefs(string $item): bool|array + { + if (isset($this->columnRefs[$item]) === false) { + return false; + } + + return $this->columnRefs[$item]; + } + + + /** + * Get $jsonRefs. + * + * @return array + */ + public function getJsonRefs(): array + { + return $this->jsonRefs; + } + + + /** + * Get types of prd. + * + * @return array + */ + public function getTypesPrd(): array + { + $result = []; + foreach ($this->prdData as $key => $value) { + $result[$key] = $value['label']; + } + + return $result; + } + + + /** + * Export prd. + * + * @return array + */ + public function exportPrd(string $type, $value, $name) :array + { + $result = []; + + $prd_data = $this->getOnePrdData($type); + if (empty($prd_data) === false) { + $result['prd_data'] = [ + 'type' => $type, + 'name' => $name, + ]; + + foreach ($prd_data['data'] as $key => $element) { + $sql = sprintf( + 'SELECT * FROM %s WHERE %s = %s', + $element['table'], + $element['ref'], + $value, + ); + + $test = db_get_all_rows_sql($sql); + + // $result[$element['table']] + // hd($test, true); + } + } + + return $result; + + } + + +} From 401b1973bed7bde5e06a680d2d1973f1bb4184d4 Mon Sep 17 00:00:00 2001 From: Daniel Maya Date: Wed, 24 Jan 2024 12:15:16 +0100 Subject: [PATCH 007/100] #12687 Added import/export prd 2 --- .../resources/resources_export_import.php | 28 +- .../include/ajax/resources.ajax.php | 94 ++++-- pandora_console/include/class/Prd.class.php | 318 ++++++++++++++++-- pandora_console/include/constants.php | 3 + 4 files changed, 381 insertions(+), 62 deletions(-) diff --git a/pandora_console/godmode/resources/resources_export_import.php b/pandora_console/godmode/resources/resources_export_import.php index 569c854278..146784f2e4 100644 --- a/pandora_console/godmode/resources/resources_export_import.php +++ b/pandora_console/godmode/resources/resources_export_import.php @@ -114,6 +114,7 @@ html_print_table($table); $("#button-export_button").addClass("invisible_important"); $("#export_data_table-1-0").html(''); } else { + $("#export_data_table-1-0").html(''); $.ajax({ type: "GET", url: "ajax.php", @@ -137,10 +138,18 @@ html_print_table($table); $("#button-export_button").click(function(e) { const value = $("#select_value").val(); if (value !== '0') { + //Show dialog. + confirmDialog({ + title: "", + message: "", + hideCancelButton: true + }, + "downloadDialog" + ); + $.ajax({ type: "GET", url: "ajax.php", - dataType: "html", data: { page: 'include/ajax/resources.ajax', exportPrd: 1, @@ -149,7 +158,24 @@ html_print_table($table); name: $("#select_value").text(), }, success: function(data) { + let a = document.createElement('a'); + const url = '' + data; + a.href = url; + a.download = data; + a.click(); + setTimeout(() => { + $.ajax({ + type: "DELETE", + url: "ajax.php", + data: { + page: 'include/ajax/resources.ajax', + deleteFile: 1, + filename: data, + }, + }); + $("#confirm_downloadDialog").dialog("close"); + }, 3000); }, error: function(data) { console.error("Fatal error in AJAX call to interpreter order", data) diff --git a/pandora_console/include/ajax/resources.ajax.php b/pandora_console/include/ajax/resources.ajax.php index 5c6c8ed02d..379a499407 100644 --- a/pandora_console/include/ajax/resources.ajax.php +++ b/pandora_console/include/ajax/resources.ajax.php @@ -20,6 +20,7 @@ if ((bool) is_ajax() === true) { $getResource = (bool) get_parameter('getResource', false); $exportPrd = (bool) get_parameter('exportPrd', false); + $deleteFile = (bool) get_parameter('deleteFile', false); $prd = new Prd(); @@ -27,37 +28,34 @@ if ((bool) is_ajax() === true) { $type = (string) get_parameter('type', ''); $result = false; - $check = $prd->getOnePrdData($type); - if (empty($check) === false) { - switch ($type) { - case 'visual_console': - $result = html_print_label_input_block( - __('Visual console'), - io_safe_output( - html_print_select_from_sql( - 'SELECT id, name FROM tlayout', - 'select_value', - '', - '', - '', - 0, - true, - false, - true, - false, - false, - false, - GENERIC_SIZE_TEXT, - 'w40p', - ), - ) - ); - break; - - default: - // TODO. - break; - } + $data = $prd->getOnePrdData($type); + if (empty($data) === false) { + $sql = sprintf( + 'SELECT %s FROM %s', + reset($data['items']['value']).', '.reset($data['items']['show']), + $data['items']['table'] + ); + $result = html_print_label_input_block( + $data['label'], + io_safe_output( + html_print_select_from_sql( + $sql, + 'select_value', + '', + '', + '', + 0, + true, + false, + true, + false, + false, + false, + GENERIC_SIZE_TEXT, + 'w40p', + ), + ) + ); } echo $result; @@ -69,6 +67,38 @@ if ((bool) is_ajax() === true) { $value = (int) get_parameter('value', 0); $name = (string) get_parameter('name', ''); - $prd->exportPrd($type, $value, $name); + $data = $prd->exportPrd($type, $value, $name); + + $return = ''; + + if (empty($data) === false) { + $filename = $type.'-'.date('Ymd').'-'.date('His').'.prd'; + $file = $config['attachment_store'].'/'.$filename; + + $file_pointer = fopen($file, 'a'); + if ($file_pointer !== false) { + $write = fwrite($file_pointer, $data); + + if ($write === false) { + $return = -2; + } else { + $return = $filename; + } + + fclose($file_pointer); + } else { + $return = -1; + } + } + + echo $return; + + return; + } + + if ($deleteFile === true) { + $filename = (string) get_parameter('filename', ''); + + unlink($config['attachment_store'].'/'.$filename); } } diff --git a/pandora_console/include/class/Prd.class.php b/pandora_console/include/class/Prd.class.php index faf4a13c28..c115b639a2 100644 --- a/pandora_console/include/class/Prd.class.php +++ b/pandora_console/include/class/Prd.class.php @@ -76,17 +76,219 @@ class Prd 'label' => __('Visual console'), 'items' => [ 'table' => 'tlayout', - 'value' => 'id', - 'show' => 'name', - ], - 'data' => [ - [ - 'table' => 'tlayout', - 'ref' => 'id', + 'value' => ['id'], + 'show' => ['name'], + 'data' => [ + [ + 'table' => 'tlayout_data', + 'ref' => ['id_layout'], + 'value' => ['id'], + ], ], - [ - 'table' => 'tlayout_data', - 'ref' => 'id_layout', + ], + ], + 'custom_report' => [ + 'label' => __('Custom report'), + 'items' => [ + 'table' => 'treport', + 'value' => ['id_report'], + 'show' => ['name'], + 'data' => [ + [ + 'table' => 'treport_content', + 'ref' => ['id_report'], + 'value' => ['id_rc'], + 'data' => [ + [ + 'table' => 'treport_content_item', + 'ref' => ['id_report_content'], + 'value' => ['id'], + ], + [ + 'table' => 'treport_content_sla_combined', + 'ref' => ['id_report_content'], + 'value' => ['id'], + ], + ], + ], + ], + ], + ], + 'policy' => [ + 'label' => __('Policy'), + 'items' => [ + 'table' => 'tpolicies', + 'value' => ['id'], + 'show' => ['name'], + 'data' => [ + [ + 'table' => 'tpolicy_agents', + 'ref' => ['id_policy'], + 'value' => ['id'], + ], + [ + 'table' => 'tpolicy_alerts', + 'ref' => ['id_policy'], + 'value' => ['id'], + 'data' => [ + [ + 'table' => 'tpolicy_alerts_actions', + 'ref' => ['id_policy_alert'], + 'value' => ['id'], + ], + ], + ], + [ + 'table' => 'tpolicy_collections', + 'ref' => ['id_policy'], + 'value' => ['id'], + ], + [ + 'table' => 'tpolicy_group_agents', + 'ref' => ['id_policy'], + 'value' => ['id'], + ], + [ + 'table' => 'tpolicy_groups', + 'ref' => ['id_policy'], + 'value' => ['id'], + ], + [ + 'table' => 'tpolicy_modules', + 'ref' => ['id_policy'], + 'value' => ['id'], + 'data' => [ + [ + 'table' => 'ttag_policy_module', + 'ref' => ['id_policy_module'], + 'value' => [ + 'id_tag', + 'id_policy_module', + ], + ], + [ + 'table' => 'tpolicy_modules_synth', + 'ref' => ['id_agent_module_target'], + 'value' => ['id'], + ], + ], + ], + [ + 'table' => 'tpolicy_modules_inventory', + 'ref' => ['id_policy'], + 'value' => ['id'], + ], + [ + 'table' => 'tpolicy_plugins', + 'ref' => ['id_policy'], + 'value' => ['id'], + ], + ], + ], + ], + 'service' => [ + 'label' => __('Service'), + 'items' => [ + 'table' => 'tservice', + 'value' => ['id'], + 'show' => ['name'], + 'data' => [ + [ + 'table' => 'tservice_element', + 'ref' => ['id_service'], + 'value' => ['id'], + ], + ], + ], + ], + 'network_map' => [ + 'label' => __('Network map'), + 'items' => [ + 'table' => 'tmap', + 'value' => ['id'], + 'show' => ['name'], + 'data' => [ + [ + 'table' => 'titem', + 'ref' => ['id_map'], + 'value' => ['id'], + ], + [ + 'table' => 'trel_item', + 'ref' => ['id_map'], + 'value' => ['id'], + ], + ], + ], + ], + 'gis_map' => [ + 'label' => __('GIS map'), + 'items' => [ + 'table' => 'tgis_map', + 'value' => ['id_tgis_map'], + 'show' => ['map_name'], + 'data' => [ + [ + 'table' => 'tgis_map_layer', + 'ref' => ['tgis_map_id_tgis_map'], + 'value' => ['id_tmap_layer'], + 'data' => [ + [ + 'table' => 'tgis_map_layer_groups', + 'ref' => ['layer_id'], + 'value' => [ + 'layer_id', + 'group_id', + ], + ], + [ + 'table' => 'tgis_map_layer_has_tagente', + 'ref' => ['tgis_map_layer_id_tmap_layer'], + 'value' => [ + 'tgis_map_layer_id_tmap_layer', + 'tagente_id_agente', + ], + ], + ], + ], + [ + 'table' => 'tgis_map_has_tgis_map_con', + 'ref' => ['tgis_map_id_tgis_map'], + 'value' => [ + 'tgis_map_id_tgis_map', + 'tgis_map_con_id_tmap_con', + ], + ], + ], + ], + ], + 'custom_graph' => [ + 'label' => __('Custom graph'), + 'items' => [ + 'table' => 'tgraph', + 'value' => ['id_graph'], + 'show' => ['name'], + 'data' => [ + [ + 'table' => 'tgraph_source', + 'ref' => ['id_graph'], + 'value' => ['id_gs'], + ], + ], + ], + ], + 'dashboard' => [ + 'label' => __('Dashboard'), + 'items' => [ + 'table' => 'tdashboard', + 'value' => ['id'], + 'show' => ['name'], + 'data' => [ + [ + 'table' => 'twidget_dashboard', + 'ref' => ['id_dashboard'], + 'value' => ['id'], + ], ], ], ], @@ -243,38 +445,96 @@ class Prd /** - * Export prd. + * Converts a resource into a string. * - * @return array + * @param string $type Item type. + * @param mixed $id Item value. + * @param string $name Item name. + * + * @return string */ - public function exportPrd(string $type, $value, $name) :array + public function exportPrd(string $type, mixed $id, string $name) :string { - $result = []; + $result = ''; $prd_data = $this->getOnePrdData($type); if (empty($prd_data) === false) { - $result['prd_data'] = [ - 'type' => $type, - 'name' => $name, - ]; + $result .= '[prd_data]'.LINE_BREAK.LINE_BREAK; + $result .= 'type="'.$type.'"'.LINE_BREAK; + $result .= 'name="'.$name.'"'.LINE_BREAK.LINE_BREAK; - foreach ($prd_data['data'] as $key => $element) { - $sql = sprintf( - 'SELECT * FROM %s WHERE %s = %s', - $element['table'], - $element['ref'], - $value, - ); + $result .= '['.$prd_data['items']['table'].']'.LINE_BREAK.LINE_BREAK; - $test = db_get_all_rows_sql($sql); + $sql = sprintf( + 'SELECT * FROM %s WHERE %s = %s', + $prd_data['items']['table'], + reset($prd_data['items']['value']), + $id, + ); - // $result[$element['table']] - // hd($test, true); + $row = db_get_row_sql($sql); + $primary_key = $row[reset($prd_data['items']['value'])]; + foreach ($row as $column => $value) { + $result .= $column.'['.$primary_key.']="'.$value.'"'.LINE_BREAK; + } + + $result .= LINE_BREAK; + + $result .= $this->recursiveExport($prd_data['items']['data'], $id); + } + + return $result; + } + + + /** + * Recursive function to traverse all data + * + * @param mixed $data Data. + * @param mixed $id Id value for search. + * + * @return string + */ + private function recursiveExport($data, $id): string + { + $result = ''; + + foreach ($data as $key => $element) { + $result .= '['.$element['table'].']'.LINE_BREAK.LINE_BREAK; + $sql = sprintf( + 'SELECT * FROM %s WHERE %s = %s', + $element['table'], + reset($element['ref']), + $id, + ); + + $rows = db_get_all_rows_sql($sql); + foreach ($rows as $row) { + if (count($element['value']) > 1) { + $primary_key = ''; + foreach ($element['value'] as $value) { + $primary_key .= $row[$value].'-'; + } + + $primary_key = substr($primary_key, 0, -1); + hd($primary_key, true); + } else { + $primary_key = $row[reset($element['value'])]; + } + + foreach ($row as $column => $value) { + $result .= $column.'['.$primary_key.']="'.$value.'"'.LINE_BREAK; + } + + $result .= LINE_BREAK; + } + + if (isset($element['data']) === true) { + $result .= $this->recursiveExport($element['data'], $primary_key); } } return $result; - } diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index b2ce8d88b4..422c2dcc95 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -906,3 +906,6 @@ define('DEMO_SERVICE', 6); define('DEMO_DASHBOARD', 7); define('DEMO_VISUAL_CONSOLE', 8); define('DEMO_PLUGIN', 9); + +// Export resources. +define('LINE_BREAK', "\n"); From e07d89883f1ba7d667c7370bf2228c80d8e75ee9 Mon Sep 17 00:00:00 2001 From: Daniel Maya Date: Mon, 29 Jan 2024 17:38:01 +0100 Subject: [PATCH 008/100] #12687 Added import/export prd 3 --- .../resources/resources_export_import.php | 36 +- pandora_console/include/class/Prd.class.php | 1278 ++++++++++++++++- 2 files changed, 1275 insertions(+), 39 deletions(-) diff --git a/pandora_console/godmode/resources/resources_export_import.php b/pandora_console/godmode/resources/resources_export_import.php index 146784f2e4..d1dcfc2123 100644 --- a/pandora_console/godmode/resources/resources_export_import.php +++ b/pandora_console/godmode/resources/resources_export_import.php @@ -43,6 +43,21 @@ if (check_acl($config['id_user'], 0, 'PM') === false) { require_once $config['homedir'].'/include/class/Prd.class.php'; +// Instance of the prd class. +$prd = new Prd(); + +$msg = ''; +if (isset($_FILES['resource_import']) === true) { + $data = parse_ini_file($_FILES['resource_import']['tmp_name'], true); + if ($data !== false) { + $msg[] = $prd->importPrd($data); + } else { + $msg[] = 'Esto es una prueba'; + } +} + +$msg = json_encode($msg); + $table = new stdClass(); $table->id = 'import_data_table'; $table->class = 'databox filter-table-adv'; @@ -56,12 +71,17 @@ $table->data[0][0] = html_print_label_input_block( html_print_input_file('resource_import', true) ); -$table->data[0][1] = html_print_label_input_block( - __('Group filter'), - html_print_select_groups(false, 'AW', true, 'group', '', '', __('All'), 0, true) +$table->data[0][0] .= html_print_submit_button( + __('Import resource'), + 'upload', + false, + [], + true ); +echo '
'; html_print_table($table); +echo '
'; $table = new stdClass(); $table->id = 'export_data_table'; @@ -73,9 +93,6 @@ $table->size = []; $table->size[0] = '50%'; $table->size[1] = '50%'; -// Instance of the prd class. -$prd = new Prd(); - $export_type = $prd->getTypesPrd(); $table->data[0][0] = html_print_label_input_block( @@ -109,6 +126,12 @@ html_print_table($table); ?>