Back to index

nagios-nrpe  2.13
Defines | Functions | Variables
nrpe.c File Reference
#include "../include/common.h"
#include "../include/config.h"
#include "../include/nrpe.h"
#include "../include/utils.h"
#include "../include/acl.h"

Go to the source code of this file.

Defines

#define DEFAULT_COMMAND_TIMEOUT   60 /* default timeout for execution of plugins */
#define MAXFD   64
#define NASTY_METACHARS   "|`&><'\"\\[]{};"

Functions

int main (int argc, char **argv)
int read_config_file (char *filename)
int read_config_dir (char *dirname)
int get_log_facility (char *varvalue)
int add_command (char *command_name, char *command_line)
commandfind_command (char *command_name)
void wait_for_connections (void)
void handle_connection (int sock)
void free_memory (void)
int my_system (char *command, int timeout, int *early_timeout, char *output, int output_length)
void my_system_sighandler (int sig)
void my_connection_sighandler (int sig)
int drop_privileges (char *user, char *group)
int write_pid_file (void)
int remove_pid_file (void)
int check_privileges (void)
void sighandler (int sig)
void child_sighandler (int sig)
int validate_request (packet *pkt)
int contains_nasty_metachars (char *str)
int process_macros (char *input_buffer, char *output_buffer, int buffer_length)
int process_arguments (int argc, char **argv)

Variables

int use_ssl = FALSE
char * command_name = NULL
char * macro_argv [MAX_COMMAND_ARGUMENTS]
char config_file [MAX_INPUT_BUFFER] = "nrpe.cfg"
int log_facility = LOG_DAEMON
int server_port = DEFAULT_SERVER_PORT
char server_address [16] = "0.0.0.0"
int socket_timeout = DEFAULT_SOCKET_TIMEOUT
int command_timeout = DEFAULT_COMMAND_TIMEOUT
int connection_timeout = DEFAULT_CONNECTION_TIMEOUT
char * command_prefix = NULL
commandcommand_list = NULL
char * nrpe_user = NULL
char * nrpe_group = NULL
char * allowed_hosts = NULL
char * pid_file = NULL
int wrote_pid_file = FALSE
int allow_arguments = FALSE
int allow_weak_random_seed = FALSE
int sigrestart = FALSE
int sigshutdown = FALSE
int show_help = FALSE
int show_license = FALSE
int show_version = FALSE
int use_inetd = TRUE
int debug = FALSE

Define Documentation

#define DEFAULT_COMMAND_TIMEOUT   60 /* default timeout for execution of plugins */

Definition at line 50 of file nrpe.c.

#define MAXFD   64

Definition at line 51 of file nrpe.c.

#define NASTY_METACHARS   "|`&><'\"\\[]{};"

Definition at line 52 of file nrpe.c.


Function Documentation

int add_command ( char *  command_name,
char *  command_line 
)

Definition at line 654 of file nrpe.c.

                                                       {
       command *new_command;

       if(command_name==NULL || command_line==NULL)
              return ERROR;

       /* allocate memory for the new command */
       new_command=(command *)malloc(sizeof(command));
       if(new_command==NULL)
              return ERROR;

       new_command->command_name=strdup(command_name);
       if(new_command->command_name==NULL){
              free(new_command);
              return ERROR;
               }
       new_command->command_line=strdup(command_line);
       if(new_command->command_line==NULL){
              free(new_command->command_name);
              free(new_command);
              return ERROR;
               }

       /* add new command to head of list in memory */
       new_command->next=command_list;
       command_list=new_command;

       if(debug==TRUE)
              syslog(LOG_DEBUG,"Added command[%s]=%s\n",command_name,command_line);

       return OK;
        }

Here is the caller graph for this function:

int check_privileges ( void  )

Definition at line 1595 of file nrpe.c.

                          {
       uid_t uid=-1;
       gid_t gid=-1;

       uid=geteuid();
       gid=getegid();

       if(uid==0 || gid==0){
              syslog(LOG_ERR,"Error: NRPE daemon cannot be run as user/group root!");
              exit(STATE_CRITICAL);
               }

       return OK;
        }

Here is the caller graph for this function:

void child_sighandler ( int  sig)

Definition at line 1650 of file nrpe.c.

                              {

       /* free all memory we allocated */
       free_memory();

       /* terminate */
       exit(0);
       
       /* so the compiler doesn't complain... */
       return;
        }

Here is the call graph for this function:

Here is the caller graph for this function:

int contains_nasty_metachars ( char *  str)

Definition at line 1759 of file nrpe.c.

                                       {
       int result;

       if(str==NULL)
              return FALSE;
       
       result=strcspn(str,NASTY_METACHARS);
       if(result!=strlen(str))
              return TRUE;

       return FALSE;
        }

Here is the caller graph for this function:

int drop_privileges ( char *  user,
char *  group 
)

Definition at line 1448 of file nrpe.c.

                                            {
       uid_t uid=-1;
       gid_t gid=-1;
       struct group *grp;
       struct passwd *pw;

       /* set effective group ID */
       if(group!=NULL){
              
              /* see if this is a group name */
              if(strspn(group,"0123456789")<strlen(group)){
                     grp=(struct group *)getgrnam(group);
                     if(grp!=NULL)
                            gid=(gid_t)(grp->gr_gid);
                     else
                            syslog(LOG_ERR,"Warning: Could not get group entry for '%s'",group);
                     endgrent();
                      }

              /* else we were passed the GID */
              else
                     gid=(gid_t)atoi(group);

              /* set effective group ID if other than current EGID */
              if(gid!=getegid()){

                     if(setgid(gid)==-1)
                            syslog(LOG_ERR,"Warning: Could not set effective GID=%d",(int)gid);
                      }
               }


       /* set effective user ID */
       if(user!=NULL){
              
              /* see if this is a user name */
              if(strspn(user,"0123456789")<strlen(user)){
                     pw=(struct passwd *)getpwnam(user);
                     if(pw!=NULL)
                            uid=(uid_t)(pw->pw_uid);
                     else
                            syslog(LOG_ERR,"Warning: Could not get passwd entry for '%s'",user);
                     endpwent();
                      }

              /* else we were passed the UID */
              else
                     uid=(uid_t)atoi(user);
                     
              /* set effective user ID if other than current EUID */
              if(uid!=geteuid()){

#ifdef HAVE_INITGROUPS
                     /* initialize supplementary groups */
                     if(initgroups(user,gid)==-1){
                            if(errno==EPERM)
                                   syslog(LOG_ERR,"Warning: Unable to change supplementary groups using initgroups()");
                            else{
                                   syslog(LOG_ERR,"Warning: Possibly root user failed dropping privileges with initgroups()");
                                   return ERROR;
                                     }
                               }
#endif

                     if(setuid(uid)==-1)
                            syslog(LOG_ERR,"Warning: Could not set effective UID=%d",(int)uid);
                      }
               }

       return OK;
        }

Here is the caller graph for this function:

command* find_command ( char *  command_name)

Definition at line 690 of file nrpe.c.

                                         {
       command *temp_command;

       for(temp_command=command_list;temp_command!=NULL;temp_command=temp_command->next)
              if(!strcmp(command_name,temp_command->command_name))
                     return temp_command;

       return NULL;
        }

Here is the caller graph for this function:

void free_memory ( void  )

