net-snmp 5.7
snmp-tc.c
00001 /*
00002  *  Host Resources MIB - utility functions - hr_utils.c
00003  *
00004  */
00005 
00006 
00007 #include <net-snmp/net-snmp-config.h>
00008 #include <net-snmp/net-snmp-features.h>
00009 #include <sys/types.h>
00010 #if HAVE_STDLIB_H
00011 #include <stdlib.h>
00012 #endif
00013 #include <ctype.h>
00014 #if HAVE_STRING_H
00015 #include <string.h>
00016 #endif
00017 #if HAVE_NETINET_IN_H
00018 #include <netinet/in.h>
00019 #endif
00020 
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 
00032 #include <net-snmp/types.h>
00033 #include <net-snmp/library/snmp-tc.h>   /* for "internal" definitions */
00034 #include <net-snmp/library/snmp_api.h>
00035 
00036 netsnmp_feature_child_of(snmp_tc_all, libnetsnmp)
00037 
00038 netsnmp_feature_child_of(netsnmp_dateandtime_set_buf_from_vars, netsnmp_unused)
00039 netsnmp_feature_child_of(date_n_time, snmp_tc_all)
00040 netsnmp_feature_child_of(ctime_to_timet, snmp_tc_all)
00041 netsnmp_feature_child_of(check_rowstatus_with_storagetype_transition, snmp_tc_all)
00042 
00043 #ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_DATEANDTIME_SET_BUF_FROM_VARS
00044 /*
00045   DateAndTime ::= TEXTUAL-CONVENTION
00046     DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
00047     STATUS       current
00048     DESCRIPTION
00049             "A date-time specification.
00050 
00051             field  octets  contents                  range
00052             -----  ------  --------                  -----
00053               1      1-2   year*                     0..65536
00054               2       3    month                     1..12
00055               3       4    day                       1..31
00056               4       5    hour                      0..23
00057               5       6    minutes                   0..59
00058               6       7    seconds                   0..60
00059                            (use 60 for leap-second)
00060               7       8    deci-seconds              0..9
00061               8       9    direction from UTC        '+' / '-'
00062               9      10    hours from UTC*           0..13
00063              10      11    minutes from UTC          0..59
00064 
00065             * Notes:
00066             - the value of year is in network-byte order
00067             - daylight saving time in New Zealand is +13
00068 
00069             For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
00070             displayed as:
00071 
00072                              1992-5-26,13:30:15.0,-4:0
00073 
00074             Note that if only local time is known, then timezone
00075             information (fields 8-10) is not present."
00076     SYNTAX       OCTET STRING (SIZE (8 | 11))
00077 */
00078 
00079 int
00080 netsnmp_dateandtime_set_buf_from_vars(u_char *buf, size_t *bufsize,
00081                                       u_short year, u_char month, u_char day,
00082                                       u_char hour, u_char minutes,
00083                                       u_char seconds, u_char deci_seconds,
00084                                       int utc_offset_direction,
00085                                       u_char utc_offset_hours,
00086                                       u_char utc_offset_minutes)
00087 {
00088     u_short tmp_year = htons(year);
00089 
00090     /*
00091      * if we have a utc offset, need 11 bytes. Otherwise we
00092      * just need 8 bytes.
00093      */
00094     if(utc_offset_direction) {
00095         if(*bufsize < 11)
00096             return SNMPERR_RANGE;
00097 
00098         /*
00099          * set utc offset data
00100          */
00101         buf[8] = (utc_offset_direction < 0) ? '-' : '+';
00102         buf[9] = utc_offset_hours;
00103         buf[10] = utc_offset_minutes;
00104         *bufsize = 11;
00105     }
00106     else if(*bufsize < 8)
00107         return SNMPERR_RANGE;
00108     else
00109         *bufsize = 8;
00110 
00111     /*
00112      * set basic date/time data
00113      */
00114     memcpy(buf, &tmp_year, sizeof(tmp_year));
00115     buf[2] = month;
00116     buf[3] = day;
00117     buf[4] = hour;
00118     buf[5] = minutes;
00119     buf[6] = seconds;
00120     buf[7] = deci_seconds;
00121 
00122     return SNMPERR_SUCCESS;
00123 }
00124 #endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_DATEANDTIME_SET_BUF_FROM_VARS */
00125 
00126 #ifndef NETSNMP_FEATURE_REMOVE_DATE_N_TIME
00127 u_char         *
00128 date_n_time(const time_t * when, size_t * length)
00129 {
00130     struct tm      *tm_p;
00131     static u_char   string[11];
00132     unsigned short yauron;
00133 
00134     /*
00135      * Null time
00136      */
00137     if (when == NULL || *when == 0 || *when == (time_t) - 1) {
00138         string[0] = 0;
00139         string[1] = 0;
00140         string[2] = 1;
00141         string[3] = 1;
00142         string[4] = 0;
00143         string[5] = 0;
00144         string[6] = 0;
00145         string[7] = 0;
00146         *length = 8;
00147         return string;
00148     }
00149 
00150 
00151     /*
00152      * Basic 'local' time handling
00153      */
00154     tm_p = localtime(when);
00155     yauron = tm_p->tm_year + 1900;
00156     string[0] = (u_char)(yauron >> 8);
00157     string[1] = (u_char)yauron;
00158     string[2] = tm_p->tm_mon + 1;
00159     string[3] = tm_p->tm_mday;
00160     string[4] = tm_p->tm_hour;
00161     string[5] = tm_p->tm_min;
00162     string[6] = tm_p->tm_sec;
00163     string[7] = 0;
00164     *length = 8;
00165 
00166 #ifndef cygwin
00167     /*
00168      * Timezone offset
00169      */
00170     {
00171 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
00172     const int tzoffset = -tm_p->tm_gmtoff;   /* Seconds east of UTC */
00173 #else
00174     const int tzoffset = timezone;           /* Seconds west of UTC */
00175 #endif
00176     if (tzoffset > 0)
00177         string[8] = '-';
00178     else
00179         string[8] = '+';
00180     string[9] = abs(tzoffset) / 3600;
00181     string[10] = (abs(tzoffset) - string[9] * 3600) / 60;
00182     *length = 11;
00183     }
00184 #endif
00185 
00186 #if defined(SYSV) && !HAVE_STRUCT_TM_TM_GMTOFF
00187     /*
00188      * Daylight saving time
00189      */
00190     if (tm_p->tm_isdst > 0) {
00191         /*
00192          * Assume add one hour 
00193          */
00194         if (string[8] == '-')
00195             --string[9];
00196         else
00197             ++string[9];
00198 
00199         if (string[9] == 0)
00200             string[8] = '+';
00201     }
00202 #endif
00203 
00204     return string;
00205 }
00206 #endif /* NETSNMP_FEATURE_REMOVE_DATE_N_TIME */
00207 
00208 #ifndef NETSNMP_FEATURE_REMOVE_CTIME_TO_TIMET
00209 time_t
00210 ctime_to_timet(const char *str)
00211 {
00212     struct tm       tm;
00213 
00214     if (strlen(str) < 24)
00215         return 0;
00216 
00217     /*
00218      * Month 
00219      */
00220     if (!strncmp(str + 4, "Jan", 3))
00221         tm.tm_mon = 0;
00222     else if (!strncmp(str + 4, "Feb", 3))
00223         tm.tm_mon = 1;
00224     else if (!strncmp(str + 4, "Mar", 3))
00225         tm.tm_mon = 2;
00226     else if (!strncmp(str + 4, "Apr", 3))
00227         tm.tm_mon = 3;
00228     else if (!strncmp(str + 4, "May", 3))
00229         tm.tm_mon = 4;
00230     else if (!strncmp(str + 4, "Jun", 3))
00231         tm.tm_mon = 5;
00232     else if (!strncmp(str + 4, "Jul", 3))
00233         tm.tm_mon = 6;
00234     else if (!strncmp(str + 4, "Aug", 3))
00235         tm.tm_mon = 7;
00236     else if (!strncmp(str + 4, "Sep", 3))
00237         tm.tm_mon = 8;
00238     else if (!strncmp(str + 4, "Oct", 3))
00239         tm.tm_mon = 9;
00240     else if (!strncmp(str + 4, "Nov", 3))
00241         tm.tm_mon = 10;
00242     else if (!strncmp(str + 4, "Dec", 3))
00243         tm.tm_mon = 11;
00244     else
00245         return 0;
00246 
00247     tm.tm_mday = atoi(str + 8);
00248     tm.tm_hour = atoi(str + 11);
00249     tm.tm_min = atoi(str + 14);
00250     tm.tm_sec = atoi(str + 17);
00251     tm.tm_year = atoi(str + 20) - 1900;
00252 
00253     /*
00254      *  Cope with timezone and DST
00255      */
00256 
00257 #ifdef SYSV
00258     if (daylight)
00259         tm.tm_isdst = 1;
00260 
00261     tm.tm_sec -= timezone;
00262 #endif
00263 
00264     return (mktime(&tm));
00265 }
00266 #endif /* NETSNMP_FEATURE_REMOVE_CTIME_TO_TIMET */
00267 
00268 /*
00269  * blatantly lifted from opensnmp 
00270  */
00271 char
00272 check_rowstatus_transition(int oldValue, int newValue)
00273 {
00274     /*
00275      * From the SNMPv2-TC MIB:
00276      *                                          STATE
00277      *               +--------------+-----------+-------------+-------------
00278      *               |      A       |     B     |      C      |      D
00279      *               |              |status col.|status column|
00280      *               |status column |    is     |      is     |status column
00281      *     ACTION    |does not exist|  notReady | notInService|  is active
00282      * --------------+--------------+-----------+-------------+-------------
00283      * set status    |noError    ->D|inconsist- |inconsistent-|inconsistent-
00284      * column to     |       or     |   entValue|        Value|        Value
00285      * createAndGo   |inconsistent- |           |             |
00286      *               |         Value|           |             |
00287      * --------------+--------------+-----------+-------------+-------------
00288      * set status    |noError  see 1|inconsist- |inconsistent-|inconsistent-
00289      * column to     |       or     |   entValue|        Value|        Value
00290      * createAndWait |wrongValue    |           |             |
00291      * --------------+--------------+-----------+-------------+-------------
00292      * set status    |inconsistent- |inconsist- |noError      |noError
00293      * column to     |         Value|   entValue|             |
00294      * active        |              |           |             |
00295      *               |              |     or    |             |
00296      *               |              |           |             |
00297      *               |              |see 2   ->D|see 8     ->D|          ->D
00298      * --------------+--------------+-----------+-------------+-------------
00299      * set status    |inconsistent- |inconsist- |noError      |noError   ->C
00300      * column to     |         Value|   entValue|             |
00301      * notInService  |              |           |             |
00302      *               |              |     or    |             |      or
00303      *               |              |           |             |
00304      *               |              |see 3   ->C|          ->C|see 6
00305      * --------------+--------------+-----------+-------------+-------------
00306      * set status    |noError       |noError    |noError      |noError   ->A
00307      * column to     |              |           |             |      or
00308      * destroy       |           ->A|        ->A|          ->A|see 7
00309      * --------------+--------------+-----------+-------------+-------------
00310      * set any other |see 4         |noError    |noError      |see 5
00311      * column to some|              |           |             |
00312      * value         |              |      see 1|          ->C|          ->D
00313      * --------------+--------------+-----------+-------------+-------------
00314      
00315      *             (1) goto B or C, depending on information available to the
00316      *             agent.
00317      
00318      *             (2) if other variable bindings included in the same PDU,
00319      *             provide values for all columns which are missing but
00320      *             required, and all columns have acceptable values, then
00321      *             return noError and goto D.
00322      
00323      *             (3) if other variable bindings included in the same PDU,
00324      *             provide legal values for all columns which are missing but
00325      *             required, then return noError and goto C.
00326      
00327      *             (4) at the discretion of the agent, the return value may be
00328      *             either:
00329      
00330      *                  inconsistentName:  because the agent does not choose to
00331      *                  create such an instance when the corresponding
00332      *                  RowStatus instance does not exist, or
00333      
00334      *                  inconsistentValue:  if the supplied value is
00335      *                  inconsistent with the state of some other MIB object's
00336      *                  value, or
00337      
00338      *                  noError: because the agent chooses to create the
00339      *                  instance.
00340      
00341      *             If noError is returned, then the instance of the status
00342      *             column must also be created, and the new state is B or C,
00343      *             depending on the information available to the agent.  If
00344      *             inconsistentName or inconsistentValue is returned, the row
00345      *             remains in state A.
00346      
00347      *             (5) depending on the MIB definition for the column/table,
00348      *             either noError or inconsistentValue may be returned.
00349      
00350      *             (6) the return value can indicate one of the following
00351      *             errors:
00352      
00353      *                  wrongValue: because the agent does not support
00354      *                  notInService (e.g., an agent which does not support
00355      *                  createAndWait), or
00356      
00357      *                  inconsistentValue: because the agent is unable to take
00358      *                  the row out of service at this time, perhaps because it
00359      *                  is in use and cannot be de-activated.
00360      
00361      *             (7) the return value can indicate the following error:
00362      
00363      *                  inconsistentValue: because the agent is unable to
00364      *                  remove the row at this time, perhaps because it is in
00365      *                  use and cannot be de-activated.
00366      
00367      *             (8) the transition to D can fail, e.g., if the values of the
00368      *             conceptual row are inconsistent, then the error code would
00369      *             be inconsistentValue.
00370      
00371      *             NOTE: Other processing of (this and other varbinds of) the
00372      *             set request may result in a response other than noError
00373      *             being returned, e.g., wrongValue, noCreation, etc.
00374      */
00375 
00376     switch (newValue) {
00377         /*
00378          * these two end up being equivelent as far as checking the 
00379          * status goes, although the final states are based on the 
00380          * newValue. 
00381          */
00382     case RS_ACTIVE:
00383     case RS_NOTINSERVICE:
00384         if (oldValue == RS_NOTINSERVICE || oldValue == RS_ACTIVE)
00385             ;
00386         else
00387             return SNMP_ERR_INCONSISTENTVALUE;
00388         break;
00389 
00390     case RS_NOTREADY:
00391         /*
00392          * Illegal set value. 
00393          */
00394         return SNMP_ERR_WRONGVALUE;
00395         break;
00396 
00397     case RS_CREATEANDGO:
00398     case RS_CREATEANDWAIT:
00399         if (oldValue != RS_NONEXISTENT)
00400             /*
00401              * impossible, we already exist. 
00402              */
00403             return SNMP_ERR_INCONSISTENTVALUE;
00404         break;
00405 
00406     case RS_DESTROY:
00407         break;
00408 
00409     default:
00410         return SNMP_ERR_WRONGVALUE;
00411         break;
00412     }
00413 
00414     return SNMP_ERR_NOERROR;
00415 }
00416 
00417 #ifndef NETSNMP_FEATURE_REMOVE_CHECK_ROWSTATUS_WITH_STORAGETYPE_TRANSITION
00418 char
00419 check_rowstatus_with_storagetype_transition(int oldValue, int newValue,
00420                                             int oldStorage)
00421 {
00422     /*
00423      * can not destroy permanent or readonly rows
00424      */
00425     if ((RS_DESTROY == newValue) &&
00426         ((SNMP_STORAGE_PERMANENT == oldStorage) ||
00427          (SNMP_STORAGE_READONLY == oldStorage)))
00428         return SNMP_ERR_WRONGVALUE;
00429 
00430     return check_rowstatus_transition(oldValue, newValue);
00431 }
00432 #endif /* NETSNMP_FEATURE_REMOVE_CHECK_ROWSTATUS_WITH_STORAGETYPE_TRANSITION */
00433 
00434 netsnmp_feature_child_of(check_storage_transition, snmp_tc_all)
00435 #ifndef NETSNMP_FEATURE_REMOVE_CHECK_STORAGE_TRANSITION
00436 char
00437 check_storage_transition(int oldValue, int newValue)
00438 {
00439     /*
00440      * From the SNMPv2-TC MIB:
00441      
00442      *             "Describes the memory realization of a conceptual row.  A
00443      *             row which is volatile(2) is lost upon reboot.  A row which
00444      *             is either nonVolatile(3), permanent(4) or readOnly(5), is
00445      *             backed up by stable storage.  A row which is permanent(4)
00446      *             can be changed but not deleted.  A row which is readOnly(5)
00447      *             cannot be changed nor deleted.
00448      
00449      *             If the value of an object with this syntax is either
00450      *             permanent(4) or readOnly(5), it cannot be written.
00451      *             Conversely, if the value is either other(1), volatile(2) or
00452      *             nonVolatile(3), it cannot be modified to be permanent(4) or
00453      *             readOnly(5).  (All illegal modifications result in a
00454      *             'wrongValue' error.)
00455      
00456      *             Every usage of this textual convention is required to
00457      *             specify the columnar objects which a permanent(4) row must
00458      *             at a minimum allow to be writable."
00459      */
00460     switch (oldValue) {
00461     case SNMP_STORAGE_PERMANENT:
00462     case SNMP_STORAGE_READONLY:
00463         return SNMP_ERR_INCONSISTENTVALUE;
00464 
00465     case SNMP_STORAGE_NONE:
00466     case SNMP_STORAGE_OTHER:
00467     case SNMP_STORAGE_VOLATILE:
00468     case SNMP_STORAGE_NONVOLATILE:
00469         if (newValue == SNMP_STORAGE_PERMANENT ||
00470             newValue == SNMP_STORAGE_READONLY)
00471             return SNMP_ERR_INCONSISTENTVALUE;
00472     }
00473 
00474     return SNMP_ERR_NOERROR;
00475 }
00476 #endif /* NETSNMP_FEATURE_REMOVE_CHECK_STORAGE_TRANSITION */