You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-11-05 04:50:35 +03:00
1651 lines
48 KiB
C
1651 lines
48 KiB
C
/*
|
|
* snmpv3.c
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
#ifdef HAVE_LIMITS_H
|
|
#include <limits.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
|
|
#if TIME_WITH_SYS_TIME
|
|
# ifdef WIN32
|
|
# include <sys/timeb.h>
|
|
# else
|
|
# include <sys/time.h>
|
|
# endif
|
|
# include <time.h>
|
|
#else
|
|
# if HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
# else
|
|
# include <time.h>
|
|
# endif
|
|
#endif
|
|
#if HAVE_SYS_TIMES_H
|
|
#include <sys/times.h>
|
|
#endif
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#if HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#if HAVE_WINSOCK_H
|
|
#include <winsock.h>
|
|
#endif
|
|
#if HAVE_SYS_SOCKET_H
|
|
#include <sys/socket.h>
|
|
#endif
|
|
#if HAVE_NETDB_H
|
|
#include <netdb.h>
|
|
#endif
|
|
#if HAVE_STDLIB_H
|
|
# include <stdlib.h>
|
|
#endif
|
|
|
|
/*
|
|
* Stuff needed for getHwAddress(...)
|
|
*/
|
|
#ifdef HAVE_SYS_IOCTL_H
|
|
# include <sys/ioctl.h>
|
|
#endif
|
|
#ifdef HAVE_NET_IF_H
|
|
# include <net/if.h>
|
|
#endif
|
|
|
|
#if HAVE_DMALLOC_H
|
|
#include <dmalloc.h>
|
|
#endif
|
|
|
|
#include <net-snmp/types.h>
|
|
#include <net-snmp/output_api.h>
|
|
#include <net-snmp/config_api.h>
|
|
#include <net-snmp/utilities.h>
|
|
|
|
#include <net-snmp/library/snmpv3.h>
|
|
#include <net-snmp/library/callback.h>
|
|
#include <net-snmp/library/snmp_api.h>
|
|
#include <net-snmp/library/lcd_time.h>
|
|
#include <net-snmp/library/scapi.h>
|
|
#include <net-snmp/library/keytools.h>
|
|
#include <net-snmp/library/lcd_time.h>
|
|
#include <net-snmp/library/snmp_secmod.h>
|
|
#include <net-snmp/library/snmpusm.h>
|
|
#include <net-snmp/library/transform_oids.h>
|
|
|
|
static u_long engineBoots = 1;
|
|
static unsigned int engineIDType = ENGINEID_TYPE_NETSNMP_RND;
|
|
static unsigned char *engineID = NULL;
|
|
static size_t engineIDLength = 0;
|
|
static unsigned char *engineIDNic = NULL;
|
|
static unsigned int engineIDIsSet = 0; /* flag if ID set by config */
|
|
static unsigned char *oldEngineID = NULL;
|
|
static size_t oldEngineIDLength = 0;
|
|
static struct timeval snmpv3starttime;
|
|
|
|
/*
|
|
* Set up default snmpv3 parameter value storage.
|
|
*/
|
|
static const oid *defaultAuthType = NULL;
|
|
static size_t defaultAuthTypeLen = 0;
|
|
static const oid *defaultPrivType = NULL;
|
|
static size_t defaultPrivTypeLen = 0;
|
|
|
|
/* this is probably an over-kill ifdef, but why not */
|
|
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_UNISTD_H) && defined(HAVE_TIMES) && defined(_SC_CLK_TCK) && defined(HAVE_SYSCONF) && defined(UINT_MAX)
|
|
|
|
#define SNMP_USE_TIMES 1
|
|
|
|
static clock_t snmpv3startClock;
|
|
static long clockticks = 0;
|
|
static unsigned int lastcalltime = 0;
|
|
static unsigned int wrapcounter = 0;
|
|
|
|
#endif /* times() tests */
|
|
|
|
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
|
|
static int getHwAddress(const char *networkDevice, char *addressOut);
|
|
#endif
|
|
|
|
void
|
|
snmpv3_authtype_conf(const char *word, char *cptr)
|
|
{
|
|
#ifndef DISABLE_MD5
|
|
if (strcasecmp(cptr, "MD5") == 0)
|
|
defaultAuthType = usmHMACMD5AuthProtocol;
|
|
else
|
|
#endif
|
|
if (strcasecmp(cptr, "SHA") == 0)
|
|
defaultAuthType = usmHMACSHA1AuthProtocol;
|
|
else
|
|
config_perror("Unknown authentication type");
|
|
defaultAuthTypeLen = USM_LENGTH_OID_TRANSFORM;
|
|
DEBUGMSGTL(("snmpv3", "set default authentication type: %s\n", cptr));
|
|
}
|
|
|
|
const oid *
|
|
get_default_authtype(size_t * len)
|
|
{
|
|
if (defaultAuthType == NULL) {
|
|
defaultAuthType = SNMP_DEFAULT_AUTH_PROTO;
|
|
defaultAuthTypeLen = SNMP_DEFAULT_AUTH_PROTOLEN;
|
|
}
|
|
if (len)
|
|
*len = defaultAuthTypeLen;
|
|
return defaultAuthType;
|
|
}
|
|
|
|
void
|
|
snmpv3_privtype_conf(const char *word, char *cptr)
|
|
{
|
|
int testcase = 0;
|
|
|
|
#ifndef DISABLE_DES
|
|
if (strcasecmp(cptr, "DES") == 0) {
|
|
testcase = 1;
|
|
defaultPrivType = usmDESPrivProtocol;
|
|
}
|
|
#endif
|
|
|
|
#if HAVE_AES
|
|
/* XXX AES: assumes oid length == des oid length */
|
|
if (strcasecmp(cptr, "AES128") == 0 ||
|
|
strcasecmp(cptr, "AES") == 0) {
|
|
testcase = 1;
|
|
defaultPrivType = usmAES128PrivProtocol;
|
|
}
|
|
#endif
|
|
if (testcase == 0)
|
|
config_perror("Unknown privacy type");
|
|
defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN;
|
|
DEBUGMSGTL(("snmpv3", "set default privacy type: %s\n", cptr));
|
|
}
|
|
|
|
const oid *
|
|
get_default_privtype(size_t * len)
|
|
{
|
|
if (defaultPrivType == NULL) {
|
|
#ifndef DISABLE_DES
|
|
defaultPrivType = usmDESPrivProtocol;
|
|
#else
|
|
defaultPrivType = usmAESPrivProtocol;
|
|
#endif
|
|
defaultPrivTypeLen = USM_LENGTH_OID_TRANSFORM;
|
|
}
|
|
if (len)
|
|
*len = defaultPrivTypeLen;
|
|
return defaultPrivType;
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* snmpv3_secLevel_conf
|
|
*
|
|
* Parameters:
|
|
* *word
|
|
* *cptr
|
|
*
|
|
* Line syntax:
|
|
* defSecurityLevel "noAuthNoPriv" | "authNoPriv" | "authPriv"
|
|
*/
|
|
void
|
|
snmpv3_secLevel_conf(const char *word, char *cptr)
|
|
{
|
|
char buf[1024];
|
|
|
|
if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 ||
|
|
strcasecmp(cptr, "nanp") == 0) {
|
|
netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_NOAUTH);
|
|
} else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 ||
|
|
strcasecmp(cptr, "anp") == 0) {
|
|
netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHNOPRIV);
|
|
} else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 ||
|
|
strcasecmp(cptr, "ap") == 0) {
|
|
netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHPRIV);
|
|
} else {
|
|
snprintf(buf, sizeof(buf), "Unknown security level: %s", cptr);
|
|
buf[ sizeof(buf)-1 ] = 0;
|
|
config_perror(buf);
|
|
}
|
|
DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %d\n", cptr,
|
|
netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_SECLEVEL)));
|
|
}
|
|
|
|
|
|
int
|
|
snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz,
|
|
char **Xpsz, int argc, char *const *argv)
|
|
{
|
|
char *cp = optarg;
|
|
int testcase;
|
|
optarg++;
|
|
/*
|
|
* Support '... -3x=value ....' syntax
|
|
*/
|
|
if (*optarg == '=') {
|
|
optarg++;
|
|
}
|
|
/*
|
|
* and '.... "-3x value" ....' (*with* the quotes)
|
|
*/
|
|
while (*optarg && isspace(*optarg)) {
|
|
optarg++;
|
|
}
|
|
/*
|
|
* Finally, handle ".... -3x value ...." syntax
|
|
* (*without* surrounding quotes)
|
|
*/
|
|
if (!*optarg) {
|
|
/*
|
|
* We've run off the end of the argument
|
|
* so move on the the next.
|
|
*/
|
|
optarg = argv[optind++];
|
|
if (optind > argc) {
|
|
fprintf(stderr,
|
|
"Missing argument after SNMPv3 '-3%c' option.\n", *cp);
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
switch (*cp) {
|
|
|
|
case 'Z':
|
|
session->engineBoots = strtoul(optarg, NULL, 10);
|
|
if (session->engineBoots == 0 || !isdigit(optarg[0])) {
|
|
fprintf(stderr, "Need engine boots value after -3Z flag.\n");
|
|
return (-1);
|
|
}
|
|
cp = strchr(optarg, ',');
|
|
if (cp && *(++cp) && isdigit(*cp))
|
|
session->engineTime = strtoul(cp, NULL, 10);
|
|
else {
|
|
fprintf(stderr, "Need engine time value after -3Z flag.\n");
|
|
return (-1);
|
|
}
|
|
break;
|
|
|
|
case 'e':{
|
|
size_t ebuf_len = 32, eout_len = 0;
|
|
u_char *ebuf = (u_char *) malloc(ebuf_len);
|
|
|
|
if (ebuf == NULL) {
|
|
fprintf(stderr, "malloc failure processing -3e flag.\n");
|
|
return (-1);
|
|
}
|
|
if (!snmp_hex_to_binary
|
|
(&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
|
|
fprintf(stderr, "Bad engine ID value after -3e flag.\n");
|
|
SNMP_FREE(ebuf);
|
|
return (-1);
|
|
}
|
|
session->securityEngineID = ebuf;
|
|
session->securityEngineIDLen = eout_len;
|
|
break;
|
|
}
|
|
|
|
case 'E':{
|
|
size_t ebuf_len = 32, eout_len = 0;
|
|
u_char *ebuf = (u_char *) malloc(ebuf_len);
|
|
|
|
if (ebuf == NULL) {
|
|
fprintf(stderr, "malloc failure processing -3E flag.\n");
|
|
return (-1);
|
|
}
|
|
if (!snmp_hex_to_binary
|
|
(&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
|
|
fprintf(stderr, "Bad engine ID value after -3E flag.\n");
|
|
SNMP_FREE(ebuf);
|
|
return (-1);
|
|
}
|
|
session->contextEngineID = ebuf;
|
|
session->contextEngineIDLen = eout_len;
|
|
break;
|
|
}
|
|
|
|
case 'n':
|
|
session->contextName = optarg;
|
|
session->contextNameLen = strlen(optarg);
|
|
break;
|
|
|
|
case 'u':
|
|
session->securityName = optarg;
|
|
session->securityNameLen = strlen(optarg);
|
|
break;
|
|
|
|
case 'l':
|
|
if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
|
|
!strcasecmp(optarg, "nanp")) {
|
|
session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
|
|
} else if (!strcasecmp(optarg, "authNoPriv")
|
|
|| !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
|
|
session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
|
|
} else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
|
|
|| !strcasecmp(optarg, "ap")) {
|
|
session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
|
|
} else {
|
|
fprintf(stderr,
|
|
"Invalid security level specified after -3l flag: %s\n",
|
|
optarg);
|
|
return (-1);
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
#ifndef DISABLE_MD5
|
|
if (!strcasecmp(optarg, "MD5")) {
|
|
session->securityAuthProto = usmHMACMD5AuthProtocol;
|
|
session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
|
|
} else
|
|
#endif
|
|
if (!strcasecmp(optarg, "SHA")) {
|
|
session->securityAuthProto = usmHMACSHA1AuthProtocol;
|
|
session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
|
|
} else {
|
|
fprintf(stderr,
|
|
"Invalid authentication protocol specified after -3a flag: %s\n",
|
|
optarg);
|
|
return (-1);
|
|
}
|
|
break;
|
|
|
|
case 'x':
|
|
testcase = 0;
|
|
#ifndef DISABLE_DES
|
|
if (!strcasecmp(optarg, "DES")) {
|
|
session->securityPrivProto = usmDESPrivProtocol;
|
|
session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
|
|
testcase = 1;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_AES
|
|
if (!strcasecmp(optarg, "AES128") ||
|
|
strcasecmp(optarg, "AES")) {
|
|
session->securityPrivProto = usmAES128PrivProtocol;
|
|
session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
|
|
testcase = 1;
|
|
}
|
|
#endif
|
|
if (testcase == 0) {
|
|
fprintf(stderr,
|
|
"Invalid privacy protocol specified after -3x flag: %s\n",
|
|
optarg);
|
|
return (-1);
|
|
}
|
|
break;
|
|
|
|
case 'A':
|
|
*Apsz = optarg;
|
|
break;
|
|
|
|
case 'X':
|
|
*Xpsz = optarg;
|
|
break;
|
|
|
|
case 'm': {
|
|
size_t bufSize = sizeof(session->securityAuthKey);
|
|
u_char *tmpp = session->securityAuthKey;
|
|
if (!snmp_hex_to_binary(&tmpp, &bufSize,
|
|
&session->securityAuthKeyLen, 0, optarg)) {
|
|
fprintf(stderr, "Bad key value after -3m flag.\n");
|
|
return (-1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'M': {
|
|
size_t bufSize = sizeof(session->securityPrivKey);
|
|
u_char *tmpp = session->securityPrivKey;
|
|
if (!snmp_hex_to_binary(&tmpp, &bufSize,
|
|
&session->securityPrivKeyLen, 0, optarg)) {
|
|
fprintf(stderr, "Bad key value after -3M flag.\n");
|
|
return (-1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'k': {
|
|
size_t kbuf_len = 32, kout_len = 0;
|
|
u_char *kbuf = (u_char *) malloc(kbuf_len);
|
|
|
|
if (kbuf == NULL) {
|
|
fprintf(stderr, "malloc failure processing -3k flag.\n");
|
|
return (-1);
|
|
}
|
|
if (!snmp_hex_to_binary
|
|
(&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
|
|
fprintf(stderr, "Bad key value after -3k flag.\n");
|
|
SNMP_FREE(kbuf);
|
|
return (-1);
|
|
}
|
|
session->securityAuthLocalKey = kbuf;
|
|
session->securityAuthLocalKeyLen = kout_len;
|
|
break;
|
|
}
|
|
|
|
case 'K': {
|
|
size_t kbuf_len = 32, kout_len = 0;
|
|
u_char *kbuf = (u_char *) malloc(kbuf_len);
|
|
|
|
if (kbuf == NULL) {
|
|
fprintf(stderr, "malloc failure processing -3K flag.\n");
|
|
return (-1);
|
|
}
|
|
if (!snmp_hex_to_binary
|
|
(&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
|
|
fprintf(stderr, "Bad key value after -3K flag.\n");
|
|
SNMP_FREE(kbuf);
|
|
return (-1);
|
|
}
|
|
session->securityPrivLocalKey = kbuf;
|
|
session->securityPrivLocalKeyLen = kout_len;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", *cp);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* setup_engineID
|
|
*
|
|
* Parameters:
|
|
* **eidp
|
|
* *text Printable (?) text to be plugged into the snmpEngineID.
|
|
*
|
|
* Return:
|
|
* Length of allocated engineID string in bytes, -OR-
|
|
* -1 on error.
|
|
*
|
|
*
|
|
* Create an snmpEngineID using text and the local IP address. If eidp
|
|
* is defined, use it to return a pointer to the newly allocated data.
|
|
* Otherwise, use the result to define engineID defined in this module.
|
|
*
|
|
* Line syntax:
|
|
* engineID <text> | NULL
|
|
*
|
|
* XXX What if a node has multiple interfaces?
|
|
* XXX What if multiple engines all choose the same address?
|
|
* (answer: You're screwed, because you might need a kul database
|
|
* which is dependant on the current engineID. Enumeration and other
|
|
* tricks won't work).
|
|
*/
|
|
int
|
|
setup_engineID(u_char ** eidp, const char *text)
|
|
{
|
|
int enterpriseid = htonl(ENTERPRISE_OID),
|
|
netsnmpoid = htonl(NETSNMP_OID),
|
|
localsetup = (eidp) ? 0 : 1;
|
|
|
|
/*
|
|
* Use local engineID if *eidp == NULL.
|
|
*/
|
|
#ifdef HAVE_GETHOSTNAME
|
|
u_char buf[SNMP_MAXBUF_SMALL];
|
|
struct hostent *hent = NULL;
|
|
#endif
|
|
u_char *bufp = NULL;
|
|
size_t len;
|
|
int localEngineIDType = engineIDType;
|
|
int tmpint;
|
|
time_t tmptime;
|
|
|
|
engineIDIsSet = 1;
|
|
|
|
#ifdef HAVE_GETHOSTNAME
|
|
#ifdef AF_INET6
|
|
/*
|
|
* see if they selected IPV4 or IPV6 support
|
|
*/
|
|
if ((ENGINEID_TYPE_IPV6 == localEngineIDType) ||
|
|
(ENGINEID_TYPE_IPV4 == localEngineIDType)) {
|
|
/*
|
|
* get the host name and save the information
|
|
*/
|
|
gethostname((char *) buf, sizeof(buf));
|
|
hent = gethostbyname((char *) buf);
|
|
if (hent && hent->h_addrtype == AF_INET6) {
|
|
localEngineIDType = ENGINEID_TYPE_IPV6;
|
|
} else {
|
|
/*
|
|
* Not IPV6 so we go with default
|
|
*/
|
|
localEngineIDType = ENGINEID_TYPE_IPV4;
|
|
}
|
|
}
|
|
#else
|
|
/*
|
|
* No IPV6 support. Check if they selected IPV6 engineID type.
|
|
* If so make it IPV4 instead
|
|
*/
|
|
if (ENGINEID_TYPE_IPV6 == localEngineIDType) {
|
|
localEngineIDType = ENGINEID_TYPE_IPV4;
|
|
}
|
|
if (ENGINEID_TYPE_IPV4 == localEngineIDType) {
|
|
/*
|
|
* get the host name and save the information
|
|
*/
|
|
gethostname((char *) buf, sizeof(buf));
|
|
hent = gethostbyname((char *) buf);
|
|
}
|
|
#endif
|
|
#endif /* HAVE_GETHOSTNAME */
|
|
|
|
/*
|
|
* Determine if we have text and if so setup our localEngineIDType
|
|
* * appropriately.
|
|
*/
|
|
if (NULL != text) {
|
|
engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT;
|
|
}
|
|
/*
|
|
* Determine length of the engineID string.
|
|
*/
|
|
len = 5; /* always have 5 leading bytes */
|
|
switch (localEngineIDType) {
|
|
case ENGINEID_TYPE_TEXT:
|
|
len += strlen(text); /* 5 leading bytes+text. No NULL char */
|
|
break;
|
|
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
|
|
case ENGINEID_TYPE_MACADDR: /* MAC address */
|
|
len += 6; /* + 6 bytes for MAC address */
|
|
break;
|
|
#endif
|
|
case ENGINEID_TYPE_IPV4: /* IPv4 */
|
|
len += 4; /* + 4 byte IPV4 address */
|
|
break;
|
|
case ENGINEID_TYPE_IPV6: /* IPv6 */
|
|
len += 16; /* + 16 byte IPV6 address */
|
|
break;
|
|
case ENGINEID_TYPE_NETSNMP_RND: /* Net-SNMP specific encoding */
|
|
if (engineID) /* already setup, keep current value */
|
|
return engineIDLength;
|
|
if (oldEngineID) {
|
|
len = oldEngineIDLength;
|
|
} else {
|
|
len += sizeof(int) + sizeof(time_t);
|
|
}
|
|
break;
|
|
default:
|
|
snmp_log(LOG_ERR,
|
|
"Unknown EngineID type requested for setup (%d). Using IPv4.\n",
|
|
localEngineIDType);
|
|
localEngineIDType = ENGINEID_TYPE_IPV4; /* make into IPV4 */
|
|
len += 4; /* + 4 byte IPv4 address */
|
|
break;
|
|
} /* switch */
|
|
|
|
|
|
/*
|
|
* Allocate memory and store enterprise ID.
|
|
*/
|
|
if ((bufp = (u_char *) malloc(len)) == NULL) {
|
|
snmp_log_perror("setup_engineID malloc");
|
|
return -1;
|
|
}
|
|
if (localEngineIDType == ENGINEID_TYPE_NETSNMP_RND)
|
|
/*
|
|
* we must use the net-snmp enterprise id here, regardless
|
|
*/
|
|
memcpy(bufp, &netsnmpoid, sizeof(netsnmpoid)); /* XXX Must be 4 bytes! */
|
|
else
|
|
memcpy(bufp, &enterpriseid, sizeof(enterpriseid)); /* XXX Must be 4 bytes! */
|
|
|
|
bufp[0] |= 0x80;
|
|
|
|
|
|
/*
|
|
* Store the given text -OR- the first found IP address
|
|
* -OR- the MAC address -OR- random elements
|
|
* (the latter being the recommended default)
|
|
*/
|
|
switch (localEngineIDType) {
|
|
case ENGINEID_TYPE_NETSNMP_RND:
|
|
if (oldEngineID) {
|
|
/*
|
|
* keep our previous notion of the engineID
|
|
*/
|
|
memcpy(bufp, oldEngineID, oldEngineIDLength);
|
|
} else {
|
|
/*
|
|
* Here we've desigend our own ENGINEID that is not based on
|
|
* an address which may change and may even become conflicting
|
|
* in the future like most of the default v3 engineID types
|
|
* suffer from.
|
|
*
|
|
* Ours is built from 2 fairly random elements: a random number and
|
|
* the current time in seconds. This method suffers from boxes
|
|
* that may not have a correct clock setting and random number
|
|
* seed at startup, but few OSes should have that problem.
|
|
*/
|
|
bufp[4] = ENGINEID_TYPE_NETSNMP_RND;
|
|
tmpint = random();
|
|
memcpy(bufp + 5, &tmpint, sizeof(tmpint));
|
|
tmptime = time(NULL);
|
|
memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime));
|
|
}
|
|
break;
|
|
case ENGINEID_TYPE_TEXT:
|
|
bufp[4] = ENGINEID_TYPE_TEXT;
|
|
memcpy((char *) bufp + 5, text, strlen(text));
|
|
break;
|
|
#ifdef HAVE_GETHOSTNAME
|
|
#ifdef AF_INET6
|
|
case ENGINEID_TYPE_IPV6:
|
|
bufp[4] = ENGINEID_TYPE_IPV6;
|
|
memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
|
|
break;
|
|
#endif
|
|
#endif
|
|
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
|
|
case ENGINEID_TYPE_MACADDR:
|
|
{
|
|
int x;
|
|
bufp[4] = ENGINEID_TYPE_MACADDR;
|
|
/*
|
|
* use default NIC if none provided
|
|
*/
|
|
if (NULL == engineIDNic) {
|
|
x = getHwAddress(DEFAULT_NIC, &bufp[5]);
|
|
} else {
|
|
x = getHwAddress(engineIDNic, &bufp[5]);
|
|
}
|
|
if (0 != x)
|
|
/*
|
|
* function failed fill MAC address with zeros
|
|
*/
|
|
{
|
|
memset(&bufp[5], 0, 6);
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
case ENGINEID_TYPE_IPV4:
|
|
default:
|
|
bufp[4] = ENGINEID_TYPE_IPV4;
|
|
#ifdef HAVE_GETHOSTNAME
|
|
if (hent && hent->h_addrtype == AF_INET) {
|
|
memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
|
|
} else { /* Unknown address type. Default to 127.0.0.1. */
|
|
|
|
bufp[5] = 127;
|
|
bufp[6] = 0;
|
|
bufp[7] = 0;
|
|
bufp[8] = 1;
|
|
}
|
|
#else /* HAVE_GETHOSTNAME */
|
|
/*
|
|
* Unknown address type. Default to 127.0.0.1.
|
|
*/
|
|
bufp[5] = 127;
|
|
bufp[6] = 0;
|
|
bufp[7] = 0;
|
|
bufp[8] = 1;
|
|
#endif /* HAVE_GETHOSTNAME */
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Pass the string back to the calling environment, or use it for
|
|
* our local engineID.
|
|
*/
|
|
if (localsetup) {
|
|
SNMP_FREE(engineID);
|
|
engineID = bufp;
|
|
engineIDLength = len;
|
|
|
|
} else {
|
|
*eidp = bufp;
|
|
}
|
|
|
|
|
|
return len;
|
|
|
|
} /* end setup_engineID() */
|
|
|
|
int
|
|
free_engineID(int majorid, int minorid, void *serverarg,
|
|
void *clientarg)
|
|
{
|
|
SNMP_FREE(engineID);
|
|
SNMP_FREE(engineIDNic);
|
|
SNMP_FREE(oldEngineID);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
free_enginetime_on_shutdown(int majorid, int minorid, void *serverarg,
|
|
void *clientarg)
|
|
{
|
|
DEBUGMSGTL(("snmpv3", "free enginetime callback called\n"));
|
|
if (engineID != NULL)
|
|
free_enginetime(engineID, engineIDLength);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
usm_parse_create_usmUser(const char *token, char *line)
|
|
{
|
|
char *cp;
|
|
char buf[SNMP_MAXBUF_MEDIUM];
|
|
struct usmUser *newuser;
|
|
u_char userKey[SNMP_MAXBUF_SMALL], *tmpp;
|
|
size_t userKeyLen = SNMP_MAXBUF_SMALL;
|
|
size_t privKeyLen = 0;
|
|
size_t ret;
|
|
int testcase;
|
|
|
|
newuser = usm_create_user();
|
|
|
|
/*
|
|
* READ: Security Name
|
|
*/
|
|
cp = copy_nword(line, buf, sizeof(buf));
|
|
|
|
/*
|
|
* might be a -e ENGINEID argument
|
|
*/
|
|
if (strcmp(buf, "-e") == 0) {
|
|
size_t ebuf_len = 32, eout_len = 0;
|
|
u_char *ebuf = (u_char *) malloc(ebuf_len);
|
|
|
|
if (ebuf == NULL) {
|
|
config_perror("malloc failure processing -e flag");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Get the specified engineid from the line.
|
|
*/
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) {
|
|
config_perror("invalid EngineID argument to -e");
|
|
usm_free_user(newuser);
|
|
SNMP_FREE(ebuf);
|
|
return;
|
|
}
|
|
|
|
newuser->engineID = ebuf;
|
|
newuser->engineIDLen = eout_len;
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
} else {
|
|
newuser->engineID = snmpv3_generate_engineID(&ret);
|
|
if (ret == 0) {
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
newuser->engineIDLen = ret;
|
|
}
|
|
|
|
newuser->secName = strdup(buf);
|
|
newuser->name = strdup(buf);
|
|
|
|
if (!cp)
|
|
goto add; /* no authentication or privacy type */
|
|
|
|
/*
|
|
* READ: Authentication Type
|
|
*/
|
|
#ifndef DISABLE_MD5
|
|
if (strncmp(cp, "MD5", 3) == 0) {
|
|
memcpy(newuser->authProtocol, usmHMACMD5AuthProtocol,
|
|
sizeof(usmHMACMD5AuthProtocol));
|
|
} else
|
|
#endif
|
|
if (strncmp(cp, "SHA", 3) == 0) {
|
|
memcpy(newuser->authProtocol, usmHMACSHA1AuthProtocol,
|
|
sizeof(usmHMACSHA1AuthProtocol));
|
|
} else {
|
|
config_perror("Unknown authentication protocol");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
|
|
cp = skip_token(cp);
|
|
|
|
/*
|
|
* READ: Authentication Pass Phrase or key
|
|
*/
|
|
if (!cp) {
|
|
config_perror("no authentication pass phrase");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
if (strcmp(buf,"-m") == 0) {
|
|
/* a master key is specified */
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
ret = sizeof(userKey);
|
|
tmpp = userKey;
|
|
userKeyLen = 0;
|
|
if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
|
|
config_perror("invalid key value argument to -m");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
} else if (strcmp(buf,"-l") != 0) {
|
|
/* a password is specified */
|
|
userKeyLen = sizeof(userKey);
|
|
ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
|
|
(u_char *) buf, strlen(buf), userKey, &userKeyLen);
|
|
if (ret != SNMPERR_SUCCESS) {
|
|
config_perror("could not generate the authentication key from the "
|
|
"suppiled pass phrase.");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* And turn it into a localized key
|
|
*/
|
|
ret =
|
|
sc_get_properlength(newuser->authProtocol,
|
|
newuser->authProtocolLen);
|
|
if (ret <= 0) {
|
|
config_perror("Could not get proper authentication protocol key length");
|
|
return;
|
|
}
|
|
newuser->authKey = (u_char *) malloc(ret);
|
|
|
|
if (strcmp(buf,"-l") == 0) {
|
|
/* a local key is directly specified */
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
newuser->authKeyLen = 0;
|
|
if (!snmp_hex_to_binary(&newuser->authKey, &ret,
|
|
&newuser->authKeyLen, 0, buf)) {
|
|
config_perror("invalid key value argument to -l");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
if (ret != newuser->authKeyLen) {
|
|
config_perror("improper key length to -l");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
} else {
|
|
newuser->authKeyLen = ret;
|
|
ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
|
|
newuser->engineID, newuser->engineIDLen,
|
|
userKey, userKeyLen,
|
|
newuser->authKey, &newuser->authKeyLen);
|
|
if (ret != SNMPERR_SUCCESS) {
|
|
config_perror("could not generate localized authentication key "
|
|
"(Kul) from the master key (Ku).");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!cp)
|
|
goto add; /* no privacy type (which is legal) */
|
|
|
|
/*
|
|
* READ: Privacy Type
|
|
*/
|
|
testcase = 0;
|
|
#ifndef DISABLE_DES
|
|
if (strncmp(cp, "DES", 3) == 0) {
|
|
memcpy(newuser->privProtocol, usmDESPrivProtocol,
|
|
sizeof(usmDESPrivProtocol));
|
|
testcase = 1;
|
|
/* DES uses a 128 bit key, 64 bits of which is a salt */
|
|
privKeyLen = 16;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_AES
|
|
if (strncmp(cp, "AES128", 6) == 0 ||
|
|
strncmp(cp, "AES", 3) == 0) {
|
|
memcpy(newuser->privProtocol, usmAESPrivProtocol,
|
|
sizeof(usmAESPrivProtocol));
|
|
testcase = 1;
|
|
privKeyLen = 16;
|
|
}
|
|
#endif
|
|
if (testcase == 0) {
|
|
config_perror("Unknown privacy protocol");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
|
|
cp = skip_token(cp);
|
|
/*
|
|
* READ: Encryption Pass Phrase or key
|
|
*/
|
|
if (!cp) {
|
|
/*
|
|
* assume the same as the authentication key
|
|
*/
|
|
memdup(&newuser->privKey, newuser->authKey, newuser->authKeyLen);
|
|
newuser->privKeyLen = newuser->authKeyLen;
|
|
} else {
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
|
|
if (strcmp(buf,"-m") == 0) {
|
|
/* a master key is specified */
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
ret = sizeof(userKey);
|
|
tmpp = userKey;
|
|
userKeyLen = 0;
|
|
if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
|
|
config_perror("invalid key value argument to -m");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
} else if (strcmp(buf,"-l") != 0) {
|
|
/* a password is specified */
|
|
userKeyLen = sizeof(userKey);
|
|
ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
|
|
(u_char *) buf, strlen(buf), userKey, &userKeyLen);
|
|
if (ret != SNMPERR_SUCCESS) {
|
|
config_perror("could not generate the privacy key from the "
|
|
"suppiled pass phrase.");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* And turn it into a localized key
|
|
*/
|
|
ret =
|
|
sc_get_properlength(newuser->authProtocol,
|
|
newuser->authProtocolLen);
|
|
if (ret < 0) {
|
|
config_perror("could not get proper key length to use for the "
|
|
"privacy algorithm.");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
newuser->privKey = (u_char *) malloc(ret);
|
|
|
|
if (strcmp(buf,"-l") == 0) {
|
|
/* a local key is directly specified */
|
|
cp = copy_nword(cp, buf, sizeof(buf));
|
|
newuser->privKeyLen = 0;
|
|
if (!snmp_hex_to_binary(&newuser->privKey, &ret,
|
|
&newuser->privKeyLen, 0, buf)) {
|
|
config_perror("invalid key value argument to -l");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
} else {
|
|
newuser->privKeyLen = ret;
|
|
ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
|
|
newuser->engineID, newuser->engineIDLen,
|
|
userKey, userKeyLen,
|
|
newuser->privKey, &newuser->privKeyLen);
|
|
if (ret != SNMPERR_SUCCESS) {
|
|
config_perror("could not generate localized privacy key "
|
|
"(Kul) from the master key (Ku).");
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((newuser->privKeyLen >= privKeyLen) || (privKeyLen == 0)){
|
|
newuser->privKeyLen = privKeyLen;
|
|
}
|
|
else {
|
|
/* The privKey length is smaller than required by privProtocol */
|
|
usm_free_user(newuser);
|
|
return;
|
|
}
|
|
|
|
add:
|
|
usm_add_user(newuser);
|
|
DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName));
|
|
DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen));
|
|
DEBUGMSG(("usmUser", "\n"));
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* engineBoots_conf
|
|
*
|
|
* Parameters:
|
|
* *word
|
|
* *cptr
|
|
*
|
|
* Line syntax:
|
|
* engineBoots <num_boots>
|
|
*/
|
|
void
|
|
engineBoots_conf(const char *word, char *cptr)
|
|
{
|
|
engineBoots = atoi(cptr) + 1;
|
|
DEBUGMSGTL(("snmpv3", "engineBoots: %d\n", engineBoots));
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* engineIDType_conf
|
|
*
|
|
* Parameters:
|
|
* *word
|
|
* *cptr
|
|
*
|
|
* Line syntax:
|
|
* engineIDType <1 or 3>
|
|
* 1 is default for IPv4 engine ID type. Will automatically
|
|
* chose between IPv4 & IPv6 if either 1 or 2 is specified.
|
|
* 2 is for IPv6.
|
|
* 3 is hardware (MAC) address, currently supported under Linux
|
|
*/
|
|
void
|
|
engineIDType_conf(const char *word, char *cptr)
|
|
{
|
|
engineIDType = atoi(cptr);
|
|
/*
|
|
* verify valid type selected
|
|
*/
|
|
switch (engineIDType) {
|
|
case ENGINEID_TYPE_IPV4: /* IPv4 */
|
|
case ENGINEID_TYPE_IPV6: /* IPv6 */
|
|
/*
|
|
* IPV? is always good
|
|
*/
|
|
break;
|
|
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
|
|
case ENGINEID_TYPE_MACADDR: /* MAC address */
|
|
break;
|
|
#endif
|
|
default:
|
|
/*
|
|
* unsupported one chosen
|
|
*/
|
|
config_perror("Unsupported enginedIDType, forcing IPv4");
|
|
engineIDType = ENGINEID_TYPE_IPV4;
|
|
}
|
|
DEBUGMSGTL(("snmpv3", "engineIDType: %d\n", engineIDType));
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* engineIDNic_conf
|
|
*
|
|
* Parameters:
|
|
* *word
|
|
* *cptr
|
|
*
|
|
* Line syntax:
|
|
* engineIDNic <string>
|
|
* eth0 is default
|
|
*/
|
|
void
|
|
engineIDNic_conf(const char *word, char *cptr)
|
|
{
|
|
/*
|
|
* Make sure they haven't already specified the engineID via the
|
|
* * configuration file
|
|
*/
|
|
if (0 == engineIDIsSet)
|
|
/*
|
|
* engineID has NOT been set via configuration file
|
|
*/
|
|
{
|
|
/*
|
|
* See if already set if so erase & release it
|
|
*/
|
|
if (NULL != engineIDNic) {
|
|
SNMP_FREE(engineIDNic);
|
|
}
|
|
engineIDNic = (u_char *) malloc(strlen(cptr) + 1);
|
|
if (NULL != engineIDNic) {
|
|
strcpy((char *) engineIDNic, cptr);
|
|
DEBUGMSGTL(("snmpv3", "Initializing engineIDNic: %s\n",
|
|
engineIDNic));
|
|
} else {
|
|
DEBUGMSGTL(("snmpv3",
|
|
"Error allocating memory for engineIDNic!\n"));
|
|
}
|
|
} else {
|
|
DEBUGMSGTL(("snmpv3",
|
|
"NOT setting engineIDNic, engineID already set\n"));
|
|
}
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* engineID_conf
|
|
*
|
|
* Parameters:
|
|
* *word
|
|
* *cptr
|
|
*
|
|
* This function reads a string from the configuration file and uses that
|
|
* string to initialize the engineID. It's assumed to be human readable.
|
|
*/
|
|
void
|
|
engineID_conf(const char *word, char *cptr)
|
|
{
|
|
setup_engineID(NULL, cptr);
|
|
DEBUGMSGTL(("snmpv3", "initialized engineID with: %s\n", cptr));
|
|
}
|
|
|
|
void
|
|
version_conf(const char *word, char *cptr)
|
|
{
|
|
int valid = 0;
|
|
#ifndef DISABLE_SNMPV1
|
|
if ((strcmp(cptr, "1") == 0) ||
|
|
(strcmp(cptr, "v1") == 0)) {
|
|
netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
|
|
NETSNMP_DS_SNMP_VERSION_1); /* bogus value */
|
|
valid = 1;
|
|
}
|
|
#endif
|
|
#ifndef DISABLE_SNMPV2C
|
|
if ((strcasecmp(cptr, "2c") == 0) ||
|
|
(strcasecmp(cptr, "v2c") == 0)) {
|
|
netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
|
|
NETSNMP_DS_SNMP_VERSION_2c);
|
|
valid = 1;
|
|
}
|
|
#endif
|
|
if ((strcasecmp(cptr, "3" ) == 0) ||
|
|
(strcasecmp(cptr, "v3" ) == 0)) {
|
|
netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
|
|
NETSNMP_DS_SNMP_VERSION_3);
|
|
valid = 1;
|
|
}
|
|
if (!valid) {
|
|
config_perror("Unknown version specification");
|
|
return;
|
|
}
|
|
DEBUGMSGTL(("snmpv3", "set default version to %d\n",
|
|
netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_SNMPVERSION)));
|
|
}
|
|
|
|
/*
|
|
* engineID_old_conf(const char *, char *):
|
|
*
|
|
* Reads a octet string encoded engineID into the oldEngineID and
|
|
* oldEngineIDLen pointers.
|
|
*/
|
|
void
|
|
oldengineID_conf(const char *word, char *cptr)
|
|
{
|
|
read_config_read_octet_string(cptr, &oldEngineID, &oldEngineIDLength);
|
|
}
|
|
|
|
/*
|
|
* merely call
|
|
*/
|
|
void
|
|
get_enginetime_alarm(unsigned int regnum, void *clientargs)
|
|
{
|
|
/* we do this every so (rarely) often just to make sure we watch
|
|
wrapping of the times() output */
|
|
snmpv3_local_snmpEngineTime();
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* init_snmpv3
|
|
*
|
|
* Parameters:
|
|
* *type Label for the config file "type" used by calling entity.
|
|
*
|
|
* Set time and engineID.
|
|
* Set parsing functions for config file tokens.
|
|
* Initialize SNMP Crypto API (SCAPI).
|
|
*/
|
|
void
|
|
init_snmpv3(const char *type)
|
|
{
|
|
#if SNMP_USE_TIMES
|
|
struct tms dummy;
|
|
|
|
/* fixme: -1 is fault code... */
|
|
snmpv3startClock = times(&dummy);
|
|
|
|
/* remember how many ticks per second there are, since times() returns this */
|
|
|
|
clockticks = sysconf(_SC_CLK_TCK);
|
|
|
|
#endif /* SNMP_USE_TIMES */
|
|
|
|
gettimeofday(&snmpv3starttime, NULL);
|
|
|
|
if (!type)
|
|
type = "__snmpapp__";
|
|
|
|
/*
|
|
* we need to be called back later
|
|
*/
|
|
snmp_register_callback(SNMP_CALLBACK_LIBRARY,
|
|
SNMP_CALLBACK_POST_READ_CONFIG,
|
|
init_snmpv3_post_config, NULL);
|
|
|
|
snmp_register_callback(SNMP_CALLBACK_LIBRARY,
|
|
SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
|
|
init_snmpv3_post_premib_config, NULL);
|
|
/*
|
|
* we need to be called back later
|
|
*/
|
|
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
|
|
snmpv3_store, (void *) strdup(type));
|
|
|
|
/*
|
|
* Free stuff at shutdown time
|
|
*/
|
|
snmp_register_callback(SNMP_CALLBACK_LIBRARY,
|
|
SNMP_CALLBACK_SHUTDOWN,
|
|
free_enginetime_on_shutdown, NULL);
|
|
|
|
/*
|
|
* initialize submodules
|
|
*/
|
|
/*
|
|
* NOTE: this must be after the callbacks are registered above,
|
|
* since they need to be called before the USM callbacks.
|
|
*/
|
|
init_secmod();
|
|
|
|
/*
|
|
* register all our configuration handlers (ack, there's a lot)
|
|
*/
|
|
|
|
/*
|
|
* handle engineID setup before everything else which may depend on it
|
|
*/
|
|
register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL,
|
|
"string");
|
|
register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf,
|
|
NULL, NULL);
|
|
register_prenetsnmp_mib_handler(type, "engineIDType",
|
|
engineIDType_conf, NULL, "num");
|
|
register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf,
|
|
NULL, "string");
|
|
register_config_handler(type, "engineBoots", engineBoots_conf, NULL,
|
|
NULL);
|
|
|
|
/*
|
|
* default store config entries
|
|
*/
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName",
|
|
NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext",
|
|
NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_PASSPHRASE);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_AUTHPASSPHRASE);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_PRIVPASSPHRASE);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthMasterKey",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_AUTHMASTERKEY);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivMasterKey",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_PRIVMASTERKEY);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthLocalizedKey",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_AUTHLOCALIZEDKEY);
|
|
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivLocalizedKey",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_PRIVLOCALIZEDKEY);
|
|
register_config_handler("snmp", "defVersion", version_conf, NULL,
|
|
"1|2c|3");
|
|
|
|
register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf,
|
|
NULL, "MD5|SHA");
|
|
register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
|
|
NULL,
|
|
#ifdef HAVE_AES
|
|
"DES (AES support not available)");
|
|
#else
|
|
"DES|AES");
|
|
#endif
|
|
register_config_handler("snmp", "defSecurityLevel",
|
|
snmpv3_secLevel_conf, NULL,
|
|
"noAuthNoPriv|authNoPriv|authPriv");
|
|
register_config_handler(type, "userSetAuthPass", usm_set_password,
|
|
NULL, NULL);
|
|
register_config_handler(type, "userSetPrivPass", usm_set_password,
|
|
NULL, NULL);
|
|
register_config_handler(type, "userSetAuthKey", usm_set_password, NULL,
|
|
NULL);
|
|
register_config_handler(type, "userSetPrivKey", usm_set_password, NULL,
|
|
NULL);
|
|
register_config_handler(type, "userSetAuthLocalKey", usm_set_password,
|
|
NULL, NULL);
|
|
register_config_handler(type, "userSetPrivLocalKey", usm_set_password,
|
|
NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
* initializations for SNMPv3 to be called after the configuration files
|
|
* have been read.
|
|
*/
|
|
|
|
int
|
|
init_snmpv3_post_config(int majorid, int minorid, void *serverarg,
|
|
void *clientarg)
|
|
{
|
|
|
|
size_t engineIDLen;
|
|
u_char *c_engineID;
|
|
|
|
c_engineID = snmpv3_generate_engineID(&engineIDLen);
|
|
|
|
if (engineIDLen == 0) {
|
|
/*
|
|
* Somethine went wrong - help!
|
|
*/
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
/*
|
|
* if our engineID has changed at all, the boots record must be set to 1
|
|
*/
|
|
if (engineIDLen != (int) oldEngineIDLength ||
|
|
oldEngineID == NULL || c_engineID == NULL ||
|
|
memcmp(oldEngineID, c_engineID, engineIDLen) != 0) {
|
|
engineBoots = 1;
|
|
}
|
|
|
|
/*
|
|
* set our local engineTime in the LCD timing cache
|
|
*/
|
|
set_enginetime(c_engineID, engineIDLen,
|
|
snmpv3_local_snmpEngineBoots(),
|
|
snmpv3_local_snmpEngineTime(), TRUE);
|
|
|
|
SNMP_FREE(c_engineID);
|
|
return SNMPERR_SUCCESS;
|
|
}
|
|
|
|
int
|
|
init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg,
|
|
void *clientarg)
|
|
{
|
|
if (!engineIDIsSet)
|
|
setup_engineID(NULL, NULL);
|
|
|
|
return SNMPERR_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* store_snmpv3
|
|
*
|
|
* Parameters:
|
|
* *type
|
|
*/
|
|
int
|
|
snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg)
|
|
{
|
|
char line[SNMP_MAXBUF_SMALL];
|
|
u_char c_engineID[SNMP_MAXBUF_SMALL];
|
|
int engineIDLen;
|
|
const char *type = (const char *) clientarg;
|
|
|
|
if (type == NULL) /* should never happen, since the arg is ours */
|
|
type = "unknown";
|
|
|
|
sprintf(line, "engineBoots %ld", engineBoots);
|
|
read_config_store(type, line);
|
|
|
|
engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL);
|
|
|
|
if (engineIDLen) {
|
|
/*
|
|
* store the engineID used for this run
|
|
*/
|
|
sprintf(line, "oldEngineID ");
|
|
read_config_save_octet_string(line + strlen(line), c_engineID,
|
|
engineIDLen);
|
|
read_config_store(type, line);
|
|
}
|
|
return SNMPERR_SUCCESS;
|
|
} /* snmpv3_store() */
|
|
|
|
u_long
|
|
snmpv3_local_snmpEngineBoots(void)
|
|
{
|
|
return engineBoots;
|
|
}
|
|
|
|
|
|
/*******************************************************************-o-******
|
|
* snmpv3_get_engineID
|
|
*
|
|
* Parameters:
|
|
* *buf
|
|
* buflen
|
|
*
|
|
* Returns:
|
|
* Length of engineID On Success
|
|
* SNMPERR_GENERR Otherwise.
|
|
*
|
|
*
|
|
* Store engineID in buf; return the length.
|
|
*
|
|
*/
|
|
size_t
|
|
snmpv3_get_engineID(u_char * buf, size_t buflen)
|
|
{
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!buf || (buflen < engineIDLength)) {
|
|
return 0;
|
|
}
|
|
|
|
memcpy(buf, engineID, engineIDLength);
|
|
return engineIDLength;
|
|
|
|
} /* end snmpv3_get_engineID() */
|
|
|
|
/*******************************************************************-o-******
|
|
* snmpv3_clone_engineID
|
|
*
|
|
* Parameters:
|
|
* **dest
|
|
* *dest_len
|
|
* src
|
|
* srclen
|
|
*
|
|
* Returns:
|
|
* Length of engineID On Success
|
|
* 0 Otherwise.
|
|
*
|
|
*
|
|
* Clones engineID, creates memory
|
|
*
|
|
*/
|
|
int
|
|
snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src,
|
|
size_t srclen)
|
|
{
|
|
if (!dest || !destlen)
|
|
return 0;
|
|
|
|
if (*dest) {
|
|
SNMP_FREE(*dest);
|
|
*dest = NULL;
|
|
}
|
|
*destlen = 0;
|
|
|
|
if (srclen && src) {
|
|
*dest = (u_char *) malloc(srclen);
|
|
if (*dest == NULL)
|
|
return 0;
|
|
memmove(*dest, src, srclen);
|
|
*destlen = srclen;
|
|
}
|
|
return *destlen;
|
|
} /* end snmpv3_clone_engineID() */
|
|
|
|
|
|
/*******************************************************************-o-******
|
|
* snmpv3_generate_engineID
|
|
*
|
|
* Parameters:
|
|
* *length
|
|
*
|
|
* Returns:
|
|
* Pointer to copy of engineID On Success.
|
|
* NULL If malloc() or snmpv3_get_engineID()
|
|
* fail.
|
|
*
|
|
* Generates a malloced copy of our engineID.
|
|
*
|
|
* 'length' is set to the length of engineID -OR- < 0 on failure.
|
|
*/
|
|
u_char *
|
|
snmpv3_generate_engineID(size_t * length)
|
|
{
|
|
u_char *newID;
|
|
newID = (u_char *) malloc(engineIDLength);
|
|
|
|
if (newID) {
|
|
*length = snmpv3_get_engineID(newID, engineIDLength);
|
|
}
|
|
|
|
if (*length == 0) {
|
|
SNMP_FREE(newID);
|
|
newID = NULL;
|
|
}
|
|
|
|
return newID;
|
|
|
|
} /* end snmpv3_generate_engineID() */
|
|
|
|
/*
|
|
* snmpv3_local_snmpEngineTime(): return the number of seconds since the
|
|
* snmpv3 engine last incremented engine_boots
|
|
*/
|
|
u_long
|
|
snmpv3_local_snmpEngineTime(void)
|
|
{
|
|
#ifdef SNMP_USE_TIMES
|
|
struct tms dummy;
|
|
clock_t now = times(&dummy);
|
|
/* fixme: -1 is fault code... */
|
|
unsigned int result;
|
|
|
|
if (now < snmpv3startClock) {
|
|
result = UINT_MAX - (snmpv3startClock - now);
|
|
} else {
|
|
result = now - snmpv3startClock;
|
|
}
|
|
if (result < lastcalltime) {
|
|
/* wrapped */
|
|
wrapcounter++;
|
|
}
|
|
lastcalltime = result;
|
|
result = (UINT_MAX/clockticks)*wrapcounter + result/clockticks;
|
|
|
|
return result;
|
|
#else /* !SNMP_USE_TIMES */
|
|
struct timeval now;
|
|
|
|
gettimeofday(&now, NULL);
|
|
return calculate_sectime_diff(&now, &snmpv3starttime);
|
|
#endif /* HAVE_SYS_TIMES_H */
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Code only for Linux systems
|
|
*/
|
|
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
|
|
static int
|
|
getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */
|
|
char *addressOut)
|
|
{ /* return address. Len=IFHWADDRLEN */
|
|
/*
|
|
* getHwAddress(...)
|
|
* *
|
|
* * This function will return a Network Interfaces Card's Hardware
|
|
* * address (aka MAC address).
|
|
* *
|
|
* * Input Parameter(s):
|
|
* * networkDevice - a null terminated string with the name of a network
|
|
* * device. Examples: eth0, eth1, etc...
|
|
* *
|
|
* * Output Parameter(s):
|
|
* * addressOut - This is the binary value of the hardware address.
|
|
* * This value is NOT converted into a hexadecimal string.
|
|
* * The caller must pre-allocate for a return value of
|
|
* * length IFHWADDRLEN
|
|
* *
|
|
* * Return value: This function will return zero (0) for success. If
|
|
* * an error occurred the function will return -1.
|
|
* *
|
|
* * Caveats: This has only been tested on Ethernet networking cards.
|
|
*/
|
|
int sock; /* our socket */
|
|
struct ifreq request; /* struct which will have HW address */
|
|
|
|
if ((NULL == networkDevice) || (NULL == addressOut)) {
|
|
return -1;
|
|
}
|
|
/*
|
|
* In order to find out the hardware (MAC) address of our system under
|
|
* * Linux we must do the following:
|
|
* * 1. Create a socket
|
|
* * 2. Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation.
|
|
*/
|
|
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (sock < 0) {
|
|
return -1;
|
|
}
|
|
/*
|
|
* erase the request block
|
|
*/
|
|
memset(&request, 0, sizeof(request));
|
|
/*
|
|
* copy the name of the net device we want to find the HW address for
|
|
*/
|
|
strncpy(request.ifr_name, networkDevice, IFNAMSIZ - 1);
|
|
/*
|
|
* Get the HW address
|
|
*/
|
|
if (ioctl(sock, SIOCGIFHWADDR, &request)) {
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
close(sock);
|
|
memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef SNMP_TESTING_CODE
|
|
/*
|
|
* snmpv3_set_engineBootsAndTime(): this function does not exist. Go away.
|
|
*/
|
|
/*
|
|
* It certainly should never be used, unless in a testing scenero,
|
|
* which is why it was created
|
|
*/
|
|
void
|
|
snmpv3_set_engineBootsAndTime(int boots, int ttime)
|
|
{
|
|
engineBoots = boots;
|
|
gettimeofday(&snmpv3starttime, NULL);
|
|
snmpv3starttime.tv_sec -= ttime;
|
|
}
|
|
#endif
|