Definition at line 1239 of file nrpe.c.

                      {
       command *this_command;
       command *next_command;
       
       /* free memory for the command list */
       this_command=command_list;
       while(this_command!=NULL){
              next_command=this_command->next;
              if(this_command->command_name)
                     free(this_command->command_name);
              if(this_command->command_line)
                     free(this_command->command_line);
              free(this_command);
              this_command=next_command;
               }

       command_list=NULL;

       return;
        }

Here is the caller graph for this function:

int get_log_facility ( char *  varvalue)

Definition at line 601 of file nrpe.c.

                                    {

       if(!strcmp(varvalue,"kern"))
              log_facility=LOG_KERN;
       else if(!strcmp(varvalue,"user"))
              log_facility=LOG_USER;
       else if(!strcmp(varvalue,"mail"))
              log_facility=LOG_MAIL;
       else if(!strcmp(varvalue,"daemon"))
              log_facility=LOG_DAEMON;
       else if(!strcmp(varvalue,"auth"))
              log_facility=LOG_AUTH;
       else if(!strcmp(varvalue,"syslog"))
              log_facility=LOG_SYSLOG;
       else if(!strcmp(varvalue,"lrp"))
              log_facility=LOG_LPR;
       else if(!strcmp(varvalue,"news"))
              log_facility=LOG_NEWS;
       else if(!strcmp(varvalue,"uucp"))
              log_facility=LOG_UUCP;
       else if(!strcmp(varvalue,"cron"))
              log_facility=LOG_CRON;
       else if(!strcmp(varvalue,"authpriv"))
              log_facility=LOG_AUTHPRIV;
       else if(!strcmp(varvalue,"ftp"))
              log_facility=LOG_FTP;
       else if(!strcmp(varvalue,"local0"))
              log_facility=LOG_LOCAL0;
       else if(!strcmp(varvalue,"local1"))
              log_facility=LOG_LOCAL1;
       else if(!strcmp(varvalue,"local2"))
              log_facility=LOG_LOCAL2;
       else if(!strcmp(varvalue,"local3"))
              log_facility=LOG_LOCAL3;
       else if(!strcmp(varvalue,"local4"))
              log_facility=LOG_LOCAL4;
       else if(!strcmp(varvalue,"local5"))
              log_facility=LOG_LOCAL5;
       else if(!strcmp(varvalue,"local6"))
              log_facility=LOG_LOCAL6;
       else if(!strcmp(varvalue,"local7"))
              log_facility=LOG_LOCAL7;
       else{
              log_facility=LOG_DAEMON;
              return ERROR;
              }

       return OK;
       }

Here is the caller graph for this function:

void handle_connection ( int  sock)

Definition at line 963 of file nrpe.c.

                                {
        u_int32_t calculated_crc32;
       command *temp_command;
       packet receive_packet;
       packet send_packet;
       int bytes_to_send;
       int bytes_to_recv;
       char buffer[MAX_INPUT_BUFFER];
       char raw_command[MAX_INPUT_BUFFER];
       char processed_command[MAX_INPUT_BUFFER];
       int result=STATE_OK;
       int early_timeout=FALSE;
       int rc;
       int x;
#ifdef DEBUG
       FILE *errfp;
#endif
#ifdef HAVE_SSL
       SSL *ssl=NULL;
#endif


       /* log info to syslog facility */
       if(debug==TRUE)
              syslog(LOG_DEBUG,"Handling the connection...");

#ifdef OLDSTUFF
       /* socket should be non-blocking */
       fcntl(sock,F_SETFL,O_NONBLOCK);
#endif

       /* set connection handler */
       signal(SIGALRM,my_connection_sighandler);
       alarm(connection_timeout);

#ifdef HAVE_SSL
       /* do SSL handshake */
       if(result==STATE_OK && use_ssl==TRUE){
              if((ssl=SSL_new(ctx))!=NULL){
                     SSL_set_fd(ssl,sock);

                     /* keep attempting the request if needed */
                        while(((rc=SSL_accept(ssl))!=1) && (SSL_get_error(ssl,rc)==SSL_ERROR_WANT_READ));

                     if(rc!=1){
                            syslog(LOG_ERR,"Error: Could not complete SSL handshake. %d\n",SSL_get_error(ssl,rc));
#ifdef DEBUG
                            errfp=fopen("/tmp/err.log","w");
                            ERR_print_errors_fp(errfp);
                            fclose(errfp);
#endif
                            return;
                             }
                      }
              else{
                     syslog(LOG_ERR,"Error: Could not create SSL connection structure.\n");
#ifdef DEBUG
                     errfp=fopen("/tmp/err.log","w");
                     ERR_print_errors_fp(errfp);
                     fclose(errfp);
#endif
                     return;
                      }
               }
#endif

       bytes_to_recv=sizeof(receive_packet);
       if(use_ssl==FALSE)
              rc=recvall(sock,(char *)&receive_packet,&bytes_to_recv,socket_timeout);
#ifdef HAVE_SSL
       else{
                while(((rc=SSL_read(ssl,&receive_packet,bytes_to_recv))<=0) && (SSL_get_error(ssl,rc)==SSL_ERROR_WANT_READ));
              }
#endif

       /* recv() error or client disconnect */
       if(rc<=0){

              /* log error to syslog facility */
              syslog(LOG_ERR,"Could not read request from client, bailing out...");

#ifdef HAVE_SSL
              if(ssl){
                     SSL_shutdown(ssl);
                     SSL_free(ssl);
                     syslog(LOG_INFO,"INFO: SSL Socket Shutdown.\n");
                     }
#endif

              return;
                }

       /* we couldn't read the correct amount of data, so bail out */
       else if(bytes_to_recv!=sizeof(receive_packet)){

              /* log error to syslog facility */
              syslog(LOG_ERR,"Data packet from client was too short, bailing out...");

#ifdef HAVE_SSL
              if(ssl){
                     SSL_shutdown(ssl);
                     SSL_free(ssl);
                     }
#endif

              return;
               }

#ifdef DEBUG
       fp=fopen("/tmp/packet","w");
       if(fp){
              fwrite(&receive_packet,1,sizeof(receive_packet),fp);
              fclose(fp);
               }
#endif

       /* make sure the request is valid */
       if(validate_request(&receive_packet)==ERROR){

              /* log an error */
              syslog(LOG_ERR,"Client request was invalid, bailing out...");

              /* free memory */
              free(command_name);
              command_name=NULL;
              for(x=0;x<MAX_COMMAND_ARGUMENTS;x++){
                     free(macro_argv[x]);
                     macro_argv[x]=NULL;
                       }

#ifdef HAVE_SSL
              if(ssl){
                     SSL_shutdown(ssl);
                     SSL_free(ssl);
                     }
#endif

              return;
               }

       /* log info to syslog facility */
       if(debug==TRUE)
              syslog(LOG_DEBUG,"Host is asking for command '%s' to be run...",receive_packet.buffer);

       /* disable connection alarm - a new alarm will be setup during my_system */
       alarm(0);

       /* if this is the version check command, just spew it out */
       if(!strcmp(command_name,NRPE_HELLO_COMMAND)){

              snprintf(buffer,sizeof(buffer),"NRPE v%s",PROGRAM_VERSION);
              buffer[sizeof(buffer)-1]='\x0';

              /* log info to syslog facility */
              if(debug==TRUE)
                     syslog(LOG_DEBUG,"Response: %s",buffer);

              result=STATE_OK;
               }

       /* find the command we're supposed to run */
       else{
              temp_command=find_command(command_name);
              if(temp_command==NULL){

                     snprintf(buffer,sizeof(buffer),"NRPE: Command '%s' not defined",command_name);
                     buffer[sizeof(buffer)-1]='\x0';

                     /* log error to syslog facility */
                     if(debug==TRUE)
                            syslog(LOG_DEBUG,"%s",buffer);

                     result=STATE_CRITICAL;
                       }

              else{

                     /* process command line */
                     if(command_prefix==NULL)
                            strncpy(raw_command,temp_command->command_line,sizeof(raw_command)-1);
                     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)){

                            /* log error to syslog facility */
                            syslog(LOG_ERR,"Bad return code for [%s]: %d", buffer,result);

                            result=STATE_UNKNOWN;
                             }
                      }
               }

       /* free memory */
       free(command_name);
       command_name=NULL;
       for(x=0;x<MAX_COMMAND_ARGUMENTS;x++){
              free(macro_argv[x]);
              macro_argv[x]=NULL;
               }

       /* strip newline character from end of output buffer */
       if(buffer[strlen(buffer)-1]=='\n')
              buffer[strlen(buffer)-1]='\x0';

       /* clear the response packet buffer */
       bzero(&send_packet,sizeof(send_packet));

       /* fill the packet with semi-random data */
       randomize_buffer((char *)&send_packet,sizeof(send_packet));

       /* initialize response packet data */
       send_packet.packet_version=(int16_t)htons(NRPE_PACKET_VERSION_2);
       send_packet.packet_type=(int16_t)htons(RESPONSE_PACKET);
       send_packet.result_code=(int16_t)htons(result);
       strncpy(&send_packet.buffer[0],buffer,MAX_PACKETBUFFER_LENGTH);
       send_packet.buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0';
       
       /* calculate the crc 32 value of the packet */
       send_packet.crc32_value=(u_int32_t)0L;
       calculated_crc32=calculate_crc32((char *)&send_packet,sizeof(send_packet));
       send_packet.crc32_value=(u_int32_t)htonl(calculated_crc32);


       /***** ENCRYPT RESPONSE *****/


       /* send the response back to the client */
       bytes_to_send=sizeof(send_packet);
       if(use_ssl==FALSE)
              sendall(sock,(char *)&send_packet,&bytes_to_send);
