static netsnmp_transport * agent_priv_unix_transport(const char *string, int len, int local) { struct sockaddr_un addr = { .sun_family = AF_UNIX }; netsnmp_transport *t = NULL; if (local) { log_warnx("snmp", "should not have been called for local transport"); return NULL; } if (!string) return NULL; if (len >= sizeof(addr.sun_path) || strlcpy(addr.sun_path, string, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) { log_warnx("snmp", "path too long for Unix domain transport"); return NULL; } if ((t = (netsnmp_transport *) calloc(1, sizeof(netsnmp_transport))) == NULL) return NULL; t->domain = netsnmp_unix; t->domain_length = sizeof(netsnmp_unix) / sizeof(netsnmp_unix[0]); if ((t->sock = priv_snmp_socket(&addr)) < 0) { netsnmp_transport_free(t); return NULL; } t->flags = NETSNMP_TRANSPORT_FLAG_STREAM; if ((t->remote = (u_char *) malloc(strlen(addr.sun_path))) == NULL) { agent_priv_unix_close(t); netsnmp_transport_free(t); return NULL; } memcpy(t->remote, addr.sun_path, strlen(addr.sun_path)); t->remote_length = strlen(addr.sun_path); t->msgMaxSize = 0x7fffffff; t->f_recv = agent_priv_unix_recv; t->f_send = agent_priv_unix_send; t->f_close = agent_priv_unix_close; t->f_accept = agent_priv_unix_accept; t->f_fmtaddr = agent_priv_unix_fmtaddr; return t; }
void netsnmp_transport_free(netsnmp_transport *t) { if (NULL == t) return; SNMP_FREE(t->local); SNMP_FREE(t->remote); SNMP_FREE(t->data); netsnmp_transport_free(t->base_transport); SNMP_FREE(t); }
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::efF:g:hHI:L:m:M:no:O:PqsS:tu:vx:-:"; netsnmp_session *sess_list = NULL, *ss = NULL; netsnmp_transport *transport = NULL; int arg, i = 0, depmsg = 0; int uid = 0, gid = 0; int count, numfds, block; fd_set readfds,writefds,exceptfds; struct timeval timeout, *tvp; char *cp, *listen_ports = NULL; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) int agentx_subagent = 1; #endif netsnmp_trapd_handler *traph; #ifdef NETSNMP_EMBEDDED_PERL extern void init_perl(void); #endif #ifndef WIN32 /* * close all non-standard file descriptors we may have * inherited from the shell. */ for (i = getdtablesize() - 1; i > 2; --i) { (void) close(i); } #endif /* #WIN32 */ #ifdef SIGTERM signal(SIGTERM, term_handler); #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif #ifdef SIGINT signal(SIGINT, term_handler); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif /* * register our configuration handlers now so -H properly displays them */ snmptrapd_register_configs( ); init_usm_conf( "snmptrapd" ); register_config_handler("snmptrapd", "snmpTrapdAddr", parse_trapd_address, free_trapd_address, "string"); register_config_handler("snmptrapd", "doNotLogTraps", parse_config_doNotLogTraps, NULL, "(1|yes|true|0|no|false)"); #if HAVE_GETPID register_config_handler("snmptrapd", "pidFile", parse_config_pidFile, NULL, "string"); #endif #ifdef HAVE_UNISTD_H register_config_handler("snmptrapd", "agentuser", parse_config_agentuser, NULL, "userid"); register_config_handler("snmptrapd", "agentgroup", parse_config_agentgroup, NULL, "groupid"); #endif register_config_handler("snmptrapd", "logOption", parse_config_logOption, NULL, "string"); register_config_handler("snmptrapd", "doNotFork", parse_config_doNotFork, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "printEventNumbers", parse_config_printEventNumbers, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "ignoreAuthFailure", parse_config_ignoreAuthFailure, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "outputOption", parse_config_outputOption, NULL, "string"); #ifdef WIN32 setvbuf(stdout, NULL, _IONBF, BUFSIZ); #else setvbuf(stdout, NULL, _IOLBF, BUFSIZ); #endif /* * Add some options if they are available. */ #if HAVE_GETPID strcat(options, "p:"); #endif #ifdef WIN32 snmp_log_syslogname(app_name_long); #else snmp_log_syslogname(app_name); #endif /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(); exit(0); } if (strcasecmp(optarg, "version") == 0) { version(); exit(0); } handle_long_opt(optarg); break; case 'a': dropauth = 1; break; case 'A': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES, 1); break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(); exit(1); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': snmp_set_dump_packet(1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'e': Event++; break; case 'f': dofork = 0; break; case 'F': if (optarg != NULL) { trap1_fmt_str_remember = optarg; } else { usage(); exit(1); } break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, gid = atoi(optarg)); } else { usage(); exit(1); } break; #endif case 'h': usage(); exit(0); case 'H': init_agent("snmptrapd"); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE init_notification_log(); #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); #endif init_snmp("snmptrapd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(); } break; case 'S': fprintf(stderr, "Warning: -S option is deprecated; use -Ls <facility> instead\n"); depmsg = 1; if (optarg != NULL) { switch (*optarg) { case 'd': case 'D': Facility = LOG_DAEMON; break; case 'i': case 'I': Facility = LOG_INFO; break; case '0': Facility = LOG_LOCAL0; break; case '1': Facility = LOG_LOCAL1; break; case '2': Facility = LOG_LOCAL2; break; case '3': Facility = LOG_LOCAL3; break; case '4': Facility = LOG_LOCAL4; break; case '5': Facility = LOG_LOCAL5; break; case '6': Facility = LOG_LOCAL6; break; case '7': Facility = LOG_LOCAL7; break; default: fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg); usage(); exit(1); } } else { fprintf(stderr, "no syslog facility specified\n"); usage(); exit(1); } break; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(); exit(1); } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(); exit(1); } break; case 'n': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_NUMERIC_IP, 1); break; case 'o': fprintf(stderr, "Warning: -o option is deprecated; use -Lf <file> instead\n"); if (optarg != NULL) { logfile = optarg; snmp_enable_filelog(optarg, netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES)); } else { usage(); exit(1); } break; case 'O': cp = snmp_out_toggle_options(optarg); if (cp != NULL) { fprintf(stderr, "Unknown output option passed to -O: %c\n", *cp); usage(); exit(1); } break; case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(); exit(1); } break; #if HAVE_GETPID case 'p': if (optarg != NULL) { parse_config_pidFile(NULL, optarg); } else { usage(); exit(1); } break; #endif case 'P': fprintf(stderr, "Warning: -P option is deprecated; use -f -Le instead\n"); dofork = 0; snmp_enable_stderrlog(); break; case 's': fprintf(stderr, "Warning: -s option is deprecated; use -Lsd instead\n"); depmsg = 1; #ifdef WIN32 snmp_enable_syslog_ident(app_name_long, Facility); #else snmp_enable_syslog_ident(app_name, Facility); #endif break; case 't': SyslogTrap++; break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; uid = strtoul(optarg, &ecp, 10); if (*ecp) { #if HAVE_GETPWNAM && HAVE_PWD_H struct passwd *info; info = getpwnam(optarg); if (info) { uid = info->pw_uid; } else { #endif fprintf(stderr, "Bad user id: %s\n", optarg); exit(1); #if HAVE_GETPWNAM && HAVE_PWD_H } #endif } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(); exit(1); } break; #endif case 'v': version(); exit(0); break; case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(); exit(1); } break; default: fprintf(stderr, "invalid option: -%c\n", arg); usage(); exit(1); break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ for (i = optind; i < argc; i++) { char *astring; if (listen_ports != NULL) { astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", listen_ports, argv[i]); free(listen_ports); listen_ports = astring; } else { listen_ports = strdup(argv[i]); if (listen_ports == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } } } } SOCK_STARTUP; /* * I'm being lazy here, and not checking the * return value from these registration calls. * Don't try this at home, children! */ if (0 == snmp_get_do_logging()) { traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, syslog_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_syslog(); } else { traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; } if (Event) { traph = netsnmp_add_traphandler(event_handler, risingAlarm, OID_LENGTH(risingAlarm)); traph->authtypes = TRAP_AUTH_LOG; traph = netsnmp_add_traphandler(event_handler, fallingAlarm, OID_LENGTH(fallingAlarm)); traph->authtypes = TRAP_AUTH_LOG; traph = netsnmp_add_traphandler(event_handler, unavailableAlarm, OID_LENGTH(unavailableAlarm)); traph->authtypes = TRAP_AUTH_LOG; /* XXX - might be worth setting some "magic data" * in the traphandler structure that 'event_handler' * can use to avoid checking the trap OID values. */ } #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) /* * we're an agentx subagent? */ if (agentx_subagent) { /* * make us a agentx client. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); } #endif /* * don't fail if we can't do agentx (ie, socket not there, or not root) */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); /* * ignore any warning messages. */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS); /* * initialize the agent library */ init_agent("snmptrapd"); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) /* * initialize local modules */ if (agentx_subagent) { #ifdef USING_SNMPV3_SNMPENGINE_MODULE extern void register_snmpEngine_scalars_context(const char *); #endif subagent_init(); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE /* register the notification log table */ if (should_init("notificationLogMib")) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_NOTIF_LOG_CTX, "snmptrapd"); traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER, notification_handler); traph->authtypes = TRAP_AUTH_LOG; init_notification_log(); } #endif #ifdef USING_SNMPV3_SNMPENGINE_MODULE /* * register scalars from SNMP-FRAMEWORK-MIB::snmpEngineID group; * allows engineID probes via the master agent under the * snmptrapd context */ register_snmpEngine_scalars_context("snmptrapd"); #endif } #endif /* USING_AGENTX_SUBAGENT_MODULE && !NETSNMP_SNMPTRAPD_DISABLE_AGENTX */ /* register our authorization handler */ init_netsnmp_trapd_auth(); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) if (agentx_subagent) { #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE extern void init_register_nsVacm_context(const char *); #endif #ifdef USING_SNMPV3_USMUSER_MODULE extern void init_register_usmUser_context(const char *); /* register ourselves as having a USM user database */ init_register_usmUser_context("snmptrapd"); #endif #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE /* register net-snmp vacm extensions */ init_register_nsVacm_context("snmptrapd"); #endif } #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); { /* set the default path to load */ char init_file[SNMP_MAXBUF]; snprintf(init_file, sizeof(init_file) - 1, "%s/%s", SNMPSHAREPATH, "snmp_perl_trapd.pl"); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PERL_INIT_FILE, init_file); } #endif /* * Initialize the world. */ init_snmp("snmptrapd"); #ifdef SIGHUP signal(SIGHUP, hup_handler); #endif if (trap1_fmt_str_remember) { free_trap1_fmt(); free_trap2_fmt(); print_format1 = strdup(trap1_fmt_str_remember); print_format2 = strdup(trap1_fmt_str_remember); } if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) { /* * just starting up to process specific configuration and then * shutting down immediately. */ netsnmp_running = 0; } /* * if no logging options on command line or in conf files, use syslog */ if (0 == snmp_get_do_logging()) { #ifdef WIN32 snmp_enable_syslog_ident(app_name_long, Facility); #else snmp_enable_syslog_ident(app_name, Facility); #endif } #ifndef WIN32 /* * fork the process to the background if we are not printing to stderr */ if (dofork && netsnmp_running) { int fd; switch (fork()) { case -1: fprintf(stderr, "bad fork - %s\n", strerror(errno)); _exit(1); case 0: /* * become process group leader */ if (setsid() == -1) { fprintf(stderr, "bad setsid - %s\n", strerror(errno)); _exit(1); } /* * if we are forked, we don't want to print out to stdout or stderr */ fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); break; default: _exit(0); } } #endif /* WIN32 */ #if HAVE_GETPID if (pid_file != NULL) { if ((PID = fopen(pid_file, "w")) == NULL) { snmp_log_perror("fopen"); exit(1); } fprintf(PID, "%d\n", (int) getpid()); fclose(PID); free_config_pidFile(); } #endif snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); if (depmsg) { snmp_log(LOG_WARNING, "-s and -S options are deprecated; use -Ls <facility> instead\n"); } if (listen_ports) cp = listen_ports; else cp = default_port; while (cp != NULL) { char *sep = strchr(cp, ','); if (sep != NULL) { *sep = 0; } transport = netsnmp_transport_open_server("snmptrap", cp); if (transport == NULL) { snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n", cp, errno, strerror(errno)); snmptrapd_close_sessions(sess_list); SOCK_CLEANUP; exit(1); } else { ss = snmptrapd_add_session(transport); if (ss == NULL) { /* * Shouldn't happen? We have already opened the transport * successfully so what could have gone wrong? */ snmptrapd_close_sessions(sess_list); netsnmp_transport_free(transport); snmp_log(LOG_ERR, "couldn't open snmp - %s", strerror(errno)); SOCK_CLEANUP; exit(1); } else { ss->next = sess_list; sess_list = ss; } } /* * Process next listen address, if there is one. */ if (sep != NULL) { *sep = ','; cp = sep + 1; } else { cp = NULL; } } /* * ignore early sighup during startup */ reconfig = 0; #if HAVE_UNISTD_H #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #endif #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_RUNNING; #endif while (netsnmp_running) { if (reconfig) { /* * If we are logging to a file, receipt of SIGHUP also * indicates the the log file should be closed and * re-opened. This is useful for users that want to * rotate logs in a more predictable manner. */ netsnmp_logging_restart(); snmp_log(LOG_INFO, "NET-SNMP version %s restarted\n", netsnmp_get_version()); trapd_update_config(); if (trap1_fmt_str_remember) { free_trap1_fmt(); free_trap2_fmt(); print_format1 = strdup(trap1_fmt_str_remember); print_format2 = strdup(trap1_fmt_str_remember); } reconfig = 0; } numfds = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); block = 0; tvp = &timeout; timerclear(tvp); tvp->tv_sec = 5; snmp_select_info(&numfds, &readfds, tvp, &block); if (block == 1) tvp = NULL; /* block without timeout */ netsnmp_external_event_info(&numfds, &readfds, &writefds, &exceptfds); count = select(numfds, &readfds, &writefds, &exceptfds, tvp); gettimeofday(&Now, 0); if (count > 0) { netsnmp_dispatch_external_events(&count, &readfds, &writefds, &exceptfds); /* If there are any more events after external events, then * try SNMP events. */ if (count > 0) { snmp_read(&readfds); } } else switch (count) { case 0: snmp_timeout(); break; case -1: if (errno == EINTR) continue; snmp_log_perror("select"); netsnmp_running = 0; break; default: fprintf(stderr, "select returned %d\n", count); netsnmp_running = 0; } run_alarms(); } if (snmp_get_do_logging()) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } snmp_log(LOG_INFO, "Stopping snmptrapd"); snmptrapd_close_sessions(sess_list); snmp_shutdown("snmptrapd"); #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_STOPPED; #endif snmp_disable_log(); SOCK_CLEANUP; return 0; }
netsnmp_transport * netsnmp_ipx_transport(struct sockaddr_ipx *addr, int local) { netsnmp_transport *t = NULL; int rc = 0; char *str = NULL; if (addr == NULL || addr->sipx_family != AF_IPX) { return NULL; } t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } str = netsnmp_ipx_fmtaddr(NULL, (void *)addr, sizeof(struct sockaddr_ipx)); DEBUGMSGTL(("netsnmp_ipx", "open %s %s\n", local ? "local" : "remote", str)); free(str); memset(t, 0, sizeof(netsnmp_transport)); t->domain = netsnmpIPXDomain; t->domain_length = netsnmpIPXDomain_len; t->sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } if (local) { t->local = (unsigned char*)malloc(12); if (t->local == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(&(t->local[00]), (u_char *) & (addr->sipx_network), 4); memcpy(&(t->local[04]), (u_char *) & (addr->sipx_node), 6); memcpy(&(t->local[10]), (u_char *) & (addr->sipx_port), 2); t->local_length = 12; /* * This session is inteneded as a server, so we must bind on to the * given address (which may include a particular network and/or node * address, but definitely includes a port number). */ rc = bind(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr)); if (rc != 0) { netsnmp_ipx_close(t); netsnmp_transport_free(t); return NULL; } t->data = NULL; t->data_length = 0; } else { t->remote = (unsigned char*)malloc(12); if (t->remote == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(&(t->remote[00]), (u_char *) & (addr->sipx_network), 4); memcpy(&(t->remote[04]), (u_char *) & (addr->sipx_node), 6); memcpy(&(t->remote[10]), (u_char *) & (addr->sipx_port), 2); t->remote_length = 12; /* * This is a client session. Save the address in the * transport-specific data pointer for later use by snmp_ipx_send. */ t->data = malloc(sizeof(struct sockaddr_ipx)); if (t->data == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(t->data, addr, sizeof(struct sockaddr_ipx)); t->data_length = sizeof(struct sockaddr_ipx); } /* * Maximum size of an IPX PDU is 576 bytes including a 30-byte header. * Ridiculous! */ t->msgMaxSize = 576 - 30; t->f_recv = netsnmp_ipx_recv; t->f_send = netsnmp_ipx_send; t->f_close = netsnmp_ipx_close; t->f_accept = NULL; t->f_fmtaddr = netsnmp_ipx_fmtaddr; return t; }
netsnmp_transport * netsnmp_udp6_transport(struct sockaddr_in6 *addr, int local) { netsnmp_transport *t = NULL; int rc = 0; char *str = NULL; int socket_initialized = 0; #ifdef NETSNMP_NO_LISTEN_SUPPORT if (local) return NULL; #endif /* NETSNMP_NO_LISTEN_SUPPORT */ if (addr == NULL || addr->sin6_family != AF_INET6) { return NULL; } t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } str = netsnmp_udp6_fmtaddr(NULL, (void *) addr, sizeof(struct sockaddr_in6)); DEBUGMSGTL(("netsnmp_udp6", "open %s %s\n", local ? "local" : "remote", str)); free(str); memset(t, 0, sizeof(netsnmp_transport)); t->domain = netsnmp_UDPIPv6Domain; t->domain_length = sizeof(netsnmp_UDPIPv6Domain) / sizeof(netsnmp_UDPIPv6Domain[0]); #ifndef NETSNMP_NO_SYSTEMD /* * Maybe the socket was already provided by systemd... */ if (local) { t->sock = netsnmp_sd_find_inet_socket(PF_INET6, SOCK_DGRAM, -1, ntohs(addr->sin6_port)); if (t->sock) socket_initialized = 1; } #endif if (!socket_initialized) t->sock = (int) socket(PF_INET6, SOCK_DGRAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } _netsnmp_udp_sockopt_set(t->sock, local); if (local) { #ifndef NETSNMP_NO_LISTEN_SUPPORT /* * This session is intended as a server, so we must bind on to the * given IP address, which may include an interface address, or could * be INADDR_ANY, but certainly includes a port number. */ #ifdef IPV6_V6ONLY /* Try to restrict PF_INET6 socket to IPv6 communications only. */ { int one=1; if (setsockopt(t->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) != 0) { DEBUGMSGTL(("netsnmp_udp6", "couldn't set IPV6_V6ONLY to %d bytes: %s\n", one, strerror(errno))); } } #endif if (!socket_initialized) { rc = bind(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr_in6)); if (rc != 0) { netsnmp_socketbase_close(t); netsnmp_transport_free(t); return NULL; } } t->local = (unsigned char*)malloc(18); if (t->local == NULL) { netsnmp_socketbase_close(t); netsnmp_transport_free(t); return NULL; } memcpy(t->local, addr->sin6_addr.s6_addr, 16); t->local[16] = (addr->sin6_port & 0xff00) >> 8; t->local[17] = (addr->sin6_port & 0x00ff) >> 0; t->local_length = 18; t->data = NULL; t->data_length = 0; #else /* NETSNMP_NO_LISTEN_SUPPORT */ return NULL; #endif /* NETSNMP_NO_LISTEN_SUPPORT */ } else {
netsnmp_transport * netsnmp_udp_transport(struct sockaddr_in *addr, int local) { netsnmp_transport *t = NULL; int rc = 0, udpbuf = (1 << 17); char *string = NULL; if (addr == NULL || addr->sin_family != AF_INET) { return NULL; } t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } string = netsnmp_udp_fmtaddr(NULL, (void *)addr, sizeof(struct sockaddr_in)); DEBUGMSGTL(("netsnmp_udp", "open %s %s\n", local ? "local" : "remote", string)); free(string); memset(t, 0, sizeof(netsnmp_transport)); t->domain = netsnmpUDPDomain; t->domain_length = netsnmpUDPDomain_len; t->sock = socket(PF_INET, SOCK_DGRAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } #ifdef SO_BSDCOMPAT /* * Patch for Linux. Without this, UDP packets that fail get an ICMP * response. Linux turns the failed ICMP response into an error message * and return value, unlike all other OS's. */ { int one = 1; setsockopt(t->sock, SOL_SOCKET, SO_BSDCOMPAT, (void *) &one, sizeof(one)); } #endif /*SO_BSDCOMPAT */ /* * SO_REUSEADDR will allow multiple apps to open the same port at * the same time. Only the last one to open the socket will get * data. Obviously, for an agent, this is a bad thing. There should * only be one listener. */ #ifdef ALLOW_PORT_HIJACKING #ifdef SO_REUSEADDR /* * Allow the same port to be specified multiple times without failing. * (useful for a listener) */ { int one = 1; setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one)); } #endif /*SO_REUSEADDR */ #endif /* * Try to set the send and receive buffers to a reasonably large value, so * that we can send and receive big PDUs (defaults to 8192 bytes (!) on * Solaris, for instance). Don't worry too much about errors -- just * plough on regardless. */ #ifdef SO_SNDBUF if (setsockopt (t->sock, SOL_SOCKET, SO_SNDBUF, (void *) &udpbuf, sizeof(int)) != 0) { DEBUGMSGTL(("netsnmp_udp", "couldn't set SO_SNDBUF to %d bytes: %s\n", udpbuf, strerror(errno))); } #endif /*SO_SNDBUF */ #ifdef SO_RCVBUF if (setsockopt (t->sock, SOL_SOCKET, SO_RCVBUF, (void *) &udpbuf, sizeof(int)) != 0) { DEBUGMSGTL(("netsnmp_udp", "couldn't set SO_RCVBUF to %d bytes: %s\n", udpbuf, strerror(errno))); } #endif /*SO_RCVBUF */ if (local) { /* * This session is inteneded as a server, so we must bind on to the * given IP address, which may include an interface address, or could * be INADDR_ANY, but certainly includes a port number. */ t->local = malloc(6); if (t->local == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4); t->local[4] = (htons(addr->sin_port) & 0xff00) >> 8; t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0; t->local_length = 6; rc = bind(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr)); if (rc != 0) { netsnmp_udp_close(t); netsnmp_transport_free(t); return NULL; } t->data = NULL; t->data_length = 0; } else {
netsnmp_transport * netsnmp_ssh_transport(const struct sockaddr_in *addr, int local) { netsnmp_transport *t = NULL; netsnmp_ssh_addr_pair *addr_pair = NULL; int rc = 0; int i, auth_pw = 0; const char *fingerprint; char *userauthlist; struct sockaddr_un *unaddr; const char *sockpath = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSHTOSNMP_SOCKET); char tmpsockpath[MAXPATHLEN]; #ifdef NETSNMP_NO_LISTEN_SUPPORT if (local) return NULL; #endif /* NETSNMP_NO_LISTEN_SUPPORT */ if (addr == NULL || addr->sin_family != AF_INET) { return NULL; } t = SNMP_MALLOC_TYPEDEF(netsnmp_transport); if (t == NULL) { return NULL; } t->domain = netsnmp_snmpSSHDomain; t->domain_length = netsnmp_snmpSSHDomain_len; t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED; addr_pair = SNMP_MALLOC_TYPEDEF(netsnmp_ssh_addr_pair); if (addr_pair == NULL) { netsnmp_transport_free(t); return NULL; } t->data = addr_pair; t->data_length = sizeof(netsnmp_ssh_addr_pair); if (local) { #ifndef NETSNMP_NO_LISTEN_SUPPORT #ifdef SNMPSSHDOMAIN_USE_EXTERNAL_PIPE /* XXX: set t->local and t->local_length */ t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN; unaddr = &addr_pair->unix_socket_end; /* open a unix domain socket */ /* XXX: get data from the transport def for it's location */ unaddr->sun_family = AF_UNIX; if (NULL == sockpath) { sprintf(tmpsockpath, "%s/%s", get_persistent_directory(), DEFAULT_SOCK_NAME); sockpath = tmpsockpath; } snprintf(unaddr->sun_path, sizeof(unaddr->sun_path), "%s", sockpath); snprintf(addr_pair->socket_path, sizeof(addr_pair->socket_path), "%s", sockpath); t->sock = socket(PF_UNIX, SOCK_STREAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } /* set the SO_PASSCRED option so we can receive the remote uid */ { int one = 1; setsockopt(t->sock, SOL_SOCKET, SO_PASSCRED, (void *) &one, sizeof(one)); } unlink(unaddr->sun_path); rc = bind(t->sock, unaddr, SUN_LEN(unaddr)); if (rc != 0) { DEBUGMSGTL(("netsnmp_ssh_transport", "couldn't bind \"%s\", errno %d (%s)\n", unaddr->sun_path, errno, strerror(errno))); netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* set the socket permissions */ { /* * Apply any settings to the ownership/permissions of the * Sshdomain socket */ int sshdomain_sock_perm = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_SSHDOMAIN_SOCK_PERM); int sshdomain_sock_user = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_SSHDOMAIN_SOCK_USER); int sshdomain_sock_group = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_SSHDOMAIN_SOCK_GROUP); DEBUGMSGTL(("ssh", "here: %s, %d, %d, %d\n", unaddr->sun_path, sshdomain_sock_perm, sshdomain_sock_user, sshdomain_sock_group)); if (sshdomain_sock_perm != 0) { DEBUGMSGTL(("ssh", "Setting socket perms to %d\n", sshdomain_sock_perm)); chmod(unaddr->sun_path, sshdomain_sock_perm); } if (sshdomain_sock_user || sshdomain_sock_group) { /* * If either of user or group haven't been set, * then leave them unchanged. */ if (sshdomain_sock_user == 0 ) sshdomain_sock_user = -1; if (sshdomain_sock_group == 0 ) sshdomain_sock_group = -1; DEBUGMSGTL(("ssh", "Setting socket user/group to %d/%d\n", sshdomain_sock_user, sshdomain_sock_group)); chown(unaddr->sun_path, sshdomain_sock_user, sshdomain_sock_group); } } rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN); if (rc != 0) { DEBUGMSGTL(("netsnmp_ssh_transport", "couldn't listen to \"%s\", errno %d (%s)\n", unaddr->sun_path, errno, strerror(errno))); netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } #else /* we're called directly by sshd and use stdin/out */ /* for ssh on the server side we've been launched so bind to stdin/out */ /* nothing to do */ /* XXX: verify we're inside ssh */ t->sock = STDIN_FILENO; #endif /* ! SNMPSSHDOMAIN_USE_EXTERNAL_PIPE */ #else /* NETSNMP_NO_LISTEN_SUPPORT */ netsnmp_transport_free(t); return NULL; #endif /* NETSNMP_NO_LISTEN_SUPPORT */ } else { char *username; char *keyfilepub; char *keyfilepriv; /* use the requested user name */ /* XXX: default to the current user name on the system like ssh does */ username = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSH_USERNAME); if (!username || 0 == *username) { snmp_log(LOG_ERR, "You must specify a ssh username to use. See the snmp.conf manual page\n"); netsnmp_transport_free(t); return NULL; } /* use the requested public key file */ keyfilepub = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSH_PUBKEY); if (!keyfilepub || 0 == *keyfilepub) { /* XXX: default to ~/.ssh/id_rsa.pub */ snmp_log(LOG_ERR, "You must specify a ssh public key file to use. See the snmp.conf manual page\n"); netsnmp_transport_free(t); return NULL; } /* use the requested private key file */ keyfilepriv = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSH_PRIVKEY); if (!keyfilepriv || 0 == *keyfilepriv) { /* XXX: default to keyfilepub without the .pub suffix */ snmp_log(LOG_ERR, "You must specify a ssh private key file to use. See the snmp.conf manual page\n"); netsnmp_transport_free(t); return NULL; } /* xxx: need an ipv6 friendly one too (sigh) */ /* XXX: not ideal when structs don't actually match size wise */ memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in)); t->sock = socket(PF_INET, SOCK_STREAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } t->remote_length = sizeof(*addr); t->remote = netsnmp_memdup(addr, sizeof(*addr)); if (!t->remote) { netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* * This is a client-type session, so attempt to connect to the far * end. We don't go non-blocking here because it's not obvious what * you'd then do if you tried to do snmp_sends before the connection * had completed. So this can block. */ rc = connect(t->sock, addr, sizeof(struct sockaddr)); if (rc < 0) { netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* * Allow user to override the send and receive buffers. Default is * to use os default. Don't worry too much about errors -- * just plough on regardless. */ netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0); netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0); /* open the SSH session and channel */ addr_pair->session = libssh2_session_init(); if (libssh2_session_startup(addr_pair->session, t->sock)) { shutdown: snmp_log(LOG_ERR, "Failed to establish an SSH session\n"); netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* At this point we havn't authenticated, The first thing to do is check the hostkey's fingerprint against our known hosts Your app may have it hard coded, may go to a file, may present it to the user, that's your call */ fingerprint = libssh2_hostkey_hash(addr_pair->session, LIBSSH2_HOSTKEY_HASH_MD5); DEBUGMSGTL(("ssh", "Fingerprint: ")); for(i = 0; i < 16; i++) { DEBUGMSG(("ssh", "%02x", (unsigned char)fingerprint[i])); } DEBUGMSG(("ssh", "\n")); /* check what authentication methods are available */ userauthlist = libssh2_userauth_list(addr_pair->session, username, strlen(username)); DEBUGMSG(("ssh", "Authentication methods: %s\n", userauthlist)); /* XXX: allow other types */ /* XXX: 4 seems magic to me... */ if (strstr(userauthlist, "publickey") != NULL) { auth_pw |= 4; } /* XXX: hard coded paths and users */ if (auth_pw & 4) { /* public key */ if (libssh2_userauth_publickey_fromfile(addr_pair->session, username, keyfilepub, keyfilepriv, NULL)) { snmp_log(LOG_ERR,"Authentication by public key failed!\n"); goto shutdown; } else { DEBUGMSG(("ssh", "\tAuthentication by public key succeeded.\n")); } } else { snmp_log(LOG_ERR,"Authentication by public key failed!\n"); goto shutdown; } /* we've now authenticated both sides; contining onward ... */ /* Request a channel */ if (!(addr_pair->channel = libssh2_channel_open_session(addr_pair->session))) { snmp_log(LOG_ERR, "Unable to open a session\n"); goto shutdown; } /* Request a terminal with 'vanilla' terminal emulation * See /etc/termcap for more options */ /* XXX: needed? doubt it */ /* if (libssh2_channel_request_pty(addr_pair->channel, "vanilla")) { */ /* snmp_log(LOG_ERR, "Failed requesting pty\n"); */ /* goto shutdown; */ /* } */ if (libssh2_channel_subsystem(addr_pair->channel, "snmp")) { snmp_log(LOG_ERR, "Failed to request the ssh 'snmp' subsystem\n"); goto shutdown; } } DEBUGMSG(("ssh","Opened connection.\n")); /* * Message size is not limited by this transport (hence msgMaxSize * is equal to the maximum legal size of an SNMP message). */ t->msgMaxSize = SNMP_MAX_PACKET_LEN; t->f_recv = netsnmp_ssh_recv; t->f_send = netsnmp_ssh_send; t->f_close = netsnmp_ssh_close; t->f_accept = netsnmp_ssh_accept; t->f_fmtaddr = netsnmp_ssh_fmtaddr; return t; }
netsnmp_transport * netsnmp_transport_copy(netsnmp_transport *t) { netsnmp_transport *n = NULL; n = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (n == NULL) { return NULL; } memset(n, 0, sizeof(netsnmp_transport)); if (t->domain != NULL) { n->domain = t->domain; n->domain_length = t->domain_length; } else { n->domain = NULL; n->domain_length = 0; } if (t->local != NULL) { n->local = (u_char *) malloc(t->local_length); if (n->local == NULL) { netsnmp_transport_free(n); return NULL; } n->local_length = t->local_length; memcpy(n->local, t->local, t->local_length); } else { n->local = NULL; n->local_length = 0; } if (t->remote != NULL) { n->remote = (u_char *) malloc(t->remote_length); if (n->remote == NULL) { netsnmp_transport_free(n); return NULL; } n->remote_length = t->remote_length; memcpy(n->remote, t->remote, t->remote_length); } else { n->remote = NULL; n->remote_length = 0; } if (t->data != NULL && t->data_length > 0) { n->data = malloc(t->data_length); if (n->data == NULL) { netsnmp_transport_free(n); return NULL; } n->data_length = t->data_length; memcpy(n->data, t->data, t->data_length); } else { n->data = NULL; n->data_length = 0; } n->msgMaxSize = t->msgMaxSize; n->f_accept = t->f_accept; n->f_recv = t->f_recv; n->f_send = t->f_send; n->f_close = t->f_close; n->f_fmtaddr = t->f_fmtaddr; n->sock = t->sock; n->flags = t->flags; return n; }
netsnmp_transport * netsnmp_std_transport(const char *instring, size_t instring_len, const char *default_target) { netsnmp_transport *t; t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } memset(t, 0, sizeof(netsnmp_transport)); t->domain = netsnmp_snmpSTDDomain; t->domain_length = sizeof(netsnmp_snmpSTDDomain) / sizeof(netsnmp_snmpSTDDomain[0]); t->sock = 0; t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED; /* * Message size is not limited by this transport (hence msgMaxSize * is equal to the maximum legal size of an SNMP message). */ t->msgMaxSize = 0x7fffffff; t->f_recv = netsnmp_std_recv; t->f_send = netsnmp_std_send; t->f_close = netsnmp_std_close; t->f_accept = netsnmp_std_accept; t->f_fmtaddr = netsnmp_std_fmtaddr; /* * if instring is not null length, it specifies a path to a prog * XXX: plus args */ if (instring_len == 0 && default_target != NULL) { instring = default_target; instring_len = strlen(default_target); } if (instring_len != 0) { int infd[2], outfd[2]; /* sockets to and from the client */ int childpid; if (pipe(infd) || pipe(outfd)) { snmp_log(LOG_ERR, "Failed to create needed pipes for a STD transport"); netsnmp_transport_free(t); return NULL; } childpid = fork(); /* parentpid => childpid */ /* infd[1] => infd[0] */ /* outfd[0] <= outfd[1] */ if (childpid) { netsnmp_std_data *data; /* we're in the parent */ close(infd[0]); close(outfd[1]); data = SNMP_MALLOC_TYPEDEF(netsnmp_std_data); if (!data) { snmp_log(LOG_ERR, "snmpSTDDomain: memdup failed"); netsnmp_transport_free(t); return NULL; } t->data = data; t->data_length = sizeof(netsnmp_std_data); t->sock = outfd[0]; data->prog = strdup(instring); data->outfd = infd[1]; data->childpid = childpid; DEBUGMSGTL(("domain:std","parent. data=%x\n", t->data)); } else { /* we're in the child */ /* close stdin */ close(0); /* copy pipe output to stdout */ dup(infd[0]); /* close stdout */ close(1); /* copy pipe output to stdin */ dup(outfd[1]); /* close all the pipes themselves */ close(infd[0]); close(infd[1]); close(outfd[0]); close(outfd[1]); /* call exec */ system(instring); /* XXX: TODO: use exec form instead; needs args */ /* execv(instring, NULL); */ exit(0); /* ack... we should never ever get here */ snmp_log(LOG_ERR, "STD transport returned after execv()\n"); } } return t; }
/* * Open a session to the master agent. */ int subagent_open_master_session(void) { netsnmp_transport *t; netsnmp_session sess; DEBUGMSGTL(("agentx/subagent", "opening session...\n")); if (main_session) { snmp_log(LOG_WARNING, "AgentX session to master agent attempted to be re-opened."); return -1; } snmp_sess_init(&sess); sess.version = AGENTX_VERSION_1; sess.retries = SNMP_DEFAULT_RETRIES; sess.timeout = SNMP_DEFAULT_TIMEOUT; sess.flags |= SNMP_FLAGS_STREAM_SOCKET; sess.callback = handle_agentx_packet; sess.authenticator = NULL; t = netsnmp_transport_open_client( "agentx", netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET)); if (t == NULL) { /* * Diagnose snmp_open errors with the input * netsnmp_session pointer. */ if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS)) { char buf[1024]; const char *socket = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET); snprintf(buf, sizeof(buf), "Warning: " "Failed to connect to the agentx master agent (%s)", socket ? socket : "[NIL]"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { netsnmp_sess_log_error(LOG_WARNING, buf, &sess); } else { snmp_sess_perror(buf, &sess); } } return -1; } main_session = snmp_add_full(&sess, t, NULL, agentx_parse, NULL, NULL, agentx_realloc_build, agentx_check_packet, NULL); if (main_session == NULL) { if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS)) { char buf[1024]; snprintf(buf, sizeof(buf), "Error: " "Failed to create the agentx master agent session (%s)", netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET)); snmp_sess_perror(buf, &sess); } netsnmp_transport_free(t); return -1; } /* * I don't know why 1 is success instead of the usual 0 = noerr, * but that's what the function returns. */ if (1 != agentx_open_session(main_session)) { snmp_close(main_session); main_session = NULL; return -1; } if (add_trap_session(main_session, AGENTX_MSG_NOTIFY, 1, AGENTX_VERSION_1)) { DEBUGMSGTL(("agentx/subagent", " trap session registered OK\n")); } else { DEBUGMSGTL(("agentx/subagent", "trap session registration failed\n")); snmp_close(main_session); main_session = NULL; return -1; } agentx_register_callbacks(main_session); snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_INDEX_START, (void *) main_session); snmp_log(LOG_INFO, "NET-SNMP version %s AgentX subagent connected\n", netsnmp_get_version()); DEBUGMSGTL(("agentx/subagent", "opening session... DONE (%p)\n", main_session)); return 0; }
netsnmp_transport * netsnmp_aal5pvc_transport(struct sockaddr_atmpvc *addr, int local) { char *str = NULL; struct atm_qos qos; netsnmp_transport *t = NULL; if (addr == NULL || addr->sap_family != AF_ATMPVC) { return NULL; } t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } str = netsnmp_aal5pvc_fmtaddr(NULL, (void *) addr, sizeof(struct sockaddr_atmpvc)); DEBUGMSGTL(("netsnmp_aal5pvc", "open %s %s\n", local ? "local" : "remote", str)); free(str); memset(t, 0, sizeof(netsnmp_transport)); t->domain = netsnmp_AAL5PVCDomain; t->domain_length = sizeof(netsnmp_AAL5PVCDomain) / sizeof(netsnmp_AAL5PVCDomain[0]); t->sock = socket(PF_ATMPVC, SOCK_DGRAM, 0); if (t->sock < 0) { DEBUGMSGTL(("netsnmp_aal5pvc","socket failed (%s)\n",strerror(errno))); netsnmp_transport_free(t); return NULL; } DEBUGMSGTL(("netsnmp_aal5pvc", "fd %d opened\n", t->sock)); /* * Set up the QOS parameters. */ memset(&qos, 0, sizeof(struct atm_qos)); qos.aal = ATM_AAL5; qos.rxtp.traffic_class = ATM_UBR; qos.rxtp.max_sdu = SNMP_MAX_LEN; /* Hmm -- this is a bit small? */ qos.txtp = qos.rxtp; if (setsockopt(t->sock, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) { DEBUGMSGTL(("netsnmp_aal5pvc", "setsockopt failed (%s)\n", strerror(errno))); netsnmp_aal5pvc_close(t); netsnmp_transport_free(t); return NULL; } if (local) { t->local = (unsigned char*)malloc(8); if (t->local == NULL) { netsnmp_transport_free(t); return NULL; } t->local[0] = (addr->sap_addr.itf & 0xff00) >> 8; t->local[1] = (addr->sap_addr.itf & 0x00ff) >> 0; t->local[2] = (addr->sap_addr.vpi & 0xff00) >> 8; t->local[3] = (addr->sap_addr.vpi & 0x00ff) >> 0; t->local[4] = (addr->sap_addr.vci & 0xff000000) >> 24; t->local[5] = (addr->sap_addr.vci & 0x00ff0000) >> 16; t->local[6] = (addr->sap_addr.vci & 0x0000ff00) >> 8; t->local[7] = (addr->sap_addr.vci & 0x000000ff) >> 0; t->local_length = 8; if (bind(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr_atmpvc)) < 0) { DEBUGMSGTL(("netsnmp_aal5pvc", "bind failed (%s)\n", strerror(errno))); netsnmp_aal5pvc_close(t); netsnmp_transport_free(t); return NULL; } } else {
/* * Make a deep copy of an netsnmp_transport. */ netsnmp_transport * netsnmp_transport_copy(netsnmp_transport *t) { netsnmp_transport *n = NULL; if (t == NULL) { return NULL; } n = SNMP_MALLOC_TYPEDEF(netsnmp_transport); if (n == NULL) { return NULL; } if (t->domain != NULL) { n->domain = t->domain; n->domain_length = t->domain_length; } else { n->domain = NULL; n->domain_length = 0; } if (t->local != NULL) { n->local = (u_char *) malloc(t->local_length); if (n->local == NULL) { netsnmp_transport_free(n); return NULL; } n->local_length = t->local_length; memcpy(n->local, t->local, t->local_length); } else { n->local = NULL; n->local_length = 0; } if (t->remote != NULL) { n->remote = (u_char *) malloc(t->remote_length); if (n->remote == NULL) { netsnmp_transport_free(n); return NULL; } n->remote_length = t->remote_length; memcpy(n->remote, t->remote, t->remote_length); } else { n->remote = NULL; n->remote_length = 0; } if (t->data != NULL && t->data_length > 0) { n->data = malloc(t->data_length); if (n->data == NULL) { netsnmp_transport_free(n); return NULL; } n->data_length = t->data_length; memcpy(n->data, t->data, t->data_length); } else { n->data = NULL; n->data_length = 0; } n->msgMaxSize = t->msgMaxSize; n->f_accept = t->f_accept; n->f_recv = t->f_recv; n->f_send = t->f_send; n->f_close = t->f_close; n->f_copy = t->f_copy; n->f_config = t->f_config; n->f_fmtaddr = t->f_fmtaddr; n->sock = t->sock; n->flags = t->flags; n->base_transport = netsnmp_transport_copy(t->base_transport); /* give the transport a chance to do "special things" */ if (t->f_copy) t->f_copy(t, n); return n; }
netsnmp_transport * netsnmp_udp_transport(struct sockaddr_in *addr, int local) { netsnmp_transport *t = NULL; int rc = 0, udpbuf = (1 << 17); char *string = NULL; if (addr == NULL || addr->sin_family != AF_INET) { return NULL; } t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } #if __vms if (dbg_if_on) { #endif string = snmp_udp_fmtaddr(NULL, (void *) addr, sizeof(struct sockaddr_in)); DEBUGMSGTL(("snmp_udp", "open %s %s\n", local ? "local" : "remote", string)); free(string); #if __vms } #endif memset(t, 0, sizeof(netsnmp_transport)); t->domain = netsnmpUDPDomain; t->domain_length = netsnmpUDPDomain_len; t->sock = socket(PF_INET, SOCK_DGRAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } #ifdef SO_BSDCOMPAT /* * Patch for Linux. Without this, UDP packets that fail get an ICMP * response. Linux turns the failed ICMP response into an error message * and return value, unlike all other OS's. */ { int one = 1; setsockopt(t->sock, SOL_SOCKET, SO_BSDCOMPAT, (void *) &one, sizeof(one)); } #endif /*SO_BSDCOMPAT */ /* * Try to set the send and receive buffers to a reasonably large value, so * that we can send and receive big PDUs (defaults to 8192 bytes (!) on * Solaris, for instance). Don't worry too much about errors -- just * plough on regardless. */ #ifdef SO_SNDBUF if (setsockopt (t->sock, SOL_SOCKET, SO_SNDBUF, (void *) &udpbuf, sizeof(int)) != 0) { DEBUGMSGTL(("snmp_udp", "couldn't set SO_SNDBUF to %d bytes: %s\n", udpbuf, strerror(errno))); } #endif /*SO_SNDBUF */ #ifdef SO_RCVBUF if (setsockopt (t->sock, SOL_SOCKET, SO_RCVBUF, (void *) &udpbuf, sizeof(int)) != 0) { DEBUGMSGTL(("snmp_udp", "couldn't set SO_RCVBUF to %d bytes: %s\n", udpbuf, strerror(errno))); } #endif /*SO_RCVBUF */ if (local) { /* * This session is inteneded as a server, so we must bind on to the given * IP address, which may include an interface address, or could be * INADDR_ANY, but certainly includes a port number. */ t->local = malloc(6); if (t->local == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4); t->local[4] = (addr->sin_port & 0xff00) >> 8; t->local[5] = (addr->sin_port & 0x00ff) >> 0; t->local_length = 6; rc = bind(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr)); if (rc != 0) { snmp_udp_close(t); netsnmp_transport_free(t); return NULL; } t->data = NULL; t->data_length = 0; } else {
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::efF:g:hHI:L:m:M:no:O:PqsS:tu:vx:-:"; netsnmp_session *sess_list = NULL, *ss = NULL; netsnmp_transport *transport = NULL; int arg, i = 0; int uid = 0, gid = 0; char *cp, *listen_ports = NULL; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) int agentx_subagent = 1; #endif netsnmp_trapd_handler *traph; #ifndef WIN32 int prepared_sockets = 0; #endif #ifndef WIN32 #ifndef NETSNMP_NO_SYSTEMD /* check if systemd has sockets for us and don't close them */ prepared_sockets = netsnmp_sd_listen_fds(0); #endif /* * close all non-standard file descriptors we may have * inherited from the shell. */ if (!prepared_sockets) { for (i = getdtablesize() - 1; i > 2; --i) { (void) close(i); } } #endif /* #WIN32 */ #ifdef SIGTERM signal(SIGTERM, term_handler); #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif #ifdef SIGINT signal(SIGINT, term_handler); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif /* * register our configuration handlers now so -H properly displays them */ snmptrapd_register_configs( ); #ifdef NETSNMP_USE_MYSQL snmptrapd_register_sql_configs( ); #endif #ifdef NETSNMP_SECMOD_USM init_usm_conf( "snmptrapd" ); #endif /* NETSNMP_SECMOD_USM */ register_config_handler("snmptrapd", "snmpTrapdAddr", parse_trapd_address, free_trapd_address, "string"); register_config_handler("snmptrapd", "doNotLogTraps", parse_config_doNotLogTraps, NULL, "(1|yes|true|0|no|false)"); #if HAVE_GETPID register_config_handler("snmptrapd", "pidFile", parse_config_pidFile, NULL, "string"); #endif #ifdef HAVE_UNISTD_H register_config_handler("snmptrapd", "agentuser", parse_config_agentuser, NULL, "userid"); register_config_handler("snmptrapd", "agentgroup", parse_config_agentgroup, NULL, "groupid"); #endif register_config_handler("snmptrapd", "doNotFork", parse_config_doNotFork, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "ignoreAuthFailure", parse_config_ignoreAuthFailure, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "outputOption", parse_config_outputOption, NULL, "string"); /* * Add some options if they are available. */ #if HAVE_GETPID strcat(options, "p:"); #endif #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_log_syslogname(app_name_long); #else snmp_log_syslogname(app_name); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(); exit(0); } if (strcasecmp(optarg, "version") == 0) { version(); exit(0); } handle_long_opt(optarg); break; case 'a': dropauth = 1; break; case 'A': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES, 1); break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(); exit(1); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET, 1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'f': dofork = 0; break; case 'F': if (optarg != NULL) { if (( strncmp( optarg, "print", 5 ) == 0 ) || ( strncmp( optarg, "syslog", 6 ) == 0 ) || ( strncmp( optarg, "execute", 7 ) == 0 )) { /* New style: "type=format" */ trap1_fmt_str_remember = strdup(optarg); cp = strchr( trap1_fmt_str_remember, '=' ); if (cp) *cp = ' '; } else { /* Old style: implicitly "print=format" */ trap1_fmt_str_remember = malloc(strlen(optarg) + 7); sprintf( trap1_fmt_str_remember, "print %s", optarg ); } } else { usage(); exit(1); } break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, gid = atoi(optarg)); } else { usage(); exit(1); } break; #endif case 'h': usage(); exit(0); case 'H': init_agent("snmptrapd"); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE init_notification_log(); #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); #endif init_snmp("snmptrapd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(); } break; case 'S': fprintf(stderr, "Warning: -S option has been withdrawn; use -Ls <facility> instead\n"); exit(1); break; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(); exit(1); } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(); exit(1); } break; case 'n': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_NUMERIC_IP, 1); break; case 'o': fprintf(stderr, "Warning: -o option has been withdrawn; use -Lf <file> instead\n"); exit(1); break; case 'O': cp = snmp_out_toggle_options(optarg); if (cp != NULL) { fprintf(stderr, "Unknown output option passed to -O: %c\n", *cp); usage(); exit(1); } break; case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(); exit(1); } break; #if HAVE_GETPID case 'p': if (optarg != NULL) { parse_config_pidFile(NULL, optarg); } else { usage(); exit(1); } break; #endif case 'P': fprintf(stderr, "Warning: -P option has been withdrawn; use -f -Le instead\n"); exit(1); break; case 's': fprintf(stderr, "Warning: -s option has been withdrawn; use -Lsd instead\n"); exit(1); break; case 't': SyslogTrap++; break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; uid = strtoul(optarg, &ecp, 10); #if HAVE_GETPWNAM && HAVE_PWD_H if (*ecp) { struct passwd *info; info = getpwnam(optarg); uid = info ? info->pw_uid : -1; endpwent(); } #endif if (uid < 0) { fprintf(stderr, "Bad user id: %s\n", optarg); exit(1); } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(); exit(1); } break; #endif case 'v': version(); exit(0); break; case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(); exit(1); } break; default: fprintf(stderr, "invalid option: -%c\n", arg); usage(); exit(1); break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ for (i = optind; i < argc; i++) { char *astring; if (listen_ports != NULL) { astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", listen_ports, argv[i]); free(listen_ports); listen_ports = astring; } else { listen_ports = strdup(argv[i]); if (listen_ports == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } } } } SOCK_STARTUP; /* * I'm being lazy here, and not checking the * return value from these registration calls. * Don't try this at home, children! */ if (0 == snmp_get_do_logging()) { #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, syslog_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_syslog(); #else /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_stderr(); #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */ #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ } else { traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; } #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) /* * we're an agentx subagent? */ if (agentx_subagent) { /* * make us a agentx client. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); } #endif /* * don't fail if we can't do agentx (ie, socket not there, or not root) */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); /* * ignore any warning messages. */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS); /* * initialize the agent library */ init_agent("snmptrapd"); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) #ifdef NETSNMP_FEATURE_CHECKING netsnmp_feature_require(register_snmpEngine_scalars_context) #endif /* NETSNMP_FEATURE_CHECKING */ /* * initialize local modules */ if (agentx_subagent) { #ifdef USING_SNMPV3_SNMPENGINE_MODULE extern void register_snmpEngine_scalars_context(const char *); #endif subagent_init(); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE /* register the notification log table */ if (should_init("notificationLogMib")) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_NOTIF_LOG_CTX, "snmptrapd"); traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER, notification_handler); traph->authtypes = TRAP_AUTH_LOG; init_notification_log(); } #endif #ifdef USING_SNMPV3_SNMPENGINE_MODULE /* * register scalars from SNMP-FRAMEWORK-MIB::snmpEngineID group; * allows engineID probes via the master agent under the * snmptrapd context */ register_snmpEngine_scalars_context("snmptrapd"); #endif } #endif /* USING_AGENTX_SUBAGENT_MODULE && !NETSNMP_SNMPTRAPD_DISABLE_AGENTX */ /* register our authorization handler */ init_netsnmp_trapd_auth(); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) if (agentx_subagent) { #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE extern void init_register_nsVacm_context(const char *); #endif #ifdef USING_SNMPV3_USMUSER_MODULE #ifdef NETSNMP_FEATURE_CHECKING netsnmp_feature_require(init_register_usmUser_context) #endif /* NETSNMP_FEATURE_CHECKING */ extern void init_register_usmUser_context(const char *); /* register ourselves as having a USM user database */ init_register_usmUser_context("snmptrapd"); #endif #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE /* register net-snmp vacm extensions */ init_register_nsVacm_context("snmptrapd"); #endif #ifdef USING_TLSTM_MIB_SNMPTLSTMCERTTOTSNTABLE_MODULE init_snmpTlstmCertToTSNTable_context("snmptrapd"); #endif } #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); { /* set the default path to load */ char init_file[SNMP_MAXBUF]; snprintf(init_file, sizeof(init_file) - 1, "%s/%s", SNMPSHAREPATH, "snmp_perl_trapd.pl"); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PERL_INIT_FILE, init_file); } #endif /* * Initialize the world. */ init_snmp("snmptrapd"); #ifdef SIGHUP signal(SIGHUP, hup_handler); #endif if (trap1_fmt_str_remember) { parse_format( NULL, trap1_fmt_str_remember ); } if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) { /* * just starting up to process specific configuration and then * shutting down immediately. */ netsnmp_running = 0; } /* * if no logging options on command line or in conf files, use syslog */ if (0 == snmp_get_do_logging()) { #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_enable_syslog_ident(app_name_long, Facility); #else snmp_enable_syslog_ident(app_name, Facility); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ } if (listen_ports) cp = listen_ports; else cp = default_port; while (cp != NULL) { char *sep = strchr(cp, ','); if (sep != NULL) { *sep = 0; } transport = netsnmp_transport_open_server("snmptrap", cp); if (transport == NULL) { snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n", cp, errno, strerror(errno)); snmptrapd_close_sessions(sess_list); SOCK_CLEANUP; exit(1); } else { ss = snmptrapd_add_session(transport); if (ss == NULL) { /* * Shouldn't happen? We have already opened the transport * successfully so what could have gone wrong? */ snmptrapd_close_sessions(sess_list); netsnmp_transport_free(transport); snmp_log(LOG_ERR, "couldn't open snmp - %s", strerror(errno)); SOCK_CLEANUP; exit(1); } else { ss->next = sess_list; sess_list = ss; } } /* * Process next listen address, if there is one. */ if (sep != NULL) { *sep = ','; cp = sep + 1; } else { cp = NULL; } } SNMP_FREE(listen_ports); /* done with them */ #ifdef NETSNMP_USE_MYSQL if( netsnmp_mysql_init() ) { fprintf(stderr, "MySQL initialization failed\n"); exit(1); } #endif #ifndef WIN32 /* * fork the process to the background if we are not printing to stderr */ if (dofork && netsnmp_running) { int fd; switch (fork()) { case -1: fprintf(stderr, "bad fork - %s\n", strerror(errno)); _exit(1); case 0: /* * become process group leader */ if (setsid() == -1) { fprintf(stderr, "bad setsid - %s\n", strerror(errno)); _exit(1); } /* * if we are forked, we don't want to print out to stdout or stderr */ fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); break; default: _exit(0); } } #endif /* WIN32 */ #if HAVE_GETPID if (pid_file != NULL) { if ((PID = fopen(pid_file, "w")) == NULL) { snmp_log_perror("fopen"); exit(1); } fprintf(PID, "%d\n", (int) getpid()); fclose(PID); free_config_pidFile(); } #endif snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); /* * ignore early sighup during startup */ reconfig = 0; #if HAVE_UNISTD_H #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #endif /* * Let systemd know we're up. */ #ifndef NETSNMP_NO_SYSTEMD netsnmp_sd_notify(1, "READY=1\n"); if (prepared_sockets) /* * Clear the environment variable, we already processed all the sockets * by now. */ netsnmp_sd_listen_fds(1); #endif #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_RUNNING; #endif snmptrapd_main_loop(); if (snmp_get_do_logging()) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } snmp_log(LOG_INFO, "Stopping snmptrapd\n"); #ifdef NETSNMP_EMBEDDED_PERL shutdown_perl(); #endif snmptrapd_close_sessions(sess_list); snmp_shutdown("snmptrapd"); #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_STOPPED; #endif snmp_disable_log(); SOCK_CLEANUP; return 0; }
netsnmp_session * get_target_sessions(char *taglist, TargetFilterFunction * filterfunct, void *filterArg) { netsnmp_session *ret = NULL, thissess; struct targetAddrTable_struct *targaddrs; char buf[SPRINT_MAX_LEN]; char tags[MAX_TAGS][SPRINT_MAX_LEN], *cp; int numtags = 0, i; static struct targetParamTable_struct *param; DEBUGMSGTL(("target_sessions", "looking for: %s\n", taglist)); for (cp = taglist; cp && numtags < MAX_TAGS;) { cp = copy_nword(cp, tags[numtags], sizeof(tags[numtags])); DEBUGMSGTL(("target_sessions", " for: %d=%s\n", numtags, tags[numtags])); numtags++; } for (targaddrs = get_addrTable(); targaddrs; targaddrs = targaddrs->next) { /* * legal row? */ if (targaddrs->tDomain == NULL || targaddrs->tAddress == NULL || targaddrs->rowStatus != SNMP_ROW_ACTIVE) { DEBUGMSGTL(("target_sessions", " which is not ready yet\n")); continue; } if (netsnmp_tdomain_support (targaddrs->tDomain, targaddrs->tDomainLen, NULL, NULL) == 0) { snmp_log(LOG_ERR, "unsupported domain for target address table entry %s\n", targaddrs->name); } /* * check tag list to see if we match */ if (targaddrs->tagList) { /* * loop through tag list looking for requested tags */ for (cp = targaddrs->tagList; cp;) { cp = copy_nword(cp, buf, sizeof(buf)); for (i = 0; i < numtags; i++) { if (strcmp(buf, tags[i]) == 0) { /* * found a valid target table entry */ DEBUGMSGTL(("target_sessions", "found one: %s\n", tags[i])); if (targaddrs->params) { param = get_paramEntry(targaddrs->params); if (!param || param->rowStatus != SNMP_ROW_ACTIVE) { /* * parameter entry must exist and be active */ continue; } } else { /* * parameter entry must be specified */ continue; } /* * last chance for caller to opt-out. Call * filtering function */ if (filterfunct && (*(filterfunct)) (targaddrs, param, filterArg)) { continue; } if (targaddrs->storageType != ST_READONLY && targaddrs->sess && param->updateTime >= targaddrs->sessionCreationTime) { /* * parameters have changed, nuke the old session */ snmp_close(targaddrs->sess); targaddrs->sess = NULL; } /* * target session already exists? */ if (targaddrs->sess == NULL) { /* * create an appropriate snmp session and add * it to our return list */ netsnmp_transport *t = NULL; t = netsnmp_tdomain_transport_oid(targaddrs-> tDomain, targaddrs-> tDomainLen, targaddrs-> tAddress, targaddrs-> tAddressLen, 0); if (t == NULL) { DEBUGMSGTL(("target_sessions", "bad dest \"")); DEBUGMSGOID(("target_sessions", targaddrs->tDomain, targaddrs->tDomainLen)); DEBUGMSG(("target_sessions", "\", \"")); DEBUGMSGHEX(("target_sessions", targaddrs->tAddress, targaddrs->tAddressLen)); DEBUGMSG(("target_sessions", "\n")); continue; } else { char *dst_str = t->f_fmtaddr(t, NULL, 0); if (dst_str != NULL) { DEBUGMSGTL(("target_sessions", " to: %s\n", dst_str)); free(dst_str); } } memset(&thissess, 0, sizeof(thissess)); thissess.timeout = (targaddrs->timeout) * 1000; thissess.retries = targaddrs->retryCount; DEBUGMSGTL(("target_sessions", "timeout: %d -> %d\n", targaddrs->timeout, thissess.timeout)); if (param->mpModel == SNMP_VERSION_3 && param->secModel != 3) { snmp_log(LOG_ERR, "unsupported model/secmodel combo for target %s\n", targaddrs->name); /* * XXX: memleak */ netsnmp_transport_free(t); continue; } thissess.version = param->mpModel; if (param->mpModel == SNMP_VERSION_3) { thissess.securityName = param->secName; thissess.securityNameLen = strlen(thissess.securityName); thissess.securityLevel = param->secLevel; #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C) } else { thissess.community = (u_char *) strdup(param->secName); thissess.community_len = strlen((char *) thissess.community); #endif } targaddrs->sess = snmp_add(&thissess, t, NULL, NULL); targaddrs->sessionCreationTime = time(NULL); } if (targaddrs->sess) { if (ret) { targaddrs->sess->next = ret; } ret = targaddrs->sess; } else { snmp_sess_perror("target session", &thissess); } } } } } } return ret; }
netsnmp_transport * netsnmp_unix_transport(struct sockaddr_un *addr, int local) { netsnmp_transport *t = NULL; sockaddr_un_pair *sup = NULL; int rc = 0; char *string = NULL; if (addr == NULL || addr->sun_family != AF_UNIX) { return NULL; } t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } string = netsnmp_unix_fmtaddr(NULL, (void *)addr, sizeof(struct sockaddr_un)); DEBUGMSGTL(("netsnmp_unix", "open %s %s\n", local ? "local" : "remote", string)); free(string); memset(t, 0, sizeof(netsnmp_transport)); t->domain = netsnmp_UnixDomain; t->domain_length = sizeof(netsnmp_UnixDomain) / sizeof(netsnmp_UnixDomain[0]); t->data = malloc(sizeof(sockaddr_un_pair)); if (t->data == NULL) { netsnmp_transport_free(t); return NULL; } memset(t->data, 0, sizeof(sockaddr_un_pair)); t->data_length = sizeof(sockaddr_un_pair); sup = (sockaddr_un_pair *) t->data; t->sock = socket(PF_UNIX, SOCK_STREAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } t->flags = NETSNMP_TRANSPORT_FLAG_STREAM; if (local) { t->local = (u_char *)malloc(strlen(addr->sun_path)); if (t->local == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(t->local, addr->sun_path, strlen(addr->sun_path)); t->local_length = strlen(addr->sun_path); /* * This session is inteneded as a server, so we must bind to the given * path (unlinking it first, to avoid errors). */ t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN; unlink(addr->sun_path); rc = bind(t->sock, (struct sockaddr *) addr, SUN_LEN(addr)); if (rc != 0) { DEBUGMSGTL(("netsnmp_unix_transport", "couldn't bind \"%s\", errno %d (%s)\n", addr->sun_path, errno, strerror(errno))); netsnmp_unix_close(t); netsnmp_transport_free(t); return NULL; } /* * Save the address in the transport-specific data pointer for later * use by netsnmp_unix_close. */ sup->server.sun_family = AF_UNIX; strcpy(sup->server.sun_path, addr->sun_path); sup->local = 1; /* * Now sit here and listen for connections to arrive. */ rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN); if (rc != 0) { DEBUGMSGTL(("netsnmp_unix_transport", "couldn't listen to \"%s\", errno %d (%s)\n", addr->sun_path, errno, strerror(errno))); netsnmp_unix_close(t); netsnmp_transport_free(t); return NULL; } } else { t->remote = (u_char *)malloc(strlen(addr->sun_path)); if (t->remote == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(t->remote, addr->sun_path, strlen(addr->sun_path)); t->remote_length = strlen(addr->sun_path); rc = connect(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr_un)); if (rc != 0) { DEBUGMSGTL(("netsnmp_unix_transport", "couldn't connect to \"%s\", errno %d (%s)\n", addr->sun_path, errno, strerror(errno))); netsnmp_unix_close(t); netsnmp_transport_free(t); return NULL; } /* * Save the remote address in the transport-specific data pointer for * later use by netsnmp_unix_send. */ sup->server.sun_family = AF_UNIX; strcpy(sup->server.sun_path, addr->sun_path); sup->local = 0; netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0); netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0); } /* * Message size is not limited by this transport (hence msgMaxSize * is equal to the maximum legal size of an SNMP message). */ t->msgMaxSize = 0x7fffffff; t->f_recv = netsnmp_unix_recv; t->f_send = netsnmp_unix_send; t->f_close = netsnmp_unix_close; t->f_accept = netsnmp_unix_accept; t->f_fmtaddr = netsnmp_unix_fmtaddr; return t; }
void real_init_master(void) { netsnmp_session sess, *session = NULL; char *agentx_sockets; char *cp1; if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) return; if (netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET)) { agentx_sockets = strdup(netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET)); #ifdef NETSNMP_AGENTX_DOM_SOCK_ONLY if (agentx_sockets[0] != '/') { /* unix:/path */ if (agentx_sockets[5] != '/') { snmp_log(LOG_ERR, "Error: %s transport is not supported, disabling agentx/master.\n", agentx_sockets); SNMP_FREE(agentx_sockets); return; } } #endif } else { agentx_sockets = strdup(""); } DEBUGMSGTL(("agentx/master", "initializing...\n")); snmp_sess_init(&sess); sess.version = AGENTX_VERSION_1; sess.flags |= SNMP_FLAGS_STREAM_SOCKET; sess.timeout = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_TIMEOUT); sess.retries = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_RETRIES); #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN { int agentx_dir_perm = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_DIR_PERM); if (agentx_dir_perm == 0) agentx_dir_perm = NETSNMP_AGENT_DIRECTORY_MODE; netsnmp_unix_create_path_with_mode(agentx_dir_perm); } #endif cp1 = agentx_sockets; while (cp1) { netsnmp_transport *t; /* * If the AgentX socket string contains multiple descriptors, * then pick this apart and handle them one by one. * */ sess.peername = cp1; cp1 = strchr(sess.peername, ','); if (cp1 != NULL) { *cp1++ = '\0'; } /* * Let 'snmp_open' interpret the descriptor. */ sess.local_port = AGENTX_PORT; /* Indicate server & set default port */ sess.remote_port = 0; sess.callback = handle_master_agentx_packet; errno = 0; t = netsnmp_transport_open_server("agentx", sess.peername); if (t == NULL) { /* * diagnose snmp_open errors with the input netsnmp_session * pointer. */ char buf[1024]; if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { snprintf(buf, sizeof(buf), "Error: Couldn't open a master agentx socket to " "listen on (%s)", sess.peername); snmp_sess_perror(buf, &sess); exit(1); } else { snprintf(buf, sizeof(buf), "Warning: Couldn't open a master agentx socket to " "listen on (%s)", sess.peername); netsnmp_sess_log_error(LOG_WARNING, buf, &sess); } } else { #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN if (t->domain == netsnmp_UnixDomain && t->local != NULL) { /* * Apply any settings to the ownership/permissions of the * AgentX socket */ int agentx_sock_perm = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCK_PERM); int agentx_sock_user = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCK_USER); int agentx_sock_group = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCK_GROUP); char name[sizeof(struct sockaddr_un) + 1]; memcpy(name, t->local, t->local_length); name[t->local_length] = '\0'; if (agentx_sock_perm != 0) chmod(name, agentx_sock_perm); if (agentx_sock_user || agentx_sock_group) { /* * If either of user or group haven't been set, * then leave them unchanged. */ if (agentx_sock_user == 0 ) agentx_sock_user = -1; if (agentx_sock_group == 0 ) agentx_sock_group = -1; chown(name, agentx_sock_user, agentx_sock_group); } } #endif session = snmp_add_full(&sess, t, NULL, agentx_parse, NULL, NULL, agentx_realloc_build, agentx_check_packet, NULL); } if (session == NULL) { netsnmp_transport_free(t); } } #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN netsnmp_unix_dont_create_path(); #endif SNMP_FREE(agentx_sockets); DEBUGMSGTL(("agentx/master", "initializing... DONE\n")); }
netsnmp_session *get_target_sessions (char *taglist, TargetFilterFunction * filterfunct, void *filterArg) { netsnmp_session *ret = NULL, thissess; struct targetAddrTable_struct *targaddrs; char buf[SPRINT_MAX_LEN]; char tags[MAX_TAGS][SPRINT_MAX_LEN], *cp; int numtags = 0, i; #if defined(NETSNMP_TRANSPORT_DTLSUDP_DOMAIN) || defined(NETSNMP_TRANSPORT_TLSTCP_DOMAIN) int tls = 0; #endif static struct targetParamTable_struct *param; DEBUGMSGTL (("target_sessions", "looking for: %s\n", taglist)); for (cp = taglist; cp && numtags < MAX_TAGS;) { cp = copy_nword (cp, tags[numtags], sizeof (tags[numtags])); DEBUGMSGTL (("target_sessions", " for: %d=%s\n", numtags, tags[numtags])); numtags++; } for (targaddrs = get_addrTable (); targaddrs; targaddrs = targaddrs->next) { /* * legal row? */ if (targaddrs->tDomain == NULL || targaddrs->tAddress == NULL || targaddrs->rowStatus != SNMP_ROW_ACTIVE) { DEBUGMSGTL (("target_sessions", " which is not ready yet\n")); continue; } if (netsnmp_tdomain_support (targaddrs->tDomain, targaddrs->tDomainLen, NULL, NULL) == 0) { snmp_log (LOG_ERR, "unsupported domain for target address table entry %s\n", targaddrs->name); } /* * check tag list to see if we match */ if (targaddrs->tagList) { int matched = 0; /* * loop through tag list looking for requested tags */ for (cp = targaddrs->tagList; cp && !matched;) { cp = copy_nword (cp, buf, sizeof (buf)); for (i = 0; i < numtags && !matched; i++) { if (strcmp (buf, tags[i]) == 0) { /* * found a valid target table entry */ DEBUGMSGTL (("target_sessions", "found one: %s\n", tags[i])); if (targaddrs->params) { param = get_paramEntry (targaddrs->params); if (!param || param->rowStatus != SNMP_ROW_ACTIVE) { /* * parameter entry must exist and be active */ continue; } } else { /* * parameter entry must be specified */ continue; } /* * last chance for caller to opt-out. Call * filtering function */ if (filterfunct && (*(filterfunct)) (targaddrs, param, filterArg)) { continue; } /* * Only one notification per TargetAddrEntry, * rather than one per tag */ matched = 1; if (targaddrs->storageType != ST_READONLY && targaddrs->sess && param->updateTime >= targaddrs->sessionCreationTime) { /* * parameters have changed, nuke the old session */ snmp_close (targaddrs->sess); targaddrs->sess = NULL; } /* * target session already exists? */ if (targaddrs->sess == NULL) { /* * create an appropriate snmp session and add * it to our return list */ netsnmp_transport *t = NULL; t = netsnmp_tdomain_transport_oid (targaddrs->tDomain, targaddrs->tDomainLen, targaddrs->tAddress, targaddrs->tAddressLen, 0); if (t == NULL) { DEBUGMSGTL (("target_sessions", "bad dest \"")); DEBUGMSGOID (("target_sessions", targaddrs->tDomain, targaddrs->tDomainLen)); DEBUGMSG (("target_sessions", "\", \"")); DEBUGMSGHEX (("target_sessions", targaddrs->tAddress, targaddrs->tAddressLen)); DEBUGMSG (("target_sessions", "\n")); continue; } else { char *dst_str = t->f_fmtaddr (t, NULL, 0); if (dst_str != NULL) { DEBUGMSGTL (("target_sessions", " to: %s\n", dst_str)); free (dst_str); } } /* * if tDomain is tls related, check for tls config */ #ifdef NETSNMP_TRANSPORT_DTLSUDP_DOMAIN tls = snmp_oid_compare (targaddrs->tDomain, targaddrs->tDomainLen, netsnmpDTLSUDPDomain, netsnmpDTLSUDPDomain_len); #endif #ifdef NETSNMP_TRANSPORT_TLSTCP_DOMAIN if (tls) tls = snmp_oid_compare (targaddrs->tDomain, targaddrs->tDomainLen, netsnmpTLSTCPDomain, netsnmpTLSTCPDomain_len); #endif #if defined(NETSNMP_TRANSPORT_DTLSUDP_DOMAIN) || defined(NETSNMP_TRANSPORT_TLSTCP_DOMAIN) if (!tls) { netsnmp_cert *cert; char *server_id = NULL; DEBUGMSGTL (("target_sessions", " looking up our id: %s\n", targaddrs->params)); cert = netsnmp_cert_find (NS_CERT_IDENTITY, NS_CERTKEY_TARGET_PARAM, targaddrs->params); netsnmp_assert (t->f_config); if (cert) { DEBUGMSGTL (("target_sessions", " found fingerprint: %s\n", cert->fingerprint)); t->f_config (t, "localCert", cert->fingerprint); } DEBUGMSGTL (("target_sessions", " looking up their id: %s\n", targaddrs->name)); cert = netsnmp_cert_find (NS_CERT_REMOTE_PEER, NS_CERTKEY_TARGET_ADDR, targaddrs->name); if (cert) { DEBUGMSGTL (("target_sessions", " found fingerprint: %s\n", cert->fingerprint)); t->f_config (t, "peerCert", cert->fingerprint); } #ifndef NETSNMP_FEATURE_REMOVE_TLSTMADDR_GET_SERVERID server_id = netsnmp_tlstmAddr_get_serverId (targaddrs->name); #endif /* NETSNMP_FEATURE_REMOVE_TLSTMADDR_GET_SERVERID */ if (server_id) { DEBUGMSGTL (("target_sessions", " found serverId: %s\n", server_id)); t->f_config (t, "their_hostname", server_id); } } #endif memset (&thissess, 0, sizeof (thissess)); thissess.timeout = (targaddrs->timeout) * 1000; thissess.retries = targaddrs->retryCount; DEBUGMSGTL (("target_sessions", "timeout: %d -> %ld\n", targaddrs->timeout, thissess.timeout)); if (param->mpModel == SNMP_VERSION_3 && param->secModel != SNMP_SEC_MODEL_USM && param->secModel != SNMP_SEC_MODEL_TSM) { snmp_log (LOG_ERR, "unsupported mpModel/secModel combo %d/%d for target %s\n", param->mpModel, param->secModel, targaddrs->name); /* * XXX: memleak */ netsnmp_transport_free (t); continue; } thissess.paramName = strdup (param->paramName); thissess.version = param->mpModel; if (param->mpModel == SNMP_VERSION_3) { thissess.securityName = strdup (param->secName); thissess.securityNameLen = strlen (thissess.securityName); thissess.securityLevel = param->secLevel; thissess.securityModel = param->secModel; #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) } else { thissess.community = (u_char *) strdup (param->secName); thissess.community_len = strlen ((char *) thissess.community); #endif } thissess.flags |= SNMP_FLAGS_DONT_PROBE; targaddrs->sess = snmp_add (&thissess, t, NULL, NULL); thissess.flags &= ~SNMP_FLAGS_DONT_PROBE; targaddrs->sessionCreationTime = time (NULL); } if (targaddrs->sess) { if (NULL == targaddrs->sess->paramName) targaddrs->sess->paramName = strdup (param->paramName); targaddrs->sess->next = ret; ret = targaddrs->sess; } else { snmp_sess_perror ("target session", &thissess); } } } } } } return ret; }
netsnmp_transport * netsnmp_tcp6_transport(struct sockaddr_in6 *addr, int local) { netsnmp_transport *t = NULL; int rc = 0; char *str = NULL; if (addr == NULL || addr->sin6_family != AF_INET6) { return NULL; } t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); if (t == NULL) { return NULL; } memset(t, 0, sizeof(netsnmp_transport)); str = netsnmp_tcp6_fmtaddr(NULL, (void *)addr, sizeof(struct sockaddr_in6)); DEBUGMSGTL(("netsnmp_tcp6", "open %s %s\n", local ? "local" : "remote", str)); free(str); memset(t, 0, sizeof(netsnmp_transport)); t->data = malloc(sizeof(struct sockaddr_in6)); if (t->data == NULL) { netsnmp_transport_free(t); return NULL; } t->data_length = sizeof(struct sockaddr_in6); memcpy(t->data, addr, sizeof(struct sockaddr_in6)); t->domain = netsnmp_TCPIPv6Domain; t->domain_length = sizeof(netsnmp_TCPIPv6Domain) / sizeof(oid); t->sock = socket(PF_INET6, SOCK_STREAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } t->flags = NETSNMP_TRANSPORT_FLAG_STREAM; if (local) { int sockflags = 0, opt = 1; /* * This session is inteneded as a server, so we must bind on to the * given IP address, which may include an interface address, or could * be INADDR_ANY, but certainly includes a port number. */ #ifdef IPV6_V6ONLY /* Try to restrict PF_INET6 socket to IPv6 communications only. */ { int one=1; if (setsockopt(t->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) != 0) { DEBUGMSGTL(("netsnmp_udp6", "couldn't set IPV6_V6ONLY to %d bytes: %s\n", one, strerror(errno))); } } #endif t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN; t->local = (unsigned char*)malloc(18); if (t->local == NULL) { netsnmp_tcp6_close(t); netsnmp_transport_free(t); return NULL; } memcpy(t->local, addr->sin6_addr.s6_addr, 16); t->local[16] = (addr->sin6_port & 0xff00) >> 8; t->local[17] = (addr->sin6_port & 0x00ff) >> 0; t->local_length = 18; /* * We should set SO_REUSEADDR too. */ setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)); rc = bind(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr_in6)); if (rc != 0) { netsnmp_tcp6_close(t); netsnmp_transport_free(t); return NULL; } /* * Since we are going to be letting select() tell us when connections * are ready to be accept()ed, we need to make the socket n0n-blocking * to avoid the race condition described in W. R. Stevens, ``Unix * Network Programming Volume I Second Edition'', pp. 422--4, which * could otherwise wedge the agent. */ #ifdef WIN32 opt = 1; ioctlsocket(t->sock, FIONBIO, &opt); #else sockflags = fcntl(t->sock, F_GETFL, 0); fcntl(t->sock, F_SETFL, sockflags | O_NONBLOCK); #endif /* * Now sit here and wait for connections to arrive. */ rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN); if (rc != 0) { netsnmp_tcp6_close(t); netsnmp_transport_free(t); return NULL; } /* * no buffer size on listen socket - doesn't make sense */ } else {
netsnmp_transport * netsnmp_udpipv4base_transport(struct sockaddr_in *addr, int local) { netsnmp_transport *t = NULL; int rc = 0, rc2; char *str = NULL; char *client_socket = NULL; netsnmp_indexed_addr_pair addr_pair; socklen_t local_addr_len; if (addr == NULL || addr->sin_family != AF_INET) { return NULL; } memset(&addr_pair, 0, sizeof(netsnmp_indexed_addr_pair)); memcpy(&(addr_pair.remote_addr), addr, sizeof(struct sockaddr_in)); t = SNMP_MALLOC_TYPEDEF(netsnmp_transport); netsnmp_assert_or_return(t != NULL, NULL); str = netsnmp_udp_fmtaddr(NULL, (void *)&addr_pair, sizeof(netsnmp_indexed_addr_pair)); DEBUGMSGTL(("netsnmp_udpbase", "open %s %s\n", local ? "local" : "remote", str)); free(str); t->sock = socket(PF_INET, SOCK_DGRAM, 0); DEBUGMSGTL(("UDPBase", "openned socket %d as local=%d\n", t->sock, local)); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } _netsnmp_udp_sockopt_set(t->sock, local); if (local) { /* * This session is inteneded as a server, so we must bind on to the * given IP address, which may include an interface address, or could * be INADDR_ANY, but certainly includes a port number. */ t->local = (u_char *) malloc(6); if (t->local == NULL) { netsnmp_transport_free(t); return NULL; } memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4); t->local[4] = (htons(addr->sin_port) & 0xff00) >> 8; t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0; t->local_length = 6; #if defined(linux) && defined(IP_PKTINFO) { int sockopt = 1; if (setsockopt(t->sock, SOL_IP, IP_PKTINFO, &sockopt, sizeof sockopt) == -1) { DEBUGMSGTL(("netsnmp_udpbase", "couldn't set IP_PKTINFO: %s\n", strerror(errno))); netsnmp_transport_free(t); return NULL; } DEBUGMSGTL(("netsnmp_udpbase", "set IP_PKTINFO\n")); } #endif rc = bind(t->sock, (struct sockaddr *) addr, sizeof(struct sockaddr)); if (rc != 0) { netsnmp_socketbase_close(t); netsnmp_transport_free(t); return NULL; } t->data = NULL; t->data_length = 0; } else {
main(int argc, char *argv[]) #endif { char options[128] = "ac:CdD::efF:hHl:L:m:M:no:PqsS:tvO:-:"; netsnmp_session *sess_list = NULL, *ss = NULL; netsnmp_transport *transport = NULL; int arg, i = 0; int count, numfds, block; fd_set fdset; struct timeval timeout, *tvp; char *cp, *listen_ports = NULL; int agentx_subagent = 1, depmsg = 0; /* * register our configuration handlers now so -H properly displays them */ snmptrapd_register_configs( ); init_usm_conf( "snmptrapd" ); register_config_handler("snmptrapd", "snmptrapdaddr", parse_trapd_address, free_trapd_address, "string"); register_config_handler("snmptrapd", "doNotLogTraps", parse_config_doNotLogTraps, NULL, "(1|yes|true|0|no|false)"); #if HAVE_GETPID register_config_handler("snmptrapd", "pidFile", parse_config_pidFile, NULL, "string"); #endif register_config_handler("snmptrapd", "logOption", parse_config_logOption, NULL, "string"); register_config_handler("snmptrapd", "doNotFork", parse_config_doNotFork, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "printEventNumbers", parse_config_printEventNumbers, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "ignoreAuthFailure", parse_config_ignoreAuthFailure, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "outputOption", parse_config_outputOption, NULL, "string"); #ifdef WIN32 setvbuf(stdout, NULL, _IONBF, BUFSIZ); #else setvbuf(stdout, NULL, _IOLBF, BUFSIZ); #endif /* * Add some options if they are available. */ #if HAVE_GETPID strcat(options, "p:u:"); #endif snmp_log_syslogname(app_name); /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(); exit(0); } if (strcasecmp(optarg, "version") == 0) { version(); exit(0); } handle_long_opt(optarg); break; case 'a': dropauth = 1; break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(); exit(1); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': snmp_set_dump_packet(1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'e': Event++; break; case 'f': dofork = 0; break; case 'F': if (optarg != NULL) { trap1_fmt_str_remember = optarg; } else { usage(); exit(1); } break; case 'h': usage(); exit(0); case 'H': init_notification_log(); init_snmp("snmptrapd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); case 'S': fprintf(stderr, "Warning: -S option is deprecated; use -Ls <facility> instead\n"); depmsg = 1; if (optarg != NULL) { switch (*optarg) { case 'd': case 'D': Facility = LOG_DAEMON; break; case 'i': case 'I': Facility = LOG_INFO; break; case '0': Facility = LOG_LOCAL0; break; case '1': Facility = LOG_LOCAL1; break; case '2': Facility = LOG_LOCAL2; break; case '3': Facility = LOG_LOCAL3; break; case '4': Facility = LOG_LOCAL4; break; case '5': Facility = LOG_LOCAL5; break; case '6': Facility = LOG_LOCAL6; break; case '7': Facility = LOG_LOCAL7; break; default: fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg); usage(); exit(1); } } else { fprintf(stderr, "no syslog facility specified\n"); usage(); exit(1); } break; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(); exit(1); } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(); exit(1); } break; case 'n': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_NUMERIC_IP, 1); break; case 'o': fprintf(stderr, "Warning: -o option is deprecated; use -Lf <file> instead\n"); Print++; if (optarg != NULL) { logfile = optarg; snmp_enable_filelog(optarg, 0); } else { usage(); exit(1); } break; case 'O': cp = snmp_out_toggle_options(optarg); if (cp != NULL) { fprintf(stderr, "Unknown output option passed to -O: %c\n", *cp); usage(); exit(1); } break; case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(); exit(1); } Log++; break; case 'P': fprintf(stderr, "Warning: -P option is deprecated; use -f -Le instead\n"); dofork = 0; snmp_enable_stderrlog(); Print++; break; case 's': fprintf(stderr, "Warning: -s option is deprecated; use -Lsd instead\n"); depmsg = 1; Syslog++; break; case 't': SyslogTrap++; break; #if HAVE_GETPID case 'u': fprintf(stderr, "Warning: -u option is deprecated; use -p instead\n"); case 'p': if (optarg != NULL) { parse_config_pidFile(NULL, optarg); } else { usage(); exit(1); } break; #endif case 'v': version(); exit(0); break; default: fprintf(stderr, "invalid option: -%c\n", arg); usage(); exit(1); break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ for (i = optind; i < argc; i++) { char *astring; if (listen_ports != NULL) { astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", listen_ports, argv[i]); free(listen_ports); listen_ports = astring; } else { listen_ports = strdup(argv[i]); if (listen_ports == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } } } } /* * I'm being lazy here, and not checking the * return value from these registration calls. * Don't try this at home, children! */ if (!Log && !Print) { Syslog = 1; netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, syslog_handler); } else { netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); } netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER, notification_handler); if (Event) { netsnmp_add_traphandler(event_handler, risingAlarm, OID_LENGTH(risingAlarm)); netsnmp_add_traphandler(event_handler, fallingAlarm, OID_LENGTH(fallingAlarm)); netsnmp_add_traphandler(event_handler, unavailableAlarm, OID_LENGTH(unavailableAlarm)); /* XXX - might be worth setting some "magic data" * in the traphandler structure that 'event_handler' * can use to avoid checking the trap OID values. */ } #ifdef USING_AGENTX_SUBAGENT_MODULE /* * we're an agentx subagent? */ if (agentx_subagent) { /* * make us a agentx client. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); } #endif /* * don't fail if we can't do agentx (ie, socket not there, or not root) */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); /* * ignore any warning messages. */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS); /* * initialize the agent library */ init_agent("snmptrapd"); /* * initialize local modules */ if (agentx_subagent) { extern void init_register_usmUser_context(const char *); #ifdef USING_AGENTX_SUBAGENT_MODULE void init_subagent(void); init_subagent(); #endif /* register the notification log table */ init_notification_log(); /* register ourselves as having a USM user database */ init_register_usmUser_context("snmptrapd"); } #ifdef NETSNMP_EMBEDDED_PERL init_perl(); { /* set the default path to load */ char init_file[SNMP_MAXBUF]; snprintf(init_file, sizeof(init_file) - 1, "%s/%s", SNMPSHAREPATH, "snmp_perl_trapd.pl"); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PERL_INIT_FILE, init_file); } #endif /* * Initialize the world. */ init_snmp("snmptrapd"); if (trap1_fmt_str_remember) { free_trap1_fmt(); free_trap2_fmt(); print_format1 = strdup(trap1_fmt_str_remember); print_format2 = strdup(trap1_fmt_str_remember); } if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) { /* * just starting up to process specific configuration and then * shutting down immediately. */ running = 0; } #ifndef WIN32 /* * fork the process to the background if we are not printing to stderr */ if (dofork && running) { int fd; switch (fork()) { case -1: fprintf(stderr, "bad fork - %s\n", strerror(errno)); _exit(1); case 0: /* * become process group leader */ if (setsid() == -1) { fprintf(stderr, "bad setsid - %s\n", strerror(errno)); _exit(1); } /* * if we are forked, we don't want to print out to stdout or stderr */ fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); break; default: _exit(0); } } #endif /* WIN32 */ #if HAVE_GETPID if (pid_file != NULL) { if ((PID = fopen(pid_file, "w")) == NULL) { snmp_log_perror("fopen"); exit(1); } fprintf(PID, "%d\n", (int) getpid()); fclose(PID); free_config_pidFile(); } #endif if (Syslog) { snmp_enable_syslog_ident(app_name, Facility); snmp_log(LOG_INFO, "Starting snmptrapd %s\n", netsnmp_get_version()); if (depmsg) { snmp_log(LOG_WARNING, "-s and -S options are deprecated; use -Ls <facility> instead\n"); } } if (Print || Log) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Started.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } SOCK_STARTUP; if (listen_ports) cp = listen_ports; else cp = default_port; while (cp != NULL) { char *sep = strchr(cp, ','); char listen_name[128]; char *cp2 = strchr(cp, ':'); if (sep != NULL) { *sep = 0; } /* * Make sure this defaults to listening on port 162 */ if (!cp2) { snprintf(listen_name, sizeof(listen_name), "%s:162", cp); cp2 = listen_name; } else { cp2 = cp; } transport = netsnmp_tdomain_transport(cp2, 1, "udp"); if (transport == NULL) { snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n", cp2, errno, strerror(errno)); snmptrapd_close_sessions(sess_list); SOCK_CLEANUP; exit(1); } else { ss = snmptrapd_add_session(transport); if (ss == NULL) { /* * Shouldn't happen? We have already opened the transport * successfully so what could have gone wrong? */ snmptrapd_close_sessions(sess_list); netsnmp_transport_free(transport); if (Syslog) { snmp_log(LOG_ERR, "couldn't open snmp - %m"); } SOCK_CLEANUP; exit(1); } else { ss->next = sess_list; sess_list = ss; } } /* * Process next listen address, if there is one. */ if (sep != NULL) { *sep = ','; cp = sep + 1; } else { cp = NULL; } } signal(SIGTERM, term_handler); #ifdef SIGHUP signal(SIGHUP, hup_handler); #endif signal(SIGINT, term_handler); #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_RUNNING; #endif while (running) { if (reconfig) { if (Print || Log) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); /* * If we are logging to a file, receipt of SIGHUP also * indicates the the log file should be closed and * re-opened. This is useful for users that want to * rotate logs in a more predictable manner. */ if (logfile) snmp_enable_filelog(logfile, 1); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Reconfigured.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } if (Syslog) snmp_log(LOG_INFO, "Snmptrapd reconfiguring"); trapd_update_config(); if (trap1_fmt_str_remember) { free_trap1_fmt(); print_format1 = strdup(trap1_fmt_str_remember); } reconfig = 0; } numfds = 0; FD_ZERO(&fdset); block = 0; tvp = &timeout; timerclear(tvp); tvp->tv_sec = 5; snmp_select_info(&numfds, &fdset, tvp, &block); if (block == 1) tvp = NULL; /* block without timeout */ count = select(numfds, &fdset, 0, 0, tvp); gettimeofday(&Now, 0); if (count > 0) { snmp_read(&fdset); } else switch (count) { case 0: snmp_timeout(); break; case -1: if (errno == EINTR) continue; snmp_log_perror("select"); running = 0; break; default: fprintf(stderr, "select returned %d\n", count); running = 0; } run_alarms(); } if (Print || Log) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } if (Syslog) { snmp_log(LOG_INFO, "Stopping snmptrapd"); } snmptrapd_close_sessions(sess_list); snmp_shutdown("snmptrapd"); #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_STOPPED; #endif snmp_disable_log(); SOCK_CLEANUP; return 0; }