1 #ifdef BRCM_SNMP_MIB_SUPPORT
6 #include <net-snmp/net-snmp-config.h>
10 #if TIME_WITH_SYS_TIME
12 # include <sys/timeb.h>
14 # include <sys/time.h>
19 # include <sys/time.h>
31 #include <netinet/in.h>
40 #include <sys/socket.h>
50 * Stuff needed for getHwAddress(...)
52 #ifdef HAVE_SYS_IOCTL_H
53 # include <sys/ioctl.h>
63 #include <net-snmp/types.h>
64 #include <net-snmp/output_api.h>
65 #include <net-snmp/config_api.h>
66 #include <net-snmp/utilities.h>
68 #include <net-snmp/library/snmpv3.h>
69 #include <net-snmp/library/callback.h>
70 #include <net-snmp/library/snmp_api.h>
71 #include <net-snmp/library/lcd_time.h>
72 #include <net-snmp/library/scapi.h>
73 #include <net-snmp/library/keytools.h>
74 #include <net-snmp/library/lcd_time.h>
75 #include <net-snmp/library/snmp_secmod.h>
76 #include <net-snmp/library/snmpusm.h>
77 #include <net-snmp/library/transform_oids.h>
79 static u_long engineBoots = 1;
80 static unsigned int engineIDType = ENGINEID_TYPE_UCD_RND;
81 static unsigned char *engineID = NULL;
82 static size_t engineIDLength = 0;
83 static unsigned char *engineIDNic = NULL;
84 static unsigned int engineIDIsSet = 0; /* flag if ID set by config */
85 static unsigned char *oldEngineID = NULL;
86 static size_t oldEngineIDLength = 0;
87 static struct timeval snmpv3starttime;
90 * Set up default snmpv3 parameter value storage.
92 static const oid *defaultAuthType = NULL;
93 static size_t defaultAuthTypeLen = 0;
94 static const oid *defaultPrivType = NULL;
95 static size_t defaultPrivTypeLen = 0;
97 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
98 static int getHwAddress(const char *networkDevice, char *addressOut);
102 snmpv3_authtype_conf(const char *word, char *cptr)
104 if (strcasecmp(cptr, "MD5") == 0)
105 defaultAuthType = usmHMACMD5AuthProtocol;
106 else if (strcasecmp(cptr, "SHA") == 0)
107 defaultAuthType = usmHMACSHA1AuthProtocol;
109 config_perror("Unknown authentication type");
110 defaultAuthTypeLen = USM_LENGTH_OID_TRANSFORM;
111 DEBUGMSGTL(("snmpv3", "set default authentication type: %s\n", cptr));
115 get_default_authtype(size_t * len)
117 if (defaultAuthType == NULL) {
118 defaultAuthType = SNMP_DEFAULT_AUTH_PROTO;
119 defaultAuthTypeLen = SNMP_DEFAULT_AUTH_PROTOLEN;
122 *len = defaultAuthTypeLen;
123 return defaultAuthType;
127 snmpv3_privtype_conf(const char *word, char *cptr)
129 if (strcasecmp(cptr, "DES") == 0)
130 defaultPrivType = usmDESPrivProtocol;
132 /* XXX AES: assumes oid length == des oid length */
133 else if (strcasecmp(cptr, "AES128") == 0)
134 defaultPrivType = usmAES128PrivProtocol;
135 else if (strcasecmp(cptr, "AES192") == 0)
136 defaultPrivType = usmAES192PrivProtocol;
137 else if (strcasecmp(cptr, "AES256") == 0)
138 defaultPrivType = usmAES256PrivProtocol;
141 config_perror("Unknown privacy type");
142 defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN;
143 DEBUGMSGTL(("snmpv3", "set default privacy type: %s\n", cptr));
147 get_default_privtype(size_t * len)
149 if (defaultPrivType == NULL) {
150 defaultPrivType = usmDESPrivProtocol;
151 defaultPrivTypeLen = USM_LENGTH_OID_TRANSFORM;
154 *len = defaultPrivTypeLen;
155 return defaultPrivType;
158 /*******************************************************************-o-******
159 * snmpv3_secLevel_conf
166 * defSecurityLevel "noAuthNoPriv" | "authNoPriv" | "authPriv"
169 snmpv3_secLevel_conf(const char *word, char *cptr)
173 if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 ||
174 strcasecmp(cptr, "nanp") == 0) {
175 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
176 NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_NOAUTH);
177 } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 ||
178 strcasecmp(cptr, "anp") == 0) {
179 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
180 NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHNOPRIV);
181 } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 ||
182 strcasecmp(cptr, "ap") == 0) {
183 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
184 NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHPRIV);
186 snprintf(buf, sizeof(buf), "Unknown security level: %s", cptr);
187 buf[ sizeof(buf)-1 ] = 0;
190 DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %d\n", cptr,
191 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
192 NETSNMP_DS_LIB_SECLEVEL)));
197 snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz,
198 char **Xpsz, int argc, char *const *argv)
203 * Support '... -3x=value ....' syntax
205 if (*optarg == '=') {
209 * and '.... "-3x value" ....' (*with* the quotes)
211 while (*optarg && isspace(*optarg)) {
215 * Finally, handle ".... -3x value ...." syntax
216 * (*without* surrounding quotes)
220 * We've run off the end of the argument
221 * so move on the the next.
223 optarg = argv[optind++];
226 "Missing argument after SNMPv3 '-3%c' option.\n", *cp);
234 session->engineBoots = strtoul(optarg, NULL, 10);
235 if (session->engineBoots == 0 || !isdigit(optarg[0])) {
236 fprintf(stderr, "Need engine boots value after -3Z flag.\n");
239 cp = strchr(optarg, ',');
240 if (cp && *(++cp) && isdigit(*cp))
241 session->engineTime = strtoul(cp, NULL, 10);
243 fprintf(stderr, "Need engine time value after -3Z flag.\n");
249 size_t ebuf_len = 32, eout_len = 0;
250 u_char *ebuf = (u_char *) malloc(ebuf_len);
253 fprintf(stderr, "malloc failure processing -3e flag.\n");
256 if (!snmp_hex_to_binary
257 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
258 fprintf(stderr, "Bad engine ID value after -3e flag.\n");
262 session->securityEngineID = ebuf;
263 session->securityEngineIDLen = eout_len;
268 size_t ebuf_len = 32, eout_len = 0;
269 u_char *ebuf = (u_char *) malloc(ebuf_len);
272 fprintf(stderr, "malloc failure processing -3E flag.\n");
275 if (!snmp_hex_to_binary
276 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
277 fprintf(stderr, "Bad engine ID value after -3E flag.\n");
281 session->contextEngineID = ebuf;
282 session->contextEngineIDLen = eout_len;
287 session->contextName = optarg;
288 session->contextNameLen = strlen(optarg);
292 session->securityName = optarg;
293 session->securityNameLen = strlen(optarg);
297 if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
298 !strcasecmp(optarg, "nanp")) {
299 session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
300 } else if (!strcasecmp(optarg, "authNoPriv")
301 || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
302 session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
303 } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
304 || !strcasecmp(optarg, "ap")) {
305 session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
308 "Invalid security level specified after -3l flag: %s\n",
316 if (!strcasecmp(optarg, "MD5")) {
317 session->securityAuthProto = usmHMACMD5AuthProtocol;
318 session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
319 } else if (!strcasecmp(optarg, "SHA")) {
320 session->securityAuthProto = usmHMACSHA1AuthProtocol;
321 session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
324 "Invalid authentication protocol specified after -3a flag: %s\n",
331 if (!strcasecmp(optarg, "DES")) {
332 session->securityPrivProto = usmDESPrivProtocol;
333 session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
335 } else if (!strcasecmp(optarg, "AES128")) {
336 session->securityPrivProto = usmAES128PrivProtocol;
337 session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
338 } else if (!strcasecmp(optarg, "AES192")) {
339 session->securityPrivProto = usmAES192PrivProtocol;
340 session->securityPrivProtoLen = USM_PRIV_PROTO_AES192_LEN;
341 } else if (!strcasecmp(optarg, "AES256")) {
342 session->securityPrivProto = usmAES256PrivProtocol;
343 session->securityPrivProtoLen = USM_PRIV_PROTO_AES256_LEN;
347 "Invalid privacy protocol specified after -3x flag: %s\n",
362 fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", *cp);
368 /*******************************************************************-o-******
373 * *text Printable (?) text to be plugged into the snmpEngineID.
376 * Length of allocated engineID string in bytes, -OR-
380 * Create an snmpEngineID using text and the local IP address. If eidp
381 * is defined, use it to return a pointer to the newly allocated data.
382 * Otherwise, use the result to define engineID defined in this module.
385 * engineID <text> | NULL
387 * XXX What if a node has multiple interfaces?
388 * XXX What if multiple engines all choose the same address?
389 * (answer: You're screwed, because you might need a kul database
390 * which is dependant on the current engineID. Enumeration and other
391 * tricks won't work).
394 setup_engineID(u_char ** eidp, const char *text)
396 int enterpriseid = htonl(ENTERPRISE_OID),
397 ucdavisid = htonl(UCDAVIS_OID), localsetup = (eidp) ? 0 : 1;
400 * Use local engineID if *eidp == NULL.
402 #ifdef HAVE_GETHOSTNAME
403 u_char buf[SNMP_MAXBUF_SMALL];
404 struct hostent *hent;
408 int localEngineIDType = engineIDType;
415 * get the host name and save the information
417 #ifdef HAVE_GETHOSTNAME
418 gethostname((char *) buf, sizeof(buf));
419 hent = gethostbyname((char *) buf);
421 * Determine if we are using IPV6
425 * see if they selected IPV4 or IPV6 support
427 if ((ENGINEID_TYPE_IPV6 == localEngineIDType) ||
428 (ENGINEID_TYPE_IPV4 == localEngineIDType)) {
429 if (hent && hent->h_addrtype == AF_INET6) {
430 localEngineIDType = ENGINEID_TYPE_IPV6;
433 * Not IPV6 so we go with default
435 localEngineIDType = ENGINEID_TYPE_IPV4;
440 * No IPV6 support. Check if they selected IPV6 engineID type. If so
441 * * make it IPV4 for them
443 if (ENGINEID_TYPE_IPV6 == localEngineIDType) {
444 localEngineIDType = ENGINEID_TYPE_IPV4;
447 #endif /* HAVE_GETHOSTNAME */
450 * Determine if we have text and if so setup our localEngineIDType
454 engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT;
457 * Determine length of the engineID string.
459 len = 5; /* always have 5 leading bytes */
460 switch (localEngineIDType) {
461 case ENGINEID_TYPE_TEXT:
462 len += strlen(text); /* 5 leading bytes+text. No NULL char */
464 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
465 case ENGINEID_TYPE_MACADDR: /* MAC address */
466 len += 6; /* + 6 bytes for MAC address */
469 case ENGINEID_TYPE_IPV4: /* IPv4 */
470 len += 4; /* + 4 byte IPV4 address */
472 case ENGINEID_TYPE_IPV6: /* IPv6 */
473 len += 16; /* + 16 byte IPV6 address */
475 case ENGINEID_TYPE_UCD_RND: /* UCD specific encoding */
476 if (engineID) /* already setup, keep current value */
477 return engineIDLength;
479 len = oldEngineIDLength;
481 len += sizeof(int) + sizeof(time_t);
486 "Unknown EngineID type requested for setup (%d). Using IPv4.\n",
488 localEngineIDType = ENGINEID_TYPE_IPV4; /* make into IPV4 */
489 len += 4; /* + 4 byte IPv4 address */
495 * Allocate memory and store enterprise ID.
497 if ((bufp = (u_char *) malloc(len)) == NULL) {
498 snmp_log_perror("setup_engineID malloc");
501 if (localEngineIDType == ENGINEID_TYPE_UCD_RND)
503 * we must use the net-snmp enterprise id here, regardless
505 memcpy(bufp, &ucdavisid, sizeof(ucdavisid)); /* XXX Must be 4 bytes! */
507 memcpy(bufp, &enterpriseid, sizeof(enterpriseid)); /* XXX Must be 4 bytes! */
513 * Store the given text -OR- the first found IP address.
515 switch (localEngineIDType) {
516 case ENGINEID_TYPE_UCD_RND:
519 * keep our previous notion of the engineID
521 memcpy(bufp, oldEngineID, oldEngineIDLength);
524 * Here we've desigend our own ENGINEID that is not based on
525 * an address which may change and may even become conflicting
526 * in the future like most of the default v3 engineID types
529 * Ours is built from 2 fairly random elements: a random number and
530 * the current time in seconds. This method suffers from boxes
531 * that may not have a correct clock setting and random number
532 * seed at startup, but few OSes should have that problem.
534 bufp[4] = ENGINEID_TYPE_UCD_RND;
536 memcpy(bufp + 5, &tmpint, sizeof(tmpint));
537 tmptime = time(NULL);
538 memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime));
541 case ENGINEID_TYPE_TEXT:
542 bufp[4] = ENGINEID_TYPE_TEXT;
543 memcpy((char *) bufp + 5, text, strlen(text));
545 #ifdef HAVE_GETHOSTNAME
547 case ENGINEID_TYPE_IPV6:
548 bufp[4] = ENGINEID_TYPE_IPV6;
549 memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
553 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
554 case ENGINEID_TYPE_MACADDR:
557 bufp[4] = ENGINEID_TYPE_MACADDR;
559 * use default NIC if none provided
561 if (NULL == engineIDNic) {
562 x = getHwAddress(DEFAULT_NIC, &bufp[5]);
564 x = getHwAddress(engineIDNic, &bufp[5]);
568 * function failed fill MAC address with zeros
571 memset(&bufp[5], 0, 6);
576 case ENGINEID_TYPE_IPV4:
578 bufp[4] = ENGINEID_TYPE_IPV4;
579 #ifdef HAVE_GETHOSTNAME
580 if (hent && hent->h_addrtype == AF_INET) {
581 memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
582 } else { /* Unknown address type. Default to 127.0.0.1. */
589 #else /* HAVE_GETHOSTNAME */
591 * Unknown address type. Default to 127.0.0.1.
597 #endif /* HAVE_GETHOSTNAME */
602 * Pass the string back to the calling environment, or use it for
603 * our local engineID.
608 engineIDLength = len;
617 } /* end setup_engineID() */
620 usm_parse_create_usmUser(const char *token, char *line)
623 char buf[SNMP_MAXBUF_MEDIUM];
624 struct usmUser *newuser;
625 u_char userKey[SNMP_MAXBUF_SMALL];
626 size_t userKeyLen = SNMP_MAXBUF_SMALL;
629 newuser = usm_create_user();
632 * READ: Security Name
634 cp = copy_nword(line, buf, sizeof(buf));
637 * might be a -e ENGINEID argument
639 if (strcmp(buf, "-e") == 0) {
640 size_t ebuf_len = 32, eout_len = 0;
641 u_char *ebuf = (u_char *) malloc(ebuf_len);
644 config_perror("malloc failure processing -e flag");
645 usm_free_user(newuser);
650 * Get the specified engineid from the line.
652 cp = copy_nword(cp, buf, sizeof(buf));
653 if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) {
654 config_perror("invalid EngineID argument to -e");
655 usm_free_user(newuser);
660 newuser->engineID = ebuf;
661 newuser->engineIDLen = eout_len;
662 cp = copy_nword(cp, buf, sizeof(buf));
664 newuser->engineID = snmpv3_generate_engineID(&ret);
666 usm_free_user(newuser);
669 newuser->engineIDLen = ret;
672 newuser->secName = strdup(buf);
673 newuser->name = strdup(buf);
676 goto add; /* no authentication or privacy type */
679 * READ: Authentication Type
681 if (strncmp(cp, "MD5", 3) == 0) {
682 memcpy(newuser->authProtocol, usmHMACMD5AuthProtocol,
683 sizeof(usmHMACMD5AuthProtocol));
684 } else if (strncmp(cp, "SHA", 3) == 0) {
685 memcpy(newuser->authProtocol, usmHMACSHA1AuthProtocol,
686 sizeof(usmHMACSHA1AuthProtocol));
688 config_perror("Unknown authentication protocol");
689 usm_free_user(newuser);
696 * READ: Authentication Pass Phrase
699 config_perror("no authentication pass phrase");
700 usm_free_user(newuser);
703 cp = copy_nword(cp, buf, sizeof(buf));
705 * And turn it into a localized key
707 ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
708 (u_char *) buf, strlen(buf), userKey, &userKeyLen);
709 if (ret != SNMPERR_SUCCESS) {
710 config_perror("could not generate the authentication key from the "
711 "suppiled pass phrase.");
712 usm_free_user(newuser);
715 newuser->authKeyLen =
716 sc_get_properlength(newuser->authProtocol,
717 newuser->authProtocolLen);
718 newuser->authKey = (u_char *) malloc(newuser->authKeyLen);
719 ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
720 newuser->engineID, newuser->engineIDLen,
722 newuser->authKey, &newuser->authKeyLen);
723 if (ret != SNMPERR_SUCCESS) {
724 config_perror("could not generate localized authentication key (Kul) "
725 "from the master key (Ku).");
726 usm_free_user(newuser);
731 goto add; /* no privacy type (which is legal) */
736 if (strncmp(cp, "DES", 3) == 0) {
737 memcpy(newuser->privProtocol, usmDESPrivProtocol,
738 sizeof(usmDESPrivProtocol));
740 } else if (strncmp(cp, "AES128", 3) == 0) {
741 memcpy(newuser->privProtocol, usmAES128PrivProtocol,
742 sizeof(usmAES128PrivProtocol));
743 } else if (strncmp(cp, "AES192", 3) == 0) {
744 memcpy(newuser->privProtocol, usmAES192PrivProtocol,
745 sizeof(usmAES192PrivProtocol));
746 } else if (strncmp(cp, "AES256", 3) == 0) {
747 memcpy(newuser->privProtocol, usmAES256PrivProtocol,
748 sizeof(usmAES256PrivProtocol));
751 config_perror("Unknown privacy protocol");
752 usm_free_user(newuser);
758 * READ: Authentication Pass Phrase
762 * assume the same as the authentication key
764 memdup(&newuser->privKey, newuser->authKey, newuser->authKeyLen);
765 newuser->privKeyLen = newuser->authKeyLen;
767 cp = copy_nword(cp, buf, sizeof(buf));
769 * And turn it into a localized key
771 ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
772 (u_char *) buf, strlen(buf),
773 userKey, &userKeyLen);
774 if (ret != SNMPERR_SUCCESS) {
775 config_perror("could not generate privacy key from the supplied "
777 usm_free_user(newuser);
782 sc_get_properlength(newuser->authProtocol,
783 newuser->authProtocolLen);
785 config_perror("could not get proper key length to use for the "
786 "privacy algorithm.");
787 usm_free_user(newuser);
790 newuser->privKeyLen = ret;
792 newuser->privKey = (u_char *) malloc(newuser->privKeyLen);
793 ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
794 newuser->engineID, newuser->engineIDLen,
796 newuser->privKey, &newuser->privKeyLen);
797 if (ret != SNMPERR_SUCCESS) {
798 config_perror("could not generate the localized privacy key (Kul) "
799 "from the master key (Ku).");
800 usm_free_user(newuser);
805 usm_add_user(newuser);
806 DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName));
807 DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen));
808 DEBUGMSG(("usmUser", "\n"));
811 /*******************************************************************-o-******
819 * engineBoots <num_boots>
822 engineBoots_conf(const char *word, char *cptr)
824 engineBoots = atoi(cptr) + 1;
825 DEBUGMSGTL(("snmpv3", "engineBoots: %d\n", engineBoots));
828 /*******************************************************************-o-******
836 * engineIDType <1 or 3>
837 * 1 is default for IPv4 engine ID type. Will automatically
838 * chose between IPv4 & IPv6 if either 1 or 2 is specified.
840 * 3 is hardware (MAC) address, currently supported under Linux
843 engineIDType_conf(const char *word, char *cptr)
845 engineIDType = atoi(cptr);
847 * verify valid type selected
849 switch (engineIDType) {
850 case ENGINEID_TYPE_IPV4: /* IPv4 */
851 case ENGINEID_TYPE_IPV6: /* IPv6 */
853 * IPV? is always good
856 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
857 case ENGINEID_TYPE_MACADDR: /* MAC address */
862 * unsupported one chosen
864 config_perror("Unsupported enginedIDType, forcing IPv4");
865 engineIDType = ENGINEID_TYPE_IPV4;
867 DEBUGMSGTL(("snmpv3", "engineIDType: %d\n", engineIDType));
870 /*******************************************************************-o-******
878 * engineIDNic <string>
882 engineIDNic_conf(const char *word, char *cptr)
885 * Make sure they haven't already specified the engineID via the
886 * * configuration file
888 if (0 == engineIDIsSet)
890 * engineID has NOT been set via configuration file
894 * See if already set if so erase & release it
896 if (NULL != engineIDNic) {
899 engineIDNic = (u_char *) malloc(strlen(cptr) + 1);
900 if (NULL != engineIDNic) {
901 strcpy((char *) engineIDNic, cptr);
902 DEBUGMSGTL(("snmpv3", "Initializing engineIDNic: %s\n",
905 DEBUGMSGTL(("snmpv3",
906 "Error allocating memory for engineIDNic!\n"));
909 DEBUGMSGTL(("snmpv3",
910 "NOT setting engineIDNic, engineID already set\n"));
914 /*******************************************************************-o-******
921 * This function reads a string from the configuration file and uses that
922 * string to initialize the engineID. It's assumed to be human readable.
925 engineID_conf(const char *word, char *cptr)
927 setup_engineID(NULL, cptr);
928 DEBUGMSGTL(("snmpv3", "initialized engineID with: %s\n", cptr));
932 version_conf(const char *word, char *cptr)
934 if ((strcmp(cptr, "1") == 0) ||
935 (strcmp(cptr, "v1") == 0)) {
936 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
937 NETSNMP_DS_SNMP_VERSION_1); /* bogus value */
938 } else if ((strcasecmp(cptr, "2c") == 0) ||
939 (strcasecmp(cptr, "v2c") == 0)) {
940 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
941 NETSNMP_DS_SNMP_VERSION_2c);
942 } else if ((strcasecmp(cptr, "3" ) == 0) ||
943 (strcasecmp(cptr, "v3" ) == 0)) {
944 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
945 NETSNMP_DS_SNMP_VERSION_3);
947 config_perror("Unknown version specification");
950 DEBUGMSGTL(("snmpv3", "set default version to %d\n",
951 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
952 NETSNMP_DS_LIB_SNMPVERSION)));
956 * engineID_old_conf(const char *, char *):
958 * Reads a octet string encoded engineID into the oldEngineID and
959 * oldEngineIDLen pointers.
962 oldengineID_conf(const char *word, char *cptr)
964 read_config_read_octet_string(cptr, &oldEngineID, &oldEngineIDLength);
968 /*******************************************************************-o-******
972 * *type Label for the config file "type" used by calling entity.
974 * Set time and engineID.
975 * Set parsing functions for config file tokens.
976 * Initialize SNMP Crypto API (SCAPI).
979 init_snmpv3(const char *type)
982 gettimeofday(&snmpv3starttime, NULL);
985 type = "__snmpapp__";
988 * we need to be called back later
990 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
991 SNMP_CALLBACK_POST_READ_CONFIG,
992 init_snmpv3_post_config, NULL);
993 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
994 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
995 init_snmpv3_post_premib_config, NULL);
997 * we need to be called back later
999 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
1000 snmpv3_store, (void *) strdup(type));
1003 * initialize submodules
1006 * NOTE: this must be after the callbacks are registered above,
1007 * since they need to be called before the USM callbacks.
1012 * register all our configuration handlers (ack, there's a lot)
1016 * handle engineID setup before everything else which may depend on it
1018 register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL,
1020 register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf,
1022 register_prenetsnmp_mib_handler(type, "engineIDType",
1023 engineIDType_conf, NULL, "num");
1024 register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf,
1026 register_config_handler(type, "engineBoots", engineBoots_conf, NULL,
1030 * default store config entries
1032 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName",
1033 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME);
1034 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext",
1035 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT);
1036 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase",
1037 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PASSPHRASE);
1038 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase",
1039 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_AUTHPASSPHRASE);
1040 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase",
1041 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRIVPASSPHRASE);
1042 register_config_handler("snmp", "defVersion", version_conf, NULL,
1045 register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf,
1047 register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
1050 "DES (AES support not available)");
1052 "DES|AES128|AES192|AES256");
1054 register_config_handler("snmp", "defSecurityLevel",
1055 snmpv3_secLevel_conf, NULL,
1056 "noAuthNoPriv|authNoPriv|authPriv");
1057 register_config_handler(type, "userSetAuthPass", usm_set_password,
1059 register_config_handler(type, "userSetPrivPass", usm_set_password,
1061 register_config_handler(type, "userSetAuthKey", usm_set_password, NULL,
1063 register_config_handler(type, "userSetPrivKey", usm_set_password, NULL,
1065 register_config_handler(type, "userSetAuthLocalKey", usm_set_password,
1067 register_config_handler(type, "userSetPrivLocalKey", usm_set_password,
1072 * initializations for SNMPv3 to be called after the configuration files
1077 init_snmpv3_post_config(int majorid, int minorid, void *serverarg,
1084 c_engineID = snmpv3_generate_engineID(&engineIDLen);
1086 if (engineIDLen == 0) {
1088 * Somethine went wrong - help!
1090 return SNMPERR_GENERR;
1094 * if our engineID has changed at all, the boots record must be set to 1
1096 if (engineIDLen != (int) oldEngineIDLength ||
1097 oldEngineID == NULL || c_engineID == NULL ||
1098 memcmp(oldEngineID, c_engineID, engineIDLen) != 0) {
1103 * set our local engineTime in the LCD timing cache
1105 set_enginetime(c_engineID, engineIDLen,
1106 snmpv3_local_snmpEngineBoots(),
1107 snmpv3_local_snmpEngineTime(), TRUE);
1110 return SNMPERR_SUCCESS;
1114 init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg,
1118 setup_engineID(NULL, NULL);
1120 return SNMPERR_SUCCESS;
1123 /*******************************************************************-o-******
1130 snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg)
1132 char line[SNMP_MAXBUF_SMALL];
1133 u_char c_engineID[SNMP_MAXBUF_SMALL];
1135 const char *type = (const char *) clientarg;
1137 if (type == NULL) /* should never happen, since the arg is ours */
1140 sprintf(line, "engineBoots %ld", engineBoots);
1141 read_config_store(type, line);
1143 engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL);
1147 * store the engineID used for this run
1149 sprintf(line, "oldEngineID ");
1150 read_config_save_octet_string(line + strlen(line), c_engineID,
1152 read_config_store(type, line);
1154 return SNMPERR_SUCCESS;
1155 } /* snmpv3_store() */
1158 snmpv3_local_snmpEngineBoots(void)
1164 /*******************************************************************-o-******
1165 * snmpv3_get_engineID
1172 * Length of engineID On Success
1173 * SNMPERR_GENERR Otherwise.
1176 * Store engineID in buf; return the length.
1180 snmpv3_get_engineID(u_char * buf, size_t buflen)
1185 if (!buf || (buflen < engineIDLength)) {
1189 memcpy(buf, engineID, engineIDLength);
1190 return engineIDLength;
1192 } /* end snmpv3_get_engineID() */
1194 /*******************************************************************-o-******
1195 * snmpv3_clone_engineID
1204 * Length of engineID On Success
1208 * Clones engineID, creates memory
1212 snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src,
1215 if (!dest || !destlen)
1224 if (srclen && src) {
1225 *dest = (u_char *) malloc(srclen);
1228 memmove(*dest, src, srclen);
1232 } /* end snmpv3_clone_engineID() */
1235 /*******************************************************************-o-******
1236 * snmpv3_generate_engineID
1242 * Pointer to copy of engineID On Success.
1243 * NULL If malloc() or snmpv3_get_engineID()
1246 * Generates a malloced copy of our engineID.
1248 * 'length' is set to the length of engineID -OR- < 0 on failure.
1251 snmpv3_generate_engineID(size_t * length)
1254 newID = (u_char *) malloc(engineIDLength);
1257 *length = snmpv3_get_engineID(newID, engineIDLength);
1267 } /* end snmpv3_generate_engineID() */
1270 * snmpv3_local_snmpEngineTime(): return the number of seconds since the
1271 * snmpv3 engine last incremented engine_boots
1274 snmpv3_local_snmpEngineTime(void)
1278 gettimeofday(&now, NULL);
1279 return calculate_time_diff(&now, &snmpv3starttime) / 100;
1284 * Code only for Linux systems
1286 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
1288 getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */
1290 { /* return address. Len=IFHWADDRLEN */
1294 * * This function will return a Network Interfaces Card's Hardware
1295 * * address (aka MAC address).
1297 * * Input Parameter(s):
1298 * * networkDevice - a null terminated string with the name of a network
1299 * * device. Examples: eth0, eth1, etc...
1301 * * Output Parameter(s):
1302 * * addressOut - This is the binary value of the hardware address.
1303 * * This value is NOT converted into a hexadecimal string.
1304 * * The caller must pre-allocate for a return value of
1305 * * length IFHWADDRLEN
1307 * * Return value: This function will return zero (0) for success. If
1308 * * an error occurred the function will return -1.
1310 * * Caveats: This has only been tested on Ethernet networking cards.
1312 int sock; /* our socket */
1313 struct ifreq request; /* struct which will have HW address */
1315 if ((NULL == networkDevice) || (NULL == addressOut)) {
1319 * In order to find out the hardware (MAC) address of our system under
1320 * * Linux we must do the following:
1321 * * 1. Create a socket
1322 * * 2. Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation.
1324 sock = socket(AF_INET, SOCK_DGRAM, 0);
1329 * erase the request block
1331 memset(&request, 0, sizeof(request));
1333 * copy the name of the net device we want to find the HW address for
1335 strncpy(request.ifr_name, networkDevice, IFNAMSIZ - 1);
1337 * Get the HW address
1339 if (ioctl(sock, SIOCGIFHWADDR, &request)) {
1344 memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN);
1349 #ifdef SNMP_TESTING_CODE
1351 * snmpv3_set_engineBootsAndTime(): this function does not exist. Go away.
1354 * It certainly should never be used, unless in a testing scenero,
1355 * which is why it was created
1358 snmpv3_set_engineBootsAndTime(int boots, int ttime)
1360 engineBoots = boots;
1361 gettimeofday(&snmpv3starttime, NULL);
1362 snmpv3starttime.tv_sec -= ttime;
1366 #endif /* BRCM_SNMP_MIB_SUPPORT (snmpv3) */