/*****************************************************************************
*
* ntpSnmpSubAgentObject.c
*
* This file provides the callback functions for net-snmp and registers the
* serviced MIB objects with the master agent.
*
* Each object has its own callback function that is called by the
* master agent process whenever someone queries the corresponding MIB
* object.
*
* At the moment this triggers a full send/receive procedure for each
* queried MIB object, one of the things that are still on my todo list:
* a caching mechanism that reduces the number of requests sent to the
* ntpd process.
*
****************************************************************************/
#include <ntp_snmp.h>
#include <ctype.h>
#include <ntp.h>
#include <libntpq.h>
/* general purpose buffer length definition */
#define NTPQ_BUFLEN 2048
char ntpvalue[NTPQ_BUFLEN];
/*****************************************************************************
*
* ntpsnmpd_parse_string
*
* This function will parse a given NULL terminated string and cut it
* into a fieldname and a value part (using the '=' as the delimiter.
* The fieldname will be converted to uppercase and all whitespace
* characters are removed from it.
* The value part is stripped, e.g. all whitespace characters are removed
* from the beginning and end of the string.
* If the value is started and ended with quotes ("), they will be removed
* and everything between the quotes is left untouched (including
* whitespace)
* Example:
* server host name = hello world!
* will result in a field string "SERVERHOSTNAME" and a value
* of "hello world!".
* My first Parameter = " is this! "
* results in a field string "MYFIRSTPARAMETER" and a value " is this! "
****************************************************************************
* Parameters:
* string const char * The source string to parse.
* NOTE: must be NULL terminated!
* field char * The buffer for the field name.
* fieldsize size_t The size of the field buffer.
* value char * The buffer for the value.
* valuesize size_t The size of the value buffer.
*
* Returns:
* size_t length of value string
****************************************************************************/
size_t
ntpsnmpd_parse_string(
const char * string,
char * field,
size_t fieldsize,
char * value,
size_t valuesize
)
{
int i;
int j;
int loop;
size_t str_cnt;
size_t val_cnt;
/* we need at least one byte to work with to simplify */
if (fieldsize < 1 || valuesize < 1)
return 0;
str_cnt = strlen(string);
/* Parsing the field name */
j = 0;
loop = TRUE;
for (i = 0; loop && i <= str_cnt; i++) {
switch (string[i]) {
case '\t': /* Tab */
case '\n': /* LF */
case '\r': /* CR */
case ' ': /* Space */
break;
case '=':
loop = FALSE;
break;
default:
if (j < fieldsize)
field[j++] = toupper(string[i]);
}
}
j = min(j, fieldsize - 1);
field[j] = '\0';
/* Now parsing the value */
value[0] = '\0';
j = 0;
for (val_cnt = 0; i < str_cnt; i++) {
if (string[i] > 0x0D && string[i] != ' ')
val_cnt = min(j + 1, valuesize - 1);
/*****************************************************************************
*
* ntpsnmpd_cut_string
*
* This function will parse a given NULL terminated string and cut it
* into fields using the specified delimiter character.
* It will then copy the requested field into a destination buffer
* Example:
* ntpsnmpd_cut_string(read:my:lips:fool, RESULT, ':', 2, sizeof(RESULT))
* will copy "lips" to RESULT.
****************************************************************************
* Parameters:
* src const char * The name of the source string variable
* NOTE: must be NULL terminated!
* dest char * The name of the string which takes the
* requested field content
* delim char The delimiter character
* fieldnumber int The number of the required field
* (start counting with 0)
* maxsize size_t The maximum size of dest
*
* Returns:
* size_t length of resulting dest string
****************************************************************************/
/* Parsing the field name */
for (i = 0, l = 0; i < str_cnt && l <= fieldnumber; i++) {
if (string[i] == delim)
l++; /* next field */
else if (l == fieldnumber && j < maxsize)
dest[j++] = string[i];
}
j = min(j, maxsize - 1);
dest[j] = '\0';
return j;
}
/*****************************************************************************
*
* read_ntp_value
*
* This function retrieves the value for a given variable, currently
* this only supports sysvars. It starts a full mode 6 send/receive/parse
* iteration and needs to be optimized, e.g. by using a caching mechanism
*
****************************************************************************
* Parameters:
* variable char* The name of the required variable
* rbuffer char* The buffer where the value goes
* maxlength int Max. number of bytes for resultbuf
*
* Returns:
* u_int number of chars that have been copied to
* rbuffer
****************************************************************************/
/*****************************************************************************
*
* The get_xxx functions
*
* The following function calls are callback functions that will be
* used by the master agent process to retrieve a value for a requested
* MIB object.
*
****************************************************************************/
default:
/* If we cannot get the information we need, we will return a generic error to the SNMP client */
return SNMP_ERR_GENERR;
}
}
return SNMP_ERR_NOERROR;
}
default:
/* If we cannot get the information we need, we will return a generic error to the SNMP client */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/*
* ntpEntTimeResolution
* "The time resolution in integer format, where the resolution
* is represented as divisions of a second, e.g., a value of 1000
* translates to 1.0 ms."
*
* ntpEntTimeResolution is a challenge for ntpd, as the resolution is
* not known nor exposed by ntpd, only the measured precision (time to
* read the clock).
*
* Logically the resolution must be at least the precision, so report
* it as our best approximation of resolution until/unless ntpd provides
* better.
*/
int
get_ntpEntTimeResolution(
netsnmp_mib_handler * handler,
netsnmp_handler_registration * reginfo,
netsnmp_agent_request_info * reqinfo,
netsnmp_request_info * requests
)
{
int precision;
u_int32 resolution;
switch (reqinfo->mode) {
case MODE_GET:
if (!read_ntp_value("precision", ntpvalue,
sizeof(ntpvalue)))
return SNMP_ERR_GENERR;
if (1 != sscanf(ntpvalue, "%d", &precision))
return SNMP_ERR_GENERR;
if (precision >= 0)
return SNMP_ERR_GENERR;
precision = max(precision, -31);
resolution = 1 << -precision;
snmp_set_var_typed_value(
requests->requestvb,
ASN_UNSIGNED,
(void *)&resolution,
sizeof(resolution));
break;
default:
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/*
* ntpEntTimePrecision
* "The entity's precision in integer format, shows the precision.
* A value of -5 would mean 2^-5 = 31.25 ms."
*/
int
get_ntpEntTimePrecision(
netsnmp_mib_handler * handler,
netsnmp_handler_registration * reginfo,
netsnmp_agent_request_info * reqinfo,
netsnmp_request_info * requests
)
{
int precision;
int32 precision32;
switch (reqinfo->mode) {
case MODE_GET:
if (!read_ntp_value("precision", ntpvalue,
sizeof(ntpvalue)))
return SNMP_ERR_GENERR;
if (1 != sscanf(ntpvalue, "%d", &precision))
return SNMP_ERR_GENERR;
precision32 = (int32)precision;
snmp_set_var_typed_value(
requests->requestvb,
ASN_INTEGER,
(void *)&precision32,
sizeof(precision32));
break;
default:
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int get_ntpEntTimeDistance (netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
switch (reqinfo->mode) {
case MODE_GET:
{