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, &current->maillist);
2186                   }
2187                 | alertmail '{' eventoptionlist '}' formatlist reminder {
2188                         addmail($<string>1, &mailset, &current->maillist);
2189                   }
2190                 | alertmail NOT '{' eventoptionlist '}' formatlist reminder {
2191                         mailset.events = ~mailset.events;
2192                         addmail($<string>1, &mailset, &current->maillist);
2193                   }
2194                 | noalertmail {
2195                         addmail($<string>1, &mailset, &current->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(&timestampset);
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(&timestampset);
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(&current->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 ? &current->matchignorelist : &current->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