Coverage Report

Created: 2024-02-11 06:06

/src/net-snmp/snmplib/lcd_time.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * lcd_time.c
3
 *
4
 * XXX  Should etimelist entries with <0,0> time tuples be timed out?
5
 * XXX  Need a routine to free the memory?  (Perhaps at shutdown?)
6
 */
7
8
#include <net-snmp/net-snmp-config.h>
9
#include <net-snmp/net-snmp-features.h>
10
11
#include <sys/types.h>
12
#include <stdio.h>
13
#ifdef HAVE_STDLIB_H
14
#include <stdlib.h>
15
#endif
16
#ifdef HAVE_STRING_H
17
#include <string.h>
18
#else
19
#include <strings.h>
20
#endif
21
#ifdef TIME_WITH_SYS_TIME
22
# include <sys/time.h>
23
# include <time.h>
24
#else
25
# ifdef HAVE_SYS_TIME_H
26
#  include <sys/time.h>
27
# else
28
#  include <time.h>
29
# endif
30
#endif
31
#ifdef HAVE_NETINET_IN_H
32
#include <netinet/in.h>
33
#endif
34
35
#ifdef HAVE_UNISTD_H
36
#include <unistd.h>
37
#endif
38
39
#include <net-snmp/types.h>
40
#include <net-snmp/output_api.h>
41
#include <net-snmp/utilities.h>
42
43
#include <net-snmp/library/snmp_api.h>
44
#include <net-snmp/library/callback.h>
45
#include <net-snmp/library/snmp_secmod.h>
46
#include <net-snmp/library/snmpusm.h>
47
#include <net-snmp/library/lcd_time.h>
48
#include <net-snmp/library/scapi.h>
49
#include <net-snmp/library/snmpv3.h>
50
51
#include <net-snmp/library/transform_oids.h>
52
53
netsnmp_feature_child_of(usm_support, libnetsnmp);
54
netsnmp_feature_child_of(usm_lcd_time, usm_support);
55
56
#ifndef NETSNMP_FEATURE_REMOVE_USM_LCD_TIME
57
58
/*
59
 * Global static hashlist to contain Enginetime entries.
60
 *
61
 * New records are prepended to the appropriate list at the hash index.
62
 */
63
static Enginetime etimelist[ETIMELIST_SIZE];
64
65
66
67
68
/*******************************************************************-o-******
69
 * get_enginetime
70
 *
71
 * Parameters:
72
 *  *engineID
73
 *   engineID_len
74
 *  *engineboot
75
 *  *engine_time
76
 *      
77
 * Returns:
78
 *  SNMPERR_SUCCESS   Success -- when a record for engineID is found.
79
 *  SNMPERR_GENERR    Otherwise.
80
 *
81
 *
82
 * Lookup engineID and return the recorded values for the
83
 * <engine_time, engineboot> tuple adjusted to reflect the estimated time
84
 * at the engine in question.
85
 *
86
 * Special case: if engineID is NULL or if engineID_len is 0 then
87
 * the time tuple is returned immediately as zero.
88
 *
89
 * XXX  What if timediff wraps?  >shrug<
90
 * XXX  Then: you need to increment the boots value.  Now.  Detecting
91
 *            this is another matter.
92
 */
93
int
94
get_enginetime(const u_char * engineID,
95
               u_int engineID_len,
96
               u_int * engineboot,
97
               u_int * engine_time, u_int authenticated)
