1 // Copyright (C) 2006-2009 Hendrik Baecker <andurin@process-zero.de>
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License version 2 as
5 // published by the Free Software Foundation;
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 General Public License
13 // along with this program; if not, write to the Free Software
14 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
15 
16 #include "../include/config.h"
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <signal.h>
23 
24 #ifdef HAVE_GETOPT_H
25 #include <getopt.h>
26 #endif
27 
28 #include<unistd.h>
29 #include<sys/types.h>
30 #include<sys/socket.h>
31 #include<netinet/in.h>
32 
33 #define BUFFER_SIZE 255
34 #define DEFAULT_SERVERPORT	5661 	/* Ein Port der auch von 'gewhnlichen' Benutzern verwendet werden darf */
35 #define MSG_SIZE	8192		/* Die maximale Anzahl an Zeichen, die 'msg' enhalten darf */
36 
37 #define OPEN 	1
38 #define CLOSE	0
39 
40 #define TRUE 	1
41 #define FALSE 	0
42 
43 #define OK	0
44 #define ERROR	-1
45 
46 struct Nagios_Env {
47 	char varname[128];
48 	char varvalue[128];
49 	struct Nagios_Env *next;
50 };
51 
52 /* function prototypes */
53 void print_list(int, struct Nagios_Env *);
54 int parse_env(char *, struct Nagios_Env **);
55 int process_env(char *[]);
56 int open_sock();
57 int process_arguments(int, char **);
58 
59 void timeout_sighandler(int);
60 
61 /* variable declaration*/
62 pid_t fork(void);
63 int socket_status = CLOSE;
64 int serverport = DEFAULT_SERVERPORT;
65 int timeout = 10; /* Default time out to 10 seconds */
66 char *serverip, *datatype;
67 char msg[MSG_SIZE]; /* Buffer for sending the message to remote server */
68 
main(int argc,char * argv[],char * envp[])69 int main(int argc, char *argv[], char *envp[]) {
70 
71 	if (process_arguments(argc, argv) == ERROR)
72 		exit(ERROR);
73 
74 	pid_t pid;
75 	int error_code = 0;
76 	switch (pid = fork()) {
77 	case -1:
78 		/* Here pid is -1, the fork failed */
79 		/* Some possible reasons are that you're */
80 		/* out of process slots or virtual memory */
81 		perror("The fork failed!");
82 		error_code = -1;
83 		break;
84 
85 	case 0:
86 		/* pid of zero is the child */
87 		signal(SIGALRM, timeout_sighandler);
88 		alarm(timeout);
89 		process_env(envp);
90 		_exit(0);
91 
92 	default:
93 		/* pid greater than zero is parent getting the child's pid */
94 		//printf("Child's pid is %d\n",pid);
95 		error_code = 0;
96 	}
97 	exit(error_code);
98 }
99 
timeout_sighandler(int sig)100 void timeout_sighandler(int sig) {
101 
102 	/* force the child process to exit... */
103 	fprintf(stderr, "Caught SIGALRM - timeout\n");
104 	_exit(-1);
105 }
106 
107 /***************************************************
108  * processing command line arguments
109  *
110  * Gets number of args and pointer reference to argv
111  ***************************************************/
process_arguments(int argc,char ** argv)112 int process_arguments(int argc, char **argv) {
113 	int c;
114 	int error = FALSE;
115 	int test_mode = FALSE;
116 	int display_license = FALSE;
117 	int display_help = FALSE;
118 
119 #ifdef HAVE_GETOPT_H
120 	int option_index=0;
121 	static struct option long_options[]= {
122 		{	"help",no_argument,0,'h'},
123 		{	"version",no_argument,0,'V'},
124 		{	"license",no_argument,0,'V'},
125 		{	"test",no_argument,0,'t'},
126 		{	"host",required_argument,0,'H'},
127 		{	"port",required_argument,0,'p'},
128 		{	"datatype",required_argument,0,'d'},
129 		{	"timeout",required_argument,0,'t'},
130 		{	0,0,0,0}
131 	};
132 #endif
133 
134 	/* make sure we have the correct number of command line arguments */
135 	if (argc < 2)
136 		error = TRUE;
137 
138 	while (1) {
139 
140 #ifdef HAVE_GETOPT_H
141 		c=getopt_long(argc,argv,"+hH:p:d:Vt:",long_options,&option_index);
142 #else
143 		c = getopt(argc, argv, "+hH:p:d:Vt:");
144 #endif
145 
146 		if (c == -1 || c == EOF)
147 			break;
148 
149 		switch (c) {
150 
151 		case '?': /* usage */
152 		case 'h':
153 			display_help = TRUE;
154 			break;
155 
156 		case 'V': /* version */
157 			display_license = TRUE;
158 			break;
159 
160 		case 'H': /* host ip */
161 			// ToDo: Check if it there
162 			if (optarg != NULL) {
163 				serverip = optarg;
164 			} else
165 				error = TRUE;
166 			break;
167 
168 		case 'p': /* port to use */
169 			// ToDo: Check for port
170 			if (optarg != NULL)
171 				serverport = atoi(optarg);
172 			break;
173 
174 		case 'd': /* datatype like hostperfdata, serviceperfdata and so on */
175 			if (optarg != NULL)
176 				datatype = optarg;
177 			else
178 				error = TRUE;
179 			break;
180 
181 		case 't': /* timeout */
182 			if (optarg != NULL)
183 				timeout = atoi(optarg);
184 			else
185 				error = TRUE;
186 			break;
187 
188 		default:
189 			break;
190 		}
191 
192 	}
193 
194 	/* it makes no sense to do anything without a target host*/
195 	if (serverip == NULL)
196 		error = TRUE;
197 
198 	if (display_license == TRUE) {
199 
200 		printf(
201 				"This program is free software; you can redistribute it and/or modify\n");
202 		printf(
203 				"it under the terms of the GNU General Public License version 2 as\n");
204 		printf("published by the Free Software Foundation.\n\n");
205 		printf(
206 				"This program is distributed in the hope that it will be useful,\n");
207 		printf(
208 				"but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
209 		printf(
210 				"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
211 		printf("GNU General Public License for more details.\n\n");
212 		printf(
213 				"You should have received a copy of the GNU General Public License\n");
214 		printf("along with this program; if not, write to the Free Software\n");
215 		printf(
216 				"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.\n\n");
217 
218 		exit(OK);
219 	}
220 
221 	/* if there are no command line options (or if we encountered an error), print usage */
222 	if (error == TRUE || display_help == TRUE) {
223 		printf(
224 				"Usage: %s -H <serverip> [-p <serverport>] -d <datatype> -t <timeout>\n",
225 				argv[0]);
226 		printf("\n");
227 		printf("Options:\n");
228 		printf("\n");
229 		printf("  -H | --host     Host IP Address to send data to.\n");
230 		printf("\n");
231 		printf(
232 				"  -p | --port     Host Port to send data to. (Default: tcp/1500)\n");
233 		printf("\n");
234 		printf(
235 				"  -t | --timeout  Timeout value to kill process (Default: 10 seconds)\n");
236 		printf("\n");
237 		printf("  -d | --datatype Free string what this Data stands for\n");
238 		printf(
239 				"                  like \"serviceperfdata\", \"hostperfdata\", \"eventhandler\"\n");
240 		printf("\n\n");
241 		printf(
242 				"Visit the PNP website at http://www.pnp4nagios.org/pnp/ for bug fixes, new\n");
243 		printf(
244 				"releases, online documentation, FAQs, information on subscribing to\n");
245 		printf("the mailing lists.\n");
246 		printf("\n");
247 
248 		exit(ERROR);
249 	}
250 	return OK;
251 }
252 
process_env(char * envp[])253 int process_env(char *envp[]) {
254 	int count = 0;
255 	int socket;
256 	struct Nagios_Env *base = NULL;
257 	struct Nagios_Env *ptr = NULL;
258 	while (1) {
259 		if (socket_status == CLOSE) {
260 			socket = open_sock(serverip);
261 		}
262 		if (envp[count] == NULL) {
263 			break;
264 		}
265 		parse_env(envp[count], &base);
266 		count++;
267 	}
268 	print_list(socket, base);
269 	return (0);
270 }
271 
print_list(int socket,struct Nagios_Env * base)272 void print_list(int socket, struct Nagios_Env *base) {
273 	struct Nagios_Env *ptr = NULL;
274 	char *message, dtype[BUFFER_SIZE];
275 	int message_length = sizeof(struct Nagios_Env) - sizeof(ptr->next);
276 	ptr = base;
277 	strcat(dtype,
278 			"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
279 	strcat(dtype, "<NAGIOS>\n");
280 	strcat(dtype, "  <NAGIOS_DATATYPE>");
281 	strcat(dtype, datatype);
282 	strcat(dtype, "</NAGIOS_DATATYPE>\n");
283 	if (send(socket, dtype, strlen(dtype), 0) == -1) {
284 		fprintf(stderr, "error while sending request to server\n");
285 	}
286 	bzero((void *) dtype, BUFFER_SIZE);
287 
288 	while (ptr != NULL) {
289 		if (!(message = (char *) malloc(sizeof(struct Nagios_Env)))) {
290 			fprintf(stderr, "Cannot allocate memory for this message\n");
291 			exit(ERROR);
292 		}
293 		strncat(message, "  <", message_length);
294 		strncat(message, ptr->varname, message_length);
295 		strncat(message, ">", message_length);
296 		strncat(message, ptr->varvalue, message_length);
297 		strncat(message, "</", message_length);
298 		strncat(message, ptr->varname, message_length);
299 		strncat(message, ">\n", message_length);
300 		message[message_length] = '\0';
301 		if (send(socket, message, strlen(message), 0) == -1) {
302 			fprintf(stderr, "error while sending request to server\n");
303 		}
304 		ptr = ptr->next;
305 	}
306 	strcat(dtype, "</NAGIOS>\n");
307 	if (send(socket, dtype, strlen(dtype), 0) == -1) {
308 		fprintf(stderr, "error while sending request to server\n");
309 	}
310 }
311 
parse_env(char * curr,struct Nagios_Env ** base)312 int parse_env(char *curr, struct Nagios_Env **base) {
313 	char tmpbuf[BUFFER_SIZE];
314 	char *var1;
315 	char *var2;
316 	struct Nagios_Env *ptr = NULL;
317 	ptr = *base;
318 
319 	strncpy(tmpbuf, curr, BUFFER_SIZE);
320 	var1 = strtok(tmpbuf, "=");
321 	var2 = strtok(NULL, "");
322 	if (strncmp(var1, (char *) "NAGIOS_", 7) == 0) {
323 		if (var2 != NULL) {
324 			if (ptr == NULL) {
325 				/* create first list element */
326 				ptr = (struct Nagios_Env *) malloc(sizeof(struct Nagios_Env));
327 				if (ptr == NULL)
328 					return ERROR;
329 				*base = ptr;
330 			} else {
331 				/* create a new list element */
332 				/* first look for the end of list */
333 				while (ptr->next != NULL)
334 					ptr = ptr->next;
335 
336 				/* neues Listenelement erzeugen */
337 				ptr->next = (struct Nagios_Env *) malloc(
338 						sizeof(struct Nagios_Env));
339 				if (ptr->next == NULL)
340 					return ERROR;
341 				ptr = ptr->next;
342 			}
343 
344 			// Building dynamic list
345 			strcpy(ptr->varname, var1);
346 			strcpy(ptr->varvalue, var2);
347 			ptr->next = NULL;
348 		}
349 	}
350 	bzero((void *) tmpbuf, BUFFER_SIZE);
351 	return (0);
352 }
353 
open_sock()354 int open_sock() {
355 	int tosocket; /* the socket descriptor*/
356 
357 	/* description of struct sockaddr_in is mentioned in netinet/in.h */
358 	struct sockaddr_in toaddr; /* store address of server here */
359 
360 	/* create tcp socket */
361 	tosocket = socket(PF_INET, SOCK_STREAM, 0);
362 	if (tosocket == -1) {
363 		fprintf(stderr, "cannot open socket\n");
364 		exit(1);
365 	}
366 
367 	/* define server address */
368 	toaddr.sin_family = PF_INET;
369 	toaddr.sin_addr.s_addr = inet_addr(serverip);
370 	toaddr.sin_port = htons(serverport);
371 
372 	/* connect to server */
373 	if (connect(tosocket, (struct sockaddr *) &toaddr, sizeof(toaddr)) == -1) {
374 		fprintf(stderr,
375 				"Unable to connect to server '%s' on port %d. Exiting...\n",
376 				serverip, serverport);
377 		close(tosocket);
378 		exit(1);
379 	} else {
380 		socket_status = OPEN;
381 		return tosocket;
382 	}
383 	return -1;
384 }
385