Coverage Report

Created: 2026-01-09 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/snmp-tc.c
Line
Count
Source
1
/*
2
 *  Host Resources MIB - utility functions - hr_utils.c
3
 *
4
 */
5
6
7
#include <net-snmp/net-snmp-config.h>
8
#include <net-snmp/net-snmp-features.h>
9
#include <sys/types.h>
10
#ifdef HAVE_STDLIB_H
11
#include <stdlib.h>
12
#endif
13
#include <ctype.h>
14
#ifdef HAVE_STRING_H
15
#include <string.h>
16
#endif
17
#ifdef HAVE_NETINET_IN_H
18
#include <netinet/in.h>
19
#endif
20
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
32
#include <net-snmp/types.h>
33
#include <net-snmp/library/snmp.h>
34
#include <net-snmp/library/snmp-tc.h>   /* for "internal" definitions */
35
#include <net-snmp/library/snmp_api.h>
36
37
netsnmp_feature_child_of(snmp_tc_all, libnetsnmp);
38
39
netsnmp_feature_child_of(netsnmp_dateandtime_set_buf_from_vars, netsnmp_unused);
40
netsnmp_feature_child_of(date_n_time, snmp_tc_all);
41
netsnmp_feature_child_of(ctime_to_timet, snmp_tc_all);
42
netsnmp_feature_child_of(check_rowstatus_with_storagetype_transition, snmp_tc_all);
43
44
#ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_DATEANDTIME_SET_BUF_FROM_VARS
45
/*
46
  DateAndTime ::= TEXTUAL-CONVENTION
47
    DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
48
    STATUS       current
49
    DESCRIPTION
50
            "A date-time specification.
51
52
            field  octets  contents                  range
53
            -----  ------  --------                  -----
54
              1      1-2   year*                     0..65536
55
              2       3    month                     1..12
56
              3       4    day                       1..31
57
              4       5    hour                      0..23
58
              5       6    minutes                   0..59
59
              6       7    seconds                   0..60
60
                           (use 60 for leap-second)
61
              7       8    deci-seconds              0..9
62
              8       9    direction from UTC        '+' / '-'
63
              9      10    hours from UTC*           0..13
64
             10      11    minutes from UTC          0..59
65
66
            * Notes:
67
            - the value of year is in network-byte order
68
            - daylight saving time in New Zealand is +13
69
70
            For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
71
            displayed as:
72
73
                             1992-5-26,13:30:15.0,-4:0
74
75
            Note that if only local time is known, then timezone
76
            information (fields 8-10) is not present."
77
    SYNTAX       OCTET STRING (SIZE (8 | 11))
78
*/
79
80
int
81
netsnmp_dateandtime_set_buf_from_vars(u_char *buf, size_t *bufsize,
82
                                      u_short year, u_char month, u_char day,
83
                                      u_char hour, u_char minutes,
84
                                      u_char seconds, u_char deci_seconds,
85
                                      int utc_offset_direction,
86
                                      u_char utc_offset_hours,
87
                                      u_char utc_offset_minutes)