#ifdef HAVE_SSL
       else
              SSL_write(ssl,&send_packet,bytes_to_send);
#endif

#ifdef HAVE_SSL
       if(ssl){
              SSL_shutdown(ssl);
              SSL_free(ssl);
              }
#endif

       /* log info to syslog facility */
       if(debug==TRUE)
              syslog(LOG_DEBUG,"Return Code: %d, Output: %s",result,buffer);

       return;
        }

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 92 of file nrpe.c.

                               {
       int result=OK;
       int x;
       char buffer[MAX_INPUT_BUFFER];
       char *env_string=NULL;
#ifdef HAVE_SSL
       DH *dh;
       char seedfile[FILENAME_MAX];
       int i,c;
#endif

       /* set some environment variables */
       asprintf(&env_string,"NRPE_MULTILINESUPPORT=1");
       putenv(env_string);
       asprintf(&env_string,"NRPE_PROGRAMVERSION=%s",PROGRAM_VERSION);
       putenv(env_string);

       /* process command-line args */
       result=process_arguments(argc,argv);

        if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE){

              printf("\n");
              printf("NRPE - Nagios Remote Plugin Executor\n");
              printf("Copyright (c) 1999-2008 Ethan Galstad (nagios@nagios.org)\n");
              printf("Version: %s\n",PROGRAM_VERSION);
              printf("Last Modified: %s\n",MODIFICATION_DATE);
              printf("License: GPL v2 with exemptions (-l for more info)\n");
#ifdef HAVE_SSL
              printf("SSL/TLS Available: Anonymous DH Mode, OpenSSL 0.9.6 or higher required\n");
#endif
#ifdef HAVE_LIBWRAP
              printf("TCP Wrappers Available\n");
#endif
              printf("\n");
#ifdef ENABLE_COMMAND_ARGUMENTS
              printf("***************************************************************\n");
              printf("** POSSIBLE SECURITY RISK - COMMAND ARGUMENTS ARE SUPPORTED! **\n");
              printf("**      Read the NRPE SECURITY file for more information     **\n");
              printf("***************************************************************\n");
              printf("\n");
#endif
#ifndef HAVE_LIBWRAP
              printf("***************************************************************\n");
              printf("** POSSIBLE SECURITY RISK - TCP WRAPPERS ARE NOT AVAILABLE!  **\n");
              printf("**      Read the NRPE SECURITY file for more information     **\n");
              printf("***************************************************************\n");
              printf("\n");
#endif
               }

       if(show_license==TRUE)
              display_license();

       else if(result!=OK || show_help==TRUE){

              printf("Usage: nrpe [-n] -c <config_file> <mode>\n");
              printf("\n");
              printf("Options:\n");
              printf(" -n            = Do not use SSL\n");
              printf(" <config_file> = Name of config file to use\n");
              printf(" <mode>        = One of the following two operating modes:\n");  
              printf("   -i          =    Run as a service under inetd or xinetd\n");
              printf("   -d          =    Run as a standalone daemon\n");
              printf("\n");
              printf("Notes:\n");
              printf("This program is designed to process requests from the check_nrpe\n");
              printf("plugin on the host(s) running Nagios.  It can run as a service\n");
              printf("under inetd or xinetd (read the docs for info on this), or as a\n");
              printf("standalone daemon. Once a request is received from an authorized\n");
              printf("host, NRPE will execute the command/plugin (as defined in the\n");
              printf("config file) and return the plugin output and return code to the\n");
              printf("check_nrpe plugin.\n");
              printf("\n");
              }

        if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE)
              exit(STATE_UNKNOWN);


       /* open a connection to the syslog facility */
       /* facility name may be overridden later */
       get_log_facility(NRPE_LOG_FACILITY);
        openlog("nrpe",LOG_PID,log_facility); 

       /* make sure the config file uses an absolute path */
       if(config_file[0]!='/'){

              /* save the name of the config file */
              strncpy(buffer,config_file,sizeof(buffer));
              buffer[sizeof(buffer)-1]='\x0';

              /* get absolute path of current working directory */
              strcpy(config_file,"");
              getcwd(config_file,sizeof(config_file));

              /* append a forward slash */
              strncat(config_file,"/",sizeof(config_file)-2);
              config_file[sizeof(config_file)-1]='\x0';

              /* append the config file to the path */
              strncat(config_file,buffer,sizeof(config_file)-strlen(config_file)-1);
              config_file[sizeof(config_file)-1]='\x0';
               }

       /* read the config file */
       result=read_config_file(config_file);     

       /* exit if there are errors... */
       if(result==ERROR){
              syslog(LOG_ERR,"Config file '%s' contained errors, aborting...",config_file);
              return STATE_CRITICAL;
              }

        /* generate the CRC 32 table */
        generate_crc32_table();

       /* initialize macros */
       for(x=0;x<MAX_COMMAND_ARGUMENTS;x++)
              macro_argv[x]=NULL;

