check_nrpe.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /********************************************************************************************
  2. *
  3. * CHECK_NRPE.C - NRPE Plugin For Nagios
  4. * Copyright (c) 1999-2003 Ethan Galstad (nagios@nagios.org)
  5. * License: GPL
  6. *
  7. * Last Modified: 04-17-2003
  8. *
  9. * Command line: CHECK_NRPE -H <host_address> [-p port] [-c command] [-to to_sec]
  10. *
  11. * Description:
  12. *
  13. * This plugin will attempt to connect to the NRPE daemon on the specified server and port.
  14. * The daemon will attempt to run the command defined as [command]. Program output and
  15. * return code are sent back from the daemon and displayed as this plugin's own output and
  16. * return code.
  17. *
  18. ********************************************************************************************/
  19. #include "../common/common.h"
  20. #include "../common/config.h"
  21. #include "utils.h"
  22. #define DEFAULT_NRPE_COMMAND "_NRPE_CHECK" /* check version of NRPE daemon */
  23. int server_port=DEFAULT_SERVER_PORT;
  24. char *server_name=NULL;
  25. char *command_name=NULL;
  26. int socket_timeout=DEFAULT_SOCKET_TIMEOUT;
  27. int sd;
  28. char query[MAX_INPUT_BUFFER]="";
  29. int show_help=FALSE;
  30. int show_license=FALSE;
  31. int show_version=FALSE;
  32. #ifdef HAVE_SSL
  33. SSL_METHOD *meth;
  34. SSL_CTX *ctx;
  35. SSL *ssl;
  36. int use_ssl=TRUE;
  37. #else
  38. int use_ssl=FALSE;
  39. #endif
  40. int process_arguments(int,char **);
  41. void alarm_handler(int);
  42. int main(int argc, char **argv){
  43. u_int32_t packet_crc32;
  44. u_int32_t calculated_crc32;
  45. int16_t result;
  46. int rc;
  47. packet send_packet;
  48. packet receive_packet;
  49. int bytes_to_send;
  50. int bytes_to_recv;
  51. result=process_arguments(argc,argv);
  52. if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE){
  53. if(result!=OK)
  54. printf("Incorrect command line arguments supplied\n");
  55. printf("\n");
  56. printf("NRPE Plugin for Nagios\n");
  57. printf("Copyright (c) 1999-2003 Ethan Galstad (nagios@nagios.org)\n");
  58. printf("Version: %s\n",PROGRAM_VERSION);
  59. printf("Last Modified: %s\n",MODIFICATION_DATE);
  60. printf("License: GPL\n");
  61. #ifdef HAVE_SSL
  62. printf("SSL/TLS Available: Anonymous DH Mode, OpenSSL 0.9.6 or higher required\n");
  63. #endif
  64. printf("\n");
  65. }
  66. if(result!=OK || show_help==TRUE){
  67. printf("Usage: check_nrpe -H <host> [-p <port>] [-t <timeout>] [-c <command>] [-a <arglist...>]\n");
  68. printf("\n");
  69. printf("Options:\n");
  70. printf(" <host> = The address of the host running the NRPE daemon\n");
  71. printf(" [port] = The port on which the daemon is running (default=%d)\n",DEFAULT_SERVER_PORT);
  72. printf(" [timeout] = Number of seconds before connection times out (default=%d)\n",DEFAULT_SOCKET_TIMEOUT);
  73. printf(" [command] = The name of the command that the remote daemon should run\n");
  74. printf(" [arglist] = Optional arguments that should be passed to the command. Multiple\n");
  75. printf(" arguments should be separated by a space. If provided, this must be\n");
  76. printf(" the last option supplied on the command line.\n");
  77. printf("\n");
  78. printf("Note:\n");
  79. printf("This plugin requires that you have the NRPE daemon running on the remote host.\n");
  80. printf("You must also have configured the daemon to associate a specific plugin command\n");
  81. printf("with the [command] option you are specifying here. Upon receipt of the\n");
  82. printf("[command] argument, the NRPE daemon will run the appropriate plugin command and\n");
  83. printf("send the plugin output and return code back to *this* plugin. This allows you\n");
  84. printf("to execute plugins on remote hosts and 'fake' the results to make Nagios think\n");
  85. printf("the plugin is being run locally.\n");
  86. printf("\n");
  87. }
  88. if(show_license==TRUE)
  89. display_license();
  90. if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE)
  91. exit(STATE_UNKNOWN);
  92. /* generate the CRC 32 table */
  93. generate_crc32_table();
  94. #ifdef HAVE_SSL
  95. /* initialize SSL */
  96. if(use_ssl==TRUE){
  97. SSL_library_init();
  98. SSLeay_add_ssl_algorithms();
  99. meth=SSLv23_client_method();
  100. SSL_load_error_strings();
  101. if((ctx=SSL_CTX_new(meth))==NULL){
  102. printf("CHECK_NRPE: Error - could not create SSL context.\n");
  103. exit(STATE_CRITICAL);
  104. }
  105. }
  106. #endif
  107. /* initialize alarm signal handling */
  108. signal(SIGALRM,alarm_handler);
  109. /* set socket timeout */
  110. alarm(socket_timeout);
  111. /* try to connect to the host at the given port number */
  112. result=my_tcp_connect(server_name,server_port,&sd);
  113. #ifdef HAVE_SSL
  114. /* do SSL handshake */
  115. if(result==STATE_OK && use_ssl==TRUE){
  116. if((ssl=SSL_new(ctx))!=NULL){
  117. SSL_CTX_set_cipher_list(ctx,"ADH");
  118. SSL_set_fd(ssl,sd);
  119. if((rc=SSL_connect(ssl))!=1){
  120. printf("CHECK_NRPE: Error - Could not complete SSL handshake.\n");
  121. #ifdef DEBUG
  122. printf("SSL_connect=%d\n",rc);
  123. /*
  124. rc=SSL_get_error(ssl,rc);
  125. printf("SSL_get_error=%d\n",rc);
  126. printf("ERR_get_error=%lu\n",ERR_get_error());
  127. printf("%s\n",ERR_error_string(rc,NULL));
  128. */
  129. ERR_print_errors_fp(stdout);
  130. #endif
  131. result=STATE_CRITICAL;
  132. }
  133. }
  134. else{
  135. printf("CHECK_NRPE: Error - Could not create SSL connection structure.\n");
  136. result=STATE_CRITICAL;
  137. }
  138. /* bail if we had errors */
  139. if(result!=STATE_OK){
  140. SSL_CTX_free(ctx);
  141. close(sd);
  142. exit(result);
  143. }
  144. }
  145. #endif
  146. /* we're connected and ready to go */
  147. if(result==STATE_OK){
  148. /* clear the packet buffer */
  149. bzero(&send_packet,sizeof(send_packet));
  150. /* fill the packet with semi-random data */
  151. randomize_buffer((char *)&send_packet,sizeof(send_packet));
  152. /* initialize packet data */
  153. send_packet.packet_version=(int16_t)htons(NRPE_PACKET_VERSION_2);
  154. send_packet.packet_type=(int16_t)htons(QUERY_PACKET);
  155. strncpy(&send_packet.buffer[0],query,MAX_PACKETBUFFER_LENGTH);
  156. send_packet.buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0';
  157. /* calculate the crc 32 value of the packet */
  158. send_packet.crc32_value=(u_int32_t)0L;
  159. calculated_crc32=calculate_crc32((char *)&send_packet,sizeof(send_packet));
  160. send_packet.crc32_value=(u_int32_t)htonl(calculated_crc32);
  161. /***** ENCRYPT REQUEST *****/
  162. /* send the packet */
  163. bytes_to_send=sizeof(send_packet);
  164. if(use_ssl==FALSE)
  165. rc=sendall(sd,(char *)&send_packet,&bytes_to_send);
  166. #ifdef HAVE_SSL
  167. else{
  168. rc=SSL_write(ssl,&send_packet,bytes_to_send);
  169. if(rc<0)
  170. rc=-1;
  171. }
  172. #endif
  173. if(rc==-1){
  174. printf("CHECK_NRPE: Error sending query to host.\n");
  175. close(sd);
  176. return STATE_UNKNOWN;
  177. }
  178. /* wait for the response packet */
  179. bytes_to_recv=sizeof(receive_packet);
  180. if(use_ssl==FALSE)
  181. rc=recvall(sd,(char *)&receive_packet,&bytes_to_recv,socket_timeout);
  182. #ifdef HAVE_SSL
  183. else
  184. rc=SSL_read(ssl,&receive_packet,bytes_to_recv);
  185. #endif
  186. /* reset timeout */
  187. alarm(0);
  188. /* close the connection */
  189. #ifdef HAVE_SSL
  190. if(use_ssl==TRUE){
  191. SSL_shutdown(ssl);
  192. SSL_free(ssl);
  193. SSL_CTX_free(ctx);
  194. }
  195. #endif
  196. close(sd);
  197. /* recv() error */
  198. if(rc<0){
  199. printf("CHECK_NRPE: Error receiving data from daemon.\n");
  200. return STATE_UNKNOWN;
  201. }
  202. /* server disconnected */
  203. else if(rc==0){
  204. printf("CHECK_NRPE: Received 0 bytes from daemon. Check the remote server logs for error messages.\n");
  205. return STATE_UNKNOWN;
  206. }
  207. /* receive underflow */
  208. else if(bytes_to_recv<sizeof(receive_packet)){
  209. printf("CHECK_NRPE: Receive underflow - only %d bytes received (%d expected).\n",bytes_to_recv,sizeof(receive_packet));
  210. return STATE_UNKNOWN;
  211. }
  212. /***** DECRYPT RESPONSE *****/
  213. /* check the crc 32 value */
  214. packet_crc32=ntohl(receive_packet.crc32_value);
  215. receive_packet.crc32_value=0L;
  216. calculated_crc32=calculate_crc32((char *)&receive_packet,sizeof(receive_packet));
  217. if(packet_crc32!=calculated_crc32){
  218. printf("CHECK_NRPE: Response packet had invalid CRC32.\n");
  219. close(sd);
  220. return STATE_UNKNOWN;
  221. }
  222. /* check packet version */
  223. if(ntohs(receive_packet.packet_version)!=NRPE_PACKET_VERSION_2){
  224. printf("CHECK_NRPE: Invalid packet version received from server.\n");
  225. close(sd);
  226. return STATE_UNKNOWN;
  227. }
  228. /* check packet type */
  229. if(ntohs(receive_packet.packet_type)!=RESPONSE_PACKET){
  230. printf("CHECK_NRPE: Invalid packet type received from server.\n");
  231. close(sd);
  232. return STATE_UNKNOWN;
  233. }
  234. /* get the return code from the remote plugin */
  235. result=(int16_t)ntohs(receive_packet.result_code);
  236. /* print the output returned by the daemon */
  237. receive_packet.buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0';
  238. if(!strcmp(receive_packet.buffer,""))
  239. printf("CHECK_NRPE: No output returned from daemon.\n");
  240. else
  241. printf("%s\n",receive_packet.buffer);
  242. }
  243. /* reset the alarm */
  244. else
  245. alarm(0);
  246. return result;
  247. }
  248. /* process command line arguments */
  249. int process_arguments(int argc, char **argv){
  250. char optchars[MAX_INPUT_BUFFER];
  251. int argindex=0;
  252. int c=1;
  253. int i=1;
  254. #ifdef HAVE_GETOPT_H
  255. int option_index=0;
  256. static struct option long_options[]={
  257. {"host", required_argument, 0, 'H'},
  258. {"command", required_argument, 0, 'c'},
  259. {"args", required_argument, 0, 'a'},
  260. {"no-ssl", no_argument, 0, 'n'},
  261. {"timeout", required_argument, 0, 't'},
  262. {"port", required_argument, 0, 'p'},
  263. {"help", no_argument, 0, 'h'},
  264. {"license", no_argument, 0, 'l'},
  265. {0, 0, 0, 0}
  266. };
  267. #endif
  268. /* no options were supplied */
  269. if(argc<2)
  270. return ERROR;
  271. snprintf(optchars,MAX_INPUT_BUFFER,"H:c:a:t:p:nhl");
  272. while(1){
  273. #ifdef HAVE_GETOPT_H
  274. c=getopt_long(argc,argv,optchars,long_options,&option_index);
  275. #else
  276. c=getopt(argc,argv,optchars);
  277. #endif
  278. if(c==-1 || c==EOF)
  279. break;
  280. /* process all arguments */
  281. switch(c){
  282. case '?':
  283. case 'h':
  284. show_help=TRUE;
  285. break;
  286. case 'V':
  287. show_version=TRUE;
  288. break;
  289. case 'l':
  290. show_license=TRUE;
  291. break;
  292. case 't':
  293. socket_timeout=atoi(optarg);
  294. if(socket_timeout<=0)
  295. return ERROR;
  296. break;
  297. case 'p':
  298. server_port=atoi(optarg);
  299. if(server_port<=0)
  300. return ERROR;
  301. break;
  302. case 'H':
  303. server_name=strdup(optarg);
  304. break;
  305. case 'c':
  306. command_name=strdup(optarg);
  307. break;
  308. case 'a':
  309. argindex=optind;
  310. break;
  311. case 'n':
  312. use_ssl=FALSE;
  313. break;
  314. default:
  315. return ERROR;
  316. break;
  317. }
  318. }
  319. /* determine (base) command query */
  320. snprintf(query,sizeof(query),"%s",(command_name==NULL)?DEFAULT_NRPE_COMMAND:command_name);
  321. query[sizeof(query)-1]='\x0';
  322. /* get the command args */
  323. if(argindex>0){
  324. for(c=argindex-1;c<argc;c++){
  325. i=sizeof(query)-strlen(query)-2;
  326. if(i<=0)
  327. break;
  328. strcat(query,"!");
  329. strncat(query,argv[c],i);
  330. query[sizeof(query)-1]='\x0';
  331. }
  332. }
  333. /* make sure required args were supplied */
  334. if(server_name==NULL)
  335. return ERROR;
  336. return OK;
  337. }
  338. void alarm_handler(int sig){
  339. printf("CHECK_NRPE: Socket timeout after %d seconds.\n",socket_timeout);
  340. exit(STATE_CRITICAL);
  341. }