88
0
{
89
0
    u_short tmp_year = htons(year);
90
91
    /*
92
     * if we have a utc offset, need 11 bytes. Otherwise we
93
     * just need 8 bytes.
94
     */
95
0
    if(utc_offset_direction) {
96
0
        if(*bufsize < 11)
97
0
            return SNMPERR_RANGE;
98
99
        /*
100
         * set utc offset data
101
         */
102
0
        buf[8] = (utc_offset_direction < 0) ? '-' : '+';
103
0
        buf[9] = utc_offset_hours;
104
0
        buf[10] = utc_offset_minutes;
105
0
        *bufsize = 11;
106
0
    }
107
0
    else if(*bufsize < 8)
108
0
        return SNMPERR_RANGE;
109
0
    else
110
0
        *bufsize = 8;
111
112
    /*
113
     * set basic date/time data
114
     */
115
0
    memcpy(buf, &tmp_year, sizeof(tmp_year));
116
0
    buf[2] = month;
117
0
    buf[3] = day;
118
0
    buf[4] = hour;
119
0
    buf[5] = minutes;
120
0
    buf[6] = seconds;
121
0
    buf[7] = deci_seconds;
122
123
0
    return SNMPERR_SUCCESS;
124
0
}
125
#endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_DATEANDTIME_SET_BUF_FROM_VARS */
126
127
#ifndef NETSNMP_FEATURE_REMOVE_DATE_N_TIME
128
u_char         *
129
date_n_time(const time_t * when, size_t * length)
130
0
{
131
0
    struct tm      *tm_p;
132
0
    static u_char   string[11];
133
0
    unsigned short yauron;
134
135
    /*
136
     * Null time
137
     */
138
0
    if (when == NULL || *when == 0 || *when == (time_t) - 1) {
139
0
invalid_time:
140
0
        string[0] = 0;
141
0
        string[1] = 0;
142
0
        string[2] = 1;
143
0
        string[3] = 1;
144
0
        string[4] = 0;
145
0
        string[5] = 0;
146
0
        string[6] = 0;
147
0
        string[7] = 0;
148
0
        *length = 8;
149
0
        return string;
150
0
    }
151
152
153
    /*
154
     * Basic 'local' time handling
155
     */
156
0
    tm_p = localtime(when);
157
0
    if (!tm_p)
158
0
        goto invalid_time;
159
160
0
    yauron = tm_p->tm_year + 1900;
161
0
    string[0] = (u_char)(yauron >> 8);
162
0
    string[1] = (u_char)yauron;
163
0
    string[2] = tm_p->tm_mon + 1;
164
0
    string[3] = tm_p->tm_mday;
165
0
    string[4] = tm_p->tm_hour;
166
0
    string[5] = tm_p->tm_min;
167
0
    string[6] = tm_p->tm_sec;
168
0
    string[7] = 0;
169
0
    *length = 8;
170
171
0
#if defined(HAVE_STRUCT_TM_TM_GMTOFF) || HAVE_DECL_TIMEZONE
172
    /*
173
     * Timezone offset
174
     */
175
0
    {
176
0
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
177
0
    const int tzoffset = -tm_p->tm_gmtoff;   /* Seconds east of UTC */
178
#else
179
    const int tzoffset = timezone;           /* Seconds west of UTC */
180
#endif
181
0
    if (tzoffset > 0)
182
0
        string[8] = '-';
183
0
    else
184
0
        string[8] = '+';
185
0
    string[9] = abs(tzoffset) / 3600;
186
0
    string[10] = (abs(tzoffset) - string[9] * 3600) / 60;
187
0
    *length = 11;
188
0
    }
189
0
#endif
190
191
#if defined(SYSV) && !HAVE_STRUCT_TM_TM_GMTOFF
192
    /*
193
     * Daylight saving time
194
     */
195
    if (tm_p->tm_isdst > 0) {
196
        /*
197
         * Assume add one hour 
198
         */
199
        if (string[8] == '-')
200
            --string[9];
201
        else
202
            ++string[9];
203
204
        if (string[9] == 0)
205
            string[8] = '+';
206
    }
207
#endif
208
209
0
    return string;
210
0
}
211
#endif /* NETSNMP_FEATURE_REMOVE_DATE_N_TIME */
212
213
#ifndef NETSNMP_FEATURE_REMOVE_CTIME_TO_TIMET
214
time_t
215
ctime_to_timet(const char *str)
216
0
{
217
0
    struct tm       tm;
218
219
0
    if (strlen(str) < 24)
220
0
        return 0;
221
222
    /*
223
     * Month 
224
     */
225
0
    if (!strncmp(str + 4, "Jan", 3))
226
0
        tm.tm_mon = 0;
227
0
    else if (!strncmp(str + 4, "Feb", 3))
228
0
        tm.tm_mon = 1;
229
0
    else if (!strncmp(str + 4, "Mar", 3))
230
0
        tm.tm_mon = 2;
231
0
    else if (!strncmp(str + 4, "Apr", 3))
232
0
        tm.tm_mon = 3;
233
0
    else if (!strncmp(str + 4, "May", 3))
234
0
        tm.tm_mon = 4;
235
0
    else if (!strncmp(str + 4, "Jun", 3))
236
0
        tm.tm_mon = 5;
237
0
    else if (!strncmp(str + 4, "Jul", 3))
238
0
        tm.tm_mon = 6;
239
0
    else if (!strncmp(str + 4, "Aug", 3))
240
0
        tm.tm_mon = 7;
241
0
    else if (!strncmp(str + 4, "Sep", 3))
242
0
        tm.tm_mon = 8;
243
0
    else if (!strncmp(str + 4, "Oct", 3))
244
0
        tm.tm_mon = 9;
245
0
    else if (!strncmp(str + 4, "Nov", 3))
246
0
        tm.tm_mon = 10;
247
0
    else if (!strncmp(str + 4, "Dec", 3))
248
0
        tm.tm_mon = 11;
249
0
    else
250
0
        return 0;
251
252
0
    tm.tm_mday = atoi(str + 8);
253
0
    tm.tm_hour = atoi(str + 11);
254
0
    tm.tm_min = atoi(str + 14);
255
0
    tm.tm_sec = atoi(str + 17);
256
0
    tm.tm_year = atoi(str + 20) - 1900;
257
258
    /*
259
     *  Cope with timezone and DST
260
     */
261
262
0
#ifdef HAVE_STRUCT_TM_TM_ISDST
263
0
#if HAVE_DECL_DAYLIGHT==1
264
0
    tm.tm_isdst = !!daylight;
265
#else
266
    tm.tm_isdst = 0;
267
#endif
268
0
#if defined(HAVE_DECL_TIMEZONE) && defined(HAVE_SCALAR_TIMEZONE)
269
0
    tm.tm_sec -= timezone;
270
0
#endif
271
0
#endif
272
273
0
    return (mktime(&tm));
274
0
}
275
#endif /* NETSNMP_FEATURE_REMOVE_CTIME_TO_TIMET */
276
277
/*
278
 * blatantly lifted from opensnmp 
279
 */
