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
26 %{
27
28 /*
29 * DESCRIPTION
30 * Simple context-free grammar for parsing the control file.
31 *
32 */
33
34 #include "config.h"
35
36 #ifdef HAVE_STDIO_H
37 #include <stdio.h>
38 #endif
39
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43
44 #ifdef HAVE_ERRNO_H
45 #include <errno.h>
46 #endif
47
48 #ifdef HAVE_CTYPE_H
49 #include <ctype.h>
50 #endif
51
52 #ifdef HAVE_PWD_H
53 #include <pwd.h>
54 #endif
55
56 #ifdef HAVE_GRP_H
57 #include <grp.h>
58 #endif
59
60 #ifdef HAVE_SYS_TYPES_H
61 #include <sys/types.h>
62 #endif
63
64 #ifdef HAVE_SYS_TIME_H
65 #include <sys/time.h>
66 #endif
67
68 #ifdef HAVE_TIME_H
69 #include <time.h>
70 #endif
71
72 #ifdef HAVE_SYS_SOCKET_H
73 #include <sys/socket.h>
74 #endif
75
76 #ifdef HAVE_ASM_PARAM_H
77 #include <asm/param.h>
78 #endif
79
80 #ifdef HAVE_STRING_H
81 #include <string.h>
82 #endif
83
84 #ifdef HAVE_STRINGS_H
85 #include <strings.h>
86 #endif
87
88 #ifdef HAVE_NETDB_H
89 #include <netdb.h>
90 #endif
91
92 #ifdef HAVE_SYSLOG_H
93 #include <syslog.h>
94 #endif
95
96 #ifdef HAVE_NETINET_IN_SYSTM_H
97 #include <netinet/in_systm.h>
98 #endif
99
100 #ifdef HAVE_NETINET_IN_H
101 #include <netinet/in.h>
102 #endif
103
104 #ifdef HAVE_NETINET_IP_H
105 #include <netinet/ip.h>
106 #endif
107
108 #ifdef HAVE_NETINET_IP_ICMP_H
109 #include <netinet/ip_icmp.h>
110 #endif
111
112 #ifdef HAVE_REGEX_H
113 #include <regex.h>
114 #endif
115
116 #ifdef HAVE_UNISTD_H
117 #include <unistd.h>
118 #endif
119
120 #ifdef HAVE_OPENSSL
121 #include <openssl/ssl.h>
122 #endif
123
124 #include "monit.h"
125 #include "protocol.h"
126 #include "engine.h"
127 #include "alert.h"
128 #include "ProcessTree.h"
129 #include "device.h"
130 #include "processor.h"
131 #include "md5.h"
132 #include "sha1.h"
133 #include "checksum.h"
134 #include "process_sysdep.h"
135
136 // libmonit
137 #include "io/File.h"
138 #include "util/Str.h"
139 #include "thread/Thread.h"
140
141
142 /* ------------------------------------------------------------- Definitions */
143
144
145 struct precedence_t {
146 bool daemon;
147 bool logfile;
148 bool pidfile;
149 };
150
151 struct rate_t {
152 unsigned int count;
153 unsigned int cycles;
154 };
155
156 /* yacc interface */
157 void yyerror(const char *,...) __attribute__((format (printf, 1, 2)));
158 void yyerror2(const char *,...) __attribute__((format (printf, 1, 2)));
159 void yywarning(const char *,...) __attribute__((format (printf, 1, 2)));
160 void yywarning2(const char *,...) __attribute__((format (printf, 1, 2)));
161
162 /* lexer interface */
163 int yylex(void);
164 extern FILE *yyin;
165 extern int lineno;
166 extern int arglineno;
167 extern char *yytext;
168 extern char *argyytext;
169 extern char *currentfile;
170 extern char *argcurrentfile;
171 extern int buffer_stack_ptr;
172
173 /* Local variables */
174 static int cfg_errflag = 0;
175 static Service_T tail = NULL;
176 static Service_T current = NULL;
177 static Request_T urlrequest = NULL;
178 static command_t command = NULL;
179 static command_t command1 = NULL;
180 static command_t command2 = NULL;
181 static Service_T depend_list = NULL;
182 static struct Uid_T uidset = {};
183 static struct Gid_T gidset = {};
184 static struct Pid_T pidset = {};
185 static struct Pid_T ppidset = {};
186 static struct FsFlag_T fsflagset = {};
187 static struct NonExist_T nonexistset = {};
188 static struct Exist_T existset = {};
189 static struct Status_T statusset = {};
190 static struct Perm_T permset = {};
191 static struct Size_T sizeset = {};
192 static struct Uptime_T uptimeset = {};
193 static struct ResponseTime_T responsetimeset = {};
194 static struct LinkStatus_T linkstatusset = {};
195 static struct LinkSpeed_T linkspeedset = {};
196 static struct LinkSaturation_T linksaturationset = {};
197 static struct Bandwidth_T bandwidthset = {};
198 static struct Match_T matchset = {};
199 static struct Icmp_T icmpset = {};
200 static struct Mail_T mailset = {};
201 static struct SslOptions_T sslset = {};
202 static struct Port_T portset = {};
203 static struct MailServer_T mailserverset = {};
204 static struct Mmonit_T mmonitset = {};
205 static struct FileSystem_T filesystemset = {};
206 static struct Resource_T resourceset = {};
207 static struct Checksum_T checksumset = {};
208 static struct Timestamp_T timestampset = {};
209 static struct ActionRate_T actionrateset = {};
210 static struct precedence_t ihp = {false, false, false};
211 static struct rate_t rate = {1, 1};
212 static struct rate_t rate1 = {1, 1};
213 static struct rate_t rate2 = {1, 1};
214 static char * htpasswd_file = NULL;
215 static unsigned int repeat = 0;
216 static unsigned int repeat1 = 0;
217 static unsigned int repeat2 = 0;
218 static Digest_Type digesttype = Digest_Cleartext;
219
220 #define BITMAP_MAX (sizeof(long long) * 8)
221
222
223 /* -------------------------------------------------------------- Prototypes */
224
225 static void preparse(void);
226 static void postparse(void);
227 static bool _parseOutgoingAddress(char *ip, Outgoing_T *outgoing);
228 static void addmail(char *, Mail_T, Mail_T *);
229 static Service_T createservice(Service_Type, char *, char *, State_Type (*)(Service_T));
230 static void addservice(Service_T);
231 static void adddependant(char *);
232 static void addservicegroup(char *);
233 static void addport(Port_T *, Port_T);
234 static void addhttpheader(Port_T, char *);
235 static void addresource(Resource_T);
236 static void addtimestamp(Timestamp_T);
237 static void addactionrate(ActionRate_T);
238 static void addsize(Size_T);
239 static void adduptime(Uptime_T);
240 static void addpid(Pid_T);
241 static void addppid(Pid_T);
242 static void addfsflag(FsFlag_T);
243 static void addnonexist(NonExist_T);
244 static void addexist(Exist_T);
245 static void addlinkstatus(Service_T, LinkStatus_T);
246 static void addlinkspeed(Service_T, LinkSpeed_T);
247 static void addlinksaturation(Service_T, LinkSaturation_T);
248 static void addbandwidth(Bandwidth_T *, Bandwidth_T);
249 static void addfilesystem(FileSystem_T);
250 static void addicmp(Icmp_T);
251 static void addgeneric(Port_T, char*, char*);
252 static void addcommand(int, unsigned);
253 static void addargument(char *);
254 static void addmmonit(Mmonit_T);
255 static void addmailserver(MailServer_T);
256 static bool addcredentials(char *, char *, Digest_Type, bool);
257 #ifdef HAVE_LIBPAM
258 static void addpamauth(char *, int);
259 #endif
260 static void addhtpasswdentry(char *, char *, Digest_Type);
261 static uid_t get_uid(char *, uid_t);
262 static gid_t get_gid(char *, gid_t);
263 static void addchecksum(Checksum_T);
264 static void addperm(Perm_T);
265 static void addmatch(Match_T, int, int);
266 static void addmatchpath(Match_T, Action_Type);
267 static void addstatus(Status_T);
268 static Uid_T adduid(Uid_T);
269 static Gid_T addgid(Gid_T);
270 static void addeuid(uid_t);
271 static void addegid(gid_t);
272 static void addeventaction(EventAction_T *, Action_Type, Action_Type);
273 static void prepare_urlrequest(URL_T U);
274 static void seturlrequest(int, char *);
275 static void setlogfile(char *);
276 static void setpidfile(char *);
277 static void reset_sslset(void);
278 static void reset_mailset(void);
279 static void reset_mailserverset(void);
280 static void reset_mmonitset(void);
281 static void reset_portset(void);
282 static void reset_resourceset(void);
283 static void reset_timestampset(void);
284 static void reset_actionrateset(void);
285 static void reset_sizeset(void);
286 static void reset_uptimeset(void);
287 static void reset_responsetimeset(void);
288 static void reset_pidset(void);
289 static void reset_ppidset(void);
290 static void reset_fsflagset(void);
291 static void reset_nonexistset(void);
292 static void reset_existset(void);
293 static void reset_linkstatusset(void);
294 static void reset_linkspeedset(void);
295 static void reset_linksaturationset(void);
296 static void reset_bandwidthset(void);
297 static void reset_checksumset(void);
298 static void reset_permset(void);
299 static void reset_uidset(void);
300 static void reset_gidset(void);
301 static void reset_statusset(void);
302 static void reset_filesystemset(void);
303 static void reset_icmpset(void);
304 static void reset_rateset(struct rate_t *);
305 static void check_name(char *);
306 static int check_perm(int);
307 static void check_exec(char *);
308 static int cleanup_hash_string(char *);
309 static void check_depend(void);
310 static void setsyslog(char *);
311 static command_t copycommand(command_t);
312 static int verifyMaxForward(int);
313 static void _setPEM(char **store, char *path, const char *description, bool isFile);
314 static void _setSSLOptions(SslOptions_T options);
315 #ifdef HAVE_OPENSSL
316 static void _setSSLVersion(short version);
317 #endif
318 static void _unsetSSLVersion(short version);
319 static void addsecurityattribute(char *, Action_Type, Action_Type);
320 static void addfiledescriptors(Operator_Type, bool, long long, float, Action_Type, Action_Type);
321 static void _sanityCheckEveryStatement(Service_T s);
322
323 %}
324
325 %union {
326 URL_T url;
327 Address_T address;
328 float real;
329 int number;
330 char *string;
331 }
332
333 %token IF ELSE THEN FAILED
334 %token SET LOGFILE FACILITY DAEMON SYSLOG MAILSERVER HTTPD ALLOW REJECTOPT ADDRESS INIT TERMINAL BATCH
335 %token READONLY CLEARTEXT MD5HASH SHA1HASH CRYPT DELAY
336 %token PEMFILE PEMKEY PEMCHAIN ENABLE DISABLE SSLTOKEN CIPHER CLIENTPEMFILE ALLOWSELFCERTIFICATION SELFSIGNED VERIFY CERTIFICATE CACERTIFICATEFILE CACERTIFICATEPATH VALID
337 %token INTERFACE LINK PACKET BYTEIN BYTEOUT PACKETIN PACKETOUT SPEED SATURATION UPLOAD DOWNLOAD TOTAL UP DOWN
338 %token IDFILE STATEFILE SEND EXPECT CYCLE COUNT REMINDER REPEAT
339 %token LIMITS SENDEXPECTBUFFER EXPECTBUFFER FILECONTENTBUFFER HTTPCONTENTBUFFER PROGRAMOUTPUT NETWORKTIMEOUT PROGRAMTIMEOUT STARTTIMEOUT STOPTIMEOUT RESTARTTIMEOUT
340 %token PIDFILE START STOP PATHTOK RSAKEY
341 %token HOST HOSTNAME PORT IPV4 IPV6 TYPE UDP TCP TCPSSL PROTOCOL CONNECTION
342 %token ALERT NOALERT MAILFORMAT UNIXSOCKET SIGNATURE
343 %token TIMEOUT RETRY RESTART CHECKSUM EVERY NOTEVERY
344 %token DEFAULT HTTP HTTPS APACHESTATUS FTP SMTP SMTPS POP POPS IMAP IMAPS CLAMAV NNTP NTP3 MYSQL MYSQLS DNS WEBSOCKET MQTT
345 %token SSH DWP LDAP2 LDAP3 RDATE RSYNC TNS PGSQL POSTFIXPOLICY SIP LMTP GPS RADIUS MEMCACHE REDIS MONGODB SIEVE SPAMASSASSIN FAIL2BAN
346 %token <string> STRING PATH MAILADDR MAILFROM MAILREPLYTO MAILSUBJECT
347 %token <string> MAILBODY SERVICENAME STRINGNAME
348 %token <number> NUMBER PERCENT LOGLIMIT CLOSELIMIT DNSLIMIT KEEPALIVELIMIT
349 %token <number> REPLYLIMIT REQUESTLIMIT STARTLIMIT WAITLIMIT GRACEFULLIMIT
350 %token <number> CLEANUPLIMIT
351 %token <real> REAL
352 %token CHECKPROC CHECKFILESYS CHECKFILE CHECKDIR CHECKHOST CHECKSYSTEM CHECKFIFO CHECKPROGRAM CHECKNET
353 %token THREADS CHILDREN METHOD GET HEAD STATUS ORIGIN VERSIONOPT READ WRITE OPERATION SERVICETIME DISK
354 %token RESOURCE MEMORY TOTALMEMORY LOADAVG1 LOADAVG5 LOADAVG15 SWAP
355 %token MODE ACTIVE PASSIVE MANUAL ONREBOOT NOSTART LASTSTATE
356 %token CORE CPU TOTALCPU CPUUSER CPUSYSTEM CPUWAIT CPUNICE CPUHARDIRQ CPUSOFTIRQ CPUSTEAL CPUGUEST CPUGUESTNICE
357 %token GROUP REQUEST DEPENDS BASEDIR SLOT EVENTQUEUE SECRET HOSTHEADER
358 %token UID EUID GID MMONIT INSTANCE USERNAME PASSWORD DATABASE
359 %token TIME ATIME CTIME MTIME CHANGED MILLISECOND SECOND MINUTE HOUR DAY MONTH
360 %token SSLV2 SSLV3 TLSV1 TLSV11 TLSV12 TLSV13 CERTMD5 AUTO
361 %token NOSSLV2 NOSSLV3 NOTLSV1 NOTLSV11 NOTLSV12 NOTLSV13
362 %token BYTE KILOBYTE MEGABYTE GIGABYTE
363 %token INODE SPACE TFREE PERMISSION SIZE MATCH NOT IGNORE ACTION UPTIME RESPONSETIME
364 %token EXEC UNMONITOR PING PING4 PING6 ICMP ICMPECHO NONEXIST EXIST INVALID DATA RECOVERED PASSED SUCCEEDED
365 %token URL CONTENT PID PPID FSFLAG
366 %token REGISTER CREDENTIALS
367 %token <url> URLOBJECT
368 %token <address> ADDRESSOBJECT
369 %token <string> TARGET TIMESPEC HTTPHEADER
370 %token <number> MAXFORWARD
371 %token FIPS
372 %token SECURITY ATTRIBUTE
373 %token FILEDESCRIPTORS
374
375 %left GREATER GREATEROREQUAL LESS LESSOREQUAL EQUAL NOTEQUAL
376
377
378 %%
379 cfgfile : /* EMPTY */
380 | statement_list
381 ;
382
383 statement_list : statement
384 | statement_list statement
385 ;
386
387 statement : setalert
388 | setssl
389 | setdaemon
390 | setterminal
391 | setlog
392 | seteventqueue
393 | setmmonits
394 | setmailservers
395 | setmailformat
396 | sethttpd
397 | setpid
398 | setidfile
399 | setstatefile
400 | setexpectbuffer
401 | setinit
402 | setlimits
403 | setonreboot
404 | setfips
405 | checkproc optproclist
406 | checkfile optfilelist
407 | checkfilesys optfilesyslist
408 | checkdir optdirlist
409 | checkhost opthostlist
410 | checksystem optsystemlist
411 | checkfifo optfifolist
412 | checkprogram optprogramlist
413 | checknet optnetlist
414 ;
415
416 optproclist : /* EMPTY */
417 | optproclist optproc
418 ;
419
420 optproc : start
421 | stop
422 | restart
423 | exist
424 | pid
425 | ppid
426 | uid
427 | euid
428 | secattr
429 | filedescriptorsprocess
430 | filedescriptorsprocesstotal
431 | gid
432 | uptime
433 | connection
434 | connectionurl
435 | connectionunix
436 | actionrate
437 | alert
438 | every
439 | mode
440 | onreboot
441 | group
442 | depend
443 | resourceprocess
444 ;
445
446 optfilelist : /* EMPTY */
447 | optfilelist optfile
448 ;
449
450 optfile : start
451 | stop
452 | restart
453 | exist
454 | timestamp
455 | actionrate
456 | every
457 | alert
458 | permission
459 | uid
460 | gid
461 | checksum
462 | size
463 | match
464 | mode
465 | onreboot
466 | group
467 | depend
468 ;
469
470 optfilesyslist : /* EMPTY */
471 | optfilesyslist optfilesys
472 ;
473
474 optfilesys : start
475 | stop
476 | restart
477 | exist
478 | actionrate
479 | every
480 | alert
481 | permission
482 | uid
483 | gid
484 | mode
485 | onreboot
486 | group
487 | depend
488 | inode
489 | space
490 | read
491 | write
492 | servicetime
493 | fsflag
494 ;
495
496 optdirlist : /* EMPTY */
497 | optdirlist optdir
498 ;
499
500 optdir : start
501 | stop
502 | restart
503 | exist
504 | timestamp
505 | actionrate
506 | every
507 | alert
508 | permission
509 | uid
510 | gid
511 | mode
512 | onreboot
513 | group
514 | depend
515 ;
516
517 opthostlist : /* EMPTY */
518 | opthostlist opthost
519 ;
520
521 opthost : start
522 | stop
523 | restart
524 | connection
525 | connectionurl
526 | icmp
527 | actionrate
528 | alert
529 | every
530 | mode
531 | onreboot
532 | group
533 | depend
534 ;
535
536 optnetlist : /* EMPTY */
537 | optnetlist optnet
538 ;
539
540 optnet : start
541 | stop
542 | restart
543 | linkstatus
544 | linkspeed
545 | linksaturation
546 | upload
547 | download
548 | actionrate
549 | every
550 | mode
551 | onreboot
552 | alert
553 | group
554 | depend
555 ;
556
557 optsystemlist : /* EMPTY */
558 | optsystemlist optsystem
559 ;
560
561 optsystem : start
562 | stop
563 | restart
564 | actionrate
565 | alert
566 | every
567 | mode
568 | onreboot
569 | group
570 | depend
571 | resourcesystem
572 | uptime
573 | filedescriptorssystem
574 ;
575
576 optfifolist : /* EMPTY */
577 | optfifolist optfifo
578 ;
579
580 optfifo : start
581 | stop
582 | restart
583 | exist
584 | timestamp
585 | actionrate
586 | every
587 | alert
588 | permission
589 | uid
590 | gid
591 | mode
592 | onreboot
593 | group
594 | depend
595 ;
596
597 optprogramlist : /* EMPTY */
598 | optprogramlist optprogram
599 ;
600
601 optprogram : start
602 | stop
603 | restart
604 | actionrate
605 | alert
606 | every
607 | mode
608 | onreboot
609 | group
610 | depend
611 | statusvalue
612 | programmatch
613 ;
614
615 setalert : SET alertmail formatlist reminder {
616 mailset.events = Event_All;
617 addmail($<string>2, &mailset, &Run.maillist);
618 }
619 | SET alertmail '{' eventoptionlist '}' formatlist reminder {
620 addmail($<string>2, &mailset, &Run.maillist);
621 }
622 | SET alertmail NOT '{' eventoptionlist '}' formatlist reminder {
623 mailset.events = ~mailset.events;
624 addmail($<string>2, &mailset, &Run.maillist);
625 }
626 ;
627
628 setdaemon : SET DAEMON NUMBER startdelay {
629 if (! (Run.flags & Run_Daemon) || ihp.daemon) {
630 ihp.daemon = true;
631 Run.flags |= Run_Daemon;
632 Run.polltime = $3;
633 Run.startdelay = $<number>4;
634 }
635 }
636 ;
637
638 setterminal : SET TERMINAL BATCH {
639 Run.flags |= Run_Batch;
640 }
641 ;
642
643 startdelay : /* EMPTY */ {
644 $<number>$ = 0;
645 }
646 | START DELAY NUMBER {
647 $<number>$ = $3;
648 }
649 ;
650
651 setinit : SET INIT {
652 Run.flags |= Run_Foreground;
653 }
654 ;
655
656 setonreboot : SET ONREBOOT START {
657 Run.onreboot = Onreboot_Start;
658 }
659 | SET ONREBOOT NOSTART {
660 Run.onreboot = Onreboot_Nostart;
661 }
662 | SET ONREBOOT LASTSTATE {
663 Run.onreboot = Onreboot_Laststate;
664 }
665 ;
666
667 setexpectbuffer : SET EXPECTBUFFER NUMBER unit {
668 // Note: deprecated (replaced by "set limits" statement's "sendExpectBuffer" option)
669 Run.limits.sendExpectBuffer = $3 * $<number>4;
670 }
671 ;
672
673 setlimits : SET LIMITS '{' limitlist '}'
674 ;
675
676 limitlist : /* EMPTY */
677 | limitlist limit
678 ;
679
680 limit : SENDEXPECTBUFFER ':' NUMBER unit {
681 Run.limits.sendExpectBuffer = $3 * $<number>4;
682 }
683 | FILECONTENTBUFFER ':' NUMBER unit {
684 Run.limits.fileContentBuffer = $3 * $<number>4;
685 }
686 | HTTPCONTENTBUFFER ':' NUMBER unit {
687 Run.limits.httpContentBuffer = $3 * $<number>4;
688 }
689 | PROGRAMOUTPUT ':' NUMBER unit {
690 Run.limits.programOutput = $3 * $<number>4;
691 }
692 | NETWORKTIMEOUT ':' NUMBER MILLISECOND {
693 Run.limits.networkTimeout = $3;
694 }
695 | NETWORKTIMEOUT ':' NUMBER SECOND {
696 Run.limits.networkTimeout = $3 * 1000;
697 }
698 | PROGRAMTIMEOUT ':' NUMBER MILLISECOND {
699 Run.limits.programTimeout = $3;
700 }
701 | PROGRAMTIMEOUT ':' NUMBER SECOND {
702 Run.limits.programTimeout = $3 * 1000;
703 }
704 | STOPTIMEOUT ':' NUMBER MILLISECOND {
705 Run.limits.stopTimeout = $3;
706 }
707 | STOPTIMEOUT ':' NUMBER SECOND {
708 Run.limits.stopTimeout = $3 * 1000;
709 }
710 | STARTTIMEOUT ':' NUMBER MILLISECOND {
711 Run.limits.startTimeout = $3;
712 }
713 | STARTTIMEOUT ':' NUMBER SECOND {
714 Run.limits.startTimeout = $3 * 1000;
715 }
716 | RESTARTTIMEOUT ':' NUMBER MILLISECOND {
717 Run.limits.restartTimeout = $3;
718 }
719 | RESTARTTIMEOUT ':' NUMBER SECOND {
720 Run.limits.restartTimeout = $3 * 1000;
721 }
722 ;
723
724 setfips : SET FIPS {
725 Run.flags |= Run_FipsEnabled;
726 }
727 ;
728
729 setlog : SET LOGFILE PATH {
730 if (! Run.files.log || ihp.logfile) {
731 ihp.logfile = true;
732 setlogfile($3);
733 Run.flags &= ~Run_UseSyslog;
734 Run.flags |= Run_Log;
735 }
736 }
737 | SET LOGFILE SYSLOG {
738 setsyslog(NULL);
739 }
740 | SET LOGFILE SYSLOG FACILITY STRING {
741 setsyslog($5); FREE($5);
742 }
743 ;
744
745 seteventqueue : SET EVENTQUEUE BASEDIR PATH {
746 Run.eventlist_dir = $4;
747 }
748 | SET EVENTQUEUE BASEDIR PATH SLOT NUMBER {
749 Run.eventlist_dir = $4;
750 Run.eventlist_slots = $6;
751 }
752 | SET EVENTQUEUE SLOT NUMBER {
753 Run.eventlist_dir = Str_dup(MYEVENTLISTBASE);
754 Run.eventlist_slots = $4;
755 }
756 ;
757
758 setidfile : SET IDFILE PATH {
759 Run.files.id = $3;
760 }
761 ;
762
763 setstatefile : SET STATEFILE PATH {
764 Run.files.state = $3;
765 }
766 ;
767
768 setpid : SET PIDFILE PATH {
769 if (! Run.files.pid || ihp.pidfile) {
770 ihp.pidfile = true;
771 setpidfile($3);
772 }
773 }
774 ;
775
776 setmmonits : SET MMONIT mmonitlist
777 ;
778
779 mmonitlist : mmonit credentials
780 | mmonitlist mmonit credentials
781 ;
782
783 mmonit : URLOBJECT mmonitoptlist {
784 mmonitset.url = $<url>1;
785 addmmonit(&mmonitset);
786 }
787 ;
788
789 mmonitoptlist : /* EMPTY */
790 | mmonitoptlist mmonitopt
791 ;
792
793 mmonitopt : TIMEOUT NUMBER SECOND {
794 mmonitset.timeout = $<number>2 * 1000; // net timeout is in milliseconds internally
795 }
796 | ssl
797 | sslchecksum
798 | sslversion
799 | certmd5
800 ;
801
802 credentials : /* EMPTY */
803 | REGISTER CREDENTIALS {
804 Run.flags &= ~Run_MmonitCredentials;
805 }
806 ;
807
808 setssl : SET SSLTOKEN '{' ssloptionlist '}' {
809 _setSSLOptions(&(Run.ssl));
810 }
811 ;
812
813 ssl : SSLTOKEN {
814 sslset.flags = SSL_Enabled;
815 }
816 | SSLTOKEN '{' ssloptionlist '}'
817 ;
818
819 ssloptionlist : /* EMPTY */
820 | ssloptionlist ssloption
821 ;
822
823 ssloption : VERIFY ':' ENABLE {
824 sslset.flags = SSL_Enabled;
825 sslset.verify = true;
826 }
827 | VERIFY ':' DISABLE {
828 sslset.flags = SSL_Enabled;
829 sslset.verify = false;
830 }
831 | SELFSIGNED ':' ALLOW {
832 sslset.flags = SSL_Enabled;
833 sslset.allowSelfSigned = true;
834 }
835 | SELFSIGNED ':' REJECTOPT {
836 sslset.flags = SSL_Enabled;
837 sslset.allowSelfSigned = false;
838 }
839 | VERSIONOPT ':' sslversionlist {
840 sslset.flags = SSL_Enabled;
841 }
842 | CIPHER ':' STRING {
843 FREE(sslset.ciphers);
844 sslset.ciphers = $<string>3;
845 }
846 | PEMFILE ':' PATH {
847 _setPEM(&(sslset.pemfile), $3, "SSL server PEM file", true);
848 }
849 | PEMCHAIN ':' PATH {
850 _setPEM(&(sslset.pemchain), $3, "SSL certificate chain PEM file", true);
851 }
852 | PEMKEY ':' PATH {
853 _setPEM(&(sslset.pemkey), $3, "SSL server private key PEM file", true);
854 }
855 | CLIENTPEMFILE ':' PATH {
856 _setPEM(&(sslset.clientpemfile), $3, "SSL client PEM file", true);
857 }
858 | CACERTIFICATEFILE ':' PATH {
859 _setPEM(&(sslset.CACertificateFile), $3, "SSL CA certificates file", true);
860 }
861 | CACERTIFICATEPATH ':' PATH {
862 _setPEM(&(sslset.CACertificatePath), $3, "SSL CA certificates directory", false);
863 }
864 ;
865
866 sslexpire : CERTIFICATE VALID expireoperator NUMBER DAY {
867 sslset.flags = SSL_Enabled;
868 portset.target.net.ssl.certificate.minimumDays = $<number>4;
869 }
870 ;
871
872 expireoperator : /* EMPTY */
873 | GREATER
874 ;
875
876 sslchecksum : CERTIFICATE CHECKSUM checksumoperator STRING {
877 sslset.flags = SSL_Enabled;
878 sslset.checksum = $<string>4;
879 switch (cleanup_hash_string(sslset.checksum)) {
880 case 32:
881 sslset.checksumType = Hash_Md5;
882 break;
883 case 40:
884 sslset.checksumType = Hash_Sha1;
885 break;
886 default:
887 yyerror2("Unknown checksum type: [%s] is not MD5 nor SHA1", sslset.checksum);
888 }
889 }
890 | CERTIFICATE CHECKSUM MD5HASH checksumoperator STRING {
891 sslset.flags = SSL_Enabled;
892 sslset.checksum = $<string>5;
893 if (cleanup_hash_string(sslset.checksum) != 32)
894 yyerror2("Unknown checksum type: [%s] is not MD5", sslset.checksum);
895 sslset.checksumType = Hash_Md5;
896 }
897 | CERTIFICATE CHECKSUM SHA1HASH checksumoperator STRING {
898 sslset.flags = SSL_Enabled;
899 sslset.checksum = $<string>5;
900 if (cleanup_hash_string(sslset.checksum) != 40)
901 yyerror2("Unknown checksum type: [%s] is not SHA1", sslset.checksum);
902 sslset.checksumType = Hash_Sha1;
903 }
904 ;
905
906 checksumoperator : /* EMPTY */
907 | EQUAL
908 ;
909
910 sslversionlist : /* EMPTY */
911 | sslversionlist sslversion
912 ;
913
914 sslversion : SSLV2 {
915 #if defined OPENSSL_NO_SSL2 || ! defined HAVE_SSLV2 || ! defined HAVE_OPENSSL
916 yyerror("Your SSL Library does not support SSL version 2");
917 #else
918 _setSSLVersion(SSL_V2);
919 #endif
920 }
921 | NOSSLV2 {
922 _unsetSSLVersion(SSL_V2);
923 }
924 | SSLV3 {
925 #if defined OPENSSL_NO_SSL3 || ! defined HAVE_OPENSSL
926 yyerror("Your SSL Library does not support SSL version 3");
927 #else
928 _setSSLVersion(SSL_V3);
929 #endif
930 }
931 | NOSSLV3 {
932 _unsetSSLVersion(SSL_V3);
933 }
934 | TLSV1 {
935 #if defined OPENSSL_NO_TLS1_METHOD || ! defined HAVE_OPENSSL
936 yyerror("Your SSL Library does not support TLS version 1.0");
937 #else
938 _setSSLVersion(SSL_TLSV1);
939 #endif
940 }
941 | NOTLSV1 {
942 _unsetSSLVersion(SSL_TLSV1);
943 }
944 | TLSV11 {
945 #if defined OPENSSL_NO_TLS1_1_METHOD || ! defined HAVE_TLSV1_1 || ! defined HAVE_OPENSSL
946 yyerror("Your SSL Library does not support TLS version 1.1");
947 #else
948 _setSSLVersion(SSL_TLSV11);
949 #endif
950 }
951 | NOTLSV11 {
952 _unsetSSLVersion(SSL_TLSV11);
953 }
954 | TLSV12 {
955 #if defined OPENSSL_NO_TLS1_2_METHOD || ! defined HAVE_TLSV1_2 || ! defined HAVE_OPENSSL
956 yyerror("Your SSL Library does not support TLS version 1.2");
957 #else
958 _setSSLVersion(SSL_TLSV12);
959 #endif
960 }
961 | NOTLSV12 {
962 _unsetSSLVersion(SSL_TLSV12);
963 }
964 | TLSV13 {
965 #if defined OPENSSL_NO_TLS1_3_METHOD || ! defined HAVE_TLSV1_3 || ! defined HAVE_OPENSSL
966 yyerror("Your SSL Library does not support TLS version 1.3");
967 #else
968 _setSSLVersion(SSL_TLSV13);
969 #endif
970 }
971 | NOTLSV13 {
972 _unsetSSLVersion(SSL_TLSV13);
973 }
974 | AUTO {
975 // Enable just TLS 1.2 and 1.3 by default
976 #if ! defined OPENSSL_NO_TLS1_2_METHOD && defined HAVE_TLSV1_2 && defined HAVE_OPENSSL
977 _setSSLVersion(SSL_TLSV12);
978 #endif
979 #if ! defined OPENSSL_NO_TLS1_3_METHOD && defined HAVE_TLSV1_3 && defined HAVE_OPENSSL
980 _setSSLVersion(SSL_TLSV13);
981 #endif
982 }
983 ;
984
985 certmd5 : CERTMD5 STRING { // Backward compatibility
986 sslset.flags = SSL_Enabled;
987 sslset.checksum = $<string>2;
988 if (cleanup_hash_string(sslset.checksum) != 32)
989 yyerror2("Unknown checksum type: [%s] is not MD5", sslset.checksum);
990 sslset.checksumType = Hash_Md5;
991 }
992 ;
993
994 setmailservers : SET MAILSERVER mailserverlist nettimeout hostname {
995 if (($<number>4) > SMTP_TIMEOUT)
996 Run.mailserver_timeout = $<number>4;
997 Run.mail_hostname = $<string>5;
998 }
999 ;
1000
1001 setmailformat : SET MAILFORMAT '{' formatoptionlist '}' {
1002 if (mailset.from) {
1003 Run.MailFormat.from = mailset.from;
1004 } else {
1005 Run.MailFormat.from = Address_new();
1006 Run.MailFormat.from->address = Str_dup(ALERT_FROM);
1007 }
1008 if (mailset.replyto)
1009 Run.MailFormat.replyto = mailset.replyto;
1010 Run.MailFormat.subject = mailset.subject ? mailset.subject : Str_dup(ALERT_SUBJECT);
1011 Run.MailFormat.message = mailset.message ? mailset.message : Str_dup(ALERT_MESSAGE);
1012 reset_mailset();
1013 }
1014 ;
1015
1016 mailserverlist : mailserver
1017 | mailserverlist mailserver
1018 ;
1019
1020 mailserver : STRING mailserveroptlist {
1021 /* Restore the current text overridden by lookahead */
1022 FREE(argyytext);
1023 argyytext = Str_dup($1);
1024
1025 mailserverset.host = $1;
1026 mailserverset.port = PORT_SMTP;
1027 addmailserver(&mailserverset);
1028 }
1029 | STRING PORT NUMBER mailserveroptlist {
1030 /* Restore the current text overridden by lookahead */
1031 FREE(argyytext);
1032 argyytext = Str_dup($1);
1033
1034 mailserverset.host = $1;
1035 mailserverset.port = $<number>3;
1036 addmailserver(&mailserverset);
1037 }
1038 ;
1039
1040 mailserveroptlist : /* EMPTY */
1041 | mailserveroptlist mailserveropt
1042 ;
1043
1044 mailserveropt : username {
1045 mailserverset.username = $<string>1;
1046 }
1047 | password {
1048 mailserverset.password = $<string>1;
1049 }
1050 | ssl
1051 | sslchecksum
1052 | sslversion
1053 | certmd5
1054 ;
1055
1056 sethttpd : SET HTTPD httpdlist {
1057 if (sslset.flags & SSL_Enabled) {
1058 #ifdef HAVE_OPENSSL
1059 if (sslset.pemfile) {
1060 if (sslset.pemchain || sslset.pemkey) {
1061 yyerror("SSL server option pemfile and pemchain|pemkey are mutually exclusive");
1062 } else if (! file_checkStat(sslset.pemfile, "SSL server PEM file", S_IRWXU | S_IRGRP | S_IXGRP)) {
1063 yyerror("SSL server PEM file permissions check failed");
1064 } else {
1065 _setSSLOptions(&(Run.httpd.socket.net.ssl));
1066 }
1067 } else if (sslset.pemchain && sslset.pemkey) {
1068 if (! file_checkStat(sslset.pemkey, "SSL server private key PEM file", S_IRWXU | S_IRGRP | S_IXGRP)) {
1069 yyerror("SSL server private key PEM file permissions check failed");
1070 } else {
1071 _setSSLOptions(&(Run.httpd.socket.net.ssl));
1072 }
1073 } else {
1074 yyerror("SSL server PEM file is required (please use ssl pemfile option)");
1075 }
1076 #else
1077 yyerror("SSL is not supported");
1078 #endif
1079 }
1080 }
1081 ;
1082
1083 httpdlist : /* EMPTY */
1084 | httpdlist httpdoption
1085 ;
1086
1087 httpdoption : ssl
1088 | pemfile
1089 | clientpemfile
1090 | allowselfcert
1091 | signature
1092 | bindaddress
1093 | allow
1094 | httpdport
1095 | httpdsocket
1096 ;
1097
1098 /* deprecated by "ssl" options since monit 5.21 (kept for backward compatibility) */
1099 pemfile : PEMFILE PATH {
1100 _setPEM(&(sslset.pemfile), $2, "SSL server PEM file", true);
1101 }
1102 ;
1103
1104 /* deprecated by "ssl" options since monit 5.21 (kept for backward compatibility) */
1105 clientpemfile : CLIENTPEMFILE PATH {
1106 _setPEM(&(sslset.clientpemfile), $2, "SSL client PEM file", true);
1107 }
1108 ;
1109
1110 /* deprecated by "ssl" options since monit 5.21 (kept for backward compatibility) */
1111 allowselfcert : ALLOWSELFCERTIFICATION {
1112 sslset.flags = SSL_Enabled;
1113 sslset.allowSelfSigned = true;
1114 }
1115 ;
1116
1117 httpdport : PORT NUMBER {
1118 Run.httpd.flags |= Httpd_Net;
1119 Run.httpd.socket.net.port = $2;
1120 }
1121 ;
1122
1123 httpdsocket : UNIXSOCKET PATH httpdsocketoptionlist {
1124 Run.httpd.flags |= Httpd_Unix;
1125 Run.httpd.socket.unix.path = $2;
1126 }
1127 ;
1128
1129 httpdsocketoptionlist : /* EMPTY */
1130 | httpdsocketoptionlist httpdsocketoption
1131 ;
1132
1133 httpdsocketoption : UID STRING {
1134 Run.httpd.flags |= Httpd_UnixUid;
1135 Run.httpd.socket.unix.uid = get_uid($2, 0);
1136 FREE($2);
1137 }
1138 | GID STRING {
1139 Run.httpd.flags |= Httpd_UnixGid;
1140 Run.httpd.socket.unix.gid = get_gid($2, 0);
1141 FREE($2);
1142 }
1143 | UID NUMBER {
1144 Run.httpd.flags |= Httpd_UnixUid;
1145 Run.httpd.socket.unix.uid = get_uid(NULL, $2);
1146 }
1147 | GID NUMBER {
1148 Run.httpd.flags |= Httpd_UnixGid;
1149 Run.httpd.socket.unix.gid = get_gid(NULL, $2);
1150 }
1151 | PERMISSION NUMBER {
1152 Run.httpd.flags |= Httpd_UnixPermission;
1153 Run.httpd.socket.unix.permission = check_perm($2);
1154 }
1155 ;
1156
1157 sigenable : SIGNATURE ENABLE
1158 | ENABLE SIGNATURE
1159 ;
1160
1161 sigdisable : SIGNATURE DISABLE
1162 | DISABLE SIGNATURE
1163 ;
1164
1165 signature : sigenable {
1166 Run.httpd.flags |= Httpd_Signature;
1167 }
1168 | sigdisable {
1169 Run.httpd.flags &= ~Httpd_Signature;
1170 }
1171 ;
1172
1173 bindaddress : ADDRESS STRING {
1174 Run.httpd.socket.net.address = $2;
1175 }
1176 ;
1177
1178 allow : ALLOW STRING':'STRING readonly {
1179 addcredentials($2, $4, Digest_Cleartext, $<number>5);
1180 }
1181 | ALLOW '@'STRING readonly {
1182 #ifdef HAVE_LIBPAM
1183 addpamauth($3, $<number>4);
1184 #else
1185 yyerror("PAM is not supported");
1186 FREE($3);
1187 #endif
1188 }
1189 | ALLOW PATH {
1190 addhtpasswdentry($2, NULL, Digest_Cleartext);
1191 FREE($2);
1192 }
1193 | ALLOW CLEARTEXT PATH {
1194 addhtpasswdentry($3, NULL, Digest_Cleartext);
1195 FREE($3);
1196 }
1197 | ALLOW MD5HASH PATH {
1198 addhtpasswdentry($3, NULL, Digest_Md5);
1199 FREE($3);
1200 }
1201 | ALLOW CRYPT PATH {
1202 addhtpasswdentry($3, NULL, Digest_Crypt);
1203 FREE($3);
1204 }
1205 | ALLOW PATH {
1206 htpasswd_file = $2;
1207 digesttype = Digest_Cleartext;
1208 }
1209 allowuserlist {
1210 FREE(htpasswd_file);
1211 }
1212 | ALLOW CLEARTEXT PATH {
1213 htpasswd_file = $3;
1214 digesttype = Digest_Cleartext;
1215 }
1216 allowuserlist {
1217 FREE(htpasswd_file);
1218 }
1219 | ALLOW MD5HASH PATH {
1220 htpasswd_file = $3;
1221 digesttype = Digest_Md5;
1222 }
1223 allowuserlist {
1224 FREE(htpasswd_file);
1225 }
1226 | ALLOW CRYPT PATH {
1227 htpasswd_file = $3;
1228 digesttype = Digest_Crypt;
1229 }
1230 allowuserlist {
1231 FREE(htpasswd_file);
1232 }
1233 | ALLOW STRING {
1234 if (! Engine_addAllow($2))
1235 yywarning2("invalid allow option: %s", $2);
1236 FREE($2);
1237 }
1238 ;
1239
1240 allowuserlist : allowuser
1241 | allowuserlist allowuser
1242 ;
1243
1244 allowuser : STRING {
1245 addhtpasswdentry(htpasswd_file, $1, digesttype);
1246 FREE($1);
1247 }
1248 ;
1249
1250 readonly : /* EMPTY */ {
1251 $<number>$ = false;
1252 }
1253 | READONLY {
1254 $<number>$ = true;
1255 }
1256 ;
1257
1258 checkproc : CHECKPROC SERVICENAME PIDFILE PATH {
1259 createservice(Service_Process, $<string>2, $4, check_process);
1260 }
1261 | CHECKPROC SERVICENAME PATHTOK PATH {
1262 createservice(Service_Process, $<string>2, $4, check_process);
1263 }
1264 | CHECKPROC SERVICENAME MATCH STRING {
1265 createservice(Service_Process, $<string>2, $4, check_process);
1266 matchset.ignore = false;
1267 matchset.match_path = NULL;
1268 matchset.match_string = Str_dup($4);
1269 addmatch(&matchset, Action_Ignored, 0);
1270 }
1271 | CHECKPROC SERVICENAME MATCH PATH {
1272 createservice(Service_Process, $<string>2, $4, check_process);
1273 matchset.ignore = false;
1274 matchset.match_path = NULL;
1275 matchset.match_string = Str_dup($4);
1276 addmatch(&matchset, Action_Ignored, 0);
1277 }
1278 ;
1279
1280 checkfile : CHECKFILE SERVICENAME PATHTOK PATH {
1281 createservice(Service_File, $<string>2, $4, check_file);
1282 }
1283 ;
1284
1285 checkfilesys : CHECKFILESYS SERVICENAME PATHTOK PATH {
1286 createservice(Service_Filesystem, $<string>2, $4, check_filesystem);
1287 }
1288 | CHECKFILESYS SERVICENAME PATHTOK STRING {
1289 createservice(Service_Filesystem, $<string>2, $4, check_filesystem);
1290 }
1291 ;
1292
1293 checkdir : CHECKDIR SERVICENAME PATHTOK PATH {
1294 createservice(Service_Directory, $<string>2, $4, check_directory);
1295 }
1296 ;
1297
1298 checkhost : CHECKHOST SERVICENAME ADDRESS STRING {
1299 createservice(Service_Host, $<string>2, $4, check_remote_host);
1300 }
1301 ;
1302
1303 checknet : CHECKNET SERVICENAME ADDRESS STRING {
1304 if (Link_isGetByAddressSupported()) {
1305 createservice(Service_Net, $<string>2, $4, check_net);
1306 current->inf.net->stats = Link_createForAddress($4);
1307 } else {
1308 yyerror("Network monitoring by IP address is not supported on this platform, please use 'check network <foo> with interface <bar>' instead");
1309 }
1310 }
1311 | CHECKNET SERVICENAME INTERFACE STRING {
1312 createservice(Service_Net, $<string>2, $4, check_net);
1313 current->inf.net->stats = Link_createForInterface($4);
1314 }
1315 ;
1316
1317 checksystem : CHECKSYSTEM SERVICENAME {
1318 char *servicename = $<string>2;
1319 if (Str_sub(servicename, "$HOST")) {
1320 char hostname[STRLEN];
1321 if (gethostname(hostname, sizeof(hostname))) {
1322 Log_error("System hostname error -- %s\n", STRERROR);
1323 cfg_errflag++;
1324 } else {
1325 Util_replaceString(&servicename, "$HOST", hostname);
1326 }
1327 }
1328 Run.system = createservice(Service_System, servicename, NULL, check_system); // The name given in the 'check system' statement overrides system hostname
1329 }
1330 ;
1331
1332 checkfifo : CHECKFIFO SERVICENAME PATHTOK PATH {
1333 createservice(Service_Fifo, $<string>2, $4, check_fifo);
1334 }
1335 ;
1336
1337 checkprogram : CHECKPROGRAM SERVICENAME PATHTOK argumentlist programtimeout {
1338 createservice(Service_Program, $<string>2, NULL, check_program);
1339 current->program->timeout = $<number>5;
1340 current->program->lastOutput = StringBuffer_create(64);
1341 current->program->inprogressOutput = StringBuffer_create(64);
1342 }
1343 | CHECKPROGRAM SERVICENAME PATHTOK argumentlist useroptionlist programtimeout {
1344 createservice(Service_Program, $<string>2, NULL, check_program);
1345 current->program->timeout = $<number>6;
1346 current->program->lastOutput = StringBuffer_create(64);
1347 current->program->inprogressOutput = StringBuffer_create(64);
1348 }
1349 ;
1350
1351 start : START argumentlist starttimeout {
1352 addcommand(START, $<number>3);
1353 }
1354 | START argumentlist useroptionlist starttimeout {
1355 addcommand(START, $<number>4);
1356 }
1357 ;
1358
1359 stop : STOP argumentlist stoptimeout {
1360 addcommand(STOP, $<number>3);
1361 }
1362 | STOP argumentlist useroptionlist stoptimeout {
1363 addcommand(STOP, $<number>4);
1364 }
1365 ;
1366
1367
1368 restart : RESTART argumentlist restarttimeout {
1369 addcommand(RESTART, $<number>3);
1370 }
1371 | RESTART argumentlist useroptionlist restarttimeout {
1372 addcommand(RESTART, $<number>4);
1373 }
1374 ;
1375
1376 argumentlist : argument
1377 | argumentlist argument
1378 ;
1379
1380 useroptionlist : useroption
1381 | useroptionlist useroption
1382 ;
1383
1384 argument : STRING {
1385 addargument($1);
1386 }
1387 | PATH {
1388 addargument($1);
1389 }
1390 ;
1391
1392 useroption : UID STRING {
1393 addeuid(get_uid($2, 0));
1394 FREE($2);
1395 }
1396 | GID STRING {
1397 addegid(get_gid($2, 0));
1398 FREE($2);
1399 }
1400 | UID NUMBER {
1401 addeuid(get_uid(NULL, $2));
1402 }
1403 | GID NUMBER {
1404 addegid(get_gid(NULL, $2));
1405 }
1406 ;
1407
1408 username : USERNAME MAILADDR {
1409 $<string>$ = $2;
1410 }
1411 | USERNAME STRING {
1412 $<string>$ = $2;
1413 }
1414 ;
1415
1416 password : PASSWORD STRING {
1417 $<string>$ = $2;
1418 }
1419 ;
1420
1421 database : DATABASE STRING {
1422 $<string>$ = $2;
1423 }
1424 ;
1425
1426 hostname : /* EMPTY */ {
1427 $<string>$ = NULL;
1428 }
1429 | HOSTNAME STRING {
1430 $<string>$ = $2;
1431 }
1432 ;
1433
1434 connection : IF FAILED host port connectionoptlist rate1 THEN action1 recovery_success {
1435 /* This is a workaround to support content match without having to create an URL object. 'urloption' creates the Request_T object we need minus the URL object, but with enough information to perform content test.
1436 TODO: Parser is in need of refactoring */
1437 portset.url_request = urlrequest;
1438 portset.check_invers = false;
1439 portset.responsetime.operator = responsetimeset.operator;
1440 portset.responsetime.limit = responsetimeset.limit;
1441 addeventaction(&(portset).action, $<number>8, $<number>9);
1442 addport(&(current->portlist), &portset);
1443 }
1444 | IF SUCCEEDED host port connectionoptlist rate1 THEN action1 recovery_failure {
1445 portset.url_request = urlrequest;
1446 portset.check_invers = true;
1447 portset.responsetime.operator = responsetimeset.operator;
1448 portset.responsetime.limit = responsetimeset.limit;
1449 addeventaction(&(portset).action, $<number>8, $<number>9);
1450 addport(&(current->portlist), &portset);
1451 }
1452 ;
1453
1454 connectionoptlist : /* EMPTY */
1455 | connectionoptlist connectionopt
1456 ;
1457
1458 connectionopt : ip
1459 | type
1460 | protocol
1461 | sendexpect
1462 | urloption
1463 | connectiontimeout
1464 | responsetime
1465 | outgoing
1466 | retry
1467 | ssl
1468 | sslchecksum
1469 | sslexpire
1470 ;
1471
1472 connectionurl : IF FAILED URL URLOBJECT connectionurloptlist rate1 THEN action1 recovery_success {
1473 portset.check_invers = false;
1474 portset.responsetime.operator = responsetimeset.operator;
1475 portset.responsetime.limit = responsetimeset.limit;
1476 prepare_urlrequest($<url>4);
1477 addeventaction(&(portset).action, $<number>8, $<number>9);
1478 addport(&(current->portlist), &portset);
1479 }
1480 | IF SUCCEEDED URL URLOBJECT connectionurloptlist rate1 THEN action1 recovery_failure {
1481 portset.check_invers = true;
1482 portset.responsetime.operator = responsetimeset.operator;
1483 portset.responsetime.limit = responsetimeset.limit;
1484 prepare_urlrequest($<url>4);
1485 addeventaction(&(portset).action, $<number>8, $<number>9);
1486 addport(&(current->portlist), &portset);
1487 }
1488 ;
1489
1490 connectionurloptlist : /* EMPTY */
1491 | connectionurloptlist connectionurlopt
1492 ;
1493
1494 connectionurlopt : urloption
1495 | connectiontimeout
1496 | retry
1497 | ssl
1498 | sslchecksum
1499 | sslexpire
1500 ;
1501
1502 connectionunix : IF FAILED unixsocket connectionuxoptlist rate1 THEN action1 recovery_success {
1503 portset.check_invers = false;
1504 portset.responsetime.operator = responsetimeset.operator;
1505 portset.responsetime.limit = responsetimeset.limit;
1506 addeventaction(&(portset).action, $<number>7, $<number>8);
1507 addport(&(current->socketlist), &portset);
1508 }
1509 | IF SUCCEEDED unixsocket connectionuxoptlist rate1 THEN action1 recovery_failure {
1510 portset.check_invers = true;
1511 portset.responsetime.operator = responsetimeset.operator;
1512 portset.responsetime.limit = responsetimeset.limit;
1513 addeventaction(&(portset).action, $<number>7, $<number>8);
1514 addport(&(current->socketlist), &portset);
1515 }
1516 ;
1517
1518 connectionuxoptlist : /* EMPTY */
1519 | connectionuxoptlist connectionuxopt
1520 ;
1521
1522 connectionuxopt : type
1523 | protocol
1524 | sendexpect
1525 | connectiontimeout
1526 | responsetime
1527 | retry
1528 ;
1529
1530 icmp : IF FAILED ICMP icmptype icmpoptlist rate1 THEN action1 recovery_success {
1531 icmpset.family = Socket_Ip;
1532 icmpset.check_invers = false;
1533 icmpset.type = $<number>4;
1534 icmpset.responsetime.operator = responsetimeset.operator;
1535 icmpset.responsetime.limit = responsetimeset.limit;
1536 addeventaction(&(icmpset).action, $<number>8, $<number>9);
1537 addicmp(&icmpset);
1538 }
1539 | IF FAILED PING icmpoptlist rate1 THEN action1 recovery_success {
1540 icmpset.family = Socket_Ip;
1541 icmpset.check_invers = false;
1542 addeventaction(&(icmpset).action, $<number>7, $<number>8);
1543 addicmp(&icmpset);
1544 }
1545 | IF FAILED PING4 icmpoptlist rate1 THEN action1 recovery_success {
1546 icmpset.family = Socket_Ip4;
1547 icmpset.check_invers = false;
1548 addeventaction(&(icmpset).action, $<number>7, $<number>8);
1549 addicmp(&icmpset);
1550 }
1551 | IF FAILED PING6 icmpoptlist rate1 THEN action1 recovery_success {
1552 icmpset.family = Socket_Ip6;
1553 icmpset.check_invers = false;
1554 addeventaction(&(icmpset).action, $<number>7, $<number>8);
1555 addicmp(&icmpset);
1556 }
1557 | IF SUCCEEDED ICMP icmptype icmpoptlist rate1 THEN action1 recovery_failure {
1558 icmpset.family = Socket_Ip;
1559 icmpset.check_invers = true;
1560 icmpset.type = $<number>4;
1561 icmpset.responsetime.operator = responsetimeset.operator;
1562 icmpset.responsetime.limit = responsetimeset.limit;
1563 addeventaction(&(icmpset).action, $<number>8, $<number>9);
1564 addicmp(&icmpset);
1565 }
1566 | IF SUCCEEDED PING icmpoptlist rate1 THEN action1 recovery_failure {
1567 icmpset.family = Socket_Ip;
1568 icmpset.check_invers = true;
1569 addeventaction(&(icmpset).action, $<number>7, $<number>8);
1570 addicmp(&icmpset);
1571 }
1572 | IF SUCCEEDED PING4 icmpoptlist rate1 THEN action1 recovery_failure {
1573 icmpset.family = Socket_Ip4;
1574 icmpset.check_invers = true;
1575 addeventaction(&(icmpset).action, $<number>7, $<number>8);
1576 addicmp(&icmpset);
1577 }
1578 | IF SUCCEEDED PING6 icmpoptlist rate1 THEN action1 recovery_failure {
1579 icmpset.family = Socket_Ip6;
1580 icmpset.check_invers = true;
1581 addeventaction(&(icmpset).action, $<number>7, $<number>8);
1582 addicmp(&icmpset);
1583 }
1584 ;
1585
1586 icmpoptlist : /* EMPTY */
1587 | icmpoptlist icmpopt
1588 ;
1589
1590 icmpopt : icmpcount
1591 | icmpsize
1592 | icmptimeout
1593 | icmpoutgoing
1594 ;
1595
1596 host : /* EMPTY */ {
1597 portset.hostname = Str_dup(current->type == Service_Host ? current->path : LOCALHOST);
1598 }
1599 | HOST STRING {
1600 portset.hostname = $2;
1601 }
1602 ;
1603
1604 port : PORT NUMBER {
1605 portset.target.net.port = $2;
1606 }
1607 ;
1608
1609 unixsocket : UNIXSOCKET PATH {
1610 portset.family = Socket_Unix;
1611 portset.target.unix.pathname = $2;
1612 }
1613 ;
1614
1615 ip : IPV4 {
1616 portset.family = Socket_Ip4;
1617 }
1618 | IPV6 {
1619 portset.family = Socket_Ip6;
1620 }
1621 ;
1622
1623 type : TYPE TCP {
1624 portset.type = Socket_Tcp;
1625 }
1626 | TYPE TCPSSL typeoptlist { // The typelist is kept for backward compatibility (replaced by ssloptionlist)
1627 portset.type = Socket_Tcp;
1628 sslset.flags = SSL_Enabled;
1629 }
1630 | TYPE UDP {
1631 portset.type = Socket_Udp;
1632 }
1633 ;
1634
1635 typeoptlist : /* EMPTY */
1636 | typeoptlist typeopt
1637 ;
1638
1639 typeopt : sslversion
1640 | certmd5
1641 ;
1642
1643 outgoing : ADDRESS STRING {
1644 _parseOutgoingAddress($<string>2, &(portset.outgoing));
1645 }
1646 ;
1647
1648 protocol : PROTOCOL APACHESTATUS apache_stat_list {
1649 portset.protocol = Protocol_get(Protocol_APACHESTATUS);
1650 }
1651 | PROTOCOL CLAMAV {
1652 portset.protocol = Protocol_get(Protocol_CLAMAV);
1653 }
1654 | PROTOCOL DEFAULT {
1655 portset.protocol = Protocol_get(Protocol_DEFAULT);
1656 }
1657 | PROTOCOL DNS {
1658 portset.protocol = Protocol_get(Protocol_DNS);
1659 }
1660 | PROTOCOL DWP {
1661 portset.protocol = Protocol_get(Protocol_DWP);
1662 }
1663 | PROTOCOL FAIL2BAN {
1664 portset.protocol = Protocol_get(Protocol_FAIL2BAN);
1665 }
1666 | PROTOCOL FTP {
1667 portset.protocol = Protocol_get(Protocol_FTP);
1668 }
1669 | PROTOCOL GPS {
1670 portset.protocol = Protocol_get(Protocol_GPS);
1671 }
1672 | PROTOCOL HTTP httplist {
1673 portset.protocol = Protocol_get(Protocol_HTTP);
1674 }
1675 | PROTOCOL HTTPS httplist {
1676 sslset.flags = SSL_Enabled;
1677 portset.type = Socket_Tcp;
1678 portset.protocol = Protocol_get(Protocol_HTTP);
1679 }
1680 | PROTOCOL IMAP {
1681 portset.protocol = Protocol_get(Protocol_IMAP);
1682 }
1683 | PROTOCOL IMAPS {
1684 sslset.flags = SSL_Enabled;
1685 portset.type = Socket_Tcp;
1686 portset.protocol = Protocol_get(Protocol_IMAP);
1687 }
1688 | PROTOCOL LDAP2 {
1689 portset.protocol = Protocol_get(Protocol_LDAP2);
1690 }
1691 | PROTOCOL LDAP3 {
1692 portset.protocol = Protocol_get(Protocol_LDAP3);
1693 }
1694 | PROTOCOL LMTP {
1695 portset.protocol = Protocol_get(Protocol_LMTP);
1696 }
1697 | PROTOCOL MEMCACHE {
1698 portset.protocol = Protocol_get(Protocol_MEMCACHE);
1699 }
1700 | PROTOCOL MONGODB {
1701 portset.protocol = Protocol_get(Protocol_MONGODB);
1702 }
1703 | PROTOCOL MQTT mqttlist {
1704 portset.protocol = Protocol_get(Protocol_MQTT);
1705 }
1706 | PROTOCOL MYSQL mysqllist {
1707 portset.protocol = Protocol_get(Protocol_MYSQL);
1708 }
1709 | PROTOCOL MYSQLS mysqllist {
1710 sslset.flags = SSL_StartTLS;
1711 portset.protocol = Protocol_get(Protocol_MYSQL);
1712 }
1713 | PROTOCOL NNTP {
1714 portset.protocol = Protocol_get(Protocol_NNTP);
1715 }
1716 | PROTOCOL NTP3 {
1717 portset.protocol = Protocol_get(Protocol_NTP3);
1718 portset.type = Socket_Udp;
1719 }
1720 | PROTOCOL PGSQL postgresqllist {
1721 portset.protocol = Protocol_get(Protocol_PGSQL);
1722 }
1723 | PROTOCOL POP {
1724 portset.protocol = Protocol_get(Protocol_POP);
1725 }
1726 | PROTOCOL POPS {
1727 sslset.flags = SSL_Enabled;
1728 portset.type = Socket_Tcp;
1729 portset.protocol = Protocol_get(Protocol_POP);
1730 }
1731 | PROTOCOL POSTFIXPOLICY {
1732 portset.protocol = Protocol_get(Protocol_POSTFIXPOLICY);
1733 }
1734 | PROTOCOL RADIUS radiuslist {
1735 portset.protocol = Protocol_get(Protocol_RADIUS);
1736 }
1737 | PROTOCOL RDATE {
1738 portset.protocol = Protocol_get(Protocol_RDATE);
1739 }
1740 | PROTOCOL REDIS {
1741 portset.protocol = Protocol_get(Protocol_REDIS);
1742 }
1743 | PROTOCOL RSYNC {
1744 portset.protocol = Protocol_get(Protocol_RSYNC);
1745 }
1746 | PROTOCOL SIEVE {
1747 portset.protocol = Protocol_get(Protocol_SIEVE);
1748 }
1749 | PROTOCOL SIP siplist {
1750 portset.protocol = Protocol_get(Protocol_SIP);
1751 }
1752 | PROTOCOL SMTP smtplist {
1753 portset.protocol = Protocol_get(Protocol_SMTP);
1754 }
1755 | PROTOCOL SMTPS smtplist {
1756 sslset.flags = SSL_Enabled;
1757 portset.type = Socket_Tcp;
1758 portset.protocol = Protocol_get(Protocol_SMTP);
1759 }
1760 | PROTOCOL SPAMASSASSIN {
1761 portset.protocol = Protocol_get(Protocol_SPAMASSASSIN);
1762 }
1763 | PROTOCOL SSH {
1764 portset.protocol = Protocol_get(Protocol_SSH);
1765 }
1766 | PROTOCOL TNS {
1767 portset.protocol = Protocol_get(Protocol_TNS);
1768 }
1769 | PROTOCOL WEBSOCKET websocketlist {
1770 portset.protocol = Protocol_get(Protocol_WEBSOCKET);
1771 }
1772 ;
1773
1774 sendexpect : SEND STRING {
1775 if (portset.protocol->check == check_default || portset.protocol->check == check_generic) {
1776 portset.protocol = Protocol_get(Protocol_GENERIC);
1777 addgeneric(&portset, $2, NULL);
1778 } else {
1779 yyerror("The SEND statement is not allowed in the %s protocol context", portset.protocol->name);
1780 }
1781 }
1782 | EXPECT STRING {
1783 if (portset.protocol->check == check_default || portset.protocol->check == check_generic) {
1784 portset.protocol = Protocol_get(Protocol_GENERIC);
1785 addgeneric(&portset, NULL, $2);
1786 } else {
1787 yyerror("The EXPECT statement is not allowed in the %s protocol context", portset.protocol->name);
1788 }
1789 }
1790 ;
1791
1792 websocketlist : websocket
1793 | websocketlist websocket
1794 ;
1795
1796 websocket : ORIGIN STRING {
1797 portset.parameters.websocket.origin = $<string>2;
1798 }
1799 | REQUEST PATH {
1800 portset.parameters.websocket.request = $<string>2;
1801 }
1802 | HOST STRING {
1803 portset.parameters.websocket.host = $<string>2;
1804 }
1805 | VERSIONOPT NUMBER {
1806 portset.parameters.websocket.version = $<number>2;
1807 }
1808 ;
1809
1810 smtplist : /* EMPTY */
1811 | smtplist smtp
1812 ;
1813
1814 smtp : username {
1815 portset.parameters.smtp.username = $<string>1;
1816 }
1817 | password {
1818 portset.parameters.smtp.password = $<string>1;
1819 }
1820 ;
1821
1822 mqttlist : /* EMPTY */
1823 | mqttlist mqtt
1824 ;
1825
1826 mqtt : username {
1827 portset.parameters.mqtt.username = $<string>1;
1828 }
1829 | password {
1830 portset.parameters.mqtt.password = $<string>1;
1831 }
1832 ;
1833
1834 mysqllist : /* EMPTY */
1835 | mysqllist mysql
1836 ;
1837
1838 mysql : username {
1839 portset.parameters.mysql.username = $<string>1;
1840 }
1841 | password {
1842 portset.parameters.mysql.password = $<string>1;
1843 }
1844 | RSAKEY CHECKSUM checksumoperator STRING {
1845 portset.parameters.mysql.rsaChecksum = $<string>4;
1846 switch (cleanup_hash_string(portset.parameters.mysql.rsaChecksum)) {
1847 case 32:
1848 portset.parameters.mysql.rsaChecksumType = Hash_Md5;
1849 break;
1850 case 40:
1851 portset.parameters.mysql.rsaChecksumType = Hash_Sha1;
1852 break;
1853 default:
1854 yyerror2("Unknown checksum type: [%s] is not MD5 nor SHA1", portset.parameters.mysql.rsaChecksum);
1855 }
1856 }
1857 | RSAKEY CHECKSUM MD5HASH checksumoperator STRING {
1858 portset.parameters.mysql.rsaChecksum = $<string>5;
1859 if (cleanup_hash_string(portset.parameters.mysql.rsaChecksum) != 32)
1860 yyerror2("Unknown checksum type: [%s] is not MD5", portset.parameters.mysql.rsaChecksum);
1861 portset.parameters.mysql.rsaChecksumType = Hash_Md5;
1862 }
1863 | RSAKEY CHECKSUM SHA1HASH checksumoperator STRING {
1864 portset.parameters.mysql.rsaChecksum = $<string>5;
1865 if (cleanup_hash_string(portset.parameters.mysql.rsaChecksum) != 40)
1866 yyerror2("Unknown checksum type: [%s] is not SHA1", portset.parameters.mysql.rsaChecksum);
1867 portset.parameters.mysql.rsaChecksumType = Hash_Sha1;
1868 }
1869 ;
1870
1871 postgresqllist : /* EMPTY */
1872 | postgresqllist postgresql
1873 ;
1874
1875 postgresql : username {
1876 portset.parameters.postgresql.username = $<string>1;
1877 }
1878 | password {
1879 portset.parameters.postgresql.password = $<string>1;
1880 }
1881 | database {
1882 portset.parameters.postgresql.database = $<string>1;
1883 }
1884 ;
1885
1886 target : TARGET MAILADDR {
1887 $<string>$ = $2;
1888 }
1889 | TARGET STRING {
1890 $<string>$ = $2;
1891 }
1892 ;
1893
1894 maxforward : MAXFORWARD NUMBER {
1895 $<number>$ = verifyMaxForward($2);
1896 }
1897 ;
1898
1899 siplist : /* EMPTY */
1900 | siplist sip
1901 ;
1902
1903 sip : target {
1904 portset.parameters.sip.target = $<string>1;
1905 }
1906 | maxforward {
1907 portset.parameters.sip.maxforward = $<number>1;
1908 }
1909 ;
1910
1911 httplist : /* EMPTY */
1912 | httplist http
1913 ;
1914
1915 http : username {
1916 portset.parameters.http.username = $<string>1;
1917 }
1918 | password {
1919 portset.parameters.http.password = $<string>1;
1920 }
1921 | request
1922 | responsesum
1923 | status
1924 | method
1925 | hostheader
1926 | '[' httpheaderlist ']'
1927 ;
1928
1929 status : STATUS operator NUMBER {
1930 if ($<number>3 < 0) {
1931 yyerror2("The status value must be greater or equal to 0");
1932 }
1933 portset.parameters.http.operator = $<number>2;
1934 portset.parameters.http.status = $<number>3;
1935 portset.parameters.http.hasStatus = true;
1936 }
1937 ;
1938
1939 method : METHOD GET {
1940 portset.parameters.http.method = Http_Get;
1941 }
1942 | METHOD HEAD {
1943 portset.parameters.http.method = Http_Head;
1944 }
1945 ;
1946
1947 request : REQUEST PATH {
1948 portset.parameters.http.request = Util_urlEncode($2, false);
1949 FREE($2);
1950 }
1951 | REQUEST STRING {
1952 portset.parameters.http.request = Util_urlEncode($2, false);
1953 FREE($2);
1954 }
1955 ;
1956
1957 responsesum : CHECKSUM STRING {
1958 portset.parameters.http.checksum = $2;
1959 }
1960 ;
1961
1962 hostheader : HOSTHEADER STRING {
1963 addhttpheader(&portset, Str_cat("Host:%s", $2));
1964 FREE($2);
1965 }
1966 ;
1967
1968 httpheaderlist : /* EMPTY */
1969 | httpheaderlist HTTPHEADER {
1970 addhttpheader(&portset, $2);
1971 }
1972 ;
1973
1974 secret : SECRET STRING {
1975 $<string>$ = $2;
1976 }
1977 ;
1978
1979 radiuslist : /* EMPTY */
1980 | radiuslist radius
1981 ;
1982
1983 radius : secret {
1984 portset.parameters.radius.secret = $<string>1;
1985 }
1986 ;
1987
1988 apache_stat_list: apache_stat
1989 | apache_stat_list apache_stat
1990 ;
1991
1992 apache_stat : username {
1993 portset.parameters.apachestatus.username = $<string>1;
1994 }
1995 | password {
1996 portset.parameters.apachestatus.password = $<string>1;
1997 }
1998 | PATHTOK PATH {
1999 portset.parameters.apachestatus.path = $<string>2;
2000 }
2001 | LOGLIMIT operator NUMBER PERCENT {
2002 portset.parameters.apachestatus.loglimitOP = $<number>2;
2003 portset.parameters.apachestatus.loglimit = $<number>3;
2004 }
2005 | CLOSELIMIT operator NUMBER PERCENT {
2006 portset.parameters.apachestatus.closelimitOP = $<number>2;
2007 portset.parameters.apachestatus.closelimit = $<number>3;
2008 }
2009 | DNSLIMIT operator NUMBER PERCENT {
2010 portset.parameters.apachestatus.dnslimitOP = $<number>2;
2011 portset.parameters.apachestatus.dnslimit = $<number>3;
2012 }
2013 | KEEPALIVELIMIT operator NUMBER PERCENT {
2014 portset.parameters.apachestatus.keepalivelimitOP = $<number>2;
2015 portset.parameters.apachestatus.keepalivelimit = $<number>3;
2016 }
2017 | REPLYLIMIT operator NUMBER PERCENT {
2018 portset.parameters.apachestatus.replylimitOP = $<number>2;
2019 portset.parameters.apachestatus.replylimit = $<number>3;
2020 }
2021 | REQUESTLIMIT operator NUMBER PERCENT {
2022 portset.parameters.apachestatus.requestlimitOP = $<number>2;
2023 portset.parameters.apachestatus.requestlimit = $<number>3;
2024 }
2025 | STARTLIMIT operator NUMBER PERCENT {
2026 portset.parameters.apachestatus.startlimitOP = $<number>2;
2027 portset.parameters.apachestatus.startlimit = $<number>3;
2028 }
2029 | WAITLIMIT operator NUMBER PERCENT {
2030 portset.parameters.apachestatus.waitlimitOP = $<number>2;
2031 portset.parameters.apachestatus.waitlimit = $<number>3;
2032 }
2033 | GRACEFULLIMIT operator NUMBER PERCENT {
2034 portset.parameters.apachestatus.gracefullimitOP = $<number>2;
2035 portset.parameters.apachestatus.gracefullimit = $<number>3;
2036 }
2037 | CLEANUPLIMIT operator NUMBER PERCENT {
2038 portset.parameters.apachestatus.cleanuplimitOP = $<number>2;
2039 portset.parameters.apachestatus.cleanuplimit = $<number>3;
2040 }
2041 ;
2042
2043 exist : IF NOT EXIST rate1 THEN action1 recovery_success {
2044 addeventaction(&(nonexistset).action, $<number>6, $<number>7);
2045 addnonexist(&nonexistset);
2046 }
2047 | IF EXIST rate1 THEN action1 recovery_success {
2048 addeventaction(&(existset).action, $<number>5, $<number>6);
2049 addexist(&existset);
2050 }
2051 ;
2052
2053
2054 pid : IF CHANGED PID rate1 THEN action1 {
2055 addeventaction(&(pidset).action, $<number>6, Action_Ignored);
2056 addpid(&pidset);
2057 }
2058 ;
2059
2060 ppid : IF CHANGED PPID rate1 THEN action1 {
2061 addeventaction(&(ppidset).action, $<number>6, Action_Ignored);
2062 addppid(&ppidset);
2063 }
2064 ;
2065
2066 uptime : IF UPTIME operator NUMBER time rate1 THEN action1 recovery_success {
2067 uptimeset.operator = $<number>3;
2068 uptimeset.uptime = ((unsigned long long)$4 * $<number>5);
2069 addeventaction(&(uptimeset).action, $<number>8, $<number>9);
2070 adduptime(&uptimeset);
2071 }
2072 ;
2073
2074 responsetime : RESPONSETIME operator NUMBER MILLISECOND {
2075 responsetimeset.operator = $<number>2;
2076 responsetimeset.limit = $3;
2077 }
2078 | RESPONSETIME operator NUMBER SECOND {
2079 responsetimeset.operator = $<number>2;
2080 responsetimeset.limit = $3 * 1000;
2081 }
2082 ;
2083
2084 icmpcount : COUNT NUMBER {
2085 icmpset.count = $<number>2;
2086 }
2087 ;
2088
2089 icmpsize : SIZE NUMBER {
2090 icmpset.size = $<number>2;
2091 if (icmpset.size < 8) {
2092 yyerror2("The minimum ping size is 8 bytes");
2093 } else if (icmpset.size > 1492) {
2094 yyerror2("The maximum ping size is 1492 bytes");
2095 }
2096 }
2097 ;
2098
2099 icmptimeout : TIMEOUT NUMBER SECOND {
2100 icmpset.timeout = $<number>2 * 1000; // timeout is in milliseconds internally
2101 }
2102 ;
2103
2104 icmpoutgoing : ADDRESS STRING {
2105 _parseOutgoingAddress($<string>2, &(icmpset.outgoing));
2106 }
2107 ;
2108
2109 stoptimeout : /* EMPTY */ {
2110 $<number>$ = Run.limits.stopTimeout;
2111 }
2112 | TIMEOUT NUMBER SECOND {
2113 $<number>$ = $2 * 1000; // milliseconds internally
2114 }
2115 ;
2116
2117 starttimeout : /* EMPTY */ {
2118 $<number>$ = Run.limits.startTimeout;
2119 }
2120 | TIMEOUT NUMBER SECOND {
2121 $<number>$ = $2 * 1000; // milliseconds internally
2122 }
2123 ;
2124
2125 restarttimeout : /* EMPTY */ {
2126 $<number>$ = Run.limits.restartTimeout;
2127 }
2128 | TIMEOUT NUMBER SECOND {
2129 $<number>$ = $2 * 1000; // milliseconds internally
2130 }
2131 ;
2132
2133 programtimeout : /* EMPTY */ {
2134 $<number>$ = Run.limits.programTimeout;
2135 }
2136 | TIMEOUT NUMBER SECOND {
2137 $<number>$ = $2 * 1000; // milliseconds internally
2138 }
2139 ;
2140
2141 nettimeout : /* EMPTY */ {
2142 $<number>$ = Run.limits.networkTimeout;
2143 }
2144 | TIMEOUT NUMBER SECOND {
2145 $<number>$ = $2 * 1000; // net timeout is in milliseconds internally
2146 }
2147 ;
2148
2149 connectiontimeout : TIMEOUT NUMBER SECOND {
2150 portset.timeout = $<number>2 * 1000; // timeout is in milliseconds internally
2151 }
2152 ;
2153
2154 retry : RETRY NUMBER {
2155 portset.retry = $2;
2156 }
2157 ;
2158
2159 actionrate : IF NUMBER RESTART NUMBER CYCLE THEN action1 {
2160 actionrateset.count = $2;
2161 actionrateset.cycle = $4;
2162 addeventaction(&(actionrateset).action, $<number>7, Action_Alert);
2163 addactionrate(&actionrateset);
2164 }
2165 | IF NUMBER RESTART NUMBER CYCLE THEN TIMEOUT {
2166 actionrateset.count = $2;
2167 actionrateset.cycle = $4;
2168 addeventaction(&(actionrateset).action, Action_Unmonitor, Action_Alert);
2169 addactionrate(&actionrateset);
2170 }
2171 ;
2172
2173 urloption : CONTENT urloperator STRING {
2174 seturlrequest($<number>2, $<string>3);
2175 FREE($3);
2176 }
2177 ;
2178
2179 urloperator : EQUAL { $<number>$ = Operator_Equal; }
2180 | NOTEQUAL { $<number>$ = Operator_NotEqual; }
2181 ;
2182
2183 alert : alertmail formatlist reminder {
2184 mailset.events = Event_All;
2185 addmail($<string>1, &mailset, ¤t->maillist);
2186 }
2187 | alertmail '{' eventoptionlist '}' formatlist reminder {
2188 addmail($<string>1, &mailset, ¤t->maillist);
2189 }
2190 | alertmail NOT '{' eventoptionlist '}' formatlist reminder {
2191 mailset.events = ~mailset.events;
2192 addmail($<string>1, &mailset, ¤t->maillist);
2193 }
2194 | noalertmail {
2195 addmail($<string>1, &mailset, ¤t->maillist);
2196 }
2197 ;
2198
2199 alertmail : ALERT MAILADDR { $<string>$ = $2; }
2200 ;
2201
2202 noalertmail : NOALERT MAILADDR { $<string>$ = $2; }
2203 ;
2204
2205 eventoptionlist : eventoption
2206 | eventoptionlist eventoption
2207 ;
2208
2209 eventoption : ACTION { mailset.events |= Event_Action; }
2210 | BYTEIN { mailset.events |= Event_ByteIn; }
2211 | BYTEOUT { mailset.events |= Event_ByteOut; }
2212 | CHECKSUM { mailset.events |= Event_Checksum; }
2213 | CONNECTION { mailset.events |= Event_Connection; }
2214 | CONTENT { mailset.events |= Event_Content; }
2215 | DATA { mailset.events |= Event_Data; }
2216 | EXEC { mailset.events |= Event_Exec; }
2217 | EXIST { mailset.events |= Event_Exist; }
2218 | FSFLAG { mailset.events |= Event_FsFlag; }
2219 | GID { mailset.events |= Event_Gid; }
2220 | ICMP { mailset.events |= Event_Icmp; }
2221 | INSTANCE { mailset.events |= Event_Instance; }
2222 | INVALID { mailset.events |= Event_Invalid; }
2223 | LINK { mailset.events |= Event_Link; }
2224 | NONEXIST { mailset.events |= Event_NonExist; }
2225 | PACKETIN { mailset.events |= Event_PacketIn; }
2226 | PACKETOUT { mailset.events |= Event_PacketOut; }
2227 | PERMISSION { mailset.events |= Event_Permission; }
2228 | PID { mailset.events |= Event_Pid; }
2229 | PPID { mailset.events |= Event_PPid; }
2230 | RESOURCE { mailset.events |= Event_Resource; }
2231 | SATURATION { mailset.events |= Event_Saturation; }
2232 | SIZE { mailset.events |= Event_Size; }
2233 | SPEED { mailset.events |= Event_Speed; }
2234 | STATUS { mailset.events |= Event_Status; }
2235 | TIMEOUT { mailset.events |= Event_Timeout; }
2236 | TIME { mailset.events |= Event_Timestamp; }
2237 | UID { mailset.events |= Event_Uid; }
2238 | UPTIME { mailset.events |= Event_Uptime; }
2239 ;
2240
2241 formatlist : /* EMPTY */
2242 | MAILFORMAT '{' formatoptionlist '}'
2243 ;
2244
2245 formatoptionlist: formatoption
2246 | formatoptionlist formatoption
2247 ;
2248
2249 formatoption : MAILFROM ADDRESSOBJECT { mailset.from = $<address>1; }
2250 | MAILREPLYTO ADDRESSOBJECT { mailset.replyto = $<address>1; }
2251 | MAILSUBJECT { mailset.subject = $1; }
2252 | MAILBODY { mailset.message = $1; }
2253 ;
2254
2255 every : EVERY NUMBER CYCLE {
2256 _sanityCheckEveryStatement(current);
2257 current->every.type = Every_SkipCycles;
2258 current->every.spec.cycle.counter = current->every.spec.cycle.number = $2;
2259 }
2260 | EVERY TIMESPEC {
2261 _sanityCheckEveryStatement(current);
2262 current->every.type = Every_Cron;
2263 current->every.spec.cron = $2;
2264 }
2265 | NOTEVERY TIMESPEC {
2266 _sanityCheckEveryStatement(current);
2267 current->every.type = Every_NotInCron;
2268 current->every.spec.cron = $2;
2269 }
2270 ;
2271
2272 mode : MODE ACTIVE {
2273 current->mode = Monitor_Active;
2274 }
2275 | MODE PASSIVE {
2276 current->mode = Monitor_Passive;
2277 }
2278 | MODE MANUAL {
2279 // Deprecated since monit 5.18
2280 current->onreboot = Onreboot_Laststate;
2281 }
2282 ;
2283
2284 onreboot : ONREBOOT START {
2285 current->onreboot = Onreboot_Start;
2286 }
2287 | ONREBOOT NOSTART {
2288 current->onreboot = Onreboot_Nostart;
2289 current->monitor = Monitor_Not;
2290 }
2291 | ONREBOOT LASTSTATE {
2292 current->onreboot = Onreboot_Laststate;
2293 }
2294 ;
2295
2296 group : GROUP STRINGNAME {
2297 addservicegroup($2);
2298 FREE($2);
2299 }
2300 ;
2301
2302
2303 depend : DEPENDS dependlist
2304 ;
2305
2306 dependlist : dependant
2307 | dependlist dependant
2308 ;
2309
2310 dependant : SERVICENAME { adddependant($<string>1); }
2311 ;
2312
2313 statusvalue : IF STATUS operator NUMBER rate1 THEN action1 recovery_success {
2314 statusset.initialized = true;
2315 statusset.operator = $<number>3;
2316 statusset.return_value = $<number>4;
2317 addeventaction(&(statusset).action, $<number>7, $<number>8);
2318 addstatus(&statusset);
2319 }
2320 | IF CHANGED STATUS rate1 THEN action1 {
2321 statusset.initialized = false;
2322 statusset.operator = Operator_Changed;
2323 statusset.return_value = 0;
2324 addeventaction(&(statusset).action, $<number>6, Action_Ignored);
2325 addstatus(&statusset);
2326 }
2327 ;
2328
2329 resourceprocess : IF resourceprocesslist rate1 THEN action1 recovery_success {
2330 addeventaction(&(resourceset).action, $<number>5, $<number>6);
2331 addresource(&resourceset);
2332 }
2333 ;
2334
2335 resourceprocesslist : resourceprocessopt
2336 | resourceprocesslist resourceprocessopt
2337 ;
2338
2339 resourceprocessopt : resourcecpuproc
2340 | resourcememproc
2341 | resourcethreads
2342 | resourcechild
2343 | resourceload
2344 | resourceread
2345 | resourcewrite
2346 ;
2347
2348 resourcesystem : IF resourcesystemlist rate1 THEN action1 recovery_success {
2349 addeventaction(&(resourceset).action, $<number>5, $<number>6);
2350 addresource(&resourceset);
2351 }
2352 ;
2353
2354 resourcesystemlist : resourcesystemopt
2355 | resourcesystemlist resourcesystemopt
2356 ;
2357
2358 resourcesystemopt : resourceload
2359 | resourcemem
2360 | resourceswap
2361 | resourcecpu
2362 ;
2363
2364 resourcecpuproc : CPU operator value PERCENT {
2365 resourceset.resource_id = Resource_CpuPercent;
2366 resourceset.operator = $<number>2;
2367 resourceset.limit = $<real>3;
2368 }
2369 | TOTALCPU operator value PERCENT {
2370 resourceset.resource_id = Resource_CpuPercentTotal;
2371 resourceset.operator = $<number>2;
2372 resourceset.limit = $<real>3;
2373 }
2374 ;
2375
2376 resourcecpu : resourcecpuid operator value PERCENT {
2377 resourceset.resource_id = $<number>1;
2378 resourceset.operator = $<number>2;
2379 resourceset.limit = $<real>3;
2380 }
2381 ;
2382
2383 resourcecpuid : CPUUSER {
2384 if (systeminfo.statisticsAvailable & Statistics_CpuUser)
2385 $<number>$ = Resource_CpuUser;
2386 else
2387 yywarning2("The CPU user usage statistics is not available on this system\n");
2388 }
2389 | CPUSYSTEM {
2390 if (systeminfo.statisticsAvailable & Statistics_CpuSystem)
2391 $<number>$ = Resource_CpuSystem;
2392 else
2393 yywarning2("The CPU system usage statistics is not available on this system\n");
2394 }
2395 | CPUWAIT {
2396 if (systeminfo.statisticsAvailable & Statistics_CpuIOWait)
2397 $<number>$ = Resource_CpuWait;
2398 else
2399 yywarning2("The CPU I/O wait usage statistics is not available on this system\n");
2400 }
2401 | CPUNICE {
2402 if (systeminfo.statisticsAvailable & Statistics_CpuNice)
2403 $<number>$ = Resource_CpuNice;
2404 else
2405 yywarning2("The CPU nice usage statistics is not available on this system\n");
2406 }
2407 | CPUHARDIRQ {
2408 if (systeminfo.statisticsAvailable & Statistics_CpuHardIRQ)
2409 $<number>$ = Resource_CpuHardIRQ;
2410 else
2411 yywarning2("The CPU hardware IRQ usage statistics is not available on this system\n");
2412 }
2413 | CPUSOFTIRQ {
2414 if (systeminfo.statisticsAvailable & Statistics_CpuSoftIRQ)
2415 $<number>$ = Resource_CpuSoftIRQ;
2416 else
2417 yywarning2("The CPU software IRQ usage statistics is not available on this system\n");
2418 }
2419 | CPUSTEAL {
2420 if (systeminfo.statisticsAvailable & Statistics_CpuSteal)
2421 $<number>$ = Resource_CpuSteal;
2422 else
2423 yywarning2("The CPU steal usage statistics is not available on this system\n");
2424 }
2425 | CPUGUEST {
2426 if (systeminfo.statisticsAvailable & Statistics_CpuGuest)
2427 $<number>$ = Resource_CpuGuest;
2428 else
2429 yywarning2("The CPU guest usage statistics is not available on this system\n");
2430 }
2431 | CPUGUESTNICE {
2432 if (systeminfo.statisticsAvailable & Statistics_CpuGuestNice)
2433 $<number>$ = Resource_CpuGuestNice;
2434 else
2435 yywarning2("The CPU guest nice usage statistics is not available on this system\n");
2436 }
2437 | CPU {
2438 $<number>$ = Resource_CpuPercent;
2439 }
2440 ;
2441
2442 resourcemem : MEMORY operator value unit {
2443 resourceset.resource_id = Resource_MemoryKbyte;
2444 resourceset.operator = $<number>2;
2445 resourceset.limit = $<real>3 * $<number>4;
2446 }
2447 | MEMORY operator value PERCENT {
2448 resourceset.resource_id = Resource_MemoryPercent;
2449 resourceset.operator = $<number>2;
2450 resourceset.limit = $<real>3;
2451 }
2452 ;
2453
2454 resourcememproc : MEMORY operator value unit {
2455 resourceset.resource_id = Resource_MemoryKbyte;
2456 resourceset.operator = $<number>2;
2457 resourceset.limit = $<real>3 * $<number>4;
2458 }
2459 | MEMORY operator value PERCENT {
2460 resourceset.resource_id = Resource_MemoryPercent;
2461 resourceset.operator = $<number>2;
2462 resourceset.limit = $<real>3;
2463 }
2464 | TOTALMEMORY operator value unit {
2465 resourceset.resource_id = Resource_MemoryKbyteTotal;
2466 resourceset.operator = $<number>2;
2467 resourceset.limit = $<real>3 * $<number>4;
2468 }
2469 | TOTALMEMORY operator value PERCENT {
2470 resourceset.resource_id = Resource_MemoryPercentTotal;
2471 resourceset.operator = $<number>2;
2472 resourceset.limit = $<real>3;
2473 }
2474 ;
2475
2476 resourceswap : SWAP operator value unit {
2477 resourceset.resource_id = Resource_SwapKbyte;
2478 resourceset.operator = $<number>2;
2479 resourceset.limit = $<real>3 * $<number>4;
2480 }
2481 | SWAP operator value PERCENT {
2482 resourceset.resource_id = Resource_SwapPercent;
2483 resourceset.operator = $<number>2;
2484 resourceset.limit = $<real>3;
2485 }
2486 ;
2487
2488 resourcethreads : THREADS operator NUMBER {
2489 resourceset.resource_id = Resource_Threads;
2490 resourceset.operator = $<number>2;
2491 resourceset.limit = $<number>3;
2492 }
2493 ;
2494
2495 resourcechild : CHILDREN operator NUMBER {
2496 resourceset.resource_id = Resource_Children;
2497 resourceset.operator = $<number>2;
2498 resourceset.limit = $<number>3;
2499 }
2500 ;
2501
2502 resourceload : resourceloadavg coremultiplier operator value {
2503 switch ($<number>1) {
2504 case Resource_LoadAverage1m:
2505 resourceset.resource_id = $<number>2 > 1 ? Resource_LoadAveragePerCore1m : $<number>1;
2506 break;
2507 case Resource_LoadAverage5m:
2508 resourceset.resource_id = $<number>2 > 1 ? Resource_LoadAveragePerCore5m : $<number>1;
2509 break;
2510 case Resource_LoadAverage15m:
2511 resourceset.resource_id = $<number>2 > 1 ? Resource_LoadAveragePerCore15m : $<number>1;
2512 break;
2513 default:
2514 resourceset.resource_id = $<number>1;
2515 break;
2516 }
2517 resourceset.operator = $<number>3;
2518 resourceset.limit = $<real>4;
2519 }
2520 ;
2521
2522 resourceloadavg : LOADAVG1 { $<number>$ = Resource_LoadAverage1m; }
2523 | LOADAVG5 { $<number>$ = Resource_LoadAverage5m; }
2524 | LOADAVG15 { $<number>$ = Resource_LoadAverage15m; }
2525 ;
2526
2527 coremultiplier : /* EMPTY */ { $<number>$ = 1; }
2528 | CORE { $<number>$ = systeminfo.cpu.count; }
2529 ;
2530
2531
2532 resourceread : READ operator value unit currenttime {
2533 resourceset.resource_id = Resource_ReadBytes;
2534 resourceset.operator = $<number>2;
2535 resourceset.limit = $<real>3 * $<number>4;
2536 }
2537 | DISK READ operator value unit currenttime {
2538 resourceset.resource_id = Resource_ReadBytesPhysical;
2539 resourceset.operator = $<number>3;
2540 resourceset.limit = $<real>4 * $<number>5;
2541 }
2542 | DISK READ operator NUMBER OPERATION {
2543 resourceset.resource_id = Resource_ReadOperations;
2544 resourceset.operator = $<number>3;
2545 resourceset.limit = $<number>4;
2546 }
2547 ;
2548
2549 resourcewrite : WRITE operator value unit currenttime {
2550 resourceset.resource_id = Resource_WriteBytes;
2551 resourceset.operator = $<number>2;
2552 resourceset.limit = $<real>3 * $<number>4;
2553 }
2554 | DISK WRITE operator value unit currenttime {
2555 resourceset.resource_id = Resource_WriteBytesPhysical;
2556 resourceset.operator = $<number>3;
2557 resourceset.limit = $<real>4 * $<number>5;
2558 }
2559 | DISK WRITE operator NUMBER OPERATION {
2560 resourceset.resource_id = Resource_WriteOperations;
2561 resourceset.operator = $<number>3;
2562 resourceset.limit = $<number>4;
2563 }
2564 ;
2565
2566 value : REAL { $<real>$ = $1; }
2567 | NUMBER { $<real>$ = (float) $1; }
2568 ;
2569
2570 timestamptype : TIME { $<number>$ = Timestamp_Default; }
2571 | ATIME { $<number>$ = Timestamp_Access; }
2572 | CTIME { $<number>$ = Timestamp_Change; }
2573 | MTIME { $<number>$ = Timestamp_Modification; }
2574 ;
2575
2576 timestamp : IF timestamptype operator NUMBER time rate1 THEN action1 recovery_success {
2577 timestampset.type = $<number>2;
2578 timestampset.operator = $<number>3;
2579 timestampset.time = ($4 * $<number>5);
2580 addeventaction(&(timestampset).action, $<number>8, $<number>9);
2581 addtimestamp(×tampset);
2582 }
2583 | IF CHANGED timestamptype rate1 THEN action1 {
2584 timestampset.type = $<number>3;
2585 timestampset.test_changes = true;
2586 addeventaction(&(timestampset).action, $<number>6, Action_Ignored);
2587 addtimestamp(×tampset);
2588 }
2589 ;
2590
2591 operator : /* EMPTY */ { $<number>$ = Operator_Equal; }
2592 | GREATER { $<number>$ = Operator_Greater; }
2593 | GREATEROREQUAL { $<number>$ = Operator_GreaterOrEqual; }
2594 | LESS { $<number>$ = Operator_Less; }
2595 | LESSOREQUAL { $<number>$ = Operator_LessOrEqual; }
2596 | EQUAL { $<number>$ = Operator_Equal; }
2597 | NOTEQUAL { $<number>$ = Operator_NotEqual; }
2598 | CHANGED { $<number>$ = Operator_Changed; }
2599 ;
2600
2601 time : /* EMPTY */ { $<number>$ = Time_Second; }
2602 | SECOND { $<number>$ = Time_Second; }
2603 | MINUTE { $<number>$ = Time_Minute; }
2604 | HOUR { $<number>$ = Time_Hour; }
2605 | DAY { $<number>$ = Time_Day; }
2606 | MONTH { $<number>$ = Time_Month; }
2607 ;
2608
2609 totaltime : MINUTE { $<number>$ = Time_Minute; }
2610 | HOUR { $<number>$ = Time_Hour; }
2611 | DAY { $<number>$ = Time_Day; }
2612
2613 currenttime : /* EMPTY */ { $<number>$ = Time_Second; }
2614 | SECOND { $<number>$ = Time_Second; }
2615
2616 repeat : /* EMPTY */ {
2617 repeat = 0;
2618 }
2619 | REPEAT EVERY CYCLE {
2620 repeat = 1;
2621 }
2622 | REPEAT EVERY NUMBER CYCLE {
2623 if ($<number>3 < 0) {
2624 yyerror2("The number of repeat cycles must be greater or equal to 0");
2625 }
2626 repeat = $<number>3;
2627 }
2628 ;
2629
2630 action : ALERT {
2631 $<number>$ = Action_Alert;
2632 }
2633 | EXEC argumentlist repeat {
2634 $<number>$ = Action_Exec;
2635 }
2636 | EXEC argumentlist useroptionlist repeat
2637 {
2638 $<number>$ = Action_Exec;
2639 }
2640 | RESTART {
2641 $<number>$ = Action_Restart;
2642 }
2643 | START {
2644 $<number>$ = Action_Start;
2645 }
2646 | STOP {
2647 $<number>$ = Action_Stop;
2648 }
2649 | UNMONITOR {
2650 $<number>$ = Action_Unmonitor;
2651 }
2652 ;
2653
2654 action1 : action {
2655 $<number>$ = $<number>1;
2656 if ($<number>1 == Action_Exec && command) {
2657 repeat1 = repeat;
2658 repeat = 0;
2659 command1 = command;
2660 command = NULL;
2661 }
2662 }
2663 ;
2664
2665 action2 : action {
2666 $<number>$ = $<number>1;
2667 if ($<number>1 == Action_Exec && command) {
2668 repeat2 = repeat;
2669 repeat = 0;
2670 command2 = command;
2671 command = NULL;
2672 }
2673 }
2674 ;
2675
2676 rateXcycles : NUMBER CYCLE {
2677 if ($<number>1 < 1 || (unsigned long)$<number>1 > BITMAP_MAX) {
2678 yyerror2("The number of cycles must be between 1 and %zu", BITMAP_MAX);
2679 } else {
2680 rate.count = $<number>1;
2681 rate.cycles = $<number>1;
2682 }
2683 }
2684 ;
2685
2686 rateXYcycles : NUMBER NUMBER CYCLE {
2687 if ($<number>2 < 1 || (unsigned long)$<number>2 > BITMAP_MAX) {
2688 yyerror2("The number of cycles must be between 1 and %zu", BITMAP_MAX);
2689 } else if ($<number>1 < 1 || $<number>1 > $<number>2) {
2690 yyerror2("The number of events must be between 1 and less then poll cycles");
2691 } else {
2692 rate.count = $<number>1;
2693 rate.cycles = $<number>2;
2694 }
2695 }
2696 ;
2697
2698 rate1 : /* EMPTY */
2699 | rateXcycles {
2700 rate1.count = rate.count;
2701 rate1.cycles = rate.cycles;
2702 reset_rateset(&rate);
2703 }
2704 | rateXYcycles {
2705 rate1.count = rate.count;
2706 rate1.cycles = rate.cycles;
2707 reset_rateset(&rate);
2708 }
2709 ;
2710
2711 rate2 : /* EMPTY */
2712 | rateXcycles {
2713 rate2.count = rate.count;
2714 rate2.cycles = rate.cycles;
2715 reset_rateset(&rate);
2716 }
2717 | rateXYcycles {
2718 rate2.count = rate.count;
2719 rate2.cycles = rate.cycles;
2720 reset_rateset(&rate);
2721 }
2722 ;
2723
2724 recovery_success : /* EMPTY */ {
2725 $<number>$ = Action_Alert;
2726 }
2727 | ELSE action2 {
2728 $<number>$ = $<number>2;
2729 }
2730 | ELSE IF RECOVERED rate2 THEN action2 {
2731 $<number>$ = $<number>6;
2732 }
2733 | ELSE IF PASSED rate2 THEN action2 {
2734 $<number>$ = $<number>6;
2735 }
2736 | ELSE IF SUCCEEDED rate2 THEN action2 {
2737 $<number>$ = $<number>6;
2738 }
2739 ;
2740
2741 recovery_failure : /* EMPTY */ {
2742 $<number>$ = Action_Alert;
2743 }
2744 | ELSE action2 {
2745 $<number>$ = $<number>2;
2746 }
2747 | ELSE IF FAILED rate2 THEN action2 {
2748 $<number>$ = $<number>6;
2749 }
2750 ;
2751
2752 checksum : IF FAILED hashtype CHECKSUM rate1 THEN action1 recovery_success {
2753 addeventaction(&(checksumset).action, $<number>7, $<number>8);
2754 addchecksum(&checksumset);
2755 }
2756 | IF FAILED hashtype CHECKSUM EXPECT STRING rate1 THEN action1
2757 recovery_success {
2758 snprintf(checksumset.hash, sizeof(checksumset.hash), "%s", $6);
2759 FREE($6);
2760 addeventaction(&(checksumset).action, $<number>9, $<number>10);
2761 addchecksum(&checksumset);
2762 }
2763 | IF CHANGED hashtype CHECKSUM rate1 THEN action1 {
2764 checksumset.test_changes = true;
2765 addeventaction(&(checksumset).action, $<number>7, Action_Ignored);
2766 addchecksum(&checksumset);
2767 }
2768 ;
2769 hashtype : /* EMPTY */ { checksumset.type = Hash_Unknown; }
2770 | MD5HASH { checksumset.type = Hash_Md5; }
2771 | SHA1HASH { checksumset.type = Hash_Sha1; }
2772 ;
2773
2774 inode : IF INODE operator NUMBER rate1 THEN action1 recovery_success {
2775 filesystemset.resource = Resource_Inode;
2776 filesystemset.operator = $<number>3;
2777 filesystemset.limit_absolute = $4;
2778 addeventaction(&(filesystemset).action, $<number>7, $<number>8);
2779 addfilesystem(&filesystemset);
2780 }
2781 | IF INODE operator value PERCENT rate1 THEN action1 recovery_success {
2782 filesystemset.resource = Resource_Inode;
2783 filesystemset.operator = $<number>3;
2784 filesystemset.limit_percent = $<real>4;
2785 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2786 addfilesystem(&filesystemset);
2787 }
2788 | IF INODE TFREE operator NUMBER rate1 THEN action1 recovery_success {
2789 filesystemset.resource = Resource_InodeFree;
2790 filesystemset.operator = $<number>4;
2791 filesystemset.limit_absolute = $5;
2792 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2793 addfilesystem(&filesystemset);
2794 }
2795 | IF INODE TFREE operator value PERCENT rate1 THEN action1 recovery_success {
2796 filesystemset.resource = Resource_InodeFree;
2797 filesystemset.operator = $<number>4;
2798 filesystemset.limit_percent = $<real>5;
2799 addeventaction(&(filesystemset).action, $<number>9, $<number>10);
2800 addfilesystem(&filesystemset);
2801 }
2802 ;
2803
2804 space : IF SPACE operator value unit rate1 THEN action1 recovery_success {
2805 filesystemset.resource = Resource_Space;
2806 filesystemset.operator = $<number>3;
2807 filesystemset.limit_absolute = $<real>4 * $<number>5;
2808 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2809 addfilesystem(&filesystemset);
2810 }
2811 | IF SPACE operator value PERCENT rate1 THEN action1 recovery_success {
2812 filesystemset.resource = Resource_Space;
2813 filesystemset.operator = $<number>3;
2814 filesystemset.limit_percent = $<real>4;
2815 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2816 addfilesystem(&filesystemset);
2817 }
2818 | IF SPACE TFREE operator value unit rate1 THEN action1 recovery_success {
2819 filesystemset.resource = Resource_SpaceFree;
2820 filesystemset.operator = $<number>4;
2821 filesystemset.limit_absolute = $<real>5 * $<number>6;
2822 addeventaction(&(filesystemset).action, $<number>9, $<number>10);
2823 addfilesystem(&filesystemset);
2824 }
2825 | IF SPACE TFREE operator value PERCENT rate1 THEN action1 recovery_success {
2826 filesystemset.resource = Resource_SpaceFree;
2827 filesystemset.operator = $<number>4;
2828 filesystemset.limit_percent = $<real>5;
2829 addeventaction(&(filesystemset).action, $<number>9, $<number>10);
2830 addfilesystem(&filesystemset);
2831 }
2832 ;
2833
2834 read : IF READ operator value unit currenttime rate1 THEN action1 recovery_success {
2835 filesystemset.resource = Resource_ReadBytes;
2836 filesystemset.operator = $<number>3;
2837 filesystemset.limit_absolute = $<real>4 * $<number>5;
2838 addeventaction(&(filesystemset).action, $<number>9, $<number>10);
2839 addfilesystem(&filesystemset);
2840 }
2841 | IF READ operator NUMBER OPERATION rate1 THEN action1 recovery_success {
2842 filesystemset.resource = Resource_ReadOperations;
2843 filesystemset.operator = $<number>3;
2844 filesystemset.limit_absolute = $<number>4;
2845 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2846 addfilesystem(&filesystemset);
2847 }
2848 ;
2849
2850 write : IF WRITE operator value unit currenttime rate1 THEN action1 recovery_success {
2851 filesystemset.resource = Resource_WriteBytes;
2852 filesystemset.operator = $<number>3;
2853 filesystemset.limit_absolute = $<real>4 * $<number>5;
2854 addeventaction(&(filesystemset).action, $<number>9, $<number>10);
2855 addfilesystem(&filesystemset);
2856 }
2857 | IF WRITE operator NUMBER OPERATION rate1 THEN action1 recovery_success {
2858 filesystemset.resource = Resource_WriteOperations;
2859 filesystemset.operator = $<number>3;
2860 filesystemset.limit_absolute = $<number>4;
2861 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2862 addfilesystem(&filesystemset);
2863 }
2864 ;
2865
2866 servicetime : IF SERVICETIME operator NUMBER MILLISECOND rate1 THEN action1 recovery_success {
2867 filesystemset.resource = Resource_ServiceTime;
2868 filesystemset.operator = $<number>3;
2869 filesystemset.limit_absolute = $<number>4;
2870 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2871 addfilesystem(&filesystemset);
2872 }
2873 | IF SERVICETIME operator value SECOND rate1 THEN action1 recovery_success {
2874 filesystemset.resource = Resource_ServiceTime;
2875 filesystemset.operator = $<number>3;
2876 filesystemset.limit_absolute = $<real>4 * 1000;
2877 addeventaction(&(filesystemset).action, $<number>8, $<number>9);
2878 addfilesystem(&filesystemset);
2879 }
2880 ;
2881
2882 fsflag : IF CHANGED FSFLAG rate1 THEN action1 {
2883 addeventaction(&(fsflagset).action, $<number>6, Action_Ignored);
2884 addfsflag(&fsflagset);
2885 }
2886 ;
2887
2888 unit : /* empty */ { $<number>$ = Unit_Byte; }
2889 | BYTE { $<number>$ = Unit_Byte; }
2890 | KILOBYTE { $<number>$ = Unit_Kilobyte; }
2891 | MEGABYTE { $<number>$ = Unit_Megabyte; }
2892 | GIGABYTE { $<number>$ = Unit_Gigabyte; }
2893 ;
2894
2895 permission : IF FAILED PERMISSION NUMBER rate1 THEN action1 recovery_success {
2896 permset.perm = check_perm($4);
2897 addeventaction(&(permset).action, $<number>7, $<number>8);
2898 addperm(&permset);
2899 }
2900 | IF CHANGED PERMISSION rate1 THEN action1 recovery_success {
2901 permset.test_changes = true;
2902 addeventaction(&(permset).action, $<number>6, Action_Ignored);
2903 addperm(&permset);
2904 }
2905 ;
2906
2907 programmatch : IF CONTENT urloperator STRING rate1 THEN action1 {
2908 matchset.not = $<number>3 == Operator_Equal ? false : true;
2909 matchset.ignore = false;
2910 matchset.match_path = NULL;
2911 matchset.match_string = $4;
2912 addmatch(&matchset, $<number>7, 0);
2913 }
2914 ;
2915
2916 match : IF CONTENT urloperator PATH rate1 THEN action1 {
2917 matchset.not = $<number>3 == Operator_Equal ? false : true;
2918 matchset.ignore = false;
2919 matchset.match_path = $4;
2920 matchset.match_string = NULL;
2921 addmatchpath(&matchset, $<number>7);
2922 FREE($4);
2923 }
2924 | IF CONTENT urloperator STRING rate1 THEN action1 {
2925 matchset.not = $<number>3 == Operator_Equal ? false : true;
2926 matchset.ignore = false;
2927 matchset.match_path = NULL;
2928 matchset.match_string = $4;
2929 addmatch(&matchset, $<number>7, 0);
2930 }
2931 | IGNORE CONTENT urloperator PATH {
2932 matchset.not = $<number>3 == Operator_Equal ? false : true;
2933 matchset.ignore = true;
2934 matchset.match_path = $4;
2935 matchset.match_string = NULL;
2936 addmatchpath(&matchset, Action_Ignored);
2937 FREE($4);
2938 }
2939 | IGNORE CONTENT urloperator STRING {
2940 matchset.not = $<number>3 == Operator_Equal ? false : true;
2941 matchset.ignore = true;
2942 matchset.match_path = NULL;
2943 matchset.match_string = $4;
2944 addmatch(&matchset, Action_Ignored, 0);
2945 }
2946 /* The below MATCH statement is deprecated (replaced by CONTENT) */
2947 | IF matchflagnot MATCH PATH rate1 THEN action1 {
2948 matchset.ignore = false;
2949 matchset.match_path = $4;
2950 matchset.match_string = NULL;
2951 addmatchpath(&matchset, $<number>7);
2952 FREE($4);
2953 }
2954 | IF matchflagnot MATCH STRING rate1 THEN action1 {
2955 matchset.ignore = false;
2956 matchset.match_path = NULL;
2957 matchset.match_string = $4;
2958 addmatch(&matchset, $<number>7, 0);
2959 }
2960 | IGNORE matchflagnot MATCH PATH {
2961 matchset.ignore = true;
2962 matchset.match_path = $4;
2963 matchset.match_string = NULL;
2964 addmatchpath(&matchset, Action_Ignored);
2965 FREE($4);
2966 }
2967 | IGNORE matchflagnot MATCH STRING {
2968 matchset.ignore = true;
2969 matchset.match_path = NULL;
2970 matchset.match_string = $4;
2971 addmatch(&matchset, Action_Ignored, 0);
2972 }
2973 ;
2974
2975 matchflagnot : /* EMPTY */ {
2976 matchset.not = false;
2977 }
2978 | NOT {
2979 matchset.not = true;
2980 }
2981 ;
2982
2983
2984 size : IF SIZE operator NUMBER unit rate1 THEN action1 recovery_success {
2985 sizeset.operator = $<number>3;
2986 sizeset.size = ((unsigned long long)$4 * $<number>5);
2987 addeventaction(&(sizeset).action, $<number>8, $<number>9);
2988 addsize(&sizeset);
2989 }
2990 | IF CHANGED SIZE rate1 THEN action1 {
2991 sizeset.test_changes = true;
2992 addeventaction(&(sizeset).action, $<number>6, Action_Ignored);
2993 addsize(&sizeset);
2994 }
2995 ;
2996
2997 uid : IF FAILED UID STRING rate1 THEN action1 recovery_success {
2998 uidset.uid = get_uid($4, 0);
2999 addeventaction(&(uidset).action, $<number>7, $<number>8);
3000 current->uid = adduid(&uidset);
3001 FREE($4);
3002 }
3003 | IF FAILED UID NUMBER rate1 THEN action1 recovery_success {
3004 uidset.uid = get_uid(NULL, $4);
3005 addeventaction(&(uidset).action, $<number>7, $<number>8);
3006 current->uid = adduid(&uidset);
3007 }
3008 ;
3009
3010 euid : IF FAILED EUID STRING rate1 THEN action1 recovery_success {
3011 uidset.uid = get_uid($4, 0);
3012 addeventaction(&(uidset).action, $<number>7, $<number>8);
3013 current->euid = adduid(&uidset);
3014 FREE($4);
3015 }
3016 | IF FAILED EUID NUMBER rate1 THEN action1 recovery_success {
3017 uidset.uid = get_uid(NULL, $4);
3018 addeventaction(&(uidset).action, $<number>7, $<number>8);
3019 current->euid = adduid(&uidset);
3020 }
3021 ;
3022
3023 secattr : IF FAILED SECURITY ATTRIBUTE STRING rate1 THEN action1 recovery_success {
3024 addsecurityattribute($5, $<number>8, $<number>9);
3025 }
3026 | IF FAILED SECURITY ATTRIBUTE PATH rate1 THEN action1 recovery_success {
3027 addsecurityattribute($5, $<number>8, $<number>9);
3028 }
3029 ;
3030
3031 filedescriptorssystem : IF FILEDESCRIPTORS operator NUMBER rate1 THEN action1 recovery_success {
3032 if (systeminfo.statisticsAvailable & Statistics_FiledescriptorsPerSystem)
3033 addfiledescriptors($<number>3, false, (long long)$4, -1., $<number>7, $<number>8);
3034 else
3035 yywarning("The per-system filedescriptors statistics is not available on this system\n");
3036 }
3037 | IF FILEDESCRIPTORS operator value PERCENT rate1 THEN action1 recovery_success {
3038 if (systeminfo.statisticsAvailable & Statistics_FiledescriptorsPerSystem)
3039 addfiledescriptors($<number>3, false, -1LL, $<real>4, $<number>8, $<number>9);
3040 else
3041 yywarning("The per-system filedescriptors statistics is not available on this system\n");
3042 }
3043 ;
3044
3045 filedescriptorsprocess : IF FILEDESCRIPTORS operator NUMBER rate1 THEN action1 recovery_success {
3046 if (systeminfo.statisticsAvailable & Statistics_FiledescriptorsPerProcess)
3047 addfiledescriptors($<number>3, false, (long long)$4, -1., $<number>7, $<number>8);
3048 else
3049 yywarning("The per-process filedescriptors statistics is not available on this system\n");
3050 }
3051 | IF FILEDESCRIPTORS operator value PERCENT rate1 THEN action1 recovery_success {
3052 if (systeminfo.statisticsAvailable & Statistics_FiledescriptorsPerProcessMax)
3053 addfiledescriptors($<number>3, false, -1LL, $<real>4, $<number>8, $<number>9);
3054 else
3055 yywarning("The per-process filedescriptors maximum is not exposed on this system, so we cannot compute usage %%, please use the test with absolute value\n");
3056 }
3057 ;
3058
3059 filedescriptorsprocesstotal : IF TOTAL FILEDESCRIPTORS operator NUMBER rate1 THEN action1 recovery_success {
3060 if (systeminfo.statisticsAvailable & Statistics_FiledescriptorsPerProcess)
3061 addfiledescriptors($<number>4, true, (long long)$5, -1., $<number>8, $<number>9);
3062 else
3063 yywarning("The per-process filedescriptors statistics is not available on this system\n");
3064 }
3065 ;
3066
3067 gid : IF FAILED GID STRING rate1 THEN action1 recovery_success {
3068 gidset.gid = get_gid($4, 0);
3069 addeventaction(&(gidset).action, $<number>7, $<number>8);
3070 current->gid = addgid(&gidset);
3071 FREE($4);
3072 }
3073 | IF FAILED GID NUMBER rate1 THEN action1 recovery_success {
3074 gidset.gid = get_gid(NULL, $4);
3075 addeventaction(&(gidset).action, $<number>7, $<number>8);
3076 current->gid = addgid(&gidset);
3077 }
3078 ;
3079
3080 linkstatus : IF FAILED LINK rate1 THEN action1 recovery_success { /* Deprecated */
3081 addeventaction(&(linkstatusset).action, $<number>6, $<number>7);
3082 addlinkstatus(current, &linkstatusset);
3083 }
3084 | IF LINK DOWN rate1 THEN action1 recovery_success {
3085 linkstatusset.check_invers = false;
3086 addeventaction(&(linkstatusset).action, $<number>6, $<number>7);
3087 addlinkstatus(current, &linkstatusset);
3088 }
3089 | IF LINK UP rate1 THEN action1 recovery_failure {
3090 linkstatusset.check_invers = true;
3091 addeventaction(&(linkstatusset).action, $<number>6, $<number>7);
3092 addlinkstatus(current, &linkstatusset);
3093 }
3094 ;
3095
3096 linkspeed : IF CHANGED LINK rate1 THEN action1 recovery_success {
3097 addeventaction(&(linkspeedset).action, $<number>6, $<number>7);
3098 addlinkspeed(current, &linkspeedset);
3099 }
3100
3101 linksaturation : IF SATURATION operator NUMBER PERCENT rate1 THEN action1 recovery_success {
3102 linksaturationset.operator = $<number>3;
3103 linksaturationset.limit = (unsigned long long)$4;
3104 addeventaction(&(linksaturationset).action, $<number>8, $<number>9);
3105 addlinksaturation(current, &linksaturationset);
3106 }
3107 ;
3108
3109 upload : IF UPLOAD operator NUMBER unit currenttime rate1 THEN action1 recovery_success {
3110 bandwidthset.operator = $<number>3;
3111 bandwidthset.limit = ((unsigned long long)$4 * $<number>5);
3112 bandwidthset.rangecount = 1;
3113 bandwidthset.range = $<number>6;
3114 addeventaction(&(bandwidthset).action, $<number>9, $<number>10);
3115 addbandwidth(&(current->uploadbyteslist), &bandwidthset);
3116 }
3117 | IF TOTAL UPLOAD operator NUMBER unit totaltime rate1 THEN action1 recovery_success {
3118 bandwidthset.operator = $<number>4;
3119 bandwidthset.limit = ((unsigned long long)$5 * $<number>6);
3120 bandwidthset.rangecount = 1;
3121 bandwidthset.range = $<number>7;
3122 addeventaction(&(bandwidthset).action, $<number>10, $<number>11);
3123 addbandwidth(&(current->uploadbyteslist), &bandwidthset);
3124 }
3125 | IF TOTAL UPLOAD operator NUMBER unit NUMBER totaltime rate1 THEN action1 recovery_success {
3126 bandwidthset.operator = $<number>4;
3127 bandwidthset.limit = ((unsigned long long)$5 * $<number>6);
3128 bandwidthset.rangecount = $7;
3129 bandwidthset.range = $<number>8;
3130 addeventaction(&(bandwidthset).action, $<number>11, $<number>12);
3131 addbandwidth(&(current->uploadbyteslist), &bandwidthset);
3132 }
3133 | IF UPLOAD operator NUMBER PACKET currenttime rate1 THEN action1 recovery_success {
3134 bandwidthset.operator = $<number>3;
3135 bandwidthset.limit = (unsigned long long)$4;
3136 bandwidthset.rangecount = 1;
3137 bandwidthset.range = $<number>6;
3138 addeventaction(&(bandwidthset).action, $<number>9, $<number>10);
3139 addbandwidth(&(current->uploadpacketslist), &bandwidthset);
3140 }
3141 | IF TOTAL UPLOAD operator NUMBER PACKET totaltime rate1 THEN action1 recovery_success {
3142 bandwidthset.operator = $<number>4;
3143 bandwidthset.limit = (unsigned long long)$5;
3144 bandwidthset.rangecount = 1;
3145 bandwidthset.range = $<number>7;
3146 addeventaction(&(bandwidthset).action, $<number>10, $<number>11);
3147 addbandwidth(&(current->uploadpacketslist), &bandwidthset);
3148 }
3149 | IF TOTAL UPLOAD operator NUMBER PACKET NUMBER totaltime rate1 THEN action1 recovery_success {
3150 bandwidthset.operator = $<number>4;
3151 bandwidthset.limit = (unsigned long long)$5;
3152 bandwidthset.rangecount = $7;
3153 bandwidthset.range = $<number>8;
3154 addeventaction(&(bandwidthset).action, $<number>11, $<number>12);
3155 addbandwidth(&(current->uploadpacketslist), &bandwidthset);
3156 }
3157 ;
3158
3159 download : IF DOWNLOAD operator NUMBER unit currenttime rate1 THEN action1 recovery_success {
3160 bandwidthset.operator = $<number>3;
3161 bandwidthset.limit = ((unsigned long long)$4 * $<number>5);
3162 bandwidthset.rangecount = 1;
3163 bandwidthset.range = $<number>6;
3164 addeventaction(&(bandwidthset).action, $<number>9, $<number>10);
3165 addbandwidth(&(current->downloadbyteslist), &bandwidthset);
3166 }
3167 | IF TOTAL DOWNLOAD operator NUMBER unit totaltime rate1 THEN action1 recovery_success {
3168 bandwidthset.operator = $<number>4;
3169 bandwidthset.limit = ((unsigned long long)$5 * $<number>6);
3170 bandwidthset.rangecount = 1;
3171 bandwidthset.range = $<number>7;
3172 addeventaction(&(bandwidthset).action, $<number>10, $<number>11);
3173 addbandwidth(&(current->downloadbyteslist), &bandwidthset);
3174 }
3175 | IF TOTAL DOWNLOAD operator NUMBER unit NUMBER totaltime rate1 THEN action1 recovery_success {
3176 bandwidthset.operator = $<number>4;
3177 bandwidthset.limit = ((unsigned long long)$5 * $<number>6);
3178 bandwidthset.rangecount = $7;
3179 bandwidthset.range = $<number>8;
3180 addeventaction(&(bandwidthset).action, $<number>11, $<number>12);
3181 addbandwidth(&(current->downloadbyteslist), &bandwidthset);
3182 }
3183 | IF DOWNLOAD operator NUMBER PACKET currenttime rate1 THEN action1 recovery_success {
3184 bandwidthset.operator = $<number>3;
3185 bandwidthset.limit = (unsigned long long)$4;
3186 bandwidthset.rangecount = 1;
3187 bandwidthset.range = $<number>6;
3188 addeventaction(&(bandwidthset).action, $<number>9, $<number>10);
3189 addbandwidth(&(current->downloadpacketslist), &bandwidthset);
3190 }
3191 | IF TOTAL DOWNLOAD operator NUMBER PACKET totaltime rate1 THEN action1 recovery_success {
3192 bandwidthset.operator = $<number>4;
3193 bandwidthset.limit = (unsigned long long)$5;
3194 bandwidthset.rangecount = 1;
3195 bandwidthset.range = $<number>7;
3196 addeventaction(&(bandwidthset).action, $<number>10, $<number>11);
3197 addbandwidth(&(current->downloadpacketslist), &bandwidthset);
3198 }
3199 | IF TOTAL DOWNLOAD operator NUMBER PACKET NUMBER totaltime rate1 THEN action1 recovery_success {
3200 bandwidthset.operator = $<number>4;
3201 bandwidthset.limit = (unsigned long long)$5;
3202 bandwidthset.rangecount = $7;
3203 bandwidthset.range = $<number>8;
3204 addeventaction(&(bandwidthset).action, $<number>11, $<number>12);
3205 addbandwidth(&(current->downloadpacketslist), &bandwidthset);
3206 }
3207 ;
3208
3209 icmptype : TYPE ICMPECHO { $<number>$ = ICMP_ECHO; }
3210 ;
3211
3212 reminder : /* EMPTY */ { mailset.reminder = 0; }
3213 | REMINDER NUMBER { mailset.reminder = $<number>2; }
3214 | REMINDER NUMBER CYCLE { mailset.reminder = $<number>2; }
3215 ;
3216
3217 %%
3218
3219
3220 /* -------------------------------------------------------- Parser interface */
3221
3222
3223 /**
3224 * Syntactic error routine
3225 *
3226 * This routine is automatically called by the lexer!
3227 */
3228 void yyerror(const char *s, ...) {
3229 ASSERT(s);
3230 char *msg = NULL;
3231 va_list ap;
3232 va_start(ap, s);
3233 msg = Str_vcat(s, ap);
3234 va_end(ap);
3235 Log_error("%s:%i: %s '%s'\n", currentfile, lineno, msg, yytext);
3236 cfg_errflag++;
3237 FREE(msg);
3238 }
3239
3240
3241 /**
3242 * Syntactical warning routine
3243 */
yywarning(const char * s,...)3244 void yywarning(const char *s, ...) {
3245 ASSERT(s);
3246 char *msg = NULL;
3247 va_list ap;
3248 va_start(ap, s);
3249 msg = Str_vcat(s, ap);
3250 va_end(ap);
3251 Log_warning("%s:%i: %s '%s'\n", currentfile, lineno, msg, yytext);
3252 FREE(msg);
3253 }
3254
3255
3256 /**
3257 * Argument error routine
3258 */
yyerror2(const char * s,...)3259 void yyerror2(const char *s, ...) {
3260 ASSERT(s);
3261 char *msg = NULL;
3262 va_list ap;
3263 va_start(ap, s);
3264 msg = Str_vcat(s, ap);
3265 va_end(ap);
3266 Log_error("%s:%i: %s '%s'\n", argcurrentfile, arglineno, msg, argyytext);
3267 cfg_errflag++;
3268 FREE(msg);
3269 }
3270
3271
3272 /**
3273 * Argument warning routine
3274 */
yywarning2(const char * s,...)3275 void yywarning2(const char *s, ...) {
3276 ASSERT(s);
3277 char *msg = NULL;
3278 va_list ap;
3279 va_start(ap, s);
3280 msg = Str_vcat(s, ap);
3281 va_end(ap);
3282 Log_warning("%s:%i: %s '%s'\n", argcurrentfile, arglineno, msg, argyytext);
3283 FREE(msg);
3284 }
3285
3286
3287 /*
3288 * The Parser hook - start parsing the control file
3289 * Returns true if parsing succeeded, otherwise false
3290 */
parse(char * controlfile)3291 bool parse(char *controlfile) {
3292 ASSERT(controlfile);
3293
3294 if ((yyin = fopen(controlfile,"r")) == (FILE *)NULL) {
3295 Log_error("Cannot open the control file '%s' -- %s\n", controlfile, STRERROR);
3296 return false;
3297 }
3298
3299 currentfile = Str_dup(controlfile);
3300
3301 available_statistics(&systeminfo);
3302
3303 /*
3304 * Creation of the global service list is synchronized
3305 */
3306 LOCK(Run.mutex)
3307 {
3308 preparse();
3309 yyparse();
3310 fclose(yyin);
3311 postparse();
3312 }
3313 END_LOCK;
3314
3315 FREE(currentfile);
3316
3317 if (argyytext != NULL)
3318 FREE(argyytext);
3319
3320 /*
3321 * Secure check the monitrc file. The run control file must have the
3322 * same uid as the REAL uid of this process, it must have permissions
3323 * no greater than 700 and it must not be a symbolic link.
3324 */
3325 if (! file_checkStat(controlfile, "control file", S_IRUSR|S_IWUSR|S_IXUSR))
3326 return false;
3327
3328 return cfg_errflag == 0;
3329 }
3330
3331
3332 /* ----------------------------------------------------------------- Private */
3333
3334
3335 /**
3336 * Initialize objects used by the parser.
3337 */
preparse()3338 static void preparse() {
3339 servicelist = tail = current = NULL;
3340 /* Set instance incarnation ID */
3341 time(&Run.incarnation);
3342 /* Reset lexer */
3343 buffer_stack_ptr = 0;
3344 lineno = 1;
3345 arglineno = 1;
3346 argcurrentfile = NULL;
3347 argyytext = NULL;
3348 /* Reset parser */
3349 Run.limits.sendExpectBuffer = LIMIT_SENDEXPECTBUFFER;
3350 Run.limits.fileContentBuffer = LIMIT_FILECONTENTBUFFER;
3351 Run.limits.httpContentBuffer = LIMIT_HTTPCONTENTBUFFER;
3352 Run.limits.programOutput = LIMIT_PROGRAMOUTPUT;
3353 Run.limits.networkTimeout = LIMIT_NETWORKTIMEOUT;
3354 Run.limits.programTimeout = LIMIT_PROGRAMTIMEOUT;
3355 Run.limits.stopTimeout = LIMIT_STOPTIMEOUT;
3356 Run.limits.startTimeout = LIMIT_STARTTIMEOUT;
3357 Run.limits.restartTimeout = LIMIT_RESTARTTIMEOUT;
3358 Run.onreboot = Onreboot_Start;
3359 Run.mmonitcredentials = NULL;
3360 Run.httpd.flags = Httpd_Disabled | Httpd_Signature;
3361 Run.httpd.credentials = NULL;
3362 memset(&(Run.httpd.socket), 0, sizeof(Run.httpd.socket));
3363 Run.mailserver_timeout = SMTP_TIMEOUT;
3364 Run.eventlist_dir = NULL;
3365 Run.eventlist_slots = -1;
3366 Run.system = NULL;
3367 Run.mmonits = NULL;
3368 Run.maillist = NULL;
3369 Run.mailservers = NULL;
3370 Run.MailFormat.from = NULL;
3371 Run.MailFormat.replyto = NULL;
3372 Run.MailFormat.subject = NULL;
3373 Run.MailFormat.message = NULL;
3374 depend_list = NULL;
3375 Run.flags |= Run_HandlerInit | Run_MmonitCredentials;
3376 for (int i = 0; i <= Handler_Max; i++)
3377 Run.handler_queue[i] = 0;
3378
3379 /*
3380 * Initialize objects
3381 */
3382 reset_uidset();
3383 reset_gidset();
3384 reset_statusset();
3385 reset_sizeset();
3386 reset_mailset();
3387 reset_sslset();
3388 reset_mailserverset();
3389 reset_mmonitset();
3390 reset_responsetimeset();
3391 reset_portset();
3392 reset_permset();
3393 reset_icmpset();
3394 reset_linkstatusset();
3395 reset_linkspeedset();
3396 reset_linksaturationset();
3397 reset_bandwidthset();
3398 reset_rateset(&rate);
3399 reset_rateset(&rate1);
3400 reset_rateset(&rate2);
3401 reset_filesystemset();
3402 reset_resourceset();
3403 reset_checksumset();
3404 reset_timestampset();
3405 reset_actionrateset();
3406 }
3407
3408
3409 /*
3410 * Check that values are reasonable after parsing
3411 */
postparse()3412 static void postparse() {
3413 if (cfg_errflag)
3414 return;
3415
3416 /* If defined - add the last service to the service list */
3417 if (current) {
3418 addservice(current);
3419 current = NULL;
3420 }
3421
3422 /* Check that we do not start monit in daemon mode without having a poll time */
3423 if (! Run.polltime && ((Run.flags & Run_Daemon) || (Run.flags & Run_Foreground))) {
3424 Log_error("Poll time is invalid or not defined. Please define poll time in the control file\nas a number (> 0) or use the -d option when starting monit\n");
3425 cfg_errflag++;
3426 }
3427
3428 if (Run.files.log)
3429 Run.flags |= Run_Log;
3430
3431 /* Add the default general system service if not specified explicitly: service name default to hostname */
3432 if (! Run.system) {
3433 char hostname[STRLEN];
3434 if (gethostname(hostname, sizeof(hostname))) {
3435 Log_error("Cannot get system hostname -- please add 'check system <name>'\n");
3436 cfg_errflag++;
3437 }
3438 if (Util_existService(hostname)) {
3439 Log_error("'check system' not defined in control file, failed to add automatic configuration (service name %s is used already) -- please add 'check system <name>' manually\n", hostname);
3440 cfg_errflag++;
3441 }
3442 Run.system = createservice(Service_System, Str_dup(hostname), NULL, check_system);
3443 addservice(Run.system);
3444 }
3445 addeventaction(&(Run.system->action_MONIT_START), Action_Start, Action_Ignored);
3446 addeventaction(&(Run.system->action_MONIT_STOP), Action_Stop, Action_Ignored);
3447
3448 if (Run.mmonits) {
3449 if (Run.httpd.flags & Httpd_Net) {
3450 if (Run.flags & Run_MmonitCredentials) {
3451 Auth_T c;
3452 for (c = Run.httpd.credentials; c; c = c->next) {
3453 if (c->digesttype == Digest_Cleartext && ! c->is_readonly) {
3454 Run.mmonitcredentials = c;
3455 break;
3456 }
3457 }
3458 if (! Run.mmonitcredentials)
3459 Log_warning("M/Monit registration with credentials enabled, but no suitable credentials found in monit configuration file -- please add 'allow user:password' option to 'set httpd' statement\n");
3460 }
3461 } else if (Run.httpd.flags & Httpd_Unix) {
3462 Log_warning("M/Monit enabled but Monit httpd is using unix socket -- please change 'set httpd' statement to use TCP port in order to be able to manage services on Monit\n");
3463 } else {
3464 Log_warning("M/Monit enabled but no httpd allowed -- please add 'set httpd' statement\n");
3465 }
3466 }
3467
3468 /* Check the sanity of any dependency graph */
3469 check_depend();
3470
3471 #if defined HAVE_OPENSSL && defined OPENSSL_FIPS
3472 Ssl_setFipsMode(Run.flags & Run_FipsEnabled);
3473 #endif
3474
3475 Processor_setHttpPostLimit();
3476 }
3477
3478
_parseOutgoingAddress(char * ip,Outgoing_T * outgoing)3479 static bool _parseOutgoingAddress(char *ip, Outgoing_T *outgoing) {
3480 struct addrinfo *result, hints = {.ai_flags = AI_NUMERICHOST};
3481 int status = getaddrinfo(ip, NULL, &hints, &result);
3482 if (status == 0) {
3483 outgoing->ip = ip;
3484 outgoing->addrlen = result->ai_addrlen;
3485 memcpy(&(outgoing->addr), result->ai_addr, result->ai_addrlen);
3486 freeaddrinfo(result);
3487 return true;
3488 } else {
3489 yyerror2("IP address parsing failed for %s -- %s", ip, status == EAI_SYSTEM ? STRERROR : gai_strerror(status));
3490 }
3491 return false;
3492 }
3493
3494
3495 /*
3496 * Create a new service object and add any current objects to the
3497 * service list.
3498 */
createservice(Service_Type type,char * name,char * value,State_Type (* check)(Service_T s))3499 static Service_T createservice(Service_Type type, char *name, char *value, State_Type (*check)(Service_T s)) {
3500 ASSERT(name);
3501
3502 check_name(name);
3503
3504 if (current)
3505 addservice(current);
3506
3507 NEW(current);
3508 current->type = type;
3509 switch (type) {
3510 case Service_Directory:
3511 NEW(current->inf.directory);
3512 break;
3513 case Service_Fifo:
3514 NEW(current->inf.fifo);
3515 break;
3516 case Service_File:
3517 NEW(current->inf.file);
3518 break;
3519 case Service_Filesystem:
3520 NEW(current->inf.filesystem);
3521 break;
3522 case Service_Net:
3523 NEW(current->inf.net);
3524 break;
3525 case Service_Process:
3526 NEW(current->inf.process);
3527 break;
3528 default:
3529 break;
3530 }
3531 Util_resetInfo(current);
3532
3533 if (type == Service_Program) {
3534 NEW(current->program);
3535 current->program->args = command;
3536 command = NULL;
3537 current->program->timeout = Run.limits.programTimeout;
3538 }
3539
3540 /* Set default values */
3541 current->onrebootRestored = false;
3542 current->mode = Monitor_Active;
3543 current->monitor = Monitor_Init;
3544 current->onreboot = Run.onreboot;
3545 current->name = name;
3546 current->name_urlescaped = Util_urlEncode(name, false);
3547 current->name_htmlescaped = escapeHTML(StringBuffer_create(16), name);
3548 current->check = check;
3549 current->path = value;
3550
3551 /* Initialize general event handlers */
3552 addeventaction(&(current)->action_DATA, Action_Alert, Action_Alert);
3553 addeventaction(&(current)->action_EXEC, Action_Alert, Action_Alert);
3554 addeventaction(&(current)->action_INVALID, Action_Restart, Action_Alert);
3555
3556 /* Initialize internal event handlers */
3557 addeventaction(&(current)->action_ACTION, Action_Alert, Action_Ignored);
3558
3559 gettimeofday(¤t->collected, NULL);
3560
3561 return current;
3562 }
3563
3564
3565 /*
3566 * Add a service object to the servicelist
3567 */
addservice(Service_T s)3568 static void addservice(Service_T s) {
3569 ASSERT(s);
3570
3571 // Test sanity check
3572 switch (s->type) {
3573 case Service_Host:
3574 // Verify that a remote service has a port or an icmp list
3575 if (! s->portlist && ! s->icmplist) {
3576 Log_error("'check host' statement is incomplete: Please specify a port number to test\n or an icmp test at the remote host: '%s'\n", s->name);
3577 cfg_errflag++;
3578 }
3579 break;
3580 case Service_Program:
3581 // Verify that a program test has a status test
3582 if (! s->statuslist && ! s->matchlist) {
3583 Log_error("'check program %s' is incomplete: Please add a 'status' or 'content' test\n", s->name);
3584 cfg_errflag++;
3585 }
3586 char program[PATH_MAX];
3587 strncpy(program, s->program->args->arg[0], sizeof(program) - 1);
3588 // Require that the program exist before creating the Command object
3589 if (File_isExecutable(program)) {
3590 s->program->C = Command_new(program, NULL);
3591 for (int i = 1; i < s->program->args->length; i++) {
3592 Command_appendArgument(s->program->C, s->program->args->arg[i]);
3593 snprintf(program + strlen(program), sizeof(program) - strlen(program) - 1, " %s", s->program->args->arg[i]);
3594 }
3595 s->path = Str_dup(program);
3596 if (s->program->args->has_uid)
3597 Command_setUid(s->program->C, s->program->args->uid);
3598 if (s->program->args->has_gid)
3599 Command_setGid(s->program->C, s->program->args->gid);
3600 // Set environment
3601 Command_setEnv(s->program->C, "MONIT_SERVICE", s->name);
3602 } else {
3603 Log_error("A 'check program' statement requires the program to exist '%s'\n", program);
3604 cfg_errflag++;
3605 }
3606 break;
3607 case Service_Net:
3608 if (! s->linkstatuslist) {
3609 // Add link status test if not defined
3610 addeventaction(&(linkstatusset).action, Action_Alert, Action_Alert);
3611 addlinkstatus(s, &linkstatusset);
3612 }
3613 break;
3614 case Service_Filesystem:
3615 if (! s->nonexistlist && ! s->existlist) {
3616 // Add non-existence test if not defined
3617 addeventaction(&(nonexistset).action, Action_Restart, Action_Alert);
3618 addnonexist(&nonexistset);
3619 }
3620 if (! s->fsflaglist) {
3621 // Add filesystem flags change test if not defined
3622 addeventaction(&(fsflagset).action, Action_Alert, Action_Ignored);
3623 addfsflag(&fsflagset);
3624 }
3625 break;
3626 case Service_Directory:
3627 case Service_Fifo:
3628 case Service_File:
3629 case Service_Process:
3630 if (! s->nonexistlist && ! s->existlist) {
3631 // Add existence test if not defined
3632 addeventaction(&(nonexistset).action, Action_Restart, Action_Alert);
3633 addnonexist(&nonexistset);
3634 }
3635 break;
3636 default:
3637 break;
3638 }
3639
3640 // No "every" statement was used, monitor each cycle
3641 if (s->every.type == Every_Initializing)
3642 s->every.type = Every_Cycle;
3643
3644 /* Add the service to the end of the service list */
3645 if (tail != NULL) {
3646 tail->next = s;
3647 tail->next_conf = s;
3648 } else {
3649 servicelist = s;
3650 servicelist_conf = s;
3651 }
3652 tail = s;
3653 }
3654
3655
3656 /*
3657 * Add entry to service group list
3658 */
addservicegroup(char * name)3659 static void addservicegroup(char *name) {
3660 ServiceGroup_T g;
3661
3662 ASSERT(name);
3663
3664 /* Check if service group with the same name is defined already */
3665 for (g = servicegrouplist; g; g = g->next)
3666 if (IS(g->name, name))
3667 break;
3668
3669 if (! g) {
3670 NEW(g);
3671 g->name = Str_dup(name);
3672 g->members = List_new();
3673 g->next = servicegrouplist;
3674 servicegrouplist = g;
3675 }
3676
3677 List_append(g->members, current);
3678 }
3679
3680
3681 /*
3682 * Add a dependant entry to the current service dependant list
3683 */
adddependant(char * dependant)3684 static void adddependant(char *dependant) {
3685 Dependant_T d;
3686
3687 ASSERT(dependant);
3688
3689 NEW(d);
3690
3691 if (current->dependantlist)
3692 d->next = current->dependantlist;
3693
3694 d->dependant = dependant;
3695 d->dependant_urlescaped = Util_urlEncode(dependant, false);
3696 d->dependant_htmlescaped = escapeHTML(StringBuffer_create(16), dependant);
3697 current->dependantlist = d;
3698
3699 }
3700
3701
3702 /*
3703 * Add the given mailaddress with the appropriate alert notification
3704 * values and mail attributes to the given mailinglist.
3705 */
addmail(char * mailto,Mail_T f,Mail_T * l)3706 static void addmail(char *mailto, Mail_T f, Mail_T *l) {
3707 Mail_T m;
3708
3709 ASSERT(mailto);
3710
3711 NEW(m);
3712 m->to = mailto;
3713 m->from = f->from;
3714 m->replyto = f->replyto;
3715 m->subject = f->subject;
3716 m->message = f->message;
3717 m->events = f->events;
3718 m->reminder = f->reminder;
3719
3720 m->next = *l;
3721 *l = m;
3722
3723 reset_mailset();
3724 }
3725
3726
3727 /*
3728 * Add the given portset to the current service's portlist
3729 */
addport(Port_T * list,Port_T port)3730 static void addport(Port_T *list, Port_T port) {
3731 ASSERT(port);
3732
3733 if (port->protocol->check == check_radius && port->type != Socket_Udp)
3734 yyerror("Radius protocol test supports UDP only");
3735
3736 Port_T p;
3737 NEW(p);
3738 p->is_available = Connection_Init;
3739 p->check_invers = port->check_invers;
3740 p->type = port->type;
3741 p->socket = port->socket;
3742 p->family = port->family;
3743 p->action = port->action;
3744 p->timeout = port->timeout;
3745 p->retry = port->retry;
3746 p->protocol = port->protocol;
3747 p->hostname = port->hostname;
3748 p->url_request = port->url_request;
3749 p->outgoing = port->outgoing;
3750
3751 if (p->family == Socket_Unix) {
3752 p->target.unix.pathname = port->target.unix.pathname;
3753 } else {
3754 p->target.net.port = port->target.net.port;
3755 if (sslset.flags) {
3756 #ifdef HAVE_OPENSSL
3757 p->target.net.ssl.certificate.minimumDays = port->target.net.ssl.certificate.minimumDays;
3758 if (sslset.flags && (p->target.net.port == 25 || p->target.net.port == 143 || p->target.net.port == 587))
3759 sslset.flags = SSL_StartTLS;
3760 _setSSLOptions(&(p->target.net.ssl.options));
3761 #else
3762 yyerror("SSL check cannot be activated -- Monit was not built with SSL support");
3763 #endif
3764 }
3765 }
3766 memcpy(&p->parameters, &port->parameters, sizeof(port->parameters));
3767
3768 if (p->protocol->check == check_http) {
3769 if (p->parameters.http.checksum) {
3770 cleanup_hash_string(p->parameters.http.checksum);
3771 if (strlen(p->parameters.http.checksum) == 32)
3772 p->parameters.http.hashtype = Hash_Md5;
3773 else if (strlen(p->parameters.http.checksum) == 40)
3774 p->parameters.http.hashtype = Hash_Sha1;
3775 else
3776 yyerror2("invalid checksum [%s]", p->parameters.http.checksum);
3777 } else {
3778 p->parameters.http.hashtype = Hash_Unknown;
3779 }
3780 if (! p->parameters.http.method) {
3781 p->parameters.http.method = Http_Get;
3782 } else if (p->parameters.http.method == Http_Head) {
3783 // Sanity check: if content or checksum test is used, the method Http_Head is not allowed, as we need the content
3784 if ((p->url_request && p->url_request->regex) || p->parameters.http.checksum) {
3785 yyerror2("if response content or checksum test is enabled, the HEAD method is not allowed");
3786 }
3787 }
3788 } else if (p->protocol->check == check_mysql) {
3789 if (p->parameters.mysql.rsaChecksum) {
3790 if (! p->parameters.mysql.username)
3791 yyerror2("the rsakey checksum test requires credentials to be defined");
3792 if (p->target.net.ssl.options.flags != SSL_Disabled)
3793 yyerror2("the rsakey checksum test can be used just with unsecured mysql protocol");
3794 }
3795 }
3796
3797 p->responsetime.limit = responsetimeset.limit;
3798 p->responsetime.current = responsetimeset.current;
3799 p->responsetime.operator = responsetimeset.operator;
3800
3801 p->next = *list;
3802 *list = p;
3803
3804 reset_sslset();
3805 reset_responsetimeset();
3806 reset_portset();
3807
3808 }
3809
3810
addhttpheader(Port_T port,char * header)3811 static void addhttpheader(Port_T port, char *header) {
3812 if (! port->parameters.http.headers) {
3813 port->parameters.http.headers = List_new();
3814 }
3815 if (Str_startsWith(header, "Connection:") && ! Str_sub(header, "close")) {
3816 yywarning("We don't recommend setting the Connection header. Monit will always close the connection even if 'keep-alive' is set\n");
3817 }
3818 List_append(port->parameters.http.headers, header);
3819 }
3820
3821
3822 /*
3823 * Add a new resource object to the current service resource list
3824 */
addresource(Resource_T rr)3825 static void addresource(Resource_T rr) {
3826 ASSERT(rr);
3827 if (Run.flags & Run_ProcessEngineEnabled) {
3828 Resource_T r;
3829 NEW(r);
3830 r->resource_id = rr->resource_id;
3831 r->limit = rr->limit;
3832 r->action = rr->action;
3833 r->operator = rr->operator;
3834 r->next = current->resourcelist;
3835 current->resourcelist = r;
3836 } else {
3837 yywarning("Cannot activate service check. The process status engine was disabled. On certain systems you must run monit as root to utilize this feature)\n");
3838 }
3839 reset_resourceset();
3840 }
3841
3842
3843 /*
3844 * Add a new file object to the current service timestamp list
3845 */
addtimestamp(Timestamp_T ts)3846 static void addtimestamp(Timestamp_T ts) {
3847 ASSERT(ts);
3848
3849 Timestamp_T t;
3850 NEW(t);
3851 t->type = ts->type;
3852 t->operator = ts->operator;
3853 t->time = ts->time;
3854 t->action = ts->action;
3855 t->test_changes = ts->test_changes;
3856
3857 t->next = current->timestamplist;
3858 current->timestamplist = t;
3859
3860 reset_timestampset();
3861 }
3862
3863
3864 /*
3865 * Add a new object to the current service actionrate list
3866 */
addactionrate(ActionRate_T ar)3867 static void addactionrate(ActionRate_T ar) {
3868 ActionRate_T a;
3869
3870 ASSERT(ar);
3871
3872 if (ar->count > ar->cycle)
3873 yyerror2("The number of restarts must be less than poll cycles");
3874 if (ar->count <= 0 || ar->cycle <= 0)
3875 yyerror2("Zero or negative values not allowed in a action rate statement");
3876
3877 NEW(a);
3878 a->count = ar->count;
3879 a->cycle = ar->cycle;
3880 a->action = ar->action;
3881
3882 a->next = current->actionratelist;
3883 current->actionratelist = a;
3884
3885 reset_actionrateset();
3886 }
3887
3888
3889
3890 /*
3891 * Add a new Size object to the current service size list
3892 */
addsize(Size_T ss)3893 static void addsize(Size_T ss) {
3894 Size_T s;
3895 struct stat buf;
3896
3897 ASSERT(ss);
3898
3899 NEW(s);
3900 s->operator = ss->operator;
3901 s->size = ss->size;
3902 s->action = ss->action;
3903 s->test_changes = ss->test_changes;
3904 /* Get the initial size for future comparison, if the file exists */
3905 if (s->test_changes) {
3906 s->initialized = ! stat(current->path, &buf);
3907 if (s->initialized)
3908 s->size = (unsigned long long)buf.st_size;
3909 }
3910
3911 s->next = current->sizelist;
3912 current->sizelist = s;
3913
3914 reset_sizeset();
3915 }
3916
3917
3918 /*
3919 * Add a new Uptime object to the current service uptime list
3920 */
adduptime(Uptime_T uu)3921 static void adduptime(Uptime_T uu) {
3922 Uptime_T u;
3923
3924 ASSERT(uu);
3925
3926 NEW(u);
3927 u->operator = uu->operator;
3928 u->uptime = uu->uptime;
3929 u->action = uu->action;
3930
3931 u->next = current->uptimelist;
3932 current->uptimelist = u;
3933
3934 reset_uptimeset();
3935 }
3936
3937
3938 /*
3939 * Add a new Pid object to the current service pid list
3940 */
addpid(Pid_T pp)3941 static void addpid(Pid_T pp) {
3942 ASSERT(pp);
3943
3944 Pid_T p;
3945 NEW(p);
3946 p->action = pp->action;
3947
3948 p->next = current->pidlist;
3949 current->pidlist = p;
3950
3951 reset_pidset();
3952 }
3953
3954
3955 /*
3956 * Add a new PPid object to the current service ppid list
3957 */
addppid(Pid_T pp)3958 static void addppid(Pid_T pp) {
3959 ASSERT(pp);
3960
3961 Pid_T p;
3962 NEW(p);
3963 p->action = pp->action;
3964
3965 p->next = current->ppidlist;
3966 current->ppidlist = p;
3967
3968 reset_ppidset();
3969 }
3970
3971
3972 /*
3973 * Add a new Fsflag object to the current service fsflag list
3974 */
addfsflag(FsFlag_T ff)3975 static void addfsflag(FsFlag_T ff) {
3976 ASSERT(ff);
3977
3978 FsFlag_T f;
3979 NEW(f);
3980 f->action = ff->action;
3981
3982 f->next = current->fsflaglist;
3983 current->fsflaglist = f;
3984
3985 reset_fsflagset();
3986 }
3987
3988
3989 /*
3990 * Add a new Nonexist object to the current service list
3991 */
addnonexist(NonExist_T ff)3992 static void addnonexist(NonExist_T ff) {
3993 ASSERT(ff);
3994
3995 NonExist_T f;
3996 NEW(f);
3997 f->action = ff->action;
3998
3999 f->next = current->nonexistlist;
4000 current->nonexistlist = f;
4001
4002 reset_nonexistset();
4003 }
4004
4005
addexist(Exist_T rule)4006 static void addexist(Exist_T rule) {
4007 ASSERT(rule);
4008 Exist_T r;
4009 NEW(r);
4010 r->action = rule->action;
4011 r->next = current->existlist;
4012 current->existlist = r;
4013 reset_existset();
4014 }
4015
4016
4017 /*
4018 * Set Checksum object in the current service
4019 */
addchecksum(Checksum_T cs)4020 static void addchecksum(Checksum_T cs) {
4021 ASSERT(cs);
4022
4023 cs->initialized = true;
4024
4025 if (STR_UNDEF(cs->hash)) {
4026 if (cs->type == Hash_Unknown)
4027 cs->type = Hash_Default;
4028 if (! (Checksum_getChecksum(current->path, cs->type, cs->hash, sizeof(cs->hash)))) {
4029 /* If the file doesn't exist, set dummy value */
4030 snprintf(cs->hash, sizeof(cs->hash), cs->type == Hash_Md5 ? "00000000000000000000000000000000" : "0000000000000000000000000000000000000000");
4031 cs->initialized = false;
4032 yywarning2("Cannot compute a checksum for file %s", current->path);
4033 }
4034 }
4035
4036 int len = cleanup_hash_string(cs->hash);
4037 if (cs->type == Hash_Unknown) {
4038 if (len == 32) {
4039 cs->type = Hash_Md5;
4040 } else if (len == 40) {
4041 cs->type = Hash_Sha1;
4042 } else {
4043 yyerror2("Unknown checksum type [%s] for file %s", cs->hash, current->path);
4044 reset_checksumset();
4045 return;
4046 }
4047 } else if ((cs->type == Hash_Md5 && len != 32) || (cs->type == Hash_Sha1 && len != 40)) {
4048 yyerror2("Invalid checksum [%s] for file %s", cs->hash, current->path);
4049 reset_checksumset();
4050 return;
4051 }
4052
4053 Checksum_T c;
4054 NEW(c);
4055 c->type = cs->type;
4056 c->test_changes = cs->test_changes;
4057 c->initialized = cs->initialized;
4058 c->action = cs->action;
4059 snprintf(c->hash, sizeof(c->hash), "%s", cs->hash);
4060
4061 current->checksum = c;
4062
4063 reset_checksumset();
4064
4065 }
4066
4067
4068 /*
4069 * Set Perm object in the current service
4070 */
addperm(Perm_T ps)4071 static void addperm(Perm_T ps) {
4072 ASSERT(ps);
4073
4074 Perm_T p;
4075 NEW(p);
4076 p->action = ps->action;
4077 p->test_changes = ps->test_changes;
4078 if (p->test_changes) {
4079 if (! File_exist(current->path))
4080 DEBUG("The path '%s' used in the PERMISSION statement refer to a non-existing object\n", current->path);
4081 else if ((p->perm = File_mod(current->path)) < 0)
4082 yyerror2("Cannot get the timestamp for '%s'", current->path);
4083 else
4084 p->perm &= 07777;
4085 } else {
4086 p->perm = ps->perm;
4087 }
4088 current->perm = p;
4089 reset_permset();
4090 }
4091
4092
addlinkstatus(Service_T s,LinkStatus_T L)4093 static void addlinkstatus(Service_T s, LinkStatus_T L) {
4094 ASSERT(L);
4095
4096 LinkStatus_T l;
4097
4098 // Sanity check: we don't support link up/down tests mix
4099 for (l = s->linkstatuslist; l; l = l->next) {
4100 if (l->check_invers != L->check_invers)
4101 yyerror2("Mixing link up and down tests is not supported");
4102 }
4103
4104 if (L->check_invers)
4105 s->inverseStatus = true;
4106
4107 NEW(l);
4108 l->check_invers = L->check_invers;
4109 l->action = L->action;
4110
4111 l->next = s->linkstatuslist;
4112 s->linkstatuslist = l;
4113
4114 reset_linkstatusset();
4115 }
4116
4117
addlinkspeed(Service_T s,LinkSpeed_T L)4118 static void addlinkspeed(Service_T s, LinkSpeed_T L) {
4119 ASSERT(L);
4120
4121 LinkSpeed_T l;
4122 NEW(l);
4123 l->action = L->action;
4124
4125 l->next = s->linkspeedlist;
4126 s->linkspeedlist = l;
4127
4128 reset_linkspeedset();
4129 }
4130
4131
addlinksaturation(Service_T s,LinkSaturation_T L)4132 static void addlinksaturation(Service_T s, LinkSaturation_T L) {
4133 ASSERT(L);
4134
4135 LinkSaturation_T l;
4136 NEW(l);
4137 l->operator = L->operator;
4138 l->limit = L->limit;
4139 l->action = L->action;
4140
4141 l->next = s->linksaturationlist;
4142 s->linksaturationlist = l;
4143
4144 reset_linksaturationset();
4145 }
4146
4147
4148 /*
4149 * Return Bandwidth object
4150 */
addbandwidth(Bandwidth_T * list,Bandwidth_T b)4151 static void addbandwidth(Bandwidth_T *list, Bandwidth_T b) {
4152 ASSERT(list);
4153 ASSERT(b);
4154
4155 if (b->rangecount * b->range > 24 * Time_Hour) {
4156 yyerror2("Maximum range for total test is 24 hours");
4157 } else if (b->range == Time_Minute && b->rangecount > 60) {
4158 yyerror2("Maximum value for [minute(s)] unit is 60");
4159 } else if (b->range == Time_Hour && b->rangecount > 24) {
4160 yyerror2("Maximum value for [hour(s)] unit is 24");
4161 } else if (b->range == Time_Day && b->rangecount > 1) {
4162 yyerror2("Maximum value for [day(s)] unit is 1");
4163 } else {
4164 if (b->range == Time_Day) {
4165 // translate last day -> last 24 hours
4166 b->rangecount = 24;
4167 b->range = Time_Hour;
4168 }
4169 Bandwidth_T bandwidth;
4170 NEW(bandwidth);
4171 bandwidth->operator = b->operator;
4172 bandwidth->limit = b->limit;
4173 bandwidth->rangecount = b->rangecount;
4174 bandwidth->range = b->range;
4175 bandwidth->action = b->action;
4176 bandwidth->next = *list;
4177 *list = bandwidth;
4178 }
4179 reset_bandwidthset();
4180 }
4181
4182
appendmatch(Match_T * list,Match_T item)4183 static void appendmatch(Match_T *list, Match_T item) {
4184 if (*list) {
4185 /* Find the end of the list (keep the same patterns order as in the config file) */
4186 Match_T last;
4187 for (last = *list; last->next; last = last->next)
4188 ;
4189 last->next = item;
4190 } else {
4191 *list = item;
4192 }
4193 }
4194
4195
4196 /*
4197 * Set Match object in the current service
4198 */
addmatch(Match_T ms,int actionnumber,int linenumber)4199 static void addmatch(Match_T ms, int actionnumber, int linenumber) {
4200 Match_T m;
4201
4202 ASSERT(ms);
4203
4204 NEW(m);
4205 NEW(m->regex_comp);
4206
4207 m->match_string = ms->match_string;
4208 m->match_path = ms->match_path ? Str_dup(ms->match_path) : NULL;
4209 m->action = ms->action;
4210 m->not = ms->not;
4211 m->ignore = ms->ignore;
4212 m->next = NULL;
4213
4214 addeventaction(&(m->action), actionnumber, Action_Ignored);
4215
4216 int reg_return = regcomp(m->regex_comp, ms->match_string, REG_NOSUB|REG_EXTENDED);
4217
4218 if (reg_return != 0) {
4219 char errbuf[STRLEN];
4220 regerror(reg_return, ms->regex_comp, errbuf, STRLEN);
4221 if (m->match_path != NULL)
4222 yyerror2("Regex parsing error: %s on line %i of", errbuf, linenumber);
4223 else
4224 yyerror2("Regex parsing error: %s", errbuf);
4225 }
4226 appendmatch(m->ignore ? ¤t->matchignorelist : ¤t->matchlist, m);
4227 }
4228
4229
addmatchpath(Match_T ms,Action_Type actionnumber)4230 static void addmatchpath(Match_T ms, Action_Type actionnumber) {
4231 ASSERT(ms->match_path);
4232
4233 FILE *handle = fopen(ms->match_path, "r");
4234 if (handle == NULL) {
4235 yyerror2("Cannot read regex match file (%s)", ms->match_path);
4236 return;
4237 }
4238
4239 // The addeventaction() called from addmatch() will reset the command1 to NULL, but we need to duplicate the command for each line, thus need to save it here
4240 command_t savecommand = command1;
4241 for (int linenumber = 1; ! feof(handle); linenumber++) {
4242 char buf[2048];
4243
4244 if (! fgets(buf, sizeof(buf), handle))
4245 continue;
4246
4247 size_t len = strlen(buf);
4248
4249 if (len == 0 || buf[0] == '\n')
4250 continue;
4251
4252 if (buf[len - 1] == '\n')
4253 buf[len - 1] = 0;
4254
4255 ms->match_string = Str_dup(buf);
4256
4257 if (actionnumber == Action_Exec) {
4258 if (command1 == NULL) {
4259 ASSERT(savecommand);
4260 command1 = copycommand(savecommand);
4261 }
4262 }
4263
4264 addmatch(ms, actionnumber, linenumber);
4265 }
4266 if (actionnumber == Action_Exec && savecommand)
4267 gccmd(&savecommand);
4268
4269 fclose(handle);
4270 }
4271
4272
4273 /*
4274 * Set exit status test object in the current service
4275 */
addstatus(Status_T status)4276 static void addstatus(Status_T status) {
4277 Status_T s;
4278 ASSERT(status);
4279 NEW(s);
4280 s->initialized = status->initialized;
4281 s->return_value = status->return_value;
4282 s->operator = status->operator;
4283 s->action = status->action;
4284 s->next = current->statuslist;
4285 current->statuslist = s;
4286
4287 reset_statusset();
4288 }
4289
4290
4291 /*
4292 * Set Uid object in the current service
4293 */
adduid(Uid_T u)4294 static Uid_T adduid(Uid_T u) {
4295 ASSERT(u);
4296
4297 Uid_T uid;
4298 NEW(uid);
4299 uid->uid = u->uid;
4300 uid->action = u->action;
4301 reset_uidset();
4302 return uid;
4303 }
4304
4305
4306 /*
4307 * Set Gid object in the current service
4308 */
addgid(Gid_T g)4309 static Gid_T addgid(Gid_T g) {
4310 ASSERT(g);
4311
4312 Gid_T gid;
4313 NEW(gid);
4314 gid->gid = g->gid;
4315 gid->action = g->action;
4316 reset_gidset();
4317 return gid;
4318 }
4319
4320
4321 /*
4322 * Add a new filesystem to the current service's filesystem list
4323 */
addfilesystem(FileSystem_T ds)4324 static void addfilesystem(FileSystem_T ds) {
4325 FileSystem_T dev;
4326
4327 ASSERT(ds);
4328
4329 NEW(dev);
4330 dev->resource = ds->resource;
4331 dev->operator = ds->operator;
4332 dev->limit_absolute = ds->limit_absolute;
4333 dev->limit_percent = ds->limit_percent;
4334 dev->action = ds->action;
4335
4336 dev->next = current->filesystemlist;
4337 current->filesystemlist = dev;
4338
4339 reset_filesystemset();
4340
4341 }
4342
4343
4344 /*
4345 * Add a new icmp object to the current service's icmp list
4346 */
addicmp(Icmp_T is)4347 static void addicmp(Icmp_T is) {
4348 Icmp_T icmp;
4349
4350 ASSERT(is);
4351
4352 NEW(icmp);
4353 icmp->family = is->family;
4354 icmp->type = is->type;
4355 icmp->size = is->size;
4356 icmp->count = is->count;
4357 icmp->timeout = is->timeout;
4358 icmp->action = is->action;
4359 icmp->outgoing = is->outgoing;
4360 icmp->check_invers = is->check_invers;
4361 icmp->is_available = Connection_Init;
4362
4363 icmp->responsetime.limit = responsetimeset.limit;
4364 icmp->responsetime.current = responsetimeset.current;
4365 icmp->responsetime.operator = responsetimeset.operator;
4366
4367 icmp->next = current->icmplist;
4368 current->icmplist = icmp;
4369
4370 reset_responsetimeset();
4371 reset_icmpset();
4372 }
4373
4374
4375 /*
4376 * Set EventAction object
4377 */
addeventaction(EventAction_T * _ea,Action_Type failed,Action_Type succeeded)4378 static void addeventaction(EventAction_T *_ea, Action_Type failed, Action_Type succeeded) {
4379 EventAction_T ea;
4380
4381 ASSERT(_ea);
4382
4383 NEW(ea);
4384 NEW(ea->failed);
4385 NEW(ea->succeeded);
4386
4387 ea->failed->id = failed;
4388 ea->failed->repeat = repeat1;
4389 ea->failed->count = rate1.count;
4390 ea->failed->cycles = rate1.cycles;
4391 if (failed == Action_Exec) {
4392 ASSERT(command1);
4393 ea->failed->exec = command1;
4394 command1 = NULL;
4395 }
4396
4397 ea->succeeded->id = succeeded;
4398 ea->succeeded->repeat = repeat2;
4399 ea->succeeded->count = rate2.count;
4400 ea->succeeded->cycles = rate2.cycles;
4401 if (succeeded == Action_Exec) {
4402 ASSERT(command2);
4403 ea->succeeded->exec = command2;
4404 command2 = NULL;
4405 }
4406 *_ea = ea;
4407 reset_rateset(&rate);
4408 reset_rateset(&rate1);
4409 reset_rateset(&rate2);
4410 repeat = repeat1 = repeat2 = 0;
4411 }
4412
4413
4414 /*
4415 * Add a generic protocol handler to
4416 */
addgeneric(Port_T port,char * send,char * expect)4417 static void addgeneric(Port_T port, char *send, char *expect) {
4418 Generic_T g = port->parameters.generic.sendexpect;
4419 if (! g) {
4420 NEW(g);
4421 port->parameters.generic.sendexpect = g;
4422 } else {
4423 while (g->next)
4424 g = g->next;
4425 NEW(g->next);
4426 g = g->next;
4427 }
4428 if (send) {
4429 g->send = send;
4430 g->expect = NULL;
4431 } else if (expect) {
4432 int reg_return;
4433 NEW(g->expect);
4434 reg_return = regcomp(g->expect, expect, REG_NOSUB|REG_EXTENDED);
4435 FREE(expect);
4436 if (reg_return != 0) {
4437 char errbuf[STRLEN];
4438 regerror(reg_return, g->expect, errbuf, STRLEN);
4439 yyerror2("Regex parsing error: %s", errbuf);
4440 }
4441 g->send = NULL;
4442 }
4443 }
4444
4445
4446 /*
4447 * Add the current command object to the current service object's
4448 * start or stop program.
4449 */
addcommand(int what,unsigned int timeout)4450 static void addcommand(int what, unsigned int timeout) {
4451
4452 switch (what) {
4453 case START: current->start = command; break;
4454 case STOP: current->stop = command; break;
4455 case RESTART: current->restart = command; break;
4456 }
4457
4458 command->timeout = timeout;
4459
4460 command = NULL;
4461
4462 }
4463
4464
4465 /*
4466 * Add a new argument to the argument list
4467 */
addargument(char * argument)4468 static void addargument(char *argument) {
4469
4470 ASSERT(argument);
4471
4472 if (! command) {
4473 check_exec(argument);
4474 NEW(command);
4475 }
4476
4477 command->arg[command->length++] = argument;
4478 command->arg[command->length] = NULL;
4479
4480 if (command->length >= ARGMAX)
4481 yyerror("Exceeded maximum number of program arguments");
4482
4483 }
4484
4485
4486 /*
4487 * Setup a url request for the current port object
4488 */
prepare_urlrequest(URL_T U)4489 static void prepare_urlrequest(URL_T U) {
4490
4491 ASSERT(U);
4492
4493 /* Only the HTTP protocol is supported for URLs currently. See also the lexer if this is to be changed in the future */
4494 portset.protocol = Protocol_get(Protocol_HTTP);
4495
4496 if (urlrequest == NULL)
4497 NEW(urlrequest);
4498 urlrequest->url = U;
4499 portset.hostname = Str_dup(U->hostname);
4500 portset.target.net.port = U->port;
4501 portset.url_request = urlrequest;
4502 portset.type = Socket_Tcp;
4503 portset.parameters.http.request = Str_cat("%s%s%s", U->path, U->query ? "?" : "", U->query ? U->query : "");
4504 if (IS(U->protocol, "https"))
4505 sslset.flags = SSL_Enabled;
4506 }
4507
4508
4509 /*
4510 * Set the url request for a port
4511 */
seturlrequest(int operator,char * regex)4512 static void seturlrequest(int operator, char *regex) {
4513
4514 ASSERT(regex);
4515
4516 if (! urlrequest)
4517 NEW(urlrequest);
4518 urlrequest->operator = operator;
4519 int reg_return;
4520 NEW(urlrequest->regex);
4521 reg_return = regcomp(urlrequest->regex, regex, REG_NOSUB|REG_EXTENDED);
4522 if (reg_return != 0) {
4523 char errbuf[STRLEN];
4524 regerror(reg_return, urlrequest->regex, errbuf, STRLEN);
4525 yyerror2("Regex parsing error: %s", errbuf);
4526 }
4527 }
4528
4529
4530 /*
4531 * Add a new data recipient server to the mmonit server list
4532 */
addmmonit(Mmonit_T mmonit)4533 static void addmmonit(Mmonit_T mmonit) {
4534 ASSERT(mmonit->url);
4535
4536 Mmonit_T c;
4537 NEW(c);
4538 c->url = mmonit->url;
4539 c->compress = MmonitCompress_Init;
4540 _setSSLOptions(&(c->ssl));
4541 if (IS(c->url->protocol, "https")) {
4542 #ifdef HAVE_OPENSSL
4543 c->ssl.flags = SSL_Enabled;
4544 #else
4545 yyerror("SSL check cannot be activated -- SSL disabled");
4546 #endif
4547 }
4548 c->timeout = mmonit->timeout;
4549 c->next = NULL;
4550
4551 if (Run.mmonits) {
4552 Mmonit_T C;
4553 for (C = Run.mmonits; C->next; C = C->next)
4554 /* Empty */ ;
4555 C->next = c;
4556 } else {
4557 Run.mmonits = c;
4558 }
4559 reset_sslset();
4560 reset_mmonitset();
4561 }
4562
4563
4564 /*
4565 * Add a new smtp server to the mail server list
4566 */
addmailserver(MailServer_T mailserver)4567 static void addmailserver(MailServer_T mailserver) {
4568
4569 MailServer_T s;
4570
4571 ASSERT(mailserver->host);
4572
4573 NEW(s);
4574 s->host = mailserver->host;
4575 s->port = mailserver->port;
4576 s->username = mailserver->username;
4577 s->password = mailserver->password;
4578
4579 if (sslset.flags && (mailserver->port == 25 || mailserver->port == 587))
4580 sslset.flags = SSL_StartTLS;
4581 _setSSLOptions(&(s->ssl));
4582
4583 s->next = NULL;
4584
4585 if (Run.mailservers) {
4586 MailServer_T l;
4587 for (l = Run.mailservers; l->next; l = l->next)
4588 /* empty */;
4589 l->next = s;
4590 } else {
4591 Run.mailservers = s;
4592 }
4593 reset_mailserverset();
4594 }
4595
4596
4597 /*
4598 * Return uid if found on the system. If the parameter user is NULL
4599 * the uid parameter is used for looking up the user id on the system,
4600 * otherwise the user parameter is used.
4601 */
get_uid(char * user,uid_t uid)4602 static uid_t get_uid(char *user, uid_t uid) {
4603 char buf[4096];
4604 struct passwd pwd, *result = NULL;
4605 if (user) {
4606 if (getpwnam_r(user, &pwd, buf, sizeof(buf), &result) != 0 || ! result) {
4607 yyerror2("Requested user not found on the system");
4608 return(0);
4609 }
4610 } else {
4611 if (getpwuid_r(uid, &pwd, buf, sizeof(buf), &result) != 0 || ! result) {
4612 yyerror2("Requested uid not found on the system");
4613 return(0);
4614 }
4615 }
4616 return(pwd.pw_uid);
4617 }
4618
4619
4620 /*
4621 * Return gid if found on the system. If the parameter group is NULL
4622 * the gid parameter is used for looking up the group id on the system,
4623 * otherwise the group parameter is used.
4624 */
get_gid(char * group,gid_t gid)4625 static gid_t get_gid(char *group, gid_t gid) {
4626 struct group *grd;
4627
4628 if (group) {
4629 grd = getgrnam(group);
4630
4631 if (! grd) {
4632 yyerror2("Requested group not found on the system");
4633 return(0);
4634 }
4635
4636 } else {
4637
4638 if (! (grd = getgrgid(gid))) {
4639 yyerror2("Requested gid not found on the system");
4640 return(0);
4641 }
4642
4643 }
4644
4645 return(grd->gr_gid);
4646
4647 }
4648
4649
4650 /*
4651 * Add a new user id to the current command object.
4652 */
addeuid(uid_t uid)4653 static void addeuid(uid_t uid) {
4654 if (! getuid()) {
4655 command->has_uid = true;
4656 command->uid = uid;
4657 } else {
4658 yyerror("UID statement requires root privileges");
4659 }
4660 }
4661
4662
4663 /*
4664 * Add a new group id to the current command object.
4665 */
addegid(gid_t gid)4666 static void addegid(gid_t gid) {
4667 if (! getuid()) {
4668 command->has_gid = true;
4669 command->gid = gid;
4670 } else {
4671 yyerror("GID statement requires root privileges");
4672 }
4673 }
4674
4675
4676 /*
4677 * Reset the logfile if changed
4678 */
setlogfile(char * logfile)4679 static void setlogfile(char *logfile) {
4680 if (Run.files.log) {
4681 if (IS(Run.files.log, logfile)) {
4682 FREE(logfile);
4683 return;
4684 } else {
4685 FREE(Run.files.log);
4686 }
4687 }
4688 Run.files.log = logfile;
4689 }
4690
4691
4692 /*
4693 * Reset the pidfile if changed
4694 */
setpidfile(char * pidfile)4695 static void setpidfile(char *pidfile) {
4696 if (Run.files.pid) {
4697 if (IS(Run.files.pid, pidfile)) {
4698 FREE(pidfile);
4699 return;
4700 } else {
4701 FREE(Run.files.pid);
4702 }
4703 }
4704 Run.files.pid = pidfile;
4705 }
4706
4707
4708 /*
4709 * Read a apache htpasswd file and add credentials found for username
4710 */
addhtpasswdentry(char * filename,char * username,Digest_Type dtype)4711 static void addhtpasswdentry(char *filename, char *username, Digest_Type dtype) {
4712 char *ht_username = NULL;
4713 char *ht_passwd = NULL;
4714 char buf[STRLEN];
4715 FILE *handle = NULL;
4716 int credentials_added = 0;
4717
4718 ASSERT(filename);
4719
4720 handle = fopen(filename, "r");
4721
4722 if (handle == NULL) {
4723 if (username != NULL)
4724 yyerror2("Cannot read htpasswd (%s) for user %s", filename, username);
4725 else
4726 yyerror2("Cannot read htpasswd (%s)", filename);
4727 return;
4728 }
4729
4730 while (! feof(handle)) {
4731 char *colonindex = NULL;
4732
4733 if (! fgets(buf, STRLEN, handle))
4734 continue;
4735
4736 Str_rtrim(buf);
4737 Str_curtail(buf, "#");
4738
4739 if (NULL == (colonindex = strchr(buf, ':')))
4740 continue;
4741
4742 ht_passwd = Str_dup(colonindex+1);
4743 *colonindex = '\0';
4744
4745 /* In case we have a file in /etc/passwd or /etc/shadow style we
4746 * want to remove ":.*$" and Crypt and MD5 hashed dont have a colon
4747 */
4748
4749 if ((NULL != (colonindex = strchr(ht_passwd, ':'))) && (dtype != Digest_Cleartext))
4750 *colonindex = '\0';
4751
4752 ht_username = Str_dup(buf);
4753
4754 if (username == NULL) {
4755 if (addcredentials(ht_username, ht_passwd, dtype, false))
4756 credentials_added++;
4757 } else if (Str_cmp(username, ht_username) == 0) {
4758 if (addcredentials(ht_username, ht_passwd, dtype, false))
4759 credentials_added++;
4760 } else {
4761 FREE(ht_passwd);
4762 FREE(ht_username);
4763 }
4764 }
4765
4766 if (credentials_added == 0) {
4767 if (username == NULL)
4768 yywarning2("htpasswd file (%s) has no usable credentials", filename);
4769 else
4770 yywarning2("htpasswd file (%s) has no usable credentials for user %s", filename, username);
4771 }
4772 fclose(handle);
4773 }
4774
4775
4776 #ifdef HAVE_LIBPAM
addpamauth(char * groupname,int readonly)4777 static void addpamauth(char* groupname, int readonly) {
4778 Auth_T prev = NULL;
4779
4780 ASSERT(groupname);
4781
4782 if (! Run.httpd.credentials)
4783 NEW(Run.httpd.credentials);
4784
4785 Auth_T c = Run.httpd.credentials;
4786 do {
4787 if (c->groupname != NULL && IS(c->groupname, groupname)) {
4788 yywarning2("PAM group %s was added already, entry ignored", groupname);
4789 FREE(groupname);
4790 return;
4791 }
4792 prev = c;
4793 c = c->next;
4794 } while (c != NULL);
4795
4796 NEW(prev->next);
4797 c = prev->next;
4798
4799 c->next = NULL;
4800 c->uname = NULL;
4801 c->passwd = NULL;
4802 c->groupname = groupname;
4803 c->digesttype = Digest_Pam;
4804 c->is_readonly = readonly;
4805
4806 DEBUG("Adding PAM group '%s'\n", groupname);
4807
4808 return;
4809 }
4810 #endif
4811
4812
4813 /*
4814 * Add Basic Authentication credentials
4815 */
addcredentials(char * uname,char * passwd,Digest_Type dtype,bool readonly)4816 static bool addcredentials(char *uname, char *passwd, Digest_Type dtype, bool readonly) {
4817 Auth_T c;
4818
4819 ASSERT(uname);
4820 ASSERT(passwd);
4821
4822 if (strlen(passwd) > Str_compareConstantTimeStringLength) {
4823 yyerror2("Password for user %s is too long, maximum %d allowed", uname, Str_compareConstantTimeStringLength);
4824 FREE(uname);
4825 FREE(passwd);
4826 return false;
4827 }
4828
4829 if (! Run.httpd.credentials) {
4830 NEW(Run.httpd.credentials);
4831 c = Run.httpd.credentials;
4832 } else {
4833 if (Util_getUserCredentials(uname) != NULL) {
4834 yywarning2("Credentials for user %s were already added, entry ignored", uname);
4835 FREE(uname);
4836 FREE(passwd);
4837 return false;
4838 }
4839 c = Run.httpd.credentials;
4840 while (c->next != NULL)
4841 c = c->next;
4842 NEW(c->next);
4843 c = c->next;
4844 }
4845
4846 c->next = NULL;
4847 c->uname = uname;
4848 c->passwd = passwd;
4849 c->groupname = NULL;
4850 c->digesttype = dtype;
4851 c->is_readonly = readonly;
4852
4853 DEBUG("Adding credentials for user '%s'\n", uname);
4854
4855 return true;
4856
4857 }
4858
4859
4860 /*
4861 * Set the syslog and the facilities to be used
4862 */
setsyslog(char * facility)4863 static void setsyslog(char *facility) {
4864
4865 if (! Run.files.log || ihp.logfile) {
4866 ihp.logfile = true;
4867 setlogfile(Str_dup("syslog"));
4868 Run.flags |= Run_UseSyslog;
4869 Run.flags |= Run_Log;
4870 }
4871
4872 if (facility) {
4873 if (IS(facility,"log_local0"))
4874 Run.facility = LOG_LOCAL0;
4875 else if (IS(facility, "log_local1"))
4876 Run.facility = LOG_LOCAL1;
4877 else if (IS(facility, "log_local2"))
4878 Run.facility = LOG_LOCAL2;
4879 else if (IS(facility, "log_local3"))
4880 Run.facility = LOG_LOCAL3;
4881 else if (IS(facility, "log_local4"))
4882 Run.facility = LOG_LOCAL4;
4883 else if (IS(facility, "log_local5"))
4884 Run.facility = LOG_LOCAL5;
4885 else if (IS(facility, "log_local6"))
4886 Run.facility = LOG_LOCAL6;
4887 else if (IS(facility, "log_local7"))
4888 Run.facility = LOG_LOCAL7;
4889 else if (IS(facility, "log_daemon"))
4890 Run.facility = LOG_DAEMON;
4891 else
4892 yyerror2("Invalid syslog facility");
4893 } else {
4894 Run.facility = LOG_USER;
4895 }
4896
4897 }
4898
4899
4900 /*
4901 * Reset the current sslset for reuse
4902 */
reset_sslset()4903 static void reset_sslset() {
4904 memset(&sslset, 0, sizeof(struct SslOptions_T));
4905 sslset.version = sslset.verify = sslset.allowSelfSigned = -1;
4906 }
4907
4908
4909 /*
4910 * Reset the current mailset for reuse
4911 */
reset_mailset()4912 static void reset_mailset() {
4913 memset(&mailset, 0, sizeof(struct Mail_T));
4914 }
4915
4916
4917 /*
4918 * Reset the mailserver set to default values
4919 */
reset_mailserverset()4920 static void reset_mailserverset() {
4921 memset(&mailserverset, 0, sizeof(struct MailServer_T));
4922 mailserverset.port = PORT_SMTP;
4923 }
4924
4925
4926 /*
4927 * Reset the mmonit set to default values
4928 */
reset_mmonitset()4929 static void reset_mmonitset() {
4930 memset(&mmonitset, 0, sizeof(struct Mmonit_T));
4931 mmonitset.timeout = Run.limits.networkTimeout;
4932 }
4933
4934
4935 /*
4936 * Reset the Port set to default values
4937 */
reset_portset()4938 static void reset_portset() {
4939 memset(&portset, 0, sizeof(struct Port_T));
4940 portset.check_invers = false;
4941 portset.socket = -1;
4942 portset.type = Socket_Tcp;
4943 portset.family = Socket_Ip;
4944 portset.timeout = Run.limits.networkTimeout;
4945 portset.retry = 1;
4946 portset.protocol = Protocol_get(Protocol_DEFAULT);
4947 urlrequest = NULL;
4948 }
4949
4950
4951 /*
4952 * Reset the Proc set to default values
4953 */
reset_resourceset()4954 static void reset_resourceset() {
4955 resourceset.resource_id = 0;
4956 resourceset.limit = 0;
4957 resourceset.action = NULL;
4958 resourceset.operator = Operator_Equal;
4959 }
4960
4961
4962 /*
4963 * Reset the Timestamp set to default values
4964 */
reset_timestampset()4965 static void reset_timestampset() {
4966 timestampset.type = Timestamp_Default;
4967 timestampset.operator = Operator_Equal;
4968 timestampset.time = 0;
4969 timestampset.test_changes = false;
4970 timestampset.initialized = false;
4971 timestampset.action = NULL;
4972 }
4973
4974
4975 /*
4976 * Reset the ActionRate set to default values
4977 */
reset_actionrateset()4978 static void reset_actionrateset() {
4979 actionrateset.count = 0;
4980 actionrateset.cycle = 0;
4981 actionrateset.action = NULL;
4982 }
4983
4984
4985 /*
4986 * Reset the Size set to default values
4987 */
reset_sizeset()4988 static void reset_sizeset() {
4989 sizeset.operator = Operator_Equal;
4990 sizeset.size = 0;
4991 sizeset.test_changes = false;
4992 sizeset.action = NULL;
4993 }
4994
4995
4996 /*
4997 * Reset the Uptime set to default values
4998 */
reset_uptimeset()4999 static void reset_uptimeset() {
5000 uptimeset.operator = Operator_Equal;
5001 uptimeset.uptime = 0;
5002 uptimeset.action = NULL;
5003 }
5004
5005
reset_responsetimeset()5006 static void reset_responsetimeset() {
5007 responsetimeset.operator = Operator_Less;
5008 responsetimeset.current = 0.;
5009 responsetimeset.limit = -1.;
5010 }
5011
5012
reset_linkstatusset()5013 static void reset_linkstatusset() {
5014 linkstatusset.check_invers = false;
5015 linkstatusset.action = NULL;
5016 }
5017
5018
reset_linkspeedset()5019 static void reset_linkspeedset() {
5020 linkspeedset.action = NULL;
5021 }
5022
5023
reset_linksaturationset()5024 static void reset_linksaturationset() {
5025 linksaturationset.limit = 0.;
5026 linksaturationset.operator = Operator_Equal;
5027 linksaturationset.action = NULL;
5028 }
5029
5030
5031 /*
5032 * Reset the Bandwidth set to default values
5033 */
reset_bandwidthset()5034 static void reset_bandwidthset() {
5035 bandwidthset.operator = Operator_Equal;
5036 bandwidthset.limit = 0ULL;
5037 bandwidthset.action = NULL;
5038 }
5039
5040
5041 /*
5042 * Reset the Pid set to default values
5043 */
reset_pidset()5044 static void reset_pidset() {
5045 pidset.action = NULL;
5046 }
5047
5048
5049 /*
5050 * Reset the PPid set to default values
5051 */
reset_ppidset()5052 static void reset_ppidset() {
5053 ppidset.action = NULL;
5054 }
5055
5056
5057 /*
5058 * Reset the Fsflag set to default values
5059 */
reset_fsflagset()5060 static void reset_fsflagset() {
5061 fsflagset.action = NULL;
5062 }
5063
5064
5065 /*
5066 * Reset the Nonexist set to default values
5067 */
reset_nonexistset()5068 static void reset_nonexistset() {
5069 nonexistset.action = NULL;
5070 }
5071
5072
reset_existset()5073 static void reset_existset() {
5074 existset.action = NULL;
5075 }
5076
5077
5078 /*
5079 * Reset the Checksum set to default values
5080 */
reset_checksumset()5081 static void reset_checksumset() {
5082 checksumset.type = Hash_Unknown;
5083 checksumset.test_changes = false;
5084 checksumset.action = NULL;
5085 *checksumset.hash = 0;
5086 }
5087
5088
5089 /*
5090 * Reset the Perm set to default values
5091 */
reset_permset()5092 static void reset_permset() {
5093 permset.test_changes = false;
5094 permset.perm = 0;
5095 permset.action = NULL;
5096 }
5097
5098
5099 /*
5100 * Reset the Status set to default values
5101 */
reset_statusset()5102 static void reset_statusset() {
5103 statusset.initialized = false;
5104 statusset.return_value = 0;
5105 statusset.operator = Operator_Equal;
5106 statusset.action = NULL;
5107 }
5108
5109
5110 /*
5111 * Reset the Uid set to default values
5112 */
reset_uidset()5113 static void reset_uidset() {
5114 uidset.uid = 0;
5115 uidset.action = NULL;
5116 }
5117
5118
5119 /*
5120 * Reset the Gid set to default values
5121 */
reset_gidset()5122 static void reset_gidset() {
5123 gidset.gid = 0;
5124 gidset.action = NULL;
5125 }
5126
5127
5128 /*
5129 * Reset the Filesystem set to default values
5130 */
reset_filesystemset()5131 static void reset_filesystemset() {
5132 filesystemset.resource = 0;
5133 filesystemset.operator = Operator_Equal;
5134 filesystemset.limit_absolute = -1;
5135 filesystemset.limit_percent = -1.;
5136 filesystemset.action = NULL;
5137 }
5138
5139
5140 /*
5141 * Reset the ICMP set to default values
5142 */
reset_icmpset()5143 static void reset_icmpset() {
5144 icmpset.type = ICMP_ECHO;
5145 icmpset.size = ICMP_SIZE;
5146 icmpset.count = ICMP_ATTEMPT_COUNT;
5147 icmpset.timeout = Run.limits.networkTimeout;
5148 icmpset.check_invers = false;
5149 icmpset.action = NULL;
5150 }
5151
5152
5153 /*
5154 * Reset the Rate set to default values
5155 */
reset_rateset(struct rate_t * r)5156 static void reset_rateset(struct rate_t *r) {
5157 r->count = 1;
5158 r->cycles = 1;
5159 }
5160
5161
5162 /* ---------------------------------------------------------------- Checkers */
5163
5164
5165 /*
5166 * Check for unique service name
5167 */
check_name(char * name)5168 static void check_name(char *name) {
5169 ASSERT(name);
5170
5171 if (Util_existService(name) || (current && IS(name, current->name)))
5172 yyerror2("Service name conflict, %s already defined", name);
5173 if (name && *name == '/')
5174 yyerror2("Service name '%s' must not start with '/' -- ", name);
5175 }
5176
5177
5178 /*
5179 * Permission statement semantic check
5180 */
check_perm(int perm)5181 static int check_perm(int perm) {
5182 int result;
5183 char *status;
5184 char buf[STRLEN];
5185
5186 snprintf(buf, STRLEN, "%d", perm);
5187
5188 result = (int)strtol(buf, &status, 8);
5189
5190 if (*status != '\0' || result < 0 || result > 07777)
5191 yyerror2("Permission statements must have an octal value between 0 and 7777");
5192
5193 return result;
5194 }
5195
5196
5197 /*
5198 * Check the dependency graph for errors
5199 * by doing a topological sort, thereby finding any cycles.
5200 * Assures that graph is a Directed Acyclic Graph (DAG).
5201 */
check_depend()5202 static void check_depend() {
5203 Service_T depends_on = NULL;
5204 Service_T* dlt = &depend_list; /* the current tail of it */
5205 bool done; /* no unvisited nodes left? */
5206 bool found_some; /* last iteration found anything new ? */
5207 depend_list = NULL; /* depend_list will be the topological sorted servicelist */
5208
5209 do {
5210 done = true;
5211 found_some = false;
5212 for (Service_T s = servicelist; s; s = s->next) {
5213 Dependant_T d;
5214 if (s->visited)
5215 continue;
5216 done = false; // still unvisited nodes
5217 depends_on = NULL;
5218 for (d = s->dependantlist; d; d = d->next) {
5219 Service_T dp = Util_getService(d->dependant);
5220 if (! dp) {
5221 Log_error("Depending service '%s' is not defined in the control file\n", d->dependant);
5222 exit(1);
5223 }
5224 if (! dp->visited) {
5225 depends_on = dp;
5226 }
5227 }
5228
5229 if (! depends_on) {
5230 s->visited = true;
5231 found_some = true;
5232 *dlt = s;
5233 dlt = &s->next_depend;
5234 }
5235 }
5236 } while (found_some && ! done);
5237
5238 if (! done) {
5239 ASSERT(depends_on);
5240 Log_error("Found a depend loop in the control file involving the service '%s'\n", depends_on->name);
5241 exit(1);
5242 }
5243
5244 ASSERT(depend_list);
5245 servicelist = depend_list;
5246
5247 for (Service_T s = depend_list; s; s = s->next_depend)
5248 s->next = s->next_depend;
5249 }
5250
5251
5252 // Check and warn if the executable does not exist
check_exec(char * exec)5253 static void check_exec(char *exec) {
5254 if (! File_exist(exec))
5255 yywarning2("Program does not exist:");
5256 else if (! File_isExecutable(exec))
5257 yywarning2("Program is not executable:");
5258 }
5259
5260
5261 /* Return a valid max forward value for SIP header */
verifyMaxForward(int mf)5262 static int verifyMaxForward(int mf) {
5263 if (mf == 0) {
5264 return INT_MAX; // Differentiate uninitialized (0) and explicit zero
5265 } else if (mf > 0 && mf <= 255) {
5266 return mf;
5267 }
5268 yywarning2("SIP max forward is outside the range [0..255]. Setting max forward to 70");
5269 return 70;
5270 }
5271
5272
5273 /* -------------------------------------------------------------------- Misc */
5274
5275
5276 /*
5277 * Cleans up a hash string, tolower and remove byte separators
5278 */
cleanup_hash_string(char * hashstring)5279 static int cleanup_hash_string(char *hashstring) {
5280 int i = 0, j = 0;
5281
5282 ASSERT(hashstring);
5283
5284 while (hashstring[i]) {
5285 if (isxdigit((int)hashstring[i])) {
5286 hashstring[j] = tolower((int)hashstring[i]);
5287 j++;
5288 }
5289 i++;
5290 }
5291 hashstring[j] = 0;
5292 return j;
5293 }
5294
5295
5296 /* Return deep copy of the command */
copycommand(command_t source)5297 static command_t copycommand(command_t source) {
5298 int i;
5299 command_t copy = NULL;
5300
5301 NEW(copy);
5302 copy->length = source->length;
5303 copy->has_uid = source->has_uid;
5304 copy->uid = source->uid;
5305 copy->has_gid = source->has_gid;
5306 copy->gid = source->gid;
5307 copy->timeout = source->timeout;
5308 for (i = 0; i < copy->length; i++)
5309 copy->arg[i] = Str_dup(source->arg[i]);
5310 copy->arg[copy->length] = NULL;
5311
5312 return copy;
5313 }
5314
5315
_setPEM(char ** store,char * path,const char * description,bool isFile)5316 static void _setPEM(char **store, char *path, const char *description, bool isFile) {
5317 if (*store) {
5318 yyerror2("Duplicate %s", description);
5319 FREE(path);
5320 } else if (! File_exist(path)) {
5321 yyerror2("%s doesn't exist", description);
5322 FREE(path);
5323 } else if (! (isFile ? File_isFile(path) : File_isDirectory(path))) {
5324 yyerror2("%s is not a %s", description, isFile ? "file" : "directory");
5325 FREE(path);
5326 } else if (! File_isReadable(path)) {
5327 yyerror2("Cannot read %s", description);
5328 FREE(path);
5329 } else {
5330 sslset.flags = SSL_Enabled;
5331 *store = path;
5332 }
5333 }
5334
5335
_setSSLOptions(SslOptions_T options)5336 static void _setSSLOptions(SslOptions_T options) {
5337 options->allowSelfSigned = sslset.allowSelfSigned;
5338 options->CACertificateFile = sslset.CACertificateFile;
5339 options->CACertificatePath = sslset.CACertificatePath;
5340 options->checksum = sslset.checksum;
5341 options->checksumType = sslset.checksumType;
5342 options->ciphers = sslset.ciphers;
5343 options->clientpemfile = sslset.clientpemfile;
5344 options->flags = sslset.flags;
5345 options->pemfile = sslset.pemfile;
5346 options->pemchain = sslset.pemchain;
5347 options->pemkey = sslset.pemkey;
5348 options->verify = sslset.verify;
5349 options->version = sslset.version;
5350 reset_sslset();
5351 }
5352
5353
5354 #ifdef HAVE_OPENSSL
_setSSLVersion(short version)5355 static void _setSSLVersion(short version) {
5356 sslset.flags = SSL_Enabled;
5357 if (sslset.version == -1)
5358 sslset.version = version;
5359 else
5360 sslset.version |= version;
5361 }
5362 #endif
5363
5364
_unsetSSLVersion(short version)5365 static void _unsetSSLVersion(short version) {
5366 if (sslset.version != -1)
5367 sslset.version &= ~version;
5368 }
5369
5370
addsecurityattribute(char * value,Action_Type failed,Action_Type succeeded)5371 static void addsecurityattribute(char *value, Action_Type failed, Action_Type succeeded) {
5372 SecurityAttribute_T attr;
5373 NEW(attr);
5374 addeventaction(&(attr->action), failed, succeeded);
5375 attr->attribute = value;
5376 attr->next = current->secattrlist;
5377 current->secattrlist = attr;
5378 }
5379
5380
addfiledescriptors(Operator_Type operator,bool total,long long value_absolute,float value_percent,Action_Type failed,Action_Type succeeded)5381 static void addfiledescriptors(Operator_Type operator, bool total, long long value_absolute, float value_percent, Action_Type failed, Action_Type succeeded) {
5382 Filedescriptors_T fds;
5383 NEW(fds);
5384 addeventaction(&(fds->action), failed, succeeded);
5385 fds->total = total;
5386 fds->limit_absolute = value_absolute;
5387 fds->limit_percent = value_percent;
5388 fds->operator = operator;
5389 fds->next = current->filedescriptorslist;
5390 current->filedescriptorslist = fds;
5391 }
5392
_sanityCheckEveryStatement(Service_T s)5393 static void _sanityCheckEveryStatement(Service_T s) {
5394 if (s->every.type != Every_Initializing) {
5395 yywarning2("The 'every' statement can be specified only once, the last value will be used\n");
5396 switch (s->every.type) {
5397 case Every_Cron:
5398 case Every_NotInCron:
5399 FREE(s->every.spec.cron);
5400 break;
5401 default:
5402 break;
5403 }
5404 }
5405 }
5406
5407