98
0
{
99
0
    int             rval = SNMPERR_SUCCESS;
100
0
    int             timediff = 0;
101
0
    Enginetime      e = NULL;
102
103
104
105
    /*
106
     * Sanity check.
107
     */
108
0
    if (!engine_time || !engineboot) {
109
0
        QUITFUN(SNMPERR_GENERR, get_enginetime_quit);
110
0
    }
111
112
113
    /*
114
     * Compute estimated current engine_time tuple at engineID if
115
     * a record is cached for it.
116
     */
117
0
    *engine_time = *engineboot = 0;
118
119
0
    if (!engineID || (engineID_len <= 0)) {
120
0
        QUITFUN(SNMPERR_GENERR, get_enginetime_quit);
121
0
    }
122
123
0
    if (!(e = search_enginetime_list(engineID, engineID_len))) {
124
0
        QUITFUN(SNMPERR_GENERR, get_enginetime_quit);
125
0
    }
126
0
#ifdef LCD_TIME_SYNC_OPT
127
0
    if (!authenticated || e->authenticatedFlag) {
128
0
#endif
129
0
        *engine_time = e->engineTime;
130
0
        *engineboot = e->engineBoot;
131
132
0
       timediff = (int) (snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime);
133
134
0
#ifdef LCD_TIME_SYNC_OPT
135
0
    }
136
0
#endif
137
138
0
    if (timediff > (int) (ENGINETIME_MAX - *engine_time)) {
139
0
        *engine_time = (timediff - (ENGINETIME_MAX - *engine_time));
140
141
        /*
142
         * FIX -- move this check up... should not change anything
143
         * * if engineboot is already locked.  ???
144
         */
145
0
        if (*engineboot < ENGINEBOOT_MAX) {
146
0
            *engineboot += 1;
147
0
        }
148
149
0
    } else {
150
0
        *engine_time += timediff;
151
0
    }
152
153
0
    DEBUGMSGTL(("lcd_get_enginetime", "engineID "));
154
0
    DEBUGMSGHEX(("lcd_get_enginetime", engineID, engineID_len));
155
0
    DEBUGMSG(("lcd_get_enginetime", ": boots=%d, time=%d\n", *engineboot,
156
0
              *engine_time));
157
158
0
  get_enginetime_quit:
159
0
    return rval;
160
161
0
}                               /* end get_enginetime() */
162
163
/*******************************************************************-o-******
164
 * get_enginetime
165
 *
166
 * Parameters:
167
 *  *engineID
168
 *   engineID_len
169
 *  *engineboot
170
 *  *engine_time
171
 *      
172
 * Returns:
173
 *  SNMPERR_SUCCESS   Success -- when a record for engineID is found.
174
 *  SNMPERR_GENERR    Otherwise.
175
 *
176
 *
177
 * Lookup engineID and return the recorded values for the
178
 * <engine_time, engineboot> tuple adjusted to reflect the estimated time
179
 * at the engine in question.
180
 *
181
 * Special case: if engineID is NULL or if engineID_len is 0 then
182
 * the time tuple is returned immediately as zero.
183
 *
184
 * XXX  What if timediff wraps?  >shrug<
185
 * XXX  Then: you need to increment the boots value.  Now.  Detecting
186
 *            this is another matter.
187
 */
188
int
189
get_enginetime_ex(u_char * engineID,
190
                  u_int engineID_len,
191
                  u_int * engineboot,
192
                  u_int * engine_time,
193
                  u_int * last_engine_time, u_int authenticated)
194
0
{
195
0
    int             rval = SNMPERR_SUCCESS;
196
0
    int             timediff = 0;
197
0
    Enginetime      e = NULL;
198
199
200
201
    /*
202
     * Sanity check.
203
     */
204
0
    if (!engine_time || !engineboot || !last_engine_time) {
205
0
        QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit);
206
0
    }
207
208
209
    /*
210
     * Compute estimated current engine_time tuple at engineID if
211
     * a record is cached for it.
212
     */
213
0
    *last_engine_time = *engine_time = *engineboot = 0;
214
215
0
    if (!engineID || (engineID_len <= 0)) {
216
0
        QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit);
217
0
    }
218
219
0
    if (!(e = search_enginetime_list(engineID, engineID_len))) {
220
0
        QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit);
221
0
    }
222
0
#ifdef LCD_TIME_SYNC_OPT
223
0
    if (!authenticated || e->authenticatedFlag) {
224
0
#endif
225
0
        *last_engine_time = *engine_time = e->engineTime;
226
0
        *engineboot = e->engineBoot;
227
228
0
       timediff = (int) (snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime);
229
230
0
#ifdef LCD_TIME_SYNC_OPT
231
0
    }
232
0
#endif
233
234
0
    if (timediff > (int) (ENGINETIME_MAX - *engine_time)) {
235
0
        *engine_time = (timediff - (ENGINETIME_MAX - *engine_time));
236
237
        /*
238
         * FIX -- move this check up... should not change anything
239
         * * if engineboot is already locked.  ???
240
         */
241
0
        if (*engineboot < ENGINEBOOT_MAX) {
242
0
            *engineboot += 1;
243
0
        }
244
245
0
    } else {
246
0
        *engine_time += timediff;
247
0
    }
