3 /*****************************************************************************
5 * ntpSnmpSubAgentObject.c
7 * This file provides the callback functions for net-snmp and registers the
8 * serviced MIB objects with the master agent.
10 * Each object has its own callback function that is called by the
11 * master agent process whenever someone queries the corresponding MIB
14 * At the moment this triggers a full send/receive procedure for each
15 * queried MIB object, one of the things that are still on my todo list:
16 * a caching mechanism that reduces the number of requests sent to the
19 ****************************************************************************/
20 #include <net-snmp/net-snmp-config.h>
21 #include <net-snmp/net-snmp-includes.h>
22 #include <net-snmp/agent/net-snmp-agent-includes.h>
23 #include "ntpSnmpSubagentObject.h"
26 /* general purpose buffer length definition */
27 #define NTPQ_BUFLEN 2048
29 static int ntpSnmpSubagentObject
= 3;
31 char ntpvalue
[NTPQ_BUFLEN
];
35 /*****************************************************************************
37 * ntpsnmpd_strip_string
39 * This function removes white space characters and EOL chars
40 * from the beginning and end of a given NULL terminated string.
41 * Be aware that the parameter itself is altered.
43 ****************************************************************************
45 * string char* The name of the string variable
46 * NOTE: must be NULL terminated!
48 * int length of resulting string (i.e. w/o white spaces)
49 ****************************************************************************/
51 int ntpsnmpd_strip_string(char *string
)
53 char newstring
[2048] = { 0 };
57 if ( strlen(string
) > 2047 )
62 for (i
=0;i
<strlen(string
);i
++)
72 strncpy(newstring
,(char *) &string
[i
], sizeof(newstring
));
77 strncpy(string
, newstring
, j
);
79 return(strlen(string
));
83 /*****************************************************************************
85 * ntpsnmpd_parse_string
87 * This function will parse a given NULL terminated string and cut it
88 * into a fieldname and a value part (using the '=' as the delimiter.
89 * The fieldname will be converted to uppercase and all whitespace
90 * characters are removed from it.
91 * The value part is stripped, e.g. all whitespace characters are removed
92 * from the beginning and end of the string.
93 * If the value is started and ended with quotes ("), they will be removed
94 * and everything between the quotes is left untouched (including
97 * server host name = hello world!
98 * will result in a field string "SERVERHOSTNAME" and a value
100 * My first Parameter = " is this! "
101 * results in a field string "MYFIRSTPARAMETER" and a vaue " is this! "
102 ****************************************************************************
104 * src char* The name of the source string variable
105 * NOTE: must be NULL terminated!
106 * field char* The name of the string which takes the
108 * fieldsize int The maximum size of the field name
109 * value char* The name of the string which takes the
111 * valuesize int The maximum size of the value string
114 * int length of value string
115 ****************************************************************************/
117 int ntpsnmpd_parse_string(char *src
, char *field
, int fieldsize
, char *value
, int valuesize
)
125 strncpy(string
, src
, sizeof(string
));
129 /* Parsing the field name */
150 if ( ( string
[i
] >= 'a' ) && ( string
[i
] <='z' ) )
151 field
[j
++]=( string
[i
] - 32 ); // convert to Uppercase
153 field
[j
++]=string
[i
];
160 field
[j
]=0; j
=0; value
[0]=0;
163 /* Now parsing the value */
166 if ( ( string
[i
] > 0x0D ) && ( string
[i
] != ' ' ) )
169 if ( ( value
[0] != 0 ) || ( ( string
[i
] > 0x0D ) && ( string
[i
] != ' ' ) ) )
172 value
[j
++]=string
[i
];
179 strcpy(value
, (char *) &value
[1]);
181 if ( value
[strlen(value
)-1] == '"' )
182 value
[strlen(value
)-1]=0;
184 return (strlen(value
));
189 /*****************************************************************************
191 * ntpsnmpd_cut_string
193 * This function will parse a given NULL terminated string and cut it
194 * into fields using the specified delimiter character.
195 * It will then copy the requested field into a destination buffer
197 * ntpsnmpd_cut_string(read:my:lips:fool, RESULT, ':', 2, sizeof(RESULT))
198 * will copy "lips" to RESULT.
199 ****************************************************************************
201 * src char* The name of the source string variable
202 * NOTE: must be NULL terminated!
203 * dest char* The name of the string which takes the
204 * requested field content
205 * delim char The delimiter character
206 * fieldnumber int The number of the required field
207 * (start counting with 0)
208 * maxsize int The maximum size of dest
211 * int length of resulting dest string
212 ****************************************************************************/
214 int ntpsnmpd_cut_string(char *src
, char *dest
, const char delim
, int fieldnumber
, int maxsize
)
222 strncpy (string
, src
, sizeof(string
));
226 memset (dest
, 0, maxsize
);
228 /* Parsing the field name */
229 for (i
=0;l
<=fieldnumber
;i
++)
232 l
=fieldnumber
+1; /* terminate loop */
235 if ( string
[i
] == delim
)
237 l
++; /* next field */
239 else if ( ( l
== fieldnumber
) && ( j
< maxsize
) )
247 return (strlen(dest
));
252 /*****************************************************************************
256 * This function retrieves the value for a given variable, currently
257 * this only supports sysvars. It starts a full mode 6 send/receive/parse
258 * iteration and needs to be optimized, e.g. by using a caching mechanism
260 ****************************************************************************
262 * variable char* The name of the required variable
263 * rbuffer char* The buffer where the value goes
264 * maxlength int Max. number of bytes for resultbuf
267 * u_int number of chars that have been copied to
269 ****************************************************************************/
271 unsigned int read_ntp_value(char *variable
, char *rbuffer
, unsigned int maxlength
)
273 unsigned int i
, sv_len
= 0;
274 char sv_data
[NTPQ_BUFLEN
];
276 memset (sv_data
,0, NTPQ_BUFLEN
);
277 sv_len
= ntpq_read_sysvars ( sv_data
, NTPQ_BUFLEN
);
281 i
=ntpq_getvar( sv_data
, sv_len
, variable
, rbuffer
, maxlength
);
290 /*****************************************************************************
292 * The get_xxx functions
294 * The following function calls are callback functions that will be
295 * used by the master agent process to retrieve a value for a requested
298 ****************************************************************************/
301 int get_ntpEntSoftwareName (netsnmp_mib_handler
*handler
,
302 netsnmp_handler_registration
*reginfo
,
303 netsnmp_agent_request_info
*reqinfo
,
304 netsnmp_request_info
*requests
)
306 char ntp_softwarename
[NTPQ_BUFLEN
];
308 memset (ntp_softwarename
, 0, NTPQ_BUFLEN
);
310 switch (reqinfo
->mode
) {
313 if ( read_ntp_value("product", ntpvalue
, NTPQ_BUFLEN
) )
315 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
320 else if ( read_ntp_value("version", ntpvalue
, NTPQ_BUFLEN
) )
322 ntpsnmpd_cut_string(ntpvalue
, ntp_softwarename
, ' ', 0, sizeof(ntp_softwarename
)-1);
323 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
324 (u_char
*)ntp_softwarename
,
325 strlen(ntp_softwarename
)
328 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
339 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
340 return SNMP_ERR_GENERR
;
343 return SNMP_ERR_NOERROR
;
347 int get_ntpEntSoftwareVersion (netsnmp_mib_handler
*handler
,
348 netsnmp_handler_registration
*reginfo
,
349 netsnmp_agent_request_info
*reqinfo
,
350 netsnmp_request_info
*requests
)
353 switch (reqinfo
->mode
) {
357 if ( read_ntp_value("version", ntpvalue
, NTPQ_BUFLEN
) )
359 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
364 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
375 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
376 return SNMP_ERR_GENERR
;
379 return SNMP_ERR_NOERROR
;
383 int get_ntpEntSoftwareVersionVal (netsnmp_mib_handler
*handler
,
384 netsnmp_handler_registration
*reginfo
,
385 netsnmp_agent_request_info
*reqinfo
,
386 netsnmp_request_info
*requests
)
389 switch (reqinfo
->mode
) {
393 if ( read_ntp_value("versionval", ntpvalue
, NTPQ_BUFLEN
) )
396 snmp_set_var_typed_value(requests
->requestvb
, ASN_UNSIGNED
,
402 snmp_set_var_typed_value(requests
->requestvb
, ASN_UNSIGNED
,
413 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
414 return SNMP_ERR_GENERR
;
417 return SNMP_ERR_NOERROR
;
422 int get_ntpEntSoftwareVendor (netsnmp_mib_handler
*handler
,
423 netsnmp_handler_registration
*reginfo
,
424 netsnmp_agent_request_info
*reqinfo
,
425 netsnmp_request_info
*requests
)
428 switch (reqinfo
->mode
) {
432 if ( read_ntp_value("vendor", ntpvalue
, NTPQ_BUFLEN
) )
434 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
439 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
447 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
448 return SNMP_ERR_GENERR
;
451 return SNMP_ERR_NOERROR
;
455 int get_ntpEntSystemType (netsnmp_mib_handler
*handler
,
456 netsnmp_handler_registration
*reginfo
,
457 netsnmp_agent_request_info
*reqinfo
,
458 netsnmp_request_info
*requests
)
461 switch (reqinfo
->mode
) {
465 if ( read_ntp_value("systemtype", ntpvalue
, NTPQ_BUFLEN
) )
467 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
473 if ( read_ntp_value("system", ntpvalue
, NTPQ_BUFLEN
) )
475 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
480 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
491 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
492 return SNMP_ERR_GENERR
;
495 return SNMP_ERR_NOERROR
;
498 int get_ntpEntTimeResolution (netsnmp_mib_handler
*handler
,
499 netsnmp_handler_registration
*reginfo
,
500 netsnmp_agent_request_info
*reqinfo
,
501 netsnmp_request_info
*requests
)
504 switch (reqinfo
->mode
) {
508 if ( read_ntp_value("resolution", ntpvalue
, NTPQ_BUFLEN
) )
510 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
515 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
526 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
527 return SNMP_ERR_GENERR
;
530 return SNMP_ERR_NOERROR
;
534 int get_ntpEntTimeResolutionVal (netsnmp_mib_handler
*handler
,
535 netsnmp_handler_registration
*reginfo
,
536 netsnmp_agent_request_info
*reqinfo
,
537 netsnmp_request_info
*requests
)
541 switch (reqinfo
->mode
) {
545 if ( read_ntp_value("resolutionval", ntpvalue
, NTPQ_BUFLEN
) )
548 snmp_set_var_typed_value(requests
->requestvb
, ASN_UNSIGNED
,
554 snmp_set_var_typed_value(requests
->requestvb
, ASN_UNSIGNED
,
565 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
566 return SNMP_ERR_GENERR
;
569 return SNMP_ERR_NOERROR
;
573 int get_ntpEntTimePrecision (netsnmp_mib_handler
*handler
,
574 netsnmp_handler_registration
*reginfo
,
575 netsnmp_agent_request_info
*reqinfo
,
576 netsnmp_request_info
*requests
)
578 switch (reqinfo
->mode
) {
582 if ( read_ntp_value("precision", ntpvalue
, NTPQ_BUFLEN
) )
584 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
589 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
600 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
601 return SNMP_ERR_GENERR
;
604 return SNMP_ERR_NOERROR
;
607 int get_ntpEntTimePrecisionVal (netsnmp_mib_handler
*handler
,
608 netsnmp_handler_registration
*reginfo
,
609 netsnmp_agent_request_info
*reqinfo
,
610 netsnmp_request_info
*requests
)
614 switch (reqinfo
->mode
) {
618 if ( read_ntp_value("precision", ntpvalue
, NTPQ_BUFLEN
) )
621 snmp_set_var_typed_value(requests
->requestvb
, ASN_INTEGER
,
627 snmp_set_var_typed_value(requests
->requestvb
, ASN_INTEGER
,
638 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
639 return SNMP_ERR_GENERR
;
642 return SNMP_ERR_NOERROR
;
647 int get_ntpEntTimeDistance (netsnmp_mib_handler
*handler
,
648 netsnmp_handler_registration
*reginfo
,
649 netsnmp_agent_request_info
*reqinfo
,
650 netsnmp_request_info
*requests
)
652 switch (reqinfo
->mode
) {
656 if ( read_ntp_value("rootdelay", ntpvalue
, NTPQ_BUFLEN
) )
658 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
663 snmp_set_var_typed_value(requests
->requestvb
, ASN_OCTET_STR
,
674 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
675 return SNMP_ERR_GENERR
;
678 return SNMP_ERR_NOERROR
;
684 * Initialize sub agent
685 * TODO: Define NTP MIB OID (has to be assigned by IANA)
686 * At the moment we use a private MIB branch (enterprises.5597.99)
690 init_ntpSnmpSubagentObject(void)
693 /* Register all MIB objects with the agentx master */
695 _SETUP_OID_RO( ntpEntSoftwareName
, NTPV4_OID
, 1, 1, 1, 0 );
696 _SETUP_OID_RO( ntpEntSoftwareVersion
, NTPV4_OID
, 1, 1, 2, 0 );
697 _SETUP_OID_RO( ntpEntSoftwareVersionVal
, NTPV4_OID
, 1, 1, 3, 0 );
698 _SETUP_OID_RO( ntpEntSoftwareVendor
, NTPV4_OID
, 1, 1, 4, 0 );
699 _SETUP_OID_RO( ntpEntSystemType
, NTPV4_OID
, 1, 1, 5, 0 );
700 _SETUP_OID_RO( ntpEntTimeResolution
, NTPV4_OID
, 1, 1, 6, 0 );
701 _SETUP_OID_RO( ntpEntTimeResolutionVal
, NTPV4_OID
, 1, 1, 7, 0 );
702 _SETUP_OID_RO( ntpEntTimePrecision
, NTPV4_OID
, 1, 1, 8, 0 );
703 _SETUP_OID_RO( ntpEntTimePrecisionVal
, NTPV4_OID
, 1, 1, 9, 0 );
704 _SETUP_OID_RO( ntpEntTimeDistance
, NTPV4_OID
, 1, 1,10, 0 );