snmpv3.c

00001 /*
00002  * snmpv3.c
00003  */
00004 
00005 #include <net-snmp/net-snmp-config.h>
00006 #include <errno.h>
00007 #ifdef HAVE_LIMITS_H
00008 #include <limits.h>
00009 #endif
00010 #include <stdio.h>
00011 #include <sys/types.h>
00012 
00013 #if TIME_WITH_SYS_TIME
00014 # ifdef WIN32
00015 #  include <sys/timeb.h>
00016 # else
00017 #  include <sys/time.h>
00018 # endif
00019 # include <time.h>
00020 #else
00021 # if HAVE_SYS_TIME_H
00022 #  include <sys/time.h>
00023 # else
00024 #  include <time.h>
00025 # endif
00026 #endif
00027 #if HAVE_SYS_TIMES_H
00028 #include <sys/times.h>
00029 #endif
00030 #if HAVE_STRING_H
00031 #include <string.h>
00032 #else
00033 #include <strings.h>
00034 #endif
00035 #include <ctype.h>
00036 #if HAVE_NETINET_IN_H
00037 #include <netinet/in.h>
00038 #endif
00039 #if HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 #if HAVE_WINSOCK_H
00043 #include <winsock.h>
00044 #endif
00045 #if HAVE_SYS_SOCKET_H
00046 #include <sys/socket.h>
00047 #endif
00048 #if HAVE_NETDB_H
00049 #include <netdb.h>
00050 #endif
00051 #if HAVE_STDLIB_H
00052 #       include <stdlib.h>
00053 #endif
00054 
00055 /*
00056  * Stuff needed for getHwAddress(...) 
00057  */
00058 #ifdef HAVE_SYS_IOCTL_H
00059 #       include <sys/ioctl.h>
00060 #endif
00061 #ifdef HAVE_NET_IF_H
00062 #       include <net/if.h>
00063 #endif
00064 
00065 #if HAVE_DMALLOC_H
00066 #include <dmalloc.h>
00067 #endif
00068 
00069 #include <net-snmp/types.h>
00070 #include <net-snmp/output_api.h>
00071 #include <net-snmp/config_api.h>
00072 #include <net-snmp/utilities.h>
00073 
00074 #include <net-snmp/library/snmpv3.h>
00075 #include <net-snmp/library/callback.h>
00076 #include <net-snmp/library/snmp_api.h>
00077 #include <net-snmp/library/lcd_time.h>
00078 #include <net-snmp/library/scapi.h>
00079 #include <net-snmp/library/keytools.h>
00080 #include <net-snmp/library/lcd_time.h>
00081 #include <net-snmp/library/snmp_secmod.h>
00082 #include <net-snmp/library/snmpusm.h>
00083 #include <net-snmp/library/transform_oids.h>
00084 
00085 static u_long   engineBoots = 1;
00086 static unsigned int engineIDType = ENGINEID_TYPE_NETSNMP_RND;
00087 static unsigned char *engineID = NULL;
00088 static size_t   engineIDLength = 0;
00089 static unsigned char *engineIDNic = NULL;
00090 static unsigned int engineIDIsSet = 0;  /* flag if ID set by config */
00091 static unsigned char *oldEngineID = NULL;
00092 static size_t   oldEngineIDLength = 0;
00093 static struct timeval snmpv3starttime;
00094 
00095 /*
00096  * Set up default snmpv3 parameter value storage.
00097  */
00098 static const oid *defaultAuthType = NULL;
00099 static size_t   defaultAuthTypeLen = 0;
00100 static const oid *defaultPrivType = NULL;
00101 static size_t   defaultPrivTypeLen = 0;
00102 
00103 /* this is probably an over-kill ifdef, but why not */
00104 #if defined(HAVE_SYS_TIMES_H) && defined(HAVE_UNISTD_H) && defined(HAVE_TIMES) && defined(_SC_CLK_TCK) && defined(HAVE_SYSCONF) && defined(UINT_MAX)
00105 
00106 #define SNMP_USE_TIMES 1
00107 
00108 static clock_t snmpv3startClock;
00109 static long clockticks = 0;
00110 static unsigned int lastcalltime = 0;
00111 static unsigned int wrapcounter = 0;
00112 
00113 #endif /* times() tests */
00114 
00115 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
00116 static int      getHwAddress(const char *networkDevice, char *addressOut);
00117 #endif
00118 
00119 void
00120 snmpv3_authtype_conf(const char *word, char *cptr)
00121 {
00122 #ifndef DISABLE_MD5
00123     if (strcasecmp(cptr, "MD5") == 0)
00124         defaultAuthType = usmHMACMD5AuthProtocol;
00125     else
00126 #endif
00127         if (strcasecmp(cptr, "SHA") == 0)
00128         defaultAuthType = usmHMACSHA1AuthProtocol;
00129     else
00130         config_perror("Unknown authentication type");
00131     defaultAuthTypeLen = USM_LENGTH_OID_TRANSFORM;
00132     DEBUGMSGTL(("snmpv3", "set default authentication type: %s\n", cptr));
00133 }
00134 
00135 const oid      *
00136 get_default_authtype(size_t * len)
00137 {
00138     if (defaultAuthType == NULL) {
00139         defaultAuthType = SNMP_DEFAULT_AUTH_PROTO;
00140         defaultAuthTypeLen = SNMP_DEFAULT_AUTH_PROTOLEN;
00141     }
00142     if (len)
00143         *len = defaultAuthTypeLen;
00144     return defaultAuthType;
00145 }
00146 
00147 void
00148 snmpv3_privtype_conf(const char *word, char *cptr)
00149 {
00150     int testcase = 0;
00151 
00152 #ifndef DISABLE_DES
00153     if (strcasecmp(cptr, "DES") == 0) {
00154         testcase = 1;
00155         defaultPrivType = usmDESPrivProtocol;
00156     }
00157 #endif
00158 
00159 #if HAVE_AES
00160     /* XXX AES: assumes oid length == des oid length */
00161     if (strcasecmp(cptr, "AES128") == 0 ||
00162         strcasecmp(cptr, "AES") == 0) {
00163         testcase = 1;
00164         defaultPrivType = usmAES128PrivProtocol;
00165     }
00166 #endif
00167     if (testcase == 0)
00168         config_perror("Unknown privacy type");
00169     defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN;
00170     DEBUGMSGTL(("snmpv3", "set default privacy type: %s\n", cptr));
00171 }
00172 
00173 const oid      *
00174 get_default_privtype(size_t * len)
00175 {
00176     if (defaultPrivType == NULL) {
00177 #ifndef DISABLE_DES
00178         defaultPrivType = usmDESPrivProtocol;
00179 #else
00180         defaultPrivType = usmAESPrivProtocol;
00181 #endif
00182         defaultPrivTypeLen = USM_LENGTH_OID_TRANSFORM;
00183     }
00184     if (len)
00185         *len = defaultPrivTypeLen;
00186     return defaultPrivType;
00187 }
00188 
00189 /*******************************************************************-o-******
00190  * snmpv3_secLevel_conf
00191  *
00192  * Parameters:
00193  *      *word
00194  *      *cptr
00195  *
00196  * Line syntax:
00197  *      defSecurityLevel "noAuthNoPriv" | "authNoPriv" | "authPriv"
00198  */
00199 
00200 int
00201 parse_secLevel_conf(const char *word, char *cptr) {
00202     if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 ||
00203         strcasecmp(cptr, "nanp") == 0) {
00204         return SNMP_SEC_LEVEL_NOAUTH;
00205     } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 ||
00206                strcasecmp(cptr, "anp") == 0) {
00207         return SNMP_SEC_LEVEL_AUTHNOPRIV;
00208     } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 ||
00209                strcasecmp(cptr, "ap") == 0) {
00210         return SNMP_SEC_LEVEL_AUTHPRIV;
00211     } else {
00212         return -1;
00213     }
00214 }
00215 
00216 void
00217 snmpv3_secLevel_conf(const char *word, char *cptr)
00218 {
00219     char            buf[1024];
00220     int             secLevel;
00221 
00222     if ((secLevel = parse_secLevel_conf( word, cptr )) >= 0 ) {
00223         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
00224                            NETSNMP_DS_LIB_SECLEVEL, secLevel);
00225     } else {
00226         snprintf(buf, sizeof(buf), "Unknown security level: %s", cptr);
00227         buf[ sizeof(buf)-1 ] = 0;
00228         config_perror(buf);
00229     }
00230     DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %d\n", cptr,
00231                 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
00232                                    NETSNMP_DS_LIB_SECLEVEL)));
00233 }
00234 
00235 
00236 int
00237 snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz,
00238                char **Xpsz, int argc, char *const *argv)
00239 {
00240     char           *cp = optarg;
00241     int testcase;
00242     optarg++;
00243     /*
00244      * Support '... -3x=value ....' syntax
00245      */
00246     if (*optarg == '=') {
00247         optarg++;
00248     }
00249     /*
00250      * and '.... "-3x value" ....'  (*with* the quotes)
00251      */
00252     while (*optarg && isspace(*optarg)) {
00253         optarg++;
00254     }
00255     /*
00256      * Finally, handle ".... -3x value ...." syntax
00257      *   (*without* surrounding quotes)
00258      */
00259     if (!*optarg) {
00260         /*
00261          * We've run off the end of the argument
00262          *  so move on the the next.
00263          */
00264         optarg = argv[optind++];
00265         if (optind > argc) {
00266             fprintf(stderr,
00267                     "Missing argument after SNMPv3 '-3%c' option.\n", *cp);
00268             return (-1);
00269         }
00270     }
00271 
00272     switch (*cp) {
00273 
00274     case 'Z':
00275         errno=0;
00276         session->engineBoots = strtoul(optarg, &cp, 10);
00277         if (errno || cp == optarg) {
00278             fprintf(stderr, "Need engine boots value after -3Z flag.\n");
00279             return (-1);
00280         }
00281         if (*cp == ',') {
00282             char *endptr;
00283             cp++;
00284             session->engineTime = strtoul(cp, &endptr, 10);
00285             if (errno || cp == endptr) {
00286                 fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
00287                 return (-1);
00288             }
00289         } else {
00290             fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
00291             return (-1);
00292         }
00293         break;
00294 
00295     case 'e':{
00296             size_t          ebuf_len = 32, eout_len = 0;
00297             u_char         *ebuf = (u_char *) malloc(ebuf_len);
00298 
00299             if (ebuf == NULL) {
00300                 fprintf(stderr, "malloc failure processing -3e flag.\n");
00301                 return (-1);
00302             }
00303             if (!snmp_hex_to_binary
00304                 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
00305                 fprintf(stderr, "Bad engine ID value after -3e flag.\n");
00306                 SNMP_FREE(ebuf);
00307                 return (-1);
00308             }
00309             session->securityEngineID = ebuf;
00310             session->securityEngineIDLen = eout_len;
00311             break;
00312         }
00313 
00314     case 'E':{
00315             size_t          ebuf_len = 32, eout_len = 0;
00316             u_char         *ebuf = (u_char *) malloc(ebuf_len);
00317 
00318             if (ebuf == NULL) {
00319                 fprintf(stderr, "malloc failure processing -3E flag.\n");
00320                 return (-1);
00321             }
00322             if (!snmp_hex_to_binary
00323                 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
00324                 fprintf(stderr, "Bad engine ID value after -3E flag.\n");
00325                 SNMP_FREE(ebuf);
00326                 return (-1);
00327             }
00328             session->contextEngineID = ebuf;
00329             session->contextEngineIDLen = eout_len;
00330             break;
00331         }
00332 
00333     case 'n':
00334         session->contextName = optarg;
00335         session->contextNameLen = strlen(optarg);
00336         break;
00337 
00338     case 'u':
00339         session->securityName = optarg;
00340         session->securityNameLen = strlen(optarg);
00341         break;
00342 
00343     case 'l':
00344         if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
00345             !strcasecmp(optarg, "nanp")) {
00346             session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
00347         } else if (!strcasecmp(optarg, "authNoPriv")
00348                    || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
00349             session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
00350         } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
00351                    || !strcasecmp(optarg, "ap")) {
00352             session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
00353         } else {
00354             fprintf(stderr,
00355                     "Invalid security level specified after -3l flag: %s\n",
00356                     optarg);
00357             return (-1);
00358         }
00359 
00360         break;
00361 
00362     case 'a':
00363 #ifndef DISABLE_MD5
00364         if (!strcasecmp(optarg, "MD5")) {
00365             session->securityAuthProto = usmHMACMD5AuthProtocol;
00366             session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
00367         } else
00368 #endif
00369             if (!strcasecmp(optarg, "SHA")) {
00370             session->securityAuthProto = usmHMACSHA1AuthProtocol;
00371             session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
00372         } else {
00373             fprintf(stderr,
00374                     "Invalid authentication protocol specified after -3a flag: %s\n",
00375                     optarg);
00376             return (-1);
00377         }
00378         break;
00379 
00380     case 'x':
00381         testcase = 0;
00382 #ifndef DISABLE_DES
00383         if (!strcasecmp(optarg, "DES")) {
00384             session->securityPrivProto = usmDESPrivProtocol;
00385             session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
00386             testcase = 1;
00387         }
00388 #endif
00389 #ifdef HAVE_AES
00390         if (!strcasecmp(optarg, "AES128") ||
00391             strcasecmp(optarg, "AES")) {
00392             session->securityPrivProto = usmAES128PrivProtocol;
00393             session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
00394             testcase = 1;
00395         }
00396 #endif
00397         if (testcase == 0) {
00398             fprintf(stderr,
00399                     "Invalid privacy protocol specified after -3x flag: %s\n",
00400                     optarg);
00401             return (-1);
00402         }
00403         break;
00404 
00405     case 'A':
00406         *Apsz = optarg;
00407         break;
00408 
00409     case 'X':
00410         *Xpsz = optarg;
00411         break;
00412 
00413     case 'm': {
00414         size_t bufSize = sizeof(session->securityAuthKey);
00415         u_char *tmpp = session->securityAuthKey;
00416         if (!snmp_hex_to_binary(&tmpp, &bufSize,
00417                                 &session->securityAuthKeyLen, 0, optarg)) {
00418             fprintf(stderr, "Bad key value after -3m flag.\n");
00419             return (-1);
00420         }
00421         break;
00422     }
00423 
00424     case 'M': {
00425         size_t bufSize = sizeof(session->securityPrivKey);
00426         u_char *tmpp = session->securityPrivKey;
00427         if (!snmp_hex_to_binary(&tmpp, &bufSize,
00428              &session->securityPrivKeyLen, 0, optarg)) {
00429             fprintf(stderr, "Bad key value after -3M flag.\n");
00430             return (-1);
00431         }
00432         break;
00433     }
00434 
00435     case 'k': {
00436         size_t          kbuf_len = 32, kout_len = 0;
00437         u_char         *kbuf = (u_char *) malloc(kbuf_len);
00438 
00439         if (kbuf == NULL) {
00440             fprintf(stderr, "malloc failure processing -3k flag.\n");
00441             return (-1);
00442         }
00443         if (!snmp_hex_to_binary
00444             (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
00445             fprintf(stderr, "Bad key value after -3k flag.\n");
00446             SNMP_FREE(kbuf);
00447             return (-1);
00448         }
00449         session->securityAuthLocalKey = kbuf;
00450         session->securityAuthLocalKeyLen = kout_len;
00451         break;
00452     }
00453 
00454     case 'K': {
00455         size_t          kbuf_len = 32, kout_len = 0;
00456         u_char         *kbuf = (u_char *) malloc(kbuf_len);
00457 
00458         if (kbuf == NULL) {
00459             fprintf(stderr, "malloc failure processing -3K flag.\n");
00460             return (-1);
00461         }
00462         if (!snmp_hex_to_binary
00463             (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
00464             fprintf(stderr, "Bad key value after -3K flag.\n");
00465             SNMP_FREE(kbuf);
00466             return (-1);
00467         }
00468         session->securityPrivLocalKey = kbuf;
00469         session->securityPrivLocalKeyLen = kout_len;
00470         break;
00471     }
00472         
00473     default:
00474         fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", *cp);
00475         return -1;
00476     }
00477     return 0;
00478 }
00479 
00480 /*******************************************************************-o-******
00481  * setup_engineID
00482  *
00483  * Parameters:
00484  *      **eidp
00485  *       *text  Printable (?) text to be plugged into the snmpEngineID.
00486  *
00487  * Return:
00488  *      Length of allocated engineID string in bytes,  -OR-
00489  *      -1 on error.
00490  *
00491  *
00492  * Create an snmpEngineID using text and the local IP address.  If eidp
00493  * is defined, use it to return a pointer to the newly allocated data.
00494  * Otherwise, use the result to define engineID defined in this module.
00495  *
00496  * Line syntax:
00497  *      engineID <text> | NULL
00498  *
00499  * XXX  What if a node has multiple interfaces?
00500  * XXX  What if multiple engines all choose the same address?
00501  *      (answer:  You're screwed, because you might need a kul database
00502  *       which is dependant on the current engineID.  Enumeration and other
00503  *       tricks won't work). 
00504  */
00505 int
00506 setup_engineID(u_char ** eidp, const char *text)
00507 {
00508     int             enterpriseid = htonl(ENTERPRISE_OID),
00509         netsnmpoid = htonl(NETSNMP_OID),
00510         localsetup = (eidp) ? 0 : 1;
00511 
00512     /*
00513      * Use local engineID if *eidp == NULL.  
00514      */
00515 #ifdef HAVE_GETHOSTNAME
00516     u_char          buf[SNMP_MAXBUF_SMALL];
00517     struct hostent *hent = NULL;
00518 #endif
00519     u_char         *bufp = NULL;
00520     size_t          len;
00521     int             localEngineIDType = engineIDType;
00522     int             tmpint;
00523     time_t          tmptime;
00524 
00525     engineIDIsSet = 1;
00526 
00527 #ifdef HAVE_GETHOSTNAME
00528 #ifdef AF_INET6
00529     /*
00530      * see if they selected IPV4 or IPV6 support 
00531      */
00532     if ((ENGINEID_TYPE_IPV6 == localEngineIDType) ||
00533         (ENGINEID_TYPE_IPV4 == localEngineIDType)) {
00534         /*
00535          * get the host name and save the information 
00536          */
00537         gethostname((char *) buf, sizeof(buf));
00538         hent = gethostbyname((char *) buf);
00539         if (hent && hent->h_addrtype == AF_INET6) {
00540             localEngineIDType = ENGINEID_TYPE_IPV6;
00541         } else {
00542             /*
00543              * Not IPV6 so we go with default 
00544              */
00545             localEngineIDType = ENGINEID_TYPE_IPV4;
00546         }
00547     }
00548 #else
00549     /*
00550      * No IPV6 support.  Check if they selected IPV6 engineID type.
00551      *  If so make it IPV4 instead 
00552      */
00553     if (ENGINEID_TYPE_IPV6 == localEngineIDType) {
00554         localEngineIDType = ENGINEID_TYPE_IPV4;
00555     }
00556     if (ENGINEID_TYPE_IPV4 == localEngineIDType) {
00557         /*
00558          * get the host name and save the information 
00559          */
00560         gethostname((char *) buf, sizeof(buf));
00561         hent = gethostbyname((char *) buf);
00562     }
00563 #endif
00564 #endif                          /* HAVE_GETHOSTNAME */
00565 
00566     /*
00567      * Determine if we have text and if so setup our localEngineIDType
00568      * * appropriately.  
00569      */
00570     if (NULL != text) {
00571         engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT;
00572     }
00573     /*
00574      * Determine length of the engineID string. 
00575      */
00576     len = 5;                    /* always have 5 leading bytes */
00577     switch (localEngineIDType) {
00578     case ENGINEID_TYPE_TEXT:
00579         if (NULL == text) {
00580             snmp_log(LOG_ERR,
00581                      "Can't set up engineID of type text from an empty string.\n");
00582             return -1;
00583         }
00584         len += strlen(text);    /* 5 leading bytes+text. No NULL char */
00585         break;
00586 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
00587     case ENGINEID_TYPE_MACADDR:        /* MAC address */
00588         len += 6;               /* + 6 bytes for MAC address */
00589         break;
00590 #endif
00591     case ENGINEID_TYPE_IPV4:   /* IPv4 */
00592         len += 4;               /* + 4 byte IPV4 address */
00593         break;
00594     case ENGINEID_TYPE_IPV6:   /* IPv6 */
00595         len += 16;              /* + 16 byte IPV6 address */
00596         break;
00597     case ENGINEID_TYPE_NETSNMP_RND:        /* Net-SNMP specific encoding */
00598         if (engineID)           /* already setup, keep current value */
00599             return engineIDLength;
00600         if (oldEngineID) {
00601             len = oldEngineIDLength;
00602         } else {
00603             len += sizeof(int) + sizeof(time_t);
00604         }
00605         break;
00606     default:
00607         snmp_log(LOG_ERR,
00608                  "Unknown EngineID type requested for setup (%d).  Using IPv4.\n",
00609                  localEngineIDType);
00610         localEngineIDType = ENGINEID_TYPE_IPV4; /* make into IPV4 */
00611         len += 4;               /* + 4 byte IPv4 address */
00612         break;
00613     }                           /* switch */
00614 
00615 
00616     /*
00617      * Allocate memory and store enterprise ID.
00618      */
00619     if ((bufp = (u_char *) malloc(len)) == NULL) {
00620         snmp_log_perror("setup_engineID malloc");
00621         return -1;
00622     }
00623     if (localEngineIDType == ENGINEID_TYPE_NETSNMP_RND)
00624         /*
00625          * we must use the net-snmp enterprise id here, regardless 
00626          */
00627         memcpy(bufp, &netsnmpoid, sizeof(netsnmpoid));    /* XXX Must be 4 bytes! */
00628     else
00629         memcpy(bufp, &enterpriseid, sizeof(enterpriseid));      /* XXX Must be 4 bytes! */
00630 
00631     bufp[0] |= 0x80;
00632 
00633 
00634     /*
00635      * Store the given text  -OR-   the first found IP address
00636      *  -OR-  the MAC address  -OR-  random elements
00637      * (the latter being the recommended default)
00638      */
00639     switch (localEngineIDType) {
00640     case ENGINEID_TYPE_NETSNMP_RND:
00641         if (oldEngineID) {
00642             /*
00643              * keep our previous notion of the engineID 
00644              */
00645             memcpy(bufp, oldEngineID, oldEngineIDLength);
00646         } else {
00647             /*
00648              * Here we've desigend our own ENGINEID that is not based on
00649              * an address which may change and may even become conflicting
00650              * in the future like most of the default v3 engineID types
00651              * suffer from.
00652              * 
00653              * Ours is built from 2 fairly random elements: a random number and
00654              * the current time in seconds.  This method suffers from boxes
00655              * that may not have a correct clock setting and random number
00656              * seed at startup, but few OSes should have that problem.
00657              */
00658             bufp[4] = ENGINEID_TYPE_NETSNMP_RND;
00659             tmpint = random();
00660             memcpy(bufp + 5, &tmpint, sizeof(tmpint));
00661             tmptime = time(NULL);
00662             memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime));
00663         }
00664         break;
00665     case ENGINEID_TYPE_TEXT:
00666         bufp[4] = ENGINEID_TYPE_TEXT;
00667         memcpy((char *) bufp + 5, (text), strlen(text));
00668         break;
00669 #ifdef HAVE_GETHOSTNAME
00670 #ifdef AF_INET6
00671     case ENGINEID_TYPE_IPV6:
00672         bufp[4] = ENGINEID_TYPE_IPV6;
00673         memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
00674         break;
00675 #endif
00676 #endif
00677 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
00678     case ENGINEID_TYPE_MACADDR:
00679         {
00680             int             x;
00681             bufp[4] = ENGINEID_TYPE_MACADDR;
00682             /*
00683              * use default NIC if none provided 
00684              */
00685             if (NULL == engineIDNic) {
00686                 x = getHwAddress(DEFAULT_NIC, &bufp[5]);
00687             } else {
00688                 x = getHwAddress(engineIDNic, &bufp[5]);
00689             }
00690             if (0 != x)
00691                 /*
00692                  * function failed fill MAC address with zeros 
00693                  */
00694             {
00695                 memset(&bufp[5], 0, 6);
00696             }
00697         }
00698         break;
00699 #endif
00700     case ENGINEID_TYPE_IPV4:
00701     default:
00702         bufp[4] = ENGINEID_TYPE_IPV4;
00703 #ifdef HAVE_GETHOSTNAME
00704         if (hent && hent->h_addrtype == AF_INET) {
00705             memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
00706         } else {                /* Unknown address type.  Default to 127.0.0.1. */
00707 
00708             bufp[5] = 127;
00709             bufp[6] = 0;
00710             bufp[7] = 0;
00711             bufp[8] = 1;
00712         }
00713 #else                           /* HAVE_GETHOSTNAME */
00714         /*
00715          * Unknown address type.  Default to 127.0.0.1. 
00716          */
00717         bufp[5] = 127;
00718         bufp[6] = 0;
00719         bufp[7] = 0;
00720         bufp[8] = 1;
00721 #endif                          /* HAVE_GETHOSTNAME */
00722         break;
00723     }
00724 
00725     /*
00726      * Pass the string back to the calling environment, or use it for
00727      * our local engineID.
00728      */
00729     if (localsetup) {
00730         SNMP_FREE(engineID);
00731         engineID = bufp;
00732         engineIDLength = len;
00733 
00734     } else {
00735         *eidp = bufp;
00736     }
00737 
00738 
00739     return len;
00740 
00741 }                               /* end setup_engineID() */
00742 
00743 int
00744 free_engineID(int majorid, int minorid, void *serverarg,
00745               void *clientarg)
00746 {
00747     SNMP_FREE(engineID);
00748     SNMP_FREE(engineIDNic);
00749     SNMP_FREE(oldEngineID);
00750     return 0;
00751 }
00752 
00753 int
00754 free_enginetime_on_shutdown(int majorid, int minorid, void *serverarg,
00755                             void *clientarg)
00756 {
00757     DEBUGMSGTL(("snmpv3", "free enginetime callback called\n"));
00758     if (engineID != NULL)
00759         free_enginetime(engineID, engineIDLength);
00760     return 0;
00761 }
00762 
00763 void
00764 usm_parse_create_usmUser(const char *token, char *line)
00765 {
00766     char           *cp;
00767     char            buf[SNMP_MAXBUF_MEDIUM];
00768     struct usmUser *newuser;
00769     u_char          userKey[SNMP_MAXBUF_SMALL], *tmpp;
00770     size_t          userKeyLen = SNMP_MAXBUF_SMALL;
00771     size_t          privKeyLen = 0;
00772     size_t          ret;
00773     int             ret2;
00774     int             testcase;
00775 
00776     newuser = usm_create_user();
00777 
00778     /*
00779      * READ: Security Name 
00780      */
00781     cp = copy_nword(line, buf, sizeof(buf));
00782 
00783     /*
00784      * might be a -e ENGINEID argument 
00785      */
00786     if (strcmp(buf, "-e") == 0) {
00787         size_t          ebuf_len = 32, eout_len = 0;
00788         u_char         *ebuf = (u_char *) malloc(ebuf_len);
00789 
00790         if (ebuf == NULL) {
00791             config_perror("malloc failure processing -e flag");
00792             usm_free_user(newuser);
00793             return;
00794         }
00795 
00796         /*
00797          * Get the specified engineid from the line.  
00798          */
00799         cp = copy_nword(cp, buf, sizeof(buf));
00800         if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) {
00801             config_perror("invalid EngineID argument to -e");
00802             usm_free_user(newuser);
00803             SNMP_FREE(ebuf);
00804             return;
00805         }
00806 
00807         newuser->engineID = ebuf;
00808         newuser->engineIDLen = eout_len;
00809         cp = copy_nword(cp, buf, sizeof(buf));
00810     } else {
00811         newuser->engineID = snmpv3_generate_engineID(&ret);
00812         if (ret == 0) {
00813             usm_free_user(newuser);
00814             return;
00815         }
00816         newuser->engineIDLen = ret;
00817     }
00818 
00819     newuser->secName = strdup(buf);
00820     newuser->name = strdup(buf);
00821 
00822     if (!cp)
00823         goto add;               /* no authentication or privacy type */
00824 
00825     /*
00826      * READ: Authentication Type 
00827      */
00828 #ifndef DISABLE_MD5
00829     if (strncmp(cp, "MD5", 3) == 0) {
00830         memcpy(newuser->authProtocol, usmHMACMD5AuthProtocol,
00831                sizeof(usmHMACMD5AuthProtocol));
00832     } else
00833 #endif
00834         if (strncmp(cp, "SHA", 3) == 0) {
00835         memcpy(newuser->authProtocol, usmHMACSHA1AuthProtocol,
00836                sizeof(usmHMACSHA1AuthProtocol));
00837     } else {
00838         config_perror("Unknown authentication protocol");
00839         usm_free_user(newuser);
00840         return;
00841     }
00842 
00843     cp = skip_token(cp);
00844 
00845     /*
00846      * READ: Authentication Pass Phrase or key
00847      */
00848     if (!cp) {
00849         config_perror("no authentication pass phrase");
00850         usm_free_user(newuser);
00851         return;
00852     }
00853     cp = copy_nword(cp, buf, sizeof(buf));
00854     if (strcmp(buf,"-m") == 0) {
00855         /* a master key is specified */
00856         cp = copy_nword(cp, buf, sizeof(buf));
00857         ret = sizeof(userKey);
00858         tmpp = userKey;
00859         userKeyLen = 0;
00860         if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
00861             config_perror("invalid key value argument to -m");
00862             usm_free_user(newuser);
00863             return;
00864         }
00865     } else if (strcmp(buf,"-l") != 0) {
00866         /* a password is specified */
00867         userKeyLen = sizeof(userKey);
00868         ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
00869                           (u_char *) buf, strlen(buf), userKey, &userKeyLen);
00870         if (ret2 != SNMPERR_SUCCESS) {
00871             config_perror("could not generate the authentication key from the "
00872                           "supplied pass phrase.");
00873             usm_free_user(newuser);
00874             return;
00875         }
00876     }        
00877         
00878     /*
00879      * And turn it into a localized key 
00880      */
00881     ret2 = sc_get_properlength(newuser->authProtocol,
00882                                newuser->authProtocolLen);
00883     if (ret2 <= 0) {
00884         config_perror("Could not get proper authentication protocol key length");
00885         return;
00886     }
00887     newuser->authKey = (u_char *) malloc(ret2);
00888 
00889     if (strcmp(buf,"-l") == 0) {
00890         /* a local key is directly specified */
00891         cp = copy_nword(cp, buf, sizeof(buf));
00892         newuser->authKeyLen = 0;
00893         ret = ret2;
00894         if (!snmp_hex_to_binary(&newuser->authKey, &ret,
00895                                 &newuser->authKeyLen, 0, buf)) {
00896             config_perror("invalid key value argument to -l");
00897             usm_free_user(newuser);
00898             return;
00899         }
00900         if (ret != newuser->authKeyLen) {
00901             config_perror("improper key length to -l");
00902             usm_free_user(newuser);
00903             return;
00904         }
00905     } else {
00906         newuser->authKeyLen = ret2;
00907         ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
00908                            newuser->engineID, newuser->engineIDLen,
00909                            userKey, userKeyLen,
00910                            newuser->authKey, &newuser->authKeyLen);
00911         if (ret2 != SNMPERR_SUCCESS) {
00912             config_perror("could not generate localized authentication key "
00913                           "(Kul) from the master key (Ku).");
00914             usm_free_user(newuser);
00915             return;
00916         }
00917     }
00918 
00919     if (!cp)
00920         goto add;               /* no privacy type (which is legal) */
00921 
00922     /*
00923      * READ: Privacy Type 
00924      */
00925     testcase = 0;
00926 #ifndef DISABLE_DES
00927     if (strncmp(cp, "DES", 3) == 0) {
00928         memcpy(newuser->privProtocol, usmDESPrivProtocol,
00929                sizeof(usmDESPrivProtocol));
00930         testcase = 1;
00931         /* DES uses a 128 bit key, 64 bits of which is a salt */
00932         privKeyLen = 16;
00933     }
00934 #endif
00935 #ifdef HAVE_AES
00936     if (strncmp(cp, "AES128", 6) == 0 ||
00937                strncmp(cp, "AES", 3) == 0) {
00938         memcpy(newuser->privProtocol, usmAESPrivProtocol,
00939                sizeof(usmAESPrivProtocol));
00940         testcase = 1;
00941         privKeyLen = 16;
00942     }
00943 #endif
00944     if (testcase == 0) {
00945         config_perror("Unknown privacy protocol");
00946         usm_free_user(newuser);
00947         return;
00948     }
00949 
00950     cp = skip_token(cp);
00951     /*
00952      * READ: Encryption Pass Phrase or key
00953      */
00954     if (!cp) {
00955         /*
00956          * assume the same as the authentication key 
00957          */
00958         memdup(&newuser->privKey, newuser->authKey, newuser->authKeyLen);
00959         newuser->privKeyLen = newuser->authKeyLen;
00960     } else {
00961         cp = copy_nword(cp, buf, sizeof(buf));
00962         
00963         if (strcmp(buf,"-m") == 0) {
00964             /* a master key is specified */
00965             cp = copy_nword(cp, buf, sizeof(buf));
00966             ret = sizeof(userKey);
00967             tmpp = userKey;
00968             userKeyLen = 0;
00969             if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
00970                 config_perror("invalid key value argument to -m");
00971                 usm_free_user(newuser);
00972                 return;
00973             }
00974         } else if (strcmp(buf,"-l") != 0) {
00975             /* a password is specified */
00976             userKeyLen = sizeof(userKey);
00977             ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
00978                               (u_char *) buf, strlen(buf), userKey, &userKeyLen);
00979             if (ret2 != SNMPERR_SUCCESS) {
00980                 config_perror("could not generate the privacy key from the "
00981                               "supplied pass phrase.");
00982                 usm_free_user(newuser);
00983                 return;
00984             }
00985         }        
00986         
00987         /*
00988          * And turn it into a localized key 
00989          */
00990         ret2 = sc_get_properlength(newuser->authProtocol,
00991                                    newuser->authProtocolLen);
00992         if (ret2 < 0) {
00993             config_perror("could not get proper key length to use for the "
00994                           "privacy algorithm.");
00995             usm_free_user(newuser);
00996             return;
00997         }
00998         newuser->privKey = (u_char *) malloc(ret2);
00999 
01000         if (strcmp(buf,"-l") == 0) {
01001             /* a local key is directly specified */
01002             cp = copy_nword(cp, buf, sizeof(buf));
01003             ret = ret2;
01004             newuser->privKeyLen = 0;
01005             if (!snmp_hex_to_binary(&newuser->privKey, &ret,
01006                                     &newuser->privKeyLen, 0, buf)) {
01007                 config_perror("invalid key value argument to -l");
01008                 usm_free_user(newuser);
01009                 return;
01010             }
01011         } else {
01012             newuser->privKeyLen = ret2;
01013             ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
01014                                newuser->engineID, newuser->engineIDLen,
01015                                userKey, userKeyLen,
01016                                newuser->privKey, &newuser->privKeyLen);
01017             if (ret2 != SNMPERR_SUCCESS) {
01018                 config_perror("could not generate localized privacy key "
01019                               "(Kul) from the master key (Ku).");
01020                 usm_free_user(newuser);
01021                 return;
01022             }
01023         }
01024     }
01025 
01026     if ((newuser->privKeyLen >= privKeyLen) || (privKeyLen == 0)){
01027       newuser->privKeyLen = privKeyLen;
01028     }
01029     else {
01030       /* The privKey length is smaller than required by privProtocol */
01031       usm_free_user(newuser);
01032       return;
01033     }
01034 
01035   add:
01036     usm_add_user(newuser);
01037     DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName));
01038     DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen));
01039     DEBUGMSG(("usmUser", "\n"));
01040 }
01041 
01042 /*******************************************************************-o-******
01043  * engineBoots_conf
01044  *
01045  * Parameters:
01046  *      *word
01047  *      *cptr
01048  *
01049  * Line syntax:
01050  *      engineBoots <num_boots>
01051  */
01052 void
01053 engineBoots_conf(const char *word, char *cptr)
01054 {
01055     engineBoots = atoi(cptr) + 1;
01056     DEBUGMSGTL(("snmpv3", "engineBoots: %d\n", engineBoots));
01057 }
01058 
01059 /*******************************************************************-o-******
01060  * engineIDType_conf
01061  *
01062  * Parameters:
01063  *      *word
01064  *      *cptr
01065  *
01066  * Line syntax:
01067  *      engineIDType <1 or 3>
01068  *              1 is default for IPv4 engine ID type.  Will automatically
01069  *                  chose between IPv4 & IPv6 if either 1 or 2 is specified.
01070  *              2 is for IPv6.
01071  *              3 is hardware (MAC) address, currently supported under Linux
01072  */
01073 void
01074 engineIDType_conf(const char *word, char *cptr)
01075 {
01076     engineIDType = atoi(cptr);
01077     /*
01078      * verify valid type selected 
01079      */
01080     switch (engineIDType) {
01081     case ENGINEID_TYPE_IPV4:   /* IPv4 */
01082     case ENGINEID_TYPE_IPV6:   /* IPv6 */
01083         /*
01084          * IPV? is always good 
01085          */
01086         break;
01087 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
01088     case ENGINEID_TYPE_MACADDR:        /* MAC address */
01089         break;
01090 #endif
01091     default:
01092         /*
01093          * unsupported one chosen 
01094          */
01095         config_perror("Unsupported enginedIDType, forcing IPv4");
01096         engineIDType = ENGINEID_TYPE_IPV4;
01097     }
01098     DEBUGMSGTL(("snmpv3", "engineIDType: %d\n", engineIDType));
01099 }
01100 
01101 /*******************************************************************-o-******
01102  * engineIDNic_conf
01103  *
01104  * Parameters:
01105  *      *word
01106  *      *cptr
01107  *
01108  * Line syntax:
01109  *      engineIDNic <string>
01110  *              eth0 is default
01111  */
01112 void
01113 engineIDNic_conf(const char *word, char *cptr)
01114 {
01115     /*
01116      * Make sure they haven't already specified the engineID via the
01117      * * configuration file 
01118      */
01119     if (0 == engineIDIsSet)
01120         /*
01121          * engineID has NOT been set via configuration file 
01122          */
01123     {
01124         /*
01125          * See if already set if so erase & release it 
01126          */
01127         if (NULL != engineIDNic) {
01128             SNMP_FREE(engineIDNic);
01129         }
01130         engineIDNic = (u_char *) malloc(strlen(cptr) + 1);
01131         if (NULL != engineIDNic) {
01132             strcpy((char *) engineIDNic, cptr);
01133             DEBUGMSGTL(("snmpv3", "Initializing engineIDNic: %s\n",
01134                         engineIDNic));
01135         } else {
01136             DEBUGMSGTL(("snmpv3",
01137                         "Error allocating memory for engineIDNic!\n"));
01138         }
01139     } else {
01140         DEBUGMSGTL(("snmpv3",
01141                     "NOT setting engineIDNic, engineID already set\n"));
01142     }
01143 }
01144 
01145 /*******************************************************************-o-******
01146  * engineID_conf
01147  *
01148  * Parameters:
01149  *      *word
01150  *      *cptr
01151  *
01152  * This function reads a string from the configuration file and uses that
01153  * string to initialize the engineID.  It's assumed to be human readable.
01154  */
01155 void
01156 engineID_conf(const char *word, char *cptr)
01157 {
01158     setup_engineID(NULL, cptr);
01159     DEBUGMSGTL(("snmpv3", "initialized engineID with: %s\n", cptr));
01160 }
01161 
01162 void
01163 version_conf(const char *word, char *cptr)
01164 {
01165     int valid = 0;
01166 #ifndef DISABLE_SNMPV1
01167     if ((strcmp(cptr,  "1") == 0) ||
01168         (strcmp(cptr, "v1") == 0)) {
01169         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
01170                            NETSNMP_DS_SNMP_VERSION_1);       /* bogus value */
01171         valid = 1;
01172     }
01173 #endif
01174 #ifndef DISABLE_SNMPV2C
01175     if ((strcasecmp(cptr,  "2c") == 0) ||
01176                (strcasecmp(cptr, "v2c") == 0)) {
01177         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
01178                            NETSNMP_DS_SNMP_VERSION_2c);
01179         valid = 1;
01180     }
01181 #endif
01182     if ((strcasecmp(cptr,  "3" ) == 0) ||
01183                (strcasecmp(cptr, "v3" ) == 0)) {
01184         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
01185                            NETSNMP_DS_SNMP_VERSION_3);
01186         valid = 1;
01187     }
01188     if (!valid) {
01189         config_perror("Unknown version specification");
01190         return;
01191     }
01192     DEBUGMSGTL(("snmpv3", "set default version to %d\n",
01193                 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
01194                                    NETSNMP_DS_LIB_SNMPVERSION)));
01195 }
01196 
01197 /*
01198  * engineID_old_conf(const char *, char *):
01199  * 
01200  * Reads a octet string encoded engineID into the oldEngineID and
01201  * oldEngineIDLen pointers.
01202  */
01203 void
01204 oldengineID_conf(const char *word, char *cptr)
01205 {
01206     read_config_read_octet_string(cptr, &oldEngineID, &oldEngineIDLength);
01207 }
01208 
01209 /*
01210  * merely call 
01211  */
01212 void
01213 get_enginetime_alarm(unsigned int regnum, void *clientargs)
01214 {
01215     /* we do this every so (rarely) often just to make sure we watch
01216        wrapping of the times() output */
01217     snmpv3_local_snmpEngineTime();
01218 }
01219 
01220 /*******************************************************************-o-******
01221  * init_snmpv3
01222  *
01223  * Parameters:
01224  *      *type   Label for the config file "type" used by calling entity.
01225  *      
01226  * Set time and engineID.
01227  * Set parsing functions for config file tokens.
01228  * Initialize SNMP Crypto API (SCAPI).
01229  */
01230 void
01231 init_snmpv3(const char *type)
01232 {
01233 #if SNMP_USE_TIMES
01234   struct tms dummy;
01235 
01236   /* fixme: -1 is fault code... */
01237   snmpv3startClock = times(&dummy);
01238 
01239   /* remember how many ticks per second there are, since times() returns this */
01240 
01241   clockticks = sysconf(_SC_CLK_TCK);
01242 
01243 #endif /* SNMP_USE_TIMES */
01244 
01245     gettimeofday(&snmpv3starttime, NULL);
01246 
01247     if (!type)
01248         type = "__snmpapp__";
01249 
01250     /*
01251      * we need to be called back later 
01252      */
01253     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
01254                            SNMP_CALLBACK_POST_READ_CONFIG,
01255                            init_snmpv3_post_config, NULL);
01256 
01257     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
01258                            SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
01259                            init_snmpv3_post_premib_config, NULL);
01260     /*
01261      * we need to be called back later 
01262      */
01263     snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
01264                            snmpv3_store, (void *) strdup(type));
01265 
01266     /*
01267      * Free stuff at shutdown time
01268      */
01269     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
01270                            SNMP_CALLBACK_SHUTDOWN,
01271                            free_enginetime_on_shutdown, NULL);
01272 
01273     /*
01274      * initialize submodules 
01275      */
01276     /*
01277      * NOTE: this must be after the callbacks are registered above,
01278      * since they need to be called before the USM callbacks. 
01279      */
01280     init_secmod();
01281 
01282     /*
01283      * register all our configuration handlers (ack, there's a lot) 
01284      */
01285 
01286     /*
01287      * handle engineID setup before everything else which may depend on it 
01288      */
01289     register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL,
01290                                     "string");
01291     register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf,
01292                                     NULL, NULL);
01293     register_prenetsnmp_mib_handler(type, "engineIDType",
01294                                     engineIDType_conf, NULL, "num");
01295     register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf,
01296                                     NULL, "string");
01297     register_config_handler(type, "engineBoots", engineBoots_conf, NULL,
01298                             NULL);
01299 
01300     /*
01301      * default store config entries 
01302      */
01303     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName",
01304                                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME);
01305     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext", 
01306                                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT);
01307     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase",
01308                                NETSNMP_DS_LIBRARY_ID,
01309                                NETSNMP_DS_LIB_PASSPHRASE);
01310     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase",
01311                                NETSNMP_DS_LIBRARY_ID,
01312                                NETSNMP_DS_LIB_AUTHPASSPHRASE);
01313     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase",
01314                                NETSNMP_DS_LIBRARY_ID,
01315                                NETSNMP_DS_LIB_PRIVPASSPHRASE);
01316     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthMasterKey",
01317                                NETSNMP_DS_LIBRARY_ID,
01318                                NETSNMP_DS_LIB_AUTHMASTERKEY);
01319     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivMasterKey",
01320                                NETSNMP_DS_LIBRARY_ID,
01321                                NETSNMP_DS_LIB_PRIVMASTERKEY);
01322     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthLocalizedKey",
01323                                NETSNMP_DS_LIBRARY_ID,
01324                                NETSNMP_DS_LIB_AUTHLOCALIZEDKEY);
01325     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivLocalizedKey",
01326                                NETSNMP_DS_LIBRARY_ID,
01327                                NETSNMP_DS_LIB_PRIVLOCALIZEDKEY);
01328     register_config_handler("snmp", "defVersion", version_conf, NULL,
01329                             "1|2c|3");
01330 
01331     register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf,
01332                             NULL, "MD5|SHA");
01333     register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
01334                             NULL,
01335 #ifdef HAVE_AES
01336                             "DES|AES");
01337 #else
01338                             "DES (AES support not available)");
01339 #endif
01340     register_config_handler("snmp", "defSecurityLevel",
01341                             snmpv3_secLevel_conf, NULL,
01342                             "noAuthNoPriv|authNoPriv|authPriv");
01343     register_config_handler(type, "userSetAuthPass", usm_set_password,
01344                             NULL, NULL);
01345     register_config_handler(type, "userSetPrivPass", usm_set_password,
01346                             NULL, NULL);
01347     register_config_handler(type, "userSetAuthKey", usm_set_password, NULL,
01348                             NULL);
01349     register_config_handler(type, "userSetPrivKey", usm_set_password, NULL,
01350                             NULL);
01351     register_config_handler(type, "userSetAuthLocalKey", usm_set_password,
01352                             NULL, NULL);
01353     register_config_handler(type, "userSetPrivLocalKey", usm_set_password,
01354                             NULL, NULL);
01355 }
01356 
01357 /*
01358  * initializations for SNMPv3 to be called after the configuration files
01359  * have been read.
01360  */
01361 
01362 int
01363 init_snmpv3_post_config(int majorid, int minorid, void *serverarg,
01364                         void *clientarg)
01365 {
01366 
01367     size_t          engineIDLen;
01368     u_char         *c_engineID;
01369 
01370     c_engineID = snmpv3_generate_engineID(&engineIDLen);
01371 
01372     if (engineIDLen == 0 || !c_engineID) {
01373         /*
01374          * Somethine went wrong - help! 
01375          */
01376         SNMP_FREE(c_engineID);
01377         return SNMPERR_GENERR;
01378     }
01379 
01380     /*
01381      * if our engineID has changed at all, the boots record must be set to 1 
01382      */
01383     if (engineIDLen != (int) oldEngineIDLength ||
01384         oldEngineID == NULL || c_engineID == NULL ||
01385         memcmp(oldEngineID, c_engineID, engineIDLen) != 0) {
01386         engineBoots = 1;
01387     }
01388 
01389     /*
01390      * set our local engineTime in the LCD timing cache 
01391      */
01392     set_enginetime(c_engineID, engineIDLen,
01393                    snmpv3_local_snmpEngineBoots(),
01394                    snmpv3_local_snmpEngineTime(), TRUE);
01395 
01396     SNMP_FREE(c_engineID);
01397     return SNMPERR_SUCCESS;
01398 }
01399 
01400 int
01401 init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg,
01402                                void *clientarg)
01403 {
01404     if (!engineIDIsSet)
01405         setup_engineID(NULL, NULL);
01406 
01407     return SNMPERR_SUCCESS;
01408 }
01409 
01410 /*******************************************************************-o-******
01411  * store_snmpv3
01412  *
01413  * Parameters:
01414  *      *type
01415  */
01416 int
01417 snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg)
01418 {
01419     char            line[SNMP_MAXBUF_SMALL];
01420     u_char          c_engineID[SNMP_MAXBUF_SMALL];
01421     int             engineIDLen;
01422     const char     *type = (const char *) clientarg;
01423 
01424     if (type == NULL)           /* should never happen, since the arg is ours */
01425         type = "unknown";
01426 
01427     sprintf(line, "engineBoots %ld", engineBoots);
01428     read_config_store(type, line);
01429 
01430     engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL);
01431 
01432     if (engineIDLen) {
01433         /*
01434          * store the engineID used for this run 
01435          */
01436         sprintf(line, "oldEngineID ");
01437         read_config_save_octet_string(line + strlen(line), c_engineID,
01438                                       engineIDLen);
01439         read_config_store(type, line);
01440     }
01441     return SNMPERR_SUCCESS;
01442 }                               /* snmpv3_store() */
01443 
01444 u_long
01445 snmpv3_local_snmpEngineBoots(void)
01446 {
01447     return engineBoots;
01448 }
01449 
01450 
01451 /*******************************************************************-o-******
01452  * snmpv3_get_engineID
01453  *
01454  * Parameters:
01455  *      *buf
01456  *       buflen
01457  *      
01458  * Returns:
01459  *      Length of engineID      On Success
01460  *      SNMPERR_GENERR          Otherwise.
01461  *
01462  *
01463  * Store engineID in buf; return the length.
01464  *
01465  */
01466 size_t
01467 snmpv3_get_engineID(u_char * buf, size_t buflen)
01468 {
01469     /*
01470      * Sanity check.
01471      */
01472     if (!buf || (buflen < engineIDLength)) {
01473         return 0;
01474     }
01475 
01476     memcpy(buf, engineID, engineIDLength);
01477     return engineIDLength;
01478 
01479 }                               /* end snmpv3_get_engineID() */
01480 
01481 /*******************************************************************-o-******
01482  * snmpv3_clone_engineID
01483  *
01484  * Parameters:
01485  *      **dest
01486  *       *dest_len
01487  *       src
01488  *       srclen
01489  *      
01490  * Returns:
01491  *      Length of engineID      On Success
01492  *      0                       Otherwise.
01493  *
01494  *
01495  * Clones engineID, creates memory
01496  *
01497  */
01498 int
01499 snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src,
01500                       size_t srclen)
01501 {
01502     if (!dest || !destlen)
01503         return 0;
01504 
01505     if (*dest) {
01506         SNMP_FREE(*dest);
01507         *dest = NULL;
01508     }
01509     *destlen = 0;
01510 
01511     if (srclen && src) {
01512         *dest = (u_char *) malloc(srclen);
01513         if (*dest == NULL)
01514             return 0;
01515         memmove(*dest, src, srclen);
01516         *destlen = srclen;
01517     }
01518     return *destlen;
01519 }                               /* end snmpv3_clone_engineID() */
01520 
01521 
01522 /*******************************************************************-o-******
01523  * snmpv3_generate_engineID
01524  *
01525  * Parameters:
01526  *      *length
01527  *      
01528  * Returns:
01529  *      Pointer to copy of engineID     On Success.
01530  *      NULL                            If malloc() or snmpv3_get_engineID()
01531  *                                              fail.
01532  *
01533  * Generates a malloced copy of our engineID.
01534  *
01535  * 'length' is set to the length of engineID  -OR-  < 0 on failure.
01536  */
01537 u_char         *
01538 snmpv3_generate_engineID(size_t * length)
01539 {
01540     u_char         *newID;
01541     newID = (u_char *) malloc(engineIDLength);
01542 
01543     if (newID) {
01544         *length = snmpv3_get_engineID(newID, engineIDLength);
01545     }
01546 
01547     if (*length == 0) {
01548         SNMP_FREE(newID);
01549         newID = NULL;
01550     }
01551 
01552     return newID;
01553 
01554 }                               /* end snmpv3_generate_engineID() */
01555 
01556 /*
01557  * snmpv3_local_snmpEngineTime(): return the number of seconds since the
01558  * snmpv3 engine last incremented engine_boots 
01559  */
01560 u_long
01561 snmpv3_local_snmpEngineTime(void)
01562 {
01563 #ifdef SNMP_USE_TIMES
01564   struct tms dummy;
01565   clock_t now = times(&dummy);
01566   /* fixme: -1 is fault code... */
01567   unsigned int result;
01568 
01569   if (now < snmpv3startClock) {
01570       result = UINT_MAX - (snmpv3startClock - now);
01571   } else {
01572       result = now - snmpv3startClock;
01573   }
01574   if (result < lastcalltime) {
01575       /* wrapped */
01576       wrapcounter++;
01577   }
01578   lastcalltime = result;
01579   result =  (UINT_MAX/clockticks)*wrapcounter + result/clockticks;
01580 
01581   return result;
01582 #else /* !SNMP_USE_TIMES */
01583     struct timeval  now;
01584 
01585     gettimeofday(&now, NULL);
01586     return calculate_sectime_diff(&now, &snmpv3starttime);
01587 #endif /* HAVE_SYS_TIMES_H */
01588 }
01589 
01590 
01591 
01592 /*
01593  * Code only for Linux systems 
01594  */
01595 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
01596 static int
01597 getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */
01598              char *addressOut)
01599 {                               /* return address. Len=IFHWADDRLEN */
01600     /*
01601      * getHwAddress(...)
01602      * *
01603      * *  This function will return a Network Interfaces Card's Hardware
01604      * *  address (aka MAC address).
01605      * *
01606      * *  Input Parameter(s):
01607      * *      networkDevice - a null terminated string with the name of a network
01608      * *                      device.  Examples: eth0, eth1, etc...
01609      * *
01610      * *  Output Parameter(s):
01611      * *      addressOut -    This is the binary value of the hardware address.
01612      * *                      This value is NOT converted into a hexadecimal string.
01613      * *                      The caller must pre-allocate for a return value of
01614      * *                      length IFHWADDRLEN
01615      * *
01616      * *  Return value:   This function will return zero (0) for success.  If
01617      * *                  an error occurred the function will return -1.
01618      * *
01619      * *  Caveats:    This has only been tested on Ethernet networking cards.
01620      */
01621     int             sock;       /* our socket */
01622     struct ifreq    request;    /* struct which will have HW address */
01623 
01624     if ((NULL == networkDevice) || (NULL == addressOut)) {
01625         return -1;
01626     }
01627     /*
01628      * In order to find out the hardware (MAC) address of our system under
01629      * * Linux we must do the following:
01630      * * 1.  Create a socket
01631      * * 2.  Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation.
01632      */
01633     sock = socket(AF_INET, SOCK_DGRAM, 0);
01634     if (sock < 0) {
01635         return -1;
01636     }
01637     /*
01638      * erase the request block 
01639      */
01640     memset(&request, 0, sizeof(request));
01641     /*
01642      * copy the name of the net device we want to find the HW address for 
01643      */
01644     strncpy(request.ifr_name, networkDevice, IFNAMSIZ - 1);
01645     /*
01646      * Get the HW address 
01647      */
01648     if (ioctl(sock, SIOCGIFHWADDR, &request)) {
01649         close(sock);
01650         return -1;
01651     }
01652     close(sock);
01653     memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN);
01654     return 0;
01655 }
01656 #endif
01657 
01658 #ifdef SNMP_TESTING_CODE
01659 /*
01660  * snmpv3_set_engineBootsAndTime(): this function does not exist.  Go away. 
01661  */
01662 /*
01663  * It certainly should never be used, unless in a testing scenero,
01664  * which is why it was created 
01665  */
01666 void
01667 snmpv3_set_engineBootsAndTime(int boots, int ttime)
01668 {
01669     engineBoots = boots;
01670     gettimeofday(&snmpv3starttime, NULL);
01671     snmpv3starttime.tv_sec -= ttime;
01672 }
01673 #endif

net-snmpに対してSat Sep 5 13:14:27 2009に生成されました。  doxygen 1.4.7