248
249
0
    DEBUGMSGTL(("lcd_get_enginetime_ex", "engineID "));
250
0
    DEBUGMSGHEX(("lcd_get_enginetime_ex", engineID, engineID_len));
251
0
    DEBUGMSG(("lcd_get_enginetime_ex", ": boots=%d, time=%d\n",
252
0
              *engineboot, *engine_time));
253
254
0
  get_enginetime_ex_quit:
255
0
    return rval;
256
257
0
}                               /* end get_enginetime_ex() */
258
259
260
void free_enginetime(unsigned char *engineID, size_t engineID_len)
261
0
{
262
0
    Enginetime      e = NULL;
263
0
    int             rval = 0;
264
265
0
    rval = hash_engineID(engineID, engineID_len);
266
0
    if (rval < 0)
267
0
  return;
268
269
0
    e = etimelist[rval];
270
271
0
    while (e != NULL) {
272
0
  etimelist[rval] = e->next;
273
0
  SNMP_FREE(e->engineID);
274
0
  SNMP_FREE(e);
275
0
  e = etimelist[rval];
276
0
    }
277
278
0
}
279
280
/*******************************************************************-o-****
281
**
282
 * free_etimelist
283
 *
284
 * Parameters:
285
 *   None
286
 *      
287
 * Returns:
288
 *   void
289
 *
290
 *
291
 * Free all of the memory used by entries in the etimelist.
292
 *
293
 */
294
void free_etimelist(void)
295
5.91k
{
296
5.91k
     int index = 0;
297
5.91k
     Enginetime e = NULL;
298
5.91k
     Enginetime nextE = NULL;
299
300
141k
     for( ; index < ETIMELIST_SIZE; ++index)
301
135k
     {
302
135k
           e = etimelist[index];
303
304
138k
           while(e != NULL)
305
2.95k
           {
306
2.95k
                 nextE = e->next;
307
2.95k
                 SNMP_FREE(e->engineID);
308
2.95k
                 SNMP_FREE(e);
309
2.95k
                 e = nextE;
310
2.95k
           }
311
312
135k
           etimelist[index] = NULL;
313
135k
     }
314
5.91k
     return;
315
5.91k
}
316
317
/*******************************************************************-o-******
318
 * set_enginetime
319
 *
320
 * Parameters:
321
 *  *engineID
322
 *   engineID_len
323
 *   engineboot
324
 *   engine_time
325
 *      
326
 * Returns:
327
 *  SNMPERR_SUCCESS   Success.
328
 *  SNMPERR_GENERR    Otherwise.
329
 *
330
 *
331
 * Lookup engineID and store the given <engine_time, engineboot> tuple
332
 * and then stamp the record with a consistent source of local time.
333
 * If the engineID record does not exist, create one.
334
 *
335
 * Special case: engineID is NULL or engineID_len is 0 defines an engineID
336
 * that is "always set."
337
 *
338
 * XXX  "Current time within the local engine" == time(NULL)...
339
 */
340
int
341
set_enginetime(const u_char * engineID,
342
               u_int engineID_len,
343
               u_int engineboot, u_int engine_time, u_int authenticated)