#ifdef HAVE_SSL
       /* initialize SSL */
       if(use_ssl==TRUE){
              SSL_library_init();
              SSLeay_add_ssl_algorithms();
              meth=SSLv23_server_method();
              SSL_load_error_strings();

              /* use week random seed if necessary */
              if(allow_weak_random_seed && (RAND_status()==0)){

                     if(RAND_file_name(seedfile,sizeof(seedfile)-1))
                            if(RAND_load_file(seedfile,-1))
                                   RAND_write_file(seedfile);

                     if(RAND_status()==0){
                            syslog(LOG_ERR,"Warning: SSL/TLS uses a weak random seed which is highly discouraged");
                            srand(time(NULL));
                            for(i=0;i<500 && RAND_status()==0;i++){
                                   for(c=0;c<sizeof(seedfile);c+=sizeof(int)){
                                          *((int *)(seedfile+c))=rand();
                                           }
                                   RAND_seed(seedfile,sizeof(seedfile));
                                   }
                            }
                     }

              if((ctx=SSL_CTX_new(meth))==NULL){
                     syslog(LOG_ERR,"Error: could not create SSL context.\n");
                     exit(STATE_CRITICAL);
                      }

              /* ADDED 01/19/2004 */
              /* use only TLSv1 protocol */
              SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);

              /* use anonymous DH ciphers */
              SSL_CTX_set_cipher_list(ctx,"ADH");
              dh=get_dh512();
              SSL_CTX_set_tmp_dh(ctx,dh);
              DH_free(dh);
              if(debug==TRUE)
                     syslog(LOG_INFO,"INFO: SSL/TLS initialized. All network traffic will be encrypted.");
               }
       else{
              if(debug==TRUE)
                     syslog(LOG_INFO,"INFO: SSL/TLS NOT initialized. Network encryption DISABLED.");
               }
#endif

       /* if we're running under inetd... */
       if(use_inetd==TRUE){

              /* make sure we're not root */
              check_privileges();

              /* redirect STDERR to /dev/null */
              close(2);
              open("/dev/null",O_WRONLY);

              /* handle the connection */
              handle_connection(0);
               }

       /* else daemonize and start listening for requests... */
       else if(fork()==0){
              
              /* we're a daemon - set up a new process group */
              setsid();

              /* close standard file descriptors */
              close(0);
              close(1);
              close(2);

              /* redirect standard descriptors to /dev/null */
              open("/dev/null",O_RDONLY);
              open("/dev/null",O_WRONLY);
              open("/dev/null",O_WRONLY);

              chdir("/");
              /*umask(0);*/

              /* handle signals */
              signal(SIGQUIT,sighandler);
              signal(SIGTERM,sighandler);
              signal(SIGHUP,sighandler);

              /* log info to syslog facility */
              syslog(LOG_NOTICE,"Starting up daemon");

              /* write pid file */
              if(write_pid_file()==ERROR)
                     return STATE_CRITICAL;
              
              /* drop privileges */
              drop_privileges(nrpe_user,nrpe_group);

              /* make sure we're not root */
              check_privileges();

              do{

                     /* reset flags */
                     sigrestart=FALSE;
                     sigshutdown=FALSE;

                     /* wait for connections */
                     wait_for_connections();

                     /* free all memory we allocated */
                     free_memory();

                     if(sigrestart==TRUE){

                            /* read the config file */
                            result=read_config_file(config_file);     

                            /* exit if there are errors... */
                            if(result==ERROR){
                                   syslog(LOG_ERR,"Config file '%s' contained errors, bailing out...",config_file);
                                   return STATE_CRITICAL;
                                    }
                             }
       
                      }while(sigrestart==TRUE && sigshutdown==FALSE);

              /* remove pid file */
              remove_pid_file();

              syslog(LOG_NOTICE,"Daemon shutdown\n");
               }

#ifdef HAVE_SSL
       if(use_ssl==TRUE)
              SSL_CTX_free(ctx);
#endif

       /* We are now running in daemon mode, or the connection handed over by inetd has
          been completed, so the parent process exits */
        return STATE_OK;
       }

Here is the call graph for this function:

void my_connection_sighandler ( int  sig)

Definition at line 1439 of file nrpe.c.

                                       {

       syslog(LOG_ERR,"Connection has taken too long to establish. Exiting...");

       exit(STATE_CRITICAL);
       }

Here is the caller graph for this function:

int my_system ( char *  command,
int  timeout,
int *  early_timeout,
char *  output,
int  output_length 
)

Definition at line 1263 of file nrpe.c.

                                                                                          {
        pid_t pid;
       int status;
       int result;
       extern int errno;
       char buffer[MAX_INPUT_BUFFER];
       int fd[2];
       FILE *fp;
       int bytes_read=0;
       time_t start_time,end_time;

       /* initialize return variables */
       if(output!=NULL)
              strcpy(output,"");
       *early_timeout=FALSE;

       /* if no command was passed, return with no error */
       if(command==NULL)
               return STATE_OK;

       /* create a pipe */
       pipe(fd);

       /* make the pipe non-blocking */
       fcntl(fd[0],F_SETFL,O_NONBLOCK);
       fcntl(fd[1],F_SETFL,O_NONBLOCK);

       /* get the command start time */
       time(&start_time);

       /* fork */
       pid=fork();

       /* return an error if we couldn't fork */
       if(pid==-1){

              snprintf(buffer,sizeof(buffer)-1,"NRPE: Call to fork() failed\n");
              buffer[sizeof(buffer)-1]='\x0';

              if(output!=NULL){
                     strncpy(output,buffer,output_length-1);
                     output[output_length-1]='\x0';
                      }

              /* close both ends of the pipe */
              close(fd[0]);
              close(fd[1]);
              
               return STATE_UNKNOWN;  
               }

       /* execute the command in the child process */
        if(pid==0){

              /* close pipe for reading */
              close(fd[0]);

              /* become process group leader */
              setpgid(0,0);

              /* trap commands that timeout */
              signal(SIGALRM,my_system_sighandler);
              alarm(timeout);

              /* run the command */
              fp=popen(command,"r");
              
              /* report an error if we couldn't run the command */
              if(fp==NULL){

                     strncpy(buffer,"NRPE: Call to popen() failed\n",sizeof(buffer)-1);
                     buffer[sizeof(buffer)-1]='\x0';

                     /* write the error back to the parent process */
                     write(fd[1],buffer,strlen(buffer)+1);

                     result=STATE_CRITICAL;
                      }
              else{

                     /* read all lines of output - supports Nagios 3.x multiline output */
                     while((bytes_read=fread(buffer,1,sizeof(buffer)-1,fp))>0){

                            /* write the output back to the parent process */
                            write(fd[1],buffer,bytes_read);
                            }

                     /* close the command and get termination status */
                     status=pclose(fp);

                     /* report an error if we couldn't close the command */
                     if(status==-1)
                            result=STATE_CRITICAL;
                     /* report an error if child died due to signal (Klas Lindfors) */
                     else if(!WIFEXITED(status))
                            result=STATE_CRITICAL;
                     else
                            result=WEXITSTATUS(status);
                      }

              /* close pipe for writing */
              close(fd[1]);

              /* reset the alarm */
              alarm(0);

              /* return plugin exit code to parent process */
              exit(result);
               }

       /* parent waits for child to finish executing command */
       else{
              
              /* close pipe for writing */
              close(fd[1]);

              /* wait for child to exit */
              waitpid(pid,&status,0);

              /* get the end time for running the command */
              time(&end_time);

              /* get the exit code returned from the program */
              result=WEXITSTATUS(status);

              /* because of my idiotic idea of having UNKNOWN states be equivalent to -1, I must hack things a bit... */
              if(result==255)
                     result=STATE_UNKNOWN;

              /* check bounds on the return value */
              if(result<0 || result>3)
                     result=STATE_UNKNOWN;

              /* try and read the results from the command output (retry if we encountered a signal) */
              if(output!=NULL){
                     do{
                            bytes_read=read(fd[0], output, output_length-1);
                     }while (bytes_read==-1 && errno==EINTR);

                     if(bytes_read==-1)
                            *output='\0';
                     else
                            output[bytes_read]='\0';
                     }

              /* if there was a critical return code and no output AND the command time exceeded the timeout thresholds, assume a timeout */
              if(result==STATE_CRITICAL && bytes_read==-1 && (end_time-start_time)>=timeout){
                     *early_timeout=TRUE;

                     /* send termination signal to child process group */
                     kill((pid_t)(-pid),SIGTERM);
                     kill((pid_t)(-pid),SIGKILL);
                      }

              /* close the pipe for reading */
              close(fd[0]);
               }

#ifdef DEBUG
       printf("my_system() end\n");
#endif

       return result;
        }

