[PATCH] NRPE: regular expression checks for command arguments

Bjoern Beutel bjoern-beutel at arcor.de
Fri Mar 21 19:04:31 CET 2008


Hi everybody!

The following patch for the NRPE agent adds a regular expression check facility 
for command arguments, using POSIX' extended regular expressions via regcomp()/regexec().
This makes NRPE a little bit safer for uses where command arguments are needed.

Example:

I have the following command definitions in "nrpe.cfg":

  command[check_echo1]=/bin/echo $ARG1=start|stop$
  command[check_echo2]=/bin/echo $ARG1=[A-Za-z]+$

So the format of a macro is "$ARG<x>=<re>$", where "=<re>" is optional.

NRPE will match the command line arguments against "^(<re>)$",
and reject the arguments that don't match:

bjoern at james:~$ check_nrpe -H localhost -c check_echo1 -a start
start
bjoern at james:~$ check_nrpe -H localhost -c check_echo1 -a stop
stop
bjoern at james:~$ check_nrpe -H localhost -c check_echo1 -a reload
NRPE: Malformed macro in command 'check_echo1'
bjoern at james:~$ check_nrpe -H localhost -c check_echo2 -a something
something
bjoern at james:~$ check_nrpe -H localhost -c check_echo2 -a "something dangerous"
NRPE: Malformed macro in command 'check_echo2'

Regards,
Bjoern Beutel

------------------------------ snip ------------------------------------------

diff -rU 3 nrpe-2.12/configure.in nrpe-regexp/configure.in
--- nrpe-2.12/configure.in      2008-03-10 22:04:41.000000000 +0100
+++ nrpe-regexp/configure.in    2008-03-21 18:52:24.000000000 +0100
@@ -28,7 +28,7 @@
 AC_HEADER_STDC
 AC_HEADER_TIME
 AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS(ctype.h dirent.h errno.h fcntl.h getopt.h grp.h inttypes.h netdb.h pwd.h signal.h stdint.h strings.h string.h syslog.h tcpd.h unistd.h arpa/inet.h netinet/in.h socket.h sys/types.h sys/time.h sys/resource.h sys/wait.h sys/socket.h sys/stat.h)
+AC_CHECK_HEADERS(ctype.h dirent.h errno.h fcntl.h getopt.h grp.h inttypes.h netdb.h pwd.h signal.h stdint.h strings.h string.h syslog.h tcpd.h unistd.h arpa/inet.h netinet/in.h socket.h sys/types.h sys/time.h sys/resource.h sys/wait.h sys/socket.h sys/stat.h regex.h)

 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
diff -rU 3 nrpe-2.12/include/config.h.in nrpe-regexp/include/config.h.in
--- nrpe-2.12/include/config.h.in       2007-11-23 18:31:23.000000000 +0100
+++ nrpe-regexp/include/config.h.in     2008-03-21 18:50:26.000000000 +0100
@@ -243,6 +243,11 @@
 #include <rand.h>
 #endif

+#undef HAVE_REGEX_H
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+
 #undef HAVE_KRB5_H
 #ifdef HAVE_KRB5_H
 #include <krb5.h>

diff -rU 3 nrpe-2.12/src/nrpe.c nrpe-regexp/src/nrpe.c
--- nrpe-2.12/src/nrpe.c        2008-03-10 22:04:43.000000000 +0100
+++ nrpe-regexp/src/nrpe.c      2008-03-21 18:27:38.000000000 +0100
@@ -1199,38 +1199,44 @@
                        else
                                snprintf(raw_command,sizeof(raw_command)-1,"%s %s",command_prefix,temp_command->command_line);
                        raw_command[sizeof(raw_command)-1]='\x0';