344
2.95k
{
345
2.95k
    int             rval = SNMPERR_SUCCESS, iindex;
346
2.95k
    Enginetime      e = NULL;
347
348
349
350
    /*
351
     * Sanity check.
352
     */
353
2.95k
    if (!engineID || (engineID_len <= 0)) {
354
0
        return rval;
355
0
    }
356
357
358
    /*
359
     * Store the given <engine_time, engineboot> tuple in the record
360
     * for engineID.  Create a new record if necessary.
361
     */
362
2.95k
    if (!(e = search_enginetime_list(engineID, engineID_len))) {
363
2.95k
        if ((iindex = hash_engineID(engineID, engineID_len)) < 0) {
364
0
            QUITFUN(SNMPERR_GENERR, set_enginetime_quit);
365
0
        }
366
367
2.95k
        e = calloc(1, sizeof(*e));
368
369
2.95k
        e->next = etimelist[iindex];
370
2.95k
        etimelist[iindex] = e;
371
372
2.95k
        e->engineID = calloc(1, engineID_len);
373
2.95k
        memcpy(e->engineID, engineID, engineID_len);
374
375
2.95k
        e->engineID_len = engineID_len;
376
2.95k
    }
377
2.95k
#ifdef LCD_TIME_SYNC_OPT
378
2.95k
    if (authenticated || !e->authenticatedFlag) {
379
2.95k
        e->authenticatedFlag = authenticated;
380
#else
381
    if (authenticated) {
382
#endif
383
2.95k
        e->engineTime = engine_time;
384
2.95k
        e->engineBoot = engineboot;
385
2.95k
        e->lastReceivedEngineTime = snmpv3_local_snmpEngineTime();
386
2.95k
    }
387
388
2.95k
    e = NULL;                   /* Indicates a successful update. */
389
390
2.95k
    DEBUGMSGTL(("lcd_set_enginetime", "engineID "));
391
2.95k
    DEBUGMSGHEX(("lcd_set_enginetime", engineID, engineID_len));
392
2.95k
    DEBUGMSG(("lcd_set_enginetime", ": boots=%d, time=%d\n", engineboot,
393
2.95k
              engine_time));
394
395
2.95k
  set_enginetime_quit:
396
2.95k
    SNMP_FREE(e);
397
398
2.95k
    return rval;
399
400
2.95k
}                               /* end set_enginetime() */
401
402
403
404
405
/*******************************************************************-o-******
406
 * search_enginetime_list
407
 *
408
 * Parameters:
409
 *  *engineID
410
 *   engineID_len
411
 *      
412
 * Returns:
413
 *  Pointer to a etimelist record with engineID <engineID>  -OR-
414
 *  NULL if no record exists.
415
 *
416
 *
417
 * Search etimelist for an entry with engineID.
418
 *
419
 * ASSUMES that no engineID will have more than one record in the list.
420
 */
421
Enginetime
422
search_enginetime_list(const u_char * engineID, u_int engineID_len)
423
2.95k
{
424
2.95k
    int             rval = SNMPERR_SUCCESS;
425
2.95k
    Enginetime      e = NULL;
426
427
428
    /*
429
     * Sanity check.
430
     */
431
2.95k
    if (!engineID || (engineID_len <= 0)) {
432
0
        QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit);
433
0
    }
434
435
436
    /*
437
     * Find the entry for engineID if there be one.
438
     */
439
2.95k
    rval = hash_engineID(engineID, engineID_len);
440
2.95k
    if (rval < 0) {
441
0
        QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit);
442
0
    }
443
2.95k
    e = etimelist[rval];
444
445
2.95k
    for ( /*EMPTY*/; e; e = e->next) {
446
0
        if ((engineID_len == e->engineID_len)
447
0
            && !memcmp(e->engineID, engineID, engineID_len)) {
448
0
            break;
449
0
        }
450
0
    }
451
452
453
2.95k
  search_enginetime_list_quit:
454
2.95k
    return e;
455
456
2.95k
}                               /* end search_enginetime_list() */
457
458
459
460
461
462
/*******************************************************************-o-******
463
 * hash_engineID
464
 *
465
 * Parameters:
466
 *  *engineID
467
 *   engineID_len
468
 *      
469
 * Returns:
470
 *  >0      etimelist index for this engineID.
471
 *  SNMPERR_GENERR    Error.
472
 *  
473
 * 
474
 * Use a cheap hash to build an index into the etimelist.  Method is 
475
 * to hash the engineID, then split the hash into u_int's and add them up
476
 * and modulo the size of the list.
477
 *
478
 */