Here is the call graph for this function:

Here is the caller graph for this function:

void my_system_sighandler ( int  sig)

Definition at line 1431 of file nrpe.c.

                                  {

       /* force the child process to exit... */
       exit(STATE_CRITICAL);
        }

Here is the caller graph for this function:

int process_arguments ( int  argc,
char **  argv 
)

Definition at line 1839 of file nrpe.c.

                                            {
       char optchars[MAX_INPUT_BUFFER];
       int c=1;
       int have_mode=FALSE;

#ifdef HAVE_GETOPT_LONG
       int option_index=0;
       static struct option long_options[]={
              {"config", required_argument, 0, 'c'},
              {"inetd", no_argument, 0, 'i'},
              {"daemon", no_argument, 0, 'd'},
              {"no-ssl", no_argument, 0, 'n'},
              {"help", no_argument, 0, 'h'},
              {"license", no_argument, 0, 'l'},
              {0, 0, 0, 0}
                };
#endif

       /* no options were supplied */
       if(argc<2)
              return ERROR;

       snprintf(optchars,MAX_INPUT_BUFFER,"c:hVldin");

       while(1){
#ifdef HAVE_GETOPT_LONG
              c=getopt_long(argc,argv,optchars,long_options,&option_index);
#else
              c=getopt(argc,argv,optchars);
#endif
              if(c==-1 || c==EOF)
                     break;

              /* process all arguments */
              switch(c){

              case '?':
              case 'h':
                     show_help=TRUE;
                     break;
              case 'V':
                     show_version=TRUE;
                     break;
              case 'l':
                     show_license=TRUE;
                     break;
              case 'c':
                     strncpy(config_file,optarg,sizeof(config_file));
                     config_file[sizeof(config_file)-1]='\x0';
                     break;
              case 'd':
                     use_inetd=FALSE;
                     have_mode=TRUE;
                     break;
              case 'i':
                     use_inetd=TRUE;
                     have_mode=TRUE;
                     break;
              case 'n':
                     use_ssl=FALSE;
                     break;
              default:
                     return ERROR;
                     break;
                      }
               }

       /* bail if we didn't get required args */
       if(have_mode==FALSE)
              return ERROR;

       return OK;
        }

Here is the caller graph for this function:

int process_macros ( char *  input_buffer,
char *  output_buffer,
int  buffer_length 
)

Definition at line 1775 of file nrpe.c.

                                                                            {
       char *temp_buffer;
       int in_macro;
       int arg_index=0;
       char *selected_macro=NULL;

       strcpy(output_buffer,"");

       in_macro=FALSE;

       for(temp_buffer=my_strsep(&input_buffer,"$");temp_buffer!=NULL;temp_buffer=my_strsep(&input_buffer,"$")){

              selected_macro=NULL;

              if(in_macro==FALSE){
                     if(strlen(output_buffer)+strlen(temp_buffer)<buffer_length-1){
                            strncat(output_buffer,temp_buffer,buffer_length-strlen(output_buffer)-1);
                            output_buffer[buffer_length-1]='\x0';
                             }
                     in_macro=TRUE;
                     }
              else{

                     if(strlen(output_buffer)+strlen(temp_buffer)<buffer_length-1){

                            /* argument macro */
                            if(strstr(temp_buffer,"ARG")==temp_buffer){
                                   arg_index=atoi(temp_buffer+3);
                                   if(arg_index>=1 && arg_index<=MAX_COMMAND_ARGUMENTS)
                                          selected_macro=macro_argv[arg_index-1];
                                    }

                            /* an escaped $ is done by specifying two $$ next to each other */
                            else if(!strcmp(temp_buffer,"")){
                                   strncat(output_buffer,"$",buffer_length-strlen(output_buffer)-1);
                                    }
                            
                            /* a non-macro, just some user-defined string between two $s */
                            else{
                                   strncat(output_buffer,"$",buffer_length-strlen(output_buffer)-1);
                                   output_buffer[buffer_length-1]='\x0';
                                   strncat(output_buffer,temp_buffer,buffer_length-strlen(output_buffer)-1);
                                   output_buffer[buffer_length-1]='\x0';
                                   strncat(output_buffer,"$",buffer_length-strlen(output_buffer)-1);
                                    }

                            
                            /* insert macro */
                            if(selected_macro!=NULL)
                                   strncat(output_buffer,(selected_macro==NULL)?"":selected_macro,buffer_length-strlen(output_buffer)-1);

                            output_buffer[buffer_length-1]='\x0';
                            }

                     in_macro=FALSE;
                     }
              }

       return OK;
       }

Here is the call graph for this function:

Here is the caller graph for this function:

int read_config_dir ( char *  dirname)

Definition at line 538 of file nrpe.c.

                                  {
       char config_file[MAX_FILENAME_LENGTH];
       DIR *dirp;
       struct dirent *dirfile;
       struct stat buf;
       int result=OK;
       int x;

       /* open the directory for reading */
       dirp=opendir(dirname);
        if(dirp==NULL){
              syslog(LOG_ERR,"Could not open config directory '%s' for reading.\n",dirname);
              return ERROR;
               }

       /* process all files in the directory... */
       while((dirfile=readdir(dirp))!=NULL){

              /* create the full path to the config file or subdirectory */
              snprintf(config_file,sizeof(config_file)-1,"%s/%s",dirname,dirfile->d_name);
              config_file[sizeof(config_file)-1]='\x0';
              stat(config_file, &buf);

              /* process this if it's a config file... */
              x=strlen(dirfile->d_name);
              if(x>4 && !strcmp(dirfile->d_name+(x-4),".cfg")){

                     /* only process normal files */
                     if(!S_ISREG(buf.st_mode))
                            continue;

                     /* process the config file */
                     result=read_config_file(config_file);

                     /* break out if we encountered an error */
                     if(result==ERROR)
                            break;
                      }

              /* recurse into subdirectories... */
              if(S_ISDIR(buf.st_mode)){

                     /* ignore current, parent and hidden directory entries */
                     if(dirfile->d_name[0]=='.')
                            continue;

                     /* process the config directory */
                     result=read_config_dir(config_file);

                     /* break out if we encountered an error */
                     if(result==ERROR)
                            break;
                      }
              }

       closedir(dirp);

       return result;
        }

