Annotation of embedaddon/ntp/ntpsnmpd/ntpSnmpSubagentObject.c, revision 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>