/***************************************************************************** * * MACROS.C - Common macro functions for Nagios * * Copyright (c) 1999-2010 Ethan Galstad (egalstad@nagios.org) * Last Modified: 08-06-2010 * * License: * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************************************/ #include "../include/macros.h" #include "../include/config.h" #include "../include/common.h" #include "../include/objects.h" #include "../include/statusdata.h" #include "../include/comments.h" #ifdef NSCORE #include "../include/nagios.h" #else #include "../include/cgiutils.h" #endif #ifdef NSCORE extern int use_large_installation_tweaks; extern int enable_environment_macros; #endif extern char *illegal_output_chars; extern contact *contact_list; extern contactgroup *contactgroup_list; extern host *host_list; extern hostgroup *hostgroup_list; extern service *service_list; extern servicegroup *servicegroup_list; extern command *command_list; extern timeperiod *timeperiod_list; char *macro_x_names[MACRO_X_COUNT]; /* the macro names */ char *macro_user[MAX_USER_MACROS]; /* $USERx$ macros */ struct macro_key_code { char *name; /* macro key name */ int code; /* numeric macro code, usable in case statements */ int clean_options; char *value; }; struct macro_key_code macro_keys[MACRO_X_COUNT]; /* * These point to their corresponding pointer arrays in global_macros * AFTER macros have been initialized. * * They really only exist so that eventbroker modules that reference * them won't need to be re-compiled, although modules that rely * on their values after having run a certain command will require an * update */ char **macro_x = NULL; /* * scoped to this file to prevent (unintentional) mischief, * but see base/notifications.c for how to use it */ static nagios_macros global_macros; nagios_macros *get_global_macros(void) { return &global_macros; } /******************************************************************/ /************************ MACRO FUNCTIONS *************************/ /******************************************************************/ /* * locate a macro key based on its name by using a binary search * over all keys. O(log(n)) complexity and a vast improvement over * the previous linear scan */ const struct macro_key_code *find_macro_key(const char *name) { unsigned int high, low = 0; int value; struct macro_key_code *key; high = MACRO_X_COUNT; while(high - low > 0) { unsigned int mid = low + ((high - low) / 2); key = ¯o_keys[mid]; value = strcmp(name, key->name); if(value == 0) { return key; } if(value > 0) low = mid + 1; else high = mid; } return NULL; } /* * replace macros in notification commands with their values, * the thread-safe version */ int process_macros_r(nagios_macros *mac, char *input_buffer, char **output_buffer, int options) { char *temp_buffer = NULL; char *save_buffer = NULL; char *buf_ptr = NULL; char *delim_ptr = NULL; int in_macro = FALSE; int x = 0; char *selected_macro = NULL; char *original_macro = NULL; char *cleaned_macro = NULL; int clean_macro = FALSE; int found_macro_x = FALSE; int result = OK; int clean_options = 0; int free_macro = FALSE; int macro_options = 0; log_debug_info(DEBUGL_FUNCTIONS, 0, "process_macros_r()\n"); if(output_buffer == NULL) return ERROR; *output_buffer = (char *)strdup(""); if(input_buffer == NULL) return ERROR; in_macro = FALSE; log_debug_info(DEBUGL_MACROS, 1, "**** BEGIN MACRO PROCESSING ***********\n"); log_debug_info(DEBUGL_MACROS, 1, "Processing: '%s'\n", input_buffer); /* use a duplicate of original buffer, so we don't modify the original */ save_buffer = buf_ptr = (input_buffer ? strdup(input_buffer) : NULL); while(buf_ptr) { /* save pointer to this working part of buffer */ temp_buffer = buf_ptr; /* find the next delimiter - terminate preceding string and advance buffer pointer for next run */ if((delim_ptr = strchr(buf_ptr, '$'))) { delim_ptr[0] = '\x0'; buf_ptr = (char *)delim_ptr + 1; } /* no delimiter found - we already have the last of the buffer */ else buf_ptr = NULL; log_debug_info(DEBUGL_MACROS, 2, " Processing part: '%s'\n", temp_buffer); selected_macro = NULL; found_macro_x = FALSE; clean_macro = FALSE; /* we're in plain text... */ if(in_macro == FALSE) { /* add the plain text to the end of the already processed buffer */ *output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(temp_buffer) + 1); strcat(*output_buffer, temp_buffer); log_debug_info(DEBUGL_MACROS, 2, " Not currently in macro. Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer); in_macro = TRUE; } /* looks like we're in a macro, so process it... */ else { /* reset clean options */ clean_options = 0; /* grab the macro value */ result = grab_macro_value_r(mac, temp_buffer, &selected_macro, &clean_options, &free_macro); log_debug_info(DEBUGL_MACROS, 2, " Processed '%s', Clean Options: %d, Free: %d\n", temp_buffer, clean_options, free_macro); /* an error occurred - we couldn't parse the macro, so continue on */ if(result == ERROR) { log_debug_info(DEBUGL_MACROS, 0, " WARNING: An error occurred processing macro '%s'!\n", temp_buffer); if(free_macro == TRUE) my_free(selected_macro); } /* we already have a macro... */ if(result == OK) x = 0; /* an escaped $ is done by specifying two $$ next to each other */ else if(!strcmp(temp_buffer, "")) { log_debug_info(DEBUGL_MACROS, 2, " Escaped $. Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer); *output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + 2); strcat(*output_buffer, "$"); } /* a non-macro, just some user-defined string between two $s */ else { log_debug_info(DEBUGL_MACROS, 2, " Non-macro. Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer); /* add the plain text to the end of the already processed buffer */ *output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(temp_buffer) + 3); strcat(*output_buffer, "$"); strcat(*output_buffer, temp_buffer); strcat(*output_buffer, "$"); } /* insert macro */ if(selected_macro != NULL) { log_debug_info(DEBUGL_MACROS, 2, " Processed '%s', Clean Options: %d, Free: %d\n", temp_buffer, clean_options, free_macro); /* include any cleaning options passed back to us */ macro_options = (options | clean_options); log_debug_info(DEBUGL_MACROS, 2, " Cleaning options: global=%d, local=%d, effective=%d\n", options, clean_options, macro_options); /* URL encode the macro if requested - this allocates new memory */ if(macro_options & URL_ENCODE_MACRO_CHARS) { original_macro = selected_macro; selected_macro = get_url_encoded_string(selected_macro); if(free_macro == TRUE) { my_free(original_macro); } free_macro = TRUE; } /* some macros are cleaned... */ if(clean_macro == TRUE || ((macro_options & STRIP_ILLEGAL_MACRO_CHARS) || (macro_options & ESCAPE_MACRO_CHARS))) { /* add the (cleaned) processed macro to the end of the already processed buffer */ if(selected_macro != NULL && (cleaned_macro = clean_macro_chars(selected_macro, macro_options)) != NULL) { *output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(cleaned_macro) + 1); strcat(*output_buffer, cleaned_macro); log_debug_info(DEBUGL_MACROS, 2, " Cleaned macro. Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer); } } /* others are not cleaned */ else { /* add the processed macro to the end of the already processed buffer */ if(selected_macro != NULL) { *output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(selected_macro) + 1); strcat(*output_buffer, selected_macro); log_debug_info(DEBUGL_MACROS, 2, " Uncleaned macro. Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer); } } /* free memory if necessary (if we URL encoded the macro or we were told to do so by grab_macro_value()) */ if(free_macro == TRUE) my_free(selected_macro); log_debug_info(DEBUGL_MACROS, 2, " Just finished macro. Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer); } in_macro = FALSE; } } /* free copy of input buffer */ my_free(save_buffer); log_debug_info(DEBUGL_MACROS, 1, " Done. Final output: '%s'\n", *output_buffer); log_debug_info(DEBUGL_MACROS, 1, "**** END MACRO PROCESSING *************\n"); return OK; } int process_macros(char *input_buffer, char **output_buffer, int options) { return process_macros_r(&global_macros, input_buffer, output_buffer, options); } /******************************************************************/ /********************** MACRO GRAB FUNCTIONS **********************/ /******************************************************************/ /* grab macros that are specific to a particular host */ int grab_host_macros_r(nagios_macros *mac, host *hst) { /* clear host-related macros */ clear_host_macros_r(mac); clear_hostgroup_macros_r(mac); /* save pointer to host */ mac->host_ptr = hst; mac->hostgroup_ptr = NULL; if(hst == NULL) return ERROR; #ifdef NSCORE /* save pointer to host's first/primary hostgroup */ if(hst->hostgroups_ptr) mac->hostgroup_ptr = (hostgroup *)hst->hostgroups_ptr->object_ptr; #endif return OK; } int grab_host_macros(host *hst) { return grab_host_macros_r(&global_macros, hst); } /* grab hostgroup macros */ int grab_hostgroup_macros_r(nagios_macros *mac, hostgroup *hg) { /* clear hostgroup macros */ clear_hostgroup_macros_r(mac); /* save the hostgroup pointer for later */ mac->hostgroup_ptr = hg; if(hg == NULL) return ERROR; return OK; } int grab_hostgroup_macros(hostgroup *hg) { return grab_hostgroup_macros_r(&global_macros, hg); } /* grab macros that are specific to a particular service */ int grab_service_macros_r(nagios_macros *mac, service *svc) { /* clear service-related macros */ clear_service_macros_r(mac); clear_servicegroup_macros_r(mac); /* save pointer for later */ mac->service_ptr = svc; mac->servicegroup_ptr = NULL; if(svc == NULL) return ERROR; #ifdef NSCORE /* save first/primary servicegroup pointer for later */ if(svc->servicegroups_ptr) mac->servicegroup_ptr = (servicegroup *)svc->servicegroups_ptr->object_ptr; #endif return OK; } int grab_service_macros(service *svc) { return grab_service_macros_r(&global_macros, svc); } /* grab macros that are specific to a particular servicegroup */ int grab_servicegroup_macros_r(nagios_macros *mac, servicegroup *sg) { /* clear servicegroup macros */ clear_servicegroup_macros_r(mac); /* save the pointer for later */ mac->servicegroup_ptr = sg; if(sg == NULL) return ERROR; return OK; } int grab_servicegroup_macros(servicegroup *sg) { return grab_servicegroup_macros_r(&global_macros, sg); } /* grab macros that are specific to a particular contact */ int grab_contact_macros_r(nagios_macros *mac, contact *cntct) { /* clear contact-related macros */ clear_contact_macros_r(mac); clear_contactgroup_macros_r(mac); /* save pointer to contact for later */ mac->contact_ptr = cntct; mac->contactgroup_ptr = NULL; if(cntct == NULL) return ERROR; #ifdef NSCORE /* save pointer to first/primary contactgroup for later */ if(cntct->contactgroups_ptr) mac->contactgroup_ptr = (contactgroup *)cntct->contactgroups_ptr->object_ptr; #endif return OK; } int grab_contact_macros(contact *cntct) { return grab_contact_macros_r(&global_macros, cntct); } /******************************************************************/ /******************* MACRO GENERATION FUNCTIONS *******************/ /******************************************************************/ /* this is the big one */ int grab_macro_value_r(nagios_macros *mac, char *macro_buffer, char **output, int *clean_options, int *free_macro) { char *buf = NULL; char *ptr = NULL; char *macro_name = NULL; char *arg[2] = {NULL, NULL}; contact *temp_contact = NULL; contactgroup *temp_contactgroup = NULL; contactsmember *temp_contactsmember = NULL; char *temp_buffer = NULL; int delimiter_len = 0; int x, result = OK; const struct macro_key_code *mkey; /* for the early cases, this is the default */ *free_macro = FALSE; if(output == NULL) return ERROR; /* clear the old macro value */ my_free(*output); if(macro_buffer == NULL || clean_options == NULL || free_macro == NULL) return ERROR; /* * We handle argv and user macros first, since those are by far * the most commonly accessed ones (3.4 and 1.005 per check, * respectively). Since neither of them requires that we copy * the original buffer, we can also get away with some less * code for these simple cases. */ if(strstr(macro_buffer, "ARG") == macro_buffer) { /* which arg do we want? */ x = atoi(macro_buffer + 3); if(x <= 0 || x > MAX_COMMAND_ARGUMENTS) { return ERROR; } /* use a pre-computed macro value */ *output = mac->argv[x - 1]; return OK; } if(strstr(macro_buffer, "USER") == macro_buffer) { /* which macro do we want? */ x = atoi(macro_buffer + 4); if(x <= 0 || x > MAX_USER_MACROS) { return ERROR; } /* use a pre-computed macro value */ *output = macro_user[x - 1]; return OK; } /* most frequently used "x" macro gets a shortcut */ if(mac->host_ptr && !strcmp(macro_buffer, "HOSTADDRESS")) { if(mac->host_ptr->address) *output = mac->host_ptr->address; return OK; } /* work with a copy of the original buffer */ if((buf = (char *)strdup(macro_buffer)) == NULL) return ERROR; /* BY DEFAULT, TELL CALLER TO FREE MACRO BUFFER WHEN DONE */ *free_macro = TRUE; /* macro name is at start of buffer */ macro_name = buf; /* see if there's an argument - if so, this is most likely an on-demand macro */ if((ptr = strchr(buf, ':'))) { ptr[0] = '\x0'; ptr++; /* save the first argument - host name, hostgroup name, etc. */ arg[0] = ptr; /* try and find a second argument */ if((ptr = strchr(ptr, ':'))) { ptr[0] = '\x0'; ptr++; /* save second argument - service description or delimiter */ arg[1] = ptr; } } if((mkey = find_macro_key(macro_name))) { log_debug_info(DEBUGL_MACROS, 2, " macros[%d] (%s) match.\n", mkey->code, macro_x_names[mkey->code]); if(mkey->clean_options) { *clean_options |= mkey->clean_options; log_debug_info(DEBUGL_MACROS, 2, " New clean options: %d\n", *clean_options); } /* get the macro value */ result = grab_macrox_value_r(mac, mkey->code, arg[0], arg[1], output, free_macro); } /***** CONTACT ADDRESS MACROS *****/ /* NOTE: the code below should be broken out into a separate function */ else if(strstr(macro_name, "CONTACTADDRESS") == macro_name) { /* which address do we want? */ x = atoi(macro_name + 14) - 1; /* regular macro */ if(arg[0] == NULL) { /* use the saved pointer */ if((temp_contact = mac->contact_ptr) == NULL) { my_free(buf); return ERROR; } /* get the macro value by reference, so no need to free() */ *free_macro = FALSE; result = grab_contact_address_macro(x, temp_contact, output); } /* on-demand macro */ else { /* on-demand contact macro with a contactgroup and a delimiter */ if(arg[1] != NULL) { if((temp_contactgroup = find_contactgroup(arg[0])) == NULL) return ERROR; delimiter_len = strlen(arg[1]); /* concatenate macro values for all contactgroup members */ for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) { #ifdef NSCORE if((temp_contact = temp_contactsmember->contact_ptr) == NULL) continue; if((temp_contact = find_contact(temp_contactsmember->contact_name)) == NULL) continue; #endif /* get the macro value for this contact */ grab_contact_address_macro(x, temp_contact, &temp_buffer); if(temp_buffer == NULL) continue; /* add macro value to already running macro */ if(*output == NULL) *output = (char *)strdup(temp_buffer); else { if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL) continue; strcat(*output, arg[1]); strcat(*output, temp_buffer); } my_free(temp_buffer); } } /* else on-demand contact macro */ else { /* find the contact */ if((temp_contact = find_contact(arg[0])) == NULL) { my_free(buf); return ERROR; } /* get the macro value */ result = grab_contact_address_macro(x, temp_contact, output); } } } /***** CUSTOM VARIABLE MACROS *****/ else if(macro_name[0] == '_') { /* get the macro value */ result = grab_custom_macro_value_r(mac, macro_name, arg[0], arg[1], output); } /* no macro matched... */ else { log_debug_info(DEBUGL_MACROS, 0, " WARNING: Could not find a macro matching '%s'!\n", macro_name); result = ERROR; } /* free memory */ my_free(buf); return result; } int grab_macro_value(char *macro_buffer, char **output, int *clean_options, int *free_macro) { return grab_macro_value_r(&global_macros, macro_buffer, output, clean_options, free_macro); } int grab_macrox_value_r(nagios_macros *mac, int macro_type, char *arg1, char *arg2, char **output, int *free_macro) { host *temp_host = NULL; hostgroup *temp_hostgroup = NULL; hostsmember *temp_hostsmember = NULL; service *temp_service = NULL; servicegroup *temp_servicegroup = NULL; servicesmember *temp_servicesmember = NULL; contact *temp_contact = NULL; contactgroup *temp_contactgroup = NULL; contactsmember *temp_contactsmember = NULL; char *temp_buffer = NULL; int result = OK; int delimiter_len = 0; int free_sub_macro = FALSE; #ifdef NSCORE register int x; int authorized = TRUE; int problem = TRUE; int hosts_up = 0; int hosts_down = 0; int hosts_unreachable = 0; int hosts_down_unhandled = 0; int hosts_unreachable_unhandled = 0; int host_problems = 0; int host_problems_unhandled = 0; int services_ok = 0; int services_warning = 0; int services_unknown = 0; int services_critical = 0; int services_warning_unhandled = 0; int services_unknown_unhandled = 0; int services_critical_unhandled = 0; int service_problems = 0; int service_problems_unhandled = 0; #endif if(output == NULL || free_macro == NULL) return ERROR; /* BY DEFAULT, TELL CALLER TO FREE MACRO BUFFER WHEN DONE */ *free_macro = TRUE; /* handle the macro */ switch(macro_type) { /***************/ /* HOST MACROS */ /***************/ case MACRO_HOSTNAME: case MACRO_HOSTALIAS: case MACRO_HOSTADDRESS: case MACRO_LASTHOSTCHECK: case MACRO_LASTHOSTSTATECHANGE: case MACRO_HOSTOUTPUT: case MACRO_HOSTPERFDATA: case MACRO_HOSTSTATE: case MACRO_HOSTSTATEID: case MACRO_HOSTATTEMPT: case MACRO_HOSTEXECUTIONTIME: case MACRO_HOSTLATENCY: case MACRO_HOSTDURATION: case MACRO_HOSTDURATIONSEC: case MACRO_HOSTDOWNTIME: case MACRO_HOSTSTATETYPE: case MACRO_HOSTPERCENTCHANGE: case MACRO_HOSTACKAUTHOR: case MACRO_HOSTACKCOMMENT: case MACRO_LASTHOSTUP: case MACRO_LASTHOSTDOWN: case MACRO_LASTHOSTUNREACHABLE: case MACRO_HOSTCHECKCOMMAND: case MACRO_HOSTDISPLAYNAME: case MACRO_HOSTACTIONURL: case MACRO_HOSTNOTESURL: case MACRO_HOSTNOTES: case MACRO_HOSTCHECKTYPE: case MACRO_LONGHOSTOUTPUT: case MACRO_HOSTNOTIFICATIONNUMBER: case MACRO_HOSTNOTIFICATIONID: case MACRO_HOSTEVENTID: case MACRO_LASTHOSTEVENTID: case MACRO_HOSTGROUPNAMES: case MACRO_HOSTACKAUTHORNAME: case MACRO_HOSTACKAUTHORALIAS: case MACRO_MAXHOSTATTEMPTS: case MACRO_TOTALHOSTSERVICES: case MACRO_TOTALHOSTSERVICESOK: case MACRO_TOTALHOSTSERVICESWARNING: case MACRO_TOTALHOSTSERVICESUNKNOWN: case MACRO_TOTALHOSTSERVICESCRITICAL: case MACRO_HOSTPROBLEMID: case MACRO_LASTHOSTPROBLEMID: case MACRO_LASTHOSTSTATE: case MACRO_LASTHOSTSTATEID: /* a standard host macro */ if(arg2 == NULL) { /* find the host for on-demand macros */ if(arg1) { if((temp_host = find_host(arg1)) == NULL) return ERROR; } /* else use saved host pointer */ else if((temp_host = mac->host_ptr) == NULL) return ERROR; /* get the host macro value */ result = grab_standard_host_macro_r(mac, macro_type, temp_host, output, free_macro); } /* a host macro with a hostgroup name and delimiter */ else { if((temp_hostgroup = find_hostgroup(arg1)) == NULL) return ERROR; delimiter_len = strlen(arg2); /* concatenate macro values for all hostgroup members */ for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { #ifdef NSCORE if((temp_host = temp_hostsmember->host_ptr) == NULL) continue; #else if((temp_host = find_host(temp_hostsmember->host_name)) == NULL) continue; #endif /* get the macro value for this host */ grab_standard_host_macro_r(mac, macro_type, temp_host, &temp_buffer, &free_sub_macro); if(temp_buffer == NULL) continue; /* add macro value to already running macro */ if(*output == NULL) *output = (char *)strdup(temp_buffer); else { if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL) continue; strcat(*output, arg2); strcat(*output, temp_buffer); } if(free_sub_macro == TRUE) my_free(temp_buffer); } } break; /********************/ /* HOSTGROUP MACROS */ /********************/ case MACRO_HOSTGROUPNAME: case MACRO_HOSTGROUPALIAS: case MACRO_HOSTGROUPNOTES: case MACRO_HOSTGROUPNOTESURL: case MACRO_HOSTGROUPACTIONURL: case MACRO_HOSTGROUPMEMBERS: /* a standard hostgroup macro */ /* use the saved hostgroup pointer */ if(arg1 == NULL) { if((temp_hostgroup = mac->hostgroup_ptr) == NULL) return ERROR; } /* else find the hostgroup for on-demand macros */ else { if((temp_hostgroup = find_hostgroup(arg1)) == NULL) return ERROR; } /* get the hostgroup macro value */ result = grab_standard_hostgroup_macro_r(mac, macro_type, temp_hostgroup, output); break; /******************/ /* SERVICE MACROS */ /******************/ case MACRO_SERVICEDESC: case MACRO_SERVICESTATE: case MACRO_SERVICESTATEID: case MACRO_SERVICEATTEMPT: case MACRO_LASTSERVICECHECK: case MACRO_LASTSERVICESTATECHANGE: case MACRO_SERVICEOUTPUT: case MACRO_SERVICEPERFDATA: case MACRO_SERVICEEXECUTIONTIME: case MACRO_SERVICELATENCY: case MACRO_SERVICEDURATION: case MACRO_SERVICEDURATIONSEC: case MACRO_SERVICEDOWNTIME: case MACRO_SERVICESTATETYPE: case MACRO_SERVICEPERCENTCHANGE: case MACRO_SERVICEACKAUTHOR: case MACRO_SERVICEACKCOMMENT: case MACRO_LASTSERVICEOK: case MACRO_LASTSERVICEWARNING: case MACRO_LASTSERVICEUNKNOWN: case MACRO_LASTSERVICECRITICAL: case MACRO_SERVICECHECKCOMMAND: case MACRO_SERVICEDISPLAYNAME: case MACRO_SERVICEACTIONURL: case MACRO_SERVICENOTESURL: case MACRO_SERVICENOTES: case MACRO_SERVICECHECKTYPE: case MACRO_LONGSERVICEOUTPUT: case MACRO_SERVICENOTIFICATIONNUMBER: case MACRO_SERVICENOTIFICATIONID: case MACRO_SERVICEEVENTID: case MACRO_LASTSERVICEEVENTID: case MACRO_SERVICEGROUPNAMES: case MACRO_SERVICEACKAUTHORNAME: case MACRO_SERVICEACKAUTHORALIAS: case MACRO_MAXSERVICEATTEMPTS: case MACRO_SERVICEISVOLATILE: case MACRO_SERVICEPROBLEMID: case MACRO_LASTSERVICEPROBLEMID: case MACRO_LASTSERVICESTATE: case MACRO_LASTSERVICESTATEID: /* use saved service pointer */ if(arg1 == NULL && arg2 == NULL) { if((temp_service = mac->service_ptr) == NULL) return ERROR; result = grab_standard_service_macro_r(mac, macro_type, temp_service, output, free_macro); } /* else and ondemand macro... */ else { /* if first arg is blank, it means use the current host name */ if(arg1 == NULL || arg1[0] == '\x0') { if(mac->host_ptr == NULL) return ERROR; if((temp_service = find_service(mac->host_ptr->name, arg2))) { /* get the service macro value */ result = grab_standard_service_macro_r(mac, macro_type, temp_service, output, free_macro); } } /* on-demand macro with both host and service name */ else if((temp_service = find_service(arg1, arg2))) { /* get the service macro value */ result = grab_standard_service_macro_r(mac, macro_type, temp_service, output, free_macro); } /* else we have a service macro with a servicegroup name and a delimiter... */ else if(arg1 && arg2) { if((temp_servicegroup = find_servicegroup(arg1)) == NULL) return ERROR; delimiter_len = strlen(arg2); /* concatenate macro values for all servicegroup members */ for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) { #ifdef NSCORE if((temp_service = temp_servicesmember->service_ptr) == NULL) continue; #else if((temp_service = find_service(temp_servicesmember->host_name, temp_servicesmember->service_description)) == NULL) continue; #endif /* get the macro value for this service */ grab_standard_service_macro_r(mac, macro_type, temp_service, &temp_buffer, &free_sub_macro); if(temp_buffer == NULL) continue; /* add macro value to already running macro */ if(*output == NULL) *output = (char *)strdup(temp_buffer); else { if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL) continue; strcat(*output, arg2); strcat(*output, temp_buffer); } if(free_sub_macro == TRUE) my_free(temp_buffer); } } else return ERROR; } break; /***********************/ /* SERVICEGROUP MACROS */ /***********************/ case MACRO_SERVICEGROUPNAME: case MACRO_SERVICEGROUPALIAS: case MACRO_SERVICEGROUPNOTES: case MACRO_SERVICEGROUPNOTESURL: case MACRO_SERVICEGROUPACTIONURL: case MACRO_SERVICEGROUPMEMBERS: /* a standard servicegroup macro */ /* use the saved servicegroup pointer */ if(arg1 == NULL) { if((temp_servicegroup = mac->servicegroup_ptr) == NULL) return ERROR; } /* else find the servicegroup for on-demand macros */ else { if((temp_servicegroup = find_servicegroup(arg1)) == NULL) return ERROR; } /* get the servicegroup macro value */ result = grab_standard_servicegroup_macro_r(mac, macro_type, temp_servicegroup, output); break; /******************/ /* CONTACT MACROS */ /******************/ case MACRO_CONTACTNAME: case MACRO_CONTACTALIAS: case MACRO_CONTACTEMAIL: case MACRO_CONTACTPAGER: case MACRO_CONTACTGROUPNAMES: /* a standard contact macro */ if(arg2 == NULL) { /* find the contact for on-demand macros */ if(arg1) { if((temp_contact = find_contact(arg1)) == NULL) return ERROR; } /* else use saved contact pointer */ else if((temp_contact = mac->contact_ptr) == NULL) return ERROR; /* get the contact macro value */ result = grab_standard_contact_macro_r(mac, macro_type, temp_contact, output); } /* a contact macro with a contactgroup name and delimiter */ else { if((temp_contactgroup = find_contactgroup(arg1)) == NULL) return ERROR; delimiter_len = strlen(arg2); /* concatenate macro values for all contactgroup members */ for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) { #ifdef NSCORE if((temp_contact = temp_contactsmember->contact_ptr) == NULL) continue; #else if((temp_contact = find_contact(temp_contactsmember->contact_name)) == NULL) continue; #endif /* get the macro value for this contact */ grab_standard_contact_macro_r(mac, macro_type, temp_contact, &temp_buffer); if(temp_buffer == NULL) continue; /* add macro value to already running macro */ if(*output == NULL) *output = (char *)strdup(temp_buffer); else { if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL) continue; strcat(*output, arg2); strcat(*output, temp_buffer); } my_free(temp_buffer); } } break; /***********************/ /* CONTACTGROUP MACROS */ /***********************/ case MACRO_CONTACTGROUPNAME: case MACRO_CONTACTGROUPALIAS: case MACRO_CONTACTGROUPMEMBERS: /* a standard contactgroup macro */ /* use the saved contactgroup pointer */ if(arg1 == NULL) { if((temp_contactgroup = mac->contactgroup_ptr) == NULL) return ERROR; } /* else find the contactgroup for on-demand macros */ else { if((temp_contactgroup = find_contactgroup(arg1)) == NULL) return ERROR; } /* get the contactgroup macro value */ result = grab_standard_contactgroup_macro(macro_type, temp_contactgroup, output); break; /***********************/ /* NOTIFICATION MACROS */ /***********************/ case MACRO_NOTIFICATIONTYPE: case MACRO_NOTIFICATIONNUMBER: case MACRO_NOTIFICATIONRECIPIENTS: case MACRO_NOTIFICATIONISESCALATED: case MACRO_NOTIFICATIONAUTHOR: case MACRO_NOTIFICATIONAUTHORNAME: case MACRO_NOTIFICATIONAUTHORALIAS: case MACRO_NOTIFICATIONCOMMENT: /* notification macros have already been pre-computed */ *output = mac->x[macro_type]; *free_macro = FALSE; break; /********************/ /* DATE/TIME MACROS */ /********************/ case MACRO_LONGDATETIME: case MACRO_SHORTDATETIME: case MACRO_DATE: case MACRO_TIME: case MACRO_TIMET: case MACRO_ISVALIDTIME: case MACRO_NEXTVALIDTIME: /* calculate macros */ result = grab_datetime_macro_r(mac, macro_type, arg1, arg2, output); break; /*****************/ /* STATIC MACROS */ /*****************/ case MACRO_ADMINEMAIL: case MACRO_ADMINPAGER: case MACRO_MAINCONFIGFILE: case MACRO_STATUSDATAFILE: case MACRO_RETENTIONDATAFILE: case MACRO_OBJECTCACHEFILE: case MACRO_TEMPFILE: case MACRO_LOGFILE: case MACRO_RESOURCEFILE: case MACRO_COMMANDFILE: case MACRO_HOSTPERFDATAFILE: case MACRO_SERVICEPERFDATAFILE: case MACRO_PROCESSSTARTTIME: case MACRO_TEMPPATH: case MACRO_EVENTSTARTTIME: /* no need to do any more work - these are already precomputed for us */ *output = global_macros.x[macro_type]; *free_macro = FALSE; break; /******************/ /* SUMMARY MACROS */ /******************/ case MACRO_TOTALHOSTSUP: case MACRO_TOTALHOSTSDOWN: case MACRO_TOTALHOSTSUNREACHABLE: case MACRO_TOTALHOSTSDOWNUNHANDLED: case MACRO_TOTALHOSTSUNREACHABLEUNHANDLED: case MACRO_TOTALHOSTPROBLEMS: case MACRO_TOTALHOSTPROBLEMSUNHANDLED: case MACRO_TOTALSERVICESOK: case MACRO_TOTALSERVICESWARNING: case MACRO_TOTALSERVICESCRITICAL: case MACRO_TOTALSERVICESUNKNOWN: case MACRO_TOTALSERVICESWARNINGUNHANDLED: case MACRO_TOTALSERVICESCRITICALUNHANDLED: case MACRO_TOTALSERVICESUNKNOWNUNHANDLED: case MACRO_TOTALSERVICEPROBLEMS: case MACRO_TOTALSERVICEPROBLEMSUNHANDLED: #ifdef NSCORE /* generate summary macros if needed */ if(mac->x[MACRO_TOTALHOSTSUP] == NULL) { /* get host totals */ for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) { /* filter totals based on contact if necessary */ if(mac->contact_ptr != NULL) authorized = is_contact_for_host(temp_host, mac->contact_ptr); if(authorized == TRUE) { problem = TRUE; if(temp_host->current_state == HOST_UP && temp_host->has_been_checked == TRUE) hosts_up++; else if(temp_host->current_state == HOST_DOWN) { if(temp_host->scheduled_downtime_depth > 0) problem = FALSE; if(temp_host->problem_has_been_acknowledged == TRUE) problem = FALSE; if(temp_host->checks_enabled == FALSE) problem = FALSE; if(problem == TRUE) hosts_down_unhandled++; hosts_down++; } else if(temp_host->current_state == HOST_UNREACHABLE) { if(temp_host->scheduled_downtime_depth > 0) problem = FALSE; if(temp_host->problem_has_been_acknowledged == TRUE) problem = FALSE; if(temp_host->checks_enabled == FALSE) problem = FALSE; if(problem == TRUE) hosts_down_unhandled++; hosts_unreachable++; } } } host_problems = hosts_down + hosts_unreachable; host_problems_unhandled = hosts_down_unhandled + hosts_unreachable_unhandled; /* get service totals */ for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) { /* filter totals based on contact if necessary */ if(mac->contact_ptr != NULL) authorized = is_contact_for_service(temp_service, mac->contact_ptr); if(authorized == TRUE) { problem = TRUE; if(temp_service->current_state == STATE_OK && temp_service->has_been_checked == TRUE) services_ok++; else if(temp_service->current_state == STATE_WARNING) { temp_host = find_host(temp_service->host_name); if(temp_host != NULL && (temp_host->current_state == HOST_DOWN || temp_host->current_state == HOST_UNREACHABLE)) problem = FALSE; if(temp_service->scheduled_downtime_depth > 0) problem = FALSE; if(temp_service->problem_has_been_acknowledged == TRUE) problem = FALSE; if(temp_service->checks_enabled == FALSE) problem = FALSE; if(problem == TRUE) services_warning_unhandled++; services_warning++; } else if(temp_service->current_state == STATE_UNKNOWN) { temp_host = find_host(temp_service->host_name); if(temp_host != NULL && (temp_host->current_state == HOST_DOWN || temp_host->current_state == HOST_UNREACHABLE)) problem = FALSE; if(temp_service->scheduled_downtime_depth > 0) problem = FALSE; if(temp_service->problem_has_been_acknowledged == TRUE) problem = FALSE; if(temp_service->checks_enabled == FALSE) problem = FALSE; if(problem == TRUE) services_unknown_unhandled++; services_unknown++; } else if(temp_service->current_state == STATE_CRITICAL) { temp_host = find_host(temp_service->host_name); if(temp_host != NULL && (temp_host->current_state == HOST_DOWN || temp_host->current_state == HOST_UNREACHABLE)) problem = FALSE; if(temp_service->scheduled_downtime_depth > 0) problem = FALSE; if(temp_service->problem_has_been_acknowledged == TRUE) problem = FALSE; if(temp_service->checks_enabled == FALSE) problem = FALSE; if(problem == TRUE) services_critical_unhandled++; services_critical++; } } } service_problems = services_warning + services_critical + services_unknown; service_problems_unhandled = services_warning_unhandled + services_critical_unhandled + services_unknown_unhandled; /* these macros are time-intensive to compute, and will likely be used together, so save them all for future use */ for(x = MACRO_TOTALHOSTSUP; x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED; x++) my_free(mac->x[x]); asprintf(&mac->x[MACRO_TOTALHOSTSUP], "%d", hosts_up); asprintf(&mac->x[MACRO_TOTALHOSTSDOWN], "%d", hosts_down); asprintf(&mac->x[MACRO_TOTALHOSTSUNREACHABLE], "%d", hosts_unreachable); asprintf(&mac->x[MACRO_TOTALHOSTSDOWNUNHANDLED], "%d", hosts_down_unhandled); asprintf(&mac->x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED], "%d", hosts_unreachable_unhandled); asprintf(&mac->x[MACRO_TOTALHOSTPROBLEMS], "%d", host_problems); asprintf(&mac->x[MACRO_TOTALHOSTPROBLEMSUNHANDLED], "%d", host_problems_unhandled); asprintf(&mac->x[MACRO_TOTALSERVICESOK], "%d", services_ok); asprintf(&mac->x[MACRO_TOTALSERVICESWARNING], "%d", services_warning); asprintf(&mac->x[MACRO_TOTALSERVICESCRITICAL], "%d", services_critical); asprintf(&mac->x[MACRO_TOTALSERVICESUNKNOWN], "%d", services_unknown); asprintf(&mac->x[MACRO_TOTALSERVICESWARNINGUNHANDLED], "%d", services_warning_unhandled); asprintf(&mac->x[MACRO_TOTALSERVICESCRITICALUNHANDLED], "%d", services_critical_unhandled); asprintf(&mac->x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED], "%d", services_unknown_unhandled); asprintf(&mac->x[MACRO_TOTALSERVICEPROBLEMS], "%d", service_problems); asprintf(&mac->x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED], "%d", service_problems_unhandled); } /* return only the macro the user requested */ *output = mac->x[macro_type]; /* tell caller to NOT free memory when done */ *free_macro = FALSE; #endif break; default: log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED MACRO #%d! THIS IS A BUG!\n", macro_type); return ERROR; break; } return result; } int grab_macrox_value(int macro_type, char *arg1, char *arg2, char **output, int *free_macro) { return grab_macrox_value_r(&global_macros, macro_type, arg1, arg2, output, free_macro); } /* calculates the value of a custom macro */ int grab_custom_macro_value_r(nagios_macros *mac, char *macro_name, char *arg1, char *arg2, char **output) { host *temp_host = NULL; hostgroup *temp_hostgroup = NULL; hostsmember *temp_hostsmember = NULL; service *temp_service = NULL; servicegroup *temp_servicegroup = NULL; servicesmember *temp_servicesmember = NULL; contact *temp_contact = NULL; contactgroup *temp_contactgroup = NULL; contactsmember *temp_contactsmember = NULL; int delimiter_len = 0; char *temp_buffer = NULL; int result = OK; if(macro_name == NULL || output == NULL) return ERROR; /***** CUSTOM HOST MACRO *****/ if(strstr(macro_name, "_HOST") == macro_name) { /* a standard host macro */ if(arg2 == NULL) { /* find the host for on-demand macros */ if(arg1) { if((temp_host = find_host(arg1)) == NULL) return ERROR; } /* else use saved host pointer */ else if((temp_host = mac->host_ptr) == NULL) return ERROR; /* get the host macro value */ result = grab_custom_object_macro_r(mac, macro_name + 5, temp_host->custom_variables, output); } /* a host macro with a hostgroup name and delimiter */ else { if((temp_hostgroup = find_hostgroup(arg1)) == NULL) return ERROR; delimiter_len = strlen(arg2); /* concatenate macro values for all hostgroup members */ for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { #ifdef NSCORE if((temp_host = temp_hostsmember->host_ptr) == NULL) continue; #else if((temp_host = find_host(temp_hostsmember->host_name)) == NULL) continue; #endif /* get the macro value for this host */ grab_custom_macro_value_r(mac, macro_name, temp_host->name, NULL, &temp_buffer); if(temp_buffer == NULL) continue; /* add macro value to already running macro */ if(*output == NULL) *output = (char *)strdup(temp_buffer); else { if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL) continue; strcat(*output, arg2); strcat(*output, temp_buffer); } my_free(temp_buffer); } } } /***** CUSTOM SERVICE MACRO *****/ else if(strstr(macro_name, "_SERVICE") == macro_name) { /* use saved service pointer */ if(arg1 == NULL && arg2 == NULL) { if((temp_service = mac->service_ptr) == NULL) return ERROR; /* get the service macro value */ result = grab_custom_object_macro_r(mac, macro_name + 8, temp_service->custom_variables, output); } /* else and ondemand macro... */ else { /* if first arg is blank, it means use the current host name */ if(mac->host_ptr == NULL) return ERROR; if((temp_service = find_service((mac->host_ptr) ? mac->host_ptr->name : NULL, arg2))) { /* get the service macro value */ result = grab_custom_object_macro_r(mac, macro_name + 8, temp_service->custom_variables, output); } /* else we have a service macro with a servicegroup name and a delimiter... */ else { if((temp_servicegroup = find_servicegroup(arg1)) == NULL) return ERROR; delimiter_len = strlen(arg2); /* concatenate macro values for all servicegroup members */ for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) { #ifdef NSCORE if((temp_service = temp_servicesmember->service_ptr) == NULL) continue; #else if((temp_service = find_service(temp_servicesmember->host_name, temp_servicesmember->service_description)) == NULL) continue; #endif /* get the macro value for this service */ grab_custom_macro_value_r(mac, macro_name, temp_service->host_name, temp_service->description, &temp_buffer); if(temp_buffer == NULL) continue; /* add macro value to already running macro */ if(*output == NULL) *output = (char *)strdup(temp_buffer); else { if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL) continue; strcat(*output, arg2); strcat(*output, temp_buffer); } my_free(temp_buffer); } } } } /***** CUSTOM CONTACT VARIABLE *****/ else if(strstr(macro_name, "_CONTACT") == macro_name) { /* a standard contact macro */ if(arg2 == NULL) { /* find the contact for on-demand macros */ if(arg1) { if((temp_contact = find_contact(arg1)) == NULL) return ERROR; } /* else use saved contact pointer */ else if((temp_contact = mac->contact_ptr) == NULL) return ERROR; /* get the contact macro value */ result = grab_custom_object_macro_r(mac, macro_name + 8, temp_contact->custom_variables, output); } /* a contact macro with a contactgroup name and delimiter */ else { if((temp_contactgroup = find_contactgroup(arg1)) == NULL) return ERROR; delimiter_len = strlen(arg2); /* concatenate macro values for all contactgroup members */ for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) { #ifdef NSCORE if((temp_contact = temp_contactsmember->contact_ptr) == NULL) continue; #else if((temp_contact = find_contact(temp_contactsmember->contact_name)) == NULL) continue; #endif /* get the macro value for this contact */ grab_custom_macro_value_r(mac, macro_name, temp_contact->name, NULL, &temp_buffer); if(temp_buffer == NULL) continue; /* add macro value to already running macro */ if(*output == NULL) *output = (char *)strdup(temp_buffer); else { if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL) continue; strcat(*output, arg2); strcat(*output, temp_buffer); } my_free(temp_buffer); } } } else return ERROR; return result; } int grab_custom_macro_value(char *macro_name, char *arg1, char *arg2, char **output) { return grab_custom_macro_value_r(&global_macros, macro_name, arg1, arg2, output); } /* calculates a date/time macro */ int grab_datetime_macro_r(nagios_macros *mac, int macro_type, char *arg1, char *arg2, char **output) { time_t current_time = 0L; timeperiod *temp_timeperiod = NULL; time_t test_time = 0L; #ifdef NSCORE time_t next_valid_time = 0L; #endif if(output == NULL) return ERROR; /* get the current time */ time(¤t_time); /* parse args, do prep work */ switch(macro_type) { case MACRO_ISVALIDTIME: case MACRO_NEXTVALIDTIME: /* find the timeperiod */ if((temp_timeperiod = find_timeperiod(arg1)) == NULL) return ERROR; /* what timestamp should we use? */ if(arg2) test_time = (time_t)strtoul(arg2, NULL, 0); else test_time = current_time; break; default: break; } /* calculate the value */ switch(macro_type) { case MACRO_LONGDATETIME: if(*output == NULL) *output = (char *)malloc(MAX_DATETIME_LENGTH); if(*output) get_datetime_string(¤t_time, *output, MAX_DATETIME_LENGTH, LONG_DATE_TIME); break; case MACRO_SHORTDATETIME: if(*output == NULL) *output = (char *)malloc(MAX_DATETIME_LENGTH); if(*output) get_datetime_string(¤t_time, *output, MAX_DATETIME_LENGTH, SHORT_DATE_TIME); break; case MACRO_DATE: if(*output == NULL) *output = (char *)malloc(MAX_DATETIME_LENGTH); if(*output) get_datetime_string(¤t_time, *output, MAX_DATETIME_LENGTH, SHORT_DATE); break; case MACRO_TIME: if(*output == NULL) *output = (char *)malloc(MAX_DATETIME_LENGTH); if(*output) get_datetime_string(¤t_time, *output, MAX_DATETIME_LENGTH, SHORT_TIME); break; case MACRO_TIMET: asprintf(output, "%lu", (unsigned long)current_time); break; #ifdef NSCORE case MACRO_ISVALIDTIME: asprintf(output, "%d", (check_time_against_period(test_time, temp_timeperiod) == OK) ? 1 : 0); break; case MACRO_NEXTVALIDTIME: get_next_valid_time(test_time, &next_valid_time, temp_timeperiod); if(next_valid_time == test_time && check_time_against_period(test_time, temp_timeperiod) == ERROR) next_valid_time = (time_t)0L; asprintf(output, "%lu", (unsigned long)next_valid_time); break; #endif default: return ERROR; break; } return OK; } int grab_datetime_macro(int macro_type, char *arg1, char *arg2, char **output) { return grab_datetime_macro_r(&global_macros, macro_type, arg1, arg2, output); } /* calculates a host macro */ int grab_standard_host_macro_r(nagios_macros *mac, int macro_type, host *temp_host, char **output, int *free_macro) { char *temp_buffer = NULL; #ifdef NSCORE hostgroup *temp_hostgroup = NULL; servicesmember *temp_servicesmember = NULL; service *temp_service = NULL; objectlist *temp_objectlist = NULL; time_t current_time = 0L; unsigned long duration = 0L; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; char *buf1 = NULL; char *buf2 = NULL; int total_host_services = 0; int total_host_services_ok = 0; int total_host_services_warning = 0; int total_host_services_unknown = 0; int total_host_services_critical = 0; #endif if(temp_host == NULL || output == NULL || free_macro == NULL) return ERROR; /* BY DEFAULT TELL CALLER TO FREE MACRO BUFFER WHEN DONE */ *free_macro = TRUE; /* get the macro */ switch(macro_type) { case MACRO_HOSTNAME: *output = (char *)strdup(temp_host->name); break; case MACRO_HOSTDISPLAYNAME: if(temp_host->display_name) *output = (char *)strdup(temp_host->display_name); break; case MACRO_HOSTALIAS: *output = (char *)strdup(temp_host->alias); break; case MACRO_HOSTADDRESS: *output = (char *)strdup(temp_host->address); break; #ifdef NSCORE case MACRO_HOSTSTATE: if(temp_host->current_state == HOST_DOWN) *output = (char *)strdup("DOWN"); else if(temp_host->current_state == HOST_UNREACHABLE) *output = (char *)strdup("UNREACHABLE"); else *output = (char *)strdup("UP"); break; case MACRO_HOSTSTATEID: asprintf(output, "%d", temp_host->current_state); break; case MACRO_LASTHOSTSTATE: if(temp_host->last_state == HOST_DOWN) *output = (char *)strdup("DOWN"); else if(temp_host->last_state == HOST_UNREACHABLE) *output = (char *)strdup("UNREACHABLE"); else *output = (char *)strdup("UP"); break; case MACRO_LASTHOSTSTATEID: asprintf(output, "%d", temp_host->last_state); break; case MACRO_HOSTCHECKTYPE: asprintf(output, "%s", (temp_host->check_type == HOST_CHECK_PASSIVE) ? "PASSIVE" : "ACTIVE"); break; case MACRO_HOSTSTATETYPE: asprintf(output, "%s", (temp_host->state_type == HARD_STATE) ? "HARD" : "SOFT"); break; case MACRO_HOSTOUTPUT: if(temp_host->plugin_output) *output = (char *)strdup(temp_host->plugin_output); break; case MACRO_LONGHOSTOUTPUT: if(temp_host->long_plugin_output) *output = (char *)strdup(temp_host->long_plugin_output); break; case MACRO_HOSTPERFDATA: if(temp_host->perf_data) *output = (char *)strdup(temp_host->perf_data); break; #endif case MACRO_HOSTCHECKCOMMAND: if(temp_host->host_check_command) *output = (char *)strdup(temp_host->host_check_command); break; #ifdef NSCORE case MACRO_HOSTATTEMPT: asprintf(output, "%d", temp_host->current_attempt); break; case MACRO_MAXHOSTATTEMPTS: asprintf(output, "%d", temp_host->max_attempts); break; case MACRO_HOSTDOWNTIME: asprintf(output, "%d", temp_host->scheduled_downtime_depth); break; case MACRO_HOSTPERCENTCHANGE: asprintf(output, "%.2f", temp_host->percent_state_change); break; case MACRO_HOSTDURATIONSEC: case MACRO_HOSTDURATION: time(¤t_time); duration = (unsigned long)(current_time - temp_host->last_state_change); if(macro_type == MACRO_HOSTDURATIONSEC) asprintf(output, "%lu", duration); else { days = duration / 86400; duration -= (days * 86400); hours = duration / 3600; duration -= (hours * 3600); minutes = duration / 60; duration -= (minutes * 60); seconds = duration; asprintf(output, "%dd %dh %dm %ds", days, hours, minutes, seconds); } break; case MACRO_HOSTEXECUTIONTIME: asprintf(output, "%.3f", temp_host->execution_time); break; case MACRO_HOSTLATENCY: asprintf(output, "%.3f", temp_host->latency); break; case MACRO_LASTHOSTCHECK: asprintf(output, "%lu", (unsigned long)temp_host->last_check); break; case MACRO_LASTHOSTSTATECHANGE: asprintf(output, "%lu", (unsigned long)temp_host->last_state_change); break; case MACRO_LASTHOSTUP: asprintf(output, "%lu", (unsigned long)temp_host->last_time_up); break; case MACRO_LASTHOSTDOWN: asprintf(output, "%lu", (unsigned long)temp_host->last_time_down); break; case MACRO_LASTHOSTUNREACHABLE: asprintf(output, "%lu", (unsigned long)temp_host->last_time_unreachable); break; case MACRO_HOSTNOTIFICATIONNUMBER: asprintf(output, "%d", temp_host->current_notification_number); break; case MACRO_HOSTNOTIFICATIONID: asprintf(output, "%lu", temp_host->current_notification_id); break; case MACRO_HOSTEVENTID: asprintf(output, "%lu", temp_host->current_event_id); break; case MACRO_LASTHOSTEVENTID: asprintf(output, "%lu", temp_host->last_event_id); break; case MACRO_HOSTPROBLEMID: asprintf(output, "%lu", temp_host->current_problem_id); break; case MACRO_LASTHOSTPROBLEMID: asprintf(output, "%lu", temp_host->last_problem_id); break; #endif case MACRO_HOSTACTIONURL: if(temp_host->action_url) *output = (char *)strdup(temp_host->action_url); break; case MACRO_HOSTNOTESURL: if(temp_host->notes_url) *output = (char *)strdup(temp_host->notes_url); break; case MACRO_HOSTNOTES: if(temp_host->notes) *output = (char *)strdup(temp_host->notes); break; #ifdef NSCORE case MACRO_HOSTGROUPNAMES: /* find all hostgroups this host is associated with */ for(temp_objectlist = temp_host->hostgroups_ptr; temp_objectlist != NULL; temp_objectlist = temp_objectlist->next) { if((temp_hostgroup = (hostgroup *)temp_objectlist->object_ptr) == NULL) continue; asprintf(&buf1, "%s%s%s", (buf2) ? buf2 : "", (buf2) ? "," : "", temp_hostgroup->group_name); my_free(buf2); buf2 = buf1; } if(buf2) { *output = (char *)strdup(buf2); my_free(buf2); } break; case MACRO_TOTALHOSTSERVICES: case MACRO_TOTALHOSTSERVICESOK: case MACRO_TOTALHOSTSERVICESWARNING: case MACRO_TOTALHOSTSERVICESUNKNOWN: case MACRO_TOTALHOSTSERVICESCRITICAL: /* generate host service summary macros (if they haven't already been computed) */ if(mac->x[MACRO_TOTALHOSTSERVICES] == NULL) { for(temp_servicesmember = temp_host->services; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) { if((temp_service = temp_servicesmember->service_ptr) == NULL) continue; total_host_services++; switch(temp_service->current_state) { case STATE_OK: total_host_services_ok++; break; case STATE_WARNING: total_host_services_warning++; break; case STATE_UNKNOWN: total_host_services_unknown++; break; case STATE_CRITICAL: total_host_services_critical++; break; default: break; } } /* these macros are time-intensive to compute, and will likely be used together, so save them all for future use */ my_free(mac->x[MACRO_TOTALHOSTSERVICES]); asprintf(&mac->x[MACRO_TOTALHOSTSERVICES], "%d", total_host_services); my_free(mac->x[MACRO_TOTALHOSTSERVICESOK]); asprintf(&mac->x[MACRO_TOTALHOSTSERVICESOK], "%d", total_host_services_ok); my_free(mac->x[MACRO_TOTALHOSTSERVICESWARNING]); asprintf(&mac->x[MACRO_TOTALHOSTSERVICESWARNING], "%d", total_host_services_warning); my_free(mac->x[MACRO_TOTALHOSTSERVICESUNKNOWN]); asprintf(&mac->x[MACRO_TOTALHOSTSERVICESUNKNOWN], "%d", total_host_services_unknown); my_free(mac->x[MACRO_TOTALHOSTSERVICESCRITICAL]); asprintf(&mac->x[MACRO_TOTALHOSTSERVICESCRITICAL], "%d", total_host_services_critical); } /* return only the macro the user requested */ *output = mac->x[macro_type]; /* tell caller to NOT free memory when done */ *free_macro = FALSE; break; #endif /***************/ /* MISC MACROS */ /***************/ case MACRO_HOSTACKAUTHOR: case MACRO_HOSTACKAUTHORNAME: case MACRO_HOSTACKAUTHORALIAS: case MACRO_HOSTACKCOMMENT: /* no need to do any more work - these are already precomputed elsewhere */ /* NOTE: these macros won't work as on-demand macros */ *output = mac->x[macro_type]; *free_macro = FALSE; break; default: log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED HOST MACRO #%d! THIS IS A BUG!\n", macro_type); return ERROR; break; } /* post-processing */ /* notes, notes URL and action URL macros may themselves contain macros, so process them... */ switch(macro_type) { case MACRO_HOSTACTIONURL: case MACRO_HOSTNOTESURL: process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS); my_free(*output); *output = temp_buffer; break; case MACRO_HOSTNOTES: process_macros_r(mac, *output, &temp_buffer, 0); my_free(*output); *output = temp_buffer; break; default: break; } return OK; } int grab_standard_host_macro(int macro_type, host *temp_host, char **output, int *free_macro) { return grab_standard_host_macro_r(&global_macros, macro_type, temp_host, output, free_macro); } /* computes a hostgroup macro */ int grab_standard_hostgroup_macro_r(nagios_macros *mac, int macro_type, hostgroup *temp_hostgroup, char **output) { hostsmember *temp_hostsmember = NULL; char *temp_buffer = NULL; unsigned int temp_len = 0; unsigned int init_len = 0; if(temp_hostgroup == NULL || output == NULL) return ERROR; /* get the macro value */ switch(macro_type) { case MACRO_HOSTGROUPNAME: *output = (char *)strdup(temp_hostgroup->group_name); break; case MACRO_HOSTGROUPALIAS: if(temp_hostgroup->alias) *output = (char *)strdup(temp_hostgroup->alias); break; case MACRO_HOSTGROUPMEMBERS: /* make the calculations for total string length */ for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { if(temp_hostsmember->host_name == NULL) continue; if(temp_len == 0) { temp_len += strlen(temp_hostsmember->host_name) + 1; } else { temp_len += strlen(temp_hostsmember->host_name) + 2; } } /* allocate or reallocate the memory buffer */ if(*output == NULL) { *output = (char *)malloc(temp_len); } else { init_len = strlen(*output); temp_len += init_len; *output = (char *)realloc(*output, temp_len); } /* now fill in the string with the member names */ for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { if(temp_hostsmember->host_name == NULL) continue; temp_buffer = *output + init_len; if(init_len == 0) { /* If our buffer didn't contain anything, we just need to write "%s,%s" */ init_len += sprintf(temp_buffer, "%s", temp_hostsmember->host_name); } else { init_len += sprintf(temp_buffer, ",%s", temp_hostsmember->host_name); } } break; case MACRO_HOSTGROUPACTIONURL: if(temp_hostgroup->action_url) *output = (char *)strdup(temp_hostgroup->action_url); break; case MACRO_HOSTGROUPNOTESURL: if(temp_hostgroup->notes_url) *output = (char *)strdup(temp_hostgroup->notes_url); break; case MACRO_HOSTGROUPNOTES: if(temp_hostgroup->notes) *output = (char *)strdup(temp_hostgroup->notes); break; default: log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED HOSTGROUP MACRO #%d! THIS IS A BUG!\n", macro_type); return ERROR; break; } /* post-processing */ /* notes, notes URL and action URL macros may themselves contain macros, so process them... */ switch(macro_type) { case MACRO_HOSTGROUPACTIONURL: case MACRO_HOSTGROUPNOTESURL: process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS); my_free(*output); *output = temp_buffer; break; case MACRO_HOSTGROUPNOTES: process_macros_r(mac, *output, &temp_buffer, 0); my_free(*output); *output = temp_buffer; break; default: break; } return OK; } int grab_standard_hostgroup_macro(int macro_type, hostgroup *temp_hostgroup, char **output) { return grab_standard_hostgroup_macro_r(&global_macros, macro_type, temp_hostgroup, output); } /* computes a service macro */ int grab_standard_service_macro_r(nagios_macros *mac, int macro_type, service *temp_service, char **output, int *free_macro) { char *temp_buffer = NULL; #ifdef NSCORE servicegroup *temp_servicegroup = NULL; objectlist *temp_objectlist = NULL; time_t current_time = 0L; unsigned long duration = 0L; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; char *buf1 = NULL; char *buf2 = NULL; #endif if(temp_service == NULL || output == NULL) return ERROR; /* BY DEFAULT TELL CALLER TO FREE MACRO BUFFER WHEN DONE */ *free_macro = TRUE; /* get the macro value */ switch(macro_type) { case MACRO_SERVICEDESC: *output = (char *)strdup(temp_service->description); break; case MACRO_SERVICEDISPLAYNAME: if(temp_service->display_name) *output = (char *)strdup(temp_service->display_name); break; #ifdef NSCORE case MACRO_SERVICEOUTPUT: if(temp_service->plugin_output) *output = (char *)strdup(temp_service->plugin_output); break; case MACRO_LONGSERVICEOUTPUT: if(temp_service->long_plugin_output) *output = (char *)strdup(temp_service->long_plugin_output); break; case MACRO_SERVICEPERFDATA: if(temp_service->perf_data) *output = (char *)strdup(temp_service->perf_data); break; #endif case MACRO_SERVICECHECKCOMMAND: if(temp_service->service_check_command) *output = (char *)strdup(temp_service->service_check_command); break; #ifdef NSCORE case MACRO_SERVICECHECKTYPE: *output = (char *)strdup((temp_service->check_type == SERVICE_CHECK_PASSIVE) ? "PASSIVE" : "ACTIVE"); break; case MACRO_SERVICESTATETYPE: *output = (char *)strdup((temp_service->state_type == HARD_STATE) ? "HARD" : "SOFT"); break; case MACRO_SERVICESTATE: if(temp_service->current_state == STATE_OK) *output = (char *)strdup("OK"); else if(temp_service->current_state == STATE_WARNING) *output = (char *)strdup("WARNING"); else if(temp_service->current_state == STATE_CRITICAL) *output = (char *)strdup("CRITICAL"); else *output = (char *)strdup("UNKNOWN"); break; case MACRO_SERVICESTATEID: asprintf(output, "%d", temp_service->current_state); break; case MACRO_LASTSERVICESTATE: if(temp_service->last_state == STATE_OK) *output = (char *)strdup("OK"); else if(temp_service->last_state == STATE_WARNING) *output = (char *)strdup("WARNING"); else if(temp_service->last_state == STATE_CRITICAL) *output = (char *)strdup("CRITICAL"); else *output = (char *)strdup("UNKNOWN"); break; case MACRO_LASTSERVICESTATEID: asprintf(output, "%d", temp_service->last_state); break; #endif case MACRO_SERVICEISVOLATILE: asprintf(output, "%d", temp_service->is_volatile); break; #ifdef NSCORE case MACRO_SERVICEATTEMPT: asprintf(output, "%d", temp_service->current_attempt); break; case MACRO_MAXSERVICEATTEMPTS: asprintf(output, "%d", temp_service->max_attempts); break; case MACRO_SERVICEEXECUTIONTIME: asprintf(output, "%.3f", temp_service->execution_time); break; case MACRO_SERVICELATENCY: asprintf(output, "%.3f", temp_service->latency); break; case MACRO_LASTSERVICECHECK: asprintf(output, "%lu", (unsigned long)temp_service->last_check); break; case MACRO_LASTSERVICESTATECHANGE: asprintf(output, "%lu", (unsigned long)temp_service->last_state_change); break; case MACRO_LASTSERVICEOK: asprintf(output, "%lu", (unsigned long)temp_service->last_time_ok); break; case MACRO_LASTSERVICEWARNING: asprintf(output, "%lu", (unsigned long)temp_service->last_time_warning); break; case MACRO_LASTSERVICEUNKNOWN: asprintf(output, "%lu", (unsigned long)temp_service->last_time_unknown); break; case MACRO_LASTSERVICECRITICAL: asprintf(output, "%lu", (unsigned long)temp_service->last_time_critical); break; case MACRO_SERVICEDOWNTIME: asprintf(output, "%d", temp_service->scheduled_downtime_depth); break; case MACRO_SERVICEPERCENTCHANGE: asprintf(output, "%.2f", temp_service->percent_state_change); break; case MACRO_SERVICEDURATIONSEC: case MACRO_SERVICEDURATION: time(¤t_time); duration = (unsigned long)(current_time - temp_service->last_state_change); /* get the state duration in seconds */ if(macro_type == MACRO_SERVICEDURATIONSEC) asprintf(output, "%lu", duration); /* get the state duration */ else { days = duration / 86400; duration -= (days * 86400); hours = duration / 3600; duration -= (hours * 3600); minutes = duration / 60; duration -= (minutes * 60); seconds = duration; asprintf(output, "%dd %dh %dm %ds", days, hours, minutes, seconds); } break; case MACRO_SERVICENOTIFICATIONNUMBER: asprintf(output, "%d", temp_service->current_notification_number); break; case MACRO_SERVICENOTIFICATIONID: asprintf(output, "%lu", temp_service->current_notification_id); break; case MACRO_SERVICEEVENTID: asprintf(output, "%lu", temp_service->current_event_id); break; case MACRO_LASTSERVICEEVENTID: asprintf(output, "%lu", temp_service->last_event_id); break; case MACRO_SERVICEPROBLEMID: asprintf(output, "%lu", temp_service->current_problem_id); break; case MACRO_LASTSERVICEPROBLEMID: asprintf(output, "%lu", temp_service->last_problem_id); break; #endif case MACRO_SERVICEACTIONURL: if(temp_service->action_url) *output = (char *)strdup(temp_service->action_url); break; case MACRO_SERVICENOTESURL: if(temp_service->notes_url) *output = (char *)strdup(temp_service->notes_url); break; case MACRO_SERVICENOTES: if(temp_service->notes) *output = (char *)strdup(temp_service->notes); break; #ifdef NSCORE case MACRO_SERVICEGROUPNAMES: /* find all servicegroups this service is associated with */ for(temp_objectlist = temp_service->servicegroups_ptr; temp_objectlist != NULL; temp_objectlist = temp_objectlist->next) { if((temp_servicegroup = (servicegroup *)temp_objectlist->object_ptr) == NULL) continue; asprintf(&buf1, "%s%s%s", (buf2) ? buf2 : "", (buf2) ? "," : "", temp_servicegroup->group_name); my_free(buf2); buf2 = buf1; } if(buf2) { *output = (char *)strdup(buf2); my_free(buf2); } break; #endif /***************/ /* MISC MACROS */ /***************/ case MACRO_SERVICEACKAUTHOR: case MACRO_SERVICEACKAUTHORNAME: case MACRO_SERVICEACKAUTHORALIAS: case MACRO_SERVICEACKCOMMENT: /* no need to do any more work - these are already precomputed elsewhere */ /* NOTE: these macros won't work as on-demand macros */ *output = mac->x[macro_type]; *free_macro = FALSE; break; default: log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED SERVICE MACRO #%d! THIS IS A BUG!\n", macro_type); return ERROR; break; } /* post-processing */ /* notes, notes URL and action URL macros may themselves contain macros, so process them... */ switch(macro_type) { case MACRO_SERVICEACTIONURL: case MACRO_SERVICENOTESURL: process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS); my_free(*output); *output = temp_buffer; break; case MACRO_SERVICENOTES: process_macros_r(mac, *output, &temp_buffer, 0); my_free(*output); *output = temp_buffer; break; default: break; } return OK; } int grab_standard_service_macro(int macro_type, service *temp_service, char **output, int *free_macro) { return grab_standard_service_macro_r(&global_macros, macro_type, temp_service, output, free_macro); } /* computes a servicegroup macro */ int grab_standard_servicegroup_macro_r(nagios_macros *mac, int macro_type, servicegroup *temp_servicegroup, char **output) { servicesmember *temp_servicesmember = NULL; char *temp_buffer = NULL; unsigned int temp_len = 0; unsigned int init_len = 0; if(temp_servicegroup == NULL || output == NULL) return ERROR; /* get the macro value */ switch(macro_type) { case MACRO_SERVICEGROUPNAME: *output = (char *)strdup(temp_servicegroup->group_name); break; case MACRO_SERVICEGROUPALIAS: if(temp_servicegroup->alias) *output = (char *)strdup(temp_servicegroup->alias); break; case MACRO_SERVICEGROUPMEMBERS: /* make the calculations for total string length */ for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) { if(temp_servicesmember->host_name == NULL || temp_servicesmember->service_description == NULL) continue; if(temp_len == 0) { temp_len += strlen(temp_servicesmember->host_name) + strlen(temp_servicesmember->service_description) + 2; } else { temp_len += strlen(temp_servicesmember->host_name) + strlen(temp_servicesmember->service_description) + 3; } } /* allocate or reallocate the memory buffer */ if(*output == NULL) { *output = (char *)malloc(temp_len); } else { init_len = strlen(*output); temp_len += init_len; *output = (char *)realloc(*output, temp_len); } /* now fill in the string with the group members */ for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) { if(temp_servicesmember->host_name == NULL || temp_servicesmember->service_description == NULL) continue; temp_buffer = *output + init_len; if(init_len == 0) { /* If our buffer didn't contain anything, we just need to write "%s,%s" */ init_len += sprintf(temp_buffer, "%s,%s", temp_servicesmember->host_name, temp_servicesmember->service_description); } else { /* Now we need to write ",%s,%s" */ init_len += sprintf(temp_buffer, ",%s,%s", temp_servicesmember->host_name, temp_servicesmember->service_description); } } break; case MACRO_SERVICEGROUPACTIONURL: if(temp_servicegroup->action_url) *output = (char *)strdup(temp_servicegroup->action_url); break; case MACRO_SERVICEGROUPNOTESURL: if(temp_servicegroup->notes_url) *output = (char *)strdup(temp_servicegroup->notes_url); break; case MACRO_SERVICEGROUPNOTES: if(temp_servicegroup->notes) *output = (char *)strdup(temp_servicegroup->notes); break; default: log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED SERVICEGROUP MACRO #%d! THIS IS A BUG!\n", macro_type); return ERROR; } /* post-processing */ /* notes, notes URL and action URL macros may themselves contain macros, so process them... */ switch(macro_type) { case MACRO_SERVICEGROUPACTIONURL: case MACRO_SERVICEGROUPNOTESURL: process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS); my_free(*output); *output = temp_buffer; break; case MACRO_SERVICEGROUPNOTES: process_macros_r(mac, *output, &temp_buffer, 0); my_free(*output); *output = temp_buffer; break; default: break; } return OK; } int grab_standard_servicegroup_macro(int macro_type, servicegroup *temp_servicegroup, char **output) { return grab_standard_servicegroup_macro_r(&global_macros, macro_type, temp_servicegroup, output); } /* computes a contact macro */ int grab_standard_contact_macro_r(nagios_macros *mac, int macro_type, contact *temp_contact, char **output) { #ifdef NSCORE contactgroup *temp_contactgroup = NULL; objectlist *temp_objectlist = NULL; char *buf1 = NULL; char *buf2 = NULL; #endif if(temp_contact == NULL || output == NULL) return ERROR; /* get the macro value */ switch(macro_type) { case MACRO_CONTACTNAME: *output = (char *)strdup(temp_contact->name); break; case MACRO_CONTACTALIAS: *output = (char *)strdup(temp_contact->alias); break; case MACRO_CONTACTEMAIL: if(temp_contact->email) *output = (char *)strdup(temp_contact->email); break; case MACRO_CONTACTPAGER: if(temp_contact->pager) *output = (char *)strdup(temp_contact->pager); break; #ifdef NSCORE case MACRO_CONTACTGROUPNAMES: /* get the contactgroup names */ /* find all contactgroups this contact is a member of */ for(temp_objectlist = temp_contact->contactgroups_ptr; temp_objectlist != NULL; temp_objectlist = temp_objectlist->next) { if((temp_contactgroup = (contactgroup *)temp_objectlist->object_ptr) == NULL) continue; asprintf(&buf1, "%s%s%s", (buf2) ? buf2 : "", (buf2) ? "," : "", temp_contactgroup->group_name); my_free(buf2); buf2 = buf1; } if(buf2) { *output = (char *)strdup(buf2); my_free(buf2); } break; #endif default: log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED CONTACT MACRO #%d! THIS IS A BUG!\n", macro_type); return ERROR; } return OK; } int grab_standard_contact_macro(int macro_type, contact *temp_contact, char **output) { return grab_standard_contact_macro_r(&global_macros, macro_type, temp_contact, output); } /* computes a contact address macro */ int grab_contact_address_macro(int macro_num, contact *temp_contact, char **output) { if(macro_num < 0 || macro_num >= MAX_CONTACT_ADDRESSES) return ERROR; if(temp_contact == NULL || output == NULL) return ERROR; /* get the macro */ if(temp_contact->address[macro_num]) *output = temp_contact->address[macro_num]; return OK; } /* computes a contactgroup macro */ int grab_standard_contactgroup_macro(int macro_type, contactgroup *temp_contactgroup, char **output) { contactsmember *temp_contactsmember = NULL; if(temp_contactgroup == NULL || output == NULL) return ERROR; /* get the macro value */ switch(macro_type) { case MACRO_CONTACTGROUPNAME: *output = (char *)strdup(temp_contactgroup->group_name); break; case MACRO_CONTACTGROUPALIAS: if(temp_contactgroup->alias) *output = (char *)strdup(temp_contactgroup->alias); break; case MACRO_CONTACTGROUPMEMBERS: /* get the member list */ for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) { if(temp_contactsmember->contact_name == NULL) continue; if(*output == NULL) *output = (char *)strdup(temp_contactsmember->contact_name); else if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_contactsmember->contact_name) + 2))) { strcat(*output, ","); strcat(*output, temp_contactsmember->contact_name); } } break; default: log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED CONTACTGROUP MACRO #%d! THIS IS A BUG!\n", macro_type); return ERROR; } return OK; } /* computes a custom object macro */ int grab_custom_object_macro_r(nagios_macros *mac, char *macro_name, customvariablesmember *vars, char **output) { customvariablesmember *temp_customvariablesmember = NULL; int result = ERROR; if(macro_name == NULL || vars == NULL || output == NULL) return ERROR; /* get the custom variable */ for(temp_customvariablesmember = vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) { if(temp_customvariablesmember->variable_name == NULL) continue; if(!strcmp(macro_name, temp_customvariablesmember->variable_name)) { if(temp_customvariablesmember->variable_value) *output = (char *)strdup(temp_customvariablesmember->variable_value); result = OK; break; } } return result; } int grab_custom_object_macro(char *macro_name, customvariablesmember *vars, char **output) { return grab_custom_object_macro_r(&global_macros, macro_name, vars, output); } /******************************************************************/ /********************* MACRO STRING FUNCTIONS *********************/ /******************************************************************/ /* cleans illegal characters in macros before output */ char *clean_macro_chars(char *macro, int options) { register int x = 0; register int y = 0; register int z = 0; register int ch = 0; register int len = 0; register int illegal_char = 0; if(macro == NULL) return ""; len = (int)strlen(macro); /* strip illegal characters out of macro */ if(options & STRIP_ILLEGAL_MACRO_CHARS) { for(y = 0, x = 0; x < len; x++) { /*ch=(int)macro[x];*/ /* allow non-ASCII characters (Japanese, etc) */ ch = macro[x] & 0xff; /* illegal ASCII characters */ if(ch < 32 || ch == 127) continue; /* illegal user-specified characters */ illegal_char = FALSE; if(illegal_output_chars != NULL) { for(z = 0; illegal_output_chars[z] != '\x0'; z++) { if(ch == (int)illegal_output_chars[z]) { illegal_char = TRUE; break; } } } if(illegal_char == FALSE) macro[y++] = macro[x]; } macro[y++] = '\x0'; } #ifdef ON_HOLD_FOR_NOW /* escape nasty character in macro */ if(options & ESCAPE_MACRO_CHARS) { } #endif return macro; } /* encodes a string in proper URL format */ char *get_url_encoded_string(char *input) { register int x = 0; register int y = 0; char *encoded_url_string = NULL; char temp_expansion[6] = ""; /* bail if no input */ if(input == NULL) return NULL; /* allocate enough memory to escape all characters if necessary */ if((encoded_url_string = (char *)malloc((strlen(input) * 3) + 1)) == NULL) return NULL; /* check/encode all characters */ for(x = 0, y = 0; input[x] != (char)'\x0'; x++) { /* alpha-numeric characters and a few other characters don't get encoded */ if(((char)input[x] >= '0' && (char)input[x] <= '9') || ((char)input[x] >= 'A' && (char)input[x] <= 'Z') || ((char)input[x] >= (char)'a' && (char)input[x] <= (char)'z') || (char)input[x] == (char)'.' || (char)input[x] == (char)'-' || (char)input[x] == (char)'_' || (char)input[x] == (char)':' || (char)input[x] == (char)'/' || (char)input[x] == (char)'?' || (char)input[x] == (char)'=' || (char)input[x] == (char)'&') { encoded_url_string[y] = input[x]; y++; } /* spaces are pluses */ else if((char)input[x] <= (char)' ') { encoded_url_string[y] = '+'; y++; } /* anything else gets represented by its hex value */ else { encoded_url_string[y] = '\x0'; sprintf(temp_expansion, "%%%02X", (unsigned int)(input[x] & 0xFF)); strcat(encoded_url_string, temp_expansion); y += 3; } } /* terminate encoded string */ encoded_url_string[y] = '\x0'; return encoded_url_string; } static int macro_key_cmp(const void *a_, const void *b_) { struct macro_key_code *a = (struct macro_key_code *)a_; struct macro_key_code *b = (struct macro_key_code *)b_; return strcmp(a->name, b->name); } /******************************************************************/ /***************** MACRO INITIALIZATION FUNCTIONS *****************/ /******************************************************************/ /* initializes global macros */ int init_macros(void) { init_macrox_names(); int x; /* * non-volatile macros are free()'d when they're set. * We must do this in order to not lose the constant * ones when we get SIGHUP or a RESTART_PROGRAM event * from the command fifo. Otherwise a memset() would * have been better. */ clear_volatile_macros_r(&global_macros); /* backwards compatibility hack */ macro_x = global_macros.x; /* * Now build an ordered list of X macro names so we can * do binary lookups later and avoid a ton of strcmp()'s * for each and every check that gets run. A hash table * is actually slower, since the most frequently used * keys are so long and a binary lookup is completed in * 7 steps for up to ~200 keys, worst case. */ for(x = 0; x < MACRO_X_COUNT; x++) { macro_keys[x].code = x; macro_keys[x].name = macro_x_names[x]; macro_keys[x].clean_options = 0; /* host/service output/perfdata and author/comment macros should get cleaned */ if((x >= 16 && x <= 19) || (x >= 49 && x <= 52) || (x >= 99 && x <= 100) || (x >= 124 && x <= 127)) { macro_keys[x].clean_options = (STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS); } /* url macros should get cleaned */ if((x >= 125 && x <= 126) || (x >= 128 && x <= 129) || (x >= 77 && x <= 78) || (x >= 74 && x <= 75)) { macro_keys[x].clean_options = URL_ENCODE_MACRO_CHARS; } } qsort(macro_keys, x, sizeof(struct macro_key_code), macro_key_cmp); return OK; } /* * initializes the names of macros, using this nifty little macro * which ensures we never add any typos to the list */ #define add_macrox_name(name) macro_x_names[MACRO_##name] = strdup(#name) int init_macrox_names(void) { register int x = 0; /* initialize macro names */ for(x = 0; x < MACRO_X_COUNT; x++) macro_x_names[x] = NULL; /* initialize each macro name */ add_macrox_name(HOSTNAME); add_macrox_name(HOSTALIAS); add_macrox_name(HOSTADDRESS); add_macrox_name(SERVICEDESC); add_macrox_name(SERVICESTATE); add_macrox_name(SERVICESTATEID); add_macrox_name(SERVICEATTEMPT); add_macrox_name(SERVICEISVOLATILE); add_macrox_name(LONGDATETIME); add_macrox_name(SHORTDATETIME); add_macrox_name(DATE); add_macrox_name(TIME); add_macrox_name(TIMET); add_macrox_name(LASTHOSTCHECK); add_macrox_name(LASTSERVICECHECK); add_macrox_name(LASTHOSTSTATECHANGE); add_macrox_name(LASTSERVICESTATECHANGE); add_macrox_name(HOSTOUTPUT); add_macrox_name(SERVICEOUTPUT); add_macrox_name(HOSTPERFDATA); add_macrox_name(SERVICEPERFDATA); add_macrox_name(CONTACTNAME); add_macrox_name(CONTACTALIAS); add_macrox_name(CONTACTEMAIL); add_macrox_name(CONTACTPAGER); add_macrox_name(ADMINEMAIL); add_macrox_name(ADMINPAGER); add_macrox_name(HOSTSTATE); add_macrox_name(HOSTSTATEID); add_macrox_name(HOSTATTEMPT); add_macrox_name(NOTIFICATIONTYPE); add_macrox_name(NOTIFICATIONNUMBER); add_macrox_name(NOTIFICATIONISESCALATED); add_macrox_name(HOSTEXECUTIONTIME); add_macrox_name(SERVICEEXECUTIONTIME); add_macrox_name(HOSTLATENCY); add_macrox_name(SERVICELATENCY); add_macrox_name(HOSTDURATION); add_macrox_name(SERVICEDURATION); add_macrox_name(HOSTDURATIONSEC); add_macrox_name(SERVICEDURATIONSEC); add_macrox_name(HOSTDOWNTIME); add_macrox_name(SERVICEDOWNTIME); add_macrox_name(HOSTSTATETYPE); add_macrox_name(SERVICESTATETYPE); add_macrox_name(HOSTPERCENTCHANGE); add_macrox_name(SERVICEPERCENTCHANGE); add_macrox_name(HOSTGROUPNAME); add_macrox_name(HOSTGROUPALIAS); add_macrox_name(SERVICEGROUPNAME); add_macrox_name(SERVICEGROUPALIAS); add_macrox_name(HOSTACKAUTHOR); add_macrox_name(HOSTACKCOMMENT); add_macrox_name(SERVICEACKAUTHOR); add_macrox_name(SERVICEACKCOMMENT); add_macrox_name(LASTSERVICEOK); add_macrox_name(LASTSERVICEWARNING); add_macrox_name(LASTSERVICEUNKNOWN); add_macrox_name(LASTSERVICECRITICAL); add_macrox_name(LASTHOSTUP); add_macrox_name(LASTHOSTDOWN); add_macrox_name(LASTHOSTUNREACHABLE); add_macrox_name(SERVICECHECKCOMMAND); add_macrox_name(HOSTCHECKCOMMAND); add_macrox_name(MAINCONFIGFILE); add_macrox_name(STATUSDATAFILE); add_macrox_name(HOSTDISPLAYNAME); add_macrox_name(SERVICEDISPLAYNAME); add_macrox_name(RETENTIONDATAFILE); add_macrox_name(OBJECTCACHEFILE); add_macrox_name(TEMPFILE); add_macrox_name(LOGFILE); add_macrox_name(RESOURCEFILE); add_macrox_name(COMMANDFILE); add_macrox_name(HOSTPERFDATAFILE); add_macrox_name(SERVICEPERFDATAFILE); add_macrox_name(HOSTACTIONURL); add_macrox_name(HOSTNOTESURL); add_macrox_name(HOSTNOTES); add_macrox_name(SERVICEACTIONURL); add_macrox_name(SERVICENOTESURL); add_macrox_name(SERVICENOTES); add_macrox_name(TOTALHOSTSUP); add_macrox_name(TOTALHOSTSDOWN); add_macrox_name(TOTALHOSTSUNREACHABLE); add_macrox_name(TOTALHOSTSDOWNUNHANDLED); add_macrox_name(TOTALHOSTSUNREACHABLEUNHANDLED); add_macrox_name(TOTALHOSTPROBLEMS); add_macrox_name(TOTALHOSTPROBLEMSUNHANDLED); add_macrox_name(TOTALSERVICESOK); add_macrox_name(TOTALSERVICESWARNING); add_macrox_name(TOTALSERVICESCRITICAL); add_macrox_name(TOTALSERVICESUNKNOWN); add_macrox_name(TOTALSERVICESWARNINGUNHANDLED); add_macrox_name(TOTALSERVICESCRITICALUNHANDLED); add_macrox_name(TOTALSERVICESUNKNOWNUNHANDLED); add_macrox_name(TOTALSERVICEPROBLEMS); add_macrox_name(TOTALSERVICEPROBLEMSUNHANDLED); add_macrox_name(PROCESSSTARTTIME); add_macrox_name(HOSTCHECKTYPE); add_macrox_name(SERVICECHECKTYPE); add_macrox_name(LONGHOSTOUTPUT); add_macrox_name(LONGSERVICEOUTPUT); add_macrox_name(TEMPPATH); add_macrox_name(HOSTNOTIFICATIONNUMBER); add_macrox_name(SERVICENOTIFICATIONNUMBER); add_macrox_name(HOSTNOTIFICATIONID); add_macrox_name(SERVICENOTIFICATIONID); add_macrox_name(HOSTEVENTID); add_macrox_name(LASTHOSTEVENTID); add_macrox_name(SERVICEEVENTID); add_macrox_name(LASTSERVICEEVENTID); add_macrox_name(HOSTGROUPNAMES); add_macrox_name(SERVICEGROUPNAMES); add_macrox_name(HOSTACKAUTHORNAME); add_macrox_name(HOSTACKAUTHORALIAS); add_macrox_name(SERVICEACKAUTHORNAME); add_macrox_name(SERVICEACKAUTHORALIAS); add_macrox_name(MAXHOSTATTEMPTS); add_macrox_name(MAXSERVICEATTEMPTS); add_macrox_name(TOTALHOSTSERVICES); add_macrox_name(TOTALHOSTSERVICESOK); add_macrox_name(TOTALHOSTSERVICESWARNING); add_macrox_name(TOTALHOSTSERVICESUNKNOWN); add_macrox_name(TOTALHOSTSERVICESCRITICAL); add_macrox_name(HOSTGROUPNOTES); add_macrox_name(HOSTGROUPNOTESURL); add_macrox_name(HOSTGROUPACTIONURL); add_macrox_name(SERVICEGROUPNOTES); add_macrox_name(SERVICEGROUPNOTESURL); add_macrox_name(SERVICEGROUPACTIONURL); add_macrox_name(HOSTGROUPMEMBERS); add_macrox_name(SERVICEGROUPMEMBERS); add_macrox_name(CONTACTGROUPNAME); add_macrox_name(CONTACTGROUPALIAS); add_macrox_name(CONTACTGROUPMEMBERS); add_macrox_name(CONTACTGROUPNAMES); add_macrox_name(NOTIFICATIONRECIPIENTS); add_macrox_name(NOTIFICATIONAUTHOR); add_macrox_name(NOTIFICATIONAUTHORNAME); add_macrox_name(NOTIFICATIONAUTHORALIAS); add_macrox_name(NOTIFICATIONCOMMENT); add_macrox_name(EVENTSTARTTIME); add_macrox_name(HOSTPROBLEMID); add_macrox_name(LASTHOSTPROBLEMID); add_macrox_name(SERVICEPROBLEMID); add_macrox_name(LASTSERVICEPROBLEMID); add_macrox_name(ISVALIDTIME); add_macrox_name(NEXTVALIDTIME); add_macrox_name(LASTHOSTSTATE); add_macrox_name(LASTHOSTSTATEID); add_macrox_name(LASTSERVICESTATE); add_macrox_name(LASTSERVICESTATEID); return OK; } /******************************************************************/ /********************* MACRO CLEANUP FUNCTIONS ********************/ /******************************************************************/ /* free memory associated with the macrox names */ int free_macrox_names(void) { register int x = 0; /* free each macro name */ for(x = 0; x < MACRO_X_COUNT; x++) my_free(macro_x_names[x]); return OK; } /* clear argv macros - used in commands */ int clear_argv_macros_r(nagios_macros *mac) { register int x = 0; /* command argument macros */ for(x = 0; x < MAX_COMMAND_ARGUMENTS; x++) my_free(mac->argv[x]); return OK; } int clear_argv_macros(void) { return clear_argv_macros_r(&global_macros); } /* * copies non-volatile macros from global macro_x to **dest, which * must be large enough to hold at least MACRO_X_COUNT entries. * We use a shortlived macro to save up on typing */ #define cp_macro(name) dest[MACRO_##name] = global_macros.x[MACRO_##name] void copy_constant_macros(char **dest) { cp_macro(ADMINEMAIL); cp_macro(ADMINPAGER); cp_macro(MAINCONFIGFILE); cp_macro(STATUSDATAFILE); cp_macro(RETENTIONDATAFILE); cp_macro(OBJECTCACHEFILE); cp_macro(TEMPFILE); cp_macro(LOGFILE); cp_macro(RESOURCEFILE); cp_macro(COMMANDFILE); cp_macro(HOSTPERFDATAFILE); cp_macro(SERVICEPERFDATAFILE); cp_macro(PROCESSSTARTTIME); cp_macro(TEMPPATH); cp_macro(EVENTSTARTTIME); } #undef cp_macro /* clear all macros that are not "constant" (i.e. they change throughout the course of monitoring) */ int clear_volatile_macros_r(nagios_macros *mac) { customvariablesmember *this_customvariablesmember = NULL; customvariablesmember *next_customvariablesmember = NULL; register int x = 0; for(x = 0; x < MACRO_X_COUNT; x++) { switch(x) { case MACRO_ADMINEMAIL: case MACRO_ADMINPAGER: case MACRO_MAINCONFIGFILE: case MACRO_STATUSDATAFILE: case MACRO_RETENTIONDATAFILE: case MACRO_OBJECTCACHEFILE: case MACRO_TEMPFILE: case MACRO_LOGFILE: case MACRO_RESOURCEFILE: case MACRO_COMMANDFILE: case MACRO_HOSTPERFDATAFILE: case MACRO_SERVICEPERFDATAFILE: case MACRO_PROCESSSTARTTIME: case MACRO_TEMPPATH: case MACRO_EVENTSTARTTIME: /* these don't change during the course of monitoring, so no need to free them */ break; default: my_free(mac->x[x]); break; } } /* contact address macros */ for(x = 0; x < MAX_CONTACT_ADDRESSES; x++) my_free(mac->contactaddress[x]); /* clear macro pointers */ mac->host_ptr = NULL; mac->hostgroup_ptr = NULL; mac->service_ptr = NULL; mac->servicegroup_ptr = NULL; mac->contact_ptr = NULL; mac->contactgroup_ptr = NULL; /* clear on-demand macro */ my_free(mac->ondemand); /* clear ARGx macros */ clear_argv_macros_r(mac); /* clear custom host variables */ for(this_customvariablesmember = mac->custom_host_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) { next_customvariablesmember = this_customvariablesmember->next; my_free(this_customvariablesmember->variable_name); my_free(this_customvariablesmember->variable_value); my_free(this_customvariablesmember); } mac->custom_host_vars = NULL; /* clear custom service variables */ for(this_customvariablesmember = mac->custom_service_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) { next_customvariablesmember = this_customvariablesmember->next; my_free(this_customvariablesmember->variable_name); my_free(this_customvariablesmember->variable_value); my_free(this_customvariablesmember); } mac->custom_service_vars = NULL; /* clear custom contact variables */ for(this_customvariablesmember = mac->custom_contact_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) { next_customvariablesmember = this_customvariablesmember->next; my_free(this_customvariablesmember->variable_name); my_free(this_customvariablesmember->variable_value); my_free(this_customvariablesmember); } mac->custom_contact_vars = NULL; return OK; } int clear_volatile_macros(void) { return clear_volatile_macros_r(&global_macros); } /* clear service macros */ int clear_service_macros_r(nagios_macros *mac) { customvariablesmember *this_customvariablesmember = NULL; customvariablesmember *next_customvariablesmember = NULL; /* FIXME: strings. make these not be strdup()'s anymore */ my_free(mac->x[MACRO_SERVICEDESC]); my_free(mac->x[MACRO_SERVICEDISPLAYNAME]); my_free(mac->x[MACRO_SERVICEOUTPUT]); my_free(mac->x[MACRO_LONGSERVICEOUTPUT]); my_free(mac->x[MACRO_SERVICEPERFDATA]); /* these are recursive but persistent. what to do? */ my_free(mac->x[MACRO_SERVICECHECKCOMMAND]); my_free(mac->x[MACRO_SERVICEACTIONURL]); my_free(mac->x[MACRO_SERVICENOTESURL]); my_free(mac->x[MACRO_SERVICENOTES]); my_free(mac->x[MACRO_SERVICECHECKTYPE]); my_free(mac->x[MACRO_SERVICESTATETYPE]); my_free(mac->x[MACRO_SERVICESTATE]); my_free(mac->x[MACRO_SERVICEISVOLATILE]); my_free(mac->x[MACRO_SERVICESTATEID]); my_free(mac->x[MACRO_SERVICEATTEMPT]); my_free(mac->x[MACRO_MAXSERVICEATTEMPTS]); my_free(mac->x[MACRO_SERVICEEXECUTIONTIME]); my_free(mac->x[MACRO_SERVICELATENCY]); my_free(mac->x[MACRO_LASTSERVICECHECK]); my_free(mac->x[MACRO_LASTSERVICESTATECHANGE]); my_free(mac->x[MACRO_LASTSERVICEOK]); my_free(mac->x[MACRO_LASTSERVICEWARNING]); my_free(mac->x[MACRO_LASTSERVICEUNKNOWN]); my_free(mac->x[MACRO_LASTSERVICECRITICAL]); my_free(mac->x[MACRO_SERVICEDOWNTIME]); my_free(mac->x[MACRO_SERVICEPERCENTCHANGE]); my_free(mac->x[MACRO_SERVICEDURATIONSEC]); my_free(mac->x[MACRO_SERVICEDURATION]); my_free(mac->x[MACRO_SERVICENOTIFICATIONNUMBER]); my_free(mac->x[MACRO_SERVICENOTIFICATIONID]); my_free(mac->x[MACRO_SERVICEEVENTID]); my_free(mac->x[MACRO_LASTSERVICEEVENTID]); my_free(mac->x[MACRO_SERVICEGROUPNAMES]); my_free(mac->x[MACRO_SERVICEPROBLEMID]); my_free(mac->x[MACRO_LASTSERVICEPROBLEMID]); /* clear custom service variables */ for(this_customvariablesmember = mac->custom_service_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) { next_customvariablesmember = this_customvariablesmember->next; my_free(this_customvariablesmember->variable_name); my_free(this_customvariablesmember->variable_value); my_free(this_customvariablesmember); } mac->custom_service_vars = NULL; /* clear pointers */ mac->service_ptr = NULL; return OK; } int clear_service_macros(void) { return clear_service_macros_r(&global_macros); } /* clear host macros */ int clear_host_macros_r(nagios_macros *mac) { customvariablesmember *this_customvariablesmember = NULL; customvariablesmember *next_customvariablesmember = NULL; /* FIXME: strings; Fix these to not be strdup()'s anymore */ my_free(mac->x[MACRO_HOSTNAME]); my_free(mac->x[MACRO_HOSTDISPLAYNAME]); my_free(mac->x[MACRO_HOSTALIAS]); my_free(mac->x[MACRO_HOSTADDRESS]); my_free(mac->x[MACRO_HOSTOUTPUT]); my_free(mac->x[MACRO_LONGHOSTOUTPUT]); my_free(mac->x[MACRO_HOSTPERFDATA]); /* these are recursive but persistent. what to do? */ my_free(mac->x[MACRO_HOSTCHECKCOMMAND]); my_free(mac->x[MACRO_HOSTACTIONURL]); my_free(mac->x[MACRO_HOSTNOTESURL]); my_free(mac->x[MACRO_HOSTNOTES]); /* numbers or by necessity autogenerated strings */ my_free(mac->x[MACRO_HOSTSTATE]); my_free(mac->x[MACRO_HOSTSTATEID]); my_free(mac->x[MACRO_HOSTCHECKTYPE]); my_free(mac->x[MACRO_HOSTSTATETYPE]); my_free(mac->x[MACRO_HOSTATTEMPT]); my_free(mac->x[MACRO_MAXHOSTATTEMPTS]); my_free(mac->x[MACRO_HOSTDOWNTIME]); my_free(mac->x[MACRO_HOSTPERCENTCHANGE]); my_free(mac->x[MACRO_HOSTDURATIONSEC]); my_free(mac->x[MACRO_HOSTDURATION]); my_free(mac->x[MACRO_HOSTEXECUTIONTIME]); my_free(mac->x[MACRO_HOSTLATENCY]); my_free(mac->x[MACRO_LASTHOSTCHECK]); my_free(mac->x[MACRO_LASTHOSTSTATECHANGE]); my_free(mac->x[MACRO_LASTHOSTUP]); my_free(mac->x[MACRO_LASTHOSTDOWN]); my_free(mac->x[MACRO_LASTHOSTUNREACHABLE]); my_free(mac->x[MACRO_HOSTNOTIFICATIONNUMBER]); my_free(mac->x[MACRO_HOSTNOTIFICATIONID]); my_free(mac->x[MACRO_HOSTEVENTID]); my_free(mac->x[MACRO_LASTHOSTEVENTID]); my_free(mac->x[MACRO_HOSTGROUPNAMES]); my_free(mac->x[MACRO_TOTALHOSTSERVICES]); my_free(mac->x[MACRO_TOTALHOSTSERVICESOK]); my_free(mac->x[MACRO_TOTALHOSTSERVICESWARNING]); my_free(mac->x[MACRO_TOTALHOSTSERVICESUNKNOWN]); my_free(mac->x[MACRO_TOTALHOSTSERVICESCRITICAL]); my_free(mac->x[MACRO_HOSTPROBLEMID]); my_free(mac->x[MACRO_LASTHOSTPROBLEMID]); /* clear custom host variables */ for(this_customvariablesmember = mac->custom_host_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) { next_customvariablesmember = this_customvariablesmember->next; my_free(this_customvariablesmember->variable_name); my_free(this_customvariablesmember->variable_value); my_free(this_customvariablesmember); } mac->custom_host_vars = NULL; /* clear pointers */ mac->host_ptr = NULL; return OK; } int clear_host_macros(void) { return clear_host_macros_r(&global_macros); } /* clear hostgroup macros */ int clear_hostgroup_macros_r(nagios_macros *mac) { /* FIXME: make these not strdup()'s */ my_free(mac->x[MACRO_HOSTGROUPNAME]); my_free(mac->x[MACRO_HOSTGROUPALIAS]); /* generated but persistent. what to do? */ my_free(mac->x[MACRO_HOSTGROUPACTIONURL]); my_free(mac->x[MACRO_HOSTGROUPNOTESURL]); my_free(mac->x[MACRO_HOSTGROUPNOTES]); /* generated */ my_free(mac->x[MACRO_HOSTGROUPMEMBERS]); /* clear pointers */ mac->hostgroup_ptr = NULL; return OK; } int clear_hostgroup_macros(void) { return clear_hostgroup_macros_r(&global_macros); } /* clear servicegroup macros */ int clear_servicegroup_macros_r(nagios_macros *mac) { /* FIXME: these should not be strdup()'s */ my_free(mac->x[MACRO_SERVICEGROUPNAME]); my_free(mac->x[MACRO_SERVICEGROUPALIAS]); /* generated but persistent. what to do? */ my_free(mac->x[MACRO_SERVICEGROUPACTIONURL]); my_free(mac->x[MACRO_SERVICEGROUPNOTESURL]); my_free(mac->x[MACRO_SERVICEGROUPNOTES]); /* generated */ my_free(mac->x[MACRO_SERVICEGROUPMEMBERS]); /* clear pointers */ mac->servicegroup_ptr = NULL; return OK; } int clear_servicegroup_macros(void) { return clear_servicegroup_macros_r(&global_macros); } /* clear contact macros */ int clear_contact_macros_r(nagios_macros *mac) { register int x; customvariablesmember *this_customvariablesmember = NULL; customvariablesmember *next_customvariablesmember = NULL; /* FIXME: these should not be strdup()'d */ my_free(mac->x[MACRO_CONTACTNAME]); my_free(mac->x[MACRO_CONTACTALIAS]); my_free(mac->x[MACRO_CONTACTEMAIL]); my_free(mac->x[MACRO_CONTACTPAGER]); /* generated per contact */ my_free(mac->x[MACRO_CONTACTGROUPNAMES]); /* clear contact addresses */ for(x = 0; x < MAX_CONTACT_ADDRESSES; x++) my_free(mac->contactaddress[x]); /* clear custom contact variables */ for(this_customvariablesmember = mac->custom_contact_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) { next_customvariablesmember = this_customvariablesmember->next; my_free(this_customvariablesmember->variable_name); my_free(this_customvariablesmember->variable_value); my_free(this_customvariablesmember); } mac->custom_contact_vars = NULL; /* clear pointers */ mac->contact_ptr = NULL; return OK; } int clear_contact_macros(void) { return clear_contact_macros_r(&global_macros); } /* clear contactgroup macros */ int clear_contactgroup_macros_r(nagios_macros *mac) { my_free(mac->x[MACRO_CONTACTGROUPNAME]); my_free(mac->x[MACRO_CONTACTGROUPALIAS]); my_free(mac->x[MACRO_CONTACTGROUPMEMBERS]); /* clear pointers */ mac->contactgroup_ptr = NULL; return OK; } int clear_contactgroup_macros(void) { return clear_contactgroup_macros_r(&global_macros); } /* clear summary macros */ int clear_summary_macros_r(nagios_macros *mac) { register int x; for(x = MACRO_TOTALHOSTSUP; x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED; x++) my_free(mac->x[x]); return OK; } int clear_summary_macros(void) { return clear_summary_macros_r(&global_macros); } /******************************************************************/ /****************** ENVIRONMENT MACRO FUNCTIONS *******************/ /******************************************************************/ #ifdef NSCORE /* sets or unsets all macro environment variables */ int set_all_macro_environment_vars_r(nagios_macros *mac, int set) { if(enable_environment_macros == FALSE) return ERROR; set_macrox_environment_vars_r(mac, set); set_argv_macro_environment_vars_r(mac, set); set_custom_macro_environment_vars_r(mac, set); set_contact_address_environment_vars_r(mac, set); return OK; } int set_all_macro_environment_vars(int set) { return set_all_macro_environment_vars_r(&global_macros, set); } /* sets or unsets macrox environment variables */ int set_macrox_environment_vars_r(nagios_macros *mac, int set) { register int x = 0; int free_macro = FALSE; int generate_macro = TRUE; /* set each of the macrox environment variables */ for(x = 0; x < MACRO_X_COUNT; x++) { free_macro = FALSE; /* generate the macro value if it hasn't already been done */ /* THIS IS EXPENSIVE */ if(set == TRUE) { generate_macro = TRUE; /* skip summary macro generation if lage installation tweaks are enabled */ if((x >= MACRO_TOTALHOSTSUP && x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED) && use_large_installation_tweaks == TRUE) generate_macro = FALSE; if(mac->x[x] == NULL && generate_macro == TRUE) grab_macrox_value_r(mac, x, NULL, NULL, &mac->x[x], &free_macro); } /* set the value */ set_macro_environment_var(macro_x_names[x], mac->x[x], set); } return OK; } int set_macrox_environment_vars(int set) { return set_macrox_environment_vars_r(&global_macros, set); } /* sets or unsets argv macro environment variables */ int set_argv_macro_environment_vars_r(nagios_macros *mac, int set) { char *macro_name = NULL; register int x = 0; /* set each of the argv macro environment variables */ for(x = 0; x < MAX_COMMAND_ARGUMENTS; x++) { asprintf(¯o_name, "ARG%d", x + 1); set_macro_environment_var(macro_name, mac->argv[x], set); my_free(macro_name); } return OK; } int set_argv_macro_environment_vars(int set) { return set_argv_macro_environment_vars_r(&global_macros, set); } /* sets or unsets custom host/service/contact macro environment variables */ int set_custom_macro_environment_vars_r(nagios_macros *mac, int set) { customvariablesmember *temp_customvariablesmember = NULL; host *temp_host = NULL; service *temp_service = NULL; contact *temp_contact = NULL; char *customvarname = NULL; /***** CUSTOM HOST VARIABLES *****/ /* generate variables and save them for later */ if((temp_host = mac->host_ptr) && set == TRUE) { for(temp_customvariablesmember = temp_host->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) { asprintf(&customvarname, "_HOST%s", temp_customvariablesmember->variable_name); add_custom_variable_to_object(&mac->custom_host_vars, customvarname, temp_customvariablesmember->variable_value); my_free(customvarname); } } /* set variables */ for(temp_customvariablesmember = mac->custom_host_vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) { set_macro_environment_var(temp_customvariablesmember->variable_name, clean_macro_chars(temp_customvariablesmember->variable_value, STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS), set); } /***** CUSTOM SERVICE VARIABLES *****/ /* generate variables and save them for later */ if((temp_service = mac->service_ptr) && set == TRUE) { for(temp_customvariablesmember = temp_service->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) { asprintf(&customvarname, "_SERVICE%s", temp_customvariablesmember->variable_name); add_custom_variable_to_object(&mac->custom_service_vars, customvarname, temp_customvariablesmember->variable_value); my_free(customvarname); } } /* set variables */ for(temp_customvariablesmember = mac->custom_service_vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) set_macro_environment_var(temp_customvariablesmember->variable_name, clean_macro_chars(temp_customvariablesmember->variable_value, STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS), set); /***** CUSTOM CONTACT VARIABLES *****/ /* generate variables and save them for later */ if((temp_contact = mac->contact_ptr) && set == TRUE) { for(temp_customvariablesmember = temp_contact->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) { asprintf(&customvarname, "_CONTACT%s", temp_customvariablesmember->variable_name); add_custom_variable_to_object(&mac->custom_contact_vars, customvarname, temp_customvariablesmember->variable_value); my_free(customvarname); } } /* set variables */ for(temp_customvariablesmember = mac->custom_contact_vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) set_macro_environment_var(temp_customvariablesmember->variable_name, clean_macro_chars(temp_customvariablesmember->variable_value, STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS), set); return OK; } int set_custom_macro_environment_vars(int set) { return set_custom_macro_environment_vars_r(&global_macros, set); } /* sets or unsets contact address environment variables */ int set_contact_address_environment_vars_r(nagios_macros *mac, int set) { char *varname = NULL; register int x; /* these only get set during notifications */ if(mac->contact_ptr == NULL) return OK; for(x = 0; x < MAX_CONTACT_ADDRESSES; x++) { asprintf(&varname, "CONTACTADDRESS%d", x); set_macro_environment_var(varname, mac->contact_ptr->address[x], set); my_free(varname); } return OK; } int set_contact_address_environment_vars(int set) { return set_contact_address_environment_vars_r(&global_macros, set); } /* sets or unsets a macro environment variable */ int set_macro_environment_var(char *name, char *value, int set) { char *env_macro_name = NULL; /* we won't mess with null variable names */ if(name == NULL) return ERROR; /* create environment var name */ asprintf(&env_macro_name, "%s%s", MACRO_ENV_VAR_PREFIX, name); /* set or unset the environment variable */ set_environment_var(env_macro_name, value, set); /* free allocated memory */ my_free(env_macro_name); return OK; } #endif