This program is free software; you can redistribute it and/or "
"modify it under the terms of the GNU Affero General Public License version 3
"
"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 AFFERO GENERAL PUBLIC LICENSE for more details.
");
StringBuffer_append(res->outputbuffer,
"[Back to Monit]
");
}
static void do_ping(HttpRequest req, HttpResponse res) {
StringBuffer_append(res->outputbuffer, "pong");
}
static void do_getid(HttpRequest req, HttpResponse res) {
StringBuffer_append(res->outputbuffer, "%s", Run.id);
}
static void do_runtime(HttpRequest req, HttpResponse res) {
int pid = exist_daemon();
char buf[STRLEN];
do_head(res, "_runtime", "Runtime", 1000);
StringBuffer_append(res->outputbuffer,
"Monit runtime status
");
StringBuffer_append(res->outputbuffer, ""
"Parameter | "
"Value |
");
StringBuffer_append(res->outputbuffer, "Monit ID | %s |
", Run.id);
StringBuffer_append(res->outputbuffer, "Host | %s |
", Run.system->name);
StringBuffer_append(res->outputbuffer,
"Process id | %d |
", pid);
StringBuffer_append(res->outputbuffer,
"Effective user running Monit | "
"%s |
", Run.Env.user);
StringBuffer_append(res->outputbuffer,
"Controlfile | %s |
", Run.files.control);
if (Run.files.log)
StringBuffer_append(res->outputbuffer,
"Logfile | %s |
", Run.files.log);
StringBuffer_append(res->outputbuffer,
"Pidfile | %s |
", Run.files.pid);
StringBuffer_append(res->outputbuffer,
"State file | %s |
", Run.files.state);
StringBuffer_append(res->outputbuffer,
"Debug | %s |
",
Run.debug ? "True" : "False");
StringBuffer_append(res->outputbuffer,
"Log | %s |
", (Run.flags & Run_Log) ? "True" : "False");
StringBuffer_append(res->outputbuffer,
"Use syslog | %s |
",
(Run.flags & Run_UseSyslog) ? "True" : "False");
if (Run.eventlist_dir) {
if (Run.eventlist_slots < 0)
snprintf(buf, STRLEN, "unlimited");
else
snprintf(buf, STRLEN, "%d", Run.eventlist_slots);
StringBuffer_append(res->outputbuffer,
"Event queue | "
"base directory %s with %d slots |
",
Run.eventlist_dir, Run.eventlist_slots);
}
#ifdef HAVE_OPENSSL
{
const char *options = Ssl_printOptions(&(Run.ssl), (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(res->outputbuffer,
"SSL options | %s |
", options);
}
#endif
if (Run.mmonits) {
StringBuffer_append(res->outputbuffer, "M/Monit server(s) | ");
for (Mmonit_T c = Run.mmonits; c; c = c->next)
{
StringBuffer_append(res->outputbuffer, "%s with timeout %s", c->url->url, Str_milliToTime(c->timeout, (char[23]){}));
#ifdef HAVE_OPENSSL
if (c->ssl.use_ssl) {
StringBuffer_append(res->outputbuffer, " using SSL/TLS");
const char *options = Ssl_printOptions(&c->ssl, (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(res->outputbuffer, " with options {%s}", options);
if (c->ssl.checksum)
StringBuffer_append(res->outputbuffer, " and certificate checksum %s equal to '%s'", checksumnames[c->ssl.checksumType], c->ssl.checksum);
}
#endif
if (c->url->user)
StringBuffer_append(res->outputbuffer, " using credentials");
if (c->next)
StringBuffer_append(res->outputbuffer, " |
| ");
}
StringBuffer_append(res->outputbuffer, " |
");
}
if (Run.mailservers) {
StringBuffer_append(res->outputbuffer, "Mail server(s) | ");
for (MailServer_T mta = Run.mailservers; mta; mta = mta->next) {
StringBuffer_append(res->outputbuffer, "%s:%d", mta->host, mta->port);
#ifdef HAVE_OPENSSL
if (mta->ssl.use_ssl) {
StringBuffer_append(res->outputbuffer, " using SSL/TLS");
const char *options = Ssl_printOptions(&mta->ssl, (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(res->outputbuffer, " with options {%s}", options);
if (mta->ssl.checksum)
StringBuffer_append(res->outputbuffer, " and certificate checksum %s equal to '%s'", checksumnames[mta->ssl.checksumType], mta->ssl.checksum);
}
#endif
if (mta->next)
StringBuffer_append(res->outputbuffer, " |
| ");
}
StringBuffer_append(res->outputbuffer, " |
");
}
if (Run.MailFormat.from)
StringBuffer_append(res->outputbuffer,
"Default mail from | %s |
",
Run.MailFormat.from);
if (Run.MailFormat.subject)
StringBuffer_append(res->outputbuffer,
"Default mail subject | %s |
",
Run.MailFormat.subject);
if (Run.MailFormat.message)
StringBuffer_append(res->outputbuffer,
"Default mail message | %s |
",
Run.MailFormat.message);
StringBuffer_append(res->outputbuffer, "Limit for Send/Expect buffer | %s |
", Str_bytesToSize(Run.limits.sendExpectBuffer, buf));
StringBuffer_append(res->outputbuffer, "Limit for file content buffer | %s |
", Str_bytesToSize(Run.limits.fileContentBuffer, buf));
StringBuffer_append(res->outputbuffer, "Limit for HTTP content buffer | %s |
", Str_bytesToSize(Run.limits.httpContentBuffer, buf));
StringBuffer_append(res->outputbuffer, "Limit for program output | %s |
", Str_bytesToSize(Run.limits.programOutput, buf));
StringBuffer_append(res->outputbuffer, "Limit for network timeout | %s |
", Str_milliToTime(Run.limits.networkTimeout, (char[23]){}));
StringBuffer_append(res->outputbuffer,
"Poll time | %d seconds with start delay %d seconds |
",
Run.polltime, Run.startdelay);
if (Run.httpd.flags & Httpd_Net) {
StringBuffer_append(res->outputbuffer,
"httpd bind address | %s |
",
Run.httpd.socket.net.address ? Run.httpd.socket.net.address : "Any/All");
StringBuffer_append(res->outputbuffer,
"httpd portnumber | %d |
", Run.httpd.socket.net.port);
} else if (Run.httpd.flags & Httpd_Unix) {
StringBuffer_append(res->outputbuffer,
"httpd unix socket | %s |
",
Run.httpd.socket.unix.path);
}
StringBuffer_append(res->outputbuffer,
"httpd signature | %s |
",
Run.httpd.flags & Httpd_Signature ? "True" : "False");
StringBuffer_append(res->outputbuffer,
"Use ssl encryption | %s |
",
Run.httpd.flags & Httpd_Ssl ? "True" : "False");
if (Run.httpd.flags & Httpd_Ssl) {
StringBuffer_append(res->outputbuffer,
"PEM key/certificate file | %s |
",
Run.httpd.socket.net.ssl.pem);
if (Run.httpd.socket.net.ssl.clientpem != NULL) {
StringBuffer_append(res->outputbuffer,
"Client PEM key/certification"
" | %s |
", "Enabled");
StringBuffer_append(res->outputbuffer,
"Client PEM key/certificate file"
" | %s |
", Run.httpd.socket.net.ssl.clientpem);
} else {
StringBuffer_append(res->outputbuffer,
"Client PEM key/certification"
" | %s |
", "Disabled");
}
StringBuffer_append(res->outputbuffer,
"Allow self certified certificates "
" | %s |
", Run.httpd.flags & Httpd_AllowSelfSignedCertificates ? "True" : "False");
}
StringBuffer_append(res->outputbuffer,
"httpd auth. style | %s |
",
Run.httpd.credentials && Engine_hasHostsAllow() ? "Basic Authentication and Host/Net allow list" : Run.httpd.credentials ? "Basic Authentication" : Engine_hasHostsAllow() ? "Host/Net allow list" : "No authentication");
print_alerts(res, Run.maillist);
StringBuffer_append(res->outputbuffer, "
");
if (! is_readonly(req)) {
StringBuffer_append(res->outputbuffer,
"");
}
do_foot(res);
}
static void do_viewlog(HttpRequest req, HttpResponse res) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficent privileges to access this page");
return;
}
do_head(res, "_viewlog", "View log", 100);
if ((Run.flags & Run_Log) && ! (Run.flags & Run_UseSyslog)) {
struct stat sb;
if (! stat(Run.files.log, &sb)) {
FILE *f = fopen(Run.files.log, "r");
if (f) {
#define BUFSIZE 512
size_t n;
char buf[BUFSIZE+1];
StringBuffer_append(res->outputbuffer, "
");
} else {
StringBuffer_append(res->outputbuffer, "Error opening logfile: %s", STRERROR);
}
} else {
StringBuffer_append(res->outputbuffer, "Error stating logfile: %s", STRERROR);
}
} else {
StringBuffer_append(res->outputbuffer,
"Cannot view logfile:
");
if (! (Run.flags & Run_Log))
StringBuffer_append(res->outputbuffer, "Monit was started without logging");
else
StringBuffer_append(res->outputbuffer, "Monit uses syslog");
}
do_foot(res);
}
static void handle_action(HttpRequest req, HttpResponse res) {
char *name = req->url;
Service_T s = Util_getService(++name);
if (! s) {
send_error(req, res, SC_NOT_FOUND, "There is no service named \"%s\"", name ? name : "");
return;
}
const char *action = get_parameter(req, "action");
if (action) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficent privileges to access this page");
return;
}
Action_Type doaction = Util_getAction(action);
if (doaction == Action_Ignored) {
send_error(req, res, SC_BAD_REQUEST, "Invalid action \"%s\"", action);
return;
}
s->doaction = doaction;
const char *token = get_parameter(req, "token");
if (token) {
FREE(s->token);
s->token = Str_dup(token);
}
LogInfo("'%s' %s on user request\n", s->name, action);
Run.flags |= Run_ActionPending; /* set the global flag */
do_wakeupcall();
}
do_service(req, res, s);
}
static void handle_do_action(HttpRequest req, HttpResponse res) {
Service_T s;
Action_Type doaction = Action_Ignored;
const char *action = get_parameter(req, "action");
const char *token = get_parameter(req, "token");
if (action) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficent privileges to access this page");
return;
}
if ((doaction = Util_getAction(action)) == Action_Ignored) {
send_error(req, res, SC_BAD_REQUEST, "Invalid action \"%s\"", action);
return;
}
for (HttpParameter p = req->params; p; p = p->next) {
if (IS(p->name, "service")) {
s = Util_getService(p->value);
if (! s) {
send_error(req, res, SC_BAD_REQUEST, "There is no service named \"%s\"", p->value ? p->value : "");
return;
}
s->doaction = doaction;
LogInfo("'%s' %s on user request\n", s->name, action);
}
}
/* Set token for last service only so we'll get it back after all services were handled */
if (token) {
Service_T q = NULL;
for (s = servicelist; s; s = s->next)
if (s->doaction == doaction)
q = s;
if (q) {
FREE(q->token);
q->token = Str_dup(token);
}
}
Run.flags |= Run_ActionPending;
do_wakeupcall();
}
}
static void handle_run(HttpRequest req, HttpResponse res) {
const char *action = get_parameter(req, "action");
if (action) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficent privileges to access this page");
return;
}
if (IS(action, "validate")) {
LogInfo("The Monit http server woke up on user request\n");
do_wakeupcall();
} else if (IS(action, "stop")) {
LogInfo("The Monit http server stopped on user request\n");
send_error(req, res, SC_SERVICE_UNAVAILABLE, "The Monit http server is stopped");
Engine_stop();
return;
}
}
LOCK(Run.mutex)
do_runtime(req, res);
END_LOCK;
}
static void do_service(HttpRequest req, HttpResponse res, Service_T s) {
char buf[STRLEN];
ASSERT(s);
do_head(res, s->name, s->name, Run.polltime);
StringBuffer_append(res->outputbuffer,
"%s status
"
""
""
"Parameter | "
"Value | "
"
"
""
"Name | "
"%s | "
"
",
servicetypes[s->type],
s->name);
if (s->type == Service_Process)
StringBuffer_append(res->outputbuffer, "%s | %s |
", s->matchlist ? "Match" : "Pid file", s->path);
else if (s->type == Service_Host)
StringBuffer_append(res->outputbuffer, "Address | %s |
", s->path);
else if (s->type == Service_Net)
StringBuffer_append(res->outputbuffer, "Interface | %s |
", s->path);
else if (s->type != Service_System)
StringBuffer_append(res->outputbuffer, "Path | %s |
", s->path);
StringBuffer_append(res->outputbuffer, "Status | ");
_printServiceStatus(res->outputbuffer, s);
StringBuffer_append(res->outputbuffer, " |
");
for (ServiceGroup_T sg = servicegrouplist; sg; sg = sg->next)
for (list_t m = sg->members->head; m; m = m->next)
if (m->e == s)
StringBuffer_append(res->outputbuffer, "Group | %s |
", sg->name);
StringBuffer_append(res->outputbuffer,
"Monitoring mode | %s |
", modenames[s->mode]);
StringBuffer_append(res->outputbuffer,
"Monitoring status | %s |
", get_monitoring_status(s, buf, sizeof(buf)));
for (Dependant_T d = s->dependantlist; d; d = d->next) {
if (d->dependant != NULL) {
StringBuffer_append(res->outputbuffer,
"Depends on service | %s |
",
d->dependant, d->dependant);
}
}
if (s->start) {
int i = 0;
StringBuffer_append(res->outputbuffer, "Start program | '");
while (s->start->arg[i]) {
if (i)
StringBuffer_append(res->outputbuffer, " ");
StringBuffer_append(res->outputbuffer, "%s", s->start->arg[i++]);
}
StringBuffer_append(res->outputbuffer, "'");
if (s->start->has_uid)
StringBuffer_append(res->outputbuffer, " as uid %d", s->start->uid);
if (s->start->has_gid)
StringBuffer_append(res->outputbuffer, " as gid %d", s->start->gid);
StringBuffer_append(res->outputbuffer, " timeout %d second(s)", s->start->timeout);
StringBuffer_append(res->outputbuffer, " |
");
}
if (s->stop) {
int i = 0;
StringBuffer_append(res->outputbuffer, "Stop program | '");
while (s->stop->arg[i]) {
if (i)
StringBuffer_append(res->outputbuffer, " ");
StringBuffer_append(res->outputbuffer, "%s", s->stop->arg[i++]);
}
StringBuffer_append(res->outputbuffer, "'");
if (s->stop->has_uid)
StringBuffer_append(res->outputbuffer, " as uid %d", s->stop->uid);
if (s->stop->has_gid)
StringBuffer_append(res->outputbuffer, " as gid %d", s->stop->gid);
StringBuffer_append(res->outputbuffer, " timeout %d second(s)", s->stop->timeout);
StringBuffer_append(res->outputbuffer, " |
");
}
if (s->restart) {
int i = 0;
StringBuffer_append(res->outputbuffer, "Restart program | '");
while (s->restart->arg[i]) {
if (i) StringBuffer_append(res->outputbuffer, " ");
StringBuffer_append(res->outputbuffer, "%s", s->restart->arg[i++]);
}
StringBuffer_append(res->outputbuffer, "'");
if (s->restart->has_uid)
StringBuffer_append(res->outputbuffer, " as uid %d", s->restart->uid);
if (s->restart->has_gid)
StringBuffer_append(res->outputbuffer, " as gid %d", s->restart->gid);
StringBuffer_append(res->outputbuffer, " timeout %d second(s)", s->restart->timeout);
StringBuffer_append(res->outputbuffer, " |
");
}
if (s->every.type != Every_Cycle) {
StringBuffer_append(res->outputbuffer, "Check service | ");
if (s->every.type == Every_SkipCycles)
StringBuffer_append(res->outputbuffer, "every %d cycle", s->every.spec.cycle.number);
else if (s->every.type == Every_Cron)
StringBuffer_append(res->outputbuffer, "every \"%s\" ", s->every.spec.cron);
else if (s->every.type == Every_NotInCron)
StringBuffer_append(res->outputbuffer, "not every \"%s\" ", s->every.spec.cron);
StringBuffer_append(res->outputbuffer, " |
");
}
// Status
switch (s->type) {
case Service_Filesystem:
print_service_status_perm(res, s, s->inf->priv.filesystem.mode);
print_service_status_uid(res, s, s->inf->priv.filesystem.uid);
print_service_status_gid(res, s, s->inf->priv.filesystem.gid);
print_service_status_filesystem_flags(res, s);
print_service_status_filesystem_blockstotal(res, s);
print_service_status_filesystem_blocksfree(res, s);
print_service_status_filesystem_blocksfreetotal(res, s);
print_service_status_filesystem_blocksize(res, s);
print_service_status_filesystem_inodestotal(res, s);
print_service_status_filesystem_inodesfree(res, s);
break;
case Service_Directory:
print_service_status_perm(res, s, s->inf->priv.directory.mode);
print_service_status_uid(res, s, s->inf->priv.directory.uid);
print_service_status_gid(res, s, s->inf->priv.directory.gid);
print_service_status_timestamp(res, s, s->inf->priv.directory.timestamp);
break;
case Service_File:
print_service_status_perm(res, s, s->inf->priv.file.mode);
print_service_status_uid(res, s, s->inf->priv.file.uid);
print_service_status_gid(res, s, s->inf->priv.file.gid);
print_service_status_timestamp(res, s, s->inf->priv.file.timestamp);
print_service_status_file_size(res, s);
print_service_status_file_content(res, s);
print_service_status_file_checksum(res, s);
break;
case Service_Process:
print_service_status_process_pid(res, s);
print_service_status_process_ppid(res, s);
print_service_status_uid(res, s, s->inf->priv.process.uid);
print_service_status_process_euid(res, s);
print_service_status_gid(res, s, s->inf->priv.process.gid);
print_service_status_process_uptime(res, s);
print_service_status_process_threads(res, s);
print_service_status_process_children(res, s);
print_service_status_process_cpu(res, s);
print_service_status_process_cputotal(res, s);
print_service_status_process_memory(res, s);
print_service_status_process_memorytotal(res, s);
print_service_status_port(res, s);
print_service_status_socket(res, s);
break;
case Service_Host:
print_service_status_icmp(res, s);
print_service_status_port(res, s);
break;
case Service_System:
print_service_status_system_loadavg(res, s);
print_service_status_system_cpu(res, s);
print_service_status_system_memory(res, s);
print_service_status_system_swap(res, s);
break;
case Service_Fifo:
print_service_status_perm(res, s, s->inf->priv.fifo.mode);
print_service_status_uid(res, s, s->inf->priv.fifo.uid);
print_service_status_gid(res, s, s->inf->priv.fifo.gid);
print_service_status_timestamp(res, s, s->inf->priv.fifo.timestamp);
break;
case Service_Program:
print_service_status_program_started(res, s);
print_service_status_program_status(res, s);
print_service_status_program_output(res, s);
break;
case Service_Net:
print_service_status_link(res, s);
print_service_status_download(res, s);
print_service_status_upload(res, s);
break;
default:
break;
}
StringBuffer_append(res->outputbuffer, "Data collected | %s |
", Time_string(s->collected.tv_sec, buf));
// Rules
print_service_rules_timeout(res, s);
print_service_rules_existence(res, s);
print_service_rules_icmp(res, s);
print_service_rules_port(res, s);
print_service_rules_socket(res, s);
print_service_rules_perm(res, s);
print_service_rules_uid(res, s);
print_service_rules_euid(res, s);
print_service_rules_gid(res, s);
print_service_rules_timestamp(res, s);
print_service_rules_fsflags(res, s);
print_service_rules_filesystem(res, s);
print_service_rules_size(res, s);
print_service_rules_linkstatus(res, s);
print_service_rules_linkspeed(res, s);
print_service_rules_linksaturation(res, s);
print_service_rules_uploadbytes(res, s);
print_service_rules_uploadpackets(res, s);
print_service_rules_downloadbytes(res, s);
print_service_rules_downloadpackets(res, s);
print_service_rules_uptime(res, s);
print_service_rules_content(res, s);
print_service_rules_checksum(res, s);
print_service_rules_pid(res, s);
print_service_rules_ppid(res, s);
print_service_rules_program(res, s);
print_service_rules_resource(res, s);
print_alerts(res, s->maillist);
StringBuffer_append(res->outputbuffer, "
");
print_buttons(req, res, s);
do_foot(res);
}
static void do_home_system(HttpRequest req, HttpResponse res) {
Service_T s = Run.system;
char buf[STRLEN];
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_process(HttpRequest req, HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Process)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_program(HttpRequest req, HttpResponse res) {
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Program)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_net(HttpRequest req, HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Net)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_filesystem(HttpRequest req, HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Filesystem)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_file(HttpRequest req, HttpResponse res) {
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_File)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_fifo(HttpRequest req, HttpResponse res) {
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Fifo)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_directory(HttpRequest req, HttpResponse res) {
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Directory)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
static void do_home_host(HttpRequest req, HttpResponse res) {
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Host)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"");
}
/* ------------------------------------------------------------------------- */
static void print_alerts(HttpResponse res, Mail_T s) {
for (Mail_T r = s; r; r = r->next) {
StringBuffer_append(res->outputbuffer,
"Alert mail to | "
"%s |
", r->to ? r->to : "");
StringBuffer_append(res->outputbuffer, "Alert on | ");
if (r->events == Event_Null) {
StringBuffer_append(res->outputbuffer, "No events");
} else if (r->events == Event_All) {
StringBuffer_append(res->outputbuffer, "All events");
} else {
if (IS_EVENT_SET(r->events, Event_Action))
StringBuffer_append(res->outputbuffer, "Action ");
if (IS_EVENT_SET(r->events, Event_ByteIn))
StringBuffer_append(res->outputbuffer, "ByteIn ");
if (IS_EVENT_SET(r->events, Event_ByteOut))
StringBuffer_append(res->outputbuffer, "ByteOut ");
if (IS_EVENT_SET(r->events, Event_Checksum))
StringBuffer_append(res->outputbuffer, "Checksum ");
if (IS_EVENT_SET(r->events, Event_Connection))
StringBuffer_append(res->outputbuffer, "Connection ");
if (IS_EVENT_SET(r->events, Event_Content))
StringBuffer_append(res->outputbuffer, "Content ");
if (IS_EVENT_SET(r->events, Event_Data))
StringBuffer_append(res->outputbuffer, "Data ");
if (IS_EVENT_SET(r->events, Event_Exec))
StringBuffer_append(res->outputbuffer, "Exec ");
if (IS_EVENT_SET(r->events, Event_Fsflag))
StringBuffer_append(res->outputbuffer, "Fsflags ");
if (IS_EVENT_SET(r->events, Event_Gid))
StringBuffer_append(res->outputbuffer, "Gid ");
if (IS_EVENT_SET(r->events, Event_Instance))
StringBuffer_append(res->outputbuffer, "Instance ");
if (IS_EVENT_SET(r->events, Event_Invalid))
StringBuffer_append(res->outputbuffer, "Invalid ");
if (IS_EVENT_SET(r->events, Event_Link))
StringBuffer_append(res->outputbuffer, "Link ");
if (IS_EVENT_SET(r->events, Event_Nonexist))
StringBuffer_append(res->outputbuffer, "Nonexist ");
if (IS_EVENT_SET(r->events, Event_Permission))
StringBuffer_append(res->outputbuffer, "Permission ");
if (IS_EVENT_SET(r->events, Event_PacketIn))
StringBuffer_append(res->outputbuffer, "PacketIn ");
if (IS_EVENT_SET(r->events, Event_PacketOut))
StringBuffer_append(res->outputbuffer, "PacketOut ");
if (IS_EVENT_SET(r->events, Event_Pid))
StringBuffer_append(res->outputbuffer, "PID ");
if (IS_EVENT_SET(r->events, Event_Icmp))
StringBuffer_append(res->outputbuffer, "Ping ");
if (IS_EVENT_SET(r->events, Event_PPid))
StringBuffer_append(res->outputbuffer, "PPID ");
if (IS_EVENT_SET(r->events, Event_Resource))
StringBuffer_append(res->outputbuffer, "Resource ");
if (IS_EVENT_SET(r->events, Event_Saturation))
StringBuffer_append(res->outputbuffer, "Saturation ");
if (IS_EVENT_SET(r->events, Event_Size))
StringBuffer_append(res->outputbuffer, "Size ");
if (IS_EVENT_SET(r->events, Event_Speed))
StringBuffer_append(res->outputbuffer, "Speed ");
if (IS_EVENT_SET(r->events, Event_Status))
StringBuffer_append(res->outputbuffer, "Status ");
if (IS_EVENT_SET(r->events, Event_Timeout))
StringBuffer_append(res->outputbuffer, "Timeout ");
if (IS_EVENT_SET(r->events, Event_Timestamp))
StringBuffer_append(res->outputbuffer, "Timestamp ");
if (IS_EVENT_SET(r->events, Event_Uid))
StringBuffer_append(res->outputbuffer, "Uid ");
if (IS_EVENT_SET(r->events, Event_Uptime))
StringBuffer_append(res->outputbuffer, "Uptime ");
}
StringBuffer_append(res->outputbuffer, " |
");
if (r->reminder) {
StringBuffer_append(res->outputbuffer,
"Alert reminder | %u cycles |
",
r->reminder);
}
}
}
static void print_buttons(HttpRequest req, HttpResponse res, Service_T s) {
if (is_readonly(req)) {
// A read-only REMOTE_USER does not get access to these buttons
return;
}
StringBuffer_append(res->outputbuffer, "",
s->name,
s->monitor ? "unmonitor" : "monitor",
s->monitor ? "Disable monitoring" : "Enable monitoring");
}
static void print_service_rules_timeout(HttpResponse res, Service_T s) {
for (ActionRate_T ar = s->actionratelist; ar; ar = ar->next) {
StringBuffer_append(res->outputbuffer, "Timeout | If restarted %d times within %d cycle(s) then ", ar->count, ar->cycle);
Util_printAction(ar->action->failed, res->outputbuffer);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_existence(HttpResponse res, Service_T s) {
for (Nonexist_T l = s->nonexistlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "Existence | ");
Util_printRule(res->outputbuffer, l->action, "If doesn't exist");
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_port(HttpResponse res, Service_T s) {
for (Port_T p = s->portlist; p; p = p->next) {
StringBuffer_append(res->outputbuffer, "Port | ");
StringBuffer_T buf = StringBuffer_create(64);
StringBuffer_append(buf, "If failed [%s]:%d%s",
p->hostname, p->target.net.port, Util_portRequestDescription(p));
if (p->outgoing.ip)
StringBuffer_append(buf, " via address %s", p->outgoing.ip);
StringBuffer_append(buf, " type %s/%s protocol %s with timeout %s",
Util_portTypeDescription(p), Util_portIpDescription(p), p->protocol->name, Str_milliToTime(p->timeout, (char[23]){}));
if (p->retry > 1)
StringBuffer_append(buf, " and retry %d times", p->retry);
#ifdef HAVE_OPENSSL
if (p->target.net.ssl.use_ssl) {
StringBuffer_append(buf, " using SSL/TLS");
const char *options = Ssl_printOptions(&p->target.net.ssl, (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(buf, " with options {%s}", options);
if (p->target.net.ssl.minimumValidDays > 0)
StringBuffer_append(buf, " and certificate expires in more than %d days", p->target.net.ssl.minimumValidDays);
if (p->target.net.ssl.checksum)
StringBuffer_append(buf, " and certificate checksum %s equal to '%s'", checksumnames[p->target.net.ssl.checksumType], p->target.net.ssl.checksum);
}
#endif
Util_printRule(res->outputbuffer, p->action, "%s", StringBuffer_toString(buf));
StringBuffer_free(&buf);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_socket(HttpResponse res, Service_T s) {
for (Port_T p = s->socketlist; p; p = p->next) {
StringBuffer_append(res->outputbuffer, "Unix Socket | ");
if (p->retry > 1)
Util_printRule(res->outputbuffer, p->action, "If failed %s type %s protocol %s with timeout %s and retry %d time(s)", p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name, Str_milliToTime(p->timeout, (char[23]){}), p->retry);
else
Util_printRule(res->outputbuffer, p->action, "If failed %s type %s protocol %s with timeout %s", p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name, Str_milliToTime(p->timeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_icmp(HttpResponse res, Service_T s) {
for (Icmp_T i = s->icmplist; i; i = i->next) {
switch (i->family) {
case Socket_Ip4:
StringBuffer_append(res->outputbuffer, "Ping4 | ");
break;
case Socket_Ip6:
StringBuffer_append(res->outputbuffer, " |
Ping6 | ");
break;
default:
StringBuffer_append(res->outputbuffer, " |
Ping | ");
break;
}
Util_printRule(res->outputbuffer, i->action, "If failed [count %d size %d with timeout %s%s%s]", i->count, i->size, Str_milliToTime(i->timeout, (char[23]){}), i->outgoing.ip ? " via address " : "", i->outgoing.ip ? i->outgoing.ip : "");
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_perm(HttpResponse res, Service_T s) {
if (s->perm) {
StringBuffer_append(res->outputbuffer, "Permissions | ");
if (s->perm->test_changes)
Util_printRule(res->outputbuffer, s->perm->action, "If changed");
else
Util_printRule(res->outputbuffer, s->perm->action, "If failed %o", s->perm->perm);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_uid(HttpResponse res, Service_T s) {
if (s->uid) {
StringBuffer_append(res->outputbuffer, "UID | ");
Util_printRule(res->outputbuffer, s->uid->action, "If failed %d", s->uid->uid);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_euid(HttpResponse res, Service_T s) {
if (s->euid) {
StringBuffer_append(res->outputbuffer, "EUID | ");
Util_printRule(res->outputbuffer, s->euid->action, "If failed %d", s->euid->uid);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_gid(HttpResponse res, Service_T s) {
if (s->gid) {
StringBuffer_append(res->outputbuffer, "GID | ");
Util_printRule(res->outputbuffer, s->gid->action, "If failed %d", s->gid->gid);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_timestamp(HttpResponse res, Service_T s) {
for (Timestamp_T t = s->timestamplist; t; t = t->next) {
StringBuffer_append(res->outputbuffer, "Timestamp | ");
if (t->test_changes)
Util_printRule(res->outputbuffer, t->action, "If changed");
else
Util_printRule(res->outputbuffer, t->action, "If %s %d second(s)", operatornames[t->operator], t->time);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_fsflags(HttpResponse res, Service_T s) {
for (Fsflag_T l = s->fsflaglist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "Filesystem flags | ");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_filesystem(HttpResponse res, Service_T s) {
for (Filesystem_T dl = s->filesystemlist; dl; dl = dl->next) {
if (dl->resource == Resource_Inode) {
StringBuffer_append(res->outputbuffer, "Inodes usage limit | ");
if (dl->limit_absolute > -1)
Util_printRule(res->outputbuffer, dl->action, "If %s %lld", operatornames[dl->operator], dl->limit_absolute);
else
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
StringBuffer_append(res->outputbuffer, " |
");
} else if (dl->resource == Resource_InodeFree) {
StringBuffer_append(res->outputbuffer, "Inodes free limit | ");
if (dl->limit_absolute > -1)
Util_printRule(res->outputbuffer, dl->action, "If %s %lld", operatornames[dl->operator], dl->limit_absolute);
else
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
StringBuffer_append(res->outputbuffer, " |
");
} else if (dl->resource == Resource_Space) {
StringBuffer_append(res->outputbuffer, "Space usage limit | ");
if (dl->limit_absolute > -1) {
if (s->inf->priv.filesystem.f_bsize > 0)
Util_printRule(res->outputbuffer, dl->action, "If %s %s", operatornames[dl->operator], Str_bytesToSize(dl->limit_absolute * s->inf->priv.filesystem.f_bsize, (char[10]){}));
else
Util_printRule(res->outputbuffer, dl->action, "If %s %lld blocks", operatornames[dl->operator], dl->limit_absolute);
} else {
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
}
StringBuffer_append(res->outputbuffer, " |
");
} else if (dl->resource == Resource_SpaceFree) {
StringBuffer_append(res->outputbuffer, "Space free limit | ");
if (dl->limit_absolute > -1) {
if (s->inf->priv.filesystem.f_bsize > 0)
Util_printRule(res->outputbuffer, dl->action, "If %s %s", operatornames[dl->operator], Str_bytesToSize(dl->limit_absolute * s->inf->priv.filesystem.f_bsize, (char[10]){}));
else
Util_printRule(res->outputbuffer, dl->action, "If %s %lld blocks", operatornames[dl->operator], dl->limit_absolute);
} else {
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
}
StringBuffer_append(res->outputbuffer, " |
");
}
}
}
static void print_service_rules_size(HttpResponse res, Service_T s) {
for (Size_T sl = s->sizelist; sl; sl = sl->next) {
StringBuffer_append(res->outputbuffer, "Size | ");
if (sl->test_changes)
Util_printRule(res->outputbuffer, sl->action, "If changed");
else
Util_printRule(res->outputbuffer, sl->action, "If %s %llu byte(s)", operatornames[sl->operator], sl->size);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_linkstatus(HttpResponse res, Service_T s) {
for (LinkStatus_T l = s->linkstatuslist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "Link status | ");
Util_printRule(res->outputbuffer, l->action, "If failed");
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_linkspeed(HttpResponse res, Service_T s) {
for (LinkSpeed_T l = s->linkspeedlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "Link capacity | ");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_linksaturation(HttpResponse res, Service_T s) {
for (LinkSaturation_T l = s->linksaturationlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "Link saturation | ");
Util_printRule(res->outputbuffer, l->action, "If %s %.1f%%", operatornames[l->operator], l->limit);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_uploadbytes(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->uploadbyteslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "Upload bytes | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %s/s", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}));
} else {
StringBuffer_append(res->outputbuffer, " |
Total upload bytes | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %s in last %d %s(s)", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}), bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_uploadpackets(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->uploadpacketslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "Upload packets | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets/s", operatornames[bl->operator], bl->limit);
} else {
StringBuffer_append(res->outputbuffer, " |
Total upload packets | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets in last %d %s(s)", operatornames[bl->operator], bl->limit, bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_downloadbytes(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->downloadbyteslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "Download bytes | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %s/s", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}));
} else {
StringBuffer_append(res->outputbuffer, " |
Total download bytes | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %s in last %d %s(s)", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}), bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_downloadpackets(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->downloadpacketslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "Download packets | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets/s", operatornames[bl->operator], bl->limit);
} else {
StringBuffer_append(res->outputbuffer, " |
Total download packets | ");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets in last %d %s(s)", operatornames[bl->operator], bl->limit, bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_uptime(HttpResponse res, Service_T s) {
for (Uptime_T ul = s->uptimelist; ul; ul = ul->next) {
StringBuffer_append(res->outputbuffer, "Uptime | ");
Util_printRule(res->outputbuffer, ul->action, "If %s %llu second(s)", operatornames[ul->operator], ul->uptime);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_content(HttpResponse res, Service_T s) {
if (s->type != Service_Process) {
for (Match_T ml = s->matchignorelist; ml; ml = ml->next) {
StringBuffer_append(res->outputbuffer, "Ignore content | ");
Util_printRule(res->outputbuffer, ml->action, "If content %s \"%s\"", ml->not ? "!=" : "=", ml->match_string);
StringBuffer_append(res->outputbuffer, " |
");
}
for (Match_T ml = s->matchlist; ml; ml = ml->next) {
StringBuffer_append(res->outputbuffer, "Content match | ");
Util_printRule(res->outputbuffer, ml->action, "If content %s \"%s\"", ml->not ? "!=" : "=", ml->match_string);
StringBuffer_append(res->outputbuffer, " |
");
}
}
}
static void print_service_rules_checksum(HttpResponse res, Service_T s) {
if (s->checksum) {
StringBuffer_append(res->outputbuffer, "Checksum | ");
if (s->checksum->test_changes)
Util_printRule(res->outputbuffer, s->checksum->action, "If changed %s", checksumnames[s->checksum->type]);
else
Util_printRule(res->outputbuffer, s->checksum->action, "If failed %s(%s)", s->checksum->hash, checksumnames[s->checksum->type]);
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_pid(HttpResponse res, Service_T s) {
for (Pid_T l = s->pidlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "PID | ");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_ppid(HttpResponse res, Service_T s) {
for (Pid_T l = s->ppidlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "PPID | ");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_rules_program(HttpResponse res, Service_T s) {
if (s->type == Service_Program) {
StringBuffer_append(res->outputbuffer, "Program timeout | Terminate the program if not finished within %d seconds |
", s->program->timeout);
for (Status_T status = s->statuslist; status; status = status->next) {
StringBuffer_append(res->outputbuffer, "Test Exit value | ");
if (status->operator == Operator_Changed)
Util_printRule(res->outputbuffer, status->action, "If exit value changed");
else
Util_printRule(res->outputbuffer, status->action, "If exit value %s %d", operatorshortnames[status->operator], status->return_value);
StringBuffer_append(res->outputbuffer, " |
");
}
}
}
static void print_service_rules_resource(HttpResponse res, Service_T s) {
char buf[STRLEN];
for (Resource_T q = s->resourcelist; q; q = q->next) {
StringBuffer_append(res->outputbuffer, "");
switch (q->resource_id) {
case Resource_CpuPercent:
StringBuffer_append(res->outputbuffer, "CPU usage limit");
break;
case Resource_CpuPercentTotal:
StringBuffer_append(res->outputbuffer, "CPU usage limit (incl. children)");
break;
case Resource_CpuUser:
StringBuffer_append(res->outputbuffer, "CPU user limit");
break;
case Resource_CpuSystem:
StringBuffer_append(res->outputbuffer, "CPU system limit");
break;
case Resource_CpuWait:
StringBuffer_append(res->outputbuffer, "CPU wait limit");
break;
case Resource_MemoryPercent:
StringBuffer_append(res->outputbuffer, "Memory usage limit");
break;
case Resource_MemoryKbyte:
StringBuffer_append(res->outputbuffer, "Memory amount limit");
break;
case Resource_SwapPercent:
StringBuffer_append(res->outputbuffer, "Swap usage limit");
break;
case Resource_SwapKbyte:
StringBuffer_append(res->outputbuffer, "Swap amount limit");
break;
case Resource_LoadAverage1m:
StringBuffer_append(res->outputbuffer, "Load average (1min)");
break;
case Resource_LoadAverage5m:
StringBuffer_append(res->outputbuffer, "Load average (5min)");
break;
case Resource_LoadAverage15m:
StringBuffer_append(res->outputbuffer, "Load average (15min)");
break;
case Resource_Threads:
StringBuffer_append(res->outputbuffer, "Threads");
break;
case Resource_Children:
StringBuffer_append(res->outputbuffer, "Children");
break;
case Resource_MemoryKbyteTotal:
StringBuffer_append(res->outputbuffer, "Memory amount limit (incl. children)");
break;
case Resource_MemoryPercentTotal:
StringBuffer_append(res->outputbuffer, "Memory usage limit (incl. children)");
break;
default:
break;
}
StringBuffer_append(res->outputbuffer, " | ");
switch (q->resource_id) {
case Resource_CpuPercent:
case Resource_CpuPercentTotal:
case Resource_MemoryPercentTotal:
case Resource_CpuUser:
case Resource_CpuSystem:
case Resource_CpuWait:
case Resource_MemoryPercent:
case Resource_SwapPercent:
Util_printRule(res->outputbuffer, q->action, "If %s %.1f%%", operatornames[q->operator], q->limit);
break;
case Resource_MemoryKbyte:
case Resource_SwapKbyte:
case Resource_MemoryKbyteTotal:
Util_printRule(res->outputbuffer, q->action, "If %s %s", operatornames[q->operator], Str_bytesToSize(q->limit, buf));
break;
case Resource_LoadAverage1m:
case Resource_LoadAverage5m:
case Resource_LoadAverage15m:
Util_printRule(res->outputbuffer, q->action, "If %s %.1f", operatornames[q->operator], q->limit);
break;
case Resource_Threads:
case Resource_Children:
Util_printRule(res->outputbuffer, q->action, "If %s %.0f", operatornames[q->operator], q->limit);
break;
default:
break;
}
StringBuffer_append(res->outputbuffer, " |
");
}
}
static void print_service_status_port(HttpResponse res, Service_T s) {
int status = Util_hasServiceStatus(s);
for (Port_T p = s->portlist; p; p = p->next) {
StringBuffer_append(res->outputbuffer, "Port Response time | ");
if (! status || p->is_available == Connection_Init)
StringBuffer_append(res->outputbuffer, "- | ");
else if (p->is_available == Connection_Failed)
StringBuffer_append(res->outputbuffer, " | failed to [%s]:%d%s type %s/%s %sprotocol %s | ", p->hostname, p->target.net.port, Util_portRequestDescription(p), Util_portTypeDescription(p), Util_portIpDescription(p), p->target.net.ssl.use_ssl ? "using SSL/TLS " : "", p->protocol->name);
else
StringBuffer_append(res->outputbuffer, "%s to %s:%d%s type %s/%s %s protocol %s | ", Str_milliToTime(p->response, (char[23]){}), p->hostname, p->target.net.port, Util_portRequestDescription(p), Util_portTypeDescription(p), Util_portIpDescription(p), p->target.net.ssl.use_ssl ? "using SSL/TLS " : "", p->protocol->name);
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_socket(HttpResponse res, Service_T s) {
int status = Util_hasServiceStatus(s);
for (Port_T p = s->socketlist; p; p = p->next) {
StringBuffer_append(res->outputbuffer, "Unix Socket Response time | ");
if (! status || p->is_available == Connection_Init)
StringBuffer_append(res->outputbuffer, "- | ");
else if (p->is_available == Connection_Failed)
StringBuffer_append(res->outputbuffer, " | failed to %s type %s protocol %s | ", p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name);
else
StringBuffer_append(res->outputbuffer, "%s to %s type %s protocol %s | ", Str_milliToTime(p->response, (char[23]){}), p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name);
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_icmp(HttpResponse res, Service_T s) {
int status = Util_hasServiceStatus(s);
for (Icmp_T i = s->icmplist; i; i = i->next) {
StringBuffer_append(res->outputbuffer, "Ping Response time | ");
if (! status || i->is_available == Connection_Init)
StringBuffer_append(res->outputbuffer, "- | ");
else if (i->is_available == Connection_Failed)
StringBuffer_append(res->outputbuffer, "connection failed | ");
else if (i->response < 0.)
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s | ", Str_milliToTime(i->response, (char[23]){}));
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_perm(HttpResponse res, Service_T s, int mode) {
StringBuffer_append(res->outputbuffer, "Permission | ");
if (! Util_hasServiceStatus(s) || mode < 0)
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%o | ", (s->error & Event_Permission) ? "red-text" : "", mode & 07777);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_uid(HttpResponse res, Service_T s, int uid) {
StringBuffer_append(res->outputbuffer, "UID | ");
if (! Util_hasServiceStatus(s) || uid < 0)
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%d | ", (s->error & Event_Uid) ? "red-text" : "", (int)uid);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_gid(HttpResponse res, Service_T s, int gid) {
StringBuffer_append(res->outputbuffer, "GID | ");
if (! Util_hasServiceStatus(s) || gid < 0)
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%d | ", (s->error & Event_Gid) ? "red-text" : "", (int)gid);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_link(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Link capacity | ");
if (! Util_hasServiceStatus(s) || Link_getState(s->inf->priv.net.stats) != 1) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
long long speed = Link_getSpeed(s->inf->priv.net.stats);
if (speed > 0)
StringBuffer_append(res->outputbuffer, "%.0lf Mb/s %s-duplex | ", s->error & Event_Speed ? "red-text" : "", (double)speed / 1000000., Link_getDuplex(s->inf->priv.net.stats) == 1 ? "full" : "half");
else
StringBuffer_append(res->outputbuffer, "N/A for this link type | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_download(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Download | ");
if (! Util_hasServiceStatus(s) || Link_getState(s->inf->priv.net.stats) != 1) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
long long speed = Link_getSpeed(s->inf->priv.net.stats);
long long ibytes = Link_getBytesInPerSecond(s->inf->priv.net.stats);
StringBuffer_append(res->outputbuffer, "%s/s [%lld packets/s] [%lld errors]",
(s->error & Event_ByteIn || s->error & Event_PacketIn) ? "red-text" : "",
Str_bytesToSize(ibytes, (char[10]){}),
Link_getPacketsInPerSecond(s->inf->priv.net.stats),
Link_getErrorsInPerSecond(s->inf->priv.net.stats));
if (speed > 0 && ibytes > 0)
StringBuffer_append(res->outputbuffer, " (%.1f%% link saturation)", 100. * ibytes * 8 / (double)speed);
StringBuffer_append(res->outputbuffer, " | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_upload(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Upload | ");
if (! Util_hasServiceStatus(s) || Link_getState(s->inf->priv.net.stats) != 1) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
long long speed = Link_getSpeed(s->inf->priv.net.stats);
long long obytes = Link_getBytesOutPerSecond(s->inf->priv.net.stats);
StringBuffer_append(res->outputbuffer, "%s/s [%lld packets/s] [%lld errors]",
(s->error & Event_ByteOut || s->error & Event_PacketOut) ? "red-text" : "",
Str_bytesToSize(obytes, (char[10]){}),
Link_getPacketsOutPerSecond(s->inf->priv.net.stats),
Link_getErrorsOutPerSecond(s->inf->priv.net.stats));
if (speed > 0 && obytes > 0)
StringBuffer_append(res->outputbuffer, " (%.1f%% link saturation)", 100. * obytes * 8 / (double)speed);
StringBuffer_append(res->outputbuffer, " | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_timestamp(HttpResponse res, Service_T s, time_t timestamp) {
StringBuffer_append(res->outputbuffer, "Timestamp | ");
if (! Util_hasServiceStatus(s) || timestamp == 0)
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s | ", (s->error & Event_Timestamp) ? "red-text" : "", Time_string(timestamp, (char[32]){}));
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_filesystem_flags(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Filesystem flags | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "0x%x | ", s->inf->priv.filesystem.flags);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_filesystem_blockstotal(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Space total | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s (of which %.1f%% is reserved for root user) | ",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocks * s->inf->priv.filesystem.f_bsize, (char[10]){}) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)(s->inf->priv.filesystem.f_blocksfreetotal - s->inf->priv.filesystem.f_blocksfree) / (float)s->inf->priv.filesystem.f_blocks) : 0);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_filesystem_blocksfree(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Space free for non superuser | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s [%.1f%%] | ",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocksfree * s->inf->priv.filesystem.f_bsize, (char[10]){}) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)s->inf->priv.filesystem.f_blocksfree / (float)s->inf->priv.filesystem.f_blocks) : 0);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_filesystem_blocksfreetotal(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Space free total | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer,
"%s [%.1f%%] | ", (s->error & Event_Resource) ? "red-text" : "",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocksfreetotal * s->inf->priv.filesystem.f_bsize, (char[10]){}) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)s->inf->priv.filesystem.f_blocksfreetotal / (float)s->inf->priv.filesystem.f_blocks) : 0);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_filesystem_blocksize(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Block size | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s | ", Str_bytesToSize(s->inf->priv.filesystem.f_bsize, (char[10]){}));
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_filesystem_inodestotal(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Inodes total | ");
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
if (s->inf->priv.filesystem.f_files > 0)
StringBuffer_append(res->outputbuffer, "%lld | ", s->inf->priv.filesystem.f_files);
else
StringBuffer_append(res->outputbuffer, "- | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_filesystem_inodesfree(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Inodes free | ");
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
if (s->inf->priv.filesystem.f_files > 0)
StringBuffer_append(res->outputbuffer, "%lld [%.1f%%] | ", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.filesystem.f_filesfree, (float)100 * (float)s->inf->priv.filesystem.f_filesfree / (float)s->inf->priv.filesystem.f_files);
else
StringBuffer_append(res->outputbuffer, "- | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_file_size(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Size | ");
if (! Util_hasServiceStatus(s) || s->inf->priv.file.size < 0)
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s | ", (s->error & Event_Size) ? "red-text" : "", Str_bytesToSize(s->inf->priv.file.size, (char[10]){}));
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_file_content(HttpResponse res, Service_T s) {
if (s->matchlist) {
StringBuffer_append(res->outputbuffer, "Content matches pattern(s) | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s | ", (s->error & Event_Content) ? "red-text" : "", (s->error & Event_Content) ? "yes" : "no");
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_file_checksum(HttpResponse res, Service_T s) {
if (s->checksum) {
StringBuffer_append(res->outputbuffer, "Checksum | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s(%s) | ", (s->error & Event_Checksum) ? "red-text" : "", s->inf->priv.file.cs_sum, checksumnames[s->checksum->type]);
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_process_pid(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Process id | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%d | ", s->inf->priv.process.pid > 0 ? s->inf->priv.process.pid : 0);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_process_ppid(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Parent process id | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%d | ", s->inf->priv.process.ppid > 0 ? s->inf->priv.process.ppid : 0);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_process_euid(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Effective UID | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%d | ", s->inf->priv.process.euid);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_process_uptime(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Process uptime | ");
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
char *uptime = Util_getUptime(s->inf->priv.process.uptime, " ");
StringBuffer_append(res->outputbuffer, "%s | ", uptime);
FREE(uptime);
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_process_threads(HttpResponse res, Service_T s) {
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer, "Threads | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%d | ", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.process.threads);
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_process_children(HttpResponse res, Service_T s) {
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer, "Children | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%d | ", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.process.children);
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_process_cpu(HttpResponse res, Service_T s) {
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer, "CPU usage | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%.1f%% (Usage / Number of CPUs) | ", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.process.cpu_percent);
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_process_cputotal(HttpResponse res, Service_T s) {
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer, "Total CPU usage (incl. children) | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%.1f%% | ", (s->error & Event_Resource) ? "red-text" :"", s->inf->priv.process.total_cpu_percent);
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_process_memory(HttpResponse res, Service_T s) {
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer, "Memory usage | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%.1f%% [%s] | ", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.process.mem_percent, Str_bytesToSize(s->inf->priv.process.mem, (char[10]){}));
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_process_memorytotal(HttpResponse res, Service_T s) {
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer, "Total memory usage (incl. children) | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%.1f%% [%s] | ", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.process.total_mem_percent, Str_bytesToSize(s->inf->priv.process.total_mem, (char[10]){}));
StringBuffer_append(res->outputbuffer, "
");
}
}
static void print_service_status_system_loadavg(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Load average | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "[%.2f] [%.2f] [%.2f] | ", (s->error & Event_Resource) ? "red-text" : "", systeminfo.loadavg[0], systeminfo.loadavg[1], systeminfo.loadavg[2]);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_system_cpu(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "CPU usage | ");
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
StringBuffer_append(res->outputbuffer,
"%.1f%%us %.1f%%sy"
#ifdef HAVE_CPU_WAIT
" %.1f%%wa"
#endif
"%s",
(s->error & Event_Resource) ? "red-text" : "",
systeminfo.total_cpu_user_percent > 0. ? systeminfo.total_cpu_user_percent : 0.,
systeminfo.total_cpu_syst_percent > 0. ? systeminfo.total_cpu_syst_percent : 0.,
#ifdef HAVE_CPU_WAIT
systeminfo.total_cpu_wait_percent > 0. ? systeminfo.total_cpu_wait_percent : 0.,
#endif
" | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_system_memory(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Memory usage | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s [%.1f%%] | ", (s->error & Event_Resource) ? "red-text" : "", Str_bytesToSize(systeminfo.total_mem, (char[10]){}), systeminfo.total_mem_percent);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_system_swap(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Swap usage | ");
if (! Util_hasServiceStatus(s))
StringBuffer_append(res->outputbuffer, "- | ");
else
StringBuffer_append(res->outputbuffer, "%s [%.1f%%] | ", (s->error & Event_Resource) ? "red-text" : "", Str_bytesToSize(systeminfo.total_swap, (char[10]){}), systeminfo.total_swap_percent);
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_program_started(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Last started | ");
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
if (s->program->started)
StringBuffer_append(res->outputbuffer, "%s | ", Time_string(s->program->started, (char[32]){}));
else
StringBuffer_append(res->outputbuffer, "Not yet started | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_program_status(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Last exit value | ");
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
if (s->program->started)
StringBuffer_append(res->outputbuffer, "%d | ", s->program->exitStatus);
else
StringBuffer_append(res->outputbuffer, "- | ");
}
StringBuffer_append(res->outputbuffer, "
");
}
static void print_service_status_program_output(HttpResponse res, Service_T s) {
StringBuffer_append(res->outputbuffer, "Last output | ");
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "- | ");
} else {
if (s->program->started) {
StringBuffer_append(res->outputbuffer, "");
if (StringBuffer_length(s->program->output)) {
// If the output contains multiple line, wrap use , otherwise keep as is
int multiline = StringBuffer_lastIndexOf(s->program->output, "\n") > 0;
if (multiline)
StringBuffer_append(res->outputbuffer, "");
escapeHTML(res->outputbuffer, StringBuffer_toString(s->program->output));
if (multiline)
StringBuffer_append(res->outputbuffer, " ");
} else {
StringBuffer_append(res->outputbuffer, "no output");
}
StringBuffer_append(res->outputbuffer, " | ");
} else {
StringBuffer_append(res->outputbuffer, "- | ");
}
}
StringBuffer_append(res->outputbuffer, "
");
}
static boolean_t is_readonly(HttpRequest req) {
if (req->remote_user) {
Auth_T user_creds = Util_getUserCredentials(req->remote_user);
return (user_creds ? user_creds->is_readonly : true);
}
return false;
}
/* ----------------------------------------------------------- Status output */
/* Print status in the given format. Text status is default. */
static void print_status(HttpRequest req, HttpResponse res, int version) {
Level_Type level = Level_Full;
const char *stringFormat = get_parameter(req, "format");
const char *stringLevel = get_parameter(req, "level");
const char *stringGroup = Util_urlDecode((char *)get_parameter(req, "group"));
const char *stringService = Util_urlDecode((char *)get_parameter(req, "service"));
if (stringLevel && Str_startsWith(stringLevel, LEVEL_NAME_SUMMARY))
level = Level_Summary;
if (stringFormat && Str_startsWith(stringFormat, "xml")) {
char buf[STRLEN];
StringBuffer_T sb = StringBuffer_create(256);
status_xml(sb, NULL, level, version, Socket_getLocalHost(req->S, buf, sizeof(buf)));
StringBuffer_append(res->outputbuffer, "%s", StringBuffer_toString(sb));
StringBuffer_free(&sb);
set_content_type(res, "text/xml");
} else {
set_content_type(res, "text/plain");
char *uptime = Util_getUptime(getProcessUptime(getpid(), ptree, ptreesize), " ");
StringBuffer_append(res->outputbuffer, "The Monit daemon %s uptime: %s\n\n", VERSION, uptime);
FREE(uptime);
int found = 0;
if (stringGroup) {
for (ServiceGroup_T sg = servicegrouplist; sg; sg = sg->next) {
if (IS(stringGroup, sg->name)) {
for (list_t m = sg->members->head; m; m = m->next) {
status_service_txt(m->e, res, level);
found++;
}
break;
}
}
} else {
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (! stringService || IS(stringService, s->name)) {
status_service_txt(s, res, level);
found++;
}
}
}
if (found == 0) {
if (stringGroup)
send_error(req, res, SC_BAD_REQUEST, "Service group '%s' not found", stringGroup);
else if (stringService)
send_error(req, res, SC_BAD_REQUEST, "Service '%s' not found", stringService);
else
send_error(req, res, SC_BAD_REQUEST, "No service found");
}
}
}
static void status_service_txt(Service_T s, HttpResponse res, Level_Type level) {
char buf[STRLEN];
if (level == Level_Summary) {
char prefix[STRLEN];
snprintf(prefix, STRLEN, "%s '%s'", servicetypes[s->type], s->name);
StringBuffer_append(res->outputbuffer, "%-35s %s\n", prefix, get_service_status(s, buf, sizeof(buf)));
} else {
StringBuffer_append(res->outputbuffer,
"%s '%s'\n"
" %-33s %s\n",
servicetypes[s->type], s->name,
"status", get_service_status(s, buf, sizeof(buf)));
StringBuffer_append(res->outputbuffer,
" %-33s %s\n",
"monitoring status", get_monitoring_status(s, buf, sizeof(buf)));
char *uptime = NULL;
if (Util_hasServiceStatus(s)) {
switch (s->type) {
case Service_File:
if (s->inf->priv.file.mode >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %o\n", "permission", s->inf->priv.file.mode & 07777);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "permission");
if (s->inf->priv.file.uid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "uid", (int)s->inf->priv.file.uid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "uid");
if (s->inf->priv.file.gid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "gid", (int)s->inf->priv.file.gid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "gid");
if (s->inf->priv.file.gid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %s\n", "size", Str_bytesToSize(s->inf->priv.file.size, buf));
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "size");
if (s->inf->priv.file.timestamp > 0)
StringBuffer_append(res->outputbuffer, " %-33s %s\n", "timestamp", Time_string(s->inf->priv.file.timestamp, buf));
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "timestamp");
if (s->checksum) {
if (*s->inf->priv.file.cs_sum)
StringBuffer_append(res->outputbuffer, " %-33s %s (%s)\n", "checksum", s->inf->priv.file.cs_sum, checksumnames[s->checksum->type]);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "checksum");
}
break;
case Service_Directory:
if (s->inf->priv.directory.mode >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %o\n", "permission", s->inf->priv.directory.mode & 07777);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "permission");
if (s->inf->priv.directory.uid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "uid", (int)s->inf->priv.directory.uid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "uid");
if (s->inf->priv.directory.gid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "gid", (int)s->inf->priv.directory.gid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "gid");
if (s->inf->priv.directory.timestamp > 0)
StringBuffer_append(res->outputbuffer, " %-33s %s\n", "timestamp", Time_string(s->inf->priv.directory.timestamp, buf));
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "timestamp");
break;
case Service_Fifo:
if (s->inf->priv.fifo.mode >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %o\n", "permission", s->inf->priv.fifo.mode & 07777);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "permission");
if (s->inf->priv.fifo.uid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "uid", (int)s->inf->priv.fifo.uid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "uid");
if (s->inf->priv.fifo.gid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "gid", (int)s->inf->priv.fifo.gid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "gid");
if (s->inf->priv.fifo.timestamp > 0)
StringBuffer_append(res->outputbuffer, " %-33s %s\n", "timestamp", Time_string(s->inf->priv.fifo.timestamp, buf));
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "timestamp");
break;
case Service_Net:
if (Link_getState(s->inf->priv.net.stats) == 1) {
long long speed = Link_getSpeed(s->inf->priv.net.stats);
if (speed > 0)
StringBuffer_append(res->outputbuffer,
" %-33s %.0lf Mb/s %s-duplex\n",
"link capacity", (double)speed / 1000000., Link_getDuplex(s->inf->priv.net.stats) == 1 ? "full" : "half");
else
StringBuffer_append(res->outputbuffer,
" %-33s N/A for this link type\n",
"link capacity");
long long ibytes = Link_getBytesInPerSecond(s->inf->priv.net.stats);
StringBuffer_append(res->outputbuffer, " %-33s %s/s [%lld packets/s] [%lld errors]",
"download",
Str_bytesToSize(ibytes, buf),
Link_getPacketsInPerSecond(s->inf->priv.net.stats),
Link_getErrorsInPerSecond(s->inf->priv.net.stats));
if (speed > 0 && ibytes > 0)
StringBuffer_append(res->outputbuffer, " (%.1f%% link saturation)", 100. * ibytes * 8 / (double)speed);
StringBuffer_append(res->outputbuffer, "\n");
long long obytes = Link_getBytesOutPerSecond(s->inf->priv.net.stats);
StringBuffer_append(res->outputbuffer, " %-33s %s/s [%lld packets/s] [%lld errors]",
"upload",
Str_bytesToSize(obytes, buf),
Link_getPacketsOutPerSecond(s->inf->priv.net.stats),
Link_getErrorsOutPerSecond(s->inf->priv.net.stats));
if (speed > 0 && obytes > 0)
StringBuffer_append(res->outputbuffer, " (%.1f%% link saturation)", 100. * obytes * 8 / (double)speed);
StringBuffer_append(res->outputbuffer, "\n");
}
break;
case Service_Filesystem:
if (s->inf->priv.filesystem.mode >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %o\n", "permission", s->inf->priv.filesystem.mode & 07777);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "permission");
if (s->inf->priv.filesystem.uid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "uid", (int)s->inf->priv.filesystem.uid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "uid");
if (s->inf->priv.filesystem.gid >= 0)
StringBuffer_append(res->outputbuffer, " %-33s %d\n", "gid", (int)s->inf->priv.filesystem.gid);
else
StringBuffer_append(res->outputbuffer, " %-33s -\n", "gid");
StringBuffer_append(res->outputbuffer,
" %-33s 0x%x\n"
" %-33s %s\n",
"filesystem flags",
s->inf->priv.filesystem.flags,
"block size",
Str_bytesToSize(s->inf->priv.filesystem.f_bsize, buf));
StringBuffer_append(res->outputbuffer,
" %-33s %s (of which %.1f%% is reserved for root user)\n",
"space total",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize((long long)(s->inf->priv.filesystem.f_blocks * s->inf->priv.filesystem.f_bsize), buf) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)(s->inf->priv.filesystem.f_blocksfreetotal - s->inf->priv.filesystem.f_blocksfree) / (float)s->inf->priv.filesystem.f_blocks) : 0);
StringBuffer_append(res->outputbuffer,
" %-33s %s [%.1f%%]\n",
"space free for non superuser",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocksfree * s->inf->priv.filesystem.f_bsize, buf) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)s->inf->priv.filesystem.f_blocksfree / (float)s->inf->priv.filesystem.f_blocks) : 0);
StringBuffer_append(res->outputbuffer,
" %-33s %s [%.1f%%]\n",
"space free total",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocksfreetotal * s->inf->priv.filesystem.f_bsize, buf) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)s->inf->priv.filesystem.f_blocksfreetotal / (float)s->inf->priv.filesystem.f_blocks) : 0);
if (s->inf->priv.filesystem.f_files > 0) {
StringBuffer_append(res->outputbuffer,
" %-33s %lld\n"
" %-33s %lld [%.1f%%]\n",
"inodes total",
s->inf->priv.filesystem.f_files,
"inodes free",
s->inf->priv.filesystem.f_filesfree,
((float)100*(float)s->inf->priv.filesystem.f_filesfree/ (float)s->inf->priv.filesystem.f_files));
}
break;
case Service_Process:
uptime = Util_getUptime(s->inf->priv.process.uptime, " ");
StringBuffer_append(res->outputbuffer,
" %-33s %d\n"
" %-33s %d\n"
" %-33s %d\n"
" %-33s %d\n"
" %-33s %d\n"
" %-33s %s\n",
"pid", s->inf->priv.process.pid > 0 ? s->inf->priv.process.pid : 0,
"parent pid", s->inf->priv.process.ppid > 0 ? s->inf->priv.process.ppid : 0,
"uid", s->inf->priv.process.uid,
"effective uid", s->inf->priv.process.euid,
"gid", s->inf->priv.process.gid,
"uptime", uptime);
FREE(uptime);
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer,
" %-33s %d\n",
"threads", s->inf->priv.process.threads);
StringBuffer_append(res->outputbuffer,
" %-33s %d\n",
"children", s->inf->priv.process.children);
StringBuffer_append(res->outputbuffer,
" %-33s %s\n",
"memory", Str_bytesToSize(s->inf->priv.process.mem, buf));
StringBuffer_append(res->outputbuffer,
" %-33s %s\n",
"memory total", Str_bytesToSize(s->inf->priv.process.total_mem, buf));
StringBuffer_append(res->outputbuffer,
" %-33s %.1f%%\n"
" %-33s %.1f%%\n"
" %-33s %.1f%%\n"
" %-33s %.1f%%\n",
"memory percent", s->inf->priv.process.mem_percent,
"memory percent total", s->inf->priv.process.total_mem_percent,
"cpu percent", s->inf->priv.process.cpu_percent,
"cpu percent total", s->inf->priv.process.total_cpu_percent);
}
break;
default:
break;
}
for (Icmp_T i = s->icmplist; i; i = i->next) {
if (i->is_available == Connection_Failed)
StringBuffer_append(res->outputbuffer,
" %-33s connection failed\n",
"ping response time");
else if (i->is_available == Connection_Init)
StringBuffer_append(res->outputbuffer,
" %-33s -\n",
"ping response time");
else
StringBuffer_append(res->outputbuffer,
" %-33s %s\n",
"ping response time", Str_milliToTime(i->response, (char[23]){}));
}
for (Port_T p = s->portlist; p; p = p->next) {
if (p->is_available == Connection_Failed)
StringBuffer_append(res->outputbuffer,
" %-33s FAILED to [%s]:%d%s type %s/%s %sprotocol %s\n",
"port response time", p->hostname, p->target.net.port, Util_portRequestDescription(p), Util_portTypeDescription(p), Util_portIpDescription(p), p->target.net.ssl.use_ssl ? "using SSL/TLS " : "", p->protocol->name);
else if (p->is_available == Connection_Init)
StringBuffer_append(res->outputbuffer,
" %-33s -\n",
"port response time");
else
StringBuffer_append(res->outputbuffer,
" %-33s %s to [%s]:%d%s type %s/%s %sprotocol %s\n",
"port response time", Str_milliToTime(p->response, (char[23]){}), p->hostname, p->target.net.port, Util_portRequestDescription(p), Util_portTypeDescription(p), Util_portIpDescription(p), p->target.net.ssl.use_ssl ? "using SSL/TLS " : "", p->protocol->name);
}
for (Port_T p = s->socketlist; p; p = p->next) {
if (p->is_available == Connection_Failed)
StringBuffer_append(res->outputbuffer,
" %-33s FAILED to %s type %s protocol %s\n",
"unix socket response time", p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name);
else if (p->is_available == Connection_Init)
StringBuffer_append(res->outputbuffer,
" %-33s -\n",
"unix socket response time");
else
StringBuffer_append(res->outputbuffer,
" %-33s %s to %s type %s protocol %s\n",
"unix socket response time", Str_milliToTime(p->response, (char[23]){}), p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name);
}
if (s->type == Service_System && (Run.flags & Run_ProcessEngineEnabled)) {
StringBuffer_append(res->outputbuffer,
" %-33s [%.2f] [%.2f] [%.2f]\n"
" %-33s %.1f%%us %.1f%%sy"
#ifdef HAVE_CPU_WAIT
" %.1f%%wa"
#endif
"\n",
"load average", systeminfo.loadavg[0], systeminfo.loadavg[1], systeminfo.loadavg[2],
"cpu", systeminfo.total_cpu_user_percent > 0. ? systeminfo.total_cpu_user_percent : 0., systeminfo.total_cpu_syst_percent > 0. ? systeminfo.total_cpu_syst_percent : 0.
#ifdef HAVE_CPU_WAIT
, systeminfo.total_cpu_wait_percent > 0. ? systeminfo.total_cpu_wait_percent : 0.
#endif
);
StringBuffer_append(res->outputbuffer,
" %-33s %s [%.1f%%]\n",
"memory usage", Str_bytesToSize(systeminfo.total_mem, buf), systeminfo.total_mem_percent);
StringBuffer_append(res->outputbuffer,
" %-33s %s [%.1f%%]\n",
"swap usage", Str_bytesToSize(systeminfo.total_swap, buf), systeminfo.total_swap_percent);
}
if (s->type == Service_Program) {
if (s->program->started) {
StringBuffer_append(res->outputbuffer,
" %-33s %s\n"
" %-33s %d\n",
"last started", Time_string(s->program->started, (char[32]){}),
"last exit value", s->program->exitStatus);
if (StringBuffer_length(s->program->output)) {
const char *output = StringBuffer_toString(s->program->output);
StringBuffer_append(res->outputbuffer,
" %-33s ", "last output");
for (int i = 0; output[i]; i++) {
if (output[i] == '\r') {
// Discard CR
continue;
} else if (output[i] == '\n') {
// Indent 2nd+ line
if (output[i + 1])
StringBuffer_append(res->outputbuffer, "\n ");
continue;
} else {
StringBuffer_append(res->outputbuffer, "%c", output[i]);
}
}
StringBuffer_append(res->outputbuffer,
"\n");
}
} else
StringBuffer_append(res->outputbuffer,
" %-33s\n",
"not yet started");
}
}
StringBuffer_append(res->outputbuffer, " %-33s %s\n\n", "data collected", Time_string(s->collected.tv_sec, buf));
}
}
static char *get_monitoring_status(Service_T s, char *buf, int buflen) {
ASSERT(s);
ASSERT(buf);
if (s->monitor == Monitor_Not)
snprintf(buf, buflen, "Not monitored");
else if (s->monitor & Monitor_Waiting)
snprintf(buf, buflen, "Waiting");
else if (s->monitor & Monitor_Init)
snprintf(buf, buflen, "Initializing");
else if (s->monitor & Monitor_Yes)
snprintf(buf, buflen, "Monitored");
return buf;
}
static char *get_service_status(Service_T s, char *buf, int buflen) {
EventTable_T *et = Event_Table;
ASSERT(s);
ASSERT(buf);
if (s->monitor == Monitor_Not || s->monitor & Monitor_Init) {
get_monitoring_status(s, buf, buflen);
} else if (s->error == 0) {
snprintf(buf, buflen, "%s", statusnames[s->type]);
} else {
// In the case that the service has actualy some failure, error will be non zero. We will check the bitmap and print the description of the first error found
while ((*et).id) {
if (s->error & (*et).id) {
snprintf(buf, buflen, "%s", (s->error_hint & (*et).id) ? (*et).description_changed : (*et).description_failed);
break;
}
et++;
}
}
if (s->doaction)
snprintf(buf + strlen(buf), buflen - strlen(buf) - 1, " - %s pending", actionnames[s->doaction]);
return buf;
}
monit-5.16/src/http/cervlet.h 0000644 0001751 0001751 00000020307 12654603627 013116 0000000 0000000 /*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License
* along with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#ifndef CERVLET_H
#define CERVLET_H
#include "config.h"
#include "monit.h"
void init_service();
#define FAVICON_ICO "AAABAAIAEBAAAAAAIABoBAAAJgAAACAgAAAAACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAMAAAADAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAADAAAABMAAAAXAAAAFwAAABMAAAAMAAAABQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAAFAAAACgAAAA3AAAAPwAAAD8AAAA3AAAAKAAAABQAAAAFAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAEwAAAC8AjlOHALVkxBzVe+4r3H/uALdoxACOU4cAAAAvAAAAEwAAAAQAAAAAAAAAAAAAAAAAAAABAAAACwAAACUAhUqfAMV6/0j0t/90/9j/hP/f/1b3vv8AyH3/AIdLnwAAACUAAAALAAAAAQAAAAAAAAAAAAAAAgAAABAAbC94AKNY/wDllP8A6Z3/GvCw/yX0t/8A66X/AOaV/wCjWP8AbC94AAAAEAAAAAIAAAAAAAAAAAAAAAIAAAASAGslugCsSv8A1Xr/ANqF/wDbi/8A3ZD/AN+S/wDWfv8Aq0j/AGslugAAABIAAAACAAAAAAAAAAAAAAACAAAAEABmHuoAqzv/Esdp/xTNdv8Uz33/FNKB/xTSgP8Sx2r/AKs7/wBmHuoAAAAQAAAAAgAAAAAAAAAAAAAAAgAAAAsAXxbpDq1N/yC8Yf81xXT/Ncl5/zXJev81xXT/ILxe/w6tTf8AXxbpAAAACwAAAAIAAAAAAAAAAAAAAAEAAAAGAFYQsSOcUP9hzYj/etid/2TPjP9kz4z/etid/2HNiP8jnFD/AFYQsQAAAAYAAAABAAAAAAAAAAAAAAAAAAAAAgBaC2ABcyT/cMyM/67pwf/Q+N3/0Pjd/67pwf9wzIz/AXMk/wBaC2AAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAE4CggJuIP9ns33/iM6a/4jOmv9ns33/Am4g/wBOAoIAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAUgBdAEkArABFAOcARQDnAEkArABSAF0AAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAPgfAADwDwAA8A8AAOAHAADgBwAA4AcAAOAHAADwDwAA8A8AAPw/AAD//wAA//8AAP//AAAoAAAAIAAAAEAAAAABACAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAIAAAACAAAAAwAAAAMAAAACAAAAAgAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACAAAAAcAAAAGAAAABQAAAAQAAAADAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAwAAAAUAAAAHAAAACgAAAA0AAAAPAAAAEQAAABIAAAASAAAAEQAAAA8AAAANAAAACgAAAAcAAAAFAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAHAAAACwAAABAAAAAVAAAAGQAAAB0AAAAfAAAAIQAAACEAAAAfAAAAHQAAABkAAAAVAAAAEAAAAAsAAAAHAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAADAAAABwAAAA0AAAAUAAAAHAAAACQAAAAqAAAALwAAADMAAAA1AAAANQAAADMAAAAvAAAAKgAAACQAAAAcAAAAFAAAAA0AAAAHAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAwAAAAYAAAANAAAAFgAcDiQAQiY2AFAvRgBcNFMDZzleCnJAZxF3RWsVekVrEXRDZwVqPF4AXzRTAFAvRgBCJjYAHA4kAAAAFgAAAA0AAAAGAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAADAAAABUAAAAiAD4jOgBzQl0AjFB8AJ5YlAatYqkTvWy6HcZywiPJc8IewnC6C7JlqQCgW5QAjFB8AHNCXQA+IzoAAAAiAAAAFQAAAAwAAAAGAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABAAAAAoAAAATACMOJAA+IT4Abj9hAJZZjwasabERv3bIHc6E2yzZjus24ZTzPuOX8zjfk+sk0ojbFMJ8yAevbLEAl1uPAG4/YQA+IT4AIw4kAAAAEwAAAAoAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAHAAAADwAAABoAQyQ5AG88agCRVJsAsWvKDseB5Svcmu1D6q3zVfK6+WP2xPtr98f7ZPTB+U/ts/M035/tEsuE5QCzbsoAklabAHE+agBDJDkAAAAaAAAADwAAAAcAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAkAIQsXADIWLgBkNFkAhkiYAKJeyQDBdu0N1o3/KOml/0D0uP9T+cf/YfzQ/2j81P9h+87/S/a//zDrq/8Q2ZD/AMR47QClX8kAiEqYAGQ0WQAyFi4AIQsXAAAACQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAACwBCHSMAWydOAHs8hACWUMYAr2TtAM+A+QThk/8N6J7/Ge6p/ynytf8z9bz/Ofa//zP1vP8f8bH/EOuk/wXjlv8A0IL5AK9l7QCWUMYAezyEAFsnTgBCHSMAAAALAAAABQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAUAAAAMAE4cLgBnKWoAgTqmAJtO4gC0Y/8A0n//AOKQ/wDllf8E55v/Duqj/xXsqf8Z7qz/FO2q/wbqpP8A55z/AOSU/wDTgP8AtGP/AJtO4gCBOqYAZylqAE4cLgAAAAwAAAAFAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAABQAAAA0ATxw3AGclgwCAM78AnUXqALZa/wDNdP8A24P/AN2I/wHfjf8E4JL/B+GW/wjimP8G45n/AuOY/wDgkv8A3Ij/AM52/wC1Wv8AnUTqAIAzvwBnJYMATxw3AAAADQAAAAUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAADQBSGT4AZiGZAHwt1QCdPvEBtVL/A8hq/wTTef8E1n7/BdeD/wXYhv8F2Yn/BdqL/wXbjf8F3I3/BNqI/wTVfv8DyWz/AbVS/wCdPfEAfCzVAGYhmQBSGT4AAAANAAAABQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAUAAAAMAFIWRABkHqsAeSjnAJw49wOzSv8Kw2H/Dcxw/w7Pd/8P0Xv/D9J//w/Tgv8P1IT/D9WF/w/Vhf8O03//Dc50/wrDY/8Ds0r/AJw39wB5KOcAZB6rAFIWRAAAAAwAAAAFAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAABQAAAAsAVRZFAGIbswB3Je8Cmzf6CLJJ/xG+Xf8Xxmv/Gspy/xzMd/8czXr/HM59/xzPfv8c0H//HM9+/xrMd/8Xx2z/Eb5d/wiySf8Cmzf6AHcl7wBiG7MAVRZFAAAACwAAAAUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAEAAAACQBUE0MAXheyAnUk7webPfoPsU//GLpc/yDBZ/8oxXD/LMh2/yzKef8sy3r/LMt7/yzLe/8syXj/KMZx/yDBZv8Yulv/D7FO/webPfoCdSTvAF4XsgBUE0MAAAAJAAAABAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAHAFIQPgBbFKcEciTkDphA9hqvVf8pu2P/NcNw/0DIef9Fyn7/Qst+/0DLfv9Ay37/Qst+/0XKfv9AyHn/NcNu/ym7Yv8ar1T/DphA9gRyJOQAWxSnAFIQPgAAAAcAAAADAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAUATQ41AFgQkQlvJM8XkkLvKqtb/0S/cv9XzIP/Y9GO/2TSkP9cz4r/WM6H/1jOh/9cz4r/ZNKQ/2PRjf9XzIP/RL9y/yqrW/8XkkLvCW8kzwBYEJEATQ41AAAABQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAwBNDCsAVg13CGsitRWHO+ctoVb/Ur54/23RkP9+2Z//hdyl/4Haov9/2qD/f9qg/4Haov+F3KX/ftmf/23RkP9Svnj/LaFW/xWHO+cIayK1AFYNdwBNDCsAAAADAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAFIIHwBXDFgDZxuXCHgp3SKRRv9TuXT/edOW/5Tfrf+m57z/sOzF/7Xuyf+17sn/sOzF/6bnvP+U363/edOW/1O5dP8ikUb/CHgp3QNnG5cAVwxYAFIIHwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAUQATAFoJNgBkFW4Aax26F4A16EGkXfhmvoH/itKg/6Xgt/+26cX/vu7N/77uzf+26cX/peC3/4rSoP9mvoH/QaRd+BeANegAax26AGQVbgBaCTYAUQATAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVAAYAUQATAFsNOwBcDn8Kah65GH4y6DSUUP9isnn/gceV/5LTpP+a2av/mtmr/5LTpP+Bx5X/YrJ5/zSUUP8YfjLoCmoeuQBcDn8AWw07AFEAEwBVAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEARwAZAE0ASQBaDH8BZxm6F3gv3ECSVOZZpGruY6py9miudvlornb5Y6py9lmkau5AklTmF3gv3AFnGboAWgx/AE0ASQBHABkAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgARwAZAFgJOgBeDmwKZBaUG2gksiJrKcwkaijiJWop7SVqKe0kaijiImspzBtoJLIKZBaUAF4ObABYCToARwAZAEAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARwASAE4ANABPAFQASgByAEcAjABFAKIARQCtAEUArQBFAKIARwCMAEoAcgBPAFQATgA0AEcAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqAAYASwARAEkAHABKACYASAAuAEIANgBDADkAQwA5AEIANgBIAC4ASgAmAEkAHABLABEAKgAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/////////////////////////////////wD///wAP//4AB//8AAP/+AAB//gAAf/wAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD/+AAB//gAAf/8AAP//gAH//8AD///gB///+B//////////////////////////////////"
#endif
monit-5.16/src/http/engine.h 0000644 0001751 0001751 00000004000 12654603627 012707 0000000 0000000 /*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License
* along with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#ifndef ENGINE_H
#define ENGINE_H
/**
* Start the HTTPD server
*/
void Engine_start();
/**
* Stop the HTTPD server.
*/
void Engine_stop();
/**
* Cleanup the HTTPD server resources (remove unix socket).
*/
void Engine_cleanup();
/**
* Add hosts allowed to connect to this server.
* @param pattern A hostname (A-Record) or IP address to be added to the hosts allow list
* @return false if the given host does not resolve, otherwise true
*/
boolean_t Engine_addHostAllow(char *pattern);
/**
* Add network allowed to connect to this server.
* @param pattern A network identifier in IP/mask format to be added
* to the hosts allow list
* @return false if no correct network identifier is provided,
* otherwise true
*/
boolean_t Engine_addNetAllow(char *pattern);
/**
* Are any hosts present in the host allow list?
* @return true if the host allow list is non-empty, otherwise false
*/
boolean_t Engine_hasHostsAllow();
/**
* Free the host allow list
*/
void Engine_destroyHostsAllow();
#endif
monit-5.16/src/http/engine.c 0000644 0001751 0001751 00000035546 12654603627 012725 0000000 0000000 /*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License
* along with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include
#endif
#ifdef HAVE_STDLIB_H
#include
#endif
#ifdef HAVE_ERRNO_H
#include
#endif
#ifdef HAVE_SYS_TYPES_H
#include
#endif
#ifdef HAVE_SYS_SOCKET_H
#include
#endif
#ifdef HAVE_NETDB_H
#include
#endif
#ifdef HAVE_UNISTD_H
#include
#endif
#ifdef HAVE_FCNTL_H
#include
#endif
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_CTYPE_H
#include
#endif
#ifdef HAVE_STRINGS_H
#include
#endif
#ifdef HAVE_SYS_UN_H
#include
#endif
#ifdef HAVE_NETINET_IN_H
#include
#endif
#ifdef HAVE_ARPA_INET_H
#include
#endif
#include "monit.h"
#include "engine.h"
#include "net.h"
#include "processor.h"
#include "cervlet.h"
#include "socket.h"
#include "SslServer.h"
// libmonit
#include "system/Net.h"
#include "exceptions/AssertException.h"
/**
* A naive http 1.0 server. The server delegates handling of a HTTP
* request and response to the processor module.
*
* NOTE
* This server does not use threads or forks; Requests are
* serialized and pending requests will be popped from the
* connection queue when the current request finish.
*
* Since this server is written for monit, low traffic is expected.
* Connect from not-authenicated clients will be closed down
* promptly. The authentication schema or access control is based
* on client name/address/pam and only requests from known clients are
* accepted. Hosts allowed to connect to this server should be
* added to the access control list by calling Engine_addHostAllow().
*
* @file
*/
/* ------------------------------------------------------------- Definitions */
typedef struct HostsAllow_T {
unsigned long network;
unsigned long mask;
/* For internal use */
struct HostsAllow_T *next;
} *HostsAllow_T;
static volatile boolean_t stopped = false;
static int myServerSocket = 0;
#ifdef HAVE_OPENSSL
SslServer_T mySSLServerConnection = NULL;
#endif
static HostsAllow_T hostlist = NULL;
static Mutex_T mutex = PTHREAD_MUTEX_INITIALIZER;
/* ----------------------------------------------------------------- Private */
/**
* Parse network string and return numeric IP and netmask
* @param pattern A network identifier in IP/mask format to be parsed
* @param net A structure holding IP and mask of the network
* @return false if parsing fails otherwise true
*/
static boolean_t _parseNetwork(char *pattern, HostsAllow_T net) {
ASSERT(pattern);
ASSERT(net);
char *longmask = NULL;
int shortmask = 0;
int slashcount = 0;
int dotcount = 0;
int count = 0;
char buf[STRLEN];
snprintf(buf, STRLEN, "%s", pattern);
char *temp = buf;
/* decide if we have xxx.xxx.xxx.xxx/yyy or xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy */
while (*temp) {
if (*temp == '/') {
/* We have found a "/" -> we are preceeding to the netmask */
if ((slashcount == 1) || (dotcount != 3))
/* We have already found a "/" or we haven't had enough dots before finding the slash -> Error! */
return false;
*temp = 0;
longmask = *(temp + 1) ? temp + 1 : NULL;
count = 0;
slashcount = 1;
dotcount = 0;
} else if (*temp == '.') {
/* We have found the next dot! */
dotcount++;
} else if (! isdigit((int)*temp)) {
/* No number, "." or "/" -> Error! */
return false;
}
count++;
temp++;
}
if (slashcount == 0) {
/* We have just host portion */
shortmask = 32;
} else if ((dotcount == 0) && (count > 1) && (count < 4)) {
/* We have no dots but 1 or 2 numbers after the slash -> short netmask */
if (longmask != NULL) {
shortmask = atoi(longmask);
longmask = NULL;
}
} else if (dotcount != 3) {
/* A long netmask requires three dots */
return false;
}
/* Parse the network */
struct in_addr inp;
if (! inet_aton(buf, &inp))
return false;
net->network = inp.s_addr;
/* Convert short netmasks to integer */
if (longmask == NULL) {
if ((shortmask > 32) || (shortmask < 0)) {
return false;
} else if ( shortmask == 32 ) {
net->mask = -1;
} else {
net->mask = (1 << shortmask) - 1;
net->mask = htonl(net->mask << (32 - shortmask));
}
} else {
/* Parse long netmasks */
if (! inet_aton(longmask, &inp))
return false;
net->mask = inp.s_addr;
}
/* Remove bogus network components */
net->network &= net->mask;
return true;
}
static boolean_t _hasHostAllow(HostsAllow_T host) {
for (HostsAllow_T p = hostlist; p; p = p->next)
if ((p->network == host->network) && ((p->mask == host->mask)))
return true;
return false;
}
static void _destroyHostAllow(HostsAllow_T p) {
HostsAllow_T a = p;
if (a->next)
_destroyHostAllow(a->next);
FREE(a);
}
/**
* Returns true if remote host is allowed to connect, otherwise return false
*/
static boolean_t _authenticateHost(struct sockaddr *addr) {
if (addr->sa_family == AF_INET) { //FIXME: we support only IPv4 currently
boolean_t allow = false;
struct sockaddr_in *a = (struct sockaddr_in *)addr;
LOCK(mutex)
{
if (! hostlist) {
allow = true;
} else {
for (HostsAllow_T p = hostlist; p; p = p->next) {
if ((p->network & p->mask) == (a->sin_addr.s_addr & p->mask)) {
allow = true;
break;
}
}
}
}
END_LOCK;
if (! allow)
LogError("Denied connection from non-authorized client [%s]\n", inet_ntoa(a->sin_addr));
return allow;
} else if (addr->sa_family == AF_UNIX) {
return true;
} else {
return false;
}
}
/**
* Accept connections from Clients and create a Socket_T object for each successful accept. If accept fails, return a NULL object
*/
static Socket_T _socketProducer(int server, Httpd_Flags flags) {
int client;
struct sockaddr_storage addr_in;
struct sockaddr_un addr_un;
struct sockaddr *addr = NULL;
socklen_t addrlen;
if (Net_canRead(server, 1000)) {
if (flags & Httpd_Net) {
addr = (struct sockaddr *)&addr_in;
addrlen = sizeof(struct sockaddr_storage);
} else {
addr = (struct sockaddr *)&addr_un;
addrlen = sizeof(struct sockaddr_un);
}
if ((client = accept(server, addr, &addrlen)) < 0) {
LogError("HTTP server: cannot accept connection -- %s\n", stopped ? "service stopped" : STRERROR);
return NULL;
}
if (Net_setNonBlocking(client) < 0 || ! Net_canRead(client, 500) || ! Net_canWrite(client, 500) || ! _authenticateHost(addr)) {
Net_abort(client);
return NULL;
}
#ifdef HAVE_OPENSSL
return Socket_createAccepted(client, addr, addrlen, mySSLServerConnection);
#else
return Socket_createAccepted(client, addr, addrlen, NULL);
#endif
}
return NULL;
}
/* ------------------------------------------------------------------ Public */
void Engine_start() {
Engine_cleanup();
stopped = Run.flags & Run_Stopped;
init_service();
//FIXME: we listen currently only on one server socket: either on IP or unix socket ... should support listening on multiple sockets (IPv4, IPv6, unix)
if (Run.httpd.flags & Httpd_Net) {
if ((myServerSocket = create_server_socket(Run.httpd.socket.net.address, Run.httpd.socket.net.port, 1024)) >= 0) {
#ifdef HAVE_OPENSSL
if (Run.httpd.flags & Httpd_Ssl) {
if (! (mySSLServerConnection = SslServer_new(Run.httpd.socket.net.ssl.pem, Run.httpd.socket.net.ssl.clientpem, myServerSocket))) {
LogError("HTTP server: not available -- could not initialize SSL engine\n");
Net_close(myServerSocket);
return;
}
}
#endif
while (! stopped) {
Socket_T S = _socketProducer(myServerSocket, Run.httpd.flags);
if (S)
http_processor(S);
}
#ifdef HAVE_OPENSSL
if (Run.httpd.flags & Httpd_Ssl)
SslServer_free(&mySSLServerConnection);
#endif
Net_close(myServerSocket);
} else {
LogError("HTTP server: not available -- could not create a server socket at port %d -- %s\n", Run.httpd.socket.net.port, STRERROR);
}
} else if (Run.httpd.flags & Httpd_Unix) {
if ((myServerSocket = create_server_socket_unix(Run.httpd.socket.unix.path, 1024)) >= 0) {
while (! stopped) {
Socket_T S = _socketProducer(myServerSocket, Run.httpd.flags);
if (S)
http_processor(S);
}
Net_close(myServerSocket);
} else {
LogError("HTTP server: not available -- could not create a server socket at %s -- %s\n", Run.httpd.socket.unix.path, STRERROR);
}
}
Engine_cleanup();
}
void Engine_stop() {
stopped = true;
}
void Engine_cleanup() {
if (Run.httpd.flags & Httpd_Unix)
unlink(Run.httpd.socket.unix.path);
}
//FIXME: don't store the translated hostname->IPaddress on Monit startup to support DHCP hosts ... resolve the hostname in _authenticateHost()
boolean_t Engine_addHostAllow(char *pattern) {
ASSERT(pattern);
struct addrinfo *res, hints = {
.ai_family = AF_INET, /* we support just IPv4 currently */
.ai_protocol = IPPROTO_TCP
};
int added = 0;
if (! getaddrinfo(pattern, NULL, &hints, &res)) {
for (struct addrinfo *_res = res; _res; _res = _res->ai_next) {
if (_res->ai_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)_res->ai_addr;
HostsAllow_T h;
NEW(h);
memcpy(&h->network, &sin->sin_addr, 4);
h->mask = 0xffffffff;
LOCK(mutex)
{
if (_hasHostAllow(h)) {
DEBUG("Skipping redundant host '%s'\n", pattern);
FREE(h);
} else {
DEBUG("Adding host allow '%s'\n", pattern);
h->next = hostlist;
hostlist = h;
added++;
}
}
END_LOCK;
}
}
freeaddrinfo(res);
}
return added ? true : false;
}
boolean_t Engine_addNetAllow(char *pattern) {
ASSERT(pattern);
HostsAllow_T h;
NEW(h);
if (_parseNetwork(pattern, h)) {
int added = 0;
LOCK(mutex)
{
if (_hasHostAllow(h)) {
DEBUG("Skipping redundant net '%s'\n", pattern);
FREE(h);
} else {
DEBUG("Adding net allow '%s'\n", pattern);
h->next = hostlist;
hostlist = h;
added++;
}
}
END_LOCK;
return added ? true : false;
}
FREE(h);
return false;
}
boolean_t Engine_hasHostsAllow() {
int rv;
LOCK(mutex)
{
rv = hostlist ? true : false;
}
END_LOCK;
return rv;
}
void Engine_destroyHostsAllow() {
if (Engine_hasHostsAllow()) {
LOCK(mutex)
{
_destroyHostAllow(hostlist);
hostlist = NULL;
}
END_LOCK;
}
}
monit-5.16/src/http/processor.c 0000644 0001751 0001751 00000067255 12654603627 013501 0000000 0000000 /*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License
* along with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include
#endif
#ifdef HAVE_STDLIB_H
#include
#endif
#ifdef HAVE_ERRNO_H
#include
#endif
#ifdef HAVE_STDARG_H
#include
#endif
#ifdef HAVE_SYS_TYPES_H
#include
#endif
#ifdef HAVE_SYS_SOCKET_H
#include
#endif
#ifdef HAVE_SETJMP_H
#include
#endif
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_STRINGS_H
#include
#endif
#ifdef HAVE_UNISTD_H
#include
#endif
#ifdef HAVE_LIMITS_H
#include
#endif
#include "processor.h"
#include "base64.h"
// libmonit
#include "util/Str.h"
#include "system/Net.h"
/**
* A naive quasi HTTP Processor module that can handle HTTP requests
* received from a client, and return responses based on those
* requests.
*
* This Processor delegates the actual handling of the request and
* reponse to so called cervlets, which must implement two methods;
* doGet and doPost.
*
* NOTES
* This Processor is command oriented and if a second slash '/' is
* found in the URL it's asumed to be the PATHINFO. In other words
* this processor perceive an URL as:
*
* /COMMAND?QUERYSTRING/PATHINFO
*
* The doGet/doPost routines act's on the COMMAND. See the
* cervlet.c code in this dir. for an example.
*
* @file
*/
/* -------------------------------------------------------------- Prototypes */
static void do_service(Socket_T);
static void destroy_entry(void *);
static char *get_date(char *, int);
static char *get_server(char *, int);
static void create_headers(HttpRequest);
static void send_response(HttpResponse);
static boolean_t basic_authenticate(HttpRequest);
static void done(HttpRequest, HttpResponse);
static void destroy_HttpRequest(HttpRequest);
static void reset_response(HttpResponse res);
static HttpParameter parse_parameters(char *);
static boolean_t create_parameters(HttpRequest req);
static void destroy_HttpResponse(HttpResponse);
static HttpRequest create_HttpRequest(Socket_T);
static void internal_error(Socket_T, int, char *);
static HttpResponse create_HttpResponse(Socket_T);
static boolean_t is_authenticated(HttpRequest, HttpResponse);
static int get_next_token(char *s, int *cursor, char **r);
/*
* An object for implementors of the service functions; doGet and
* doPost. Implementing modules i.e. CERVLETS, must implement the
* doGet and doPost functions and the engine will call the add_Impl
* function to setup the callback to these functions.
*/
struct ServiceImpl {
void(*doGet)(HttpRequest, HttpResponse);
void(*doPost)(HttpRequest, HttpResponse);
} Impl;
/* ------------------------------------------------------------------ Public */
/**
* Process a HTTP request. This is done by dispatching to the service
* function.
* @param s A Socket_T representing the client connection
*/
void *http_processor(Socket_T s) {
if (! Net_canRead(Socket_getSocket(s), REQUEST_TIMEOUT * 1000))
internal_error(s, SC_REQUEST_TIMEOUT, "Time out when handling the Request");
else
do_service(s);
Socket_free(&s);
return NULL;
}
/**
* Callback for implementors of cervlet functions.
* @param doGetFunc doGet function
* @param doPostFunc doPost function
*/
void add_Impl(void(*doGet)(HttpRequest, HttpResponse), void(*doPost)(HttpRequest, HttpResponse)) {
Impl.doGet = doGet;
Impl.doPost = doPost;
}
void escapeHTML(StringBuffer_T sb, const char *s) {
for (int i = 0; s[i]; i++) {
if (s[i] == '<')
StringBuffer_append(sb, "<");
else if (s[i] == '>')
StringBuffer_append(sb, ">");
else if (s[i] == '&')
StringBuffer_append(sb, "&");
else
StringBuffer_append(sb, "%c", s[i]);
}
}
/**
* Send an error message
* @param res HttpResponse object
* @param code Error Code to lookup and send
* @param msg Optional error message (may be NULL)
*/
void send_error(HttpRequest req, HttpResponse res, int code, const char *msg, ...) {
ASSERT(msg);
const char *err = get_status_string(code);
reset_response(res);
set_content_type(res, "text/html");
set_status(res, code);
StringBuffer_append(res->outputbuffer,
""
""
"%d %s"
""
""
"%s
",
code, err, err);
char *message;
va_list ap;
va_start(ap, msg);
message = Str_vcat(msg, ap);
va_end(ap);
escapeHTML(res->outputbuffer, message);
if (code != SC_UNAUTHORIZED) // We log details in basic_authenticate() already, no need to log generic error sent to client here
LogError("HttpRequest: error -- client %s: %s %d %s\n", Socket_getRemoteHost(req->S), SERVER_PROTOCOL, code, message);
FREE(message);
char server[STRLEN];
StringBuffer_append(res->outputbuffer,
"
"
"%s"
""
""
"\r\n",
SERVER_URL, get_server(server, STRLEN));
}
/* -------------------------------------------------------------- Properties */
/**
* Adds a response header with the given name and value. If the header
* had already been set the new value overwrites the previous one.
* @param res HttpResponse object
* @param name Header key name
* @param value Header key value
*/
void set_header(HttpResponse res, const char *name, const char *value) {
HttpHeader h = NULL;
ASSERT(res);
ASSERT(name);
NEW(h);
h->name = Str_dup(name);
h->value = Str_dup(value);
if (res->headers) {
HttpHeader n, p;
for (n = p = res->headers; p; n = p, p = p->next) {
if (IS(p->name, name)) {
FREE(p->value);
p->value = Str_dup(value);
destroy_entry(h);
return;
}
}
n->next = h;
} else {
res->headers = h;
}
}
/**
* Sets the status code for the response
* @param res HttpResponse object
* @param code A HTTP status code <100-510>
* @param msg The status code string message
*/
void set_status(HttpResponse res, int code) {
res->status = code;
res->status_msg = get_status_string(code);
}
/**
* Set the response content-type
* @param res HttpResponse object
* @param mime Mime content type, e.g. text/html
*/
void set_content_type(HttpResponse res, const char *mime) {
set_header(res, "Content-Type", mime);
}
/**
* Returns the value of the specified header
* @param req HttpRequest object
* @param name Header name to lookup the value for
* @return The value of the specified header, NULL if not found
*/
const char *get_header(HttpRequest req, const char *name) {
for (HttpHeader p = req->headers; p; p = p->next)
if (IS(p->name, name))
return (p->value);
return NULL;
}
/**
* Returns the value of the specified parameter
* @param req HttpRequest object
* @param name The request parameter key to lookup the value for
* @return The value of the specified parameter, or NULL if not found
*/
const char *get_parameter(HttpRequest req, const char *name) {
for (HttpParameter p = req->params; p; p = p->next)
if (IS(p->name, name))
return (p->value);
return NULL;
}
/**
* Returns a string containing all (extra) headers found in the
* response. The headers are newline separated in the returned
* string.
* @param res HttpResponse object
* @return A String containing all headers set in the Response object
*/
char *get_headers(HttpResponse res) {
char buf[RES_STRLEN];
char *b = buf;
*buf = 0;
for (HttpHeader p = res->headers; (((b - buf) + STRLEN) < RES_STRLEN) && p; p = p->next)
b += snprintf(b, STRLEN,"%s: %s\r\n", p->name, p->value);
return buf[0] ? Str_dup(buf) : NULL;
}
/**
* Lookup the corresponding HTTP status string for the given status
* code
* @param status A HTTP status code
* @return A default status message for the specified HTTP status
* code.
*/
const char *get_status_string(int status) {
switch (status) {
case SC_OK:
return "OK";
case SC_ACCEPTED:
return "Accepted";
case SC_BAD_GATEWAY:
return "Bad Gateway";
case SC_BAD_REQUEST:
return "Bad Request";
case SC_CONFLICT:
return "Conflict";
case SC_CONTINUE:
return "Continue";
case SC_CREATED:
return "Created";
case SC_EXPECTATION_FAILED:
return "Expectation Failed";
case SC_FORBIDDEN:
return "Forbidden";
case SC_GATEWAY_TIMEOUT:
return "Gateway Timeout";
case SC_GONE:
return "Gone";
case SC_VERSION_NOT_SUPPORTED:
return "HTTP Version Not Supported";
case SC_INTERNAL_SERVER_ERROR:
return "Internal Server Error";
case SC_LENGTH_REQUIRED:
return "Length Required";
case SC_METHOD_NOT_ALLOWED:
return "Method Not Allowed";
case SC_MOVED_PERMANENTLY:
return "Moved Permanently";
case SC_MOVED_TEMPORARILY:
return "Moved Temporarily";
case SC_MULTIPLE_CHOICES:
return "Multiple Choices";
case SC_NO_CONTENT:
return "No Content";
case SC_NON_AUTHORITATIVE:
return "Non-Authoritative Information";
case SC_NOT_ACCEPTABLE:
return "Not Acceptable";
case SC_NOT_FOUND:
return "Not Found";
case SC_NOT_IMPLEMENTED:
return "Not Implemented";
case SC_NOT_MODIFIED:
return "Not Modified";
case SC_PARTIAL_CONTENT:
return "Partial Content";
case SC_PAYMENT_REQUIRED:
return "Payment Required";
case SC_PRECONDITION_FAILED:
return "Precondition Failed";
case SC_PROXY_AUTHENTICATION_REQUIRED:
return "Proxy Authentication Required";
case SC_REQUEST_ENTITY_TOO_LARGE:
return "Request Entity Too Large";
case SC_REQUEST_TIMEOUT:
return "Request Timeout";
case SC_REQUEST_URI_TOO_LARGE:
return "Request URI Too Large";
case SC_RANGE_NOT_SATISFIABLE:
return "Requested Range Not Satisfiable";
case SC_RESET_CONTENT:
return "Reset Content";
case SC_SEE_OTHER:
return "See Other";
case SC_SERVICE_UNAVAILABLE:
return "Service Unavailable";
case SC_SWITCHING_PROTOCOLS:
return "Switching Protocols";
case SC_UNAUTHORIZED:
return "Unauthorized";
case SC_UNSUPPORTED_MEDIA_TYPE:
return "Unsupported Media Type";
case SC_USE_PROXY:
return "Use Proxy";
default: {
return "Unknown HTTP status";
}
}
}
/* ----------------------------------------------------------------- Private */
/**
* Receives standard HTTP requests from a client socket and dispatches
* them to the doXXX methods defined in a cervlet module.
*/
static void do_service(Socket_T s) {
volatile HttpResponse res = create_HttpResponse(s);
volatile HttpRequest req = create_HttpRequest(s);
if (res && req) {
if (Run.httpd.flags & Httpd_Ssl)
set_header(res, "Strict-Transport-Security", "max-age=63072000; includeSubdomains; preload");
if (is_authenticated(req, res)) {
if (IS(req->method, METHOD_GET))
Impl.doGet(req, res);
else if (IS(req->method, METHOD_POST))
Impl.doPost(req, res);
else
send_error(req, res, SC_NOT_IMPLEMENTED, "Method not implemented");
}
send_response(res);
}
done(req, res);
}
/**
* Return a (RFC1123) Date string
*/
static char *get_date(char *result, int size) {
time_t now;
time(&now);
if (strftime(result, size, DATEFMT, gmtime(&now)) <= 0)
*result = 0;
return result;
}
/**
* Return this server name + version
*/
static char *get_server(char *result, int size) {
snprintf(result, size, "%s %s", SERVER_NAME, Run.httpd.flags & Httpd_Signature ? SERVER_VERSION : "");
return result;
}
/**
* Send the response to the client. If the response has already been
* commited, this function does nothing.
*/
static void send_response(HttpResponse res) {
Socket_T S = res->S;
if (! res->is_committed) {
char date[STRLEN];
char server[STRLEN];
char *headers = get_headers(res);
int length = StringBuffer_length(res->outputbuffer);
res->is_committed = true;
get_date(date, STRLEN);
get_server(server, STRLEN);
Socket_print(S, "%s %d %s\r\n", res->protocol, res->status,
res->status_msg);
Socket_print(S, "Date: %s\r\n", date);
Socket_print(S, "Server: %s\r\n", server);
Socket_print(S, "Content-Length: %d\r\n", length);
Socket_print(S, "Connection: close\r\n");
if (headers)
Socket_print(S, "%s", headers);
Socket_print(S, "\r\n");
if (length)
Socket_write(S, (unsigned char *)StringBuffer_toString(res->outputbuffer), length);
FREE(headers);
}
}
/* --------------------------------------------------------------- Factories */
/**
* Returns a new HttpRequest object wrapping the client request
*/
static HttpRequest create_HttpRequest(Socket_T S) {
HttpRequest req = NULL;
char url[REQ_STRLEN];
char line[REQ_STRLEN];
char protocol[STRLEN];
char method[REQ_STRLEN];
if (Socket_readLine(S, line, REQ_STRLEN) == NULL) {
internal_error(S, SC_BAD_REQUEST, "No request found");
return NULL;
}
Str_chomp(line);
if (sscanf(line, "%1023s %1023s HTTP/%3[1.0]", method, url, protocol) != 3) {
internal_error(S, SC_BAD_REQUEST, "Cannot parse request");
return NULL;
}
if (strlen(url) >= MAX_URL_LENGTH) {
internal_error(S, SC_BAD_REQUEST, "[error] URL too long");
return NULL;
}
NEW(req);
req->S = S;
Util_urlDecode(url);
req->url = Str_dup(url);
req->method = Str_dup(method);
req->protocol = Str_dup(protocol);
create_headers(req);
if (! create_parameters(req)) {
destroy_HttpRequest(req);
internal_error(S, SC_BAD_REQUEST, "Cannot parse Request parameters");
return NULL;
}
return req;
}
/**
* Returns a new HttpResponse object wrapping a default response. Use
* the set_XXX methods to change the object.
*/
static HttpResponse create_HttpResponse(Socket_T S) {
HttpResponse res = NULL;
NEW(res);
res->S = S;
res->status = SC_OK;
res->outputbuffer = StringBuffer_create(256);
res->is_committed = false;
res->protocol = SERVER_PROTOCOL;
res->status_msg = get_status_string(SC_OK);
return res;
}
/**
* Create HTTP headers for the given request
*/
static void create_headers(HttpRequest req) {
Socket_T S;
char *value;
HttpHeader header = NULL;
char line[REQ_STRLEN];
S = req->S;
while (true) {
if (! Socket_readLine(S, line, sizeof(line)))
break;
if (Str_isEqual(line, "\r\n") || Str_isEqual(line, "\n"))
break;
if (NULL != (value = strchr(line, ':'))) {
NEW(header);
*value++ = 0;
Str_trim(line);
Str_trim(value);
Str_chomp(value);
header->name = Str_dup(line);
header->value = Str_dup(value);
header->next = req->headers;
req->headers = header;
}
}
}
/**
* Create parameters for the given request. Returns false if an error
* occurs.
*/
static boolean_t create_parameters(HttpRequest req) {
char query_string[REQ_STRLEN] = {0};
if (IS(req->method, METHOD_POST) && get_header(req, "Content-Length")) {
int n;
int len;
Socket_T S = req->S;
const char *cl = get_header(req, "Content-Length");
if (! cl || sscanf(cl, "%d", &len) != 1)
return false;
if (len < 0 || len >= REQ_STRLEN)
return false;
if (len == 0)
return true;
if (((n = Socket_read(S, query_string, len)) <= 0) || (n != len))
return false;
query_string[n] = 0;
} else if (IS(req->method, METHOD_GET)) {
char *p;
if (NULL != (p = strchr(req->url, '?'))) {
*p++ = 0;
strncpy(query_string, p, sizeof(query_string) - 1);
query_string[sizeof(query_string) - 1] = 0;
}
}
if (*query_string) {
char *p;
if (NULL != (p = strchr(query_string, '/'))) {
*p++ = 0;
req->pathinfo = Str_dup(p);
}
req->params = parse_parameters(query_string);
}
return true;
}
/* ----------------------------------------------------------------- Cleanup */
/**
* Clear the response output buffer and headers
*/
static void reset_response(HttpResponse res) {
if (res->headers) {
destroy_entry(res->headers);
res->headers = NULL; /* Release Pragma */
}
StringBuffer_clear(res->outputbuffer);
}
/**
* Finalize the request and response object.
*/
static void done(HttpRequest req, HttpResponse res) {
destroy_HttpRequest(req);
destroy_HttpResponse(res);
}
/**
* Free a HttpRequest object
*/
static void destroy_HttpRequest(HttpRequest req) {
if (req) {
FREE(req->method);
FREE(req->url);
FREE(req->pathinfo);
FREE(req->protocol);
FREE(req->remote_user);
if (req->headers)
destroy_entry(req->headers);
if (req->params)
destroy_entry(req->params);
FREE(req);
}
}
/**
* Free a HttpResponse object
*/
static void destroy_HttpResponse(HttpResponse res) {
if (res) {
StringBuffer_free(&(res->outputbuffer));
if (res->headers)
destroy_entry(res->headers);
FREE(res);
}
}
/**
* Free a (linked list of) http entry object(s). Both HttpHeader and
* HttpParameter are of this type.
*/
static void destroy_entry(void *p) {
struct entry *h = p;
if (h->next)
destroy_entry(h->next);
FREE(h->name);
FREE(h->value);
FREE(h);
}
/* ----------------------------------------------------- Checkers/Validators */
/**
* Do Basic Authentication if this auth. style is allowed.
*/
static boolean_t is_authenticated(HttpRequest req, HttpResponse res) {
if (Run.httpd.credentials) {
if (! basic_authenticate(req)) {
// Send just generic error message to the client to not disclose e.g. username existence in case of credentials harvesting attack
send_error(req, res, SC_UNAUTHORIZED, "You are not authorized to access monit. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required");
set_header(res, "WWW-Authenticate", "Basic realm=\"monit\"");
return false;
}
}
return true;
}
/**
* Authenticate the basic-credentials (uname/password) submitted by
* the user.
*/
static boolean_t basic_authenticate(HttpRequest req) {
const char *credentials = get_header(req, "Authorization");
if (! (credentials && Str_startsWith(credentials, "Basic "))) {
LogError("HttpRequest: access denied -- client %s: missing or invalid Authorization header\n", Socket_getRemoteHost(req->S));
return false;
}
char buf[STRLEN] = {0};
strncpy(buf, &credentials[6], sizeof(buf) - 1);
char uname[STRLEN] = {0};
if (decode_base64((unsigned char *)uname, buf) <= 0) {
LogError("HttpRequest: access denied -- client %s: invalid Authorization header\n", Socket_getRemoteHost(req->S));
return false;
}
if (! *uname) {
LogError("HttpRequest: access denied -- client %s: empty username\n", Socket_getRemoteHost(req->S));
return false;
}
char *password = password = strchr(uname, ':');
if (! password || ! *password) {
LogError("HttpRequest: access denied -- client %s: empty password\n", Socket_getRemoteHost(req->S));
return false;
}
*password++ = 0;
/* Check if user exist */
if (! Util_getUserCredentials(uname)) {
LogError("HttpRequest: access denied -- client %s: unknown user '%s'\n", Socket_getRemoteHost(req->S), uname);
return false;
}
/* Check if user has supplied the right password */
if (! Util_checkCredentials(uname, password)) {
LogError("HttpRequest: access denied -- client %s: wrong password for user '%s'\n", Socket_getRemoteHost(req->S), uname);
return false;
}
req->remote_user = Str_dup(uname);
return true;
}
/* --------------------------------------------------------------- Utilities */
/**
* Send an error message to the client. This is a helper function,
* used internal if the service function fails to setup the framework
* properly; i.e. with a valid HttpRequest and a valid HttpResponse.
*/
static void internal_error(Socket_T S, int status, char *msg) {
char date[STRLEN];
char server[STRLEN];
const char *status_msg = get_status_string(status);
get_date(date, STRLEN);
get_server(server, STRLEN);
Socket_print(S,
"%s %d %s\r\n"
"Date: %s\r\n"
"Server: %s\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"%s"
"%s
%s"
"
%s"
"\r\n",
SERVER_PROTOCOL, status, status_msg, date, server,
status_msg, status_msg, msg, SERVER_URL, server);
DEBUG("HttpRequest: error -- client %s: %s %d %s\n", Socket_getRemoteHost(S), SERVER_PROTOCOL, status, msg ? msg : status_msg);
}
/**
* Parse request parameters from the given query string and return a
* linked list of HttpParameters
*/
static HttpParameter parse_parameters(char *query_string) {
#define KEY 1
#define VALUE 2
int token;
int cursor = 0;
char *key = NULL;
char *value = NULL;
HttpParameter head = NULL;
while ((token = get_next_token(query_string, &cursor, &value))) {
if (token == KEY)
key = value;
else if (token == VALUE) {
HttpParameter p = NULL;
if (! key)
goto error;
NEW(p);
p->name = key;
p->value = value;
p->next = head;
head = p;
key = NULL;
}
}
return head;
error:
FREE(key);
FREE(value);
if ( head != NULL )
destroy_entry(head);
return NULL;
}
/**
* A mini-scanner for tokenizing a query string
*/
static int get_next_token(char *s, int *cursor, char **r) {
int i = *cursor;
while (s[*cursor]) {
if (s[*cursor+1] == '=') {
*cursor += 1;
*r = Str_ndup(&s[i], (*cursor-i));
return KEY;
}
if (s[*cursor] == '=') {
while (s[*cursor] && s[*cursor] != '&') *cursor += 1;
if (s[*cursor] == '&') {
*r = Str_ndup(&s[i+1], (*cursor-i)-1);
*cursor += 1;
} else {
*r = Str_ndup(&s[i+1], (*cursor-i));
}
return VALUE;
}
*cursor += 1;
}
return 0;
}
monit-5.16/src/http/httpstatus.h 0000644 0001751 0001751 00000006271 12654603627 013701 0000000 0000000 /*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License
* along with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#ifndef HTTPSTATUS_H
#define HTTPSTATUS_H
/* HTTP Status Codes */
#define SC_CONTINUE 100
#define SC_SWITCHING_PROTOCOLS 101
#define SC_PROCESSING 102
#define SC_OK 200
#define SC_CREATED 201
#define SC_ACCEPTED 202
#define SC_NON_AUTHORITATIVE 203
#define SC_NO_CONTENT 204
#define SC_RESET_CONTENT 205
#define SC_PARTIAL_CONTENT 206
#define SC_MULTI_STATUS 207
#define SC_MULTIPLE_CHOICES 300
#define SC_MOVED_PERMANENTLY 301
#define SC_MOVED_TEMPORARILY 302
#define SC_SEE_OTHER 303
#define SC_NOT_MODIFIED 304
#define SC_USE_PROXY 305
#define SC_TEMPORARY_REDIRECT 307
#define SC_BAD_REQUEST 400
#define SC_UNAUTHORIZED 401
#define SC_PAYMENT_REQUIRED 402
#define SC_FORBIDDEN 403
#define SC_NOT_FOUND 404
#define SC_METHOD_NOT_ALLOWED 405
#define SC_NOT_ACCEPTABLE 406
#define SC_PROXY_AUTHENTICATION_REQUIRED 407
#define SC_REQUEST_TIMEOUT 408
#define SC_CONFLICT 409
#define SC_GONE 410
#define SC_LENGTH_REQUIRED 411
#define SC_PRECONDITION_FAILED 412
#define SC_REQUEST_ENTITY_TOO_LARGE 413
#define SC_REQUEST_URI_TOO_LARGE 414
#define SC_UNSUPPORTED_MEDIA_TYPE 415
#define SC_RANGE_NOT_SATISFIABLE 416
#define SC_EXPECTATION_FAILED 417
#define SC_UNPROCESSABLE_ENTITY 422
#define SC_LOCKED 423
#define SC_FAILED_DEPENDENCY 424
#define SC_INTERNAL_SERVER_ERROR 500
#define SC_NOT_IMPLEMENTED 501
#define SC_BAD_GATEWAY 502
#define SC_SERVICE_UNAVAILABLE 503
#define SC_GATEWAY_TIMEOUT 504
#define SC_VERSION_NOT_SUPPORTED 505
#define SC_VARIANT_ALSO_VARIES 506
#define SC_INSUFFICIENT_STORAGE 507
#define SC_NOT_EXTENDED 510
#endif
monit-5.16/src/p.y 0000644 0001751 0001751 00000461442 12654603627 010764 0000000 0000000 /*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License
* along with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
%{
/*
* DESCRIPTION
* Simple context-free grammar for parsing the control file.
*
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include
#endif
#ifdef HAVE_STDLIB_H
#include
#endif
#ifdef HAVE_ERRNO_H
#include
#endif
#ifdef HAVE_CTYPE_H
#include
#endif
#ifdef HAVE_PWD_H
#include
#endif
#ifdef HAVE_GRP_H
#include
#endif
#ifdef HAVE_SYS_TYPES_H
#include
#endif
#ifdef HAVE_SYS_TIME_H
#include
#endif
#ifdef HAVE_TIME_H
#include
#endif
#ifdef HAVE_SYS_SOCKET_H
#include
#endif
#ifdef HAVE_ASM_PARAM_H
#include
#endif
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_STRINGS_H
#include
#endif
#ifdef HAVE_NETDB_H
#include
#endif
#ifdef HAVE_SYSLOG_H
#include
#endif
#ifdef HAVE_NETINET_IN_SYSTM_H
#include
#endif
#ifdef HAVE_NETINET_IN_H
#include
#endif
#ifdef HAVE_NETINET_IP_H
#include
#endif
#ifdef HAVE_NETINET_IP_ICMP_H
#include
#endif
#ifdef HAVE_REGEX_H
#include
#endif
#include "net.h"
#include "monit.h"
#include "protocol.h"
#include "engine.h"
#include "alert.h"
#include "process.h"
#include "device.h"
// libmonit
#include "io/File.h"
#include "util/Str.h"
#include "thread/Thread.h"
/* ------------------------------------------------------------- Definitions */
struct IHavePrecedence {
boolean_t daemon;
boolean_t logfile;
boolean_t pidfile;
};
struct myrate {
unsigned count;
unsigned cycles;
};
/* yacc interface */
void yyerror(const char *,...);
void yyerror2(const char *,...);
void yywarning(const char *,...);
void yywarning2(const char *,...);
/* lexer interface */
int yylex(void);
extern FILE *yyin;
extern int lineno;
extern int arglineno;
extern char *yytext;
extern char *argyytext;
extern char *currentfile;
extern char *argcurrentfile;
extern int buffer_stack_ptr;
/* Local variables */
static int cfg_errflag = 0;
static Service_T tail = NULL;
static Service_T current = NULL;
static Request_T urlrequest = NULL;
static command_t command = NULL;
static command_t command1 = NULL;
static command_t command2 = NULL;
static Service_T depend_list = NULL;
static struct myuid uidset;
static struct mygid gidset;
static struct mypid pidset;
static struct mypid ppidset;
static struct myfsflag fsflagset;
static struct mynonexist nonexistset;
static struct mystatus statusset;
static struct myperm permset;
static struct mysize sizeset;
static struct myuptime uptimeset;
static struct mylinkstatus linkstatusset;
static struct mylinkspeed linkspeedset;
static struct mylinksaturation linksaturationset;
static struct mybandwidth bandwidthset;
static struct mymatch matchset;
static struct myicmp icmpset;
static struct mymail mailset;
static struct SslOptions_T sslset;
static struct myport portset;
static struct mymailserver mailserverset;
static struct mymmonit mmonitset;
static struct myfilesystem filesystemset;
static struct myresource resourceset;
static struct mychecksum checksumset;
static struct mytimestamp timestampset;
static struct myactionrate actionrateset;
static struct IHavePrecedence ihp = {false, false, false};
static struct myrate rate = {1, 1};
static struct myrate rate1 = {1, 1};
static struct myrate rate2 = {1, 1};
static char * htpasswd_file = NULL;
static unsigned repeat = 0;
static unsigned repeat1 = 0;
static unsigned repeat2 = 0;
static Digest_Type digesttype = Digest_Cleartext;
#define BITMAP_MAX (sizeof(long long) * 8)
/* -------------------------------------------------------------- Prototypes */
static void preparse();
static void postparse();
static boolean_t _parseOutgoingAddress(const char *ip, Outgoing_T *outgoing);
static void addmail(char *, Mail_T, Mail_T *);
static Service_T createservice(Service_Type, char *, char *, State_Type (*)(Service_T));
static void addservice(Service_T);
static void adddependant(char *);
static void addservicegroup(char *);
static void addport(Port_T *, Port_T);
static void addhttpheader(Port_T, const char *);
static void addresource(Resource_T);
static void addtimestamp(Timestamp_T, boolean_t);
static void addactionrate(ActionRate_T);
static void addsize(Size_T);
static void adduptime(Uptime_T);
static void addpid(Pid_T);
static void addppid(Pid_T);
static void addfsflag(Fsflag_T);
static void addnonexist(Nonexist_T);
static void addlinkstatus(Service_T, LinkStatus_T);
static void addlinkspeed(Service_T, LinkSpeed_T);
static void addlinksaturation(Service_T, LinkSaturation_T);
static void addbandwidth(Bandwidth_T *, Bandwidth_T);
static void addfilesystem(Filesystem_T);
static void addicmp(Icmp_T);
static void addgeneric(Port_T, char*, char*);
static void addcommand(int, unsigned);
static void addargument(char *);
static void addmmonit(Mmonit_T);
static void addmailserver(MailServer_T);
static boolean_t addcredentials(char *, char *, Digest_Type, boolean_t);
#ifdef HAVE_LIBPAM
static void addpamauth(char *, int);
#endif
static void addhtpasswdentry(char *, char *, Digest_Type);
static uid_t get_uid(char *, uid_t);
static gid_t get_gid(char *, gid_t);
static void addchecksum(Checksum_T);
static void addperm(Perm_T);
static void addmatch(Match_T, int, int);
static void addmatchpath(Match_T, Action_Type);
static void addstatus(Status_T);
static Uid_T adduid(Uid_T);
static Gid_T addgid(Gid_T);
static void addeuid(uid_t);
static void addegid(gid_t);
static void addeventaction(EventAction_T *, Action_Type, Action_Type);
static void prepare_urlrequest(URL_T U);
static void seturlrequest(int, char *);
static void setlogfile(char *);
static void setpidfile(char *);
static void reset_sslset();
static void reset_mailset();
static void reset_mailserverset();
static void reset_mmonitset();
static void reset_portset();
static void reset_resourceset();
static void reset_timestampset();
static void reset_actionrateset();
static void reset_sizeset();
static void reset_uptimeset();
static void reset_pidset();
static void reset_ppidset();
static void reset_fsflagset();
static void reset_nonexistset();
static void reset_linkstatusset();
static void reset_linkspeedset();
static void reset_linksaturationset();
static void reset_bandwidthset();
static void reset_checksumset();
static void reset_permset();
static void reset_uidset();
static void reset_gidset();
static void reset_statusset();
static void reset_filesystemset();
static void reset_icmpset();
static void reset_rateset(struct myrate *);
static void check_name(char *);
static int check_perm(int);
static void check_exec(char *);
static int cleanup_hash_string(char *);
static void check_depend();
static void setsyslog(char *);
static command_t copycommand(command_t);
static int verifyMaxForward(int);
%}
%union {
URL_T url;
float real;
int number;
char *string;
}
%token IF ELSE THEN OR FAILED
%token SET LOGFILE FACILITY DAEMON SYSLOG MAILSERVER HTTPD ALLOW REJECTOPT ADDRESS INIT
%token READONLY CLEARTEXT MD5HASH SHA1HASH CRYPT DELAY
%token PEMFILE ENABLE DISABLE SSL CLIENTPEMFILE ALLOWSELFCERTIFICATION SELFSIGNED VERIFY CERTIFICATE CACERTIFICATEFILE CACERTIFICATEPATH VALID
%token INTERFACE LINK PACKET BYTEIN BYTEOUT PACKETIN PACKETOUT SPEED SATURATION UPLOAD DOWNLOAD TOTAL
%token IDFILE STATEFILE SEND EXPECT CYCLE COUNT REMINDER REPEAT
%token LIMITS SENDEXPECTBUFFER EXPECTBUFFER FILECONTENTBUFFER HTTPCONTENTBUFFER PROGRAMOUTPUT NETWORKTIMEOUT
%token PIDFILE START STOP PATHTOK
%token HOST HOSTNAME PORT IPV4 IPV6 TYPE UDP TCP TCPSSL PROTOCOL CONNECTION
%token ALERT NOALERT MAILFORMAT UNIXSOCKET SIGNATURE
%token TIMEOUT RETRY RESTART CHECKSUM EVERY NOTEVERY
%token DEFAULT HTTP HTTPS APACHESTATUS FTP SMTP SMTPS POP POPS IMAP IMAPS CLAMAV NNTP NTP3 MYSQL DNS WEBSOCKET
%token SSH DWP LDAP2 LDAP3 RDATE RSYNC TNS PGSQL POSTFIXPOLICY SIP LMTP GPS RADIUS MEMCACHE REDIS MONGODB SIEVE
%token STRING PATH MAILADDR MAILFROM MAILREPLYTO MAILSUBJECT
%token MAILBODY SERVICENAME STRINGNAME
%token NUMBER PERCENT LOGLIMIT CLOSELIMIT DNSLIMIT KEEPALIVELIMIT
%token REPLYLIMIT REQUESTLIMIT STARTLIMIT WAITLIMIT GRACEFULLIMIT
%token CLEANUPLIMIT
%token REAL
%token CHECKPROC CHECKFILESYS CHECKFILE CHECKDIR CHECKHOST CHECKSYSTEM CHECKFIFO CHECKPROGRAM CHECKNET
%token THREADS CHILDREN STATUS ORIGIN VERSIONOPT
%token RESOURCE MEMORY TOTALMEMORY LOADAVG1 LOADAVG5 LOADAVG15 SWAP
%token MODE ACTIVE PASSIVE MANUAL CPU TOTALCPU CPUUSER CPUSYSTEM CPUWAIT
%token GROUP REQUEST DEPENDS BASEDIR SLOT EVENTQUEUE SECRET HOSTHEADER
%token UID EUID GID MMONIT INSTANCE USERNAME PASSWORD
%token TIMESTAMP CHANGED MILLISECOND SECOND MINUTE HOUR DAY MONTH
%token SSLAUTO SSLV2 SSLV3 TLSV1 TLSV11 TLSV12 CERTMD5 AUTO
%token BYTE KILOBYTE MEGABYTE GIGABYTE
%token INODE SPACE TFREE PERMISSION SIZE MATCH NOT IGNORE ACTION UPTIME
%token EXEC UNMONITOR PING PING4 PING6 ICMP ICMPECHO NONEXIST EXIST INVALID DATA RECOVERED PASSED SUCCEEDED
%token URL CONTENT PID PPID FSFLAG
%token REGISTER CREDENTIALS
%token URLOBJECT
%token TARGET TIMESPEC HTTPHEADER
%token MAXFORWARD
%token FIPS
%left GREATER LESS EQUAL NOTEQUAL
%%
cfgfile : /* EMPTY */
| statement_list
;
statement_list : statement
| statement_list statement
;
statement : setalert
| setssl
| setdaemon
| setlog
| seteventqueue
| setmmonits
| setmailservers
| setmailformat
| sethttpd
| setpid
| setidfile
| setstatefile
| setexpectbuffer
| setinit
| setlimits
| setfips
| checkproc optproclist
| checkfile optfilelist
| checkfilesys optfilesyslist
| checkdir optdirlist
| checkhost opthostlist
| checksystem optsystemlist
| checkfifo optfifolist
| checkprogram optstatuslist
| checknet optnetlist
;
optproclist : /* EMPTY */
| optproclist optproc
;
optproc : start
| stop
| restart
| exist
| pid
| ppid
| uid
| euid
| gid
| uptime
| connection
| connectionurl
| connectionunix
| actionrate
| alert
| every
| mode
| group
| depend
| resourceprocess
;
optfilelist : /* EMPTY */
| optfilelist optfile
;
optfile : start
| stop
| restart
| exist
| timestamp
| actionrate
| every
| alert
| permission
| uid
| gid
| checksum
| size
| match
| mode
| group
| depend
;
optfilesyslist : /* EMPTY */
| optfilesyslist optfilesys
;
optfilesys : start
| stop
| restart
| actionrate
| every
| alert
| permission
| uid
| gid
| mode
| group
| depend
| inode
| space
| fsflag
;
optdirlist : /* EMPTY */
| optdirlist optdir
;
optdir : start
| stop
| restart
| exist
| timestamp
| actionrate
| every
| alert
| permission
| uid
| gid
| mode
| group
| depend
;
opthostlist : /* EMPTY */
| opthostlist opthost
;
opthost : start
| stop
| restart
| connection
| connectionurl
| icmp
| actionrate
| alert
| every
| mode
| group
| depend
;
optnetlist : /* EMPTY */
| optnetlist optnet
;
optnet : start
| stop
| restart
| linkstatus
| linkspeed
| linksaturation
| upload
| download
| actionrate
| every
| alert
| group
| depend
;
optsystemlist : /* EMPTY */
| optsystemlist optsystem
;
optsystem : start
| stop
| restart
| actionrate
| alert
| every
| group
| depend
| resourcesystem
;
optfifolist : /* EMPTY */
| optfifolist optfifo
;
optfifo : start
| stop
| restart
| exist
| timestamp
| actionrate
| every
| alert
| permission
| uid
| gid
| mode
| group
| depend
;
optstatuslist : /* EMPTY */
| optstatuslist optstatus
;
optstatus : start
| stop
| restart
| actionrate
| alert
| every
| group
| depend
| statusvalue
;
setalert : SET alertmail formatlist reminder {
mailset.events = Event_All;
addmail($2, &mailset, &Run.maillist);
}
| SET alertmail '{' eventoptionlist '}' formatlist reminder {
addmail($2, &mailset, &Run.maillist);
}
| SET alertmail NOT '{' eventoptionlist '}' formatlist reminder {
mailset.events = ~mailset.events;
addmail($2, &mailset, &Run.maillist);
}
;
setdaemon : SET DAEMON NUMBER startdelay {
if (! (Run.flags & Run_Daemon) || ihp.daemon) {
ihp.daemon = true;
Run.flags |= Run_Daemon;
Run.polltime = $3;
Run.startdelay = $4;
}
}
;
startdelay : /* EMPTY */ { $$ = START_DELAY; }
| START DELAY NUMBER { $$ = $3; }
;
setinit : SET INIT {
Run.flags |= Run_Foreground;
}
;
setexpectbuffer : SET EXPECTBUFFER NUMBER unit {
// Note: deprecated (replaced by "set limits" statement's "sendExpectBuffer" option)
Run.limits.sendExpectBuffer = $3 * $4;
}
;
setlimits : SET LIMITS '{' limitlist '}'
;
limitlist : /* EMPTY */
| limitlist limit
;
limit : SENDEXPECTBUFFER ':' NUMBER unit {
Run.limits.sendExpectBuffer = $3 * $4;
}
| FILECONTENTBUFFER ':' NUMBER unit {
Run.limits.fileContentBuffer = $3 * $4;
}
| HTTPCONTENTBUFFER ':' NUMBER unit {
Run.limits.httpContentBuffer = $3 * $4;
}
| PROGRAMOUTPUT ':' NUMBER unit {
Run.limits.programOutput = $3 * $4;
}
| NETWORKTIMEOUT ':' NUMBER MILLISECOND {
Run.limits.networkTimeout= $3;
}
| NETWORKTIMEOUT ':' NUMBER SECOND {
Run.limits.networkTimeout= $3 * 1000;
}
;
setfips : SET FIPS {
Run.flags |= Run_FipsEnabled;
}
;
setlog : SET LOGFILE PATH {
if (! Run.files.log || ihp.logfile) {
ihp.logfile = true;
setlogfile($3);
Run.flags &= ~Run_UseSyslog;
Run.flags |= Run_Log;
}
}
| SET LOGFILE SYSLOG {
setsyslog(NULL);
}
| SET LOGFILE SYSLOG FACILITY STRING {
setsyslog($5); FREE($5);
}
;
seteventqueue : SET EVENTQUEUE BASEDIR PATH {
Run.eventlist_dir = $4;
}
| SET EVENTQUEUE BASEDIR PATH SLOT NUMBER {
Run.eventlist_dir = $4;
Run.eventlist_slots = $6;
}
| SET EVENTQUEUE SLOT NUMBER {
Run.eventlist_dir = Str_dup(MYEVENTLISTBASE);
Run.eventlist_slots = $4;
}
;
setidfile : SET IDFILE PATH {
Run.files.id = $3;
}
;
setstatefile : SET STATEFILE PATH {
Run.files.state = $3;
}
;
setpid : SET PIDFILE PATH {
if (! Run.files.pid || ihp.pidfile) {
ihp.pidfile = true;
setpidfile($3);
}
}
;
setmmonits : SET MMONIT mmonitlist
;
mmonitlist : mmonit credentials
| mmonitlist mmonit credentials
;
mmonit : URLOBJECT mmonitoptlist {
mmonitset.url = $1;
addmmonit(&mmonitset);
}
;
mmonitoptlist : /* EMPTY */
| mmonitoptlist mmonitopt
;
mmonitopt : TIMEOUT NUMBER SECOND {
mmonitset.timeout = $2 * 1000; // net timeout is in milliseconds internally
}
| ssl
| sslchecksum
| sslversion
| certmd5
;
credentials : /* EMPTY */
| REGISTER CREDENTIALS {
Run.flags &= ~Run_MmonitCredentials;
}
;
setssl : SET SSL '{' ssloptionlist '}' {
Run.ssl.use_ssl = true;
Run.ssl.verify = sslset.verify;
Run.ssl.allowSelfSigned = sslset.allowSelfSigned;
Run.ssl.version = sslset.version;
Run.ssl.minimumValidDays = sslset.minimumValidDays;
Run.ssl.checksumType = sslset.checksumType;
Run.ssl.checksum = sslset.checksum;
Run.ssl.clientpemfile = sslset.clientpemfile;
Run.ssl.CACertificateFile = sslset.CACertificateFile;
Run.ssl.CACertificatePath = sslset.CACertificatePath;
if (Run.ssl.allowSelfSigned == true)
Run.httpd.flags |= Httpd_AllowSelfSignedCertificates;
reset_sslset();
}
;
ssl : SSL {
sslset.use_ssl = true;
}
| SSL '{' ssloptionlist '}'
;
ssloptionlist : /* EMPTY */
| ssloptionlist ssloption
;
ssloption : VERIFY ':' ENABLE {
sslset.use_ssl = true;
sslset.verify = true;
}
| VERIFY ':' DISABLE {
sslset.use_ssl = true;
sslset.verify = false;
}
| SELFSIGNED ':' ALLOW {
sslset.use_ssl = true;
sslset.allowSelfSigned = true;
}
| SELFSIGNED ':' REJECTOPT {
sslset.use_ssl = true;
sslset.allowSelfSigned = false;
}
| VERSIONOPT ':' sslversion {
sslset.use_ssl = true;
}
| CLIENTPEMFILE ':' PATH {
sslset.use_ssl = true;
sslset.clientpemfile = $3;
if (! File_exist(sslset.clientpemfile))
yyerror2("SSL client PEM file doesn't exist");
else if (! File_isFile(sslset.clientpemfile))
yyerror2("SSL client PEM file is not a file");
else if (! File_isReadable(sslset.clientpemfile))
yyerror2("Cannot read SSL client PEM file");
}
| CACERTIFICATEFILE ':' PATH {
if (sslset.CACertificateFile)
yyerror2("Duplicate SSL CA certificates file doesn't exist");
sslset.use_ssl = true;
sslset.CACertificateFile = $3;
if (! File_exist(sslset.CACertificateFile))
yyerror2("SSL CA certificates file doesn't exist");
else if (! File_isFile(sslset.CACertificateFile))
yyerror2("SSL CA certificates file is not a file");
else if (! File_isReadable(sslset.CACertificateFile))
yyerror2("Cannot read CA certificates file");
}
| CACERTIFICATEPATH ':' PATH {
sslset.use_ssl = true;
sslset.CACertificatePath = $3;
if (! File_exist(sslset.CACertificatePath))
yyerror2("SSL CA certificates directory doesn't exist");
else if (! File_isDirectory(sslset.CACertificatePath))
yyerror2("SSL CA certificates path is not directory");
else if (! File_isReadable(sslset.CACertificatePath))
yyerror2("Cannot read CA certificates directory");
}
;
sslexpire : CERTIFICATE VALID expireoperator NUMBER DAY {
sslset.use_ssl = true;
sslset.minimumValidDays = $4;
}
;
expireoperator : /* EMPTY */
| GREATER
;
sslchecksum : CERTIFICATE CHECKSUM checksumoperator STRING {
sslset.use_ssl = true;
sslset.checksum = $4;
switch (cleanup_hash_string(sslset.checksum)) {
case 32:
sslset.checksumType = Hash_Md5;
break;
case 40:
sslset.checksumType = Hash_Sha1;
break;
default:
yyerror2("Unknown checksum type: [%s] is not MD5 nor SHA1", sslset.checksum);
}
}
| CERTIFICATE CHECKSUM MD5HASH checksumoperator STRING {
sslset.use_ssl = true;
sslset.checksum = $5;
if (cleanup_hash_string(sslset.checksum) != 32)
yyerror2("Unknown checksum type: [%s] is not MD5", sslset.checksum);
sslset.checksumType = Hash_Md5;
}
| CERTIFICATE CHECKSUM SHA1HASH checksumoperator STRING {
sslset.use_ssl = true;
sslset.checksum = $5;
if (cleanup_hash_string(sslset.checksum) != 40)
yyerror2("Unknown checksum type: [%s] is not SHA1", sslset.checksum);
sslset.checksumType = Hash_Sha1;
}
;
checksumoperator : /* EMPTY */
| EQUAL
;
sslversion : SSLV2 {
sslset.use_ssl = true;
sslset.version = SSL_V2;
}
| SSLV3 {
sslset.use_ssl = true;
sslset.version = SSL_V3;
}
| TLSV1 {
sslset.use_ssl = true;
sslset.version = SSL_TLSV1;
}
| TLSV11
{
#ifndef HAVE_TLSV1_1
yyerror("Your SSL Library does not support TLS version 1.1");
#endif
sslset.use_ssl = true;
sslset.version = SSL_TLSV11;
}
| TLSV12
{
#ifndef HAVE_TLSV1_2
yyerror("Your SSL Library does not support TLS version 1.2");
#endif
sslset.use_ssl = true;
sslset.version = SSL_TLSV12;
}
| SSLAUTO {
sslset.use_ssl = true;
sslset.version = SSL_Auto;
}
| AUTO {
sslset.use_ssl = true;
sslset.version = SSL_Auto;
}
;
certmd5 : CERTMD5 STRING { // Backward compatibility
sslset.use_ssl = true;
sslset.checksum = $2;
if (cleanup_hash_string(sslset.checksum) != 32)
yyerror2("Unknown checksum type: [%s] is not MD5", sslset.checksum);
sslset.checksumType = Hash_Md5;
}
;
setmailservers : SET MAILSERVER mailserverlist nettimeout hostname {
if (($4) > SMTP_TIMEOUT)
Run.mailserver_timeout = $4;
Run.mail_hostname = $5;
}
;
setmailformat : SET MAILFORMAT '{' formatoptionlist '}' {
Run.MailFormat.from = mailset.from ? mailset.from : Str_dup(ALERT_FROM);
Run.MailFormat.replyto = mailset.replyto ? mailset.replyto : NULL;
Run.MailFormat.subject = mailset.subject ? mailset.subject : Str_dup(ALERT_SUBJECT);
Run.MailFormat.message = mailset.message ? mailset.message : Str_dup(ALERT_MESSAGE);
reset_mailset();
}
;
mailserverlist : mailserver
| mailserverlist mailserver
;
mailserver : STRING mailserveroptlist {
/* Restore the current text overriden by lookahead */
FREE(argyytext);
argyytext = Str_dup($1);
mailserverset.host = $1;
mailserverset.port = PORT_SMTP;
addmailserver(&mailserverset);
}
| STRING PORT NUMBER mailserveroptlist {
/* Restore the current text overriden by lookahead */
FREE(argyytext);
argyytext = Str_dup($1);
mailserverset.host = $1;
mailserverset.port = $3;
addmailserver(&mailserverset);
}
;
mailserveroptlist : /* EMPTY */
| mailserveroptlist mailserveropt
;
mailserveropt : username {
mailserverset.username = $1;
}
| password {
mailserverset.password = $1;
}
| ssl
| sslchecksum
| sslversion
| certmd5
;
sethttpd : SET HTTPD PORT NUMBER httpdnetlist {
Run.httpd.flags |= Httpd_Net;
Run.httpd.socket.net.port = $4;
}
| SET HTTPD UNIXSOCKET PATH httpdunixlist {
Run.httpd.flags |= Httpd_Unix;
Run.httpd.socket.unix.path = $4;
}
;
httpdnetlist : /* EMPTY */
| httpdnetlist httpdnetoption
;
httpdnetoption : sslserver
| signature
| bindaddress
| allow
;
httpdunixlist : /* EMPTY */
| httpdunixlist httpdunixoption
;
httpdunixoption : signature
| allow
;
sslserver : ssldisable optssllist {
Run.httpd.flags &= ~Httpd_Ssl;
}
| sslenable optssllist {
Run.httpd.flags |= Httpd_Ssl;
#ifdef HAVE_OPENSSL
if (! Run.httpd.socket.net.ssl.pem)
yyerror("SSL server PEM file is required (pemfile option)");
else if (! file_checkStat(Run.httpd.socket.net.ssl.pem, "SSL server PEM file", S_IRWXU))
yyerror("SSL server PEM file permissions check failed");
#else
yyerror("SSL is not supported");
#endif
}
;
optssllist : /* EMPTY */
| optssllist optssl
;
optssl : pemfile
| clientpemfile
| allowselfcert
;
sslenable : SSL ENABLE
| ENABLE SSL
;
ssldisable : SSL DISABLE
| DISABLE SSL
;
signature : sigenable {
Run.httpd.flags |= Httpd_Signature;
}
| sigdisable {
Run.httpd.flags &= ~Httpd_Signature;
}
;
sigenable : SIGNATURE ENABLE
| ENABLE SIGNATURE
;
sigdisable : SIGNATURE DISABLE
| DISABLE SIGNATURE
;
bindaddress : ADDRESS STRING {
Run.httpd.socket.net.address = $2;
}
;
pemfile : PEMFILE PATH {
Run.httpd.socket.net.ssl.pem = $2;
}
;
clientpemfile : CLIENTPEMFILE PATH {
Run.httpd.socket.net.ssl.clientpem = $2;
if (! file_checkStat(Run.httpd.socket.net.ssl.clientpem, "SSL client PEM file", S_IRWXU | S_IRGRP | S_IROTH))
yyerror2("SSL client PEM file has too loose permissions");
}
;
allowselfcert : ALLOWSELFCERTIFICATION {
Run.httpd.flags |= Httpd_AllowSelfSignedCertificates;
}
;
allow : ALLOW STRING':'STRING readonly {
addcredentials($2, $4, Digest_Cleartext, $5);
}
| ALLOW '@'STRING readonly {
#ifdef HAVE_LIBPAM
addpamauth($3, $4);
#else
yyerror("PAM is not supported");
FREE($3);
#endif
}
| ALLOW PATH {
addhtpasswdentry($2, NULL, Digest_Cleartext);
FREE($2);
}
| ALLOW CLEARTEXT PATH {
addhtpasswdentry($3, NULL, Digest_Cleartext);
FREE($3);
}
| ALLOW MD5HASH PATH {
addhtpasswdentry($3, NULL, Digest_Md5);
FREE($3);
}
| ALLOW CRYPT PATH {
addhtpasswdentry($3, NULL, Digest_Crypt);
FREE($3);
}
| ALLOW PATH {
htpasswd_file = $2;
digesttype = Digest_Cleartext;
}
allowuserlist {
FREE(htpasswd_file);
}
| ALLOW CLEARTEXT PATH {
htpasswd_file = $3;
digesttype = Digest_Cleartext;
}
allowuserlist {
FREE(htpasswd_file);
}
| ALLOW MD5HASH PATH {
htpasswd_file = $3;
digesttype = Digest_Md5;
}
allowuserlist {
FREE(htpasswd_file);
}
| ALLOW CRYPT PATH {
htpasswd_file = $3;
digesttype = Digest_Crypt;
}
allowuserlist {
FREE(htpasswd_file);
}
| ALLOW STRING {
if (! (Engine_addNetAllow($2) || Engine_addHostAllow($2)))
yyerror2("Erroneous network or host identifier %s", $2);
FREE($2);
}
;
allowuserlist : allowuser
| allowuserlist allowuser
;
allowuser : STRING {
addhtpasswdentry(htpasswd_file, $1, digesttype);
FREE($1);
}
;
readonly : /* EMPTY */ { $$ = false; }
| READONLY { $$ = true; }
;
checkproc : CHECKPROC SERVICENAME PIDFILE PATH {
createservice(Service_Process, $2, $4, check_process);
}
| CHECKPROC SERVICENAME PATHTOK PATH {
createservice(Service_Process, $2, $4, check_process);
}
| CHECKPROC SERVICENAME MATCH STRING {
createservice(Service_Process, $2, $4, check_process);
matchset.ignore = false;
matchset.match_path = NULL;
matchset.match_string = Str_dup($4);
addmatch(&matchset, Action_Ignored, 0);
}
| CHECKPROC SERVICENAME MATCH PATH {
createservice(Service_Process, $2, $4, check_process);
matchset.ignore = false;
matchset.match_path = NULL;
matchset.match_string = Str_dup($4);
addmatch(&matchset, Action_Ignored, 0);
}
;
checkfile : CHECKFILE SERVICENAME PATHTOK PATH {
createservice(Service_File, $2, $4, check_file);
}
;
checkfilesys : CHECKFILESYS SERVICENAME PATHTOK PATH {
createservice(Service_Filesystem, $2, $4, check_filesystem);
}
| CHECKFILESYS SERVICENAME PATHTOK STRING {
createservice(Service_Filesystem, $2, $4, check_filesystem);
}
;
checkdir : CHECKDIR SERVICENAME PATHTOK PATH {
createservice(Service_Directory, $2, $4, check_directory);
}
;
checkhost : CHECKHOST SERVICENAME ADDRESS STRING {
createservice(Service_Host, $2, $4, check_remote_host);
}
;
checknet : CHECKNET SERVICENAME ADDRESS STRING {
if (Link_isGetByAddressSupported()) {
createservice(Service_Net, $2, $4, check_net);
current->inf->priv.net.stats = Link_createForAddress($4);
} else {
yyerror("Network monitoring by IP address is not supported on this platform, please use 'check network with interface ' instead");
}
}
| CHECKNET SERVICENAME INTERFACE STRING {
createservice(Service_Net, $2, $4, check_net);
current->inf->priv.net.stats = Link_createForInterface($4);
}
;
checksystem : CHECKSYSTEM SERVICENAME {
char hostname[STRLEN];
if (Util_getfqdnhostname(hostname, sizeof(hostname))) {
LogError("Cannot get system hostname\n");
cfg_errflag++;
}
char *servicename = $2;
Util_replaceString(&servicename, "$HOST", hostname);
Run.system = createservice(Service_System, servicename, Str_dup(""), check_system); // The name given in the 'check system' statement overrides system hostname
}
;
checkfifo : CHECKFIFO SERVICENAME PATHTOK PATH {
createservice(Service_Fifo, $2, $4, check_fifo);
}
;
checkprogram : CHECKPROGRAM SERVICENAME PATHTOK argumentlist programtimeout {
command_t c = command; // Current command
check_exec(c->arg[0]);
createservice(Service_Program, $2, Str_dup(c->arg[0]), check_program);
current->program->timeout = $5;
current->program->output = StringBuffer_create(64);
}
| CHECKPROGRAM SERVICENAME PATHTOK argumentlist useroptionlist programtimeout {
command_t c = command; // Current command
check_exec(c->arg[0]);
createservice(Service_Program, $2, Str_dup(c->arg[0]), check_program);
current->program->timeout = $5;
current->program->output = StringBuffer_create(64);
}
;
start : START argumentlist exectimeout {
addcommand(START, $3);
}
| START argumentlist useroptionlist exectimeout {
addcommand(START, $4);
}
;
stop : STOP argumentlist exectimeout {
addcommand(STOP, $3);
}
| STOP argumentlist useroptionlist exectimeout {
addcommand(STOP, $4);
}
;
restart : RESTART argumentlist exectimeout {
addcommand(RESTART, $3);
}
| RESTART argumentlist useroptionlist exectimeout {
addcommand(RESTART, $4);
}
;
argumentlist : argument
| argumentlist argument
;
useroptionlist : useroption
| useroptionlist useroption
;
argument : STRING {
addargument($1);
}
| PATH {
addargument($1);
}
;
useroption : UID STRING {
addeuid(get_uid($2, 0));
FREE($2);
}
| GID STRING {
addegid(get_gid($2, 0));
FREE($2);
}
| UID NUMBER {
addeuid(get_uid(NULL, $2));
}
| GID NUMBER {
addegid(get_gid(NULL, $2));
}
;
username : USERNAME MAILADDR {
$$ = $2;
}
| USERNAME STRING {
$$ = $2;
}
;
password : PASSWORD STRING {
$$ = $2;
}
;
hostname : /* EMPTY */ {
$$ = NULL;
}
| HOSTNAME STRING {
$$ = $2;
}
;
connection : IF FAILED host port connectionoptlist rate1 THEN action1 recovery {
/* This is a workaround to support content match without having to create an URL object. 'urloption' creates the Request_T object we need minus the URL object, but with enough information to perform content test.
TODO: Parser is in need of refactoring */
portset.url_request = urlrequest;
addeventaction(&(portset).action, $8, $9);
addport(&(current->portlist), &portset);
}
;
connectionoptlist : /* EMPTY */
| connectionoptlist connectionopt
;
connectionopt : ip
| type
| protocol
| sendexpect
| urloption
| connectiontimeout
| outgoing
| retry
| ssl
| sslchecksum
| sslexpire
;
connectionurl : IF FAILED URL URLOBJECT connectionurloptlist rate1 THEN action1 recovery {
prepare_urlrequest($4);
addeventaction(&(portset).action, $8, $9);
addport(&(current->portlist), &portset);
}
;
connectionurloptlist : /* EMPTY */
| connectionurloptlist connectionurlopt
;
connectionurlopt : urloption
| connectiontimeout
| retry
| ssl
| sslchecksum
| sslexpire
;
connectionunix : IF FAILED unixsocket connectionuxoptlist rate1 THEN action1 recovery {
addeventaction(&(portset).action, $7, $8);
addport(&(current->socketlist), &portset);
}
;
connectionuxoptlist : /* EMPTY */
| connectionuxoptlist connectionuxopt
;
connectionuxopt : type
| protocol
| sendexpect
| connectiontimeout
| retry
;
icmp : IF FAILED ICMP icmptype icmpoptlist rate1 THEN action1 recovery {
icmpset.family = Socket_Ip;
icmpset.type = $4;
addeventaction(&(icmpset).action, $8, $9);
addicmp(&icmpset);
}
| IF FAILED PING icmpoptlist rate1 THEN action1 recovery {
icmpset.family = Socket_Ip;
addeventaction(&(icmpset).action, $7, $8);
addicmp(&icmpset);
}
| IF FAILED PING4 icmpoptlist rate1 THEN action1 recovery {
icmpset.family = Socket_Ip4;
addeventaction(&(icmpset).action, $7, $8);
addicmp(&icmpset);
}
| IF FAILED PING6 icmpoptlist rate1 THEN action1 recovery {
icmpset.family = Socket_Ip6;
addeventaction(&(icmpset).action, $7, $8);
addicmp(&icmpset);
}
;
icmpoptlist : /* EMPTY */
| icmpoptlist icmpopt
;
icmpopt : icmpcount
| icmpsize
| icmptimeout
| icmpoutgoing
;
host : /* EMPTY */ {
portset.hostname = Str_dup(current->type == Service_Host ? current->path : LOCALHOST);
}
| HOST STRING {
portset.hostname = $2;
}
;
port : PORT NUMBER {
portset.target.net.port = $2;
}
;
unixsocket : UNIXSOCKET PATH {
portset.family = Socket_Unix;
portset.target.unix.pathname = $2;
}
;
ip : IPV4 {
portset.family = Socket_Ip4;
}
| IPV6 {
portset.family = Socket_Ip6;
}
;
type : TYPE TCP {
portset.type = Socket_Tcp;
}
| TYPE TCPSSL typeoptlist { // The typelist is kept for backward compatibility (replaced by ssloptionlist)
portset.type = Socket_Tcp;
sslset.use_ssl = true;
}
| TYPE UDP {
portset.type = Socket_Udp;
}
;
typeoptlist : /* EMPTY */
| typeoptlist typeopt
;
typeopt : sslversion
| certmd5
;
outgoing : ADDRESS STRING {
_parseOutgoingAddress($2, &(portset.outgoing));
}
;
protocol : PROTOCOL APACHESTATUS apache_stat_list {
portset.protocol = Protocol_get(Protocol_APACHESTATUS);
}
| PROTOCOL DEFAULT {
portset.protocol = Protocol_get(Protocol_DEFAULT);
}
| PROTOCOL DNS {
portset.protocol = Protocol_get(Protocol_DNS);
}
| PROTOCOL DWP {
portset.protocol = Protocol_get(Protocol_DWP);
}
| PROTOCOL FTP {
portset.protocol = Protocol_get(Protocol_FTP);
}
| PROTOCOL HTTP httplist {
portset.protocol = Protocol_get(Protocol_HTTP);
}
| PROTOCOL HTTPS httplist {
sslset.use_ssl = true;
portset.type = Socket_Tcp;
portset.protocol = Protocol_get(Protocol_HTTP);
}
| PROTOCOL IMAP {
portset.protocol = Protocol_get(Protocol_IMAP);
}
| PROTOCOL IMAPS {
sslset.use_ssl = true;
portset.type = Socket_Tcp;
portset.protocol = Protocol_get(Protocol_IMAP);
}
| PROTOCOL CLAMAV {
portset.protocol = Protocol_get(Protocol_CLAMAV);
}
| PROTOCOL LDAP2 {
portset.protocol = Protocol_get(Protocol_LDAP2);
}
| PROTOCOL LDAP3 {
portset.protocol = Protocol_get(Protocol_LDAP3);
}
| PROTOCOL MONGODB {
portset.protocol = Protocol_get(Protocol_MONGODB);
}
| PROTOCOL MYSQL mysqllist {
portset.protocol = Protocol_get(Protocol_MYSQL);
}
| PROTOCOL SIP siplist {
portset.protocol = Protocol_get(Protocol_SIP);
}
| PROTOCOL NNTP {
portset.protocol = Protocol_get(Protocol_NNTP);
}
| PROTOCOL NTP3 {
portset.protocol = Protocol_get(Protocol_NTP3);
portset.type = Socket_Udp;
}
| PROTOCOL POSTFIXPOLICY {
portset.protocol = Protocol_get(Protocol_POSTFIXPOLICY);
}
| PROTOCOL POP {
portset.protocol = Protocol_get(Protocol_POP);
}
| PROTOCOL POPS {
sslset.use_ssl = true;
portset.type = Socket_Tcp;
portset.protocol = Protocol_get(Protocol_POP);
}
| PROTOCOL SIEVE {
portset.protocol = Protocol_get(Protocol_SIEVE);
}
| PROTOCOL SMTP {
portset.protocol = Protocol_get(Protocol_SMTP);
}
| PROTOCOL SMTPS {
sslset.use_ssl = true;
portset.type = Socket_Tcp;
portset.protocol = Protocol_get(Protocol_SMTP);
}
| PROTOCOL SSH {
portset.protocol = Protocol_get(Protocol_SSH);
}
| PROTOCOL RDATE {
portset.protocol = Protocol_get(Protocol_RDATE);
}
| PROTOCOL REDIS {
portset.protocol = Protocol_get(Protocol_REDIS);
}
| PROTOCOL RSYNC {
portset.protocol = Protocol_get(Protocol_RSYNC);
}
| PROTOCOL TNS {
portset.protocol = Protocol_get(Protocol_TNS);
}
| PROTOCOL PGSQL {
portset.protocol = Protocol_get(Protocol_PGSQL);
}
| PROTOCOL LMTP {
portset.protocol = Protocol_get(Protocol_LMTP);
}
| PROTOCOL GPS {
portset.protocol = Protocol_get(Protocol_GPS);
}
| PROTOCOL RADIUS radiuslist {
portset.protocol = Protocol_get(Protocol_RADIUS);
}
| PROTOCOL MEMCACHE {
portset.protocol = Protocol_get(Protocol_MEMCACHE);
}
| PROTOCOL WEBSOCKET websocketlist {
portset.protocol = Protocol_get(Protocol_WEBSOCKET);
}
;
sendexpect : SEND STRING {
portset.protocol = Protocol_get(Protocol_GENERIC);
addgeneric(&portset, $2, NULL);
}
| EXPECT STRING {
portset.protocol = Protocol_get(Protocol_GENERIC);
addgeneric(&portset, NULL, $2);
}
;
websocketlist : websocket
| websocketlist websocket
;
websocket : ORIGIN STRING {
portset.parameters.websocket.origin = $2;
}
| REQUEST PATH {
portset.parameters.websocket.request = $2;
}
| HOST STRING {
portset.parameters.websocket.host = $2;
}
| VERSIONOPT NUMBER {
portset.parameters.websocket.version = $2;
}
;
mysqllist : /* EMPTY */
| mysqllist mysql
;
mysql : username {
if ($1) {
if (strlen($1) > 16)
yyerror2("Username too long -- Maximum MySQL username lengh is 16 characters");
else
portset.parameters.mysql.username = $1;
}
}
| password {
portset.parameters.mysql.password = $1;
}
;
target : TARGET MAILADDR {
$$ = $2;
}
| TARGET STRING {
$$ = $2;
}
;
maxforward : MAXFORWARD NUMBER {
$$ = verifyMaxForward($2);
}
;
siplist : /* EMPTY */
| siplist sip
;
sip : target {
portset.parameters.sip.target = $1;
}
| maxforward {
portset.parameters.sip.maxforward = $1;
}
;
httplist : /* EMPTY */
| httplist http
;
http : request
| responsesum
| status
| hostheader
| '[' httpheaderlist ']'
;
status : STATUS operator NUMBER {
portset.parameters.http.operator = $2;
portset.parameters.http.status = $3;
}
;
request : REQUEST PATH {
portset.parameters.http.request = Util_urlEncode($2);
FREE($2);
}
;
responsesum : CHECKSUM STRING {
portset.parameters.http.checksum = $2;
}
;
hostheader : HOSTHEADER STRING {
addhttpheader(&portset, Str_cat("Host:%s", $2));
FREE($2);
}
;
httpheaderlist : /* EMPTY */
| httpheaderlist HTTPHEADER {
addhttpheader(&portset, $2);
}
;
secret : SECRET STRING {
$$ = $2;
}
;
radiuslist : /* EMPTY */
| radiuslist radius
;
radius : secret {
portset.parameters.radius.secret = $1;
}
;
apache_stat_list: apache_stat
| apache_stat_list apache_stat
;
apache_stat : PATHTOK PATH {
portset.parameters.apachestatus.path = $2;
}
| LOGLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.loglimitOP = $2;
portset.parameters.apachestatus.loglimit = $3;
}
| CLOSELIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.closelimitOP = $2;
portset.parameters.apachestatus.closelimit = $3;
}
| DNSLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.dnslimitOP = $2;
portset.parameters.apachestatus.dnslimit = $3;
}
| KEEPALIVELIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.keepalivelimitOP = $2;
portset.parameters.apachestatus.keepalivelimit = $3;
}
| REPLYLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.replylimitOP = $2;
portset.parameters.apachestatus.replylimit = $3;
}
| REQUESTLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.requestlimitOP = $2;
portset.parameters.apachestatus.requestlimit = $3;
}
| STARTLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.startlimitOP = $2;
portset.parameters.apachestatus.startlimit = $3;
}
| WAITLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.waitlimitOP = $2;
portset.parameters.apachestatus.waitlimit = $3;
}
| GRACEFULLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.gracefullimitOP = $2;
portset.parameters.apachestatus.gracefullimit = $3;
}
| CLEANUPLIMIT operator NUMBER PERCENT {
portset.parameters.apachestatus.cleanuplimitOP = $2;
portset.parameters.apachestatus.cleanuplimit = $3;
}
;
exist : IF NOT EXIST rate1 THEN action1 recovery {
addeventaction(&(nonexistset).action, $6, $7);
addnonexist(&nonexistset);
}
;
pid : IF CHANGED PID rate1 THEN action1 {
addeventaction(&(pidset).action, $6, Action_Ignored);
addpid(&pidset);
}
;
ppid : IF CHANGED PPID rate1 THEN action1 {
addeventaction(&(ppidset).action, $6, Action_Ignored);
addppid(&ppidset);
}
;
uptime : IF UPTIME operator NUMBER time rate1 THEN action1 recovery {
uptimeset.operator = $3;
uptimeset.uptime = ((unsigned long long)$4 * $5);
addeventaction(&(uptimeset).action, $8, $9);
adduptime(&uptimeset);
}
icmpcount : COUNT NUMBER {
icmpset.count = $2;
}
;
icmpsize : SIZE NUMBER {
icmpset.size = $2;
}
;
icmptimeout : TIMEOUT NUMBER SECOND {
icmpset.timeout = $2 * 1000; // timeout is in milliseconds internally
}
;
icmpoutgoing : ADDRESS STRING {
_parseOutgoingAddress($2, &(icmpset.outgoing));
}
;
exectimeout : /* EMPTY */ {
$$ = EXEC_TIMEOUT;
}
| TIMEOUT NUMBER SECOND {
$$ = $2;
}
;
programtimeout : /* EMPTY */ {
$$ = PROGRAM_TIMEOUT; // Default program status check timeout is 5 min
}
| TIMEOUT NUMBER SECOND {
$$ = $2;
}
;
nettimeout : /* EMPTY */ {
$$ = Run.limits.networkTimeout;
}
| TIMEOUT NUMBER SECOND {
$$ = $2 * 1000; // net timeout is in milliseconds internally
}
;
connectiontimeout : TIMEOUT NUMBER SECOND {
portset.timeout = $2 * 1000; // timeout is in milliseconds internally
}
;
retry : RETRY NUMBER {
$$ = $2;
}
;
actionrate : IF NUMBER RESTART NUMBER CYCLE THEN action1 {
actionrateset.count = $2;
actionrateset.cycle = $4;
addeventaction(&(actionrateset).action, $7, Action_Alert);
addactionrate(&actionrateset);
}
| IF NUMBER RESTART NUMBER CYCLE THEN TIMEOUT {
actionrateset.count = $2;
actionrateset.cycle = $4;
addeventaction(&(actionrateset).action, Action_Unmonitor, Action_Alert);
addactionrate(&actionrateset);
}
;
urloption : CONTENT urloperator STRING {
seturlrequest($2, $3);
FREE($3);
}
;
urloperator : EQUAL { $$ = Operator_Equal; }
| NOTEQUAL { $$ = Operator_NotEqual; }
;
alert : alertmail formatlist reminder {
mailset.events = Event_All;
addmail($1, &mailset, ¤t->maillist);
}
| alertmail '{' eventoptionlist '}' formatlist reminder {
addmail($1, &mailset, ¤t->maillist);
}
| alertmail NOT '{' eventoptionlist '}' formatlist reminder {
mailset.events = ~mailset.events;
addmail($1, &mailset, ¤t->maillist);
}
| noalertmail {
addmail($1, &mailset, ¤t->maillist);
}
;
alertmail : ALERT MAILADDR { $$ = $2; }
;
noalertmail : NOALERT MAILADDR { $$ = $2; }
;
eventoptionlist : eventoption
| eventoptionlist eventoption
;
eventoption : ACTION { mailset.events |= Event_Action; }
| BYTEIN { mailset.events |= Event_ByteIn; }
| BYTEOUT { mailset.events |= Event_ByteOut; }
| CHECKSUM { mailset.events |= Event_Checksum; }
| CONNECTION { mailset.events |= Event_Connection; }
| CONTENT { mailset.events |= Event_Content; }
| DATA { mailset.events |= Event_Data; }
| EXEC { mailset.events |= Event_Exec; }
| FSFLAG { mailset.events |= Event_Fsflag; }
| GID { mailset.events |= Event_Gid; }
| ICMP { mailset.events |= Event_Icmp; }
| INSTANCE { mailset.events |= Event_Instance; }
| INVALID { mailset.events |= Event_Invalid; }
| LINK { mailset.events |= Event_Link; }
| NONEXIST { mailset.events |= Event_Nonexist; }
| PACKETIN { mailset.events |= Event_PacketIn; }
| PACKETOUT { mailset.events |= Event_PacketOut; }
| PERMISSION { mailset.events |= Event_Permission; }
| PID { mailset.events |= Event_Pid; }
| PPID { mailset.events |= Event_PPid; }
| RESOURCE { mailset.events |= Event_Resource; }
| SATURATION { mailset.events |= Event_Saturation; }
| SIZE { mailset.events |= Event_Size; }
| SPEED { mailset.events |= Event_Speed; }
| STATUS { mailset.events |= Event_Status; }
| TIMEOUT { mailset.events |= Event_Timeout; }
| TIMESTAMP { mailset.events |= Event_Timestamp; }
| UID { mailset.events |= Event_Uid; }
| UPTIME { mailset.events |= Event_Uptime; }
;
formatlist : /* EMPTY */
| MAILFORMAT '{' formatoptionlist '}'
;
formatoptionlist: formatoption
| formatoptionlist formatoption
;
formatoption : MAILFROM { mailset.from = $1; }
| MAILREPLYTO { mailset.replyto = $1; }
| MAILSUBJECT { mailset.subject = $1; }
| MAILBODY { mailset.message = $1; }
;
every : EVERY NUMBER CYCLE {
current->every.type = Every_SkipCycles;
current->every.spec.cycle.number = $2;
}
| EVERY TIMESPEC {
current->every.type = Every_Cron;
current->every.spec.cron = $2;
}
| NOTEVERY TIMESPEC {
current->every.type = Every_NotInCron;
current->every.spec.cron = $2;
}
;
mode : MODE ACTIVE {
current->mode = Monitor_Active;
}
| MODE PASSIVE {
current->mode = Monitor_Passive;
}
| MODE MANUAL {
current->mode = Monitor_Manual;
current->monitor = Monitor_Not;
}
;
group : GROUP STRINGNAME {
addservicegroup($2);
FREE($2);
}
;
depend : DEPENDS dependlist
;
dependlist : dependant
| dependlist dependant
;
dependant : SERVICENAME { adddependant($1); }
;
statusvalue : IF STATUS operator NUMBER rate1 THEN action1 recovery {
statusset.initialized = true;
statusset.operator = $3;
statusset.return_value = $4;
addeventaction(&(statusset).action, $7, $8);
addstatus(&statusset);
}
| IF CHANGED STATUS rate1 THEN action1 {
statusset.initialized = false;
statusset.operator = Operator_Changed;
statusset.return_value = 0;
addeventaction(&(statusset).action, $6, Action_Ignored);
addstatus(&statusset);
}
;
resourceprocess : IF resourceprocesslist rate1 THEN action1 recovery {
addeventaction(&(resourceset).action, $5, $6);
addresource(&resourceset);
}
;
resourceprocesslist : resourceprocessopt
| resourceprocesslist resourceprocessopt
;
resourceprocessopt : resourcecpuproc
| resourcemem
| resourcethreads
| resourcechild
| resourceload
;
resourcesystem : IF resourcesystemlist rate1 THEN action1 recovery {
addeventaction(&(resourceset).action, $5, $6);
addresource(&resourceset);
}
;
resourcesystemlist : resourcesystemopt
| resourcesystemlist resourcesystemopt
;
resourcesystemopt : resourceload
| resourcemem
| resourceswap
| resourcecpu
;
resourcecpuproc : CPU operator NUMBER PERCENT {
resourceset.resource_id = Resource_CpuPercent;
resourceset.operator = $2;
resourceset.limit = $3;
}
| TOTALCPU operator NUMBER PERCENT {
resourceset.resource_id = Resource_CpuPercentTotal;
resourceset.operator = $2;
resourceset.limit = $3;
}
;
resourcecpu : resourcecpuid operator NUMBER PERCENT {
resourceset.resource_id = $1;
resourceset.operator = $2;
resourceset.limit = $3;
}
;
resourcecpuid : CPUUSER { $$ = Resource_CpuUser; }
| CPUSYSTEM { $$ = Resource_CpuSystem; }
| CPUWAIT { $$ = Resource_CpuWait; }
| CPU { $$ = Resource_CpuPercent; }
;
resourcemem : MEMORY operator value unit {
resourceset.resource_id = Resource_MemoryKbyte;
resourceset.operator = $2;
resourceset.limit = $3 * $4;
}
| MEMORY operator NUMBER PERCENT {
resourceset.resource_id = Resource_MemoryPercent;
resourceset.operator = $2;
resourceset.limit = $3;
}
| TOTALMEMORY operator value unit {
resourceset.resource_id = Resource_MemoryKbyteTotal;
resourceset.operator = $2;
resourceset.limit = $3 * $4;
}
| TOTALMEMORY operator NUMBER PERCENT {
resourceset.resource_id = Resource_MemoryPercentTotal;
resourceset.operator = $2;
resourceset.limit = $3;
}
;
resourceswap : SWAP operator value unit {
resourceset.resource_id = Resource_SwapKbyte;
resourceset.operator = $2;
resourceset.limit = $3 * $4;
}
| SWAP operator NUMBER PERCENT {
resourceset.resource_id = Resource_SwapPercent;
resourceset.operator = $2;
resourceset.limit = $3;
}
;
resourcethreads : THREADS operator NUMBER {
resourceset.resource_id = Resource_Threads;
resourceset.operator = $2;
resourceset.limit = $3;
}
;
resourcechild : CHILDREN operator NUMBER {
resourceset.resource_id = Resource_Children;
resourceset.operator = $2;
resourceset.limit = $3;
}
;
resourceload : resourceloadavg operator value {
resourceset.resource_id = $1;
resourceset.operator = $2;
resourceset.limit = $3;
}
;
resourceloadavg : LOADAVG1 { $$ = Resource_LoadAverage1m; }
| LOADAVG5 { $$ = Resource_LoadAverage5m; }
| LOADAVG15 { $$ = Resource_LoadAverage15m; }
;
value : REAL { $$ = $1; }
| NUMBER { $