1 /*
2 * Copyright (C) Tildeslash Ltd. All rights reserved.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU Affero General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * In addition, as a special exception, the copyright holders give
16 * permission to link the code of portions of this program with the
17 * OpenSSL library under certain conditions as described in each
18 * individual source file, and distribute linked combinations
19 * including the two.
20 *
21 * You must obey the GNU Affero General Public License in all respects
22 * for all of the code used other than OpenSSL.
23 */
24
25 #include "config.h"
26
27 #ifdef HAVE_STDIO_H
28 #include <stdio.h>
29 #endif
30
31 #ifdef HAVE_STDARG_H
32 #include <stdarg.h>
33 #endif
34
35 #ifdef HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38
39 #ifdef HAVE_CTYPE_H
40 #include <ctype.h>
41 #endif
42
43 #ifdef HAVE_SIGNAL_H
44 #include <signal.h>
45 #endif
46
47 #ifdef HAVE_STDLIB_H
48 #include <stdlib.h>
49 #endif
50
51 #ifdef HAVE_SYS_SOCKET_H
52 #include <sys/socket.h>
53 #endif
54
55 #ifdef HAVE_FCNTL_H
56 #include <fcntl.h>
57 #endif
58
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62
63 #ifdef HAVE_STRING_H
64 #include <string.h>
65 #endif
66
67 #ifdef HAVE_STRINGS_H
68 #include <strings.h>
69 #endif
70
71 #ifdef HAVE_SYS_TYPES_H
72 #include <sys/types.h>
73 #endif
74
75 #ifdef HAVE_NETDB_H
76 #include <netdb.h>
77 #endif
78
79 #ifdef HAVE_SYS_STAT_H
80 #include <sys/stat.h>
81 #endif
82
83 #ifdef HAVE_CRYPT_H
84 #include <crypt.h>
85 #endif
86
87 #ifdef HAVE_NETINET_IN_H
88 #include <netinet/in.h>
89 #endif
90
91 #ifdef HAVE_ARPA_INET_H
92 #include <arpa/inet.h>
93 #endif
94
95 #ifdef HAVE_PAM_PAM_APPL_H
96 #include <pam/pam_appl.h>
97 #endif
98
99 #ifdef HAVE_SECURITY_PAM_APPL_H
100 #include <security/pam_appl.h>
101 #endif
102
103 #ifdef HAVE_PWD_H
104 #include <pwd.h>
105 #endif
106
107 #ifdef HAVE_GRP_H
108 #include <grp.h>
109 #endif
110
111 #include "monit.h"
112 #include "engine.h"
113 #include "md5.h"
114 #include "md5_crypt.h"
115 #include "sha1.h"
116 #include "base64.h"
117 #include "alert.h"
118 #include "ProcessTree.h"
119 #include "event.h"
120 #include "state.h"
121 #include "protocol.h"
122 #include "checksum.h"
123
124 // libmonit
125 #include "io/File.h"
126 #include "util/Convert.h"
127 #include "system/Time.h"
128 #include "exceptions/AssertException.h"
129 #include "exceptions/IOException.h"
130
131
132 struct ad_user {
133 const char *login;
134 const char *passwd;
135 };
136
137
138 /* Unsafe URL characters: [00-1F, 7F-FF] <>\"#%}{|\\^[] ` */
139 static const unsigned char urlunsafe[256] = {
140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
146 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
148 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
149 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
150 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
151 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
152 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
153 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
154 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
155 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
156 };
157
158
159 /* Unsafe URL characters for parameter value: [00-1F, 7F-FF] ?=&/<>\"#%}{|\\^[] ` */
160 static const unsigned char urlunsafeparameter[256] = {
161 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
162 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
163 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
165 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
167 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
169 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
170 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
171 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
175 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
176 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
177 };
178
179
180 static const unsigned char b2x[][256] = {
181 "00", "01", "02", "03", "04", "05", "06", "07",
182 "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
183 "10", "11", "12", "13", "14", "15", "16", "17",
184 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
185 "20", "21", "22", "23", "24", "25", "26", "27",
186 "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
187 "30", "31", "32", "33", "34", "35", "36", "37",
188 "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
189 "40", "41", "42", "43", "44", "45", "46", "47",
190 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
191 "50", "51", "52", "53", "54", "55", "56", "57",
192 "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
193 "60", "61", "62", "63", "64", "65", "66", "67",
194 "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
195 "70", "71", "72", "73", "74", "75", "76", "77",
196 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
197 "80", "81", "82", "83", "84", "85", "86", "87",
198 "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
199 "90", "91", "92", "93", "94", "95", "96", "97",
200 "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
201 "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
202 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
203 "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
204 "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
205 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
206 "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
207 "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
208 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
209 "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7",
210 "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
211 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
212 "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
213 };
214
215
216 /**
217 * General purpose utility methods.
218 *
219 * @file
220 */
221
222
223 /* ----------------------------------------------------------------- Private */
224
225
226 /**
227 * Returns the value of the parameter if defined or the String "(not
228 * defined)"
229 */
is_str_defined(const char * s)230 static const char *is_str_defined(const char *s) {
231 return((s && *s) ? s : "(not defined)");
232 }
233
234
235 /**
236 * Convert a hex char to a char
237 */
_x2c(char * hex)238 static char _x2c(char *hex) {
239 register char digit;
240 digit = ((hex[0] >= 'A') ? ((hex[0] & 0xdf) - 'A')+10 : (hex[0] - '0'));
241 digit *= 16;
242 digit += (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A')+10 : (hex[1] - '0'));
243 return(digit);
244 }
245
246
247 /**
248 * Print registered events list
249 */
printevents(unsigned int events)250 static void printevents(unsigned int events) {
251 if (events == Event_Null) {
252 printf("No events");
253 } else if (events == Event_All) {
254 printf("All events");
255 } else {
256 if (IS_EVENT_SET(events, Event_Action))
257 printf("Action ");
258 if (IS_EVENT_SET(events, Event_ByteIn))
259 printf("ByteIn ");
260 if (IS_EVENT_SET(events, Event_ByteOut))
261 printf("ByteOut ");
262 if (IS_EVENT_SET(events, Event_Checksum))
263 printf("Checksum ");
264 if (IS_EVENT_SET(events, Event_Connection))
265 printf("Connection ");
266 if (IS_EVENT_SET(events, Event_Content))
267 printf("Content ");
268 if (IS_EVENT_SET(events, Event_Data))
269 printf("Data ");
270 if (IS_EVENT_SET(events, Event_Exec))
271 printf("Exec ");
272 if (IS_EVENT_SET(events, Event_Exist))
273 printf("Exist ");
274 if (IS_EVENT_SET(events, Event_FsFlag))
275 printf("Fsflags ");
276 if (IS_EVENT_SET(events, Event_Gid))
277 printf("Gid ");
278 if (IS_EVENT_SET(events, Event_Icmp))
279 printf("Icmp ");
280 if (IS_EVENT_SET(events, Event_Instance))
281 printf("Instance ");
282 if (IS_EVENT_SET(events, Event_Invalid))
283 printf("Invalid ");
284 if (IS_EVENT_SET(events, Event_Link))
285 printf("Link ");
286 if (IS_EVENT_SET(events, Event_NonExist))
287 printf("Nonexist ");
288 if (IS_EVENT_SET(events, Event_PacketIn))
289 printf("PacketIn ");
290 if (IS_EVENT_SET(events, Event_PacketOut))
291 printf("PacketOut ");
292 if (IS_EVENT_SET(events, Event_Permission))
293 printf("Permission ");
294 if (IS_EVENT_SET(events, Event_Pid))
295 printf("PID ");
296 if (IS_EVENT_SET(events, Event_PPid))
297 printf("PPID ");
298 if (IS_EVENT_SET(events, Event_Resource))
299 printf("Resource ");
300 if (IS_EVENT_SET(events, Event_Saturation))
301 printf("Saturation ");
302 if (IS_EVENT_SET(events, Event_Size))
303 printf("Size ");
304 if (IS_EVENT_SET(events, Event_Speed))
305 printf("Speed ");
306 if (IS_EVENT_SET(events, Event_Status))
307 printf("Status ");
308 if (IS_EVENT_SET(events, Event_Timeout))
309 printf("Timeout ");
310 if (IS_EVENT_SET(events, Event_Timestamp))
311 printf("Timestamp ");
312 if (IS_EVENT_SET(events, Event_Uid))
313 printf("Uid ");
314 if (IS_EVENT_SET(events, Event_Uptime))
315 printf("Uptime ");
316
317 }
318 printf("\n");
319 }
320
321
322 #ifdef HAVE_LIBPAM
323 /**
324 * PAM conversation
325 */
326 #if defined(SOLARIS) || defined(AIX)
PAMquery(int num_msg,struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)327 static int PAMquery(int num_msg, struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {
328 #else
329 static int PAMquery(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {
330 #endif
331 int i;
332 struct ad_user *user = (struct ad_user *)appdata_ptr;
333 struct pam_response *response;
334
335 /* Sanity checking */
336 if (! msg || ! resp || ! user )
337 return PAM_CONV_ERR;
338
339 response = CALLOC(sizeof(struct pam_response), num_msg);
340
341 for (i = 0; i < num_msg; i++) {
342 response[i].resp = NULL;
343 response[i].resp_retcode = 0;
344
345 switch ((*(msg[i])).msg_style) {
346 case PAM_PROMPT_ECHO_ON:
347 /* Store the login as the response. This likely never gets called, since login was on pam_start() */
348 response[i].resp = appdata_ptr ? Str_dup(user->login) : NULL;
349 break;
350
351 case PAM_PROMPT_ECHO_OFF:
352 /* Store the password as the response */
353 response[i].resp = appdata_ptr ? Str_dup(user->passwd) : NULL;
354 break;
355
356 case PAM_TEXT_INFO:
357 case PAM_ERROR_MSG:
358 /* Shouldn't happen since we have PAM_SILENT set. If it happens anyway, ignore it. */
359 break;
360
361 default:
362 /* Something strange... */
363 FREE(response);
364 return PAM_CONV_ERR;
365 }
366 }
367 /* On success, return the response structure */
368 *resp = response;
369 return PAM_SUCCESS;
370 }
371
372
373 /**
374 * Validate login/passwd via PAM service "monit"
375 */
376 static bool PAMcheckPasswd(const char *login, const char *passwd) {
377 int rv;
378 pam_handle_t *pamh = NULL;
379 struct ad_user user_info = {
380 login,
381 passwd
382 };
383 struct pam_conv conv = {
384 PAMquery,
385 &user_info
386 };
387
388 if ((rv = pam_start("monit", login, &conv, &pamh) != PAM_SUCCESS)) {
389 DEBUG("PAM authentication start failed -- %d\n", rv);
390 return false;
391 }
392
393 rv = pam_authenticate(pamh, PAM_SILENT);
394
395 if (pam_end(pamh, rv) != PAM_SUCCESS)
396 pamh = NULL;
397
398 return rv == PAM_SUCCESS ? true : false;
399 }
400
401
402 /**
403 * Check whether the user is member of allowed groups
404 */
405 static Auth_T PAMcheckUserGroup(const char *uname) {
406 Auth_T c = Run.httpd.credentials;
407 struct passwd *pwd = NULL;
408 struct group *grp = NULL;
409
410 ASSERT(uname);
411
412 if (! (pwd = getpwnam(uname)))
413 return NULL;
414
415 if (! (grp = getgrgid(pwd->pw_gid)))
416 return NULL;
417
418 while (c) {
419 if (c->groupname) {
420 struct group *sgrp = NULL;
421
422 /* check for primary group match */
423 if (IS(c->groupname, grp->gr_name))
424 return c;
425
426 /* check secondary groups match */
427 if ((sgrp = getgrnam(c->groupname))) {
428 char **g = NULL;
429
430 for (g = sgrp->gr_mem; *g; g++)
431 if (IS(*g, uname))
432 return c;
433 }
434 }
435 c = c->next;
436 }
437 return NULL;
438 }
439 #endif
440
441
442 /* ------------------------------------------------------------------ Public */
443
444
445 char *Util_replaceString(char **src, const char *old, const char *new) {
446 ASSERT(src);
447 ASSERT(*src);
448 ASSERT(old);
449 ASSERT(new);
450
451 int i = Util_countWords(*src, old);
452 if (i) {
453 size_t l = strlen(old);
454 size_t d = strlen(new) - l;
455 if (d > 0) {
456 d *= i;
457 } else {
458 d = 0;
459 }
460 char *buf = CALLOC(sizeof(char), strlen(*src) + d + 1);
461 char *p;
462 char *q = *src;
463 *buf = 0;
464 while ((p = strstr(q, old))) {
465 *p = 0;
466 strcat(buf, q);
467 strcat(buf, new);
468 p += l;
469 q = p;
470 }
471 strcat(buf, q);
472 FREE(*src);
473 *src = buf;
474 }
475 return *src;
476 }
477
478
479 int Util_countWords(char *s, const char *word) {
480 int i = 0;
481 char *p = s;
482
483 ASSERT(s && word);
484
485 while ((p = strstr(p, word))) { i++; p++; }
486 return i;
487 }
488
489
490 void Util_handleEscapes(char *buf) {
491 int editpos;
492 int insertpos;
493
494 ASSERT(buf);
495
496 for (editpos = insertpos = 0; *(buf + editpos) != '\0'; editpos++, insertpos++) {
497 if (*(buf + editpos) == '\\' ) {
498 switch (*(buf + editpos + 1)) {
499 case 'n':
500 *(buf + insertpos) = '\n';
501 editpos++;
502 break;
503
504 case 't':
505 *(buf + insertpos) = '\t';
506 editpos++;
507 break;
508
509 case 'r':
510 *(buf + insertpos) = '\r';
511 editpos++;
512 break;
513
514 case ' ':
515 *(buf + insertpos) = ' ';
516 editpos++;
517 break;
518
519 case '0':
520 if (*(buf + editpos+2) == 'x') {
521 if ((*(buf + editpos + 3) == '0' && *(buf + editpos + 4) == '0')) {
522 /* Don't swap \0x00 with 0 to avoid truncating the string.
523 Currently the only place where we support sending of 0 bytes
524 is in check_generic(). The \0x00 -> 0 byte swap is performed
525 there and in-place.
526 */
527 *(buf + insertpos) = *(buf+editpos);
528 } else {
529 *(buf + insertpos) = _x2c(&buf[editpos + 3]);
530 editpos += 4;
531 }
532 }
533 break;
534
535 case '\\':
536 *(buf + insertpos) = '\\';
537 editpos++;
538 break;
539
540 default:
541 *(buf + insertpos) = *(buf + editpos);
542
543 }
544
545 } else {
546 *(buf + insertpos) = *(buf + editpos);
547 }
548
549 }
550 *(buf + insertpos) = '\0';
551 }
552
553
554 int Util_handle0Escapes(char *buf) {
555 int editpos;
556 int insertpos;
557
558 ASSERT(buf);
559
560 for (editpos = insertpos = 0; *(buf + editpos) != '\0'; editpos++, insertpos++) {
561 if (*(buf + editpos) == '\\' ) {
562 switch (*(buf + editpos + 1)) {
563 case '0':
564 if (*(buf + editpos + 2) == 'x') {
565 *(buf + insertpos) = _x2c(&buf[editpos+3]);
566 editpos += 4;
567 }
568 break;
569
570 default:
571 *(buf + insertpos) = *(buf + editpos);
572
573 }
574
575 } else {
576 *(buf + insertpos) = *(buf + editpos);
577 }
578 }
579 *(buf + insertpos) = '\0';
580 return insertpos;
581 }
582
583
584 Service_T Util_getService(const char *name) {
585 ASSERT(name);
586 for (Service_T s = servicelist; s; s = s->next)
587 if (IS(s->name, name))
588 return s;
589 return NULL;
590 }
591
592
593 int Util_getNumberOfServices() {
594 int i = 0;
595 Service_T s;
596 for (s = servicelist; s; s = s->next)
597 i += 1;
598 return i;
599 }
600
601
602 bool Util_existService(const char *name) {
603 ASSERT(name);
604 return Util_getService(name) ? true : false;
605 }
606
607
608 void Util_printRunList() {
609 char buf[10];
610 printf("Runtime constants:\n");
611 printf(" %-18s = %s\n", "Control file", is_str_defined(Run.files.control));
612 printf(" %-18s = %s\n", "Log file", is_str_defined(Run.files.log));
613 printf(" %-18s = %s\n", "Pid file", is_str_defined(Run.files.pid));
614 printf(" %-18s = %s\n", "Id file", is_str_defined(Run.files.id));
615 printf(" %-18s = %s\n", "State file", is_str_defined(Run.files.state));
616 printf(" %-18s = %s\n", "Debug", Run.debug ? "True" : "False");
617 printf(" %-18s = %s\n", "Log", (Run.flags & Run_Log) ? "True" : "False");
618 printf(" %-18s = %s\n", "Use syslog", (Run.flags & Run_UseSyslog) ? "True" : "False");
619 printf(" %-18s = %s\n", "Is Daemon", (Run.flags & Run_Daemon) ? "True" : "False");
620 printf(" %-18s = %s\n", "Use process engine", (Run.flags & Run_ProcessEngineEnabled) ? "True" : "False");
621 printf(" %-18s = {\n", "Limits");
622 printf(" %-18s = programOutput: %s\n", " ", Convert_bytes2str(Run.limits.programOutput, buf));
623 printf(" %-18s = sendExpectBuffer: %s\n", " ", Convert_bytes2str(Run.limits.sendExpectBuffer, buf));
624 printf(" %-18s = fileContentBuffer: %s\n", " ", Convert_bytes2str(Run.limits.fileContentBuffer, buf));
625 printf(" %-18s = httpContentBuffer: %s\n", " ", Convert_bytes2str(Run.limits.httpContentBuffer, buf));
626 printf(" %-18s = networkTimeout: %s\n", " ", Convert_time2str(Run.limits.networkTimeout, (char[11]){}));
627 printf(" %-18s = programTimeout: %s\n", " ", Convert_time2str(Run.limits.programTimeout, (char[11]){}));
628 printf(" %-18s = stopTimeout: %s\n", " ", Convert_time2str(Run.limits.stopTimeout, (char[11]){}));
629 printf(" %-18s = startTimeout: %s\n", " ", Convert_time2str(Run.limits.startTimeout, (char[11]){}));
630 printf(" %-18s = restartTimeout: %s\n", " ", Convert_time2str(Run.limits.restartTimeout, (char[11]){}));
631 printf(" %-18s = }\n", " ");
632 printf(" %-18s = %s\n", "On reboot", onrebootnames[Run.onreboot]);
633 printf(" %-18s = %d seconds with start delay %d seconds\n", "Poll time", Run.polltime, Run.startdelay);
634
635 if (Run.eventlist_dir) {
636 char slots[STRLEN];
637
638 if (Run.eventlist_slots < 0)
639 snprintf(slots, STRLEN, "unlimited");
640 else
641 snprintf(slots, STRLEN, "%d", Run.eventlist_slots);
642
643 printf(" %-18s = base directory %s with %s slots\n",
644 "Event queue", Run.eventlist_dir, slots);
645 }
646 #ifdef HAVE_OPENSSL
647 {
648 const char *options = Ssl_printOptions(&(Run.ssl), (char[STRLEN]){}, STRLEN);
649 if (options && *options)
650 printf(" %-18s = %s\n", "SSL options", options);
651 }
652 #endif
653 if (Run.mmonits) {
654 Mmonit_T c;
655 printf(" %-18s = ", "M/Monit(s)");
656 for (c = Run.mmonits; c; c = c->next) {
657 printf("%s with timeout %s", c->url->url, Convert_time2str(c->timeout, (char[11]){}));
658 #ifdef HAVE_OPENSSL
659 if (c->ssl.flags) {
660 printf(" using TLS");
661 const char *options = Ssl_printOptions(&c->ssl, (char[STRLEN]){}, STRLEN);
662 if (options && *options)
663 printf(" with options {%s}", options);
664 if (c->ssl.checksum)
665 printf(" and certificate checksum %s equal to '%s'", checksumnames[c->ssl.checksumType], c->ssl.checksum);
666 }
667 #endif
668 if (Run.flags & Run_MmonitCredentials && c->url->user)
669 printf(" with credentials");
670 if (c->next)
671 printf(",\n = ");
672 }
673 printf("\n");
674 }
675
676 if (Run.mailservers) {
677 MailServer_T mta;
678 printf(" %-18s = ", "Mail server(s)");
679 for (mta = Run.mailservers; mta; mta = mta->next) {
680 printf("%s:%d", mta->host, mta->port);
681 #ifdef HAVE_OPENSSL
682 if (mta->ssl.flags) {
683 printf(" using TLS");
684 const char *options = Ssl_printOptions(&mta->ssl, (char[STRLEN]){}, STRLEN);
685 if (options && *options)
686 printf(" with options {%s}", options);
687 if (mta->ssl.checksum)
688 printf(" and certificate checksum %s equal to '%s'", checksumnames[mta->ssl.checksumType], mta->ssl.checksum);
689 }
690 #endif
691 if (mta->next)
692 printf(", ");
693 }
694 printf(" with timeout %s", Convert_time2str(Run.mailserver_timeout, (char[11]){}));
695 if (Run.mail_hostname)
696 printf(" using '%s' as my hostname", Run.mail_hostname);
697 printf("\n");
698 }
699
700 if (Run.MailFormat.from) {
701 if (Run.MailFormat.from->name)
702 printf(" %-18s = %s <%s>\n", "Mail from", Run.MailFormat.from->name, Run.MailFormat.from->address);
703 else
704 printf(" %-18s = %s\n", "Mail from", Run.MailFormat.from->address);
705 }
706 if (Run.MailFormat.replyto) {
707 if (Run.MailFormat.replyto->name)
708 printf(" %-18s = %s <%s>\n", "Mail reply to", Run.MailFormat.replyto->name, Run.MailFormat.replyto->address);
709 else
710 printf(" %-18s = %s\n", "Mail reply to", Run.MailFormat.replyto->address);
711 }
712 if (Run.MailFormat.subject)
713 printf(" %-18s = %s\n", "Mail subject", Run.MailFormat.subject);
714 if (Run.MailFormat.message)
715 printf(" %-18s = %-.20s..(truncated)\n", "Mail message", Run.MailFormat.message);
716
717 printf(" %-18s = %s\n", "Start monit httpd", (Run.httpd.flags & Httpd_Net || Run.httpd.flags & Httpd_Unix) ? "True" : "False");
718
719 if (Run.httpd.flags & Httpd_Net || Run.httpd.flags & Httpd_Unix) {
720 if (Run.httpd.flags & Httpd_Net) {
721 printf(" %-18s = %s\n", "httpd bind address", Run.httpd.socket.net.address ? Run.httpd.socket.net.address : "Any/All");
722 printf(" %-18s = %d\n", "httpd portnumber", Run.httpd.socket.net.port);
723 #ifdef HAVE_OPENSSL
724 const char *options = Ssl_printOptions(&(Run.httpd.socket.net.ssl), (char[STRLEN]){}, STRLEN);
725 if (options && *options)
726 printf(" %-18s = %s\n", "httpd encryption", options);
727 #endif
728 }
729 if (Run.httpd.flags & Httpd_Unix)
730 printf(" %-18s = %s\n", "httpd unix socket", Run.httpd.socket.unix.path);
731 printf(" %-18s = %s\n", "httpd signature", Run.httpd.flags & Httpd_Signature ? "Enabled" : "Disabled");
732 printf(" %-18s = %s\n", "httpd auth. style",
733 Run.httpd.credentials && Engine_hasAllow() ? "Basic Authentication and Host/Net allow list" : Run.httpd.credentials ? "Basic Authentication" : Engine_hasAllow() ? "Host/Net allow list" : "No authentication!");
734
735 }
736
737 {
738 for (Mail_T list = Run.maillist; list; list = list->next) {
739 printf(" %-18s = %s\n", "Alert mail to", is_str_defined(list->to));
740 printf(" %-16s = ", "Alert on");
741 printevents(list->events);
742 if (list->reminder)
743 printf(" %-16s = %u cycles\n", "Alert reminder", list->reminder);
744 }
745 }
746
747 printf("\n");
748 }
749
750
751 void Util_printService(Service_T s) {
752 ASSERT(s);
753
754 bool sgheader = false;
755 char buffer[STRLEN];
756 StringBuffer_T buf = StringBuffer_create(STRLEN);
757
758 printf("%-21s = %s\n", StringBuffer_toString(StringBuffer_append(buf, "%s Name", servicetypes[s->type])), s->name);
759
760 for (ServiceGroup_T o = servicegrouplist; o; o = o->next) {
761 for (list_t m = o->members->head; m; m = m->next) {
762 if (m->e == s) {
763 if (! sgheader) {
764 printf(" %-20s = %s", "Group", o->name);
765 sgheader = true;
766 } else {
767 printf(", %s", o->name);
768 }
769 }
770 }
771 }
772 if (sgheader)
773 printf("\n");
774
775 if (s->type == Service_Process) {
776 if (s->matchlist)
777 printf(" %-20s = %s\n", "Match", s->path);
778 else
779 printf(" %-20s = %s\n", "Pid file", s->path);
780 } else if (s->type == Service_Host) {
781 printf(" %-20s = %s\n", "Address", s->path);
782 } else if (s->type == Service_Net) {
783 printf(" %-20s = %s\n", "Interface", s->path);
784 } else if (s->type != Service_System) {
785 printf(" %-20s = %s\n", "Path", s->path);
786 }
787 printf(" %-20s = %s\n", "Monitoring mode", modenames[s->mode]);
788 printf(" %-20s = %s\n", "On reboot", onrebootnames[s->onreboot]);
789 if (s->start) {
790 printf(" %-20s = '%s'", "Start program", Util_commandDescription(s->start, (char[STRLEN]){}));
791 if (s->start->has_uid)
792 printf(" as uid %d", s->start->uid);
793 if (s->start->has_gid)
794 printf(" as gid %d", s->start->gid);
795 printf(" timeout %s", Convert_time2str(s->start->timeout, (char[11]){}));
796 printf("\n");
797 }
798 if (s->stop) {
799 printf(" %-20s = '%s'", "Stop program", Util_commandDescription(s->stop, (char[STRLEN]){}));
800 if (s->stop->has_uid)
801 printf(" as uid %d", s->stop->uid);
802 if (s->stop->has_gid)
803 printf(" as gid %d", s->stop->gid);
804 printf(" timeout %s", Convert_time2str(s->stop->timeout, (char[11]){}));
805 printf("\n");
806 }
807 if (s->restart) {
808 printf(" %-20s = '%s'", "Restart program", Util_commandDescription(s->restart, (char[STRLEN]){}));
809 if (s->restart->has_uid)
810 printf(" as uid %d", s->restart->uid);
811 if (s->restart->has_gid)
812 printf(" as gid %d", s->restart->gid);
813 printf(" timeout %s", Convert_time2str(s->restart->timeout, (char[11]){}));
814 printf("\n");
815 }
816
817 for (NonExist_T o = s->nonexistlist; o; o = o->next) {
818 StringBuffer_clear(buf);
819 printf(" %-20s = %s\n", "Existence", StringBuffer_toString(Util_printRule(false, buf, o->action, "if does not exist")));
820 }
821
822 for (Exist_T o = s->existlist; o; o = o->next) {
823 StringBuffer_clear(buf);
824 printf(" %-20s = %s\n", "Non-Existence", StringBuffer_toString(Util_printRule(false, buf, o->action, "if exist")));
825 }
826
827 for (Dependant_T o = s->dependantlist; o; o = o->next)
828 if (o->dependant != NULL)
829 printf(" %-20s = %s\n", "Depends on Service", o->dependant);
830
831 for (Pid_T o = s->pidlist; o; o = o->next) {
832 StringBuffer_clear(buf);
833 printf(" %-20s = %s\n", "Pid", StringBuffer_toString(Util_printRule(false, buf, o->action, "if changed")));
834 }
835
836 for (Pid_T o = s->ppidlist; o; o = o->next) {
837 StringBuffer_clear(buf);
838 printf(" %-20s = %s\n", "PPid", StringBuffer_toString(Util_printRule(false, buf, o->action, "if changed")));
839 }
840
841 for (FsFlag_T o = s->fsflaglist; o; o = o->next) {
842 StringBuffer_clear(buf);
843 printf(" %-20s = %s\n", "Filesystem flags", StringBuffer_toString(Util_printRule(false, buf, o->action, "if changed")));
844 }
845
846 if (s->type == Service_Program) {
847 printf(" %-20s = ", "Program timeout");
848 printf("terminate the program if not finished within %s\n", Convert_time2str(s->program->timeout, (char[11]){}));
849 for (Status_T o = s->statuslist; o; o = o->next) {
850 StringBuffer_clear(buf);
851 if (o->operator == Operator_Changed)
852 printf(" %-20s = %s\n", "Status", StringBuffer_toString(Util_printRule(false, buf, o->action, "if exit value changed")));
853 else
854 printf(" %-20s = %s\n", "Status", StringBuffer_toString(Util_printRule(false, buf, o->action, "if exit value %s %d", operatorshortnames[o->operator], o->return_value)));
855 }
856 }
857
858 if (s->checksum && s->checksum->action) {
859 StringBuffer_clear(buf);
860 printf(" %-20s = %s\n", "Checksum",
861 s->checksum->test_changes
862 ?
863 StringBuffer_toString(Util_printRule(false, buf, s->checksum->action, "if changed %s", checksumnames[s->checksum->type]))
864 :
865 StringBuffer_toString(Util_printRule(false, buf, s->checksum->action, "if failed %s(%s)", s->checksum->hash, checksumnames[s->checksum->type]))
866 );
867 }
868
869 if (s->perm && s->perm->action) {
870 StringBuffer_clear(buf);
871 printf(" %-20s = %s\n", "Permission",
872 s->perm->test_changes
873 ?
874 StringBuffer_toString(Util_printRule(false, buf, s->perm->action, "if changed"))
875 :
876 StringBuffer_toString(Util_printRule(false, buf, s->perm->action, "if failed %04o", s->perm->perm))
877 );
878 }
879
880 if (s->uid && s->uid->action) {
881 StringBuffer_clear(buf);
882 printf(" %-20s = %s\n", "UID", StringBuffer_toString(Util_printRule(false, buf, s->uid->action, "if failed %d", s->uid->uid)));
883 }
884
885 if (s->euid && s->euid->action) {
886 StringBuffer_clear(buf);
887 printf(" %-20s = %s\n", "EUID", StringBuffer_toString(Util_printRule(false, buf, s->euid->action, "if failed %d", s->euid->uid)));
888 }
889
890 for (SecurityAttribute_T o = s->secattrlist; o; o = o->next) {
891 StringBuffer_clear(buf);
892 printf(" %-20s = %s\n", "Security attribute", StringBuffer_toString(Util_printRule(false, buf, o->action, "if failed %s", o->attribute)));
893 }
894
895 for (Filedescriptors_T o = s->filedescriptorslist; o; o = o->next) {
896 StringBuffer_clear(buf);
897 if (o->total) {
898 printf(" %-20s = %s\n", "Total filedescriptors", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld", operatornames[o->operator], o->limit_absolute)));
899 } else {
900 if (o->limit_absolute > -1)
901 printf(" %-20s = %s\n", "Filedescriptors", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld", operatornames[o->operator], o->limit_absolute)));
902 else
903 printf(" %-20s = %s\n", "Filedescriptors", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f%%", operatornames[o->operator], o->limit_percent)));
904 }
905 }
906
907 if (s->gid && s->gid->action) {
908 StringBuffer_clear(buf);
909 printf(" %-20s = %s\n", "GID", StringBuffer_toString(Util_printRule(false, buf, s->gid->action, "if failed %d", s->gid->gid)));
910 }
911
912 for (Icmp_T o = s->icmplist; o; o = o->next) {
913 StringBuffer_clear(buf);
914 StringBuffer_T buf2 = StringBuffer_create(64);
915 StringBuffer_append(buf2, "if %s count %d size %d with timeout %s", o->check_invers ? "succeeded" : "failed", o->count, o->size, Convert_time2str(o->timeout, (char[11]){}));
916 if (o->responsetime.limit > -1.)
917 StringBuffer_append(buf2, " and responsetime %s %s", operatornames[o->responsetime.operator], Convert_time2str(o->responsetime.limit, (char[11]){}));
918 if (o->outgoing.ip)
919 StringBuffer_append(buf2, " via address %s", o->outgoing.ip);
920 switch (o->family) {
921 case Socket_Ip4:
922 printf(" %-20s = %s\n", "Ping4", StringBuffer_toString(Util_printRule(o->check_invers, buf, o->action, "%s", StringBuffer_toString(buf2))));
923 break;
924 case Socket_Ip6:
925 printf(" %-20s = %s\n", "Ping6", StringBuffer_toString(Util_printRule(o->check_invers, buf, o->action, "%s", StringBuffer_toString(buf2))));
926 break;
927 default:
928 printf(" %-20s = %s\n", "Ping", StringBuffer_toString(Util_printRule(o->check_invers, buf, o->action, "%s", StringBuffer_toString(buf2))));
929 break;
930 }
931 StringBuffer_free(&buf2);
932 }
933
934 for (Port_T o = s->portlist; o; o = o->next) {
935 StringBuffer_clear(buf);
936 StringBuffer_T buf2 = StringBuffer_create(64);
937 StringBuffer_append(buf2, "if %s [%s]:%d%s",
938 o->check_invers ? "succeeded" : "failed", o->hostname, o->target.net.port, Util_portRequestDescription(o));
939 if (o->outgoing.ip)
940 StringBuffer_append(buf2, " via address %s", o->outgoing.ip);
941 StringBuffer_append(buf2, " type %s/%s protocol %s with timeout %s",
942 Util_portTypeDescription(o), Util_portIpDescription(o), o->protocol->name, Convert_time2str(o->timeout, (char[11]){}));
943 if (o->retry > 1)
944 StringBuffer_append(buf2, " and retry %d times", o->retry);
945 if (o->responsetime.limit > -1.)
946 StringBuffer_append(buf2, " and responsetime %s %s", operatornames[o->responsetime.operator], Convert_time2str(o->responsetime.limit, (char[11]){}));
947 #ifdef HAVE_OPENSSL
948 if (o->target.net.ssl.options.flags) {
949 StringBuffer_append(buf2, " using TLS");
950 const char *options = Ssl_printOptions(&o->target.net.ssl.options, (char[STRLEN]){}, STRLEN);
951 if (options && *options)
952 StringBuffer_append(buf2, " with options {%s}", options);
953 if (o->target.net.ssl.certificate.minimumDays > 0)
954 StringBuffer_append(buf2, " and certificate valid for at least %d days", o->target.net.ssl.certificate.minimumDays);
955 if (o->target.net.ssl.options.checksum)
956 StringBuffer_append(buf2, " and certificate checksum %s equal to '%s'", checksumnames[o->target.net.ssl.options.checksumType], o->target.net.ssl.options.checksum);
957 }
958 #endif
959 printf(" %-20s = %s\n", "Port", StringBuffer_toString(Util_printRule(o->check_invers, buf, o->action, "%s", StringBuffer_toString(buf2))));
960 StringBuffer_free(&buf2);
961 }
962
963 for (Port_T o = s->socketlist; o; o = o->next) {
964 StringBuffer_clear(buf);
965 StringBuffer_T buf2 = StringBuffer_create(64);
966 StringBuffer_append(buf2, "if %s %s type %s protocol %s with timeout %s", o->check_invers ? "succeeded" : "failed", o->target.unix.pathname, Util_portTypeDescription(o), o->protocol->name, Convert_time2str(o->timeout, (char[11]){}));
967 if (o->retry > 1)
968 StringBuffer_append(buf2, " and retry %d times", o->retry);
969 if (o->responsetime.limit > -1.)
970 StringBuffer_append(buf2, " and responsetime %s %s", operatornames[o->responsetime.operator], Convert_time2str(o->responsetime.limit, (char[11]){}));
971 printf(" %-20s = %s\n", "Unix Socket", StringBuffer_toString(Util_printRule(o->check_invers, buf, o->action, "%s", StringBuffer_toString(buf2))));
972 StringBuffer_free(&buf2);
973 }
974
975 for (Timestamp_T o = s->timestamplist; o; o = o->next) {
976 StringBuffer_clear(buf);
977 printf(" %-20s = %s\n", timestampnames[o->type],
978 o->test_changes
979 ?
980 StringBuffer_toString(Util_printRule(false, buf, o->action, "if changed"))
981 :
982 StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s", operatornames[o->operator], Convert_time2str(o->time * 1000., (char[11]){})))
983 );
984 }
985
986 for (Size_T o = s->sizelist; o; o = o->next) {
987 StringBuffer_clear(buf);
988 printf(" %-20s = %s\n", "Size",
989 o->test_changes
990 ?
991 StringBuffer_toString(Util_printRule(false, buf, o->action, "if changed"))
992 :
993 StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %llu byte(s)", operatornames[o->operator], o->size))
994 );
995 }
996
997 for (LinkStatus_T o = s->linkstatuslist; o; o = o->next) {
998 StringBuffer_clear(buf);
999 printf(" %-20s = %s\n", "Link status", StringBuffer_toString(Util_printRule(o->check_invers, buf, o->action, "if %s", o->check_invers ? "up" : "down")));
1000 }
1001
1002 for (LinkSpeed_T o = s->linkspeedlist; o; o = o->next) {
1003 StringBuffer_clear(buf);
1004 printf(" %-20s = %s\n", "Link capacity", StringBuffer_toString(Util_printRule(false, buf, o->action, "if changed")));
1005 }
1006
1007 for (LinkSaturation_T o = s->linksaturationlist; o; o = o->next) {
1008 StringBuffer_clear(buf);
1009 printf(" %-20s = %s\n", "Link utilization", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f%%", operatornames[o->operator], o->limit)));
1010 }
1011
1012 for (Bandwidth_T o = s->uploadbyteslist; o; o = o->next) {
1013 StringBuffer_clear(buf);
1014 if (o->range == Time_Second) {
1015 printf(" %-20s = %s\n", "Upload bytes", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s/s", operatornames[o->operator], Convert_bytes2str(o->limit, buffer))));
1016 } else {
1017 printf(" %-20s = %s\n", "Total upload bytes", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s in last %d %s(s)", operatornames[o->operator], Convert_bytes2str(o->limit, buffer), o->rangecount, Util_timestr(o->range))));
1018 }
1019 }
1020
1021 for (Bandwidth_T o = s->uploadpacketslist; o; o = o->next) {
1022 StringBuffer_clear(buf);
1023 if (o->range == Time_Second) {
1024 printf(" %-20s = %s\n", "Upload packets", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld packets/s", operatornames[o->operator], o->limit)));
1025 } else {
1026 printf(" %-20s = %s\n", "Total upload packets", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld packets in last %d %s(s)", operatornames[o->operator], o->limit, o->rangecount, Util_timestr(o->range))));
1027 }
1028 }
1029
1030 for (Bandwidth_T o = s->downloadbyteslist; o; o = o->next) {
1031 StringBuffer_clear(buf);
1032 if (o->range == Time_Second) {
1033 printf(" %-20s = %s\n", "Download bytes", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s/s", operatornames[o->operator], Convert_bytes2str(o->limit, buffer))));
1034 } else {
1035 printf(" %-20s = %s\n", "Total download bytes", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s in last %d %s(s)", operatornames[o->operator], Convert_bytes2str(o->limit, buffer), o->rangecount, Util_timestr(o->range))));
1036 }
1037 }
1038
1039 for (Bandwidth_T o = s->downloadpacketslist; o; o = o->next) {
1040 StringBuffer_clear(buf);
1041 if (o->range == Time_Second) {
1042 printf(" %-20s = %s\n", "Download packets", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld packets/s", operatornames[o->operator], o->limit)));
1043 } else {
1044 printf(" %-20s = %s\n", "Total downl. packets", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld packets in last %d %s(s)", operatornames[o->operator], o->limit, o->rangecount, Util_timestr(o->range))));
1045 }
1046 }
1047
1048 for (Uptime_T o = s->uptimelist; o; o = o->next) {
1049 StringBuffer_clear(buf);
1050 printf(" %-20s = %s\n", "Uptime", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %llu second(s)", operatornames[o->operator], o->uptime)));
1051 }
1052
1053 if (s->type != Service_Process) {
1054 for (Match_T o = s->matchignorelist; o; o = o->next) {
1055 StringBuffer_clear(buf);
1056 printf(" %-20s = %s\n", "Ignore content", StringBuffer_toString(Util_printRule(false, buf, o->action, "if content %s \"%s\"", o->not ? "!=" : "=", o->match_string)));
1057 }
1058 for (Match_T o = s->matchlist; o; o = o->next) {
1059 StringBuffer_clear(buf);
1060 printf(" %-20s = %s\n", "Content", StringBuffer_toString(Util_printRule(false, buf, o->action, "if content %s \"%s\"", o->not ? "!=" : "=", o->match_string)));
1061 }
1062 }
1063
1064 for (FileSystem_T o = s->filesystemlist; o; o = o->next) {
1065 StringBuffer_clear(buf);
1066 if (o->resource == Resource_Inode) {
1067 printf(" %-20s = %s\n", "Inodes usage limit",
1068 o->limit_absolute > -1
1069 ?
1070 StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld", operatornames[o->operator], o->limit_absolute))
1071 :
1072 StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f%%", operatornames[o->operator], o->limit_percent))
1073 );
1074 } else if (o->resource == Resource_InodeFree) {
1075 printf(" %-20s = %s\n", "Inodes free limit",
1076 o->limit_absolute > -1
1077 ?
1078 StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %lld", operatornames[o->operator], o->limit_absolute))
1079 :
1080 StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f%%", operatornames[o->operator], o->limit_percent))
1081 );
1082 } else if (o->resource == Resource_Space) {
1083 if (o->limit_absolute > -1) {
1084 printf(" %-20s = %s\n", "Space usage limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s", operatornames[o->operator], Convert_bytes2str(o->limit_absolute, buffer))));
1085 } else {
1086 printf(" %-20s = %s\n", "Space usage limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f%%", operatornames[o->operator], o->limit_percent)));
1087 }
1088 } else if (o->resource == Resource_SpaceFree) {
1089 if (o->limit_absolute > -1) {
1090 printf(" %-20s = %s\n", "Space free limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s", operatornames[o->operator], Convert_bytes2str(o->limit_absolute, buffer))));
1091 } else {
1092 printf(" %-20s = %s\n", "Space free limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f%%", operatornames[o->operator], o->limit_percent)));
1093 }
1094 } else if (o->resource == Resource_ReadBytes) {
1095 printf(" %-20s = %s\n", "Read limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if read %s %s/s", operatornames[o->operator], Convert_bytes2str(o->limit_absolute, (char[10]){}))));
1096 } else if (o->resource == Resource_ReadOperations) {
1097 printf(" %-20s = %s\n", "Read limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if read %s %llu operations/s", operatornames[o->operator], o->limit_absolute)));
1098 } else if (o->resource == Resource_WriteBytes) {
1099 printf(" %-20s = %s\n", "Write limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if write %s %s/s", operatornames[o->operator], Convert_bytes2str(o->limit_absolute, (char[10]){}))));
1100 } else if (o->resource == Resource_WriteOperations) {
1101 printf(" %-20s = %s\n", "Write limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if write %s %llu operations/s", operatornames[o->operator], o->limit_absolute)));
1102 } else if (o->resource == Resource_ServiceTime) {
1103 printf(" %-20s = %s\n", "Service time limit", StringBuffer_toString(Util_printRule(false, buf, o->action, "if service time %s %s/operation", operatornames[o->operator], Convert_time2str(o->limit_absolute, (char[11]){}))));
1104 }
1105 }
1106
1107 for (Resource_T o = s->resourcelist; o; o = o->next) {
1108 StringBuffer_clear(buf);
1109 switch (o->resource_id) {
1110 case Resource_CpuPercent:
1111 printf(" %-20s = ", "CPU usage limit");
1112 break;
1113
1114 case Resource_CpuPercentTotal:
1115 printf(" %-20s = ", "CPU usage limit (incl. children)");
1116 break;
1117
1118 case Resource_CpuUser:
1119 printf(" %-20s = ", "CPU user limit");
1120 break;
1121
1122 case Resource_CpuSystem:
1123 printf(" %-20s = ", "CPU system limit");
1124 break;
1125
1126 case Resource_CpuWait:
1127 printf(" %-20s = ", "CPU I/O wait limit");
1128 break;
1129
1130 case Resource_CpuNice:
1131 printf(" %-20s = ", "CPU nice limit");
1132 break;
1133
1134 case Resource_CpuHardIRQ:
1135 printf(" %-20s = ", "CPU hardware IRQ limit");
1136 break;
1137
1138 case Resource_CpuSoftIRQ:
1139 printf(" %-20s = ", "CPU software IRQ limit");
1140 break;
1141
1142 case Resource_CpuSteal:
1143 printf(" %-20s = ", "CPU steal limit");
1144 break;
1145
1146 case Resource_CpuGuest:
1147 printf(" %-20s = ", "CPU guest limit");
1148 break;
1149
1150 case Resource_CpuGuestNice:
1151 printf(" %-20s = ", "CPU guest nice limit");
1152 break;
1153
1154 case Resource_MemoryPercent:
1155 printf(" %-20s = ", "Memory usage limit");
1156 break;
1157
1158 case Resource_MemoryKbyte:
1159 printf(" %-20s = ", "Memory amount limit");
1160 break;
1161
1162 case Resource_SwapPercent:
1163 printf(" %-20s = ", "Swap usage limit");
1164 break;
1165
1166 case Resource_SwapKbyte:
1167 printf(" %-20s = ", "Swap amount limit");
1168 break;
1169
1170 case Resource_LoadAverage1m:
1171 printf(" %-20s = ", "Load avg (1m)");
1172 break;
1173
1174 case Resource_LoadAverage5m:
1175 printf(" %-20s = ", "Load avg (5m)");
1176 break;
1177
1178 case Resource_LoadAverage15m:
1179 printf(" %-20s = ", "Load avg (15m)");
1180 break;
1181
1182 case Resource_LoadAveragePerCore1m:
1183 printf(" %-20s = ", "Load avg/core (1m)");
1184 break;
1185
1186 case Resource_LoadAveragePerCore5m:
1187 printf(" %-20s = ", "Load avg/core (5m)");
1188 break;
1189
1190 case Resource_LoadAveragePerCore15m:
1191 printf(" %-20s = ", "Load avg/core (15m)");
1192 break;
1193
1194 case Resource_Threads:
1195 printf(" %-20s = ", "Threads");
1196 break;
1197
1198 case Resource_Children:
1199 printf(" %-20s = ", "Children");
1200 break;
1201
1202 case Resource_MemoryKbyteTotal:
1203 printf(" %-20s = ", "Memory amount limit (incl. children)");
1204 break;
1205
1206 case Resource_MemoryPercentTotal:
1207 printf(" %-20s = ", "Memory usage limit (incl. children)");
1208 break;
1209
1210 case Resource_ReadBytes:
1211 printf(" %-20s = ", "Read limit");
1212 break;
1213
1214 case Resource_ReadBytesPhysical:
1215 printf(" %-20s = ", "Disk read limit");
1216 break;
1217
1218 case Resource_ReadOperations:
1219 printf(" %-20s = ", "Disk read limit");
1220 break;
1221
1222 case Resource_WriteBytes:
1223 printf(" %-20s = ", "Write limit");
1224 break;
1225
1226 case Resource_WriteBytesPhysical:
1227 printf(" %-20s = ", "Disk write limit");
1228 break;
1229
1230 case Resource_WriteOperations:
1231 printf(" %-20s = ", "Disk write limit");
1232 break;
1233
1234 default:
1235 break;
1236 }
1237 switch (o->resource_id) {
1238 case Resource_CpuPercent:
1239 case Resource_CpuPercentTotal:
1240 case Resource_MemoryPercentTotal:
1241 case Resource_CpuUser:
1242 case Resource_CpuSystem:
1243 case Resource_CpuWait:
1244 case Resource_CpuNice:
1245 case Resource_CpuHardIRQ:
1246 case Resource_CpuSoftIRQ:
1247 case Resource_CpuSteal:
1248 case Resource_CpuGuest:
1249 case Resource_CpuGuestNice:
1250 case Resource_MemoryPercent:
1251 case Resource_SwapPercent:
1252 printf("%s", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f%%", operatornames[o->operator], o->limit)));
1253 break;
1254
1255 case Resource_MemoryKbyte:
1256 case Resource_SwapKbyte:
1257 case Resource_MemoryKbyteTotal:
1258 printf("%s", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s", operatornames[o->operator], Convert_bytes2str(o->limit, buffer))));
1259 break;
1260
1261 case Resource_LoadAverage1m:
1262 case Resource_LoadAverage5m:
1263 case Resource_LoadAverage15m:
1264 case Resource_LoadAveragePerCore1m:
1265 case Resource_LoadAveragePerCore5m:
1266 case Resource_LoadAveragePerCore15m:
1267 printf("%s", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.1f", operatornames[o->operator], o->limit)));
1268 break;
1269
1270 case Resource_Threads:
1271 case Resource_Children:
1272 printf("%s", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.0f", operatornames[o->operator], o->limit)));
1273 break;
1274
1275 case Resource_ReadBytes:
1276 case Resource_WriteBytes:
1277 printf("%s", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s/s", operatornames[o->operator], Convert_bytes2str(o->limit, (char[10]){}))));
1278 break;
1279
1280 case Resource_ReadBytesPhysical:
1281 case Resource_WriteBytesPhysical:
1282 printf("%s", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %s/s", operatornames[o->operator], Convert_bytes2str(o->limit, (char[10]){}))));
1283 break;
1284
1285 case Resource_ReadOperations:
1286 case Resource_WriteOperations:
1287 printf("%s", StringBuffer_toString(Util_printRule(false, buf, o->action, "if %s %.0f operations/s", operatornames[o->operator], o->limit)));
1288 break;
1289
1290 default:
1291 break;
1292 }
1293 printf("\n");
1294 }
1295
1296 if (s->every.type == Every_SkipCycles)
1297 printf(" %-20s = Check service every %d cycles\n", "Every", s->every.spec.cycle.number);
1298 else if (s->every.type == Every_Cron)
1299 printf(" %-20s = Check service every %s\n", "Every", s->every.spec.cron);
1300 else if (s->every.type == Every_NotInCron)
1301 printf(" %-20s = Don't check service every %s\n", "Every", s->every.spec.cron);
1302
1303 for (ActionRate_T o = s->actionratelist; o; o = o->next) {
1304 StringBuffer_clear(buf);
1305 printf(" %-20s = If restarted %d times within %d cycle(s) then %s\n", "Timeout", o->count, o->cycle, StringBuffer_toString(Util_printAction(o->action->failed, buf)));
1306 }
1307
1308 for (Mail_T o = s->maillist; o; o = o->next) {
1309 printf(" %-20s = %s\n", "Alert mail to", is_str_defined(o->to));
1310 printf(" %-18s = ", "Alert on");
1311 printevents(o->events);
1312 if (o->reminder)
1313 printf(" %-18s = %u cycles\n", "Alert reminder", o->reminder);
1314 }
1315
1316 printf("\n");
1317
1318 StringBuffer_free(&buf);
1319 }
1320
1321
1322 void Util_printServiceList() {
1323 Service_T s;
1324 char ruler[STRLEN];
1325
1326 printf("The service list contains the following entries:\n\n");
1327
1328 for (s = servicelist_conf; s; s = s->next_conf)
1329 Util_printService(s);
1330
1331 memset(ruler, '-', STRLEN);
1332 printf("%-.79s\n", ruler);
1333 }
1334
1335
1336 char *Util_getToken(MD_T token) {
1337 md5_context_t ctx;
1338 char buf[STRLEN] = {};
1339 MD_T digest;
1340 System_random(buf, sizeof(buf));
1341 md5_init(&ctx);
1342 md5_append(&ctx, (const md5_byte_t *)buf, STRLEN - 1);
1343 md5_finish(&ctx, (md5_byte_t *)digest);
1344 Checksum_digest2Bytes((unsigned char *)digest, 16, token);
1345 return token;
1346 }
1347
1348
1349 char *Util_monitId(char *idfile) {
1350 ASSERT(idfile);
1351 FILE *file = NULL;
1352 if (! File_exist(idfile)) {
1353 // Generate the unique id
1354 file = fopen(idfile, "w");
1355 if (! file) {
1356 Log_error("Error opening the idfile '%s' -- %s\n", idfile, STRERROR);
1357 return NULL;
1358 }
1359 fprintf(file, "%s", Util_getToken(Run.id));
1360 Log_info(" New Monit id: %s\n Stored in '%s'\n", Run.id, idfile);
1361 } else {
1362 if (! File_isFile(idfile)) {
1363 Log_error("idfile '%s' is not a regular file\n", idfile);
1364 return NULL;
1365 }
1366 if ((file = fopen(idfile,"r")) == (FILE *)NULL) {
1367 Log_error("Error opening the idfile '%s' -- %s\n", idfile, STRERROR);
1368 return NULL;
1369 }
1370 if (fscanf(file, "%64s", Run.id) != 1) {
1371 Log_error("Error reading id from file '%s'\n", idfile);
1372 if (fclose(file))
1373 Log_error("Error closing file '%s' -- %s\n", idfile, STRERROR);
1374 return NULL;
1375 }
1376 }
1377 if (fclose(file))
1378 Log_error("Error closing file '%s' -- %s\n", idfile, STRERROR);
1379
1380 return Run.id;
1381 }
1382
1383
1384 pid_t Util_getPid(char *pidfile) {
1385 FILE *file = NULL;
1386 int pid = -1;
1387
1388 ASSERT(pidfile);
1389
1390 if (! File_exist(pidfile)) {
1391 DEBUG("pidfile '%s' does not exist\n", pidfile);
1392 return 0;
1393 }
1394 if (! File_isFile(pidfile)) {
1395 DEBUG("pidfile '%s' is not a regular file\n", pidfile);
1396 return 0;
1397 }
1398 if ((file = fopen(pidfile,"r")) == (FILE *)NULL) {
1399 DEBUG("Error opening the pidfile '%s' -- %s\n", pidfile, STRERROR);
1400 return 0;
1401 }
1402 if (fscanf(file, "%d", &pid) != 1) {
1403 DEBUG("Error reading pid from file '%s'\n", pidfile);
1404 if (fclose(file))
1405 DEBUG("Error closing file '%s' -- %s\n", pidfile, STRERROR);
1406 return 0;
1407 }
1408 if (fclose(file))
1409 DEBUG("Error closing file '%s' -- %s\n", pidfile, STRERROR);
1410
1411 if (pid < 0)
1412 return(0);
1413
1414 return (pid_t)pid;
1415
1416 }
1417
1418
1419 bool Util_isurlsafe(const char *url) {
1420 ASSERT(url && *url);
1421 for (int i = 0; url[i]; i++)
1422 if (urlunsafe[(unsigned char)url[i]])
1423 return false;
1424 return true;
1425 }
1426
1427
1428 char *Util_urlEncode(const char *string, bool isParameterValue) {
1429 char *escaped = NULL;
1430 if (string) {
1431 char *p;
1432 int i, n;
1433 const unsigned char *unsafe = isParameterValue ? urlunsafeparameter : urlunsafe;
1434 for (n = i = 0; string[i]; i++)
1435 if (unsafe[(unsigned char)(string[i])])
1436 n += 2;
1437 p = escaped = ALLOC(i + n + 1);
1438 for (; *string; string++, p++) {
1439 if (unsafe[(unsigned char)(*p = *string)]) {
1440 *p++ = '%';
1441 *p++ = b2x[(unsigned char)(*string)][0];
1442 *p = b2x[(unsigned char)(*string)][1];
1443 }
1444 }
1445 *p = 0;
1446 }
1447 return escaped;
1448 }
1449
1450
1451 char *Util_urlDecode(char *url) {
1452 if (url && *url) {
1453 register int x, y;
1454 for (x = 0, y = 0; url[y]; x++, y++) {
1455 if (url[y] == '+') {
1456 url[x] = ' ';
1457 } else if (url[y] == '%') {
1458 if (! url[y + 1] || ! url[y + 2])
1459 break;
1460 url[x] = _x2c(url + y + 1);
1461 y += 2;
1462 } else {
1463 url[x] = url[y];
1464 }
1465 }
1466 url[x] = 0;
1467 }
1468 return url;
1469 }
1470
1471
1472 char *Util_getBasicAuthHeader(char *username, char *password) {
1473 char *auth, *b64;
1474 char buf[STRLEN];
1475
1476 if (! username)
1477 return NULL;
1478
1479 snprintf(buf, STRLEN, "%s:%s", username, password ? password : "");
1480 if (! (b64 = encode_base64(strlen(buf), (unsigned char *)buf)) ) {
1481 Log_error("Failed to base64 encode authentication header\n");
1482 return NULL;
1483 }
1484 auth = CALLOC(sizeof(char), STRLEN + 1);
1485 snprintf(auth, STRLEN, "Authorization: Basic %s\r\n", b64);
1486 FREE(b64);
1487 return auth;
1488 }
1489
1490
1491 void Util_redirectStdFds() {
1492 for (int i = 0; i < 3; i++) {
1493 if (close(i) == -1 || open("/dev/null", O_RDWR) != i) {
1494 Log_error("Cannot reopen standard file descriptor (%d) -- %s\n", i, STRERROR);
1495 }
1496 }
1497 }
1498
1499
1500 void Util_closeFds() {
1501 for (int i = 3, descriptors = System_getDescriptorsGuarded(); i < descriptors; i++) {
1502 close(i);
1503 }
1504 errno = 0;
1505 }
1506
1507
1508 Auth_T Util_getUserCredentials(char *uname) {
1509 /* check allowed user names */
1510 for (Auth_T c = Run.httpd.credentials; c; c = c->next)
1511 if (c->uname && IS(c->uname, uname))
1512 return c;
1513
1514 #ifdef HAVE_LIBPAM
1515 /* check allowed group names */
1516 return(PAMcheckUserGroup(uname));
1517 #else
1518 return NULL;
1519 #endif
1520 }
1521
1522
1523 bool Util_checkCredentials(char *uname, char *outside) {
1524 Auth_T c = Util_getUserCredentials(uname);
1525 char outside_crypt[STRLEN];
1526 if (c == NULL)
1527 return false;
1528 switch (c->digesttype) {
1529 case Digest_Cleartext:
1530 outside_crypt[sizeof(outside_crypt) - 1] = 0;
1531 strncpy(outside_crypt, outside, sizeof(outside_crypt) - 1);
1532 break;
1533 case Digest_Md5:
1534 {
1535 char id[STRLEN];
1536 char salt[STRLEN];
1537 char *temp;
1538 /* A password looks like this,
1539 * $id$salt$digest
1540 * the '$' around the id are still part of the id.
1541 */
1542 id[sizeof(id) - 1] = 0;
1543 strncpy(id, c->passwd, sizeof(id) - 1);
1544 if (! (temp = strchr(id + 1, '$'))) {
1545 Log_error("Password not in MD5 format.\n");
1546 return false;
1547 }
1548 temp += 1;
1549 *temp = '\0';
1550 salt[sizeof(salt) - 1] = 0;
1551 strncpy(salt, c->passwd + strlen(id), sizeof(salt) - 1);
1552 if (! (temp = strchr(salt, '$'))) {
1553 Log_error("Password not in MD5 format.\n");
1554 return false;
1555 }
1556 *temp = '\0';
1557 if (md5_crypt(outside, id, salt, outside_crypt, sizeof(outside_crypt)) == NULL) {
1558 Log_error("Cannot generate MD5 digest error.\n");
1559 return false;
1560 }
1561 break;
1562 }
1563 case Digest_Crypt:
1564 {
1565 char salt[3];
1566 char *temp;
1567 snprintf(salt, 3, "%c%c", c->passwd[0], c->passwd[1]);
1568 temp = crypt(outside, salt);
1569 outside_crypt[sizeof(outside_crypt) - 1] = 0;
1570 strncpy(outside_crypt, temp, sizeof(outside_crypt) - 1);
1571 break;
1572 }
1573 #ifdef HAVE_LIBPAM
1574 case Digest_Pam:
1575 return PAMcheckPasswd(uname, outside);
1576 break;
1577 #endif
1578 default:
1579 Log_error("Unknown password digestion method.\n");
1580 return false;
1581 }
1582 if (Str_compareConstantTime(outside_crypt, c->passwd) == 0)
1583 return true;
1584 return false;
1585 }
1586
1587
1588 void Util_swapFilesystemFlags(FilesystemFlags_T flags) {
1589 char *temp = flags->previous;
1590 flags->previous = flags->current;
1591 flags->current = temp;
1592 *(flags->current) = 0;
1593 }
1594
1595
1596 static void _resetFilesystemFlags(FilesystemFlags_T flags) {
1597 flags->previous = flags->value[0];
1598 flags->current = flags->value[1];
1599 *(flags->current) = 0;
1600 *(flags->previous) = 0;
1601 }
1602
1603 static void _resetIOStatistics(IOStatistics_T S) {
1604 Statistics_reset(&(S->operations));
1605 Statistics_reset(&(S->bytes));
1606 }
1607
1608
1609 void Util_resetInfo(Service_T s) {
1610 switch (s->type) {
1611 case Service_Filesystem:
1612 s->inf.filesystem->f_bsize = 0LL;
1613 s->inf.filesystem->f_blocks = 0LL;
1614 s->inf.filesystem->f_blocksfree = 0LL;
1615 s->inf.filesystem->f_blocksfreetotal = 0LL;
1616 s->inf.filesystem->f_blocksused = 0LL;
1617 s->inf.filesystem->f_files = 0LL;
1618 s->inf.filesystem->f_filesfree = 0LL;
1619 s->inf.filesystem->f_filesused = 0LL;
1620 s->inf.filesystem->inode_percent = 0.;
1621 s->inf.filesystem->space_percent = 0.;
1622 s->inf.filesystem->mode = -1;
1623 s->inf.filesystem->uid = -1;
1624 s->inf.filesystem->gid = -1;
1625 _resetFilesystemFlags(&(s->inf.filesystem->flags));
1626 _resetIOStatistics(&(s->inf.filesystem->read));
1627 _resetIOStatistics(&(s->inf.filesystem->write));
1628 Statistics_reset(&(s->inf.filesystem->time.read));
1629 Statistics_reset(&(s->inf.filesystem->time.write));
1630 Statistics_reset(&(s->inf.filesystem->time.wait));
1631 Statistics_reset(&(s->inf.filesystem->time.run));
1632 break;
1633 case Service_File:
1634 s->inf.file->size = -1;
1635 s->inf.file->readpos = 0;
1636 s->inf.file->inode = 0;
1637 s->inf.file->inode_prev = 0;
1638 s->inf.file->mode = -1;
1639 s->inf.file->uid = -1;
1640 s->inf.file->gid = -1;
1641 s->inf.file->timestamp.access = 0;
1642 s->inf.file->timestamp.change = 0;
1643 s->inf.file->timestamp.modify = 0;
1644 *s->inf.file->cs_sum = 0;
1645 break;
1646 case Service_Directory:
1647 s->inf.directory->mode = -1;
1648 s->inf.directory->uid = -1;
1649 s->inf.directory->gid = -1;
1650 s->inf.directory->timestamp.access = 0;
1651 s->inf.directory->timestamp.change = 0;
1652 s->inf.directory->timestamp.modify = 0;
1653 break;
1654 case Service_Fifo:
1655 s->inf.fifo->mode = -1;
1656 s->inf.fifo->uid = -1;
1657 s->inf.fifo->gid = -1;
1658 s->inf.fifo->timestamp.access = 0;
1659 s->inf.fifo->timestamp.change = 0;
1660 s->inf.fifo->timestamp.modify = 0;
1661 break;
1662 case Service_Process:
1663 s->inf.process->_pid = -1;
1664 s->inf.process->_ppid = -1;
1665 s->inf.process->pid = -1;
1666 s->inf.process->ppid = -1;
1667 s->inf.process->uid = -1;
1668 s->inf.process->euid = -1;
1669 s->inf.process->gid = -1;
1670 s->inf.process->zombie = false;
1671 s->inf.process->threads = -1;
1672 s->inf.process->children = -1;
1673 s->inf.process->mem = 0ULL;
1674 s->inf.process->total_mem = 0ULL;
1675 s->inf.process->mem_percent = -1.;
1676 s->inf.process->total_mem_percent = -1.;
1677 s->inf.process->cpu_percent = -1.;
1678 s->inf.process->total_cpu_percent = -1.;
1679 s->inf.process->uptime = -1;
1680 s->inf.process->filedescriptors.open = -1LL;
1681 s->inf.process->filedescriptors.openTotal = -1LL;
1682 *(s->inf.process->secattr) = 0;
1683 _resetIOStatistics(&(s->inf.process->read));
1684 _resetIOStatistics(&(s->inf.process->write));
1685 break;
1686 case Service_Net:
1687 if (s->inf.net->stats)
1688 Link_reset(s->inf.net->stats);
1689 break;
1690 default:
1691 break;
1692 }
1693 }
1694
1695
1696 bool Util_hasServiceStatus(Service_T s) {
1697 return((s->monitor & Monitor_Yes) && ! (s->error & Event_NonExist) && ! (s->error & Event_Data));
1698 }
1699
1700
1701 char *Util_getHTTPHostHeader(Socket_T s, char *hostBuf, int len) {
1702 int port = Socket_getRemotePort(s);
1703 const char *host = Socket_getRemoteHost(s);
1704 bool ipv6 = Str_sub(host, ":") ? true : false;
1705 if (port == 80 || port == 443)
1706 snprintf(hostBuf, len, "%s%s%s", ipv6 ? "[" : "", host, ipv6 ? "]" : "");
1707 else
1708 snprintf(hostBuf, len, "%s%s%s:%d", ipv6 ? "[" : "", host, ipv6 ? "]" : "", port);
1709 return hostBuf;
1710 }
1711
1712
1713 bool Util_evalQExpression(Operator_Type operator, long long left, long long right) {
1714 switch (operator) {
1715 case Operator_Greater:
1716 if (left > right)
1717 return true;
1718 break;
1719 case Operator_GreaterOrEqual:
1720 if (left >= right)
1721 return true;
1722 break;
1723 case Operator_Less:
1724 if (left < right)
1725 return true;
1726 break;
1727 case Operator_LessOrEqual:
1728 if (left <= right)
1729 return true;
1730 break;
1731 case Operator_Equal:
1732 if (left == right)
1733 return true;
1734 break;
1735 case Operator_NotEqual:
1736 case Operator_Changed:
1737 if (left != right)
1738 return true;
1739 break;
1740 default:
1741 Log_error("Unknown comparison operator\n");
1742 return false;
1743 }
1744 return false;
1745 }
1746
1747
1748 bool Util_evalDoubleQExpression(Operator_Type operator, double left, double right) {
1749 switch (operator) {
1750 case Operator_Greater:
1751 if (left > right)
1752 return true;
1753 break;
1754 case Operator_GreaterOrEqual:
1755 if (left >= right)
1756 return true;
1757 break;
1758 case Operator_Less:
1759 if (left < right)
1760 return true;
1761 break;
1762 case Operator_LessOrEqual:
1763 if (left <= right)
1764 return true;
1765 break;
1766 case Operator_Equal:
1767 if (left == right)
1768 return true;
1769 break;
1770 case Operator_NotEqual:
1771 case Operator_Changed:
1772 if (left != right)
1773 return true;
1774 break;
1775 default:
1776 Log_error("Unknown comparison operator\n");
1777 return false;
1778 }
1779 return false;
1780 }
1781
1782
1783 void Util_monitorSet(Service_T s) {
1784 ASSERT(s);
1785 if (s->monitor == Monitor_Not) {
1786 s->monitor = Monitor_Init;
1787 DEBUG("'%s' monitoring enabled\n", s->name);
1788 State_dirty();
1789 }
1790 }
1791
1792
1793 void Util_monitorUnset(Service_T s) {
1794 ASSERT(s);
1795 if (s->monitor != Monitor_Not) {
1796 s->monitor = Monitor_Not;
1797 DEBUG("'%s' monitoring disabled\n", s->name);
1798 }
1799 s->nstart = 0;
1800 s->ncycle = 0;
1801 if (s->every.type == Every_SkipCycles)
1802 s->every.spec.cycle.counter = 0;
1803 s->error = Event_Null;
1804 if (s->eventlist)
1805 gc_event(&s->eventlist);
1806 Util_resetInfo(s);
1807 State_dirty();
1808 }
1809
1810
1811 int Util_getAction(const char *action) {
1812 int i = 1; /* the Action_Ignored has index 0 => we will start on next item */
1813
1814 ASSERT(action);
1815
1816 while (strlen(actionnames[i])) {
1817 if (IS(action, actionnames[i]))
1818 return i;
1819 i++;
1820 }
1821 /* the action was not found */
1822 return Action_Ignored;
1823 }
1824
1825
1826 StringBuffer_T Util_printAction(Action_T A, StringBuffer_T buf) {
1827 StringBuffer_append(buf, "%s", actionnames[A->id]);
1828 if (A->id == Action_Exec) {
1829 command_t C = A->exec;
1830 for (int i = 0; C->arg[i]; i++)
1831 StringBuffer_append(buf, "%s%s", i ? " " : " '", C->arg[i]);
1832 StringBuffer_append(buf, "'");
1833 if (C->has_uid)
1834 StringBuffer_append(buf, " as uid %d", C->uid);
1835 if (C->has_gid)
1836 StringBuffer_append(buf, " as gid %d", C->gid);
1837 if (C->timeout)
1838 StringBuffer_append(buf, " timeout %d cycle(s)", C->timeout);
1839 if (A->repeat)
1840 StringBuffer_append(buf, " repeat every %d cycle(s)", A->repeat);
1841 }
1842 return buf;
1843 }
1844
1845
1846 StringBuffer_T Util_printEventratio(Action_T action, StringBuffer_T buf) {
1847 if (action->cycles > 1) {
1848 if (action->count == action->cycles)
1849 StringBuffer_append(buf, "for %d cycles ", action->cycles);
1850 else
1851 StringBuffer_append(buf, "for %d times within %d cycles ", action->count, action->cycles);
1852 }
1853 return buf;
1854 }
1855
1856
1857 StringBuffer_T Util_printRule(bool inverse, StringBuffer_T buf, EventAction_T action, const char *rule, ...) {
1858 ASSERT(buf);
1859 ASSERT(action);
1860 ASSERT(rule);
1861 // Variable part
1862 va_list ap;
1863 va_start(ap, rule);
1864 StringBuffer_vappend(buf, rule, ap);
1865 va_end(ap);
1866 // Constant part (failure action)
1867 StringBuffer_append(buf, " ");
1868 Util_printEventratio(action->failed, buf);
1869 StringBuffer_append(buf, "then ");
1870 Util_printAction(action->failed, buf);
1871 // Print the success part only if it's non default action (alert is implicit => skipped for simpler output)
1872 if (action->succeeded->id != Action_Ignored && action->succeeded->id != Action_Alert) {
1873 StringBuffer_append(buf, " else if ");
1874 StringBuffer_append(buf, inverse ? "failed " : "succeeded ");
1875 Util_printEventratio(action->succeeded, buf);
1876 StringBuffer_append(buf, "then ");
1877 Util_printAction(action->succeeded, buf);
1878 }
1879 return buf;
1880 }
1881
1882
1883 const char *Util_portIpDescription(Port_T p) {
1884 switch (p->family) {
1885 case Socket_Ip:
1886 return "IP";
1887 case Socket_Ip4:
1888 return "IPv4";
1889 case Socket_Ip6:
1890 return "IPv6";
1891 default:
1892 return "UNKNOWN";
1893 }
1894 }
1895
1896
1897 const char *Util_portTypeDescription(Port_T p) {
1898 switch (p->type) {
1899 case Socket_Tcp:
1900 return "TCP";
1901 case Socket_Udp:
1902 return "UDP";
1903 default:
1904 return "UNKNOWN";
1905 }
1906 }
1907
1908
1909 const char *Util_portRequestDescription(Port_T p) {
1910 const char *request = "";
1911 if (p->protocol->check == check_http && p->parameters.http.request)
1912 request = p->parameters.http.request;
1913 else if (p->protocol->check == check_websocket && p->parameters.websocket.request)
1914 request = p->parameters.websocket.request;
1915 return request;
1916 }
1917
1918
1919 char *Util_portDescription(Port_T p, char *buf, int bufsize) {
1920 if (p->family == Socket_Ip || p->family == Socket_Ip4 || p->family == Socket_Ip6) {
1921 snprintf(buf, bufsize, "[%s]:%d%s [%s/%s%s]", p->hostname, p->target.net.port, Util_portRequestDescription(p), Util_portTypeDescription(p), Util_portIpDescription(p), p->target.net.ssl.options.flags ? " TLS" : "");
1922 } else if (p->family == Socket_Unix) {
1923 snprintf(buf, bufsize, "%s", p->target.unix.pathname);
1924 } else {
1925 *buf = 0;
1926 }
1927 return buf;
1928 }
1929
1930
1931 char *Util_commandDescription(command_t command, char s[STRLEN]) {
1932 ASSERT(s);
1933 ASSERT(command);
1934 int len = 0;
1935 for (int i = 0; command->arg[i] && len < STRLEN - 1; i++) {
1936 len += snprintf(s + len, STRLEN - len, "%s%s", i ? " " : "", command->arg[i]);
1937 }
1938 if (len >= STRLEN - 1)
1939 snprintf(s + STRLEN - 3 - 1, 4, "...");
1940 return s;
1941 }
1942
1943
1944 const char *Util_timestr(int time) {
1945 int i = 0;
1946 struct mytimetable {
1947 int id;
1948 const char *description;
1949 } tt[]= {
1950 {Time_Second, "second"},
1951 {Time_Minute, "minute"},
1952 {Time_Hour, "hour"},
1953 {Time_Day, "day"},
1954 {Time_Month, "month"},
1955 {0}
1956 };
1957 do {
1958 if (time == tt[i].id)
1959 return tt[i].description;
1960 } while (tt[++i].description);
1961 return NULL;
1962 }
1963
1964