diff options
Diffstat (limited to 'snmplib/snmpv3.c')
-rw-r--r-- | snmplib/snmpv3.c | 1675 |
1 files changed, 1675 insertions, 0 deletions
diff --git a/snmplib/snmpv3.c b/snmplib/snmpv3.c new file mode 100644 index 0000000..ae154f0 --- /dev/null +++ b/snmplib/snmpv3.c @@ -0,0 +1,1675 @@ +/* + * snmpv3.c + */ + +#include <net-snmp/net-snmp-config.h> +#include <errno.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 NETSNMP_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 NETSNMP_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 NETSNMP_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" + */ + +int +parse_secLevel_conf(const char *word, char *cptr) { + if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 || + strcasecmp(cptr, "nanp") == 0) { + return SNMP_SEC_LEVEL_NOAUTH; + } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 || + strcasecmp(cptr, "anp") == 0) { + return SNMP_SEC_LEVEL_AUTHNOPRIV; + } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 || + strcasecmp(cptr, "ap") == 0) { + return SNMP_SEC_LEVEL_AUTHPRIV; + } else { + return -1; + } +} + +void +snmpv3_secLevel_conf(const char *word, char *cptr) +{ + char buf[1024]; + int secLevel; + + if ((secLevel = parse_secLevel_conf( word, cptr )) >= 0 ) { + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_SECLEVEL, secLevel); + } 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': + errno=0; + session->engineBoots = strtoul(optarg, &cp, 10); + if (errno || cp == optarg) { + fprintf(stderr, "Need engine boots value after -3Z flag.\n"); + return (-1); + } + if (*cp == ',') { + char *endptr; + cp++; + session->engineTime = strtoul(cp, &endptr, 10); + if (errno || cp == endptr) { + fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n"); + return (-1); + } + } else { + fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\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 NETSNMP_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 NETSNMP_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(NETSNMP_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: + if (NULL == text) { + snmp_log(LOG_ERR, + "Can't set up engineID of type text from an empty string.\n"); + return -1; + } + 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, (char *)&bufp[5]); + } else { + x = getHwAddress((char *)engineIDNic, (char *)&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); + engineIDIsSet = 0; + 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 ret2; + 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 NETSNMP_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); + ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen, + (u_char *) buf, strlen(buf), userKey, &userKeyLen); + if (ret2 != SNMPERR_SUCCESS) { + config_perror("could not generate the authentication key from the " + "supplied pass phrase."); + usm_free_user(newuser); + return; + } + } + + /* + * And turn it into a localized key + */ + ret2 = sc_get_properlength(newuser->authProtocol, + newuser->authProtocolLen); + if (ret2 <= 0) { + config_perror("Could not get proper authentication protocol key length"); + usm_free_user(newuser); + return; + } + newuser->authKey = (u_char *) malloc(ret2); + + if (strcmp(buf,"-l") == 0) { + /* a local key is directly specified */ + cp = copy_nword(cp, buf, sizeof(buf)); + newuser->authKeyLen = 0; + ret = ret2; + 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 = ret2; + ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen, + newuser->engineID, newuser->engineIDLen, + userKey, userKeyLen, + newuser->authKey, &newuser->authKeyLen); + if (ret2 != 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 NETSNMP_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); + ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen, + (u_char *) buf, strlen(buf), userKey, &userKeyLen); + if (ret2 != SNMPERR_SUCCESS) { + config_perror("could not generate the privacy key from the " + "supplied pass phrase."); + usm_free_user(newuser); + return; + } + } + + /* + * And turn it into a localized key + */ + ret2 = sc_get_properlength(newuser->authProtocol, + newuser->authProtocolLen); + if (ret2 < 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(ret2); + + if (strcmp(buf,"-l") == 0) { + /* a local key is directly specified */ + cp = copy_nword(cp, buf, sizeof(buf)); + ret = ret2; + 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 = ret2; + ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen, + newuser->engineID, newuser->engineIDLen, + userKey, userKeyLen, + newuser->privKey, &newuser->privKeyLen); + if (ret2 != 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 NETSNMP_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 NETSNMP_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"); +#else + "DES (AES support not available)"); +#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 || !c_engineID) { + /* + * Somethine went wrong - help! + */ + SNMP_FREE(c_engineID); + 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 NETSNMP_ENABLE_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 |