Here is the call graph for this function:

Here is the caller graph for this function:

int read_config_file ( char *  filename)

Definition at line 360 of file nrpe.c.

                                    {
       FILE *fp;
       char config_file[MAX_FILENAME_LENGTH];
       char input_buffer[MAX_INPUT_BUFFER];
       char *input_line;
       char *temp_buffer;
       char *varname;
       char *varvalue;
       int line=0;
       int len=0;
       int x=0;


       /* open the config file for reading */
       fp=fopen(filename,"r");

       /* exit if we couldn't open the config file */
       if(fp==NULL){
              syslog(LOG_ERR,"Unable to open config file '%s' for reading\n",filename);
              return ERROR;
               }

       while(fgets(input_buffer,MAX_INPUT_BUFFER-1,fp)){

              line++;
              input_line=input_buffer;

              /* skip leading whitespace */
              while(isspace(*input_line))
                     ++input_line;

              /* trim trailing whitespace */
              len=strlen(input_line);
              for(x=len-1;x>=0;x--){
                     if(isspace(input_line[x]))
                            input_line[x]='\x0';
                     else
                            break;
                      }

              /* skip comments and blank lines */
              if(input_line[0]=='#')
                     continue;
              if(input_line[0]=='\x0')
                     continue;
              if(input_line[0]=='\n')
                     continue;

              /* get the variable name */
              varname=strtok(input_line,"=");
              if(varname==NULL){
                     syslog(LOG_ERR,"No variable name specified in config file '%s' - Line %d\n",filename,line);
                     return ERROR;
                      }

              /* get the variable value */
              varvalue=strtok(NULL,"\n");
              if(varvalue==NULL){
                     syslog(LOG_ERR,"No variable value specified in config file '%s' - Line %d\n",filename,line);
                     return ERROR;
                      }

              /* allow users to specify directories to recurse into for config files */
              else if(!strcmp(varname,"include_dir")){

                     strncpy(config_file,varvalue,sizeof(config_file)-1);
                     config_file[sizeof(config_file)-1]='\x0';

                     /* strip trailing / if necessary */
                     if(config_file[strlen(config_file)-1]=='/')
                            config_file[strlen(config_file)-1]='\x0';

                     /* process the config directory... */
                     if(read_config_dir(config_file)==ERROR)
                            syslog(LOG_ERR,"Continuing with errors...");
                     }

              /* allow users to specify individual config files to include */
              else if(!strcmp(varname,"include") || !strcmp(varname,"include_file")){

                     /* process the config file... */
                     if(read_config_file(varvalue)==ERROR)
                            syslog(LOG_ERR,"Continuing with errors...");
                      }

              else if(!strcmp(varname,"server_port")){
                     server_port=atoi(varvalue);
                     if(server_port<1024){
                            syslog(LOG_ERR,"Invalid port number specified in config file '%s' - Line %d\n",filename,line);
                            return ERROR;
                             }
                      }
              else if(!strcmp(varname,"command_prefix"))
                     command_prefix=strdup(varvalue);

              else if(!strcmp(varname,"server_address")){
                        strncpy(server_address,varvalue,sizeof(server_address) - 1);
                        server_address[sizeof(server_address)-1]='\0';
                        }
              else if(!strcmp(varname,"allowed_hosts")) {
                            allowed_hosts=strdup(varvalue);
                            parse_allowed_hosts(allowed_hosts);
              }
              else if(strstr(input_line,"command[")){
                     temp_buffer=strtok(varname,"[");
                     temp_buffer=strtok(NULL,"]");
                     if(temp_buffer==NULL){
                            syslog(LOG_ERR,"Invalid command specified in config file '%s' - Line %d\n",filename,line);
                            return ERROR;
                             }
                     add_command(temp_buffer,varvalue);
                      }

              else if(strstr(input_buffer,"debug")){
                     debug=atoi(varvalue);
                     if(debug>0)
                            debug=TRUE;
                     else 
                            debug=FALSE;
                      }

                else if(!strcmp(varname,"nrpe_user"))
                     nrpe_user=strdup(varvalue);

                else if(!strcmp(varname,"nrpe_group"))
                     nrpe_group=strdup(varvalue);
              
              else if(!strcmp(varname,"dont_blame_nrpe"))
                     allow_arguments=(atoi(varvalue)==1)?TRUE:FALSE;

              else if(!strcmp(varname,"command_timeout")){
                     command_timeout=atoi(varvalue);
                     if(command_timeout<1){
                            syslog(LOG_ERR,"Invalid command_timeout specified in config file '%s' - Line %d\n",filename,line);
                            return ERROR;
                             }
                      }

              else if(!strcmp(varname,"connection_timeout")){
                     connection_timeout=atoi(varvalue);
                     if(connection_timeout<1){
                            syslog(LOG_ERR,"Invalid connection_timeout specified in config file '%s' - Line %d\n",filename,line);
                            return ERROR;
                             }
                      }

              else if(!strcmp(varname,"allow_weak_random_seed"))
                     allow_weak_random_seed=(atoi(varvalue)==1)?TRUE:FALSE;

              else if(!strcmp(varname,"pid_file"))
                     pid_file=strdup(varvalue);

              else if(!strcmp(varname,"log_facility")){
                     if((get_log_facility(varvalue))==OK){
                            /* re-open log using new facility */
                            closelog();
                            openlog("nrpe",LOG_PID,log_facility); 
                            }
                     else
                            syslog(LOG_WARNING,"Invalid log_facility specified in config file '%s' - Line %d\n",filename,line);
                     }

              else{
                     syslog(LOG_WARNING,"Unknown option specified in config file '%s' - Line %d\n",filename,line);
                     continue;
                      }

               }


       /* close the config file */
       fclose(fp);

       return OK;
       }

Here is the call graph for this function:

Here is the caller graph for this function:

int remove_pid_file ( void  )

Definition at line 1573 of file nrpe.c.

                         {

       /* no pid file was specified */
       if(pid_file==NULL)
              return OK;

       /* pid file was not written */
       if(wrote_pid_file==FALSE)
              return OK;

       /* remove existing pid file */
       if(unlink(pid_file)==-1){
              syslog(LOG_ERR,"Cannot remove pidfile '%s' - check your privileges.",pid_file);
              return ERROR;
               }

       return OK;
        }

Here is the caller graph for this function:

void sighandler ( int  sig)

