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