blob: 2c18aab54b533de92b8a3db7975f7e7f51ccda53 [file] [log] [blame]
/*
* System MIB group implementation - system.c
*
*/
#include <net-snmp/net-snmp-config.h>
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <sys/types.h>
#if HAVE_WINSOCK_H
#include <winsock.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <ctype.h>
#if HAVE_UTSNAME_H
#include <utsname.h>
#else
#if HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_DMALLOC_H
#include <dmalloc.h>
#endif
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "util_funcs.h"
#include "system_mib.h"
#include "struct.h"
#include "sysORTable.h"
/*********************
*
* Kernel & interface information,
* and internal forward declarations
*
*********************/
#define SYS_STRING_LEN 256
char version_descr[SYS_STRING_LEN] = VERS_DESC;
char sysContact[SYS_STRING_LEN] = SYS_CONTACT;
char sysName[SYS_STRING_LEN] = SYS_NAME;
char sysLocation[SYS_STRING_LEN] = SYS_LOC;
oid version_sysoid[] = { SYSTEM_MIB };
int version_sysoid_len = 9; /* OID_LENGTH( version_sysoid ); */
char oldversion_descr[SYS_STRING_LEN];
char oldsysContact[SYS_STRING_LEN];
char oldsysName[SYS_STRING_LEN];
char oldsysLocation[SYS_STRING_LEN];
int sysServices = 72;
int sysServicesConfiged = 0;
extern oid version_id[];
extern int version_id_len;
static int sysContactSet = 0, sysLocationSet = 0, sysNameSet = 0;
WriteMethod writeSystem;
int header_system(struct variable *, oid *, size_t *, int,
size_t *, WriteMethod **);
/*********************
*
* snmpd.conf config parsing
*
*********************/
void
system_parse_config_sysloc(const char *token, char *cptr)
{
char tmpbuf[1024];
if (strlen(cptr) >= sizeof(sysLocation)) {
snprintf(tmpbuf, 1024,
"syslocation token too long (must be < %d):\n\t%s",
sizeof(sysLocation), cptr);
config_perror(tmpbuf);
}
if (strcmp(token, "psyslocation") == 0) {
if (sysLocationSet < 0) {
/*
* This is bogus (and shouldn't happen anyway) -- the sysLocation
* is already configured read-only.
*/
snmp_log(LOG_WARNING,
"ignoring attempted override of read-only sysLocation.0\n");
return;
} else {
sysLocationSet++;
}
} else {
if (sysLocationSet > 0) {
/*
* This is bogus (and shouldn't happen anyway) -- we already read a
* persistent value of sysLocation, which we should ignore in
* favour of this one.
*/
snmp_log(LOG_WARNING,
"ignoring attempted override of read-only sysLocation.0\n");
/*
* Fall through and copy in this value.
*/
}
sysLocationSet = -1;
}
if (strcmp(cptr, "\"\"") == 0) {
sysLocation[0] = '\0';
} else if (strlen(cptr) < sizeof(sysLocation)) {
strcpy(sysLocation, cptr);
}
}
void
system_parse_config_syscon(const char *token, char *cptr)
{
char tmpbuf[1024];
if (strlen(cptr) >= sizeof(sysContact)) {
snprintf(tmpbuf, 1024,
"syscontact token too long (must be < %d):\n\t%s",
sizeof(sysContact), cptr);
config_perror(tmpbuf);
}
if (strcmp(token, "psyscontact") == 0) {
if (sysContactSet < 0) {
/*
* This is bogus (and shouldn't happen anyway) -- the sysContact
* is already configured read-only.
*/
snmp_log(LOG_WARNING,
"ignoring attempted override of read-only sysContact.0\n");
return;
} else {
sysContactSet++;
}
} else {
if (sysContactSet > 0) {
/*
* This is bogus (and shouldn't happen anyway) -- we already read a
* persistent value of sysContact, which we should ignore in favour
* of this one.
*/
snmp_log(LOG_WARNING,
"ignoring attempted override of read-only sysContact.0\n");
/*
* Fall through and copy in this value.
*/
}
sysContactSet = -1;
}
if (strcmp(cptr, "\"\"") == 0) {
sysContact[0] = '\0';
} else if (strlen(cptr) < sizeof(sysContact)) {
strcpy(sysContact, cptr);
}
}
void
system_parse_config_sysname(const char *token, char *cptr)
{
char tmpbuf[1024];
if (strlen(cptr) >= sizeof(sysName)) {
snprintf(tmpbuf, 1024,
"sysname token too long (must be < %d):\n\t%s",
sizeof(sysName), cptr);
config_perror(tmpbuf);
}
if (strcmp(token, "psysname") == 0) {
if (sysNameSet < 0) {
/*
* This is bogus (and shouldn't happen anyway) -- the sysName
* is already configured read-only.
*/
snmp_log(LOG_WARNING,
"ignoring attempted override of read-only sysName.0\n");
return;
} else {
sysNameSet++;
}
} else {
if (sysNameSet > 0) {
/*
* This is bogus (and shouldn't happen anyway) -- we already read a
* persistent value of sysName, which we should ignore in favour
* of this one.
*/
snmp_log(LOG_WARNING,
"ignoring attempted override of read-only sysName.0\n");
/*
* Fall through and copy in this value.
*/
}
sysNameSet = -1;
}
if (strcmp(cptr, "\"\"") == 0) {
sysName[0] = '\0';
} else if (strlen(cptr) < sizeof(sysName)) {
strcpy(sysName, cptr);
}
}
void
system_parse_config_sysServices(const char *token, char *cptr)
{
sysServices = atoi(cptr);
sysServicesConfiged = 1;
}
/*********************
*
* Initialisation & common implementation functions
*
*********************/
/*
* define the structure we're going to ask the agent to register our
* information at
*/
struct variable2 system_variables[] = {
{VERSION_DESCR, ASN_OCTET_STR, RONLY, var_system, 1, {1}},
{VERSIONID, ASN_OBJECT_ID, RONLY, var_system, 1, {2}},
{UPTIME, ASN_TIMETICKS, RONLY, var_system, 1, {3}},
{SYSCONTACT, ASN_OCTET_STR, RWRITE, var_system, 1, {4}},
{SYSTEMNAME, ASN_OCTET_STR, RWRITE, var_system, 1, {5}},
{SYSLOCATION, ASN_OCTET_STR, RWRITE, var_system, 1, {6}},
{SYSSERVICES, ASN_INTEGER, RONLY, var_system, 1, {7}},
{SYSORLASTCHANGE, ASN_TIMETICKS, RONLY, var_system, 1, {8}}
};
/*
* Define the OID pointer to the top of the mib tree that we're
* registering underneath
*/
oid system_variables_oid[] = { SNMP_OID_MIB2, 1 };
oid system_module_oid[] = { SNMP_OID_SNMPMODULES, 1 };
int system_module_oid_len =
sizeof(system_module_oid) / sizeof(oid);
int system_module_count = 0;
static int
system_store(int a, int b, void *c, void *d)
{
char line[SNMP_MAXBUF_SMALL];
if (sysLocationSet > 0) {
snprintf(line, SNMP_MAXBUF_SMALL, "psyslocation %s", sysLocation);
snmpd_store_config(line);
}
if (sysContactSet > 0) {
snprintf(line, SNMP_MAXBUF_SMALL, "psyscontact %s", sysContact);
snmpd_store_config(line);
}
if (sysNameSet > 0) {
snprintf(line, SNMP_MAXBUF_SMALL, "psysname %s", sysName);
snmpd_store_config(line);
}
return 0;
}
void
init_system_mib(void)
{
#ifdef HAVE_UNAME
struct utsname utsName;
uname(&utsName);
sprintf(version_descr, "%s %s %s %s %s", utsName.sysname,
utsName.nodename, utsName.release, utsName.version,
utsName.machine);
#else
#if HAVE_EXECV
struct extensible extmp;
/*
* set default values of system stuff
*/
sprintf(extmp.command, "%s -a", UNAMEPROG);
/*
* setup defaults
*/
extmp.type = EXECPROC;
extmp.next = NULL;
exec_command(&extmp);
strncpy(version_descr, extmp.output, sizeof(version_descr));
version_descr[strlen(version_descr) - 1] = 0; /* chomp new line */
#else
strcpy(version_descr, "unknown");
#endif
#endif
#ifdef HAVE_GETHOSTNAME
gethostname(sysName, sizeof(sysName));
#else
#ifdef HAVE_UNAME
strncpy(sysName, utsName.nodename, sizeof(sysName));
#else
#if HAVE_EXECV
sprintf(extmp.command, "%s -n", UNAMEPROG);
/*
* setup defaults
*/
extmp.type = EXECPROC;
extmp.next = NULL;
exec_command(&extmp);
strncpy(sysName, extmp.output, sizeof(sysName));
sysName[strlen(sysName) - 1] = 0; /* chomp new line */
#else
strcpy(sysName, "unknown");
#endif /* HAVE_EXECV */
#endif /* HAVE_UNAME */
#endif /* HAVE_GETHOSTNAME */
/*
* register ourselves with the agent to handle our mib tree
*/
REGISTER_MIB("mibII/system", system_variables, variable2,
system_variables_oid);
if (++system_module_count == 3)
REGISTER_SYSOR_ENTRY(system_module_oid,
"The MIB module for SNMPv2 entities");
sysContactSet = sysLocationSet = sysNameSet = 0;
/*
* register our config handlers
*/
snmpd_register_config_handler("syslocation",
system_parse_config_sysloc, NULL,
"location");
snmpd_register_config_handler("syscontact", system_parse_config_syscon,
NULL, "contact-name");
snmpd_register_config_handler("sysname", system_parse_config_sysname,
NULL, "node-name");
snmpd_register_config_handler("psyslocation",
system_parse_config_sysloc, NULL, NULL);
snmpd_register_config_handler("psyscontact",
system_parse_config_syscon, NULL, NULL);
snmpd_register_config_handler("psysname", system_parse_config_sysname,
NULL, NULL);
snmpd_register_config_handler("sysservices",
system_parse_config_sysServices, NULL,
"NUMBER");
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
system_store, NULL);
}
/*********************
*
* System specific implementation functions
*
*********************/
#ifdef USING_MIBII_SYSORTABLE_MODULE
extern struct timeval sysOR_lastchange;
#endif
u_char *
var_system(struct variable *vp,
oid * name,
size_t * length,
int exact, size_t * var_len, WriteMethod ** write_method)
{
static u_long ulret;
if (header_generic(vp, name, length, exact, var_len, write_method) ==
MATCH_FAILED)
return NULL;
switch (vp->magic) {
case VERSION_DESCR:
*var_len = strlen(version_descr);
return (u_char *) version_descr;
case VERSIONID:
*var_len = version_sysoid_len * sizeof(version_sysoid[0]);
return (u_char *) version_sysoid;
case UPTIME:
ulret = netsnmp_get_agent_uptime();
return ((u_char *) & ulret);
case SYSCONTACT:
*var_len = strlen(sysContact);
*write_method = writeSystem;
return (u_char *) sysContact;
case SYSTEMNAME:
*var_len = strlen(sysName);
*write_method = writeSystem;
return (u_char *) sysName;
case SYSLOCATION:
*var_len = strlen(sysLocation);
*write_method = writeSystem;
return (u_char *) sysLocation;
case SYSSERVICES:
#if NO_DUMMY_VALUES
if (!sysServicesConfiged)
return NULL;
#endif
long_return = sysServices;
return (u_char *) & long_return;
#ifdef USING_MIBII_SYSORTABLE_MODULE
case SYSORLASTCHANGE:
ulret = netsnmp_timeval_uptime(&sysOR_lastchange);
return ((u_char *) & ulret);
#endif
default:
DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_system\n",
vp->magic));
}
return NULL;
}
int
writeSystem(int action,
u_char * var_val,
u_char var_val_type,
size_t var_val_len,
u_char * statP, oid * name, size_t name_len)
{
u_char *cp;
char *buf = NULL, *oldbuf = NULL;
int count, *setvar = NULL;
switch ((char) name[7]) {
case SYSCONTACT:
buf = sysContact;
oldbuf = oldsysContact;
setvar = &sysContactSet;
break;
case SYSTEMNAME:
buf = sysName;
oldbuf = oldsysName;
setvar = &sysNameSet;
break;
case SYSLOCATION:
buf = sysLocation;
oldbuf = oldsysLocation;
setvar = &sysLocationSet;
break;
default:
return SNMP_ERR_GENERR; /* ??? */
}
switch (action) {
case RESERVE1: /* Check values for acceptability */
if (var_val_type != ASN_OCTET_STR) {
snmp_log(LOG_ERR, "not string\n");
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(sysLocation) - 1) {
snmp_log(LOG_ERR, "bad length\n");
return SNMP_ERR_WRONGLENGTH;
}
for (cp = var_val, count = 0; count < (int) var_val_len;
count++, cp++) {
if (!isprint(*cp)) {
snmp_log(LOG_ERR, "not print %x\n", *cp);
return SNMP_ERR_WRONGVALUE;
}
}
if (setvar != NULL && *setvar < 0) {
/*
* The object is set in a read-only configuration file.
*/
return SNMP_ERR_NOTWRITABLE;
}
break;
case RESERVE2: /* Allocate memory and similar resources */
/*
* Using static strings, so nothing needs to be done
*/
break;
case ACTION: /* Perform the SET action (if reversible) */
/*
* Save the old value, in case of UNDO
*/
strcpy(oldbuf, buf);
memcpy(buf, var_val, var_val_len);
buf[var_val_len] = 0;
break;
case UNDO: /* Reverse the SET action and free resources */
strcpy(buf, oldbuf);
oldbuf[0] = 0;
break;
case COMMIT:
if (setvar != NULL) {
*setvar = 1;
}
snmp_save_persistent(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE));
(void) snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
SNMP_CALLBACK_STORE_DATA, NULL);
snmp_clean_persistent(netsnmp_ds_get_string
(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE));
case FREE: /* Free any resources allocated */
/*
* No resources have been allocated, but "empty" the 'oldbuf'
*/
oldbuf[0] = 0;
break;
}
return SNMP_ERR_NOERROR;
} /* end of writeSystem */
/*********************
*
* Internal implementation functions - None
*
*********************/