snmpv3.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:47k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * snmpv3.c
  3.  */
  4. #include <net-snmp/net-snmp-config.h>
  5. #ifdef HAVE_LIMITS_H
  6. #include <limits.h>
  7. #endif
  8. #include <stdio.h>
  9. #include <sys/types.h>
  10. #if TIME_WITH_SYS_TIME
  11. # ifdef WIN32
  12. #  include <sys/timeb.h>
  13. # else
  14. #  include <sys/time.h>
  15. # endif
  16. # include <time.h>
  17. #else
  18. # if HAVE_SYS_TIME_H
  19. #  include <sys/time.h>
  20. # else
  21. #  include <time.h>
  22. # endif
  23. #endif
  24. #if HAVE_SYS_TIMES_H
  25. #include <sys/times.h>
  26. #endif
  27. #if HAVE_STRING_H
  28. #include <string.h>
  29. #else
  30. #include <strings.h>
  31. #endif
  32. #include <ctype.h>
  33. #if HAVE_NETINET_IN_H
  34. #include <netinet/in.h>
  35. #endif
  36. #if HAVE_UNISTD_H
  37. #include <unistd.h>
  38. #endif
  39. #if HAVE_WINSOCK_H
  40. #include <winsock.h>
  41. #endif
  42. #if HAVE_SYS_SOCKET_H
  43. #include <sys/socket.h>
  44. #endif
  45. #if HAVE_NETDB_H
  46. #include <netdb.h>
  47. #endif
  48. #if HAVE_STDLIB_H
  49. #       include <stdlib.h>
  50. #endif
  51. /*
  52.  * Stuff needed for getHwAddress(...) 
  53.  */
  54. #ifdef HAVE_SYS_IOCTL_H
  55. # include <sys/ioctl.h>
  56. #endif
  57. #ifdef HAVE_NET_IF_H
  58. # include <net/if.h>
  59. #endif
  60. #if HAVE_DMALLOC_H
  61. #include <dmalloc.h>
  62. #endif
  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>
  67. #include <net-snmp/library/snmpv3.h>
  68. #include <net-snmp/library/callback.h>
  69. #include <net-snmp/library/snmp_api.h>
  70. #include <net-snmp/library/lcd_time.h>
  71. #include <net-snmp/library/scapi.h>
  72. #include <net-snmp/library/keytools.h>
  73. #include <net-snmp/library/lcd_time.h>
  74. #include <net-snmp/library/snmp_secmod.h>
  75. #include <net-snmp/library/snmpusm.h>
  76. #include <net-snmp/library/transform_oids.h>
  77. static u_long   engineBoots = 1;
  78. static unsigned int engineIDType = ENGINEID_TYPE_NETSNMP_RND;
  79. static unsigned char *engineID = NULL;
  80. static size_t   engineIDLength = 0;
  81. static unsigned char *engineIDNic = NULL;
  82. static unsigned int engineIDIsSet = 0;  /* flag if ID set by config */
  83. static unsigned char *oldEngineID = NULL;
  84. static size_t   oldEngineIDLength = 0;
  85. static struct timeval snmpv3starttime;
  86. /*
  87.  * Set up default snmpv3 parameter value storage.
  88.  */
  89. static const oid *defaultAuthType = NULL;
  90. static size_t   defaultAuthTypeLen = 0;
  91. static const oid *defaultPrivType = NULL;
  92. static size_t   defaultPrivTypeLen = 0;
  93. /* this is probably an over-kill ifdef, but why not */
  94. #if defined(HAVE_SYS_TIMES_H) && defined(HAVE_UNISTD_H) && defined(HAVE_TIMES) && defined(_SC_CLK_TCK) && defined(HAVE_SYSCONF) && defined(UINT_MAX)
  95. #define SNMP_USE_TIMES 1
  96. static clock_t snmpv3startClock;
  97. static long clockticks = 0;
  98. static unsigned int lastcalltime = 0;
  99. static unsigned int wrapcounter = 0;
  100. #endif /* times() tests */
  101. #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
  102. static int      getHwAddress(const char *networkDevice, char *addressOut);
  103. #endif
  104. void
  105. snmpv3_authtype_conf(const char *word, char *cptr)
  106. {
  107. #ifndef DISABLE_MD5
  108.     if (strcasecmp(cptr, "MD5") == 0)
  109.         defaultAuthType = usmHMACMD5AuthProtocol;
  110.     else
  111. #endif
  112.         if (strcasecmp(cptr, "SHA") == 0)
  113.         defaultAuthType = usmHMACSHA1AuthProtocol;
  114.     else
  115.         config_perror("Unknown authentication type");
  116.     defaultAuthTypeLen = USM_LENGTH_OID_TRANSFORM;
  117.     DEBUGMSGTL(("snmpv3", "set default authentication type: %sn", cptr));
  118. }
  119. const oid      *
  120. get_default_authtype(size_t * len)
  121. {
  122.     if (defaultAuthType == NULL) {
  123.         defaultAuthType = SNMP_DEFAULT_AUTH_PROTO;
  124.         defaultAuthTypeLen = SNMP_DEFAULT_AUTH_PROTOLEN;
  125.     }
  126.     if (len)
  127.         *len = defaultAuthTypeLen;
  128.     return defaultAuthType;
  129. }
  130. void
  131. snmpv3_privtype_conf(const char *word, char *cptr)
  132. {
  133.     int testcase = 0;
  134. #ifndef DISABLE_DES
  135.     if (strcasecmp(cptr, "DES") == 0) {
  136.         testcase = 1;
  137.         defaultPrivType = usmDESPrivProtocol;
  138.     }
  139. #endif
  140. #if HAVE_AES
  141.     /* XXX AES: assumes oid length == des oid length */
  142.     if (strcasecmp(cptr, "AES128") == 0 ||
  143.         strcasecmp(cptr, "AES") == 0) {
  144.         testcase = 1;
  145.         defaultPrivType = usmAES128PrivProtocol;
  146.     }
  147. #endif
  148.     if (testcase == 0)
  149.         config_perror("Unknown privacy type");
  150.     defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN;
  151.     DEBUGMSGTL(("snmpv3", "set default privacy type: %sn", cptr));
  152. }
  153. const oid      *
  154. get_default_privtype(size_t * len)
  155. {
  156.     if (defaultPrivType == NULL) {
  157. #ifndef DISABLE_DES
  158.         defaultPrivType = usmDESPrivProtocol;
  159. #else
  160.         defaultPrivType = usmAESPrivProtocol;
  161. #endif
  162.         defaultPrivTypeLen = USM_LENGTH_OID_TRANSFORM;
  163.     }
  164.     if (len)
  165.         *len = defaultPrivTypeLen;
  166.     return defaultPrivType;
  167. }
  168. /*******************************************************************-o-******
  169.  * snmpv3_secLevel_conf
  170.  *
  171.  * Parameters:
  172.  * *word
  173.  * *cptr
  174.  *
  175.  * Line syntax:
  176.  * defSecurityLevel "noAuthNoPriv" | "authNoPriv" | "authPriv"
  177.  */
  178. void
  179. snmpv3_secLevel_conf(const char *word, char *cptr)
  180. {
  181.     char            buf[1024];
  182.     if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 ||
  183. strcasecmp(cptr, "nanp") == 0) {
  184.         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
  185.    NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_NOAUTH);
  186.     } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 ||
  187.        strcasecmp(cptr, "anp") == 0) {
  188.         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
  189.    NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHNOPRIV);
  190.     } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 ||
  191.        strcasecmp(cptr, "ap") == 0) {
  192.         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
  193.    NETSNMP_DS_LIB_SECLEVEL, SNMP_SEC_LEVEL_AUTHPRIV);
  194.     } else {
  195.         snprintf(buf, sizeof(buf), "Unknown security level: %s", cptr);
  196.         buf[ sizeof(buf)-1 ] = 0;
  197.         config_perror(buf);
  198.     }
  199.     DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %dn", cptr,
  200.                 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  201.    NETSNMP_DS_LIB_SECLEVEL)));
  202. }
  203. int
  204. snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz,
  205.                char **Xpsz, int argc, char *const *argv)
  206. {
  207.     char           *cp = optarg;
  208.     int testcase;
  209.     optarg++;
  210.     /*
  211.      * Support '... -3x=value ....' syntax
  212.      */
  213.     if (*optarg == '=') {
  214.         optarg++;
  215.     }
  216.     /*
  217.      * and '.... "-3x value" ....'  (*with* the quotes)
  218.      */
  219.     while (*optarg && isspace(*optarg)) {
  220.         optarg++;
  221.     }
  222.     /*
  223.      * Finally, handle ".... -3x value ...." syntax
  224.      *   (*without* surrounding quotes)
  225.      */
  226.     if (!*optarg) {
  227.         /*
  228.          * We've run off the end of the argument
  229.          *  so move on the the next.
  230.          */
  231.         optarg = argv[optind++];
  232.         if (optind > argc) {
  233.             fprintf(stderr,
  234.                     "Missing argument after SNMPv3 '-3%c' option.n", *cp);
  235.             return (-1);
  236.         }
  237.     }
  238.     switch (*cp) {
  239.     case 'Z':
  240.         session->engineBoots = strtoul(optarg, NULL, 10);
  241.         if (session->engineBoots == 0 || !isdigit(optarg[0])) {
  242.             fprintf(stderr, "Need engine boots value after -3Z flag.n");
  243.             return (-1);
  244.         }
  245.         cp = strchr(optarg, ',');
  246.         if (cp && *(++cp) && isdigit(*cp))
  247.             session->engineTime = strtoul(cp, NULL, 10);
  248.         else {
  249.             fprintf(stderr, "Need engine time value after -3Z flag.n");
  250.             return (-1);
  251.         }
  252.         break;
  253.     case 'e':{
  254.             size_t          ebuf_len = 32, eout_len = 0;
  255.             u_char         *ebuf = (u_char *) malloc(ebuf_len);
  256.             if (ebuf == NULL) {
  257.                 fprintf(stderr, "malloc failure processing -3e flag.n");
  258.                 return (-1);
  259.             }
  260.             if (!snmp_hex_to_binary
  261.                 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
  262.                 fprintf(stderr, "Bad engine ID value after -3e flag.n");
  263.                 SNMP_FREE(ebuf);
  264.                 return (-1);
  265.             }
  266.             session->securityEngineID = ebuf;
  267.             session->securityEngineIDLen = eout_len;
  268.             break;
  269.         }
  270.     case 'E':{
  271.             size_t          ebuf_len = 32, eout_len = 0;
  272.             u_char         *ebuf = (u_char *) malloc(ebuf_len);
  273.             if (ebuf == NULL) {
  274.                 fprintf(stderr, "malloc failure processing -3E flag.n");
  275.                 return (-1);
  276.             }
  277.             if (!snmp_hex_to_binary
  278.                 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
  279.                 fprintf(stderr, "Bad engine ID value after -3E flag.n");
  280.                 SNMP_FREE(ebuf);
  281.                 return (-1);
  282.             }
  283.             session->contextEngineID = ebuf;
  284.             session->contextEngineIDLen = eout_len;
  285.             break;
  286.         }
  287.     case 'n':
  288.         session->contextName = optarg;
  289.         session->contextNameLen = strlen(optarg);
  290.         break;
  291.     case 'u':
  292.         session->securityName = optarg;
  293.         session->securityNameLen = strlen(optarg);
  294.         break;
  295.     case 'l':
  296.         if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
  297.             !strcasecmp(optarg, "nanp")) {
  298.             session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
  299.         } else if (!strcasecmp(optarg, "authNoPriv")
  300.                    || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
  301.             session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
  302.         } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
  303.                    || !strcasecmp(optarg, "ap")) {
  304.             session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
  305.         } else {
  306.             fprintf(stderr,
  307.                     "Invalid security level specified after -3l flag: %sn",
  308.                     optarg);
  309.             return (-1);
  310.         }
  311.         break;
  312.     case 'a':
  313. #ifndef DISABLE_MD5
  314.         if (!strcasecmp(optarg, "MD5")) {
  315.             session->securityAuthProto = usmHMACMD5AuthProtocol;
  316.             session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
  317.         } else
  318. #endif
  319.             if (!strcasecmp(optarg, "SHA")) {
  320.             session->securityAuthProto = usmHMACSHA1AuthProtocol;
  321.             session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
  322.         } else {
  323.             fprintf(stderr,
  324.                     "Invalid authentication protocol specified after -3a flag: %sn",
  325.                     optarg);
  326.             return (-1);
  327.         }
  328.         break;
  329.     case 'x':
  330.         testcase = 0;
  331. #ifndef DISABLE_DES
  332.         if (!strcasecmp(optarg, "DES")) {
  333.             session->securityPrivProto = usmDESPrivProtocol;
  334.             session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
  335.             testcase = 1;
  336.         }
  337. #endif
  338. #ifdef HAVE_AES
  339.         if (!strcasecmp(optarg, "AES128") ||
  340.             strcasecmp(optarg, "AES")) {
  341.             session->securityPrivProto = usmAES128PrivProtocol;
  342.             session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
  343.             testcase = 1;
  344.         }
  345. #endif
  346.         if (testcase == 0) {
  347.             fprintf(stderr,
  348.                     "Invalid privacy protocol specified after -3x flag: %sn",
  349.                     optarg);
  350.             return (-1);
  351.         }
  352.         break;
  353.     case 'A':
  354.         *Apsz = optarg;
  355.         break;
  356.     case 'X':
  357.         *Xpsz = optarg;
  358.         break;
  359.     case 'm': {
  360.         size_t bufSize = sizeof(session->securityAuthKey);
  361.         u_char *tmpp = session->securityAuthKey;
  362.         if (!snmp_hex_to_binary(&tmpp, &bufSize,
  363.                                 &session->securityAuthKeyLen, 0, optarg)) {
  364.             fprintf(stderr, "Bad key value after -3m flag.n");
  365.             return (-1);
  366.         }
  367.         break;
  368.     }
  369.     case 'M': {
  370.         size_t bufSize = sizeof(session->securityPrivKey);
  371.         u_char *tmpp = session->securityPrivKey;
  372.         if (!snmp_hex_to_binary(&tmpp, &bufSize,
  373.              &session->securityPrivKeyLen, 0, optarg)) {
  374.             fprintf(stderr, "Bad key value after -3M flag.n");
  375.             return (-1);
  376.         }
  377.         break;
  378.     }
  379.     case 'k': {
  380.         size_t          kbuf_len = 32, kout_len = 0;
  381.         u_char         *kbuf = (u_char *) malloc(kbuf_len);
  382.         if (kbuf == NULL) {
  383.             fprintf(stderr, "malloc failure processing -3k flag.n");
  384.             return (-1);
  385.         }
  386.         if (!snmp_hex_to_binary
  387.             (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
  388.             fprintf(stderr, "Bad key value after -3k flag.n");
  389.             SNMP_FREE(kbuf);
  390.             return (-1);
  391.         }
  392.         session->securityAuthLocalKey = kbuf;
  393.         session->securityAuthLocalKeyLen = kout_len;
  394.         break;
  395.     }
  396.     case 'K': {
  397.         size_t          kbuf_len = 32, kout_len = 0;
  398.         u_char         *kbuf = (u_char *) malloc(kbuf_len);
  399.         if (kbuf == NULL) {
  400.             fprintf(stderr, "malloc failure processing -3K flag.n");
  401.             return (-1);
  402.         }
  403.         if (!snmp_hex_to_binary
  404.             (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
  405.             fprintf(stderr, "Bad key value after -3K flag.n");
  406.             SNMP_FREE(kbuf);
  407.             return (-1);
  408.         }
  409.         session->securityPrivLocalKey = kbuf;
  410.         session->securityPrivLocalKeyLen = kout_len;
  411.         break;
  412.     }
  413.         
  414.     default:
  415.         fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.n", *cp);
  416.         return -1;
  417.     }
  418.     return 0;
  419. }
  420. /*******************************************************************-o-******
  421.  * setup_engineID
  422.  *
  423.  * Parameters:
  424.  * **eidp
  425.  *  *text Printable (?) text to be plugged into the snmpEngineID.
  426.  *
  427.  * Return:
  428.  * Length of allocated engineID string in bytes,  -OR-
  429.  * -1 on error.
  430.  *
  431.  *
  432.  * Create an snmpEngineID using text and the local IP address.  If eidp
  433.  * is defined, use it to return a pointer to the newly allocated data.
  434.  * Otherwise, use the result to define engineID defined in this module.
  435.  *
  436.  * Line syntax:
  437.  * engineID <text> | NULL
  438.  *
  439.  * XXX What if a node has multiple interfaces?
  440.  * XXX What if multiple engines all choose the same address?
  441.  *      (answer:  You're screwed, because you might need a kul database
  442.  *       which is dependant on the current engineID.  Enumeration and other
  443.  *       tricks won't work). 
  444.  */
  445. int
  446. setup_engineID(u_char ** eidp, const char *text)
  447. {
  448.     int             enterpriseid = htonl(ENTERPRISE_OID),
  449.         netsnmpoid = htonl(NETSNMP_OID),
  450.         localsetup = (eidp) ? 0 : 1;
  451.     /*
  452.      * Use local engineID if *eidp == NULL.  
  453.      */
  454. #ifdef HAVE_GETHOSTNAME
  455.     u_char          buf[SNMP_MAXBUF_SMALL];
  456.     struct hostent *hent = NULL;
  457. #endif
  458.     u_char         *bufp = NULL;
  459.     size_t          len;
  460.     int             localEngineIDType = engineIDType;
  461.     int             tmpint;
  462.     time_t          tmptime;
  463.     engineIDIsSet = 1;
  464. #ifdef HAVE_GETHOSTNAME
  465. #ifdef AF_INET6
  466.     /*
  467.      * see if they selected IPV4 or IPV6 support 
  468.      */
  469.     if ((ENGINEID_TYPE_IPV6 == localEngineIDType) ||
  470.         (ENGINEID_TYPE_IPV4 == localEngineIDType)) {
  471.         /*
  472.          * get the host name and save the information 
  473.          */
  474.         gethostname((char *) buf, sizeof(buf));
  475.         hent = gethostbyname((char *) buf);
  476.         if (hent && hent->h_addrtype == AF_INET6) {
  477.             localEngineIDType = ENGINEID_TYPE_IPV6;
  478.         } else {
  479.             /*
  480.              * Not IPV6 so we go with default 
  481.              */
  482.             localEngineIDType = ENGINEID_TYPE_IPV4;
  483.         }
  484.     }
  485. #else
  486.     /*
  487.      * No IPV6 support.  Check if they selected IPV6 engineID type.
  488.      *  If so make it IPV4 instead 
  489.      */
  490.     if (ENGINEID_TYPE_IPV6 == localEngineIDType) {
  491.         localEngineIDType = ENGINEID_TYPE_IPV4;
  492.     }
  493.     if (ENGINEID_TYPE_IPV4 == localEngineIDType) {
  494.         /*
  495.          * get the host name and save the information 
  496.          */
  497.         gethostname((char *) buf, sizeof(buf));
  498.         hent = gethostbyname((char *) buf);
  499.     }
  500. #endif
  501. #endif                          /* HAVE_GETHOSTNAME */
  502.     /*
  503.      * Determine if we have text and if so setup our localEngineIDType
  504.      * * appropriately.  
  505.      */
  506.     if (NULL != text) {
  507.         engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT;
  508.     }
  509.     /*
  510.      * Determine length of the engineID string. 
  511.      */
  512.     len = 5;                    /* always have 5 leading bytes */
  513.     switch (localEngineIDType) {
  514.     case ENGINEID_TYPE_TEXT:
  515.         len += strlen(text);    /* 5 leading bytes+text. No NULL char */
  516.         break;
  517. #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
  518.     case ENGINEID_TYPE_MACADDR:        /* MAC address */
  519.         len += 6;               /* + 6 bytes for MAC address */
  520.         break;
  521. #endif
  522.     case ENGINEID_TYPE_IPV4:   /* IPv4 */
  523.         len += 4;               /* + 4 byte IPV4 address */
  524.         break;
  525.     case ENGINEID_TYPE_IPV6:   /* IPv6 */
  526.         len += 16;              /* + 16 byte IPV6 address */
  527.         break;
  528.     case ENGINEID_TYPE_NETSNMP_RND:        /* Net-SNMP specific encoding */
  529.         if (engineID)           /* already setup, keep current value */
  530.             return engineIDLength;
  531.         if (oldEngineID) {
  532.             len = oldEngineIDLength;
  533.         } else {
  534.             len += sizeof(int) + sizeof(time_t);
  535.         }
  536.         break;
  537.     default:
  538.         snmp_log(LOG_ERR,
  539.                  "Unknown EngineID type requested for setup (%d).  Using IPv4.n",
  540.                  localEngineIDType);
  541.         localEngineIDType = ENGINEID_TYPE_IPV4; /* make into IPV4 */
  542.         len += 4;               /* + 4 byte IPv4 address */
  543.         break;
  544.     }                           /* switch */
  545.     /*
  546.      * Allocate memory and store enterprise ID.
  547.      */
  548.     if ((bufp = (u_char *) malloc(len)) == NULL) {
  549.         snmp_log_perror("setup_engineID malloc");
  550.         return -1;
  551.     }
  552.     if (localEngineIDType == ENGINEID_TYPE_NETSNMP_RND)
  553.         /*
  554.          * we must use the net-snmp enterprise id here, regardless 
  555.          */
  556.         memcpy(bufp, &netsnmpoid, sizeof(netsnmpoid));    /* XXX Must be 4 bytes! */
  557.     else
  558.         memcpy(bufp, &enterpriseid, sizeof(enterpriseid));      /* XXX Must be 4 bytes! */
  559.     bufp[0] |= 0x80;
  560.     /*
  561.      * Store the given text  -OR-   the first found IP address
  562.      *  -OR-  the MAC address  -OR-  random elements
  563.      * (the latter being the recommended default)
  564.      */
  565.     switch (localEngineIDType) {
  566.     case ENGINEID_TYPE_NETSNMP_RND:
  567.         if (oldEngineID) {
  568.             /*
  569.              * keep our previous notion of the engineID 
  570.              */
  571.             memcpy(bufp, oldEngineID, oldEngineIDLength);
  572.         } else {
  573.             /*
  574.              * Here we've desigend our own ENGINEID that is not based on
  575.              * an address which may change and may even become conflicting
  576.              * in the future like most of the default v3 engineID types
  577.              * suffer from.
  578.              * 
  579.              * Ours is built from 2 fairly random elements: a random number and
  580.              * the current time in seconds.  This method suffers from boxes
  581.              * that may not have a correct clock setting and random number
  582.              * seed at startup, but few OSes should have that problem.
  583.              */
  584.             bufp[4] = ENGINEID_TYPE_NETSNMP_RND;
  585.             tmpint = random();
  586.             memcpy(bufp + 5, &tmpint, sizeof(tmpint));
  587.             tmptime = time(NULL);
  588.             memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime));
  589.         }
  590.         break;
  591.     case ENGINEID_TYPE_TEXT:
  592.         bufp[4] = ENGINEID_TYPE_TEXT;
  593.         memcpy((char *) bufp + 5, text, strlen(text));
  594.         break;
  595. #ifdef HAVE_GETHOSTNAME
  596. #ifdef AF_INET6
  597.     case ENGINEID_TYPE_IPV6:
  598.         bufp[4] = ENGINEID_TYPE_IPV6;
  599.         memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
  600.         break;
  601. #endif
  602. #endif
  603. #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
  604.     case ENGINEID_TYPE_MACADDR:
  605.         {
  606.             int             x;
  607.             bufp[4] = ENGINEID_TYPE_MACADDR;
  608.             /*
  609.              * use default NIC if none provided 
  610.              */
  611.             if (NULL == engineIDNic) {
  612.                 x = getHwAddress(DEFAULT_NIC, &bufp[5]);
  613.             } else {
  614.                 x = getHwAddress(engineIDNic, &bufp[5]);
  615.             }
  616.             if (0 != x)
  617.                 /*
  618.                  * function failed fill MAC address with zeros 
  619.                  */
  620.             {
  621.                 memset(&bufp[5], 0, 6);
  622.             }
  623.         }
  624.         break;
  625. #endif
  626.     case ENGINEID_TYPE_IPV4:
  627.     default:
  628.         bufp[4] = ENGINEID_TYPE_IPV4;
  629. #ifdef HAVE_GETHOSTNAME
  630.         if (hent && hent->h_addrtype == AF_INET) {
  631.             memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
  632.         } else {                /* Unknown address type.  Default to 127.0.0.1. */
  633.             bufp[5] = 127;
  634.             bufp[6] = 0;
  635.             bufp[7] = 0;
  636.             bufp[8] = 1;
  637.         }
  638. #else                           /* HAVE_GETHOSTNAME */
  639.         /*
  640.          * Unknown address type.  Default to 127.0.0.1. 
  641.          */
  642.         bufp[5] = 127;
  643.         bufp[6] = 0;
  644.         bufp[7] = 0;
  645.         bufp[8] = 1;
  646. #endif                          /* HAVE_GETHOSTNAME */
  647.         break;
  648.     }
  649.     /*
  650.      * Pass the string back to the calling environment, or use it for
  651.      * our local engineID.
  652.      */
  653.     if (localsetup) {
  654.         SNMP_FREE(engineID);
  655.         engineID = bufp;
  656.         engineIDLength = len;
  657.     } else {
  658.         *eidp = bufp;
  659.     }
  660.     return len;
  661. }                               /* end setup_engineID() */
  662. int
  663. free_engineID(int majorid, int minorid, void *serverarg,
  664.       void *clientarg)
  665. {
  666.     SNMP_FREE(engineID);
  667.     SNMP_FREE(engineIDNic);
  668.     SNMP_FREE(oldEngineID);
  669.     return 0;
  670. }
  671. int
  672. free_enginetime_on_shutdown(int majorid, int minorid, void *serverarg,
  673.     void *clientarg)
  674. {
  675.     DEBUGMSGTL(("snmpv3", "free enginetime callback calledn"));
  676.     if (engineID != NULL)
  677. free_enginetime(engineID, engineIDLength);
  678.     return 0;
  679. }
  680. void
  681. usm_parse_create_usmUser(const char *token, char *line)
  682. {
  683.     char           *cp;
  684.     char            buf[SNMP_MAXBUF_MEDIUM];
  685.     struct usmUser *newuser;
  686.     u_char          userKey[SNMP_MAXBUF_SMALL], *tmpp;
  687.     size_t          userKeyLen = SNMP_MAXBUF_SMALL;
  688.     size_t          privKeyLen = 0;
  689.     size_t          ret;
  690.     int             testcase;
  691.     newuser = usm_create_user();
  692.     /*
  693.      * READ: Security Name 
  694.      */
  695.     cp = copy_nword(line, buf, sizeof(buf));
  696.     /*
  697.      * might be a -e ENGINEID argument 
  698.      */
  699.     if (strcmp(buf, "-e") == 0) {
  700.         size_t          ebuf_len = 32, eout_len = 0;
  701.         u_char         *ebuf = (u_char *) malloc(ebuf_len);
  702.         if (ebuf == NULL) {
  703.             config_perror("malloc failure processing -e flag");
  704.             usm_free_user(newuser);
  705.             return;
  706.         }
  707.         /*
  708.          * Get the specified engineid from the line.  
  709.          */
  710.         cp = copy_nword(cp, buf, sizeof(buf));
  711.         if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) {
  712.             config_perror("invalid EngineID argument to -e");
  713.             usm_free_user(newuser);
  714.             SNMP_FREE(ebuf);
  715.             return;
  716.         }
  717.         newuser->engineID = ebuf;
  718.         newuser->engineIDLen = eout_len;
  719.         cp = copy_nword(cp, buf, sizeof(buf));
  720.     } else {
  721.         newuser->engineID = snmpv3_generate_engineID(&ret);
  722.         if (ret == 0) {
  723.             usm_free_user(newuser);
  724.             return;
  725.         }
  726.         newuser->engineIDLen = ret;
  727.     }
  728.     newuser->secName = strdup(buf);
  729.     newuser->name = strdup(buf);
  730.     if (!cp)
  731.         goto add;               /* no authentication or privacy type */
  732.     /*
  733.      * READ: Authentication Type 
  734.      */
  735. #ifndef DISABLE_MD5
  736.     if (strncmp(cp, "MD5", 3) == 0) {
  737.         memcpy(newuser->authProtocol, usmHMACMD5AuthProtocol,
  738.                sizeof(usmHMACMD5AuthProtocol));
  739.     } else
  740. #endif
  741.         if (strncmp(cp, "SHA", 3) == 0) {
  742.         memcpy(newuser->authProtocol, usmHMACSHA1AuthProtocol,
  743.                sizeof(usmHMACSHA1AuthProtocol));
  744.     } else {
  745.         config_perror("Unknown authentication protocol");
  746.         usm_free_user(newuser);
  747.         return;
  748.     }
  749.     cp = skip_token(cp);
  750.     /*
  751.      * READ: Authentication Pass Phrase or key
  752.      */
  753.     if (!cp) {
  754.         config_perror("no authentication pass phrase");
  755.         usm_free_user(newuser);
  756.         return;
  757.     }
  758.     cp = copy_nword(cp, buf, sizeof(buf));
  759.     if (strcmp(buf,"-m") == 0) {
  760.         /* a master key is specified */
  761.         cp = copy_nword(cp, buf, sizeof(buf));
  762.         ret = sizeof(userKey);
  763.         tmpp = userKey;
  764.         userKeyLen = 0;
  765.         if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
  766.             config_perror("invalid key value argument to -m");
  767.             usm_free_user(newuser);
  768.             return;
  769.         }
  770.     } else if (strcmp(buf,"-l") != 0) {
  771.         /* a password is specified */
  772.         userKeyLen = sizeof(userKey);
  773.         ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
  774.                           (u_char *) buf, strlen(buf), userKey, &userKeyLen);
  775.         if (ret != SNMPERR_SUCCESS) {
  776.             config_perror("could not generate the authentication key from the "
  777.                           "suppiled pass phrase.");
  778.             usm_free_user(newuser);
  779.             return;
  780.         }
  781.     }        
  782.         
  783.     /*
  784.      * And turn it into a localized key 
  785.      */
  786.     ret =
  787.         sc_get_properlength(newuser->authProtocol,
  788.                             newuser->authProtocolLen);
  789.     if (ret <= 0) {
  790.         config_perror("Could not get proper authentication protocol key length");
  791.         return;
  792.     }
  793.     newuser->authKey = (u_char *) malloc(ret);
  794.     if (strcmp(buf,"-l") == 0) {
  795.         /* a local key is directly specified */
  796.         cp = copy_nword(cp, buf, sizeof(buf));
  797.         newuser->authKeyLen = 0;
  798.         if (!snmp_hex_to_binary(&newuser->authKey, &ret,
  799.                                 &newuser->authKeyLen, 0, buf)) {
  800.             config_perror("invalid key value argument to -l");
  801.             usm_free_user(newuser);
  802.             return;
  803.         }
  804.         if (ret != newuser->authKeyLen) {
  805.             config_perror("improper key length to -l");
  806.             usm_free_user(newuser);
  807.             return;
  808.         }
  809.     } else {
  810.         newuser->authKeyLen = ret;
  811.         ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
  812.                            newuser->engineID, newuser->engineIDLen,
  813.                            userKey, userKeyLen,
  814.                            newuser->authKey, &newuser->authKeyLen);
  815.         if (ret != SNMPERR_SUCCESS) {
  816.             config_perror("could not generate localized authentication key "
  817.                           "(Kul) from the master key (Ku).");
  818.             usm_free_user(newuser);
  819.             return;
  820.         }
  821.     }
  822.     if (!cp)
  823.         goto add;               /* no privacy type (which is legal) */
  824.     /*
  825.      * READ: Privacy Type 
  826.      */
  827.     testcase = 0;
  828. #ifndef DISABLE_DES
  829.     if (strncmp(cp, "DES", 3) == 0) {
  830.         memcpy(newuser->privProtocol, usmDESPrivProtocol,
  831.                sizeof(usmDESPrivProtocol));
  832.         testcase = 1;
  833. /* DES uses a 128 bit key, 64 bits of which is a salt */
  834. privKeyLen = 16;
  835.     }
  836. #endif
  837. #ifdef HAVE_AES
  838.     if (strncmp(cp, "AES128", 6) == 0 ||
  839.                strncmp(cp, "AES", 3) == 0) {
  840.         memcpy(newuser->privProtocol, usmAESPrivProtocol,
  841.                sizeof(usmAESPrivProtocol));
  842.         testcase = 1;
  843. privKeyLen = 16;
  844.     }
  845. #endif
  846.     if (testcase == 0) {
  847.         config_perror("Unknown privacy protocol");
  848.         usm_free_user(newuser);
  849.         return;
  850.     }
  851.     cp = skip_token(cp);
  852.     /*
  853.      * READ: Encryption Pass Phrase or key
  854.      */
  855.     if (!cp) {
  856.         /*
  857.          * assume the same as the authentication key 
  858.          */
  859.         memdup(&newuser->privKey, newuser->authKey, newuser->authKeyLen);
  860.         newuser->privKeyLen = newuser->authKeyLen;
  861.     } else {
  862.         cp = copy_nword(cp, buf, sizeof(buf));
  863.         
  864.         if (strcmp(buf,"-m") == 0) {
  865.             /* a master key is specified */
  866.             cp = copy_nword(cp, buf, sizeof(buf));
  867.             ret = sizeof(userKey);
  868.             tmpp = userKey;
  869.             userKeyLen = 0;
  870.             if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
  871.                 config_perror("invalid key value argument to -m");
  872.                 usm_free_user(newuser);
  873.                 return;
  874.             }
  875.         } else if (strcmp(buf,"-l") != 0) {
  876.             /* a password is specified */
  877.             userKeyLen = sizeof(userKey);
  878.             ret = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
  879.                               (u_char *) buf, strlen(buf), userKey, &userKeyLen);
  880.             if (ret != SNMPERR_SUCCESS) {
  881.                 config_perror("could not generate the privacy key from the "
  882.                               "suppiled pass phrase.");
  883.                 usm_free_user(newuser);
  884.                 return;
  885.             }
  886.         }        
  887.         
  888.         /*
  889.          * And turn it into a localized key 
  890.          */
  891.         ret =
  892.             sc_get_properlength(newuser->authProtocol,
  893.                                 newuser->authProtocolLen);
  894.         if (ret < 0) {
  895.             config_perror("could not get proper key length to use for the "
  896.                           "privacy algorithm.");
  897.             usm_free_user(newuser);
  898.             return;
  899.         }
  900.         newuser->privKey = (u_char *) malloc(ret);
  901.         if (strcmp(buf,"-l") == 0) {
  902.             /* a local key is directly specified */
  903.             cp = copy_nword(cp, buf, sizeof(buf));
  904.             newuser->privKeyLen = 0;
  905.             if (!snmp_hex_to_binary(&newuser->privKey, &ret,
  906.                                     &newuser->privKeyLen, 0, buf)) {
  907.                 config_perror("invalid key value argument to -l");
  908.                 usm_free_user(newuser);
  909.                 return;
  910.             }
  911.         } else {
  912.             newuser->privKeyLen = ret;
  913.             ret = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
  914.                                newuser->engineID, newuser->engineIDLen,
  915.                                userKey, userKeyLen,
  916.                                newuser->privKey, &newuser->privKeyLen);
  917.             if (ret != SNMPERR_SUCCESS) {
  918.                 config_perror("could not generate localized privacy key "
  919.                               "(Kul) from the master key (Ku).");
  920.                 usm_free_user(newuser);
  921.                 return;
  922.             }
  923.         }
  924.     }
  925.     if ((newuser->privKeyLen >= privKeyLen) || (privKeyLen == 0)){
  926.       newuser->privKeyLen = privKeyLen;
  927.     }
  928.     else {
  929.       /* The privKey length is smaller than required by privProtocol */
  930.       usm_free_user(newuser);
  931.       return;
  932.     }
  933.   add:
  934.     usm_add_user(newuser);
  935.     DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName));
  936.     DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen));
  937.     DEBUGMSG(("usmUser", "n"));
  938. }
  939. /*******************************************************************-o-******
  940.  * engineBoots_conf
  941.  *
  942.  * Parameters:
  943.  * *word
  944.  * *cptr
  945.  *
  946.  * Line syntax:
  947.  * engineBoots <num_boots>
  948.  */
  949. void
  950. engineBoots_conf(const char *word, char *cptr)
  951. {
  952.     engineBoots = atoi(cptr) + 1;
  953.     DEBUGMSGTL(("snmpv3", "engineBoots: %dn", engineBoots));
  954. }
  955. /*******************************************************************-o-******
  956.  * engineIDType_conf
  957.  *
  958.  * Parameters:
  959.  * *word
  960.  * *cptr
  961.  *
  962.  * Line syntax:
  963.  * engineIDType <1 or 3>
  964.  * 1 is default for IPv4 engine ID type.  Will automatically
  965.  *     chose between IPv4 & IPv6 if either 1 or 2 is specified.
  966.  * 2 is for IPv6.
  967.  * 3 is hardware (MAC) address, currently supported under Linux
  968.  */
  969. void
  970. engineIDType_conf(const char *word, char *cptr)
  971. {
  972.     engineIDType = atoi(cptr);
  973.     /*
  974.      * verify valid type selected 
  975.      */
  976.     switch (engineIDType) {
  977.     case ENGINEID_TYPE_IPV4:   /* IPv4 */
  978.     case ENGINEID_TYPE_IPV6:   /* IPv6 */
  979.         /*
  980.          * IPV? is always good 
  981.          */
  982.         break;
  983. #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
  984.     case ENGINEID_TYPE_MACADDR:        /* MAC address */
  985.         break;
  986. #endif
  987.     default:
  988.         /*
  989.          * unsupported one chosen 
  990.          */
  991.         config_perror("Unsupported enginedIDType, forcing IPv4");
  992.         engineIDType = ENGINEID_TYPE_IPV4;
  993.     }
  994.     DEBUGMSGTL(("snmpv3", "engineIDType: %dn", engineIDType));
  995. }
  996. /*******************************************************************-o-******
  997.  * engineIDNic_conf
  998.  *
  999.  * Parameters:
  1000.  * *word
  1001.  * *cptr
  1002.  *
  1003.  * Line syntax:
  1004.  * engineIDNic <string>
  1005.  * eth0 is default
  1006.  */
  1007. void
  1008. engineIDNic_conf(const char *word, char *cptr)
  1009. {
  1010.     /*
  1011.      * Make sure they haven't already specified the engineID via the
  1012.      * * configuration file 
  1013.      */
  1014.     if (0 == engineIDIsSet)
  1015.         /*
  1016.          * engineID has NOT been set via configuration file 
  1017.          */
  1018.     {
  1019.         /*
  1020.          * See if already set if so erase & release it 
  1021.          */
  1022.         if (NULL != engineIDNic) {
  1023.             SNMP_FREE(engineIDNic);
  1024.         }
  1025.         engineIDNic = (u_char *) malloc(strlen(cptr) + 1);
  1026.         if (NULL != engineIDNic) {
  1027.             strcpy((char *) engineIDNic, cptr);
  1028.             DEBUGMSGTL(("snmpv3", "Initializing engineIDNic: %sn",
  1029.                         engineIDNic));
  1030.         } else {
  1031.             DEBUGMSGTL(("snmpv3",
  1032.                         "Error allocating memory for engineIDNic!n"));
  1033.         }
  1034.     } else {
  1035.         DEBUGMSGTL(("snmpv3",
  1036.                     "NOT setting engineIDNic, engineID already setn"));
  1037.     }
  1038. }
  1039. /*******************************************************************-o-******
  1040.  * engineID_conf
  1041.  *
  1042.  * Parameters:
  1043.  * *word
  1044.  * *cptr
  1045.  *
  1046.  * This function reads a string from the configuration file and uses that
  1047.  * string to initialize the engineID.  It's assumed to be human readable.
  1048.  */
  1049. void
  1050. engineID_conf(const char *word, char *cptr)
  1051. {
  1052.     setup_engineID(NULL, cptr);
  1053.     DEBUGMSGTL(("snmpv3", "initialized engineID with: %sn", cptr));
  1054. }
  1055. void
  1056. version_conf(const char *word, char *cptr)
  1057. {
  1058.     int valid = 0;
  1059. #ifndef DISABLE_SNMPV1
  1060.     if ((strcmp(cptr,  "1") == 0) ||
  1061.         (strcmp(cptr, "v1") == 0)) {
  1062.         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
  1063.    NETSNMP_DS_SNMP_VERSION_1);       /* bogus value */
  1064.         valid = 1;
  1065.     }
  1066. #endif
  1067. #ifndef DISABLE_SNMPV2C
  1068.     if ((strcasecmp(cptr,  "2c") == 0) ||
  1069.                (strcasecmp(cptr, "v2c") == 0)) {
  1070.         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
  1071.    NETSNMP_DS_SNMP_VERSION_2c);
  1072.         valid = 1;
  1073.     }
  1074. #endif
  1075.     if ((strcasecmp(cptr,  "3" ) == 0) ||
  1076.                (strcasecmp(cptr, "v3" ) == 0)) {
  1077.         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
  1078.    NETSNMP_DS_SNMP_VERSION_3);
  1079.         valid = 1;
  1080.     }
  1081.     if (!valid) {
  1082.         config_perror("Unknown version specification");
  1083.         return;
  1084.     }
  1085.     DEBUGMSGTL(("snmpv3", "set default version to %dn",
  1086.                 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  1087.    NETSNMP_DS_LIB_SNMPVERSION)));
  1088. }
  1089. /*
  1090.  * engineID_old_conf(const char *, char *):
  1091.  * 
  1092.  * Reads a octet string encoded engineID into the oldEngineID and
  1093.  * oldEngineIDLen pointers.
  1094.  */
  1095. void
  1096. oldengineID_conf(const char *word, char *cptr)
  1097. {
  1098.     read_config_read_octet_string(cptr, &oldEngineID, &oldEngineIDLength);
  1099. }
  1100. /*
  1101.  * merely call 
  1102.  */
  1103. void
  1104. get_enginetime_alarm(unsigned int regnum, void *clientargs)
  1105. {
  1106.     /* we do this every so (rarely) often just to make sure we watch
  1107.        wrapping of the times() output */
  1108.     snmpv3_local_snmpEngineTime();
  1109. }
  1110. /*******************************************************************-o-******
  1111.  * init_snmpv3
  1112.  *
  1113.  * Parameters:
  1114.  * *type Label for the config file "type" used by calling entity.
  1115.  *      
  1116.  * Set time and engineID.
  1117.  * Set parsing functions for config file tokens.
  1118.  * Initialize SNMP Crypto API (SCAPI).
  1119.  */
  1120. void
  1121. init_snmpv3(const char *type)
  1122. {
  1123. #if SNMP_USE_TIMES
  1124.   struct tms dummy;
  1125.   /* fixme: -1 is fault code... */
  1126.   snmpv3startClock = times(&dummy);
  1127.   /* remember how many ticks per second there are, since times() returns this */
  1128.   clockticks = sysconf(_SC_CLK_TCK);
  1129. #endif /* SNMP_USE_TIMES */
  1130.     gettimeofday(&snmpv3starttime, NULL);
  1131.     if (!type)
  1132.         type = "__snmpapp__";
  1133.     /*
  1134.      * we need to be called back later 
  1135.      */
  1136.     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
  1137.                            SNMP_CALLBACK_POST_READ_CONFIG,
  1138.                            init_snmpv3_post_config, NULL);
  1139.     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
  1140.                            SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
  1141.                            init_snmpv3_post_premib_config, NULL);
  1142.     /*
  1143.      * we need to be called back later 
  1144.      */
  1145.     snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
  1146.                            snmpv3_store, (void *) strdup(type));
  1147.     /*
  1148.      * Free stuff at shutdown time
  1149.      */
  1150.     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
  1151.                            SNMP_CALLBACK_SHUTDOWN,
  1152.                            free_enginetime_on_shutdown, NULL);
  1153.     /*
  1154.      * initialize submodules 
  1155.      */
  1156.     /*
  1157.      * NOTE: this must be after the callbacks are registered above,
  1158.      * since they need to be called before the USM callbacks. 
  1159.      */
  1160.     init_secmod();
  1161.     /*
  1162.      * register all our configuration handlers (ack, there's a lot) 
  1163.      */
  1164.     /*
  1165.      * handle engineID setup before everything else which may depend on it 
  1166.      */
  1167.     register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL,
  1168.                                     "string");
  1169.     register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf,
  1170.                                     NULL, NULL);
  1171.     register_prenetsnmp_mib_handler(type, "engineIDType",
  1172.                                     engineIDType_conf, NULL, "num");
  1173.     register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf,
  1174.                                     NULL, "string");
  1175.     register_config_handler(type, "engineBoots", engineBoots_conf, NULL,
  1176.                             NULL);
  1177.     /*
  1178.      * default store config entries 
  1179.      */
  1180.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName",
  1181.        NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME);
  1182.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext", 
  1183.        NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT);
  1184.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase",
  1185.                                NETSNMP_DS_LIBRARY_ID,
  1186.                                NETSNMP_DS_LIB_PASSPHRASE);
  1187.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase",
  1188.                                NETSNMP_DS_LIBRARY_ID,
  1189.                                NETSNMP_DS_LIB_AUTHPASSPHRASE);
  1190.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase",
  1191.                                NETSNMP_DS_LIBRARY_ID,
  1192.                                NETSNMP_DS_LIB_PRIVPASSPHRASE);
  1193.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthMasterKey",
  1194.                                NETSNMP_DS_LIBRARY_ID,
  1195.                                NETSNMP_DS_LIB_AUTHMASTERKEY);
  1196.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivMasterKey",
  1197.                                NETSNMP_DS_LIBRARY_ID,
  1198.                                NETSNMP_DS_LIB_PRIVMASTERKEY);
  1199.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthLocalizedKey",
  1200.                                NETSNMP_DS_LIBRARY_ID,
  1201.                                NETSNMP_DS_LIB_AUTHLOCALIZEDKEY);
  1202.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivLocalizedKey",
  1203.                                NETSNMP_DS_LIBRARY_ID,
  1204.                                NETSNMP_DS_LIB_PRIVLOCALIZEDKEY);
  1205.     register_config_handler("snmp", "defVersion", version_conf, NULL,
  1206.                             "1|2c|3");
  1207.     register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf,
  1208.                             NULL, "MD5|SHA");
  1209.     register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
  1210.                             NULL,
  1211. #ifdef HAVE_AES
  1212.                             "DES|AES");
  1213. #else
  1214.                             "DES (AES support not available)");
  1215. #endif
  1216.     register_config_handler("snmp", "defSecurityLevel",
  1217.                             snmpv3_secLevel_conf, NULL,
  1218.                             "noAuthNoPriv|authNoPriv|authPriv");
  1219.     register_config_handler(type, "userSetAuthPass", usm_set_password,
  1220.                             NULL, NULL);
  1221.     register_config_handler(type, "userSetPrivPass", usm_set_password,
  1222.                             NULL, NULL);
  1223.     register_config_handler(type, "userSetAuthKey", usm_set_password, NULL,
  1224.                             NULL);
  1225.     register_config_handler(type, "userSetPrivKey", usm_set_password, NULL,
  1226.                             NULL);
  1227.     register_config_handler(type, "userSetAuthLocalKey", usm_set_password,
  1228.                             NULL, NULL);
  1229.     register_config_handler(type, "userSetPrivLocalKey", usm_set_password,
  1230.                             NULL, NULL);
  1231. }
  1232. /*
  1233.  * initializations for SNMPv3 to be called after the configuration files
  1234.  * have been read.
  1235.  */
  1236. int
  1237. init_snmpv3_post_config(int majorid, int minorid, void *serverarg,
  1238.                         void *clientarg)
  1239. {
  1240.     size_t          engineIDLen;
  1241.     u_char         *c_engineID;
  1242.     c_engineID = snmpv3_generate_engineID(&engineIDLen);
  1243.     if (engineIDLen == 0) {
  1244.         /*
  1245.          * Somethine went wrong - help! 
  1246.          */
  1247.         return SNMPERR_GENERR;
  1248.     }
  1249.     /*
  1250.      * if our engineID has changed at all, the boots record must be set to 1 
  1251.      */
  1252.     if (engineIDLen != (int) oldEngineIDLength ||
  1253.         oldEngineID == NULL || c_engineID == NULL ||
  1254.         memcmp(oldEngineID, c_engineID, engineIDLen) != 0) {
  1255.         engineBoots = 1;
  1256.     }
  1257.     /*
  1258.      * set our local engineTime in the LCD timing cache 
  1259.      */
  1260.     set_enginetime(c_engineID, engineIDLen,
  1261.                    snmpv3_local_snmpEngineBoots(),
  1262.                    snmpv3_local_snmpEngineTime(), TRUE);
  1263.     SNMP_FREE(c_engineID);
  1264.     return SNMPERR_SUCCESS;
  1265. }
  1266. int
  1267. init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg,
  1268.                                void *clientarg)
  1269. {
  1270.     if (!engineIDIsSet)
  1271.         setup_engineID(NULL, NULL);
  1272.     return SNMPERR_SUCCESS;
  1273. }
  1274. /*******************************************************************-o-******
  1275.  * store_snmpv3
  1276.  *
  1277.  * Parameters:
  1278.  * *type
  1279.  */
  1280. int
  1281. snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg)
  1282. {
  1283.     char            line[SNMP_MAXBUF_SMALL];
  1284.     u_char          c_engineID[SNMP_MAXBUF_SMALL];
  1285.     int             engineIDLen;
  1286.     const char     *type = (const char *) clientarg;
  1287.     if (type == NULL)           /* should never happen, since the arg is ours */
  1288.         type = "unknown";
  1289.     sprintf(line, "engineBoots %ld", engineBoots);
  1290.     read_config_store(type, line);
  1291.     engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL);
  1292.     if (engineIDLen) {
  1293.         /*
  1294.          * store the engineID used for this run 
  1295.          */
  1296.         sprintf(line, "oldEngineID ");
  1297.         read_config_save_octet_string(line + strlen(line), c_engineID,
  1298.                                       engineIDLen);
  1299.         read_config_store(type, line);
  1300.     }
  1301.     return SNMPERR_SUCCESS;
  1302. }                               /* snmpv3_store() */
  1303. u_long
  1304. snmpv3_local_snmpEngineBoots(void)
  1305. {
  1306.     return engineBoots;
  1307. }
  1308. /*******************************************************************-o-******
  1309.  * snmpv3_get_engineID
  1310.  *
  1311.  * Parameters:
  1312.  * *buf
  1313.  *  buflen
  1314.  *      
  1315.  * Returns:
  1316.  * Length of engineID On Success
  1317.  * SNMPERR_GENERR Otherwise.
  1318.  *
  1319.  *
  1320.  * Store engineID in buf; return the length.
  1321.  *
  1322.  */
  1323. size_t
  1324. snmpv3_get_engineID(u_char * buf, size_t buflen)
  1325. {
  1326.     /*
  1327.      * Sanity check.
  1328.      */
  1329.     if (!buf || (buflen < engineIDLength)) {
  1330.         return 0;
  1331.     }
  1332.     memcpy(buf, engineID, engineIDLength);
  1333.     return engineIDLength;
  1334. }                               /* end snmpv3_get_engineID() */
  1335. /*******************************************************************-o-******
  1336.  * snmpv3_clone_engineID
  1337.  *
  1338.  * Parameters:
  1339.  * **dest
  1340.  *       *dest_len
  1341.  *       src
  1342.  *  srclen
  1343.  *      
  1344.  * Returns:
  1345.  * Length of engineID On Success
  1346.  * 0         Otherwise.
  1347.  *
  1348.  *
  1349.  * Clones engineID, creates memory
  1350.  *
  1351.  */
  1352. int
  1353. snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src,
  1354.                       size_t srclen)
  1355. {
  1356.     if (!dest || !destlen)
  1357.         return 0;
  1358.     if (*dest) {
  1359.         SNMP_FREE(*dest);
  1360.         *dest = NULL;
  1361.     }
  1362.     *destlen = 0;
  1363.     if (srclen && src) {
  1364.         *dest = (u_char *) malloc(srclen);
  1365.         if (*dest == NULL)
  1366.             return 0;
  1367.         memmove(*dest, src, srclen);
  1368.         *destlen = srclen;
  1369.     }
  1370.     return *destlen;
  1371. }                               /* end snmpv3_clone_engineID() */
  1372. /*******************************************************************-o-******
  1373.  * snmpv3_generate_engineID
  1374.  *
  1375.  * Parameters:
  1376.  * *length
  1377.  *      
  1378.  * Returns:
  1379.  * Pointer to copy of engineID On Success.
  1380.  * NULL If malloc() or snmpv3_get_engineID()
  1381.  * fail.
  1382.  *
  1383.  * Generates a malloced copy of our engineID.
  1384.  *
  1385.  * 'length' is set to the length of engineID  -OR-  < 0 on failure.
  1386.  */
  1387. u_char         *
  1388. snmpv3_generate_engineID(size_t * length)
  1389. {
  1390.     u_char         *newID;
  1391.     newID = (u_char *) malloc(engineIDLength);
  1392.     if (newID) {
  1393.         *length = snmpv3_get_engineID(newID, engineIDLength);
  1394.     }
  1395.     if (*length == 0) {
  1396.         SNMP_FREE(newID);
  1397.         newID = NULL;
  1398.     }
  1399.     return newID;
  1400. }                               /* end snmpv3_generate_engineID() */
  1401. /*
  1402.  * snmpv3_local_snmpEngineTime(): return the number of seconds since the
  1403.  * snmpv3 engine last incremented engine_boots 
  1404.  */
  1405. u_long
  1406. snmpv3_local_snmpEngineTime(void)
  1407. {
  1408. #ifdef SNMP_USE_TIMES
  1409.   struct tms dummy;
  1410.   clock_t now = times(&dummy);
  1411.   /* fixme: -1 is fault code... */
  1412.   unsigned int result;
  1413.   if (now < snmpv3startClock) {
  1414.       result = UINT_MAX - (snmpv3startClock - now);
  1415.   } else {
  1416.       result = now - snmpv3startClock;
  1417.   }
  1418.   if (result < lastcalltime) {
  1419.       /* wrapped */
  1420.       wrapcounter++;
  1421.   }
  1422.   lastcalltime = result;
  1423.   result =  (UINT_MAX/clockticks)*wrapcounter + result/clockticks;
  1424.   return result;
  1425. #else /* !SNMP_USE_TIMES */
  1426.     struct timeval  now;
  1427.     gettimeofday(&now, NULL);
  1428.     return calculate_sectime_diff(&now, &snmpv3starttime);
  1429. #endif /* HAVE_SYS_TIMES_H */
  1430. }
  1431. /*
  1432.  * Code only for Linux systems 
  1433.  */
  1434. #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
  1435. static int
  1436. getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */
  1437.              char *addressOut)
  1438. {                               /* return address. Len=IFHWADDRLEN */
  1439.     /*
  1440.      * getHwAddress(...)
  1441.      * *
  1442.      * *  This function will return a Network Interfaces Card's Hardware
  1443.      * *  address (aka MAC address).
  1444.      * *
  1445.      * *  Input Parameter(s):
  1446.      * *      networkDevice - a null terminated string with the name of a network
  1447.      * *                      device.  Examples: eth0, eth1, etc...
  1448.      * *
  1449.      * *  Output Parameter(s):
  1450.      * *      addressOut -    This is the binary value of the hardware address.
  1451.      * *                      This value is NOT converted into a hexadecimal string.
  1452.      * *                      The caller must pre-allocate for a return value of
  1453.      * *                      length IFHWADDRLEN
  1454.      * *
  1455.      * *  Return value:   This function will return zero (0) for success.  If
  1456.      * *                  an error occurred the function will return -1.
  1457.      * *
  1458.      * *  Caveats:    This has only been tested on Ethernet networking cards.
  1459.      */
  1460.     int             sock;       /* our socket */
  1461.     struct ifreq    request;    /* struct which will have HW address */
  1462.     if ((NULL == networkDevice) || (NULL == addressOut)) {
  1463.         return -1;
  1464.     }
  1465.     /*
  1466.      * In order to find out the hardware (MAC) address of our system under
  1467.      * * Linux we must do the following:
  1468.      * * 1.  Create a socket
  1469.      * * 2.  Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation.
  1470.      */
  1471.     sock = socket(AF_INET, SOCK_DGRAM, 0);
  1472.     if (sock < 0) {
  1473.         return -1;
  1474.     }
  1475.     /*
  1476.      * erase the request block 
  1477.      */
  1478.     memset(&request, 0, sizeof(request));
  1479.     /*
  1480.      * copy the name of the net device we want to find the HW address for 
  1481.      */
  1482.     strncpy(request.ifr_name, networkDevice, IFNAMSIZ - 1);
  1483.     /*
  1484.      * Get the HW address 
  1485.      */
  1486.     if (ioctl(sock, SIOCGIFHWADDR, &request)) {
  1487.         close(sock);
  1488.         return -1;
  1489.     }
  1490.     close(sock);
  1491.     memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN);
  1492.     return 0;
  1493. }
  1494. #endif
  1495. #ifdef SNMP_TESTING_CODE
  1496. /*
  1497.  * snmpv3_set_engineBootsAndTime(): this function does not exist.  Go away. 
  1498.  */
  1499. /*
  1500.  * It certainly should never be used, unless in a testing scenero,
  1501.  * which is why it was created 
  1502.  */
  1503. void
  1504. snmpv3_set_engineBootsAndTime(int boots, int ttime)
  1505. {
  1506.     engineBoots = boots;
  1507.     gettimeofday(&snmpv3starttime, NULL);
  1508.     snmpv3starttime.tv_sec -= ttime;
  1509. }
  1510. #endif