net-snmp
5.4.1
|
00001 /* 00002 * lcd_time.c 00003 * 00004 * XXX Should etimelist entries with <0,0> time tuples be timed out? 00005 * XXX Need a routine to free the memory? (Perhaps at shutdown?) 00006 */ 00007 00008 #include <net-snmp/net-snmp-config.h> 00009 00010 #include <sys/types.h> 00011 #if HAVE_WINSOCK_H 00012 #include <winsock.h> 00013 #endif 00014 #include <stdio.h> 00015 #ifdef HAVE_STDLIB_H 00016 #include <stdlib.h> 00017 #endif 00018 #if HAVE_STRING_H 00019 #include <string.h> 00020 #else 00021 #include <strings.h> 00022 #endif 00023 #if TIME_WITH_SYS_TIME 00024 # ifdef WIN32 00025 # include <sys/timeb.h> 00026 # else 00027 # include <sys/time.h> 00028 # endif 00029 # include <time.h> 00030 #else 00031 # if HAVE_SYS_TIME_H 00032 # include <sys/time.h> 00033 # else 00034 # include <time.h> 00035 # endif 00036 #endif 00037 #ifdef HAVE_NETINET_IN_H 00038 #include <netinet/in.h> 00039 #endif 00040 00041 #if HAVE_DMALLOC_H 00042 #include <dmalloc.h> 00043 #endif 00044 00045 #include <net-snmp/types.h> 00046 #include <net-snmp/output_api.h> 00047 #include <net-snmp/utilities.h> 00048 00049 #include <net-snmp/library/snmp_api.h> 00050 #include <net-snmp/library/callback.h> 00051 #include <net-snmp/library/snmp_secmod.h> 00052 #include <net-snmp/library/snmpusm.h> 00053 #include <net-snmp/library/lcd_time.h> 00054 #include <net-snmp/library/scapi.h> 00055 #include <net-snmp/library/snmpv3.h> 00056 00057 #include <net-snmp/library/transform_oids.h> 00058 00059 /* 00060 * Global static hashlist to contain Enginetime entries. 00061 * 00062 * New records are prepended to the appropriate list at the hash index. 00063 */ 00064 static Enginetime etimelist[ETIMELIST_SIZE]; 00065 00066 00067 00068 00069 /*******************************************************************-o-****** 00070 * get_enginetime 00071 * 00072 * Parameters: 00073 * *engineID 00074 * engineID_len 00075 * *engineboot 00076 * *engine_time 00077 * 00078 * Returns: 00079 * SNMPERR_SUCCESS Success -- when a record for engineID is found. 00080 * SNMPERR_GENERR Otherwise. 00081 * 00082 * 00083 * Lookup engineID and return the recorded values for the 00084 * <engine_time, engineboot> tuple adjusted to reflect the estimated time 00085 * at the engine in question. 00086 * 00087 * Special case: if engineID is NULL or if engineID_len is 0 then 00088 * the time tuple is returned immediately as zero. 00089 * 00090 * XXX What if timediff wraps? >shrug< 00091 * XXX Then: you need to increment the boots value. Now. Detecting 00092 * this is another matter. 00093 */ 00094 int 00095 get_enginetime(u_char * engineID, 00096 u_int engineID_len, 00097 u_int * engineboot, 00098 u_int * engine_time, u_int authenticated) 00099 { 00100 int rval = SNMPERR_SUCCESS; 00101 time_t timediff = 0; 00102 Enginetime e = NULL; 00103 00104 00105 00106 /* 00107 * Sanity check. 00108 */ 00109 if (!engine_time || !engineboot) { 00110 QUITFUN(SNMPERR_GENERR, get_enginetime_quit); 00111 } 00112 00113 00114 /* 00115 * Compute estimated current engine_time tuple at engineID if 00116 * a record is cached for it. 00117 */ 00118 *engine_time = *engineboot = 0; 00119 00120 if (!engineID || (engineID_len <= 0)) { 00121 QUITFUN(SNMPERR_GENERR, get_enginetime_quit); 00122 } 00123 00124 if (!(e = search_enginetime_list(engineID, engineID_len))) { 00125 QUITFUN(SNMPERR_GENERR, get_enginetime_quit); 00126 } 00127 #ifdef LCD_TIME_SYNC_OPT 00128 if (!authenticated || e->authenticatedFlag) { 00129 #endif 00130 *engine_time = e->engineTime; 00131 *engineboot = e->engineBoot; 00132 00133 timediff = snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime; 00134 00135 #ifdef LCD_TIME_SYNC_OPT 00136 } 00137 #endif 00138 00139 if (timediff > (int) (ENGINETIME_MAX - *engine_time)) { 00140 *engine_time = (timediff - (ENGINETIME_MAX - *engine_time)); 00141 00142 /* 00143 * FIX -- move this check up... should not change anything 00144 * * if engineboot is already locked. ??? 00145 */ 00146 if (*engineboot < ENGINEBOOT_MAX) { 00147 *engineboot += 1; 00148 } 00149 00150 } else { 00151 *engine_time += timediff; 00152 } 00153 00154 DEBUGMSGTL(("lcd_get_enginetime", "engineID ")); 00155 DEBUGMSGHEX(("lcd_get_enginetime", engineID, engineID_len)); 00156 DEBUGMSG(("lcd_get_enginetime", ": boots=%d, time=%d\n", *engineboot, 00157 *engine_time)); 00158 00159 get_enginetime_quit: 00160 return rval; 00161 00162 } /* end get_enginetime() */ 00163 00164 /*******************************************************************-o-****** 00165 * get_enginetime 00166 * 00167 * Parameters: 00168 * *engineID 00169 * engineID_len 00170 * *engineboot 00171 * *engine_time 00172 * 00173 * Returns: 00174 * SNMPERR_SUCCESS Success -- when a record for engineID is found. 00175 * SNMPERR_GENERR Otherwise. 00176 * 00177 * 00178 * Lookup engineID and return the recorded values for the 00179 * <engine_time, engineboot> tuple adjusted to reflect the estimated time 00180 * at the engine in question. 00181 * 00182 * Special case: if engineID is NULL or if engineID_len is 0 then 00183 * the time tuple is returned immediately as zero. 00184 * 00185 * XXX What if timediff wraps? >shrug< 00186 * XXX Then: you need to increment the boots value. Now. Detecting 00187 * this is another matter. 00188 */ 00189 int 00190 get_enginetime_ex(u_char * engineID, 00191 u_int engineID_len, 00192 u_int * engineboot, 00193 u_int * engine_time, 00194 u_int * last_engine_time, u_int authenticated) 00195 { 00196 int rval = SNMPERR_SUCCESS; 00197 time_t timediff = 0; 00198 Enginetime e = NULL; 00199 00200 00201 00202 /* 00203 * Sanity check. 00204 */ 00205 if (!engine_time || !engineboot || !last_engine_time) { 00206 QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit); 00207 } 00208 00209 00210 /* 00211 * Compute estimated current engine_time tuple at engineID if 00212 * a record is cached for it. 00213 */ 00214 *last_engine_time = *engine_time = *engineboot = 0; 00215 00216 if (!engineID || (engineID_len <= 0)) { 00217 QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit); 00218 } 00219 00220 if (!(e = search_enginetime_list(engineID, engineID_len))) { 00221 QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit); 00222 } 00223 #ifdef LCD_TIME_SYNC_OPT 00224 if (!authenticated || e->authenticatedFlag) { 00225 #endif 00226 *last_engine_time = *engine_time = e->engineTime; 00227 *engineboot = e->engineBoot; 00228 00229 timediff = snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime; 00230 00231 #ifdef LCD_TIME_SYNC_OPT 00232 } 00233 #endif 00234 00235 if (timediff > (int) (ENGINETIME_MAX - *engine_time)) { 00236 *engine_time = (timediff - (ENGINETIME_MAX - *engine_time)); 00237 00238 /* 00239 * FIX -- move this check up... should not change anything 00240 * * if engineboot is already locked. ??? 00241 */ 00242 if (*engineboot < ENGINEBOOT_MAX) { 00243 *engineboot += 1; 00244 } 00245 00246 } else { 00247 *engine_time += timediff; 00248 } 00249 00250 DEBUGMSGTL(("lcd_get_enginetime_ex", "engineID ")); 00251 DEBUGMSGHEX(("lcd_get_enginetime_ex", engineID, engineID_len)); 00252 DEBUGMSG(("lcd_get_enginetime_ex", ": boots=%d, time=%d\n", 00253 *engineboot, *engine_time)); 00254 00255 get_enginetime_ex_quit: 00256 return rval; 00257 00258 } /* end get_enginetime_ex() */ 00259 00260 00261 void free_enginetime(unsigned char *engineID, size_t engineID_len) 00262 { 00263 Enginetime e = NULL; 00264 int rval = 0; 00265 00266 rval = hash_engineID(engineID, engineID_len); 00267 if (rval < 0) 00268 return; 00269 00270 e = etimelist[rval]; 00271 00272 while (e != NULL) { 00273 etimelist[rval] = e->next; 00274 SNMP_FREE(e->engineID); 00275 SNMP_FREE(e); 00276 e = etimelist[rval]; 00277 } 00278 00279 } 00280 00281 /*******************************************************************-o-**** 00282 ** 00283 * free_etimelist 00284 * 00285 * Parameters: 00286 * None 00287 * 00288 * Returns: 00289 * void 00290 * 00291 * 00292 * Free all of the memory used by entries in the etimelist. 00293 * 00294 */ 00295 void free_etimelist(void) 00296 { 00297 int index = 0; 00298 Enginetime e = 0; 00299 Enginetime nextE = 0; 00300 00301 for( ; index < ETIMELIST_SIZE; ++index) 00302 { 00303 e = etimelist[index]; 00304 00305 while(e != 0) 00306 { 00307 nextE = e->next; 00308 SNMP_FREE(e->engineID); 00309 SNMP_FREE(e); 00310 e = nextE; 00311 } 00312 00313 etimelist[index] = 0; 00314 } 00315 return; 00316 } 00317 00318 /*******************************************************************-o-****** 00319 * set_enginetime 00320 * 00321 * Parameters: 00322 * *engineID 00323 * engineID_len 00324 * engineboot 00325 * engine_time 00326 * 00327 * Returns: 00328 * SNMPERR_SUCCESS Success. 00329 * SNMPERR_GENERR Otherwise. 00330 * 00331 * 00332 * Lookup engineID and store the given <engine_time, engineboot> tuple 00333 * and then stamp the record with a consistent source of local time. 00334 * If the engineID record does not exist, create one. 00335 * 00336 * Special case: engineID is NULL or engineID_len is 0 defines an engineID 00337 * that is "always set." 00338 * 00339 * XXX "Current time within the local engine" == time(NULL)... 00340 */ 00341 int 00342 set_enginetime(u_char * engineID, 00343 u_int engineID_len, 00344 u_int engineboot, u_int engine_time, u_int authenticated) 00345 { 00346 int rval = SNMPERR_SUCCESS, iindex; 00347 Enginetime e = NULL; 00348 00349 00350 00351 /* 00352 * Sanity check. 00353 */ 00354 if (!engineID || (engineID_len <= 0)) { 00355 return rval; 00356 } 00357 00358 00359 /* 00360 * Store the given <engine_time, engineboot> tuple in the record 00361 * for engineID. Create a new record if necessary. 00362 */ 00363 if (!(e = search_enginetime_list(engineID, engineID_len))) { 00364 if ((iindex = hash_engineID(engineID, engineID_len)) < 0) { 00365 QUITFUN(SNMPERR_GENERR, set_enginetime_quit); 00366 } 00367 00368 e = (Enginetime) calloc(1, sizeof(*e)); 00369 00370 e->next = etimelist[iindex]; 00371 etimelist[iindex] = e; 00372 00373 e->engineID = (u_char *) calloc(1, engineID_len); 00374 memcpy(e->engineID, engineID, engineID_len); 00375 00376 e->engineID_len = engineID_len; 00377 } 00378 #ifdef LCD_TIME_SYNC_OPT 00379 if (authenticated || !e->authenticatedFlag) { 00380 e->authenticatedFlag = authenticated; 00381 #else 00382 if (authenticated) { 00383 #endif 00384 e->engineTime = engine_time; 00385 e->engineBoot = engineboot; 00386 e->lastReceivedEngineTime = snmpv3_local_snmpEngineTime(); 00387 } 00388 00389 e = NULL; /* Indicates a successful update. */ 00390 00391 DEBUGMSGTL(("lcd_set_enginetime", "engineID ")); 00392 DEBUGMSGHEX(("lcd_set_enginetime", engineID, engineID_len)); 00393 DEBUGMSG(("lcd_set_enginetime", ": boots=%d, time=%d\n", engineboot, 00394 engine_time)); 00395 00396 set_enginetime_quit: 00397 SNMP_FREE(e); 00398 00399 return rval; 00400 00401 } /* end set_enginetime() */ 00402 00403 00404 00405 00406 /*******************************************************************-o-****** 00407 * search_enginetime_list 00408 * 00409 * Parameters: 00410 * *engineID 00411 * engineID_len 00412 * 00413 * Returns: 00414 * Pointer to a etimelist record with engineID <engineID> -OR- 00415 * NULL if no record exists. 00416 * 00417 * 00418 * Search etimelist for an entry with engineID. 00419 * 00420 * ASSUMES that no engineID will have more than one record in the list. 00421 */ 00422 Enginetime 00423 search_enginetime_list(u_char * engineID, u_int engineID_len) 00424 { 00425 int rval = SNMPERR_SUCCESS; 00426 Enginetime e = NULL; 00427 00428 00429 /* 00430 * Sanity check. 00431 */ 00432 if (!engineID || (engineID_len <= 0)) { 00433 QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit); 00434 } 00435 00436 00437 /* 00438 * Find the entry for engineID if there be one. 00439 */ 00440 rval = hash_engineID(engineID, engineID_len); 00441 if (rval < 0) { 00442 QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit); 00443 } 00444 e = etimelist[rval]; 00445 00446 for ( /*EMPTY*/; e; e = e->next) { 00447 if ((engineID_len == e->engineID_len) 00448 && !memcmp(e->engineID, engineID, engineID_len)) { 00449 break; 00450 } 00451 } 00452 00453 00454 search_enginetime_list_quit: 00455 return e; 00456 00457 } /* end search_enginetime_list() */ 00458 00459 00460 00461 00462 00463 /*******************************************************************-o-****** 00464 * hash_engineID 00465 * 00466 * Parameters: 00467 * *engineID 00468 * engineID_len 00469 * 00470 * Returns: 00471 * >0 etimelist index for this engineID. 00472 * SNMPERR_GENERR Error. 00473 * 00474 * 00475 * Use a cheap hash to build an index into the etimelist. Method is 00476 * to hash the engineID, then split the hash into u_int's and add them up 00477 * and modulo the size of the list. 00478 * 00479 */ 00480 int 00481 hash_engineID(u_char * engineID, u_int engineID_len) 00482 { 00483 int rval = SNMPERR_GENERR; 00484 size_t buf_len = SNMP_MAXBUF; 00485 u_int additive = 0; 00486 u_char *bufp, buf[SNMP_MAXBUF]; 00487 void *context = NULL; 00488 00489 00490 00491 /* 00492 * Sanity check. 00493 */ 00494 if (!engineID || (engineID_len <= 0)) { 00495 QUITFUN(SNMPERR_GENERR, hash_engineID_quit); 00496 } 00497 00498 00499 /* 00500 * Hash engineID into a list index. 00501 */ 00502 #ifndef NETSNMP_DISABLE_MD5 00503 rval = sc_hash(usmHMACMD5AuthProtocol, 00504 sizeof(usmHMACMD5AuthProtocol) / sizeof(oid), 00505 engineID, engineID_len, buf, &buf_len); 00506 #else 00507 rval = sc_hash(usmHMACSHA1AuthProtocol, 00508 sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid), 00509 engineID, engineID_len, buf, &buf_len); 00510 #endif 00511 QUITFUN(rval, hash_engineID_quit); 00512 00513 for (bufp = buf; (bufp - buf) < (int) buf_len; bufp += 4) { 00514 additive += (u_int) * bufp; 00515 } 00516 00517 hash_engineID_quit: 00518 SNMP_FREE(context); 00519 memset(buf, 0, SNMP_MAXBUF); 00520 00521 return (rval < 0) ? rval : (additive % ETIMELIST_SIZE); 00522 00523 } /* end hash_engineID() */ 00524 00525 00526 00527 00528 #ifdef NETSNMP_ENABLE_TESTING_CODE 00529 /*******************************************************************-o-****** 00530 * dump_etimelist_entry 00531 * 00532 * Parameters: 00533 * e 00534 * count 00535 */ 00536 void 00537 dump_etimelist_entry(Enginetime e, int count) 00538 { 00539 u_int buflen; 00540 char tabs[SNMP_MAXBUF], *t = tabs, *s; 00541 00542 00543 00544 count += 1; 00545 while (count--) { 00546 t += sprintf(t, " "); 00547 } 00548 00549 00550 buflen = e->engineID_len; 00551 #ifdef NETSNMP_ENABLE_TESTING_CODE 00552 if (!(s = dump_snmpEngineID(e->engineID, &buflen))) { 00553 #endif 00554 binary_to_hex(e->engineID, e->engineID_len, &s); 00555 #ifdef NETSNMP_ENABLE_TESTING_CODE 00556 } 00557 #endif 00558 00559 DEBUGMSGTL(("dump_etimelist", "%s\n", tabs)); 00560 DEBUGMSGTL(("dump_etimelist", "%s%s (len=%d) <%d,%d>\n", tabs, 00561 s, e->engineID_len, e->engineTime, e->engineBoot)); 00562 DEBUGMSGTL(("dump_etimelist", "%s%ld (%ld)", tabs, 00563 e->lastReceivedEngineTime, 00564 snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime)); 00565 00566 SNMP_FREE(s); 00567 00568 } /* end dump_etimelist_entry() */ 00569 00570 00571 00572 00573 /*******************************************************************-o-****** 00574 * dump_etimelist 00575 */ 00576 void 00577 dump_etimelist(void) 00578 { 00579 int iindex = -1, count = 0; 00580 Enginetime e; 00581 00582 00583 00584 DEBUGMSGTL(("dump_etimelist", "\n")); 00585 00586 while (++iindex < ETIMELIST_SIZE) { 00587 DEBUGMSG(("dump_etimelist", "[%d]", iindex)); 00588 00589 count = 0; 00590 e = etimelist[iindex]; 00591 00592 while (e) { 00593 dump_etimelist_entry(e, count++); 00594 e = e->next; 00595 } 00596 00597 if (count > 0) { 00598 DEBUGMSG(("dump_etimelist", "\n")); 00599 } 00600 } /* endwhile */ 00601 00602 DEBUGMSG(("dump_etimelist", "\n")); 00603 00604 } /* end dump_etimelist() */ 00605 #endif /* NETSNMP_ENABLE_TESTING_CODE */