nagios4/common/macros.c
2017-05-19 23:37:19 +02:00

3479 lines
104 KiB
C

/*****************************************************************************
*
* MACROS.C - Common macro functions for Nagios
*
*
* 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/config.h"
#include "../include/macros.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
static 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 */
char *value; /* macro value */
int code; /* numeric macro code, usable in case statements */
int options; /* Options for how the macro can be escaped */
};
static 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
*/
static 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
*/
static 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 = &macro_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;
char *selected_macro = NULL;
char *original_macro = NULL;
int result = OK;
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;
/* 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 {
/* grab the macro value */
free_macro = FALSE;
result = grab_macro_value_r(mac, temp_buffer, &selected_macro, &macro_options, &free_macro);
log_debug_info(DEBUGL_MACROS, 2, " Processed '%s', Free: %d\n", temp_buffer, 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);
}
if (result == OK)
; /* do nothing special if things worked out ok */
/* 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', Free: %d, Cleaning options: %d\n", temp_buffer, free_macro, options);
/* URL encode the macro if requested - this allocates new memory */
if(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 should sometimes be cleaned */
if(macro_options & options & (STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS)) {
char *cleaned_macro = NULL;
/* add the (cleaned) processed macro to the end of the already processed buffer */
if(selected_macro != NULL && (cleaned_macro = clean_macro_chars(selected_macro, options)) != NULL) {
*output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(cleaned_macro) + 1);
strcat(*output_buffer, cleaned_macro);
if(*cleaned_macro)
my_free(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;
/* save pointer to host's first/primary hostgroup */
if(hst->hostgroups_ptr)
mac->hostgroup_ptr = (hostgroup *)hst->hostgroups_ptr->object_ptr;
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;
/* save first/primary servicegroup pointer for later */
if(svc->servicegroups_ptr)
mac->servicegroup_ptr = (servicegroup *)svc->servicegroups_ptr->object_ptr;
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;
/* save pointer to first/primary contactgroup for later */
if(cntct->contactgroups_ptr)
mac->contactgroup_ptr = (contactgroup *)cntct->contactgroups_ptr->object_ptr;
return OK;
}
int grab_contact_macros(contact *cntct) {
return grab_contact_macros_r(&global_macros, cntct);
}
int grab_argv_macros_r(nagios_macros *mac, char *check_command) {
char *cmd_ptr = check_command;
char temp_arg[MAX_COMMAND_BUFFER] = "";
char *arg_buffer = NULL;
int macro_options = STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS;
register int x = 0;
register int y = 0;
register int arg_index = 0;
/* clear the argv macros */
clear_argv_macros_r(mac);
/* make sure we've got all the requirements */
if(cmd_ptr == NULL || cmd_ptr[0] == '\0')
return ERROR;
/* skip the command name (we're about to get the arguments)... */
for(arg_index = 0;; arg_index++) {
if(cmd_ptr[arg_index] == '!' || cmd_ptr[arg_index] == '\x0')
break;
}
/* get each command argument */
for(x = 0; x < MAX_COMMAND_ARGUMENTS; x++) {
/* we reached the end of the arguments... */
if(cmd_ptr[arg_index] == '\x0')
break;
/* get the next argument */
/* can't use strtok(), as that's used in process_macros... */
for(arg_index++, y = 0; y < (int)sizeof(temp_arg) - 1; arg_index++) {
/* handle escaped argument delimiters */
if(cmd_ptr[arg_index] == '\\' && cmd_ptr[arg_index+1] == '!') {
arg_index++;
} else if(cmd_ptr[arg_index] == '!' || cmd_ptr[arg_index] == '\x0') {
/* end of argument */
break;
}
/* copy the character */
temp_arg[y] = cmd_ptr[arg_index];
y++;
}
temp_arg[y] = '\x0';
process_macros_r(mac, temp_arg, &arg_buffer, macro_options);
mac->argv[x] = arg_buffer;
}
return OK;
}
/******************************************************************/
/******************* 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 || free_macro == NULL)
return ERROR;
if(clean_options)
*clean_options = 0;
/*
* 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;
/* 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]);
/* get the macro value */
result = grab_macrox_value_r(mac, mkey->code, arg[0], arg[1], output, free_macro);
/* Return the macro attributes */
if(clean_options) {
*clean_options = mkey->options;
}
}
/***** 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) {
if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
continue;
/* 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;
*free_macro = FALSE;
/* handle the macro */
switch(macro_type) {
/***************/
/* HOST MACROS */
/***************/
case MACRO_HOSTGROUPNAMES:
*free_macro = TRUE;
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_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:
case MACRO_HOSTIMPORTANCE:
case MACRO_HOSTANDSERVICESIMPORTANCE:
/* a standard host macro */
if(arg2 == NULL) {
/* find the host for on-demand macros */
if(arg1) {
if((temp_host = find_host(arg1)) == NULL) {
if (macro_type == MACRO_HOSTSTATEID) {
*output = strdup("2");
return OK;
}
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) {
if((temp_host = temp_hostsmember->host_ptr) == NULL)
continue;
/* 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_HOSTGROUPMEMBERS:
case MACRO_HOSTGROUPMEMBERADDRESSES:
*free_macro = TRUE;
case MACRO_HOSTGROUPNAME:
case MACRO_HOSTGROUPALIAS:
case MACRO_HOSTGROUPNOTES:
case MACRO_HOSTGROUPNOTESURL:
case MACRO_HOSTGROUPACTIONURL:
/* 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_SERVICEGROUPNAMES:
*free_macro = TRUE;
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_SERVICEACKAUTHORNAME:
case MACRO_SERVICEACKAUTHORALIAS:
case MACRO_MAXSERVICEATTEMPTS:
case MACRO_SERVICEISVOLATILE:
case MACRO_SERVICEPROBLEMID:
case MACRO_LASTSERVICEPROBLEMID:
case MACRO_LASTSERVICESTATE:
case MACRO_LASTSERVICESTATEID:
case MACRO_SERVICEIMPORTANCE:
/* 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) {
if (macro_type == MACRO_SERVICESTATEID) {
*output = strdup("3");
return OK;
}
return ERROR;
}
delimiter_len = strlen(arg2);
*free_macro = TRUE;
/* concatenate macro values for all servicegroup members */
for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) {
if((temp_service = temp_servicesmember->service_ptr) == NULL)
continue;
/* 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_SERVICEGROUPMEMBERS:
case MACRO_SERVICEGROUPNOTES:
case MACRO_SERVICEGROUPNOTESURL:
case MACRO_SERVICEGROUPACTIONURL:
*free_macro = TRUE;
case MACRO_SERVICEGROUPNAME:
case MACRO_SERVICEGROUPALIAS:
/* 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_CONTACTGROUPNAMES:
*free_macro = TRUE;
case MACRO_CONTACTNAME:
case MACRO_CONTACTALIAS:
case MACRO_CONTACTEMAIL:
case MACRO_CONTACTPAGER:
/* 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);
*free_macro = TRUE;
/* concatenate macro values for all contactgroup members */
for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
continue;
/* 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_CONTACTGROUPMEMBERS:
*free_macro = TRUE;
case MACRO_CONTACTGROUPNAME:
case MACRO_CONTACTGROUPALIAS:
/* 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:
*free_macro = TRUE;
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) {
if((temp_host = temp_hostsmember->host_ptr) == NULL)
continue;
/* 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) {
if((temp_service = temp_servicesmember->service_ptr) == NULL)
continue;
/* 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) {
if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
continue;
/* 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;
#ifdef NSCORE
time_t test_time = 0L;
time_t next_valid_time = 0L;
#endif
if(output == NULL)
return ERROR;
/* get the current time */
time(&current_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? */
#ifdef NSCORE
if(arg2)
test_time = (time_t)strtoul(arg2, NULL, 0);
else
test_time = current_time;
#endif
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(&current_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(&current_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(&current_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(&current_time, *output, MAX_DATETIME_LENGTH, SHORT_TIME);
break;
case MACRO_TIMET:
*output = (char *)mkstr("%lu", (unsigned long)current_time);
break;
#ifdef NSCORE
case MACRO_ISVALIDTIME:
*output = (char *)mkstr("%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;
*output = (char *)mkstr("%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;
/* get the macro */
switch(macro_type) {
case MACRO_HOSTNAME:
*output = temp_host->name;
break;
case MACRO_HOSTDISPLAYNAME:
if(temp_host->display_name)
*output = temp_host->display_name;
break;
case MACRO_HOSTALIAS:
*output = temp_host->alias;
break;
case MACRO_HOSTADDRESS:
*output = temp_host->address;
break;
#ifdef NSCORE
case MACRO_HOSTSTATE:
*output = (char *)host_state_name(temp_host->current_state);
break;
case MACRO_HOSTSTATEID:
*output = (char *)mkstr("%d", temp_host->current_state);
break;
case MACRO_LASTHOSTSTATE:
*output = (char *)host_state_name(temp_host->last_state);
break;
case MACRO_LASTHOSTSTATEID:
*output = (char *)mkstr("%d", temp_host->last_state);
break;
case MACRO_HOSTCHECKTYPE:
*output = (char *)check_type_name(temp_host->check_type);
break;
case MACRO_HOSTSTATETYPE:
*output = (char *)state_type_name(temp_host->state_type);
break;
case MACRO_HOSTOUTPUT:
if(temp_host->plugin_output)
*output = temp_host->plugin_output;
break;
case MACRO_LONGHOSTOUTPUT:
if(temp_host->long_plugin_output)
*output = temp_host->long_plugin_output;
break;
case MACRO_HOSTPERFDATA:
if(temp_host->perf_data)
*output = temp_host->perf_data;
break;
#endif
case MACRO_HOSTCHECKCOMMAND:
if(temp_host->check_command)
*output = temp_host->check_command;
break;
#ifdef NSCORE
case MACRO_HOSTATTEMPT:
*output = (char *)mkstr("%d", temp_host->current_attempt);
break;
case MACRO_MAXHOSTATTEMPTS:
*output = (char *)mkstr("%d", temp_host->max_attempts);
break;
case MACRO_HOSTDOWNTIME:
*output = (char *)mkstr("%d", temp_host->scheduled_downtime_depth);
break;
case MACRO_HOSTPERCENTCHANGE:
*output = (char *)mkstr("%.2f", temp_host->percent_state_change);
break;
case MACRO_HOSTDURATIONSEC:
case MACRO_HOSTDURATION:
time(&current_time);
duration = (unsigned long)(current_time - temp_host->last_state_change);
if(macro_type == MACRO_HOSTDURATIONSEC)
*output = (char *)mkstr("%lu", duration);
else {
days = duration / 86400;
duration -= (days * 86400);
hours = duration / 3600;
duration -= (hours * 3600);
minutes = duration / 60;
duration -= (minutes * 60);
seconds = duration;
*output = (char *)mkstr("%dd %dh %dm %ds", days, hours, minutes, seconds);
}
break;
case MACRO_HOSTEXECUTIONTIME:
*output = (char *)mkstr("%.3f", temp_host->execution_time);
break;
case MACRO_HOSTLATENCY:
*output = (char *)mkstr("%.3f", temp_host->latency);
break;
case MACRO_LASTHOSTCHECK:
*output = (char *)mkstr("%lu", (unsigned long)temp_host->last_check);
break;
case MACRO_LASTHOSTSTATECHANGE:
*output = (char *)mkstr("%lu", (unsigned long)temp_host->last_state_change);
break;
case MACRO_LASTHOSTUP:
*output = (char *)mkstr("%lu", (unsigned long)temp_host->last_time_up);
break;
case MACRO_LASTHOSTDOWN:
*output = (char *)mkstr("%lu", (unsigned long)temp_host->last_time_down);
break;
case MACRO_LASTHOSTUNREACHABLE:
*output = (char *)mkstr("%lu", (unsigned long)temp_host->last_time_unreachable);
break;
case MACRO_HOSTNOTIFICATIONNUMBER:
*output = (char *)mkstr("%d", temp_host->current_notification_number);
break;
case MACRO_HOSTNOTIFICATIONID:
*output = (char *)mkstr("%lu", temp_host->current_notification_id);
break;
case MACRO_HOSTEVENTID:
*output = (char *)mkstr("%lu", temp_host->current_event_id);
break;
case MACRO_LASTHOSTEVENTID:
*output = (char *)mkstr("%lu", temp_host->last_event_id);
break;
case MACRO_HOSTPROBLEMID:
*output = (char *)mkstr("%lu", temp_host->current_problem_id);
break;
case MACRO_LASTHOSTPROBLEMID:
*output = (char *)mkstr("%lu", temp_host->last_problem_id);
break;
#endif
case MACRO_HOSTACTIONURL:
if(temp_host->action_url)
*output = temp_host->action_url;
break;
case MACRO_HOSTNOTESURL:
if(temp_host->notes_url)
*output = temp_host->notes_url;
break;
case MACRO_HOSTNOTES:
if(temp_host->notes)
*output = 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 */
mac->x[MACRO_TOTALHOSTSERVICES] =
(char *)mkstr("%d", total_host_services);
mac->x[MACRO_TOTALHOSTSERVICESOK] =
(char *)mkstr("%d", total_host_services_ok);
mac->x[MACRO_TOTALHOSTSERVICESWARNING] =
(char *)mkstr("%d", total_host_services_warning);
mac->x[MACRO_TOTALHOSTSERVICESUNKNOWN] =
(char *)mkstr("%d", total_host_services_unknown);
mac->x[MACRO_TOTALHOSTSERVICESCRITICAL] =
(char *)mkstr("%d", total_host_services_critical);
}
/* return only the macro the user requested */
*output = mac->x[macro_type];
break;
case MACRO_HOSTIMPORTANCE:
*output = (char *)mkstr("%u", temp_host->hourly_value);
break;
case MACRO_HOSTANDSERVICESIMPORTANCE:
*output = (char *)mkstr("%u", temp_host->hourly_value +
host_services_value(temp_host));
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];
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:
*free_macro = TRUE;
process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS);
*output = temp_buffer;
break;
case MACRO_HOSTNOTES:
*free_macro = TRUE;
process_macros_r(mac, *output, &temp_buffer, 0);
*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;
if(temp_hostgroup == NULL || output == NULL)
return ERROR;
/* get the macro value */
switch(macro_type) {
case MACRO_HOSTGROUPNAME:
*output = temp_hostgroup->group_name;
break;
case MACRO_HOSTGROUPALIAS:
if(temp_hostgroup->alias)
*output = temp_hostgroup->alias;
break;
case MACRO_HOSTGROUPMEMBERS:
case MACRO_HOSTGROUPMEMBERADDRESSES:
/* make the calculations for total string length */
for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) {
if(macro_type == MACRO_HOSTGROUPMEMBERS) {
if(temp_hostsmember->host_name != NULL)
temp_len += strlen(temp_hostsmember->host_name) + 2;
}
else {
if(temp_hostsmember->host_ptr->address != NULL)
temp_len += strlen(temp_hostsmember->host_ptr->address) + 2;
}
}
if(!temp_len) {
/* empty group, so return the nul string */
*output = calloc(1, 1);
return OK;
}
/* allocate or reallocate the memory buffer */
if(*output == NULL) {
*output = (char *)malloc(temp_len);
**output = '\0';
}
else {
temp_len += strlen(*output);
*output = (char *)realloc(*output, temp_len);
}
/* now fill in the string with the member names or addresses */
for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) {
if(macro_type == MACRO_HOSTGROUPMEMBERS) {
if(temp_hostsmember->host_name == NULL)
continue;
}
else {
if(temp_hostsmember->host_ptr->address == NULL)
continue;
}
if(**output != '\0')
strcat(*output, ",");
if(macro_type == MACRO_HOSTGROUPMEMBERS)
strcat(*output, temp_hostsmember->host_name);
else
strcat(*output, temp_hostsmember->host_ptr->address);
}
break;
case MACRO_HOSTGROUPACTIONURL:
if(temp_hostgroup->action_url)
*output = temp_hostgroup->action_url;
break;
case MACRO_HOSTGROUPNOTESURL:
if(temp_hostgroup->notes_url)
*output = temp_hostgroup->notes_url;
break;
case MACRO_HOSTGROUPNOTES:
if(temp_hostgroup->notes)
*output = 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);
*output = temp_buffer;
break;
case MACRO_HOSTGROUPNOTES:
process_macros_r(mac, *output, &temp_buffer, 0);
*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;
/* get the macro value */
switch(macro_type) {
case MACRO_SERVICEDESC:
*output = temp_service->description;
break;
case MACRO_SERVICEDISPLAYNAME:
if(temp_service->display_name)
*output = temp_service->display_name;
break;
#ifdef NSCORE
case MACRO_SERVICEOUTPUT:
if(temp_service->plugin_output)
*output = temp_service->plugin_output;
break;
case MACRO_LONGSERVICEOUTPUT:
if(temp_service->long_plugin_output)
*output = temp_service->long_plugin_output;
break;
case MACRO_SERVICEPERFDATA:
if(temp_service->perf_data)
*output = temp_service->perf_data;
break;
#endif
case MACRO_SERVICECHECKCOMMAND:
if(temp_service->check_command)
*output = temp_service->check_command;
break;
#ifdef NSCORE
case MACRO_SERVICECHECKTYPE:
*output = (char *)check_type_name(temp_service->check_type);
break;
case MACRO_SERVICESTATETYPE:
*output = (char *)state_type_name(temp_service->state_type);
break;
case MACRO_SERVICESTATE:
*output = (char *)service_state_name(temp_service->current_state);
break;
case MACRO_SERVICESTATEID:
*output = (char *)mkstr("%d", temp_service->current_state);
break;
case MACRO_LASTSERVICESTATE:
*output = (char *)service_state_name(temp_service->last_state);
break;
case MACRO_LASTSERVICESTATEID:
*output = (char *)mkstr("%d", temp_service->last_state);
break;
#endif
case MACRO_SERVICEISVOLATILE:
*output = (char *)mkstr("%d", temp_service->is_volatile);
break;
#ifdef NSCORE
case MACRO_SERVICEATTEMPT:
*output = (char *)mkstr("%d", temp_service->current_attempt);
break;
case MACRO_MAXSERVICEATTEMPTS:
*output = (char *)mkstr("%d", temp_service->max_attempts);
break;
case MACRO_SERVICEEXECUTIONTIME:
*output = (char *)mkstr("%.3f", temp_service->execution_time);
break;
case MACRO_SERVICELATENCY:
*output = (char *)mkstr("%.3f", temp_service->latency);
break;
case MACRO_LASTSERVICECHECK:
*output = (char *)mkstr("%lu", (unsigned long)temp_service->last_check);
break;
case MACRO_LASTSERVICESTATECHANGE:
*output = (char *)mkstr("%lu", (unsigned long)temp_service->last_state_change);
break;
case MACRO_LASTSERVICEOK:
*output = (char *)mkstr("%lu", (unsigned long)temp_service->last_time_ok);
break;
case MACRO_LASTSERVICEWARNING:
*output = (char *)mkstr("%lu", (unsigned long)temp_service->last_time_warning);
break;
case MACRO_LASTSERVICEUNKNOWN:
*output = (char *)mkstr("%lu", (unsigned long)temp_service->last_time_unknown);
break;
case MACRO_LASTSERVICECRITICAL:
*output = (char *)mkstr("%lu", (unsigned long)temp_service->last_time_critical);
break;
case MACRO_SERVICEDOWNTIME:
*output = (char *)mkstr("%d", temp_service->scheduled_downtime_depth);
break;
case MACRO_SERVICEPERCENTCHANGE:
*output = (char *)mkstr("%.2f", temp_service->percent_state_change);
break;
case MACRO_SERVICEDURATIONSEC:
case MACRO_SERVICEDURATION:
time(&current_time);
duration = (unsigned long)(current_time - temp_service->last_state_change);
/* get the state duration in seconds */
if(macro_type == MACRO_SERVICEDURATIONSEC)
*output = (char *)mkstr("%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;
*output = (char *)mkstr("%dd %dh %dm %ds", days, hours, minutes, seconds);
}
break;
case MACRO_SERVICENOTIFICATIONNUMBER:
*output = (char *)mkstr("%d", temp_service->current_notification_number);
break;
case MACRO_SERVICENOTIFICATIONID:
*output = (char *)mkstr("%lu", temp_service->current_notification_id);
break;
case MACRO_SERVICEEVENTID:
*output = (char *)mkstr("%lu", temp_service->current_event_id);
break;
case MACRO_LASTSERVICEEVENTID:
*output = (char *)mkstr("%lu", temp_service->last_event_id);
break;
case MACRO_SERVICEPROBLEMID:
*output = (char *)mkstr("%lu", temp_service->current_problem_id);
break;
case MACRO_LASTSERVICEPROBLEMID:
*output = (char *)mkstr("%lu", temp_service->last_problem_id);
break;
#endif
case MACRO_SERVICEACTIONURL:
if(temp_service->action_url)
*output = temp_service->action_url;
break;
case MACRO_SERVICENOTESURL:
if(temp_service->notes_url)
*output = temp_service->notes_url;
break;
case MACRO_SERVICENOTES:
if(temp_service->notes)
*output = 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;
case MACRO_SERVICEIMPORTANCE:
*output = (char *)mkstr("%u", temp_service->hourly_value);
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);
*output = temp_buffer;
break;
case MACRO_SERVICENOTES:
process_macros_r(mac, *output, &temp_buffer, 0);
*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 = temp_servicegroup->group_name;
break;
case MACRO_SERVICEGROUPALIAS:
if(temp_servicegroup->alias)
*output = 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;
}
}
if(!temp_len) {
/* empty group, so return the nul string */
*output = calloc(1, 1);
return OK;
}
/* 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 = temp_servicegroup->action_url;
break;
case MACRO_SERVICEGROUPNOTESURL:
if(temp_servicegroup->notes_url)
*output = temp_servicegroup->notes_url;
break;
case MACRO_SERVICEGROUPNOTES:
if(temp_servicegroup->notes)
*output = 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);
*output = temp_buffer;
break;
case MACRO_SERVICEGROUPNOTES:
process_macros_r(mac, *output, &temp_buffer, 0);
*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 = temp_contact->name;
break;
case MACRO_CONTACTALIAS:
*output = temp_contact->alias;
break;
case MACRO_CONTACTEMAIL:
if(temp_contact->email)
*output = temp_contact->email;
break;
case MACRO_CONTACTPAGER:
if(temp_contact->pager)
*output = 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 = temp_contactgroup->group_name;
break;
case MACRO_CONTACTGROUPALIAS:
if(temp_contactgroup->alias)
*output = 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 = 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 ch = 0;
register int len = 0;
char *ret = NULL;
if(macro == NULL || !*macro)
return "";
len = (int)strlen(macro);
ret = strdup(macro);
/* strip illegal characters out of macro */
if(options & STRIP_ILLEGAL_MACRO_CHARS) {
for(y = 0, x = 0; x < len; x++) {
ch = macro[x] & 0xff;
/* illegal chars are skipped */
if(!illegal_output_char_map[ch])
ret[y++] = ret[x];
}
ret[y++] = '\x0';
}
return ret;
}
/* encodes a string in proper URL format */
char *get_url_encoded_string(char *input) {
/* From RFC 3986:
segment = *pchar
[...]
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
query = *( pchar / "/" / "?" )
fragment = *( pchar / "/" / "?" )
pct-encoded = "%" HEXDIG HEXDIG
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
Encode everything but "unreserved", to be on safe side.
Another note:
nowhere in the RFC states that + is interpreted as space. Therefore, encode
space as %20 (as all other characters that should be escaped)
*/
register int x = 0;
register int y = 0;
char *encoded_url_string = NULL;
/* 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]; 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] >= 'a' && (char)input[x] <= 'z') ||
(char)input[x] == '.' ||
(char)input[x] == '-' ||
(char)input[x] == '_' ||
(char)input[x] == '~')
{
encoded_url_string[y++] = input[x];
}
/* anything else gets represented by its hex value */
else {
sprintf(&encoded_url_string[y], "%%%02X", (unsigned int)(input[x] & 0xFF));
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) {
int x;
init_macrox_names();
for(x = 0; x < 32; x++)
illegal_output_char_map[x] = 1;
illegal_output_char_map[127] = 1;
/*
* 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];
/* This tells which escaping is possible to do on the macro */
macro_keys[x].options = URL_ENCODE_MACRO_CHARS;
switch(x) {
case MACRO_HOSTOUTPUT:
case MACRO_LONGHOSTOUTPUT:
case MACRO_HOSTPERFDATA:
case MACRO_HOSTACKAUTHOR:
case MACRO_HOSTACKCOMMENT:
case MACRO_SERVICEOUTPUT:
case MACRO_LONGSERVICEOUTPUT:
case MACRO_SERVICEPERFDATA:
case MACRO_SERVICEACKAUTHOR:
case MACRO_SERVICEACKCOMMENT:
macro_keys[x].options |= STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS;
break;
}
}
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);
add_macrox_name(HOSTIMPORTANCE);
add_macrox_name(SERVICEIMPORTANCE);
add_macrox_name(HOSTANDSERVICESIMPORTANCE);
add_macrox_name(HOSTGROUPMEMBERADDRESSES);
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
static void clear_custom_vars(customvariablesmember **vars) {
customvariablesmember *this_customvariablesmember = NULL;
customvariablesmember *next_customvariablesmember = NULL;
for(this_customvariablesmember = *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);
}
*vars = NULL;
}
/* clear all macros that are not "constant" (i.e. they change throughout the course of monitoring) */
int clear_volatile_macros_r(nagios_macros *mac) {
register int x = 0;
log_debug_info(DEBUGL_FUNCTIONS, 0, "clear_volatile_macros_r()\n");
clear_host_macros_r(mac);
clear_service_macros_r(mac);
clear_summary_macros_r(mac);
clear_hostgroup_macros_r(mac);
clear_servicegroup_macros_r(mac);
clear_contactgroup_macros_r(mac);
clear_contact_macros_r(mac);
clear_datetime_macros_r(mac);
/* contact address macros */
for(x = 0; x < MAX_CONTACT_ADDRESSES; x++)
my_free(mac->contactaddress[x]);
/* clear on-demand macro */
my_free(mac->ondemand);
/* clear ARGx macros */
clear_argv_macros_r(mac);
return OK;
}
int clear_volatile_macros(void) {
return clear_volatile_macros_r(&global_macros);
}
/* clear datetime macros */
int clear_datetime_macros_r(nagios_macros *mac) {
my_free(mac->x[MACRO_LONGDATETIME]);
my_free(mac->x[MACRO_SHORTDATETIME]);
my_free(mac->x[MACRO_DATE]);
my_free(mac->x[MACRO_TIME]);
return OK;
}
/* clear service macros */
int clear_service_macros_r(nagios_macros *mac) {
/* these are recursive but persistent. what to do? */
my_free(mac->x[MACRO_SERVICEACTIONURL]);
my_free(mac->x[MACRO_SERVICENOTESURL]);
my_free(mac->x[MACRO_SERVICENOTES]);
my_free(mac->x[MACRO_SERVICEGROUPNAMES]);
/* clear custom service variables */
clear_custom_vars(&(mac->custom_service_vars));
/* 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) {
/* these are recursive but persistent. what to do? */
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_HOSTGROUPNAMES]);
/* clear custom host variables */
clear_custom_vars(&(mac->custom_host_vars));
/* 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) {
/* recursive 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]);
my_free(mac->x[MACRO_HOSTGROUPMEMBERADDRESSES]);
/* 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) {
/* recursive 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) {
/* generated */
my_free(mac->x[MACRO_CONTACTGROUPNAMES]);
/* clear custom contact variables */
clear_custom_vars(&(mac->custom_contact_vars));
/* 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) {
/* generated */
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;
/* set each of the macrox environment variables */
for(x = 0; x < MACRO_X_COUNT; x++) {
free_macro = FALSE;
/* large installations don't get all macros */
if(use_large_installation_tweaks == TRUE) {
/*
* member macros tend to overflow the
* environment on large installations
*/
if(x == MACRO_SERVICEGROUPMEMBERS || x == MACRO_HOSTGROUPMEMBERS || x == MACRO_HOSTGROUPMEMBERADDRESSES)
continue;
/* summary macros are CPU intensive to compute */
if(x >= MACRO_TOTALHOSTSUP && x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED)
continue;
}
/* generate the macro value if it hasn't already been done */
/* THIS IS EXPENSIVE */
if(set == TRUE) {
if(mac->x[x] == NULL)
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(&macro_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;
}
static int add_macrox_environment_vars_r(nagios_macros *, struct kvvec *);
static int add_argv_macro_environment_vars_r(nagios_macros *, struct kvvec *);
static int add_custom_macro_environment_vars_r(nagios_macros *, struct kvvec *);
static int add_contact_address_environment_vars_r(nagios_macros *,
struct kvvec *);
struct kvvec * macros_to_kvv(nagios_macros *mac) {
struct kvvec *kvvp;
log_debug_info(DEBUGL_FUNCTIONS, 0, "macros_to_kvv()\n");
/* If we're not supposed to export macros as environment variables,
just return */
if(FALSE == enable_environment_macros) return NULL;
/* Create the kvvec to hold the macros */
if((kvvp = calloc(1, sizeof(struct kvvec))) == NULL) return NULL;
if(!kvvec_init(kvvp, MACRO_X_COUNT + MAX_COMMAND_ARGUMENTS + MAX_CONTACT_ADDRESSES + 4)) return NULL;
add_macrox_environment_vars_r(mac, kvvp);
add_argv_macro_environment_vars_r(mac, kvvp);
add_custom_macro_environment_vars_r(mac, kvvp);
add_contact_address_environment_vars_r(mac, kvvp);
return kvvp;
}
/* adds macrox environment variables */
static int add_macrox_environment_vars_r(nagios_macros *mac, struct kvvec *kvvp)
{
/*register*/ int x = 0;
int free_macro = FALSE;
char *envname;
log_debug_info(DEBUGL_FUNCTIONS, 1, "add_macrox_environment_vars_r()\n");
/* set each of the macrox environment variables */
for(x = 0; x < MACRO_X_COUNT; x++) {
log_debug_info(DEBUGL_MACROS, 2, "Processing macro %d of %d\n", x,
MACRO_X_COUNT);
free_macro = FALSE;
/* large installations don't get all macros */
if(use_large_installation_tweaks == TRUE) {
/*
* member macros tend to overflow the
* environment on large installations
*/
if(x == MACRO_SERVICEGROUPMEMBERS || x == MACRO_HOSTGROUPMEMBERS ||
x == MACRO_HOSTGROUPMEMBERADDRESSES)
continue;
/* summary macros are CPU intensive to compute */
if(x >= MACRO_TOTALHOSTSUP && x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED)
continue;
}
/* generate the macro value if it hasn't already been done */
/* THIS IS EXPENSIVE */
if(mac->x[x] == NULL) {
log_debug_info(DEBUGL_MACROS, 2, "Grabbing value for macro: %s\n",
macro_x_names[x]);
grab_macrox_value_r(mac, x, NULL, NULL, &mac->x[x], &free_macro);
}
/* add the value to the kvvec */
log_debug_info(DEBUGL_MACROS, 2, "Adding macro \"%s\" with value \"%s\" to kvvec\n",
macro_x_names[x], mac->x[x]);
/* Allocate memory for each environment variable name, but not the
values because when kvvec_destroy() is called, it is called with
KVVEC_FREE_KEYS */
asprintf(&envname, "%s%s", MACRO_ENV_VAR_PREFIX, macro_x_names[x]);
kvvec_addkv(kvvp, envname, mac->x[x]);
}
log_debug_info(DEBUGL_FUNCTIONS, 2, "add_macrox_environment_vars_r() end\n");
return OK;
}
/* adds argv macro environment variables */
static int add_argv_macro_environment_vars_r(nagios_macros *mac,
struct kvvec *kvvp) {
char *macro_name = NULL;
register int x = 0;
log_debug_info(DEBUGL_FUNCTIONS, 1, "add_argv_macro_environment_vars_r()\n");
/* set each of the argv macro environment variables */
for(x = 0; x < MAX_COMMAND_ARGUMENTS; x++) {
/* Allocate memory for each environment variable name, but not the
values because when kvvec_destroy() is called, it is called with
KVVEC_FREE_KEYS */
asprintf(&macro_name, "%sARG%d", MACRO_ENV_VAR_PREFIX, x + 1);
kvvec_addkv(kvvp, macro_name, mac->argv[x]);
}
return OK;
}
/* adds custom host/service/contact macro environment variables */
static int add_custom_macro_environment_vars_r(nagios_macros *mac,
struct kvvec *kvvp) {
customvariablesmember *temp_customvariablesmember = NULL;
host *temp_host = NULL;
service *temp_service = NULL;
contact *temp_contact = NULL;
char *customvarname = NULL;
char *customvarvalue = NULL;
log_debug_info(DEBUGL_FUNCTIONS, 1, "add_custom_macro_environment_vars_r()\n");
/***** CUSTOM HOST VARIABLES *****/
/* generate variables and save them for later */
temp_host = mac->host_ptr;
if(temp_host) {
for(temp_customvariablesmember = temp_host->custom_variables;
temp_customvariablesmember != NULL;
temp_customvariablesmember = temp_customvariablesmember->next) {
asprintf(&customvarname, "%s_HOST%s", MACRO_ENV_VAR_PREFIX,
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) {
customvarvalue =
clean_macro_chars(temp_customvariablesmember->variable_value,
STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS);
if(customvarvalue && *customvarvalue) {
my_free(temp_customvariablesmember->variable_value);
temp_customvariablesmember->variable_value = customvarvalue;
/* Allocate memory for each environment variable name, but not the
values because when kvvec_destroy() is called, it is called with
KVVEC_FREE_KEYS */
kvvec_addkv(kvvp, strdup(temp_customvariablesmember->variable_name),
customvarvalue);
}
}
/***** CUSTOM SERVICE VARIABLES *****/
/* generate variables and save them for later */
temp_service = mac->service_ptr;
if(temp_service) {
for(temp_customvariablesmember = temp_service->custom_variables;
temp_customvariablesmember != NULL;
temp_customvariablesmember = temp_customvariablesmember->next) {
asprintf(&customvarname, "%s_SERVICE%s", MACRO_ENV_VAR_PREFIX,
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) {
customvarvalue =
clean_macro_chars(temp_customvariablesmember->variable_value,
STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS);
if(customvarvalue && *customvarvalue) {
my_free(temp_customvariablesmember->variable_value);
temp_customvariablesmember->variable_value = customvarvalue;
/* Allocate memory for each environment variable name, but not the
values because when kvvec_destroy() is called, it is called with
KVVEC_FREE_KEYS */
kvvec_addkv(kvvp, strdup(temp_customvariablesmember->variable_name),
customvarvalue);
}
}
/***** CUSTOM CONTACT VARIABLES *****/
/* generate variables and save them for later */
temp_contact = mac->contact_ptr;
if(temp_contact) {
for(temp_customvariablesmember = temp_contact->custom_variables;
temp_customvariablesmember != NULL;
temp_customvariablesmember = temp_customvariablesmember->next) {
asprintf(&customvarname, "%s_CONTACT%s", MACRO_ENV_VAR_PREFIX,
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) {
customvarvalue =
clean_macro_chars(temp_customvariablesmember->variable_value,
STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS);
if(customvarvalue && *customvarvalue) {
my_free(temp_customvariablesmember->variable_value);
temp_customvariablesmember->variable_value = customvarvalue;
/* Allocate memory for each environment variable name, but not the
values because when kvvec_destroy() is called, it is called with
KVVEC_FREE_KEYS */
kvvec_addkv(kvvp, strdup(temp_customvariablesmember->variable_name),
customvarvalue);
}
}
return OK;
}
/* add contact address environment variables */
static int add_contact_address_environment_vars_r(nagios_macros *mac,
struct kvvec *kvvp) {
char *varname = NULL;
register int x;
log_debug_info(DEBUGL_FUNCTIONS, 1, "add_contact_address_environment_vars_r()\n");
/* these only get set during notifications */
if(mac->contact_ptr == NULL)
return OK;
asprintf(&varname, "%sCONTACTNAME", MACRO_ENV_VAR_PREFIX);
kvvec_addkv(kvvp, varname, mac->contact_ptr->name);
asprintf(&varname, "%sCONTACTALIAS", MACRO_ENV_VAR_PREFIX);
kvvec_addkv(kvvp, varname, mac->contact_ptr->alias);
asprintf(&varname, "%sCONTACTEMAIL", MACRO_ENV_VAR_PREFIX);
kvvec_addkv(kvvp, varname, mac->contact_ptr->email);
asprintf(&varname, "%sCONTACTPAGER", MACRO_ENV_VAR_PREFIX);
kvvec_addkv(kvvp, varname, mac->contact_ptr->pager);
for(x = 0; x < MAX_CONTACT_ADDRESSES; x++) {
/* Allocate memory for each environment variable name, but not the
values because when kvvec_destroy() is called, it is called with
KVVEC_FREE_KEYS */
asprintf(&varname, "%sCONTACTADDRESS%d", MACRO_ENV_VAR_PREFIX, x);
kvvec_addkv(kvvp, varname, mac->contact_ptr->address[x]);
}
return OK;
}
#endif