Definition at line 1613 of file nrpe.c.

                        {
       static char *sigs[]={"EXIT","HUP","INT","QUIT","ILL","TRAP","ABRT","BUS","FPE","KILL","USR1","SEGV","USR2","PIPE","ALRM","TERM","STKFLT","CHLD","CONT","STOP","TSTP","TTIN","TTOU","URG","XCPU","XFSZ","VTALRM","PROF","WINCH","IO","PWR","UNUSED","ZERR","DEBUG",(char *)NULL};
       int i;

       if(sig<0)
              sig=-sig;

       for(i=0;sigs[i]!=(char *)NULL;i++);

       sig%=i;

       /* we received a SIGHUP, so restart... */
       if(sig==SIGHUP){

              sigrestart=TRUE;

              syslog(LOG_NOTICE,"Caught SIGHUP - restarting...\n");
               }

       /* else begin shutting down... */
       if(sig==SIGTERM){

              /* if shutdown is already true, we're in a signal trap loop! */
              if(sigshutdown==TRUE)
                     exit(STATE_CRITICAL);

              sigshutdown=TRUE;

              syslog(LOG_NOTICE,"Caught SIG%s - shutting down...\n",sigs[sig]);
               }

       return;
        }

Here is the caller graph for this function:

int validate_request ( packet pkt)

Definition at line 1665 of file nrpe.c.

                                 {
        u_int32_t packet_crc32;
        u_int32_t calculated_crc32;
       char *ptr;
#ifdef ENABLE_COMMAND_ARGUMENTS
       int x;
#endif


       /***** DECRYPT REQUEST ******/


        /* check the crc 32 value */
        packet_crc32=ntohl(pkt->crc32_value);
        pkt->crc32_value=0L;
        calculated_crc32=calculate_crc32((char *)pkt,sizeof(packet));
        if(packet_crc32!=calculated_crc32){
                syslog(LOG_ERR,"Error: Request packet had invalid CRC32.");
                return ERROR;
                }

       /* make sure this is the right type of packet */
       if(ntohs(pkt->packet_type)!=QUERY_PACKET || ntohs(pkt->packet_version)!=NRPE_PACKET_VERSION_2){
              syslog(LOG_ERR,"Error: Request packet type/version was invalid!");
              return ERROR;
               }

       /* make sure buffer is terminated */
       pkt->buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0';

       /* client must send some kind of request */
       if(!strcmp(pkt->buffer,"")){
              syslog(LOG_ERR,"Error: Request contained no query!");
              return ERROR;
               }

       /* make sure request doesn't contain nasties */
       if(contains_nasty_metachars(pkt->buffer)==TRUE){
              syslog(LOG_ERR,"Error: Request contained illegal metachars!");
              return ERROR;
               }

       /* make sure the request doesn't contain arguments */
       if(strchr(pkt->buffer,'!')){
#ifdef ENABLE_COMMAND_ARGUMENTS
              if(allow_arguments==FALSE){
                     syslog(LOG_ERR,"Error: Request contained command arguments, but argument option is not enabled!");
                     return ERROR;
                       }
#else
              syslog(LOG_ERR,"Error: Request contained command arguments!");
              return ERROR;
#endif
               }

       /* get command name */
#ifdef ENABLE_COMMAND_ARGUMENTS
       ptr=strtok(pkt->buffer,"!");
#else
       ptr=pkt->buffer;
#endif 
       command_name=strdup(ptr);
       if(command_name==NULL){
              syslog(LOG_ERR,"Error: Memory allocation failed");
              return ERROR;
               }

#ifdef ENABLE_COMMAND_ARGUMENTS
       /* get command arguments */
       if(allow_arguments==TRUE){

              for(x=0;x<MAX_COMMAND_ARGUMENTS;x++){
                     ptr=strtok(NULL,"!");
                     if(ptr==NULL)
                            break;
                     macro_argv[x]=strdup(ptr);
                     if(macro_argv[x]==NULL){
                            syslog(LOG_ERR,"Error: Memory allocation failed");
                            return ERROR;
                             }
                     if(!strcmp(macro_argv[x],"")){
                            syslog(LOG_ERR,"Error: Request contained an empty command argument");
                            return ERROR;
                              }
                      }
               }
#endif

       return OK;
        }

Here is the call graph for this function:

Here is the caller graph for this function:

void wait_for_connections ( void  )

Definition at line 703 of file nrpe.c.

                               {
       struct sockaddr_in myname;
       struct sockaddr_in *nptr;
       struct sockaddr addr;
       int rc;
       int sock, new_sd;
       socklen_t addrlen;
       pid_t pid;
       int flag=1;
       fd_set fdread;
       struct timeval timeout;
       int retval;
#ifdef HAVE_LIBWRAP
       struct request_info req;
#endif

       /* create a socket for listening */
       sock=socket(AF_INET,SOCK_STREAM,0);

       /* exit if we couldn't create the socket */
       if(sock<0){
               syslog(LOG_ERR,"Network server socket failure (%d: %s)",errno,strerror(errno));
               exit(STATE_CRITICAL);
              }

       /* socket should be non-blocking */
       fcntl(sock,F_SETFL,O_NONBLOCK);

        /* set the reuse address flag so we don't get errors when restarting */
        flag=1;
        if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag))<0){
              syslog(LOG_ERR,"Could not set reuse address option on socket!\n");
              exit(STATE_UNKNOWN);
               }

       myname.sin_family=AF_INET;
       myname.sin_port=htons(server_port);
       bzero(&myname.sin_zero,8);

       /* what address should we bind to? */
        if(!strlen(server_address))
              myname.sin_addr.s_addr=INADDR_ANY;

       else if(!my_inet_aton(server_address,&myname.sin_addr)){
              syslog(LOG_ERR,"Server address is not a valid IP address\n");
              exit(STATE_CRITICAL);
                }

       /* bind the address to the Internet socket */
       if(bind(sock,(struct sockaddr *)&myname,sizeof(myname))<0){
              syslog(LOG_ERR,"Network server bind failure (%d: %s)\n",errno,strerror(errno));
               exit(STATE_CRITICAL);
               }

       /* open the socket for listening */
       if(listen(sock,5)<0){
              syslog(LOG_ERR,"Network server listen failure (%d: %s)\n",errno,strerror(errno));
               exit(STATE_CRITICAL);
              }

       /* log warning about command arguments */
#ifdef ENABLE_COMMAND_ARGUMENTS
       if(allow_arguments==TRUE)
              syslog(LOG_NOTICE,"Warning: Daemon is configured to accept command arguments from clients!");