280
char
281
check_rowstatus_transition(int oldValue, int newValue)
282
0
{
283
    /*
284
     * From the SNMPv2-TC MIB:
285
     *                                          STATE
286
     *               +--------------+-----------+-------------+-------------
287
     *               |      A       |     B     |      C      |      D
288
     *               |              |status col.|status column|
289
     *               |status column |    is     |      is     |status column
290
     *     ACTION    |does not exist|  notReady | notInService|  is active
291
     * --------------+--------------+-----------+-------------+-------------
292
     * set status    |noError    ->D|inconsist- |inconsistent-|inconsistent-
293
     * column to     |       or     |   entValue|        Value|        Value
294
     * createAndGo   |inconsistent- |           |             |
295
     *               |         Value|           |             |
296
     * --------------+--------------+-----------+-------------+-------------
297
     * set status    |noError  see 1|inconsist- |inconsistent-|inconsistent-
298
     * column to     |       or     |   entValue|        Value|        Value
299
     * createAndWait |wrongValue    |           |             |
300
     * --------------+--------------+-----------+-------------+-------------
301
     * set status    |inconsistent- |inconsist- |noError      |noError
302
     * column to     |         Value|   entValue|             |
303
     * active        |              |           |             |
304
     *               |              |     or    |             |
305
     *               |              |           |             |
306
     *               |              |see 2   ->D|see 8     ->D|          ->D
307
     * --------------+--------------+-----------+-------------+-------------
308
     * set status    |inconsistent- |inconsist- |noError      |noError   ->C
309
     * column to     |         Value|   entValue|             |
310
     * notInService  |              |           |             |
311
     *               |              |     or    |             |      or
312
     *               |              |           |             |
313
     *               |              |see 3   ->C|          ->C|see 6
314
     * --------------+--------------+-----------+-------------+-------------
315
     * set status    |noError       |noError    |noError      |noError   ->A
316
     * column to     |              |           |             |      or
317
     * destroy       |           ->A|        ->A|          ->A|see 7
318
     * --------------+--------------+-----------+-------------+-------------
319
     * set any other |see 4         |noError    |noError      |see 5
320
     * column to some|              |           |             |
321
     * value         |              |      see 1|          ->C|          ->D
322
     * --------------+--------------+-----------+-------------+-------------
323
     
324
     *             (1) goto B or C, depending on information available to the
325
     *             agent.
326
     
327
     *             (2) if other variable bindings included in the same PDU,
328
     *             provide values for all columns which are missing but
329
     *             required, and all columns have acceptable values, then
330
     *             return noError and goto D.
331
     
332
     *             (3) if other variable bindings included in the same PDU,
333
     *             provide legal values for all columns which are missing but
334
     *             required, then return noError and goto C.
335
     
336
     *             (4) at the discretion of the agent, the return value may be
337
     *             either:
338
     
339
     *                  inconsistentName:  because the agent does not choose to
340
     *                  create such an instance when the corresponding
341
     *                  RowStatus instance does not exist, or
342
     
343
     *                  inconsistentValue:  if the supplied value is
344
     *                  inconsistent with the state of some other MIB object's
345
     *                  value, or
346
     
347
     *                  noError: because the agent chooses to create the
348
     *                  instance.
349
     
350
     *             If noError is returned, then the instance of the status
351
     *             column must also be created, and the new state is B or C,
352
     *             depending on the information available to the agent.  If
353
     *             inconsistentName or inconsistentValue is returned, the row
354
     *             remains in state A.
355
     
356
     *             (5) depending on the MIB definition for the column/table,
357
     *             either noError or inconsistentValue may be returned.
358
     
359
     *             (6) the return value can indicate one of the following
360
     *             errors:
361
     
362
     *                  wrongValue: because the agent does not support
363
     *                  notInService (e.g., an agent which does not support
364
     *                  createAndWait), or
365
     
366
     *                  inconsistentValue: because the agent is unable to take
367
     *                  the row out of service at this time, perhaps because it
368
     *                  is in use and cannot be de-activated.
369
     
370
     *             (7) the return value can indicate the following error:
371
     
372
     *                  inconsistentValue: because the agent is unable to
373
     *                  remove the row at this time, perhaps because it is in
374
     *                  use and cannot be de-activated.
375
     
376
     *             (8) the transition to D can fail, e.g., if the values of the
377
     *             conceptual row are inconsistent, then the error code would
378
     *             be inconsistentValue.
379
     
380
     *             NOTE: Other processing of (this and other varbinds of) the
381
     *             set request may result in a response other than noError
382
     *             being returned, e.g., wrongValue, noCreation, etc.
383
     */
384
385
0
    switch (newValue) {
386
        /*
387
         * these two end up being equivalent as far as checking the 
388
         * status goes, although the final states are based on the 
389
         * newValue. 
390
         */
391
0
    case RS_ACTIVE:
392
0
    case RS_NOTINSERVICE:
393
0
        if (oldValue == RS_NOTINSERVICE || oldValue == RS_ACTIVE)
394
0
            ;
395
0
        else
396
0
            return SNMP_ERR_INCONSISTENTVALUE;
397
0
        break;
398
399
0
    case RS_NOTREADY:
400
        /*
401
         * Illegal set value. 
402
         */
403
0
        return SNMP_ERR_WRONGVALUE;
404
0
        break;
405
406
0
    case RS_CREATEANDGO:
407
0
    case RS_CREATEANDWAIT:
408
0
        if (oldValue != RS_NONEXISTENT)
409
            /*
410
             * impossible, we already exist. 
411
             */
412
0
            return SNMP_ERR_INCONSISTENTVALUE;
413
0
        break;
414
415
0
    case RS_DESTROY:
416
0
        break;
417
418
0
    default:
419
0
        return SNMP_ERR_WRONGVALUE;
420
0
        break;
421
0
    }
422
423
0
    return SNMP_ERR_NOERROR;
424
0
}
425
426
#ifndef NETSNMP_FEATURE_REMOVE_CHECK_ROWSTATUS_WITH_STORAGETYPE_TRANSITION
427
char
428
check_rowstatus_with_storagetype_transition(int oldValue, int newValue,
429
                                            int oldStorage)
