| /* |
| * snmpv3.c |
| */ |
| |
| #include <config.h> |
| |
| #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_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #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 "system.h" |
| #include "asn1.h" |
| #include "snmpv3.h" |
| #include "callback.h" |
| #include "snmpusm.h" |
| #include "snmp.h" |
| #include "snmp_api.h" |
| #include "snmp_impl.h" |
| #include "read_config.h" |
| #include "lcd_time.h" |
| #include "scapi.h" |
| #include "tools.h" |
| #include "keytools.h" |
| #include "lcd_time.h" |
| #include "snmp_debug.h" |
| #include "snmp_logging.h" |
| #include "default_store.h" |
| |
| #include "transform_oids.h" |
| |
| static u_long engineBoots = 1; |
| static unsigned int engineIDType = ENGINEID_TYPE_IPV4; |
| 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 oid *defaultAuthType = NULL; |
| static size_t defaultAuthTypeLen = 0; |
| static oid *defaultPrivType = NULL; |
| static size_t defaultPrivTypeLen = 0; |
| |
| static int getHwAddress(const char * networkDevice, char * addressOut); |
| |
| void |
| snmpv3_authtype_conf(const char *word, char *cptr) |
| { |
| if (strcmp(cptr,"MD5") == 0) |
| defaultAuthType = usmHMACMD5AuthProtocol; |
| else if (strcmp(cptr,"SHA") == 0) |
| defaultAuthType = usmHMACMD5AuthProtocol; |
| else |
| config_perror("unknown authentication type"); |
| defaultAuthTypeLen = USM_LENGTH_OID_TRANSFORM; |
| DEBUGMSGTL(("snmpv3","set default authentication type: %s\n", cptr)); |
| } |
| |
| 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) |
| { |
| if (strcmp(cptr,"DES") == 0) |
| defaultPrivType = SNMP_DEFAULT_PRIV_PROTO; |
| else |
| config_perror("unknown privacy type"); |
| defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN; |
| DEBUGMSGTL(("snmpv3","set default privacy type: %s\n", cptr)); |
| } |
| |
| oid * |
| get_default_privtype(size_t *len) |
| { |
| if (defaultAuthType == NULL) { |
| defaultAuthType = usmDESPrivProtocol; |
| 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 (strcmp(cptr,"noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0) |
| ds_set_int(DS_LIBRARY_ID, DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_NOAUTH); |
| else if (strcmp(cptr,"authNoPriv") == 0 || strcmp(cptr, "2") == 0) |
| ds_set_int(DS_LIBRARY_ID, DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHNOPRIV); |
| else if (strcmp(cptr,"authPriv") == 0 || strcmp(cptr, "3") == 0) |
| ds_set_int(DS_LIBRARY_ID, DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHPRIV); |
| else { |
| sprintf(buf,"unknown security level: cptr"); |
| config_perror(buf); |
| } |
| DEBUGMSGTL(("snmpv3","default secLevel set to: %s = %d\n", cptr, |
| ds_get_int(DS_LIBRARY_ID, DS_LIB_SECLEVEL))); |
| } |
| |
| /*******************************************************************-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_NUMBER), |
| localsetup = (eidp) ? 0 : 1; |
| /* Use local engineID if *eidp == NULL. */ |
| #ifdef HAVE_GETHOSTNAME |
| u_char buf[SNMP_MAXBUF_SMALL]; |
| struct hostent *hent; |
| #endif |
| u_char *bufp = NULL; |
| size_t len; |
| int localEngineIDType = engineIDType; |
| |
| /* get the host name and save the information */ |
| #ifdef HAVE_GETHOSTNAME |
| gethostname((char *)buf, sizeof(buf)); |
| hent = gethostbyname((char *)buf); |
| /* Determine if we are using IPV6 */ |
| #ifdef AF_INET6 |
| /* see if they selected IPV4 or IPV6 support */ |
| if ( (ENGINEID_TYPE_IPV6 == localEngineIDType ) || \ |
| (ENGINEID_TYPE_IPV4 == localEngineIDType ) ) |
| { |
| 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 for them */ |
| if ( ENGINEID_TYPE_IPV6 == localEngineIDType ) |
| { |
| localEngineIDType = ENGINEID_TYPE_IPV4; |
| } |
| #endif |
| #endif /* HAVE_GETHOSTNAME */ |
| |
| /* Determine if we have text and if so setup our localEngineIDType |
| * appropriately. */ |
| if ( NULL != text ) |
| { |
| 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; |
| default: |
| snmp_log(LOG_ERR, "Unknown EngineID type requested for setup. Using IPv4.\n"); |
| 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; |
| } |
| memcpy(bufp, &enterpriseid, sizeof(enterpriseid)); /* XXX Must be 4 bytes! */ |
| bufp[0] |= 0x80; |
| |
| |
| /* |
| * Store the given text -OR- the first found IP address. |
| */ |
| switch (localEngineIDType) |
| { |
| 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() */ |
| |
| 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]; |
| size_t userKeyLen = SNMP_MAXBUF_SMALL; |
| size_t ret; |
| |
| newuser = usm_create_user(); |
| |
| /* READ: Security Name */ |
| cp = copy_word(line, buf); |
| newuser->secName = strdup(buf); |
| newuser->name = strdup(buf); |
| |
| newuser->engineID = snmpv3_generate_engineID(&ret); |
| if ( ret == 0 ) { |
| usm_free_user(newuser); |
| return; |
| } |
| newuser->engineIDLen = ret; |
| |
| if (!cp) |
| goto add; /* no authentication or privacy type */ |
| |
| /* READ: Authentication Type */ |
| if (strncmp(cp, "MD5", 3) == 0) { |
| memcpy(newuser->authProtocol, usmHMACMD5AuthProtocol, |
| sizeof(usmHMACMD5AuthProtocol)); |
| } else 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 */ |
| if (!cp) { |
| config_perror("no authentication pass phrase"); |
| usm_free_user(newuser); |
| return; |
| } |
| cp = copy_word(cp, buf); |
| /* And turn it into a localized key */ |
| ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen, |
| (u_char *)buf, strlen(buf), |
| userKey, &userKeyLen ); |
| if (ret != SNMPERR_SUCCESS) { |
| config_perror("Error generating auth key from pass phrase."); |
| usm_free_user(newuser); |
| return; |
| } |
| newuser->authKeyLen = |
| sc_get_properlength(newuser->authProtocol, newuser->authProtocolLen); |
| newuser->authKey = (u_char *) malloc(newuser->authKeyLen); |
| ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen, |
| newuser->engineID, newuser->engineIDLen, |
| userKey, userKeyLen, |
| newuser->authKey, &newuser->authKeyLen ); |
| if (ret != SNMPERR_SUCCESS) { |
| config_perror("Error generating localized auth key (Kul) from Ku."); |
| usm_free_user(newuser); |
| return; |
| } |
| |
| if (!cp) |
| goto add; /* no privacy type (which is legal) */ |
| |
| /* READ: Privacy Type */ |
| if (strncmp(cp, "DES", 3) == 0) { |
| memcpy(newuser->privProtocol, usmDESPrivProtocol, |
| sizeof(usmDESPrivProtocol)); |
| } else { |
| config_perror("unknown privacy protocol"); |
| usm_free_user(newuser); |
| return; |
| } |
| |
| cp = skip_token(cp); |
| /* READ: Authentication Pass Phrase */ |
| if (!cp) { |
| /* assume the same as the authentication key */ |
| memdup(&newuser->privKey, newuser->authKey, newuser->authKeyLen); |
| } else { |
| cp = copy_word(cp, buf); |
| /* And turn it into a localized key */ |
| ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen, |
| (u_char *)buf, strlen(buf), |
| userKey, &userKeyLen ); |
| if (ret != SNMPERR_SUCCESS) { |
| config_perror("Error generating priv key from pass phrase."); |
| usm_free_user(newuser); |
| return; |
| } |
| |
| ret = sc_get_properlength(newuser->authProtocol, newuser->authProtocolLen); |
| if (ret < 0) { |
| config_perror("Error getting proper key length for priv algorithm."); |
| usm_free_user(newuser); |
| return; |
| } |
| newuser->privKeyLen = ret; |
| |
| newuser->privKey = (u_char *) malloc(newuser->privKeyLen); |
| ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen, |
| newuser->engineID, newuser->engineIDLen, |
| userKey, userKeyLen, |
| newuser->privKey, &newuser->privKeyLen ); |
| if (ret != SNMPERR_SUCCESS) { |
| config_perror("Error generating localized priv key (Kul) from Ku."); |
| usm_free_user(newuser); |
| return; |
| } |
| } |
| add: |
| usm_add_user(newuser); |
| DEBUGMSGTL(("usmUser","created a new user %s\n", newuser->secName)); |
| } |
| |
| /*******************************************************************-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) |
| { |
| /* Make sure they haven't already specified the engineID via the |
| * configuration file */ |
| if ( 0 == engineIDIsSet ) |
| /* engineID has NOT been set via configuration file */ |
| { |
| 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)); |
| /* set the engine ID now */ |
| setup_engineID(NULL,NULL); |
| } |
| else |
| { |
| config_perror("NOT setting engineIDType, engineID already set"); |
| } |
| } |
| |
| /*******************************************************************-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 ) |
| { |
| free(engineIDNic); |
| } |
| engineIDNic=(u_char *)malloc(strlen(cptr)+1); |
| if ( NULL != engineIDNic ) |
| { |
| strcpy((char *)engineIDNic,cptr); |
| DEBUGMSGTL(("snmpv3","Initializing engineIDNic: %s\n", engineIDNic)); |
| setup_engineID(NULL,NULL); |
| } |
| 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); |
| engineIDIsSet=1; |
| DEBUGMSGTL(("snmpv3","initialized engineID with: %s\n",cptr)); |
| } |
| |
| void |
| version_conf(const char *word, char *cptr) |
| { |
| if (strcmp(cptr,"1") == 0) { |
| ds_set_int(DS_LIBRARY_ID, DS_LIB_SNMPVERSION, SNMP_VERSION_1); |
| } else if (strcmp(cptr,"2c") == 0) { |
| ds_set_int(DS_LIBRARY_ID, DS_LIB_SNMPVERSION, SNMP_VERSION_2c); |
| } else if (strcmp(cptr,"3") == 0) { |
| ds_set_int(DS_LIBRARY_ID, DS_LIB_SNMPVERSION, SNMP_VERSION_3); |
| } else { |
| config_perror("unknown version specification"); |
| return; |
| } |
| DEBUGMSGTL(("snmpv3","set default version to %d\n", |
| ds_get_int(DS_LIBRARY_ID, 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); |
| } |
| |
| |
| /*******************************************************************-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) { |
| gettimeofday(&snmpv3starttime, NULL); |
| |
| if (type == NULL) |
| type = "snmpapp"; |
| |
| if (type && !strcmp(type,"snmpapp")) { |
| setup_engineID(NULL,"__snmpapp__"); |
| } else { |
| setup_engineID(NULL, NULL); |
| } |
| |
| /* initialize submodules */ |
| init_usm(); |
| |
| /* we need to be called back later */ |
| snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG, |
| init_snmpv3_post_config, NULL); |
| /* we need to be called back later */ |
| snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, |
| snmpv3_store, (void *) strdup(type)); |
| |
| |
| #if !defined(USE_INTERNAL_MD5) |
| /* doesn't belong here at all */ |
| sc_init(); |
| #endif /* !USE_INTERNAL_MD5 */ |
| |
| /* register all our configuration handlers (ack, there's a lot) */ |
| |
| /* handle engineID setup before everything else which may depend on it */ |
| register_premib_handler(type,"engineID", engineID_conf, NULL, "string"); |
| register_premib_handler(type,"oldEngineID", oldengineID_conf, NULL, NULL); |
| register_premib_handler(type,"engineIDType", engineIDType_conf, NULL,"num"); |
| register_premib_handler(type,"engineIDNic", engineIDNic_conf, NULL,"string"); |
| register_config_handler(type,"engineBoots", engineBoots_conf, NULL, NULL); |
| |
| /* default store config entries */ |
| ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName", DS_LIBRARY_ID, |
| DS_LIB_SECNAME); |
| ds_register_config(ASN_OCTET_STR, "snmp", "defContext", DS_LIBRARY_ID, |
| DS_LIB_CONTEXT); |
| ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase", DS_LIBRARY_ID, |
| DS_LIB_PASSPHRASE); |
| ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase", DS_LIBRARY_ID, |
| DS_LIB_AUTHPASSPHRASE); |
| ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase", DS_LIBRARY_ID, |
| DS_LIB_PRIVPASSPHRASE); |
| 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, |
| "DES (currently the only possible value)"); |
| register_config_handler("snmp","defSecurityLevel", snmpv3_secLevel_conf, |
| NULL, "noAuthNoPriv|authNoPriv|authPriv"); |
| register_config_handler(type,"userSetAuthPass", usm_set_password, NULL, |
| "secname engineIDLen engineID pass"); |
| register_config_handler(type,"userSetPrivPass", usm_set_password, NULL, |
| "secname engineIDLen engineID pass"); |
| register_config_handler(type,"userSetAuthKey", usm_set_password, NULL, |
| "secname engineIDLen engineID KuLen Ku"); |
| register_config_handler(type,"userSetPrivKey", usm_set_password, NULL, |
| "secname engineIDLen engineID KuLen Ku"); |
| register_config_handler(type,"userSetAuthLocalKey", usm_set_password, NULL, |
| "secname engineIDLen engineID KulLen Kul"); |
| register_config_handler(type,"userSetPrivLocalKey", usm_set_password, NULL, |
| "secname engineIDLen engineID KulLen Kul"); |
| } |
| |
| /* |
| * 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); |
| |
| free(c_engineID); |
| 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; |
| |
| *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) |
| { |
| struct timeval now; |
| |
| gettimeofday(&now, NULL); |
| return calculate_time_diff(&now, &snmpv3starttime)/100; |
| } |
| |
| |
| /* 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 |