#endif

       syslog(LOG_INFO,"Listening for connections on port %d\n",htons(myname.sin_port));

       if(allowed_hosts)
              syslog(LOG_INFO,"Allowing connections from: %s\n",allowed_hosts);

       /* listen for connection requests - fork() if we get one */
       while(1){

              /* wait for a connection request */
               while(1){

                     /* wait until there's something to do */
                     FD_ZERO(&fdread);
                     FD_SET(sock,&fdread);
                     timeout.tv_sec=0;
                     timeout.tv_usec=500000;
                     retval=select(sock+1,&fdread,NULL,&fdread,&timeout);

                     /* bail out if necessary */
                     if(sigrestart==TRUE || sigshutdown==TRUE)
                            break;

                     /* error */
                     if(retval<0)
                            continue;

                     /* accept a new connection request */
                     new_sd=accept(sock,0,0);

                     /* some kind of error occurred... */
                     if(new_sd<0){

                            /* bail out if necessary */
                            if(sigrestart==TRUE || sigshutdown==TRUE)
                                   break;

                            /* retry */
                            if(errno==EWOULDBLOCK || errno==EINTR)
                                   continue;

                            /* socket is nonblocking and we don't have a connection yet */
                            if(errno==EAGAIN)
                                   continue;

                            /* fix for HP-UX 11.0 - just retry */
                            if(errno==ENOBUFS)
                                   continue;

                            /* else handle the error later */
                            break;
                             }

                     /* connection was good */
                     break;
                      }

              /* bail out if necessary */
              if(sigrestart==TRUE || sigshutdown==TRUE)
                     break;

              /* child process should handle the connection */
              pid=fork();
              if(pid==0){

                     /* fork again so we don't create zombies */
                     pid=fork();
                     if(pid==0){

                            /* hey, there was an error... */
                            if(new_sd<0){

                                   /* log error to syslog facility */
                                   syslog(LOG_ERR,"Network server accept failure (%d: %s)",errno,strerror(errno));

                                   /* close socket prioer to exiting */
                                   close(sock);
                     
                                   return;
                                    }

                            /* handle signals */
                            signal(SIGQUIT,child_sighandler);
                            signal(SIGTERM,child_sighandler);
                            signal(SIGHUP,child_sighandler);

                            /* grandchild does not need to listen for connections, so close the socket */
                            close(sock);  

                            /* find out who just connected... */
                            addrlen=sizeof(addr);
                            rc=getpeername(new_sd,&addr,&addrlen);

                            if(rc<0){

                                    /* log error to syslog facility */
                                   syslog(LOG_ERR,"Error: Network server getpeername() failure (%d: %s)",errno,strerror(errno));

                                    /* close socket prior to exiting */
                                   close(new_sd);

                                   return;
                                      }

                            nptr=(struct sockaddr_in *)&addr;

                            /* log info to syslog facility */
                            if(debug==TRUE)
                                   syslog(LOG_DEBUG,"Connection from %s port %d",inet_ntoa(nptr->sin_addr),nptr->sin_port);

                            /* is this is a blessed machine? */
                            if(allowed_hosts){
                     switch(nptr->sin_family) {
                     case AF_INET:
                            if(!is_an_allowed_host(nptr->sin_addr)) {
                                   /* log error to syslog facility */
                                   syslog(LOG_ERR,"Host %s is not allowed to talk to us!",inet_ntoa(nptr->sin_addr));

                                                        /* log info to syslog facility */
                                                        if ( debug==TRUE )
                                   syslog(LOG_DEBUG,"Connection from %s closed.",inet_ntoa(nptr->sin_addr));

                                                        /* close socket prior to exiting */
                                                        close(new_sd);
                                                        exit(STATE_OK);
                                                        } else {
                                                               /* log info to syslog facility */
                                                               if(debug==TRUE)
                                                                      syslog(LOG_DEBUG,"Host address is in allowed_hosts");

                                                        }
                                                 break;
                           
                                          case AF_INET6:
                                                 syslog(LOG_DEBUG,"Connection from %s closed. We don't support AF_INET6 addreess family in ACL\n", inet_ntoa(nptr->sin_addr));
                                                 break;
                                   }
                            }

#ifdef HAVE_LIBWRAP

                            /* Check whether or not connections are allowed from this host */
                            request_init(&req,RQ_DAEMON,"nrpe",RQ_FILE,new_sd,0);
                            fromhost(&req);

                            if(!hosts_access(&req)){

                                   syslog(LOG_DEBUG,"Connection refused by TCP wrapper");

                                   /* refuse the connection */
                                   refuse(&req);
                                   close(new_sd);

                                   /* should not be reached */
                                   syslog(LOG_ERR,"libwrap refuse() returns!");
                                   exit(STATE_CRITICAL);
                                   }
#endif

                            /* handle the client connection */
                            handle_connection(new_sd);

                            /* log info to syslog facility */
                            if(debug==TRUE)
                                   syslog(LOG_DEBUG,"Connection from %s closed.",inet_ntoa(nptr->sin_addr));

                            /* close socket prior to exiting */
                            close(new_sd);

                            exit(STATE_OK);
                             }

                     /* first child returns immediately, grandchild is inherited by INIT process -> no zombies... */
                     else
                            exit(STATE_OK);
                      }
              
              /* parent ... */
              else{
                     /* parent doesn't need the new connection */
                     close(new_sd);

                     /* parent waits for first child to exit */
                     waitpid(pid,NULL,0);
                      }
              }

       /* close the socket we're listening on */
       close(sock);

       return;
       }

Here is the call graph for this function:

Here is the caller graph for this function:

int write_pid_file ( void  )

Definition at line 1522 of file nrpe.c.

                        {
       int fd;
       int result=0;
       pid_t pid=0;
       char pbuf[16];

       /* no pid file was specified */
       if(pid_file==NULL)
              return OK;

       /* read existing pid file */
       if((fd=open(pid_file,O_RDONLY))>=0){

              result=read(fd,pbuf,(sizeof pbuf)-1);

              close(fd);

              if(result>0){

                     pbuf[result]='\x0';
                     pid=(pid_t)atoi(pbuf);

                     /* if previous process is no longer running running, remove the old pid file */
                     if(pid && (pid==getpid() || kill(pid,0)<0))
                            unlink(pid_file);

                     /* previous process is still running */
                     else{
                            syslog(LOG_ERR,"There's already an NRPE server running (PID %lu).  Bailing out...",(unsigned long)pid);
                            return ERROR;
                             }
                      }
               } 

       /* write new pid file */
       if((fd=open(pid_file,O_WRONLY | O_CREAT,0644))>=0){
              sprintf(pbuf,"%d\n",(int)getpid());
              write(fd,pbuf,strlen(pbuf));
              close(fd);
              wrote_pid_file=TRUE;
               }
       else{
              syslog(LOG_ERR,"Cannot write to pidfile '%s' - check your privileges.",pid_file);
               }

       return OK;
        }

Here is the caller graph for this function:


Variable Documentation

Definition at line 76 of file nrpe.c.

Definition at line 78 of file nrpe.c.

char* allowed_hosts = NULL

Definition at line 71 of file nrpe.c.

Definition at line 66 of file nrpe.c.

char* command_name = NULL

Definition at line 54 of file nrpe.c.

char* command_prefix = NULL

Definition at line 64 of file nrpe.c.

Definition at line 62 of file nrpe.c.

char config_file[MAX_INPUT_BUFFER] = "nrpe.cfg"

Definition at line 57 of file nrpe.c.

Definition at line 63 of file nrpe.c.

int debug = FALSE

Definition at line 87 of file nrpe.c.

int log_facility = LOG_DAEMON

Definition at line 58 of file nrpe.c.

Definition at line 55 of file nrpe.c.

char* nrpe_group = NULL

Definition at line 69 of file nrpe.c.

char* nrpe_user = NULL

Definition at line 68 of file nrpe.c.

char* pid_file = NULL

Definition at line 73 of file nrpe.c.

char server_address[16] = "0.0.0.0"

Definition at line 60 of file nrpe.c.

int server_port = DEFAULT_SERVER_PORT

Definition at line 59 of file nrpe.c.

Definition at line 83 of file nrpe.c.

Definition at line 84 of file nrpe.c.

Definition at line 85 of file nrpe.c.

Definition at line 80 of file nrpe.c.

Definition at line 81 of file nrpe.c.

Definition at line 61 of file nrpe.c.

int use_inetd = TRUE

Definition at line 86 of file nrpe.c.

int use_ssl = FALSE

Definition at line 47 of file nrpe.c.

Definition at line 74 of file nrpe.c.