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