net-snmp
5.4.1
|
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 NETSNMP_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 NETSNMP_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 NETSNMP_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 NETSNMP_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 NETSNMP_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(NETSNMP_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, (char *)&bufp[5]); 00687 } else { 00688 x = getHwAddress((char *)engineIDNic, (char *)&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 NETSNMP_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 NETSNMP_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 NETSNMP_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 NETSNMP_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 NETSNMP_ENABLE_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