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