xref: /onnv-gate/usr/src/cmd/agents/snmp/snmprelayd/dispatcher.c (revision 1706:0e053bac3f94)
1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 
9 
10 /***********************************************************
11 	Copyright 1988, 1989 by Carnegie Mellon University
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of CMU not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 ******************************************************************/
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <sys/socket.h>
40 #include <errno.h>
41 #include <syslog.h>
42 #include <unistd.h>
43 #include <signal.h>
44 
45 
46 #include "impl.h"
47 #include "error.h"
48 #include "trace.h"
49 #include "signals.h"
50 #include "snmp.h"
51 #include "pdu.h"
52 
53 #include "snmprelay_msg.h"
54 #include "agent.h"
55 #include "subtree.h"
56 #include "session.h"
57 #include "config.h"
58 #include "dispatcher.h"
59 #include "res.h"
60 
61 #include "sea_i18n.h"
62 
63 /***** LOCAL CONSTANTS ******/
64 
65 /*
66  *	select() will returned at least every
67  *	POLL_INTERVAL seconds to test if some
68  *	sessions have SNMP requests that have
69  *	timeout (<==> the SNMP agnet has not
70  *	responded)
71  */
72 
73 #define POLL_INTERVAL		240
74 
75 
76 /***** GLOBAL VARIABLES ******/
77 
78 IPAddress my_ip_address;
79 
80 int clients_sd = -1;	/* socket descriptor "connected" to SNMP application */
81 int agents_sd = -1;	/* socket descriptor "connected" to SNMP agent */
82 int trap_sd = -1; /* socket descriptor for receiving traps from agents */
83 int relay_agent_trap_port = 162;
84 
85 char *relay_agent_name = NULL;
86 char *sec_config_file ;
87 char *pid_file;
88 char *name_oid_file;
89 
90 int relay_agent_max_agent_time_out= 987654321;
91 int relay_agent_poll_interval = POLL_INTERVAL;
92 
93 
94 /*
95  *	the name of the directory that
96  *	contains the configuration files
97  */
98 
99 char *config_dir = NULL;
100 char *resource_file = NULL;
101 
102 /* There are two available modes to run the snmprelayd		*/
103 /*	1) MODE_SPLIT: we send a request for each variable	*/
104 /*	2) MODE_GROUP: we try to group the variables		*/
105 int mode = MODE_GROUP;
106 int recovery_on = FALSE;
107 
108 
109 
110 static int sighup = False;	/* if True, we received the SIGHUP signal */
111 static int port = 0;	/* relay agent port */
112 
113 static char default_config_dir[] = "/etc/snmp/conf";
114 static char default_resource_file[] = "/etc/snmp/conf/snmpdx.rsrc";
115 static char default_error_file[] = "/var/snmp/snmpdx.log";
116 static char default_relay_agent_name[] = "relay-agent";
117 static char default_pid_file[] = "/var/snmp/snmpdx.st";
118 static char default_name_oid_file[] = "/etc/snmp/conf/enterprises.oid";
119 
120 static void application_end();
121 static void signals_sighup(int siq);
122 static void signals_exit(int siq);
123 static void signals_child(int siq);
124 static void init_relay_agent();
125 static void dispatcher_init();
126 static void dispatcher_loop();
127 static void print_usage();
128 
129 
130 /*
131  *	this function is called by error_exit()
132  */
133 static void
application_end()134 application_end()
135 {
136 }
137 
138 
139 static void
signals_sighup(int siq)140 signals_sighup(int siq)
141 {
142 	if(trace_level > 0)
143 		trace("received signal %d\n\n", siq);
144 
145 	error(MSG_SIGHUP, siq);
146 
147 	sighup = True;
148 }
149 
150 static void
signals_exit(int sig)151 signals_exit(int sig)
152 {
153 	/*
154 	 * SIGTERM is a normal exit, don't log it to console.
155 	 */
156 	if (sig != SIGTERM)
157 		error_exit("received signal %d", sig);
158 	else
159 		syslog(LOG_INFO, "received signal %d\n", sig);
160 
161 	exit(sig);
162 }
163 
164 
165 static void
init_relay_agent()166 init_relay_agent()
167 {
168 	/*
169 	 * find agent matches the name, then modify
170 	 * the process id, operstatus
171 	 */
172 
173 	Agent *ap = agent_find_by_name(relay_agent_name);
174 	if (ap == NULL)
175 		return;
176 
177 	ap->agentProcessID = (int)getpid();
178 	ap->agentStatus = SSA_OPER_STATUS_ACTIVE;
179 	ap->first_manager = (struct _Manager *)get_curr_manager_set();
180 
181 
182 	if (port)
183 		ap->agentPortNumber = port;
184 	else if (ap->agentPortNumber)
185 		port = ap->agentPortNumber;
186 	else
187 		port = ap->agentPortNumber = SNMP_PORT;
188 
189 	ap->address.sin_port = port;
190 	/* init the subtrees of relay agent */
191 	agent_update_subtree(ap);
192 }
193 
194 static void
dispatcher_init()195 dispatcher_init()
196 {
197 	struct sockaddr_in me;
198 	socklen_t len;
199 
200 	/* init my_ip_address (we need it before parsing the config file) */
201 
202 	if(get_my_ip_address(&my_ip_address, error_label))
203 		error_exit(ERR_MSG_MY_IP_ADDRESS,
204 			error_label);
205 
206 	if(trace_level > 0)
207 		trace("Local IP Addresss : %s\n\n",
208 			inet_ntoa(my_ip_address));
209 
210 
211 	/* init the config_dir pointer and then parse the configuration files */
212 
213 	if(config_dir == NULL)
214 		config_dir = default_config_dir;
215 
216 	config_init(config_dir);
217 
218 	/* read enterprise name-oid file */
219 	if(name_oid_file == NULL)
220 		name_oid_file = default_name_oid_file;
221 
222 	load_enterprise_oid(name_oid_file);
223 
224 	/* set up the relay agent name */
225 	if(sec_config_file == NULL)
226 		sec_config_file = default_sec_config_file;
227 
228 	sec_config_init(sec_config_file);
229 	if(relay_agent_name == NULL)
230 		relay_agent_name = default_relay_agent_name;
231 
232 	init_relay_agent();
233 
234 	/* read the resource file */
235 	if(resource_file == NULL)
236 		resource_file = default_resource_file;
237 	if(pid_file == NULL)
238 		pid_file = default_pid_file;
239 	write_pid_file1(pid_file);
240 	res_config_init(config_dir);
241 
242 	/* init clients_sd and agents_sd */
243 
244 	clients_sd = socket(AF_INET, SOCK_DGRAM, 0);
245 	if(clients_sd < 0)
246 		error_exit(ERR_MSG_SOCKET, errno_string());
247 
248 	memset(&me, 0, sizeof(me));
249 	me.sin_family = AF_INET;
250 	me.sin_addr.s_addr = htonl(INADDR_ANY);
251 	me.sin_port = htons(port);
252 
253 	if(trace_level > 0)
254 		trace("Waiting for incoming SNMP requests on UDP port %d\n\n", port);
255 
256 	if (bind(clients_sd, (struct sockaddr *)&me, sizeof(me)) != 0)
257 		error_exit(ERR_MSG_BIND, port, errno_string());
258 
259 	agents_sd = socket(AF_INET, SOCK_DGRAM, 0);
260 	if (agents_sd < 0)
261 		error_exit(ERR_MSG_SOCKET, errno_string());
262 
263 	me.sin_family = AF_INET;
264 	me.sin_addr.s_addr = htonl(INADDR_ANY);
265 	me.sin_port = htons(0);
266 
267 	if (bind(agents_sd, (struct sockaddr *)&me, sizeof(me)) != 0)
268 		error_exit(ERR_MSG_BIND, 0, errno_string());
269 
270 	trap_sd = socket(AF_INET, SOCK_DGRAM, 0);
271 	if (trap_sd < 0)
272 		error_exit(ERR_MSG_SOCKET, errno_string());
273 
274 	me.sin_family = AF_INET;
275 	me.sin_addr.s_addr = htonl(INADDR_ANY);
276 	me.sin_port = htons(0);
277 
278 	if(bind(trap_sd, (struct sockaddr *)&me, sizeof(me)) != 0)
279 		error_exit(ERR_MSG_BIND, 0, errno_string());
280 
281 
282 	len = (socklen_t)sizeof(me);
283 	if (getsockname(trap_sd, (struct sockaddr *)&me, &len) == -1)
284 		error_exit(ERR_MSG_BIND, 0, errno_string());
285 
286 	relay_agent_trap_port = ntohs(me.sin_port);
287 	write_pid_file(pid_file);
288 }
289 
290 
dispatcher_loop()291 static void dispatcher_loop()
292 {
293 	int numfds;
294 	fd_set fdset;
295 	int count;
296 	struct timeval timeout;
297 
298 
299 	timeout.tv_usec = 0;
300 
301 	while(1)
302 	{
303 		if(sighup)
304 		{
305 			resource_update(config_dir);
306 			sighup = False;
307 		}
308 
309 		if(trace_level > 1)
310 		{
311 			trace_sessions();
312 		}
313 
314 		numfds = 0;
315 		FD_ZERO(&fdset);
316 
317 		numfds = MAX(clients_sd, agents_sd);
318 		numfds = MAX(numfds,trap_sd);
319 		numfds++;
320 		FD_SET(clients_sd, &fdset);
321 		FD_SET(agents_sd, &fdset);
322 		FD_SET(trap_sd, &fdset);
323 
324 		timeout.tv_sec = relay_agent_poll_interval;
325 
326 		/* we compute the timeout according to the	*/
327 		/* timeout of the pending requests		*/
328 		session_select_info(&timeout);
329 
330 		count = select(numfds, &fdset, 0, 0, &timeout);
331 		if(count > 0)
332 		{
333 			if(FD_ISSET(agents_sd, &fdset))
334 			{
335 				/* we read the responses of the agents */
336 				session_read();
337 				continue;
338 
339 			}
340 
341 			if(FD_ISSET(trap_sd, &fdset))
342 			{
343 				/* working on the trap */
344 				trap_processing();
345 				continue;
346 
347 			}
348 
349 			if(FD_ISSET(clients_sd, &fdset))
350 			{
351 				/* we dispatch the requests of the application */
352 				session_dispatch();
353 
354 			        session_timeout();
355 				continue;
356 			}
357 
358 		}
359 		else
360 		{
361 			switch(count)
362 			{
363 				case 0:
364 					/* we check if some requests have timeout */
365 					session_timeout();
366 					  watch_dog_in_action();
367 					break;
368 
369 				case -1:
370 					if(errno == EINTR)
371 					{
372 						break;
373 					}
374 					else
375 					{
376 						error_exit(ERR_MSG_SELECT, errno_string());
377 					}
378 			}
379 		}
380 	}
381 }
382 
383 
384 /*
385  *	\t[-m GROUP | SPLIT (default GROUP)]\n\
386  */
387 
print_usage()388 static void print_usage()
389 {
390 
391 	fprintf(stderr, FGET("%s\n"),
392 				MGET("Usage: snmpdx [-h]") );
393 	fprintf(stderr, FGET("\t%s\n"),
394 				MGET("[-h (to get help on usage)]") );
395 	fprintf(stderr, FGET("\t%s%d%s\n"),
396 				MGET("[-p port (default "),
397 				SNMP_PORT,
398 				MGET(")]"));
399 
400 	fprintf(stderr, FGET("\t%s%s%s\n"),
401 				MGET("[-r resource-file (default "),
402 				MGET(default_resource_file),
403 				MGET(")]"));
404 
405 	fprintf(stderr, FGET("\t%s%s%s\n"),
406 				MGET("[-a access-control-file (default "),
407 				MGET(default_sec_config_file),
408 				MGET(")]"));
409 
410 	fprintf(stderr, FGET("\t%s%s%s\n"),
411 				MGET("[-c config-dir (default "),
412 				MGET(default_config_dir),
413 				MGET(")]"));
414 
415 	fprintf(stderr, FGET("\t%s%s%s\n"),
416 				MGET("[-i pid-file (default "),
417 				MGET(default_pid_file),
418 				MGET(")]"));
419 
420 	fprintf(stderr, FGET("\t%s%s%s\n"),
421 				MGET("[-o enterprise-oid-file (default "),
422 				MGET(default_name_oid_file),
423 				MGET(")]"));
424 
425 	fprintf(stderr, FGET("\t%s\n"),
426 				MGET("[-y (to invoke recovery module)]"));
427 
428 	fprintf(stderr, FGET("\t%s\n"),
429 				MGET("[-m GROUP | SPLIT (default GROUP)]"));
430 
431 	fprintf(stderr, FGET("\t%s%d%s%d%s\n\n"),
432 				MGET("[-d trace-level (range 0.."),
433 				TRACE_LEVEL_MAX,
434 				MGET(", default "),
435 				trace_level,
436 				MGET(")]"));
437 
438 	exit(1);
439 }
440 
441 int
main(int argc,char * argv[])442 main(int argc, char *argv[])
443 {
444 	int arg;
445 	int Fails ;
446 	char *str;
447 	int level;
448 	char *error_file = NULL;
449 
450  	extern char *optarg;
451 	extern int optind;
452 	int opt;
453 
454 	error_init(argv[0], application_end);
455 
456 	optind = 1;
457 
458 
459 	{
460         char domain_path[MAXPATHLEN];
461 
462         setlocale(LC_ALL, "");
463 
464         sprintf(domain_path, SEA_LOCALE_PATH);
465 
466         bindtextdomain(DOMAIN_MGET, domain_path);
467         bindtextdomain(DOMAIN_SGET,   domain_path);
468         bindtextdomain(DOMAIN_LIBGET,   domain_path);
469         bindtextdomain(DOMAIN_LGET, domain_path);
470         bindtextdomain(DOMAIN_FGET,  domain_path);  /* formatting string */
471 	}
472 
473 
474 	/* parse arguments */
475 	while((opt = getopt(argc,argv,"c:i:hr:m:o:p:a:d:yf:n:?"))!=EOF){
476 		switch(opt){
477 				case 'h':
478 				case '?':
479 					print_usage();
480 					break;
481 				case 'f':
482 					Fails = strtol (optarg, &str, 10) ;
483 					if (optarg == str) {
484 						fprintf (stderr, "Invalid number following the -t option: %s\n", optarg ) ;
485 						print_usage () ;
486 					} else {
487 						SetFailThreshold (Fails) ;
488 					}
489 					break ;
490 
491 
492 				case 'y':
493 					recovery_on=TRUE;
494 					break;
495 
496 				case 'p':
497 					port = strtol(optarg, &str, 10);
498 					if(optarg == str)
499 					{
500 						fprintf(stderr, "Not a valid integer following the -p option: %s\n", optarg);
501 						print_usage();
502 					}
503 
504 					break;
505 
506 				case 'n':
507 					relay_agent_name = strdup(optarg);
508 					if(relay_agent_name == NULL)
509 					{
510 						fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
511 						exit(1);
512 					}
513 
514 					break;
515 
516 				case 'o':
517 					if(optind > argc)
518 					{
519 						fprintf(stderr, "must have the enterprise name-oid file\n");
520 						print_usage();
521 					}
522 
523 					name_oid_file= strdup(optarg);
524 					if(name_oid_file == NULL)
525 					{
526 						fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
527 						exit(1);
528 					}
529 
530 					break;
531 
532 				case 'c':
533 					if(optind > argc)
534 					{
535 						fprintf(stderr, "Must have a configuration directory name following the -c option\n");
536 						print_usage();
537 					}
538 
539 					config_dir = strdup(optarg);
540 					if(config_dir == NULL)
541 					{
542 						fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
543 						exit(1);
544 					}
545 
546 					break;
547 
548                                 case 'a':
549                                         if(optind > argc)
550                                         {
551                                                 fprintf(stderr, "Must have a access control filename following the -a option\n");
552                                                 print_usage();
553                                         }
554 
555                                         sec_config_file = strdup(optarg);
556                                         if(sec_config_file == NULL)
557                                         {
558                                                 fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
559                                                 exit(1);
560                                         }
561 
562                                         break;
563 
564 				case 'r':
565 					if(optind > argc)
566 					{
567 						fprintf(stderr, "Must have a resource file name following the -r option\n");
568 						print_usage();
569 					}
570 
571 					resource_file = strdup(optarg);
572 					if(resource_file == NULL)
573 					{
574 						fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
575 						exit(1);
576 					}
577 
578 					break;
579 
580 				case 'i':
581 					if(optind > argc)
582 					{
583 						fprintf(stderr, "Must have a pid file name following the -i option\n");
584 						print_usage();
585 					}
586 
587 					pid_file = strdup(optarg);
588 					if(pid_file == NULL)
589 					{
590 						fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
591 						exit(1);
592 					}
593 
594 					break;
595 
596 
597 				case 'd':
598 					if(optind> argc)
599 					{
600 						fprintf(stderr, "Must have a trace-level following the -d option\n");
601 						print_usage();
602 					}
603 
604 					level = strtol(optarg, &str, 10);
605 					if(optarg == str)
606 					{
607 						fprintf(stderr, "Not a valid integer following the -d option: %s\n", optarg);
608 						print_usage();
609 					}
610 
611 					if(trace_set(level, error_label))
612 					{
613 						print_usage();
614 					}
615 
616 					break;
617 
618 				case 'm':
619 					if(optind > argc)
620 					{
621 						fprintf(stderr, "Must have GROUP or SPLIT following the -m option\n");
622 						print_usage();
623 					}
624 
625 					if(strcmp(optarg, "GROUP") == 0)
626 					{
627 						mode = MODE_GROUP;
628 					}
629 					else
630 					if(strcmp(optarg, "SPLIT") == 0)
631 					{
632 						mode = MODE_SPLIT;
633 					}
634 					else
635 					{
636 						fprintf(stderr, "Invalid mode: %s\n", optarg);
637 						print_usage();
638 					}
639 
640 					break;
641 
642 				default:
643 					fprintf(stderr, "Invalid Option: -%c\n", optarg);
644 					print_usage();
645 					break;
646 			}
647 		}
648 
649 
650 /*
651 	if(error_file == NULL)
652 	{
653 		error_file = default_error_file;
654 	}
655 	error_open(error_file);
656 */
657 
658 	if(trace_level == 0)
659 	{
660 		/* run the daemon in backgound */
661 
662 		int pid;
663 
664 		pid = fork();
665 		switch(pid)
666 		{
667 			case -1:
668 				error_exit(ERR_MSG_FORK, errno_string());
669 				break;
670 
671 			case 0: /* child process */
672 				break;
673 
674 			default: /* parent process */
675 				exit(0);
676 				break;
677 		}
678 	}
679 
680 	if(fclose(stdin) == EOF)
681 	{
682 		error(ERR_MSG_FCLOSE, "stdin", errno_string());
683 	}
684 
685 	dispatcher_init();
686 
687 	if(signals_init(signals_sighup, signals_exit, error_label))
688 	{
689 		error_exit("signals_init() failed: %s", error_label);
690 	}
691 
692 	if(trace_level == 0)
693 	{
694 		if(fclose(stdout) == EOF)
695 		{
696 			error(ERR_MSG_FCLOSE, "stdout", errno_string());
697 		}
698 	}
699 
700 	if(trace_level == 0)
701 	{
702 		/* background */
703 
704 		if(chdir("/") == -1)
705 		{
706 			error(ERR_MSG_CHDIR, "/", errno_string());
707 		}
708 
709 		/* set process group ID */
710 		setpgrp();
711 
712 		error_close_stderr();
713 	}
714 
715 	dispatcher_loop();
716 
717 	return (0);
718 }
719