xref: /onnv-gate/usr/src/cmd/agents/snmp/agent/snmpd.c (revision 0:68f95e015346)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2002, 2003 by Sun Microsystems, Inc. All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <netinet/in.h>
35 #include <stdio.h>
36 #include <sys/socket.h>
37 #include <arpa/inet.h>
38 #include <errno.h>
39 #include <syslog.h>
40 #include "impl.h"
41 #include "error.h"
42 #include "trace.h"
43 #include "signals.h"
44 #include "snmp.h"
45 #include "pdu.h"
46 #include "agent_msg.h"
47 #include "agent.h"
48 #include "config.h"
49 
50 /***** DEFINES *****/
51 
52 #define DEFAULT_POLL_INTERVAL		30
53 
54 /***** IMPORTED VARIABLES *****/
55 
56 /* user defined data */
57 
58 extern char default_config_file[];
59 extern char default_sec_config_file[];
60 extern char default_error_file[];
61 
62 /***** IMPORTED FUNCTIONS *****/
63 
64 /* user defined functions */
65 extern void agent_init();
66 extern void agent_end();
67 extern void agent_loop();
68 extern void agent_select_info(fd_set *fdset, int *numfds);
69 extern void agent_select_callback(fd_set *fdset);
70 
71 /***** STATIC VARIABLES *****/
72 
73 static int sighup = False;
74 char *config_file = NULL;
75 char *sec_config_file = NULL;
76 int agent_port_number = -1;
77 
78 int dont_read_config_file = FALSE;
79 
80 static int poll_interval = DEFAULT_POLL_INTERVAL;
81 int max_agent_reg_retry = 10;
82 
83 /***** LOCAL FUNCTIONS *****/
84 
85 static void signals_sighup(int siq);
86 static void signals_exit(int siq);
87 
88 static int snmpd_init(int port);
89 static void print_usage(char *command_name);
90 static void snmpd_loop(int sd);
91 static void sap_main(int, char **);
92 
93 
94 /********************************************************************/
95 
96 static void
application_end()97 application_end()
98 {
99 	agent_end();
100 }
101 
102 
103 /********************************************************************/
104 
105 static void
signals_sighup(int sig)106 signals_sighup(int sig)
107 {
108 	if(trace_level > 0)
109 		trace("received signal SIGHUP(%d)\n\n", sig);
110 
111 	error(MSG_SIGHUP, sig);
112 
113 	sighup = True;
114 }
115 
116 
117 /********************************************************************/
118 
119 static void
signals_exit(int sig)120 signals_exit(int sig)
121 {
122 
123 	if (trace_level > 0)
124 		trace("received signal %d", sig);
125 
126 	application_end();
127 
128 	exit(1);
129 }
130 
131 
132 /********************************************************************/
133 
134 static int
snmpd_init(int port)135 snmpd_init(int port)
136 {
137 	int sd;
138 	struct sockaddr_in me;
139 
140 	/* init the config_file pointer and then parse the configuration file */
141 
142 	if (port > 0)
143 		agent_port_number = port;
144 
145 	if (dont_read_config_file == FALSE) {
146 		if (config_file == NULL)
147 			config_file = default_config_file;
148 		config_init(config_file);
149 	}
150 
151 	if (sec_config_file == NULL)
152 		sec_config_file = default_sec_config_file;
153 
154 	(void)sec_config_init(sec_config_file);
155 
156 	/* successfully register the subagent, then set the operation status of
157 	 * subagent to run.
158 	 */
159 	sd = socket(AF_INET, SOCK_DGRAM, 0);
160 	if(sd < 0)
161 		error_exit(ERR_MSG_SOCKET, errno_string());
162 
163 	/* evaluate the port to be used, the port priority is :
164 	  command port > config. file port > def. port */
165 	if(port == 0 && agent_port_number != 0){
166 		port = agent_port_number;
167 	}
168 
169 	me.sin_family = AF_INET;
170 	me.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
171 	me.sin_port = htons(port);
172 	if(bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0)
173 		error_exit(ERR_MSG_BIND, port, errno_string());
174 
175 	if(trace_level > 0)
176 		trace("Waiting for incoming SNMP requests on UDP port %d\n\n", port);
177 
178 	return sd;
179 }
180 
181 static void
snmpd_loop(int sd)182 snmpd_loop(int sd)
183 {
184 	int numfds;
185 	fd_set fdset;
186 	int count;
187 	long long timer;
188 
189 	struct timeval expire;
190 	struct timeval timeout;
191 	struct timeval now;
192 
193 	expire.tv_sec = 0;
194 	expire.tv_usec = 0;
195 
196 
197 	/* CONSTCOND */
198 	while (1) {
199 		if (sighup) {
200 			error(MSG_READING_CONFIG,
201 				config_file);
202 
203 			config_init(config_file);
204 
205 			error(MSG_READING_CONFIG, sec_config_file);
206 
207 			(void) sec_config_init(sec_config_file);
208 
209 			error(MSG_CONFIG_READED);
210 
211 			sighup = False;
212 		}
213 
214 		numfds = 0;
215 		FD_ZERO(&fdset);
216 
217 		numfds = sd + 1;
218 		FD_SET(sd, &fdset);
219 
220 		agent_select_info(&fdset, &numfds);
221 
222 		(void) gettimeofday(&now, (struct timezone *)0);
223 
224 		timer = (long long) (now.tv_sec - expire.tv_sec) * 1000000;
225 		timer += (long long) (now.tv_usec - expire.tv_usec);
226 
227 		if (timer >= 0) {
228 			/* now > timeval + poll_interval */
229 			timeout.tv_sec = 0;
230 			timeout.tv_usec = 0;
231 		} else {
232 			timeout.tv_sec = -timer / 1000000;
233 			timeout.tv_usec = -timer % 1000000;
234 		}
235 
236 		count = select(numfds, &fdset, 0, 0, &timeout);
237 		if (count > 0) {
238 			if (FD_ISSET(sd, &fdset)) {
239 				Address address;
240 				SNMP_pdu *pdu;
241 
242 				if ((pdu = snmp_pdu_receive(sd, &address,
243 						error_label)) == NULL) {
244 					error(ERR_MSG_PDU_RECEIVED,
245 						address_string(&address),
246 						error_label);
247 					continue;
248 				}
249 
250 				if (agent_process(&address, pdu) == -1) {
251 					error(ERR_MSG_PDU_PROCESS,
252 						address_string(&address));
253 					snmp_pdu_free(pdu);
254 					continue;
255 				}
256 
257 				if (pdu->error_status ==
258 					SNMP_ERR_AUTHORIZATIONERROR) {
259 						snmp_pdu_free(pdu);
260 						continue;
261 				}
262 
263 				if ((pdu->error_status != SNMP_ERR_NOERROR)
264 				&& (pdu->error_status != SNMP_ERR_NOSUCHNAME)) {
265 					error(ERR_MSG_SNMP_ERROR,
266 					error_status_string(pdu->error_status),
267 						pdu->error_index,
268 						address_string(&address));
269 				}
270 
271 				if (snmp_pdu_send(sd, &address, pdu,
272 						error_label) == -1) {
273 					error(ERR_MSG_PDU_SEND,
274 						address_string(&address),
275 						error_label);
276 					snmp_pdu_free(pdu);
277 					continue;
278 				}
279 
280 				snmp_pdu_free(pdu);
281 			}
282 
283 			agent_select_callback(&fdset);
284 		} else {
285 			switch (count) {
286 				case 0:
287 					(void) gettimeofday(&expire,
288 						(struct timezone *) 0);
289 					expire.tv_sec = expire.tv_sec + poll_interval;
290 					agent_loop();
291 					break;
292 
293 				case -1:
294 					if (errno == EINTR) {
295 						continue;
296 					} else if (errno == EBADF) {
297 					FD_CLR(sd, &fdset);
298 					fprintf(stderr, "select() failed %s\n",
299 						errno_string());
300 					continue;
301 					} else {
302 						error_exit(ERR_MSG_SELECT,
303 							errno_string());
304 					}
305 			}
306 		}
307 	}
308 }
309 
310 
print_usage(char * command_name)311 static void print_usage(char *command_name)
312 {
313 	(void)fprintf(stderr, "Usage: %s [-h]\n\
314 \t[-k (don't read config file)]\n\
315 \t[-p port ]\n\
316 \t[-c config-file (default %s)]\n\
317 \t[-a sec-config-file (default %s)]\n\
318 \t[-i poll-interval (default %d seconds)]\n\
319 \t[-d trace-level (range 0..%d, default %d)]\n\n",
320 		command_name,
321 		default_config_file,
322 		default_sec_config_file,
323 		DEFAULT_POLL_INTERVAL,
324 		TRACE_LEVEL_MAX,
325 		trace_level);
326 	exit(1);
327 }
328 
329 
330 static void
sap_main(argc,argv)331 sap_main(argc, argv)
332 	int argc;
333 	char *argv[];
334 {
335 	int arg;
336 	int port = 0;
337 	int sd;
338 	char *str;
339 	int level;
340 	char *error_file = NULL;
341 
342 
343 
344 	error_init(argv[0], application_end);
345 
346 	/* parse arguments */
347 
348 	for(arg = 1; arg < argc; arg++)
349 	{
350 		if(argv[arg][0] == '-')
351 		{
352 			switch(argv[arg][1])
353 			{
354                                 case 'k':
355                                         dont_read_config_file = TRUE;
356                                         break;
357 				case 'h':
358 				case '?':
359 					print_usage(argv[0]);
360 
361 					/* never reached */
362 					return;
363 
364 				case 'p':
365 					arg++;
366 					if(arg >= argc)
367 					{
368 						(void)fprintf(stderr, "Must have another argument following the -p option\n");
369 						print_usage(argv[0]);
370 					}
371 
372 					/* LINTED */
373 					port = (int32_t)strtol(argv[arg], &str, 10);
374 					if(argv[arg] == str)
375 					{
376 						(void)fprintf(stderr, "Not a valid integer following the -p option: %s\n", argv[arg]);
377 						print_usage(argv[0]);
378 					}
379 
380 					break;
381 
382 				case 'c':
383 					arg++;
384 					if(arg >= argc)
385 					{
386 						(void)fprintf(stderr, "Must have a configuration file name following the -c option\n");
387 						print_usage(argv[0]);
388 					}
389 
390 					config_file = (char *) strdup(argv[arg]);
391 					if(config_file == NULL)
392 					{
393 						(void)fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
394 						exit(1);
395 					}
396 
397 					break;
398 
399 				case 'a':
400 					arg++;
401 					if(arg >= argc)
402 					{
403 						(void)fprintf(stderr, "Must have a security configuration file name following the -a option\n");
404 						print_usage(argv[0]);
405 					}
406 
407 					sec_config_file = (char *) strdup(argv[arg]);
408 					if(sec_config_file == NULL)
409 					{
410 						(void)fprintf(stderr, "%s\n", ERR_MSG_ALLOC);
411 						exit(1);
412 					}
413 
414 					break;
415 
416 
417 				case 'i':
418 					arg++;
419 					if(arg >= argc)
420 					{
421 						(void)fprintf(stderr, "Must have another argument following the -i option\n");
422 						print_usage(argv[0]);
423 					}
424 
425 					/* LINTED */
426 					poll_interval = (int32_t)strtol(argv[arg], &str, 10);
427 					if(argv[arg] == str)
428 					{
429 						(void)fprintf(stderr, "Not a valid integer following the -i option: %s\n", argv[arg]);
430 						print_usage(argv[0]);
431 					}
432 					if(poll_interval <= 0)
433 					{
434 						(void)fprintf(stderr, "The poll-interval must be greater than 0: %d\n", poll_interval);
435 						print_usage(argv[0]);
436 					}
437 
438 					break;
439 
440 				case 'd':
441 					arg++;
442 					if(arg >= argc)
443 					{
444 						(void)fprintf(stderr, "Must have another argument following the -d option\n");
445 						print_usage(argv[0]);
446 					}
447 
448 					/* LINTED */
449 					level = (int32_t)strtol(argv[arg], &str, 10);
450 					if(argv[arg] == str)
451 					{
452 						(void)fprintf(stderr, "Not a valid integer following the -d option: %s\n", argv[arg]);
453 						print_usage(argv[0]);
454 					}
455 					if(trace_set(level, error_label))
456 					{
457 						print_usage(argv[0]);
458 					}
459 
460 					break;
461 
462 				default:
463 					(void)fprintf(stderr, "Invalid option: -%c\n", argv[arg][1]);
464 					print_usage(argv[0]);
465 			}
466 			continue;
467 		}
468 	}
469 
470 
471 	if(error_file == NULL)
472 	{
473 		error_file = default_error_file;
474 	}
475 	error_open(error_file);
476 
477 	if(trace_level == 0)
478 	{
479 		/* run the daemon in backgound */
480 
481 		pid_t pid;
482 
483 		pid = fork();
484 		switch(pid)
485 		{
486 			case -1:
487 				error_exit(ERR_MSG_FORK, errno_string());
488 
489 				/* never reached */
490 				return;
491 
492 			case 0: /* child process */
493 				break;
494 
495 			default: /* parent process */
496 				exit(0);
497 		}
498 	}
499 
500 	if(fclose(stdin) == EOF)
501 	{
502 		error(ERR_MSG_FCLOSE, "stdin", errno_string());
503 	}
504 
505 	sd = snmpd_init(port);
506 
507 	if(signals_init(signals_sighup, signals_exit, error_label))
508 	{
509 		error_exit("signals_init() failed: %s", error_label);
510 	}
511 
512 	if(trace_level == 0)
513 	{
514 		if(fclose(stdout) == EOF)
515 		{
516 			error(ERR_MSG_FCLOSE, "stdout", errno_string());
517 		}
518 	}
519 
520 	if(trace_level == 0)
521 	{
522 		/* backgound */
523 
524 		if(chdir("/") == -1)
525 		{
526 			error(ERR_MSG_CHDIR, "/", errno_string());
527 		}
528 
529 		/* set process group ID */
530 		(void)setpgrp();
531 
532 		error_close_stderr();
533 	}
534 
535 	/* have to be called after error_open() and error_close_stderr() */
536 	agent_init();
537 
538 	snmpd_loop(sd);
539 
540 	/* never reached */
541 }
542 
543 void
SSAMain(int argc,char ** argv)544 SSAMain(int argc, char** argv)
545 {
546 	sap_main(argc,argv);
547 }
548