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