-                       process_macros(raw_command,processed_command,sizeof(processed_command));
-
-                       /* log info to syslog facility */
-                       if(debug==TRUE)
-                               syslog(LOG_DEBUG,"Running command: %s",processed_command);
-
-                       /* run the command */
-                       strcpy(buffer,"");
-                       result=my_system(processed_command,command_timeout,&early_timeout,buffer,sizeof(buffer));
-
-                       /* log debug info */
-                       if(debug==TRUE)
-                               syslog(LOG_DEBUG,"Command completed with return code %d and output: %s",result,buffer);
-
-                       /* see if the command timed out */
-                       if(early_timeout==TRUE)
-                               snprintf(buffer,sizeof(buffer)-1,"NRPE: Command timed out after %d seconds\n",command_timeout);
-                       else if(!strcmp(buffer,""))
-                               snprintf(buffer,sizeof(buffer)-1,"NRPE: Unable to read output\n");
-
-                       buffer[sizeof(buffer)-1]='\x0';
-
-                       /* check return code bounds */
-                       if((result<0) || (result>3)){
+                       if (process_macros(raw_command,processed_command,sizeof(processed_command) == ERROR)){
+                               snprintf(buffer,sizeof(buffer), "NRPE: Malformed macro in command '%s'",command_name);

                                /* log error to syslog facility */
-                               syslog(LOG_ERR,"Bad return code for [%s]: %d", buffer,result);
-
-                               result=STATE_UNKNOWN;
-                               }
+                               if (debug==TRUE)
+                                       syslog(LOG_DEBUG,"%s",buffer);
+                               result=STATE_CRITICAL;
+                       } else {
+                               /* log info to syslog facility */
+                               if(debug==TRUE)
+                                       syslog(LOG_DEBUG,"Running command: %s",processed_command);
+
+                               /* run the command */
+                               strcpy(buffer,"");
+                               result=my_system(processed_command,command_timeout,&early_timeout,buffer,sizeof(buffer));
+
+                               /* log debug info */
+                               if(debug==TRUE)
+                                       syslog(LOG_DEBUG,"Command completed with return code %d and output: %s",result,buffer);
+
+                               /* see if the command timed out */
+                               if(early_timeout==TRUE)
+                                       snprintf(buffer,sizeof(buffer)-1,"NRPE: Command timed out after %d seconds\n",command_timeout);
+                               else if(!strcmp(buffer,""))
+                                       snprintf(buffer,sizeof(buffer)-1,"NRPE: Unable to read output\n");
+
+                               buffer[sizeof(buffer)-1]='\x0';
+
+                               /* check return code bounds */
+                               if((result<0) || (result>3)){
+                                       /* log error to syslog facility */
+                                       syslog(LOG_ERR,"Bad return code for [%s]: %d", buffer,result);
+
+                                       result=STATE_UNKNOWN;
+                               }
                        }
-               }
+               }
+       }

        /* free memory */
        free(command_name);
@@ -1856,9 +1862,31 @@
                                /* argument macro */
                                if(strstr(temp_buffer,"ARG")==temp_buffer){
                                        arg_index=atoi(temp_buffer+3);
-                                       if(arg_index>=1 && arg_index<=MAX_COMMAND_ARGUMENTS)
+                                       if(arg_index>=1 && arg_index<=MAX_COMMAND_ARGUMENTS){
+                                               char re_buffer[MAX_INPUT_BUFFER];
+                                               regex_t regexp;
+                                               char *s;
+
                                                selected_macro=macro_argv[arg_index-1];
-                                       }
+
+                                               /* For an $ARGx=<regexp>$ macro, check whether argument matches. */
+                                               for (s=temp_buffer+3;isdigit(*s);s++);
+                                               if (*s=='='){
+
+                                                       snprintf(re_buffer, MAX_INPUT_BUFFER, "^(%s)$", ++s);
+                                                       if (regcomp(&regexp,re_buffer,REG_EXTENDED|REG_NOSUB|REG_NEWLINE)){
+                                                               regfree(&regexp);
+                                                               return ERROR;
+                                                       }
+                                                       if (regexec(&regexp,selected_macro,0,NULL,0)){
+                                                               regfree(&regexp);
+                                                               return ERROR;
+                                                       }
+                                                       regfree(&regexp);
+                                               } else if (*s!='\0')
+                                                       return ERROR;
+                                       }
+                               }

                                /* an escaped $ is done by specifying two $$ next to each other */
                                else if(!strcmp(temp_buffer,"")){

--------------------------- snip -------------------------------------

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/




More information about the Developers mailing list