Annotation of embedaddon/ntp/ntpsnmpd/ntpSnmpSubagentObject.c, revision 1.1.1.1

1.1       misho       1: /*****************************************************************************
                      2:  *
                      3:  *  ntpSnmpSubAgentObject.c
                      4:  *
                      5:  *  This file provides the callback functions for net-snmp and registers the 
                      6:  *  serviced MIB objects with the master agent.
                      7:  * 
                      8:  *  Each object has its own callback function that is called by the 
                      9:  *  master agent process whenever someone queries the corresponding MIB
                     10:  *  object. 
                     11:  * 
                     12:  *  At the moment this triggers a full send/receive procedure for each
                     13:  *  queried MIB object, one of the things that are still on my todo list:
                     14:  *  a caching mechanism that reduces the number of requests sent to the
                     15:  *  ntpd process.
                     16:  *
                     17:  ****************************************************************************/
                     18: #include <ntp_snmp.h>
                     19: #include <ctype.h>
                     20: #include <ntp.h>
                     21: #include <libntpq.h>
                     22: 
                     23: /* general purpose buffer length definition */
                     24: #define NTPQ_BUFLEN 2048
                     25: 
                     26: char ntpvalue[NTPQ_BUFLEN];
                     27: 
                     28: 
                     29: /*****************************************************************************
                     30:  *
                     31:  * ntpsnmpd_parse_string
                     32:  *
                     33:  *  This function will parse a given NULL terminated string and cut it
                     34:  *  into a fieldname and a value part (using the '=' as the delimiter. 
                     35:  *  The fieldname will be converted to uppercase and all whitespace 
                     36:  *  characters are removed from it.
                     37:  *  The value part is stripped, e.g. all whitespace characters are removed
                     38:  *  from the beginning and end of the string.
                     39:  *  If the value is started and ended with quotes ("), they will be removed
                     40:  *  and everything between the quotes is left untouched (including 
                     41:  *  whitespace)
                     42:  *  Example:
                     43:  *     server host name =   hello world!
                     44:  *  will result in a field string "SERVERHOSTNAME" and a value
                     45:  *  of "hello world!".
                     46:  *     My first Parameter              =               "  is this!    "
                     47:   * results in a field string "MYFIRSTPARAMETER" and a value " is this!    "
                     48:  ****************************************************************************
                     49:  * Parameters:
                     50:  *     string          const char *    The source string to parse.
                     51:  *                                     NOTE: must be NULL terminated!
                     52:  *     field           char *          The buffer for the field name.
                     53:  *     fieldsize       size_t          The size of the field buffer.
                     54:  *     value           char *          The buffer for the value.
                     55:  *     valuesize       size_t          The size of the value buffer.
                     56:  *
                     57:  * Returns:
                     58:  *     size_t                  length of value string 
                     59:  ****************************************************************************/
                     60: 
                     61: size_t
                     62: ntpsnmpd_parse_string(
                     63:        const char *    string,
                     64:        char *          field,
                     65:        size_t          fieldsize,
                     66:        char *          value,
                     67:        size_t          valuesize
                     68:        )
                     69: {
                     70:        int i;
                     71:        int j;
                     72:        int loop;
                     73:        size_t str_cnt;
                     74:        size_t val_cnt;
                     75: 
                     76:        /* we need at least one byte to work with to simplify */
                     77:        if (fieldsize < 1 || valuesize < 1)
                     78:                return 0;
                     79: 
                     80:        str_cnt = strlen(string);
                     81: 
                     82:        /* Parsing the field name */
                     83:        j = 0;
                     84:        loop = TRUE;
                     85:        for (i = 0; loop && i <= str_cnt; i++) {
                     86:                switch (string[i]) {
                     87: 
                     88:                case '\t':      /* Tab */
                     89:                case '\n':      /* LF */
                     90:                case '\r':      /* CR */
                     91:                case ' ':       /* Space */
                     92:                        break;
                     93: 
                     94:                case '=':
                     95:                        loop = FALSE;
                     96:                        break;
                     97: 
                     98:                default:
                     99:                        if (j < fieldsize)
                    100:                                field[j++] = toupper(string[i]);
                    101:                }
                    102:        }
                    103: 
                    104:        j = min(j, fieldsize - 1);
                    105:        field[j] = '\0';
                    106: 
                    107:        /* Now parsing the value */
                    108:        value[0] = '\0';
                    109:        j = 0; 
                    110:        for (val_cnt = 0; i < str_cnt; i++) {
                    111:                if (string[i] > 0x0D && string[i] != ' ')
                    112:                        val_cnt = min(j + 1, valuesize - 1);
                    113:                
                    114:                if (value[0] != '\0' ||
                    115:                    (string[i] > 0x0D && string[i] != ' ')) {
                    116:                        if (j < valuesize)
                    117:                                value[j++] = string[i];
                    118:                }
                    119:        }
                    120:        value[val_cnt] = '\0';
                    121: 
                    122:        if (value[0] == '"') {
                    123:                val_cnt--;
                    124:                strncpy(value, &value[1], valuesize);
                    125:                if (val_cnt > 0 && value[val_cnt - 1] == '"') {
                    126:                        val_cnt--;
                    127:                        value[val_cnt] = '\0';
                    128:                }
                    129:        }
                    130: 
                    131:        return val_cnt;
                    132: }
                    133: 
                    134: 
                    135: /*****************************************************************************
                    136:  *
                    137:  * ntpsnmpd_cut_string
                    138:  *
                    139:  *  This function will parse a given NULL terminated string and cut it
                    140:  *  into fields using the specified delimiter character. 
                    141:  *  It will then copy the requested field into a destination buffer
                    142:  *  Example:
                    143:  *     ntpsnmpd_cut_string(read:my:lips:fool, RESULT, ':', 2, sizeof(RESULT))
                    144:  *  will copy "lips" to RESULT.
                    145:  ****************************************************************************
                    146:  * Parameters:
                    147:  *     src             const char *    The name of the source string variable
                    148:  *                                     NOTE: must be NULL terminated!
                    149:  *     dest            char *          The name of the string which takes the
                    150:  *                                     requested field content
                    151:  *     delim           char            The delimiter character
                    152:  *     fieldnumber     int             The number of the required field
                    153:  *                                     (start counting with 0)
                    154:  *     maxsize         size_t          The maximum size of dest
                    155:  *
                    156:  * Returns:
                    157:  *     size_t          length of resulting dest string 
                    158:  ****************************************************************************/
                    159: 
                    160: size_t
                    161: ntpsnmpd_cut_string(
                    162:        const char *    string,
                    163:        char *          dest,
                    164:        char            delim,
                    165:        int             fieldnumber,
                    166:        size_t          maxsize
                    167:        )
                    168: {
                    169:        size_t i;
                    170:        size_t j;
                    171:        int l;
                    172:        size_t str_cnt;
                    173: 
                    174:        if (maxsize < 1)
                    175:                return 0;
                    176: 
                    177:        str_cnt = strlen(string);
                    178:        j = 0;
                    179:        memset(dest, 0, maxsize);
                    180: 
                    181:        /* Parsing the field name */
                    182:        for (i = 0, l = 0; i < str_cnt && l <= fieldnumber; i++) {
                    183:                if (string[i] == delim)
                    184:                        l++;    /* next field */
                    185:                else if (l == fieldnumber && j < maxsize)
                    186:                        dest[j++] = string[i]; 
                    187:        }
                    188:        j = min(j, maxsize - 1);
                    189:        dest[j] = '\0';
                    190: 
                    191:        return j;
                    192: }
                    193: 
                    194: 
                    195: /*****************************************************************************
                    196:  *
                    197:  *  read_ntp_value
                    198:  *
                    199:  *  This function retrieves the value for a given variable, currently
                    200:  *  this only supports sysvars. It starts a full mode 6 send/receive/parse
                    201:  *  iteration and needs to be optimized, e.g. by using a caching mechanism
                    202:  *  
                    203:  ****************************************************************************
                    204:  * Parameters:
                    205:  *     variable        char*   The name of the required variable
                    206:  *     rbuffer         char*   The buffer where the value goes
                    207:  *     maxlength       int     Max. number of bytes for resultbuf
                    208:  *
                    209:  * Returns:
                    210:  *     u_int           number of chars that have been copied to 
                    211:  *                     rbuffer 
                    212:  ****************************************************************************/
                    213: 
                    214: size_t
                    215: read_ntp_value(
                    216:        const char *    variable,
                    217:        char *          value,
                    218:        size_t          valuesize
                    219:        )
                    220: {
                    221:        size_t  sv_len;
                    222:        char    sv_data[NTPQ_BUFLEN];
                    223:        
                    224:        memset(sv_data, 0, sizeof(sv_data));
                    225:        sv_len = ntpq_read_sysvars(sv_data, sizeof(sv_data));
                    226: 
                    227:        if (0 == sv_len)
                    228:                return 0;
                    229:        else
                    230:                return ntpq_getvar(sv_data, sv_len, variable, value,
                    231:                                   valuesize);
                    232: }
                    233: 
                    234: 
                    235: /*****************************************************************************
                    236:  *
                    237:  *  The get_xxx functions
                    238:  *
                    239:  *  The following function calls are callback functions that will be 
                    240:  *  used by the master agent process to retrieve a value for a requested 
                    241:  *  MIB object. 
                    242:  *
                    243:  ****************************************************************************/
                    244: 
                    245: 
                    246: int get_ntpEntSoftwareName (netsnmp_mib_handler *handler,
                    247:                                netsnmp_handler_registration *reginfo,
                    248:                                netsnmp_agent_request_info *reqinfo,
                    249:                                netsnmp_request_info *requests)
                    250: {
                    251:  char ntp_softwarename[NTPQ_BUFLEN];
                    252:        
                    253:    memset (ntp_softwarename, 0, NTPQ_BUFLEN);
                    254:        
                    255:    switch (reqinfo->mode) {
                    256:    case MODE_GET:
                    257:    {
                    258:        if ( read_ntp_value("product", ntpvalue, NTPQ_BUFLEN) )
                    259:        {
                    260:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    261:                              (u_char *)ntpvalue,
                    262:                              strlen(ntpvalue)
                    263:                             );
                    264:        } 
                    265:     else  if ( read_ntp_value("version", ntpvalue, NTPQ_BUFLEN) )
                    266:     {
                    267:        ntpsnmpd_cut_string(ntpvalue, ntp_softwarename, ' ', 0, sizeof(ntp_softwarename)-1);
                    268:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    269:                              (u_char *)ntp_softwarename,
                    270:                              strlen(ntp_softwarename)
                    271:                             );
                    272:     } else {
                    273:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    274:                              (u_char *)"N/A",
                    275:                              3
                    276:                             );
                    277:     }
                    278:     break;
                    279:     
                    280:   }
                    281: 
                    282: 
                    283:   default:
                    284:          /* If we cannot get the information we need, we will return a generic error to the SNMP client */
                    285:         return SNMP_ERR_GENERR;
                    286:   }
                    287: 
                    288:   return SNMP_ERR_NOERROR;
                    289: }
                    290: 
                    291: 
                    292: int get_ntpEntSoftwareVersion (netsnmp_mib_handler *handler,
                    293:                                netsnmp_handler_registration *reginfo,
                    294:                                netsnmp_agent_request_info *reqinfo,
                    295:                                netsnmp_request_info *requests)
                    296: {
                    297: 
                    298:    switch (reqinfo->mode) {
                    299:    case MODE_GET:
                    300:    {
                    301:     
                    302:     if ( read_ntp_value("version", ntpvalue, NTPQ_BUFLEN) )
                    303:     {
                    304:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    305:                              (u_char *)ntpvalue,
                    306:                              strlen(ntpvalue)
                    307:                             );
                    308:     } else {
                    309:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    310:                              (u_char *)"N/A",
                    311:                              3
                    312:                             );
                    313:     }
                    314:     break;
                    315:     
                    316:   }
                    317: 
                    318: 
                    319:   default:
                    320:          /* If we cannot get the information we need, we will return a generic error to the SNMP client */
                    321:         return SNMP_ERR_GENERR;
                    322:   }
                    323: 
                    324:   return SNMP_ERR_NOERROR;
                    325: }
                    326: 
                    327: 
                    328: int get_ntpEntSoftwareVendor (netsnmp_mib_handler *handler,
                    329:                                netsnmp_handler_registration *reginfo,
                    330:                                netsnmp_agent_request_info *reqinfo,
                    331:                                netsnmp_request_info *requests)
                    332: {
                    333: 
                    334:    switch (reqinfo->mode) {
                    335:    case MODE_GET:
                    336:    {
                    337:     
                    338:     if ( read_ntp_value("vendor", ntpvalue, NTPQ_BUFLEN) )
                    339:     {
                    340:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    341:                              (u_char *)ntpvalue,
                    342:                              strlen(ntpvalue)
                    343:                             );
                    344:     } else {
                    345:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    346:                              (u_char *)"N/A",
                    347:                              3
                    348:                             );
                    349:     }
                    350:     break;
                    351: 
                    352:   default:
                    353:          /* If we cannot get the information we need, we will return a generic error to the SNMP client */
                    354:         return SNMP_ERR_GENERR;
                    355:    }
                    356:   }
                    357:   return SNMP_ERR_NOERROR;
                    358: }
                    359: 
                    360: 
                    361: int get_ntpEntSystemType (netsnmp_mib_handler *handler,
                    362:                                netsnmp_handler_registration *reginfo,
                    363:                                netsnmp_agent_request_info *reqinfo,
                    364:                                netsnmp_request_info *requests)
                    365: {
                    366: 
                    367:    switch (reqinfo->mode) {
                    368:    case MODE_GET:
                    369:    {
                    370:     
                    371:     if ( read_ntp_value("systemtype", ntpvalue, NTPQ_BUFLEN) )
                    372:     {
                    373:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    374:                              (u_char *)ntpvalue,
                    375:                              strlen(ntpvalue)
                    376:                             );
                    377:     }
                    378:           
                    379:     if ( read_ntp_value("system", ntpvalue, NTPQ_BUFLEN) )
                    380:     {
                    381:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    382:                              (u_char *)ntpvalue,
                    383:                              strlen(ntpvalue)
                    384:                             );
                    385:     } else {
                    386:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    387:                              (u_char *)"N/A",
                    388:                              3
                    389:                             );
                    390:     }
                    391:     break;
                    392:     
                    393:   }
                    394: 
                    395: 
                    396:   default:
                    397:          /* If we cannot get the information we need, we will return a generic error to the SNMP client */
                    398:         return SNMP_ERR_GENERR;
                    399:   }
                    400: 
                    401:   return SNMP_ERR_NOERROR;
                    402: }
                    403: 
                    404: 
                    405: /*
                    406:  * ntpEntTimeResolution
                    407:  *     "The time resolution in integer format, where the resolution
                    408:  *      is represented as divisions of a second, e.g., a value of 1000
                    409:  *      translates to 1.0 ms."
                    410:  *
                    411:  * ntpEntTimeResolution is a challenge for ntpd, as the resolution is
                    412:  * not known nor exposed by ntpd, only the measured precision (time to
                    413:  * read the clock).
                    414:  *
                    415:  * Logically the resolution must be at least the precision, so report
                    416:  * it as our best approximation of resolution until/unless ntpd provides
                    417:  * better.
                    418:  */
                    419: int
                    420: get_ntpEntTimeResolution(
                    421:        netsnmp_mib_handler *           handler,
                    422:        netsnmp_handler_registration *  reginfo,
                    423:        netsnmp_agent_request_info *    reqinfo,
                    424:        netsnmp_request_info *          requests
                    425:        )
                    426: {
                    427:        int     precision;
                    428:        u_int32 resolution;
                    429: 
                    430:        switch (reqinfo->mode) {
                    431: 
                    432:        case MODE_GET:
                    433:                if (!read_ntp_value("precision", ntpvalue,
                    434:                                    sizeof(ntpvalue)))
                    435:                        return SNMP_ERR_GENERR;
                    436:                if (1 != sscanf(ntpvalue, "%d", &precision))
                    437:                        return SNMP_ERR_GENERR;
                    438:                if (precision >= 0)
                    439:                        return SNMP_ERR_GENERR;
                    440:                precision = max(precision, -31);
                    441:                resolution = 1 << -precision;
                    442:                snmp_set_var_typed_value(
                    443:                        requests->requestvb,
                    444:                        ASN_UNSIGNED,
                    445:                        (void *)&resolution,
                    446:                        sizeof(resolution));
                    447:                break;
                    448: 
                    449:        default:
                    450:                return SNMP_ERR_GENERR;
                    451:        }
                    452: 
                    453:        return SNMP_ERR_NOERROR;
                    454: }
                    455: 
                    456: 
                    457: /*
                    458:  * ntpEntTimePrecision
                    459:  *     "The entity's precision in integer format, shows the precision.
                    460:  *      A value of -5 would mean 2^-5 = 31.25 ms."
                    461:  */
                    462: int 
                    463: get_ntpEntTimePrecision(
                    464:        netsnmp_mib_handler *           handler,
                    465:        netsnmp_handler_registration *  reginfo,
                    466:        netsnmp_agent_request_info *    reqinfo,
                    467:        netsnmp_request_info *          requests
                    468:        )
                    469: {
                    470:        int     precision;
                    471:        int32   precision32;
                    472: 
                    473:        switch (reqinfo->mode) {
                    474: 
                    475:        case MODE_GET:
                    476:                if (!read_ntp_value("precision", ntpvalue, 
                    477:                                    sizeof(ntpvalue)))
                    478:                        return SNMP_ERR_GENERR;
                    479:                if (1 != sscanf(ntpvalue, "%d", &precision))
                    480:                        return SNMP_ERR_GENERR;
                    481:                precision32 = (int32)precision;
                    482:                snmp_set_var_typed_value(
                    483:                        requests->requestvb,
                    484:                        ASN_INTEGER,
                    485:                        (void *)&precision32,
                    486:                        sizeof(precision32));
                    487:                break;
                    488: 
                    489:        default:
                    490:                return SNMP_ERR_GENERR;
                    491:        }
                    492: 
                    493:        return SNMP_ERR_NOERROR;
                    494: }
                    495: 
                    496: 
                    497: int get_ntpEntTimeDistance (netsnmp_mib_handler *handler,
                    498:                                netsnmp_handler_registration *reginfo,
                    499:                                netsnmp_agent_request_info *reqinfo,
                    500:                                netsnmp_request_info *requests)
                    501: {
                    502:    switch (reqinfo->mode) {
                    503:    case MODE_GET:
                    504:    {
                    505:     
                    506:     if ( read_ntp_value("rootdelay", ntpvalue, NTPQ_BUFLEN) )
                    507:     {
                    508:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    509:                              (u_char *)ntpvalue,
                    510:                              strlen(ntpvalue)
                    511:                             );
                    512:     } else {
                    513:        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                    514:                              (u_char *)"N/A",
                    515:                              3
                    516:                             );
                    517:     }
                    518:     break;
                    519:     
                    520:   }
                    521: 
                    522: 
                    523:   default:
                    524:          /* If we cannot get the information we need, we will return a generic error to the SNMP client */
                    525:         return SNMP_ERR_GENERR;
                    526:   }
                    527: 
                    528:   return SNMP_ERR_NOERROR;
                    529: }
                    530: 
                    531: 
                    532: /*
                    533:  *
                    534:  * Initialize sub agent
                    535:  */
                    536: 
                    537: void
                    538: init_ntpSnmpSubagentObject(void)
                    539: {
                    540:        /* Register all MIB objects with the agentx master */
                    541:        NTP_OID_RO( ntpEntSoftwareName,         1, 1, 1, 0);
                    542:        NTP_OID_RO( ntpEntSoftwareVersion,      1, 1, 2, 0);
                    543:        NTP_OID_RO( ntpEntSoftwareVendor,       1, 1, 3, 0);
                    544:        NTP_OID_RO( ntpEntSystemType,           1, 1, 4, 0);
                    545:        NTP_OID_RO( ntpEntTimeResolution,       1, 1, 5, 0);
                    546:        NTP_OID_RO( ntpEntTimePrecision,        1, 1, 6, 0);
                    547:        NTP_OID_RO( ntpEntTimeDistance,         1, 1, 7, 0);
                    548: }
                    549: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>