430
0
{
431
    /*
432
     * can not destroy permanent or readonly rows
433
     */
434
0
    if ((RS_DESTROY == newValue) &&
435
0
        ((SNMP_STORAGE_PERMANENT == oldStorage) ||
436
0
         (SNMP_STORAGE_READONLY == oldStorage)))
437
0
        return SNMP_ERR_WRONGVALUE;
438
439
0
    return check_rowstatus_transition(oldValue, newValue);
440
0
}
441
#endif /* NETSNMP_FEATURE_REMOVE_CHECK_ROWSTATUS_WITH_STORAGETYPE_TRANSITION */
442
443
netsnmp_feature_child_of(check_storage_transition, snmp_tc_all);
444
#ifndef NETSNMP_FEATURE_REMOVE_CHECK_STORAGE_TRANSITION
445
char
446
check_storage_transition(int oldValue, int newValue)
447
0
{
448
    /*
449
     * From the SNMPv2-TC MIB:
450
     
451
     *             "Describes the memory realization of a conceptual row.  A
452
     *             row which is volatile(2) is lost upon reboot.  A row which
453
     *             is either nonVolatile(3), permanent(4) or readOnly(5), is
454
     *             backed up by stable storage.  A row which is permanent(4)
455
     *             can be changed but not deleted.  A row which is readOnly(5)
456
     *             cannot be changed nor deleted.
457
     
458
     *             If the value of an object with this syntax is either
459
     *             permanent(4) or readOnly(5), it cannot be written.
460
     *             Conversely, if the value is either other(1), volatile(2) or
461
     *             nonVolatile(3), it cannot be modified to be permanent(4) or
462
     *             readOnly(5).  (All illegal modifications result in a
463
     *             'wrongValue' error.)
464
     
465
     *             Every usage of this textual convention is required to
466
     *             specify the columnar objects which a permanent(4) row must
467
     *             at a minimum allow to be writable."
468
     */
469
0
    switch (oldValue) {
470
0
    case SNMP_STORAGE_PERMANENT:
471
0
    case SNMP_STORAGE_READONLY:
472
0
        return SNMP_ERR_INCONSISTENTVALUE;
473
474
0
    case SNMP_STORAGE_NONE:
475
0
    case SNMP_STORAGE_OTHER:
476
0
    case SNMP_STORAGE_VOLATILE:
477
0
    case SNMP_STORAGE_NONVOLATILE:
478
0
        if (newValue == SNMP_STORAGE_PERMANENT ||
479
0
            newValue == SNMP_STORAGE_READONLY)
480
0
            return SNMP_ERR_INCONSISTENTVALUE;
481
0
    }
482
483
0
    return SNMP_ERR_NOERROR;
484
0
}
485
#endif /* NETSNMP_FEATURE_REMOVE_CHECK_STORAGE_TRANSITION */