net-snmp 5.7
|
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 # include <sys/time.h> 00015 # include <time.h> 00016 #else 00017 # if HAVE_SYS_TIME_H 00018 # include <sys/time.h> 00019 # else 00020 # include <time.h> 00021 # endif 00022 #endif 00023 #if HAVE_SYS_TIMES_H 00024 #include <sys/times.h> 00025 #endif 00026 #if HAVE_STRING_H 00027 #include <string.h> 00028 #else 00029 #include <strings.h> 00030 #endif 00031 #include <ctype.h> 00032 #if HAVE_NETINET_IN_H 00033 #include <netinet/in.h> 00034 #endif 00035 #if HAVE_UNISTD_H 00036 #include <unistd.h> 00037 #endif 00038 #if HAVE_SYS_SOCKET_H 00039 #include <sys/socket.h> 00040 #endif 00041 #if HAVE_NETDB_H 00042 #include <netdb.h> 00043 #endif 00044 #if HAVE_STDLIB_H 00045 # include <stdlib.h> 00046 #endif 00047 00048 /* 00049 * Stuff needed for getHwAddress(...) 00050 */ 00051 #ifdef HAVE_SYS_IOCTL_H 00052 # include <sys/ioctl.h> 00053 #endif 00054 #ifdef HAVE_NET_IF_H 00055 # include <net/if.h> 00056 #endif 00057 00058 #if HAVE_DMALLOC_H 00059 #include <dmalloc.h> 00060 #endif 00061 00062 #include <net-snmp/types.h> 00063 #include <net-snmp/output_api.h> 00064 #include <net-snmp/config_api.h> 00065 #include <net-snmp/utilities.h> 00066 00067 #include <net-snmp/library/snmpv3.h> 00068 #include <net-snmp/library/callback.h> 00069 #include <net-snmp/library/snmp_api.h> 00070 #include <net-snmp/library/lcd_time.h> 00071 #include <net-snmp/library/scapi.h> 00072 #include <net-snmp/library/keytools.h> 00073 #include <net-snmp/library/lcd_time.h> 00074 #include <net-snmp/library/snmp_secmod.h> 00075 #include <net-snmp/library/snmpusm.h> 00076 #include <net-snmp/library/transform_oids.h> 00077 00078 #include <net-snmp/net-snmp-features.h> 00079 00080 static u_long engineBoots = 1; 00081 static unsigned int engineIDType = ENGINEID_TYPE_NETSNMP_RND; 00082 static unsigned char *engineID = NULL; 00083 static size_t engineIDLength = 0; 00084 static unsigned char *engineIDNic = NULL; 00085 static unsigned int engineIDIsSet = 0; /* flag if ID set by config */ 00086 static unsigned char *oldEngineID = NULL; 00087 static size_t oldEngineIDLength = 0; 00088 static struct timeval snmpv3starttime; 00089 00090 /* this is probably an over-kill ifdef, but why not */ 00091 #if defined(HAVE_SYS_TIMES_H) && defined(HAVE_UNISTD_H) && defined(HAVE_TIMES) && defined(_SC_CLK_TCK) && defined(HAVE_SYSCONF) && defined(UINT_MAX) 00092 00093 #define SNMP_USE_TIMES 1 00094 00095 static clock_t snmpv3startClock; 00096 static long clockticks = 0; 00097 static unsigned int lastcalltime = 0; 00098 static unsigned int wrapcounter = 0; 00099 00100 #endif /* times() tests */ 00101 00102 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR) 00103 static int getHwAddress(const char *networkDevice, char *addressOut); 00104 #endif 00105 00106 /*******************************************************************-o-****** 00107 * snmpv3_secLevel_conf 00108 * 00109 * Parameters: 00110 * *word 00111 * *cptr 00112 * 00113 * Line syntax: 00114 * defSecurityLevel "noAuthNoPriv" | "authNoPriv" | "authPriv" 00115 */ 00116 00117 int 00118 parse_secLevel_conf(const char *word, char *cptr) { 00119 if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 || 00120 strcasecmp(cptr, "nanp") == 0) { 00121 return SNMP_SEC_LEVEL_NOAUTH; 00122 } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 || 00123 strcasecmp(cptr, "anp") == 0) { 00124 return SNMP_SEC_LEVEL_AUTHNOPRIV; 00125 } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 || 00126 strcasecmp(cptr, "ap") == 0) { 00127 return SNMP_SEC_LEVEL_AUTHPRIV; 00128 } else { 00129 return -1; 00130 } 00131 } 00132 00133 void 00134 snmpv3_secLevel_conf(const char *word, char *cptr) 00135 { 00136 int secLevel; 00137 00138 if ((secLevel = parse_secLevel_conf( word, cptr )) >= 0 ) { 00139 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 00140 NETSNMP_DS_LIB_SECLEVEL, secLevel); 00141 } else { 00142 netsnmp_config_error("Unknown security level: %s", cptr); 00143 } 00144 DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %d\n", cptr, 00145 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 00146 NETSNMP_DS_LIB_SECLEVEL))); 00147 } 00148 00149 00150 NETSNMP_IMPORT int 00151 snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz, 00152 char **Xpsz, int argc, char *const *argv); 00153 int 00154 snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz, 00155 char **Xpsz, int argc, char *const *argv) 00156 { 00157 char *cp = optarg; 00158 int testcase; 00159 optarg++; 00160 /* 00161 * Support '... -3x=value ....' syntax 00162 */ 00163 if (*optarg == '=') { 00164 optarg++; 00165 } 00166 /* 00167 * and '.... "-3x value" ....' (*with* the quotes) 00168 */ 00169 while (*optarg && isspace((unsigned char)(*optarg))) { 00170 optarg++; 00171 } 00172 /* 00173 * Finally, handle ".... -3x value ...." syntax 00174 * (*without* surrounding quotes) 00175 */ 00176 if (!*optarg) { 00177 /* 00178 * We've run off the end of the argument 00179 * so move on the the next. 00180 */ 00181 optarg = argv[optind++]; 00182 if (optind > argc) { 00183 fprintf(stderr, 00184 "Missing argument after SNMPv3 '-3%c' option.\n", *cp); 00185 return (-1); 00186 } 00187 } 00188 00189 switch (*cp) { 00190 00191 case 'Z': 00192 errno=0; 00193 session->engineBoots = strtoul(optarg, &cp, 10); 00194 if (errno || cp == optarg) { 00195 fprintf(stderr, "Need engine boots value after -3Z flag.\n"); 00196 return (-1); 00197 } 00198 if (*cp == ',') { 00199 char *endptr; 00200 cp++; 00201 session->engineTime = strtoul(cp, &endptr, 10); 00202 if (errno || cp == endptr) { 00203 fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n"); 00204 return (-1); 00205 } 00206 } else { 00207 fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n"); 00208 return (-1); 00209 } 00210 break; 00211 00212 case 'e':{ 00213 size_t ebuf_len = 32, eout_len = 0; 00214 u_char *ebuf = (u_char *) malloc(ebuf_len); 00215 00216 if (ebuf == NULL) { 00217 fprintf(stderr, "malloc failure processing -3e flag.\n"); 00218 return (-1); 00219 } 00220 if (!snmp_hex_to_binary 00221 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) { 00222 fprintf(stderr, "Bad engine ID value after -3e flag.\n"); 00223 SNMP_FREE(ebuf); 00224 return (-1); 00225 } 00226 session->securityEngineID = ebuf; 00227 session->securityEngineIDLen = eout_len; 00228 break; 00229 } 00230 00231 case 'E':{ 00232 size_t ebuf_len = 32, eout_len = 0; 00233 u_char *ebuf = (u_char *) malloc(ebuf_len); 00234 00235 if (ebuf == NULL) { 00236 fprintf(stderr, "malloc failure processing -3E flag.\n"); 00237 return (-1); 00238 } 00239 if (!snmp_hex_to_binary 00240 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) { 00241 fprintf(stderr, "Bad engine ID value after -3E flag.\n"); 00242 SNMP_FREE(ebuf); 00243 return (-1); 00244 } 00245 session->contextEngineID = ebuf; 00246 session->contextEngineIDLen = eout_len; 00247 break; 00248 } 00249 00250 case 'n': 00251 session->contextName = optarg; 00252 session->contextNameLen = strlen(optarg); 00253 break; 00254 00255 case 'u': 00256 session->securityName = optarg; 00257 session->securityNameLen = strlen(optarg); 00258 break; 00259 00260 case 'l': 00261 if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") || 00262 !strcasecmp(optarg, "nanp")) { 00263 session->securityLevel = SNMP_SEC_LEVEL_NOAUTH; 00264 } else if (!strcasecmp(optarg, "authNoPriv") 00265 || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) { 00266 session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; 00267 } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3") 00268 || !strcasecmp(optarg, "ap")) { 00269 session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; 00270 } else { 00271 fprintf(stderr, 00272 "Invalid security level specified after -3l flag: %s\n", 00273 optarg); 00274 return (-1); 00275 } 00276 00277 break; 00278 00279 #ifdef NETSNMP_SECMOD_USM 00280 case 'a': 00281 #ifndef NETSNMP_DISABLE_MD5 00282 if (!strcasecmp(optarg, "MD5")) { 00283 session->securityAuthProto = usmHMACMD5AuthProtocol; 00284 session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN; 00285 } else 00286 #endif 00287 if (!strcasecmp(optarg, "SHA")) { 00288 session->securityAuthProto = usmHMACSHA1AuthProtocol; 00289 session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN; 00290 } else { 00291 fprintf(stderr, 00292 "Invalid authentication protocol specified after -3a flag: %s\n", 00293 optarg); 00294 return (-1); 00295 } 00296 break; 00297 00298 case 'x': 00299 testcase = 0; 00300 #ifndef NETSNMP_DISABLE_DES 00301 if (!strcasecmp(optarg, "DES")) { 00302 session->securityPrivProto = usmDESPrivProtocol; 00303 session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN; 00304 testcase = 1; 00305 } 00306 #endif 00307 #ifdef HAVE_AES 00308 if (!strcasecmp(optarg, "AES128") || 00309 strcasecmp(optarg, "AES")) { 00310 session->securityPrivProto = usmAES128PrivProtocol; 00311 session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN; 00312 testcase = 1; 00313 } 00314 #endif 00315 if (testcase == 0) { 00316 fprintf(stderr, 00317 "Invalid privacy protocol specified after -3x flag: %s\n", 00318 optarg); 00319 return (-1); 00320 } 00321 break; 00322 00323 case 'A': 00324 *Apsz = optarg; 00325 break; 00326 00327 case 'X': 00328 *Xpsz = optarg; 00329 break; 00330 #endif /* NETSNMP_SECMOD_USM */ 00331 00332 case 'm': { 00333 size_t bufSize = sizeof(session->securityAuthKey); 00334 u_char *tmpp = session->securityAuthKey; 00335 if (!snmp_hex_to_binary(&tmpp, &bufSize, 00336 &session->securityAuthKeyLen, 0, optarg)) { 00337 fprintf(stderr, "Bad key value after -3m flag.\n"); 00338 return (-1); 00339 } 00340 break; 00341 } 00342 00343 case 'M': { 00344 size_t bufSize = sizeof(session->securityPrivKey); 00345 u_char *tmpp = session->securityPrivKey; 00346 if (!snmp_hex_to_binary(&tmpp, &bufSize, 00347 &session->securityPrivKeyLen, 0, optarg)) { 00348 fprintf(stderr, "Bad key value after -3M flag.\n"); 00349 return (-1); 00350 } 00351 break; 00352 } 00353 00354 case 'k': { 00355 size_t kbuf_len = 32, kout_len = 0; 00356 u_char *kbuf = (u_char *) malloc(kbuf_len); 00357 00358 if (kbuf == NULL) { 00359 fprintf(stderr, "malloc failure processing -3k flag.\n"); 00360 return (-1); 00361 } 00362 if (!snmp_hex_to_binary 00363 (&kbuf, &kbuf_len, &kout_len, 1, optarg)) { 00364 fprintf(stderr, "Bad key value after -3k flag.\n"); 00365 SNMP_FREE(kbuf); 00366 return (-1); 00367 } 00368 session->securityAuthLocalKey = kbuf; 00369 session->securityAuthLocalKeyLen = kout_len; 00370 break; 00371 } 00372 00373 case 'K': { 00374 size_t kbuf_len = 32, kout_len = 0; 00375 u_char *kbuf = (u_char *) malloc(kbuf_len); 00376 00377 if (kbuf == NULL) { 00378 fprintf(stderr, "malloc failure processing -3K flag.\n"); 00379 return (-1); 00380 } 00381 if (!snmp_hex_to_binary 00382 (&kbuf, &kbuf_len, &kout_len, 1, optarg)) { 00383 fprintf(stderr, "Bad key value after -3K flag.\n"); 00384 SNMP_FREE(kbuf); 00385 return (-1); 00386 } 00387 session->securityPrivLocalKey = kbuf; 00388 session->securityPrivLocalKeyLen = kout_len; 00389 break; 00390 } 00391 00392 default: 00393 fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", *cp); 00394 return -1; 00395 } 00396 return 0; 00397 } 00398 00399 /*******************************************************************-o-****** 00400 * setup_engineID 00401 * 00402 * Parameters: 00403 * **eidp 00404 * *text Printable (?) text to be plugged into the snmpEngineID. 00405 * 00406 * Return: 00407 * Length of allocated engineID string in bytes, -OR- 00408 * -1 on error. 00409 * 00410 * 00411 * Create an snmpEngineID using text and the local IP address. If eidp 00412 * is defined, use it to return a pointer to the newly allocated data. 00413 * Otherwise, use the result to define engineID defined in this module. 00414 * 00415 * Line syntax: 00416 * engineID <text> | NULL 00417 * 00418 * XXX What if a node has multiple interfaces? 00419 * XXX What if multiple engines all choose the same address? 00420 * (answer: You're screwed, because you might need a kul database 00421 * which is dependant on the current engineID. Enumeration and other 00422 * tricks won't work). 00423 */ 00424 int 00425 setup_engineID(u_char ** eidp, const char *text) 00426 { 00427 int enterpriseid = htonl(NETSNMP_ENTERPRISE_OID), 00428 netsnmpoid = htonl(NETSNMP_OID), 00429 localsetup = (eidp) ? 0 : 1; 00430 00431 /* 00432 * Use local engineID if *eidp == NULL. 00433 */ 00434 #ifdef HAVE_GETHOSTNAME 00435 u_char buf[SNMP_MAXBUF_SMALL]; 00436 struct hostent *hent = NULL; 00437 #endif 00438 u_char *bufp = NULL; 00439 size_t len; 00440 int localEngineIDType = engineIDType; 00441 int tmpint; 00442 time_t tmptime; 00443 00444 engineIDIsSet = 1; 00445 00446 #ifdef HAVE_GETHOSTNAME 00447 #ifdef AF_INET6 00448 /* 00449 * see if they selected IPV4 or IPV6 support 00450 */ 00451 if ((ENGINEID_TYPE_IPV6 == localEngineIDType) || 00452 (ENGINEID_TYPE_IPV4 == localEngineIDType)) { 00453 /* 00454 * get the host name and save the information 00455 */ 00456 gethostname((char *) buf, sizeof(buf)); 00457 hent = netsnmp_gethostbyname((char *) buf); 00458 if (hent && hent->h_addrtype == AF_INET6) { 00459 localEngineIDType = ENGINEID_TYPE_IPV6; 00460 } else { 00461 /* 00462 * Not IPV6 so we go with default 00463 */ 00464 localEngineIDType = ENGINEID_TYPE_IPV4; 00465 } 00466 } 00467 #else 00468 /* 00469 * No IPV6 support. Check if they selected IPV6 engineID type. 00470 * If so make it IPV4 instead 00471 */ 00472 if (ENGINEID_TYPE_IPV6 == localEngineIDType) { 00473 localEngineIDType = ENGINEID_TYPE_IPV4; 00474 } 00475 if (ENGINEID_TYPE_IPV4 == localEngineIDType) { 00476 /* 00477 * get the host name and save the information 00478 */ 00479 gethostname((char *) buf, sizeof(buf)); 00480 hent = netsnmp_gethostbyname((char *) buf); 00481 } 00482 #endif 00483 #endif /* HAVE_GETHOSTNAME */ 00484 00485 /* 00486 * Determine if we have text and if so setup our localEngineIDType 00487 * * appropriately. 00488 */ 00489 if (NULL != text) { 00490 engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT; 00491 } 00492 /* 00493 * Determine length of the engineID string. 00494 */ 00495 len = 5; /* always have 5 leading bytes */ 00496 switch (localEngineIDType) { 00497 case ENGINEID_TYPE_TEXT: 00498 if (NULL == text) { 00499 snmp_log(LOG_ERR, 00500 "Can't set up engineID of type text from an empty string.\n"); 00501 return -1; 00502 } 00503 len += strlen(text); /* 5 leading bytes+text. No NULL char */ 00504 break; 00505 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR) 00506 case ENGINEID_TYPE_MACADDR: /* MAC address */ 00507 len += 6; /* + 6 bytes for MAC address */ 00508 break; 00509 #endif 00510 case ENGINEID_TYPE_IPV4: /* IPv4 */ 00511 len += 4; /* + 4 byte IPV4 address */ 00512 break; 00513 case ENGINEID_TYPE_IPV6: /* IPv6 */ 00514 len += 16; /* + 16 byte IPV6 address */ 00515 break; 00516 case ENGINEID_TYPE_NETSNMP_RND: /* Net-SNMP specific encoding */ 00517 if (engineID) /* already setup, keep current value */ 00518 return engineIDLength; 00519 if (oldEngineID) { 00520 len = oldEngineIDLength; 00521 } else { 00522 len += sizeof(int) + sizeof(time_t); 00523 } 00524 break; 00525 default: 00526 snmp_log(LOG_ERR, 00527 "Unknown EngineID type requested for setup (%d). Using IPv4.\n", 00528 localEngineIDType); 00529 localEngineIDType = ENGINEID_TYPE_IPV4; /* make into IPV4 */ 00530 len += 4; /* + 4 byte IPv4 address */ 00531 break; 00532 } /* switch */ 00533 00534 00535 /* 00536 * Allocate memory and store enterprise ID. 00537 */ 00538 if ((bufp = (u_char *) malloc(len)) == NULL) { 00539 snmp_log_perror("setup_engineID malloc"); 00540 return -1; 00541 } 00542 if (localEngineIDType == ENGINEID_TYPE_NETSNMP_RND) 00543 /* 00544 * we must use the net-snmp enterprise id here, regardless 00545 */ 00546 memcpy(bufp, &netsnmpoid, sizeof(netsnmpoid)); /* XXX Must be 4 bytes! */ 00547 else 00548 memcpy(bufp, &enterpriseid, sizeof(enterpriseid)); /* XXX Must be 4 bytes! */ 00549 00550 bufp[0] |= 0x80; 00551 00552 00553 /* 00554 * Store the given text -OR- the first found IP address 00555 * -OR- the MAC address -OR- random elements 00556 * (the latter being the recommended default) 00557 */ 00558 switch (localEngineIDType) { 00559 case ENGINEID_TYPE_NETSNMP_RND: 00560 if (oldEngineID) { 00561 /* 00562 * keep our previous notion of the engineID 00563 */ 00564 memcpy(bufp, oldEngineID, oldEngineIDLength); 00565 } else { 00566 /* 00567 * Here we've desigend our own ENGINEID that is not based on 00568 * an address which may change and may even become conflicting 00569 * in the future like most of the default v3 engineID types 00570 * suffer from. 00571 * 00572 * Ours is built from 2 fairly random elements: a random number and 00573 * the current time in seconds. This method suffers from boxes 00574 * that may not have a correct clock setting and random number 00575 * seed at startup, but few OSes should have that problem. 00576 */ 00577 bufp[4] = ENGINEID_TYPE_NETSNMP_RND; 00578 tmpint = random(); 00579 memcpy(bufp + 5, &tmpint, sizeof(tmpint)); 00580 tmptime = time(NULL); 00581 memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime)); 00582 } 00583 break; 00584 case ENGINEID_TYPE_TEXT: 00585 bufp[4] = ENGINEID_TYPE_TEXT; 00586 memcpy((char *) bufp + 5, (text), strlen(text)); 00587 break; 00588 #ifdef HAVE_GETHOSTNAME 00589 #ifdef AF_INET6 00590 case ENGINEID_TYPE_IPV6: 00591 bufp[4] = ENGINEID_TYPE_IPV6; 00592 memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length); 00593 break; 00594 #endif 00595 #endif 00596 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR) 00597 case ENGINEID_TYPE_MACADDR: 00598 { 00599 int x; 00600 bufp[4] = ENGINEID_TYPE_MACADDR; 00601 /* 00602 * use default NIC if none provided 00603 */ 00604 if (NULL == engineIDNic) { 00605 x = getHwAddress(DEFAULT_NIC, (char *)&bufp[5]); 00606 } else { 00607 x = getHwAddress((char *)engineIDNic, (char *)&bufp[5]); 00608 } 00609 if (0 != x) 00610 /* 00611 * function failed fill MAC address with zeros 00612 */ 00613 { 00614 memset(&bufp[5], 0, 6); 00615 } 00616 } 00617 break; 00618 #endif 00619 case ENGINEID_TYPE_IPV4: 00620 default: 00621 bufp[4] = ENGINEID_TYPE_IPV4; 00622 #ifdef HAVE_GETHOSTNAME 00623 if (hent && hent->h_addrtype == AF_INET) { 00624 memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length); 00625 } else { /* Unknown address type. Default to 127.0.0.1. */ 00626 00627 bufp[5] = 127; 00628 bufp[6] = 0; 00629 bufp[7] = 0; 00630 bufp[8] = 1; 00631 } 00632 #else /* HAVE_GETHOSTNAME */ 00633 /* 00634 * Unknown address type. Default to 127.0.0.1. 00635 */ 00636 bufp[5] = 127; 00637 bufp[6] = 0; 00638 bufp[7] = 0; 00639 bufp[8] = 1; 00640 #endif /* HAVE_GETHOSTNAME */ 00641 break; 00642 } 00643 00644 /* 00645 * Pass the string back to the calling environment, or use it for 00646 * our local engineID. 00647 */ 00648 if (localsetup) { 00649 SNMP_FREE(engineID); 00650 engineID = bufp; 00651 engineIDLength = len; 00652 00653 } else { 00654 *eidp = bufp; 00655 } 00656 00657 00658 return len; 00659 00660 } /* end setup_engineID() */ 00661 00662 int 00663 free_engineID(int majorid, int minorid, void *serverarg, 00664 void *clientarg) 00665 { 00666 SNMP_FREE(engineID); 00667 SNMP_FREE(engineIDNic); 00668 SNMP_FREE(oldEngineID); 00669 engineIDIsSet = 0; 00670 return 0; 00671 } 00672 00673 /*******************************************************************-o-****** 00674 * engineBoots_conf 00675 * 00676 * Parameters: 00677 * *word 00678 * *cptr 00679 * 00680 * Line syntax: 00681 * engineBoots <num_boots> 00682 */ 00683 void 00684 engineBoots_conf(const char *word, char *cptr) 00685 { 00686 engineBoots = atoi(cptr) + 1; 00687 DEBUGMSGTL(("snmpv3", "engineBoots: %lu\n", engineBoots)); 00688 } 00689 00690 /*******************************************************************-o-****** 00691 * engineIDType_conf 00692 * 00693 * Parameters: 00694 * *word 00695 * *cptr 00696 * 00697 * Line syntax: 00698 * engineIDType <1 or 3> 00699 * 1 is default for IPv4 engine ID type. Will automatically 00700 * chose between IPv4 & IPv6 if either 1 or 2 is specified. 00701 * 2 is for IPv6. 00702 * 3 is hardware (MAC) address, currently supported under Linux 00703 */ 00704 void 00705 engineIDType_conf(const char *word, char *cptr) 00706 { 00707 engineIDType = atoi(cptr); 00708 /* 00709 * verify valid type selected 00710 */ 00711 switch (engineIDType) { 00712 case ENGINEID_TYPE_IPV4: /* IPv4 */ 00713 case ENGINEID_TYPE_IPV6: /* IPv6 */ 00714 /* 00715 * IPV? is always good 00716 */ 00717 break; 00718 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR) 00719 case ENGINEID_TYPE_MACADDR: /* MAC address */ 00720 break; 00721 #endif 00722 default: 00723 /* 00724 * unsupported one chosen 00725 */ 00726 config_perror("Unsupported enginedIDType, forcing IPv4"); 00727 engineIDType = ENGINEID_TYPE_IPV4; 00728 } 00729 DEBUGMSGTL(("snmpv3", "engineIDType: %d\n", engineIDType)); 00730 } 00731 00732 /*******************************************************************-o-****** 00733 * engineIDNic_conf 00734 * 00735 * Parameters: 00736 * *word 00737 * *cptr 00738 * 00739 * Line syntax: 00740 * engineIDNic <string> 00741 * eth0 is default 00742 */ 00743 void 00744 engineIDNic_conf(const char *word, char *cptr) 00745 { 00746 /* 00747 * Make sure they haven't already specified the engineID via the 00748 * * configuration file 00749 */ 00750 if (0 == engineIDIsSet) 00751 /* 00752 * engineID has NOT been set via configuration file 00753 */ 00754 { 00755 /* 00756 * See if already set if so erase & release it 00757 */ 00758 SNMP_FREE(engineIDNic); 00759 engineIDNic = (u_char *) malloc(strlen(cptr) + 1); 00760 if (NULL != engineIDNic) { 00761 strcpy((char *) engineIDNic, cptr); 00762 DEBUGMSGTL(("snmpv3", "Initializing engineIDNic: %s\n", 00763 engineIDNic)); 00764 } else { 00765 DEBUGMSGTL(("snmpv3", 00766 "Error allocating memory for engineIDNic!\n")); 00767 } 00768 } else { 00769 DEBUGMSGTL(("snmpv3", 00770 "NOT setting engineIDNic, engineID already set\n")); 00771 } 00772 } 00773 00774 /*******************************************************************-o-****** 00775 * engineID_conf 00776 * 00777 * Parameters: 00778 * *word 00779 * *cptr 00780 * 00781 * This function reads a string from the configuration file and uses that 00782 * string to initialize the engineID. It's assumed to be human readable. 00783 */ 00784 void 00785 engineID_conf(const char *word, char *cptr) 00786 { 00787 setup_engineID(NULL, cptr); 00788 DEBUGMSGTL(("snmpv3", "initialized engineID with: %s\n", cptr)); 00789 } 00790 00791 void 00792 version_conf(const char *word, char *cptr) 00793 { 00794 int valid = 0; 00795 #ifndef NETSNMP_DISABLE_SNMPV1 00796 if ((strcmp(cptr, "1") == 0) || 00797 (strcmp(cptr, "v1") == 0)) { 00798 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 00799 NETSNMP_DS_SNMP_VERSION_1); /* bogus value */ 00800 valid = 1; 00801 } 00802 #endif 00803 #ifndef NETSNMP_DISABLE_SNMPV2C 00804 if ((strcasecmp(cptr, "2c") == 0) || 00805 (strcasecmp(cptr, "v2c") == 0)) { 00806 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 00807 NETSNMP_DS_SNMP_VERSION_2c); 00808 valid = 1; 00809 } 00810 #endif 00811 if ((strcasecmp(cptr, "3" ) == 0) || 00812 (strcasecmp(cptr, "v3" ) == 0)) { 00813 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 00814 NETSNMP_DS_SNMP_VERSION_3); 00815 valid = 1; 00816 } 00817 if (!valid) { 00818 config_perror("Unknown version specification"); 00819 return; 00820 } 00821 DEBUGMSGTL(("snmpv3", "set default version to %d\n", 00822 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 00823 NETSNMP_DS_LIB_SNMPVERSION))); 00824 } 00825 00826 /* 00827 * oldengineID_conf(const char *, char *): 00828 * 00829 * Reads a octet string encoded engineID into the oldEngineID and 00830 * oldEngineIDLen pointers. 00831 */ 00832 void 00833 oldengineID_conf(const char *word, char *cptr) 00834 { 00835 read_config_read_octet_string(cptr, &oldEngineID, &oldEngineIDLength); 00836 } 00837 00838 /* 00839 * exactEngineID_conf(const char *, char *): 00840 * 00841 * Reads a octet string encoded engineID into the engineID and 00842 * engineIDLen pointers. 00843 */ 00844 void 00845 exactEngineID_conf(const char *word, char *cptr) 00846 { 00847 read_config_read_octet_string(cptr, &engineID, &engineIDLength); 00848 if (engineIDLength > MAX_ENGINEID_LENGTH) { 00849 netsnmp_config_error( 00850 "exactEngineID '%s' too long; truncating to %d bytes", 00851 cptr, MAX_ENGINEID_LENGTH); 00852 engineID[MAX_ENGINEID_LENGTH - 1] = '\0'; 00853 engineIDLength = MAX_ENGINEID_LENGTH; 00854 } 00855 engineIDIsSet = 1; 00856 engineIDType = ENGINEID_TYPE_EXACT; 00857 } 00858 00859 00860 /* 00861 * merely call 00862 */ 00863 netsnmp_feature_child_of(get_enginetime_alarm, netsnmp_unused) 00864 #ifndef NETSNMP_FEATURE_REMOVE_GET_ENGINETIME_ALARM 00865 void 00866 get_enginetime_alarm(unsigned int regnum, void *clientargs) 00867 { 00868 /* we do this every so (rarely) often just to make sure we watch 00869 wrapping of the times() output */ 00870 snmpv3_local_snmpEngineTime(); 00871 } 00872 #endif /* NETSNMP_FEATURE_REMOVE_GET_ENGINETIME_ALARM */ 00873 00874 /*******************************************************************-o-****** 00875 * init_snmpv3 00876 * 00877 * Parameters: 00878 * *type Label for the config file "type" used by calling entity. 00879 * 00880 * Set time and engineID. 00881 * Set parsing functions for config file tokens. 00882 * Initialize SNMP Crypto API (SCAPI). 00883 */ 00884 void 00885 init_snmpv3(const char *type) 00886 { 00887 #if SNMP_USE_TIMES 00888 struct tms dummy; 00889 00890 /* fixme: -1 is fault code... */ 00891 snmpv3startClock = times(&dummy); 00892 00893 /* remember how many ticks per second there are, since times() returns this */ 00894 00895 clockticks = sysconf(_SC_CLK_TCK); 00896 00897 #endif /* SNMP_USE_TIMES */ 00898 00899 gettimeofday(&snmpv3starttime, NULL); 00900 00901 if (!type) 00902 type = "__snmpapp__"; 00903 00904 /* 00905 * we need to be called back later 00906 */ 00907 snmp_register_callback(SNMP_CALLBACK_LIBRARY, 00908 SNMP_CALLBACK_POST_READ_CONFIG, 00909 init_snmpv3_post_config, NULL); 00910 00911 snmp_register_callback(SNMP_CALLBACK_LIBRARY, 00912 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, 00913 init_snmpv3_post_premib_config, NULL); 00914 /* 00915 * we need to be called back later 00916 */ 00917 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, 00918 snmpv3_store, (void *) strdup(type)); 00919 00920 /* 00921 * initialize submodules 00922 */ 00923 /* 00924 * NOTE: this must be after the callbacks are registered above, 00925 * since they need to be called before the USM callbacks. 00926 */ 00927 init_secmod(); 00928 00929 /* 00930 * register all our configuration handlers (ack, there's a lot) 00931 */ 00932 00933 /* 00934 * handle engineID setup before everything else which may depend on it 00935 */ 00936 register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL, 00937 "string"); 00938 register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf, 00939 NULL, NULL); 00940 register_prenetsnmp_mib_handler(type, "exactEngineID", exactEngineID_conf, 00941 NULL, NULL); 00942 register_prenetsnmp_mib_handler(type, "engineIDType", 00943 engineIDType_conf, NULL, "num"); 00944 register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf, 00945 NULL, "string"); 00946 register_config_handler(type, "engineBoots", engineBoots_conf, NULL, 00947 NULL); 00948 00949 /* 00950 * default store config entries 00951 */ 00952 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName", 00953 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME); 00954 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext", 00955 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT); 00956 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase", 00957 NETSNMP_DS_LIBRARY_ID, 00958 NETSNMP_DS_LIB_PASSPHRASE); 00959 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase", 00960 NETSNMP_DS_LIBRARY_ID, 00961 NETSNMP_DS_LIB_AUTHPASSPHRASE); 00962 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase", 00963 NETSNMP_DS_LIBRARY_ID, 00964 NETSNMP_DS_LIB_PRIVPASSPHRASE); 00965 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthMasterKey", 00966 NETSNMP_DS_LIBRARY_ID, 00967 NETSNMP_DS_LIB_AUTHMASTERKEY); 00968 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivMasterKey", 00969 NETSNMP_DS_LIBRARY_ID, 00970 NETSNMP_DS_LIB_PRIVMASTERKEY); 00971 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthLocalizedKey", 00972 NETSNMP_DS_LIBRARY_ID, 00973 NETSNMP_DS_LIB_AUTHLOCALIZEDKEY); 00974 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivLocalizedKey", 00975 NETSNMP_DS_LIBRARY_ID, 00976 NETSNMP_DS_LIB_PRIVLOCALIZEDKEY); 00977 register_config_handler("snmp", "defVersion", version_conf, NULL, 00978 "1|2c|3"); 00979 00980 register_config_handler("snmp", "defSecurityLevel", 00981 snmpv3_secLevel_conf, NULL, 00982 "noAuthNoPriv|authNoPriv|authPriv"); 00983 } 00984 00985 /* 00986 * initializations for SNMPv3 to be called after the configuration files 00987 * have been read. 00988 */ 00989 00990 int 00991 init_snmpv3_post_config(int majorid, int minorid, void *serverarg, 00992 void *clientarg) 00993 { 00994 00995 size_t engineIDLen; 00996 u_char *c_engineID; 00997 00998 c_engineID = snmpv3_generate_engineID(&engineIDLen); 00999 01000 if (engineIDLen == 0 || !c_engineID) { 01001 /* 01002 * Somethine went wrong - help! 01003 */ 01004 SNMP_FREE(c_engineID); 01005 return SNMPERR_GENERR; 01006 } 01007 01008 /* 01009 * if our engineID has changed at all, the boots record must be set to 1 01010 */ 01011 if (engineIDLen != oldEngineIDLength || 01012 oldEngineID == NULL || c_engineID == NULL || 01013 memcmp(oldEngineID, c_engineID, engineIDLen) != 0) { 01014 engineBoots = 1; 01015 } 01016 01017 #ifdef NETSNMP_SECMOD_USM 01018 /* 01019 * for USM set our local engineTime in the LCD timing cache 01020 */ 01021 set_enginetime(c_engineID, engineIDLen, 01022 snmpv3_local_snmpEngineBoots(), 01023 snmpv3_local_snmpEngineTime(), TRUE); 01024 #endif /* NETSNMP_SECMOD_USM */ 01025 01026 SNMP_FREE(c_engineID); 01027 return SNMPERR_SUCCESS; 01028 } 01029 01030 int 01031 init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg, 01032 void *clientarg) 01033 { 01034 if (!engineIDIsSet) 01035 setup_engineID(NULL, NULL); 01036 01037 return SNMPERR_SUCCESS; 01038 } 01039 01040 /*******************************************************************-o-****** 01041 * store_snmpv3 01042 * 01043 * Parameters: 01044 * *type 01045 */ 01046 int 01047 snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg) 01048 { 01049 char line[SNMP_MAXBUF_SMALL]; 01050 u_char c_engineID[SNMP_MAXBUF_SMALL]; 01051 int engineIDLen; 01052 const char *type = (const char *) clientarg; 01053 01054 if (type == NULL) /* should never happen, since the arg is ours */ 01055 type = "unknown"; 01056 01057 sprintf(line, "engineBoots %ld", engineBoots); 01058 read_config_store(type, line); 01059 01060 engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL); 01061 01062 if (engineIDLen) { 01063 /* 01064 * store the engineID used for this run 01065 */ 01066 sprintf(line, "oldEngineID "); 01067 read_config_save_octet_string(line + strlen(line), c_engineID, 01068 engineIDLen); 01069 read_config_store(type, line); 01070 } 01071 return SNMPERR_SUCCESS; 01072 } /* snmpv3_store() */ 01073 01074 u_long 01075 snmpv3_local_snmpEngineBoots(void) 01076 { 01077 return engineBoots; 01078 } 01079 01080 01081 /*******************************************************************-o-****** 01082 * snmpv3_get_engineID 01083 * 01084 * Parameters: 01085 * *buf 01086 * buflen 01087 * 01088 * Returns: 01089 * Length of engineID On Success 01090 * SNMPERR_GENERR Otherwise. 01091 * 01092 * 01093 * Store engineID in buf; return the length. 01094 * 01095 */ 01096 size_t 01097 snmpv3_get_engineID(u_char * buf, size_t buflen) 01098 { 01099 /* 01100 * Sanity check. 01101 */ 01102 if (!buf || (buflen < engineIDLength)) { 01103 return 0; 01104 } 01105 if (!engineID) { 01106 return 0; 01107 } 01108 01109 memcpy(buf, engineID, engineIDLength); 01110 return engineIDLength; 01111 01112 } /* end snmpv3_get_engineID() */ 01113 01114 /*******************************************************************-o-****** 01115 * snmpv3_clone_engineID 01116 * 01117 * Parameters: 01118 * **dest 01119 * *dest_len 01120 * src 01121 * srclen 01122 * 01123 * Returns: 01124 * Length of engineID On Success 01125 * 0 Otherwise. 01126 * 01127 * 01128 * Clones engineID, creates memory 01129 * 01130 */ 01131 int 01132 snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src, 01133 size_t srclen) 01134 { 01135 if (!dest || !destlen) 01136 return 0; 01137 01138 SNMP_FREE(*dest); 01139 *destlen = 0; 01140 01141 if (srclen && src) { 01142 *dest = (u_char *) malloc(srclen); 01143 if (*dest == NULL) 01144 return 0; 01145 memmove(*dest, src, srclen); 01146 *destlen = srclen; 01147 } 01148 return *destlen; 01149 } /* end snmpv3_clone_engineID() */ 01150 01151 01152 /*******************************************************************-o-****** 01153 * snmpv3_generate_engineID 01154 * 01155 * Parameters: 01156 * *length 01157 * 01158 * Returns: 01159 * Pointer to copy of engineID On Success. 01160 * NULL If malloc() or snmpv3_get_engineID() 01161 * fail. 01162 * 01163 * Generates a malloced copy of our engineID. 01164 * 01165 * 'length' is set to the length of engineID -OR- < 0 on failure. 01166 */ 01167 u_char * 01168 snmpv3_generate_engineID(size_t * length) 01169 { 01170 u_char *newID; 01171 newID = (u_char *) malloc(engineIDLength); 01172 01173 if (newID) { 01174 *length = snmpv3_get_engineID(newID, engineIDLength); 01175 } 01176 01177 if (*length == 0) { 01178 SNMP_FREE(newID); 01179 newID = NULL; 01180 } 01181 01182 return newID; 01183 01184 } /* end snmpv3_generate_engineID() */ 01185 01186 /* 01187 * snmpv3_local_snmpEngineTime(): return the number of seconds since the 01188 * snmpv3 engine last incremented engine_boots 01189 */ 01190 u_long 01191 snmpv3_local_snmpEngineTime(void) 01192 { 01193 #ifdef SNMP_USE_TIMES 01194 struct tms dummy; 01195 clock_t now = times(&dummy); 01196 /* fixme: -1 is fault code... */ 01197 unsigned int result; 01198 01199 if (now < snmpv3startClock) { 01200 result = UINT_MAX - (snmpv3startClock - now); 01201 } else { 01202 result = now - snmpv3startClock; 01203 } 01204 if (result < lastcalltime) { 01205 /* wrapped */ 01206 wrapcounter++; 01207 } 01208 lastcalltime = result; 01209 result = (UINT_MAX/clockticks)*wrapcounter + result/clockticks; 01210 01211 return result; 01212 #else /* !SNMP_USE_TIMES */ 01213 #ifdef NETSNMP_FEATURE_CHECKING 01214 netsnmp_feature_require(calculate_sectime_diff) 01215 #endif /* NETSNMP_FEATURE_CHECKING */ 01216 struct timeval now; 01217 01218 gettimeofday(&now, NULL); 01219 return calculate_sectime_diff(&now, &snmpv3starttime); 01220 #endif /* HAVE_SYS_TIMES_H */ 01221 } 01222 01223 01224 01225 /* 01226 * Code only for Linux systems 01227 */ 01228 #if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR) 01229 static int 01230 getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */ 01231 char *addressOut) 01232 { /* return address. Len=IFHWADDRLEN */ 01233 /* 01234 * getHwAddress(...) 01235 * * 01236 * * This function will return a Network Interfaces Card's Hardware 01237 * * address (aka MAC address). 01238 * * 01239 * * Input Parameter(s): 01240 * * networkDevice - a null terminated string with the name of a network 01241 * * device. Examples: eth0, eth1, etc... 01242 * * 01243 * * Output Parameter(s): 01244 * * addressOut - This is the binary value of the hardware address. 01245 * * This value is NOT converted into a hexadecimal string. 01246 * * The caller must pre-allocate for a return value of 01247 * * length IFHWADDRLEN 01248 * * 01249 * * Return value: This function will return zero (0) for success. If 01250 * * an error occurred the function will return -1. 01251 * * 01252 * * Caveats: This has only been tested on Ethernet networking cards. 01253 */ 01254 int sock; /* our socket */ 01255 struct ifreq request; /* struct which will have HW address */ 01256 01257 if ((NULL == networkDevice) || (NULL == addressOut)) { 01258 return -1; 01259 } 01260 /* 01261 * In order to find out the hardware (MAC) address of our system under 01262 * * Linux we must do the following: 01263 * * 1. Create a socket 01264 * * 2. Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation. 01265 */ 01266 sock = socket(AF_INET, SOCK_DGRAM, 0); 01267 if (sock < 0) { 01268 return -1; 01269 } 01270 /* 01271 * erase the request block 01272 */ 01273 memset(&request, 0, sizeof(request)); 01274 /* 01275 * copy the name of the net device we want to find the HW address for 01276 */ 01277 strncpy(request.ifr_name, networkDevice, IFNAMSIZ - 1); 01278 /* 01279 * Get the HW address 01280 */ 01281 if (ioctl(sock, SIOCGIFHWADDR, &request)) { 01282 close(sock); 01283 return -1; 01284 } 01285 close(sock); 01286 memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN); 01287 return 0; 01288 } 01289 #endif 01290 01291 #ifdef NETSNMP_ENABLE_TESTING_CODE 01292 /* 01293 * snmpv3_set_engineBootsAndTime(): this function does not exist. Go away. 01294 */ 01295 /* 01296 * It certainly should never be used, unless in a testing scenero, 01297 * which is why it was created 01298 */ 01299 void 01300 snmpv3_set_engineBootsAndTime(int boots, int ttime) 01301 { 01302 engineBoots = boots; 01303 gettimeofday(&snmpv3starttime, NULL); 01304 snmpv3starttime.tv_sec -= ttime; 01305 } 01306 #endif