479
int
480
hash_engineID(const u_char * engineID, u_int engineID_len)
481
5.91k
{
482
5.91k
    int             rval = SNMPERR_GENERR;
483
5.91k
    size_t          buf_len = SNMP_MAXBUF;
484
5.91k
    u_int           additive = 0;
485
5.91k
    u_char         *bufp, buf[SNMP_MAXBUF];
486
5.91k
    void           *context = NULL;
487
488
489
490
    /*
491
     * Sanity check.
492
     */
493
5.91k
    if (!engineID || (engineID_len <= 0)) {
494
0
        QUITFUN(SNMPERR_GENERR, hash_engineID_quit);
495
0
    }
496
497
498
    /*
499
     * Hash engineID into a list index.
500
     */
501
5.91k
#ifndef NETSNMP_DISABLE_MD5
502
5.91k
    rval = sc_hash(usmHMACMD5AuthProtocol,
503
5.91k
                   OID_LENGTH(usmHMACMD5AuthProtocol),
504
5.91k
                   engineID, engineID_len, buf, &buf_len);
505
5.91k
    if (rval == SNMPERR_SC_NOT_CONFIGURED) {
506
        /* fall back to sha1 */
507
0
        rval = sc_hash(usmHMACSHA1AuthProtocol,
508
0
                   OID_LENGTH(usmHMACSHA1AuthProtocol),
509
0
                   engineID, engineID_len, buf, &buf_len);
510
0
    }
511
#else
512
    rval = sc_hash(usmHMACSHA1AuthProtocol,
513
                   OID_LENGTH(usmHMACSHA1AuthProtocol),
514
                   engineID, engineID_len, buf, &buf_len);
515
#endif
516
5.91k
    QUITFUN(rval, hash_engineID_quit);
517
518
29.5k
    for (bufp = buf; (bufp - buf) < (int) buf_len; bufp += 4) {
519
23.6k
        additive += (u_int) * bufp;
520
23.6k
    }
521
522
5.91k
  hash_engineID_quit:
523
5.91k
    SNMP_FREE(context);
524
5.91k
    memset(buf, 0, SNMP_MAXBUF);
525
526
5.91k
    return (rval < 0) ? rval : (int)(additive % ETIMELIST_SIZE);
527
528
5.91k
}                               /* end hash_engineID() */
529
530
531
532
533
#ifdef NETSNMP_ENABLE_TESTING_CODE
534
/*******************************************************************-o-******
535
 * dump_etimelist_entry
536
 *
537
 * Parameters:
538
 *  e
539
 *  count
540
 */
541
void
542
dump_etimelist_entry(Enginetime e, int count)
543
{
544
    size_t          buflen;
545
    char            tabs[SNMP_MAXBUF], *t = tabs, *s;
546
547
548
549
    count += 1;
550
    while (count--) {
551
        t += sprintf(t, "  ");
552
    }
553
554
555
    buflen = e->engineID_len;
556
    if (!(s = dump_snmpEngineID(e->engineID, &buflen))) {
557
        binary_to_hex(e->engineID, e->engineID_len, &s);
558
    }
559
560
    DEBUGMSGTL(("dump_etimelist", "%s\n", tabs));
561
    DEBUGMSGTL(("dump_etimelist", "%s%s (len=%d) <%d,%d>\n", tabs,
562
                s, e->engineID_len, e->engineTime, e->engineBoot));
563
    DEBUGMSGTL(("dump_etimelist", "%s%ld (%ld)", tabs,
564
                e->lastReceivedEngineTime,
565
                snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime));
566
567
    SNMP_FREE(s);
568
569
}                               /* end dump_etimelist_entry() */
570
571
572
573
574
/*******************************************************************-o-******
575
 * dump_etimelist
576
 */
577
void
578
dump_etimelist(void)
579
{
580
    int             iindex = -1, count = 0;
581
    Enginetime      e;
582
583
584
585
    DEBUGMSGTL(("dump_etimelist", "\n"));
586
587
    while (++iindex < ETIMELIST_SIZE) {
588
        DEBUGMSG(("dump_etimelist", "[%d]", iindex));
589
590
        count = 0;
591
        e = etimelist[iindex];
592
593
        while (e) {
594
            dump_etimelist_entry(e, count++);
595
            e = e->next;
596
        }
597
598
        if (count > 0) {
599
            DEBUGMSG(("dump_etimelist", "\n"));
600
        }
601
    }                           /* endwhile */
602
603
    DEBUGMSG(("dump_etimelist", "\n"));
604
605
}                               /* end dump_etimelist() */
606
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
607
#endif /* NETSNMP_FEATURE_REMOVE_USM_LCD_TIME */