Blame apps/snmptrapd_sql.c

Packit fcad23
/*
Packit fcad23
 * File       : snmptrapd_sql
Packit fcad23
 * Author     : Robert Story
Packit fcad23
 *
Packit fcad23
 * Copyright © 2009 Science Logic, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 *
Packit fcad23
 * This file implements a handler for snmptrapd which will cache incoming
Packit fcad23
 * traps and then write them to a MySQL database.
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#include <net-snmp/net-snmp-features.h>
Packit fcad23
Packit fcad23
#ifdef NETSNMP_USE_MYSQL
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * SQL includes
Packit fcad23
 */
Packit fcad23
#undef PACKAGE_BUGREPORT
Packit fcad23
#undef PACKAGE_NAME
Packit fcad23
#undef PACKAGE_STRING
Packit fcad23
#undef PACKAGE_TARNAME
Packit fcad23
#undef PACKAGE_VERSION
Packit fcad23
#ifdef HAVE_MY_GLOBAL_H
Packit fcad23
#include <my_global.h>
Packit fcad23
#endif
Packit fcad23
#ifdef HAVE_MY_SYS_H
Packit fcad23
#include <my_sys.h>
Packit fcad23
#endif
Packit fcad23
#include <mysql.h>
Packit fcad23
#include <errmsg.h>
Packit fcad23
Packit fcad23
#if HAVE_STDLIB_H
Packit fcad23
#include <stdlib.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_UNISTD_H
Packit fcad23
#include <unistd.h>
Packit fcad23
#endif
Packit fcad23
#include <stdio.h>
Packit fcad23
#if HAVE_STRING_H
Packit fcad23
#include <string.h>
Packit fcad23
#else
Packit fcad23
#include <strings.h>
Packit fcad23
#endif
Packit fcad23
#include <ctype.h>
Packit fcad23
#include <sys/types.h>
Packit fcad23
#if HAVE_NETINET_IN_H
Packit fcad23
#include <netinet/in.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_NETDB_H
Packit fcad23
#include <netdb.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-includes.h>
Packit fcad23
#include <net-snmp/agent/net-snmp-agent-includes.h>
Packit fcad23
#include "snmptrapd_handlers.h"
Packit fcad23
#include "snmptrapd_auth.h"
Packit fcad23
#include "snmptrapd_log.h"
Packit fcad23
#include "snmptrapd_sql.h"
Packit fcad23
Packit fcad23
netsnmp_feature_require(container_fifo)
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * define a structure to hold all the file globals
Packit fcad23
 */
Packit fcad23
typedef struct netsnmp_sql_globals_t {
Packit fcad23
    char        *host_name;       /* server host (def=localhost) */
Packit fcad23
    char        *user_name;       /* username (def=login name) */
Packit fcad23
    char        *password;        /* password (def=none) */
Packit fcad23
    u_int        port_num;        /* port number (built-in value) */
Packit fcad23
    char        *socket_name;     /* socket name (built-in value) */
Packit fcad23
    const char  *db_name;         /* database name (def=none) */
Packit fcad23
    u_int        flags;           /* connection flags (none) */
Packit fcad23
    MYSQL       *conn;            /* connection */
Packit fcad23
    u_char       connected;       /* connected flag */
Packit fcad23
    const char  *groups[3];
Packit fcad23
    MYSQL_STMT  *trap_stmt, *vb_stmt; /* prepared statements */
Packit fcad23
    u_int        alarm_id;        /* id of periodic save alarm */
Packit fcad23
    netsnmp_container *queue;     /* container; traps pending database write */
Packit fcad23
    u_int        queue_max;       /* auto save queue when it gets this big */
Packit fcad23
    int          queue_interval;  /* auto save every N seconds */
Packit fcad23
} netsnmp_sql_globals;
Packit fcad23
Packit fcad23
static netsnmp_sql_globals _sql = {
Packit fcad23
    NULL,                  /* host */
Packit fcad23
    NULL,                  /* username */
Packit fcad23
    NULL,                  /* password */
Packit fcad23
    0,                     /* port */
Packit fcad23
    NULL,                  /* socket */
Packit fcad23
    "net_snmp",            /* database */
Packit fcad23
    0,                     /* conn flags */
Packit fcad23
    NULL,                  /* connection */
Packit fcad23
    0,                     /* connected */
Packit fcad23
    { "client", "snmptrapd", NULL },  /* groups to read from .my.cnf */
Packit fcad23
    NULL,                  /* trap_stmt */
Packit fcad23
    NULL,                  /* vb_stmt */
Packit fcad23
    0,                     /* alarm_id */
Packit fcad23
    NULL,                  /* queue */
Packit fcad23
    1,                     /* queue_max */
Packit fcad23
    -1                     /* queue_interval */
Packit fcad23
};
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * log traps as text, or binary blobs?
Packit fcad23
 */
Packit fcad23
#define NETSNMP_MYSQL_TRAP_VALUE_TEXT 1
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * We will be using prepared statements for performance reasons. This
Packit fcad23
 * requires a sql bind structure for each cell to be inserted in the
Packit fcad23
 * database. We will be using 2 global static structures to bind to,
Packit fcad23
 * and a netsnmp container to store the necessary data until it is
Packit fcad23
 * written to the database. Fixed size buffers are also used to
Packit fcad23
 * simplify memory management.
Packit fcad23
 */
Packit fcad23
/** enums for the trap fields to be bound */
Packit fcad23
enum{
Packit fcad23
    TBIND_DATE = 0,           /* time received */
Packit fcad23
    TBIND_HOST,               /* src ip */
Packit fcad23
    TBIND_USER,               /* auth/user information */
Packit fcad23
    TBIND_TYPE,               /* pdu type */
Packit fcad23
    TBIND_VER,                /* snmp version */
Packit fcad23
    TBIND_REQID,              /* request id */
Packit fcad23
    TBIND_OID,                /* trap OID */
Packit fcad23
    TBIND_TRANSPORT,          /* transport */
Packit fcad23
    TBIND_SECURITY_MODEL,     /* security model */
Packit fcad23
    TBIND_v3_MSGID,           /* v3 msg id */
Packit fcad23
    TBIND_v3_SECURITY_LEVEL,  /* security level */
Packit fcad23
    TBIND_v3_CONTEXT_NAME,    /* context */
Packit fcad23
    TBIND_v3_CONTEXT_ENGINE,  /* context engine id */
Packit fcad23
    TBIND_v3_SECURITY_NAME,   /* security name */
Packit fcad23
    TBIND_v3_SECURITY_ENGINE, /* security engine id */
Packit fcad23
    TBIND_MAX
Packit fcad23
};
Packit fcad23
Packit fcad23
/** enums for the varbind fields to be bound */
Packit fcad23
enum {
Packit fcad23
    VBIND_ID = 0,             /* trap_id */
Packit fcad23
    VBIND_OID,                /* varbind oid */
Packit fcad23
    VBIND_TYPE,               /* varbind type */
Packit fcad23
    VBIND_VAL,                /* varbind value */
Packit fcad23
    VBIND_MAX
Packit fcad23
};
Packit fcad23
Packit fcad23
/** buffer struct for varbind data */
Packit fcad23
typedef struct sql_vb_buf_t {
Packit fcad23
Packit fcad23
    char      *oid;
Packit fcad23
    u_long     oid_len;
Packit fcad23
Packit fcad23
    u_char    *val;
Packit fcad23
    u_long     val_len;
Packit fcad23
Packit fcad23
    uint16_t   type;
Packit fcad23
Packit fcad23
} sql_vb_buf;
Packit fcad23
Packit fcad23
/** buffer struct for trap data */
Packit fcad23
typedef struct sql_buf_t {
Packit fcad23
    char      *host;
Packit fcad23
    u_long     host_len;
Packit fcad23
Packit fcad23
    char      *oid;
Packit fcad23
    u_long     oid_len;
Packit fcad23
Packit fcad23
    char      *user;
Packit fcad23
    u_long     user_len;
Packit fcad23
Packit fcad23
    MYSQL_TIME time;
Packit fcad23
    uint16_t   version, type;
Packit fcad23
    uint32_t   reqid;
Packit fcad23
Packit fcad23
    char      *transport;
Packit fcad23
    u_long     transport_len;
Packit fcad23
Packit fcad23
    uint16_t   security_level, security_model;
Packit fcad23
    uint32_t   msgid;
Packit fcad23
Packit fcad23
    char      *context;
Packit fcad23
    u_long     context_len;
Packit fcad23
Packit fcad23
    char      *context_engine;
Packit fcad23
    u_long     context_engine_len;
Packit fcad23
Packit fcad23
    char      *security_name;
Packit fcad23
    u_long     security_name_len;
Packit fcad23
Packit fcad23
    char      *security_engine;
Packit fcad23
    u_long     security_engine_len;
Packit fcad23
Packit fcad23
    netsnmp_container *varbinds;
Packit fcad23
Packit fcad23
    char       logged;
Packit fcad23
} sql_buf;
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * static bind structures, plus 2 static buffers to bind to.
Packit fcad23
 */
Packit fcad23
static MYSQL_BIND _tbind[TBIND_MAX], _vbind[VBIND_MAX];
Packit fcad23
static my_bool    _no_v3;
Packit fcad23
Packit fcad23
static void _sql_process_queue(u_int dontcare, void *meeither);
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * parse the sqlMaxQueue configuration token
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_parse_queue_fmt(const char *token, char *cptr)
Packit fcad23
{
Packit fcad23
    _sql.queue_max = atoi(cptr);
Packit fcad23
    DEBUGMSGTL(("sql:queue","queue max now %d\n", _sql.queue_max));
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * parse the sqlSaveInterval configuration token
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_parse_interval_fmt(const char *token, char *cptr)
Packit fcad23
{
Packit fcad23
    _sql.queue_interval = atoi(cptr);
Packit fcad23
    DEBUGMSGTL(("sql:queue","queue interval now %d seconds\n",
Packit fcad23
                _sql.queue_interval));
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * register sql related configuration tokens
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
snmptrapd_register_sql_configs( void )
Packit fcad23
{
Packit fcad23
    register_config_handler("snmptrapd", "sqlMaxQueue",
Packit fcad23
                            _parse_queue_fmt, NULL, "integer");
Packit fcad23
    register_config_handler("snmptrapd", "sqlSaveInterval",
Packit fcad23
                            _parse_interval_fmt, NULL, "seconds");
Packit fcad23
}
Packit fcad23
Packit fcad23
static void
Packit fcad23
netsnmp_sql_disconnected(void)
Packit fcad23
{
Packit fcad23
    DEBUGMSGTL(("sql:connection","disconnected\n"));
Packit fcad23
Packit fcad23
    _sql.connected = 0;
Packit fcad23
Packit fcad23
    /** release prepared statements */
Packit fcad23
    if (_sql.trap_stmt) {
Packit fcad23
        mysql_stmt_close(_sql.trap_stmt);
Packit fcad23
        _sql.trap_stmt = NULL;
Packit fcad23
    }
Packit fcad23
    if (_sql.vb_stmt) {
Packit fcad23
        mysql_stmt_close(_sql.vb_stmt);
Packit fcad23
        _sql.vb_stmt = NULL;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * convenience function to log mysql errors
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
netsnmp_sql_error(const char *message)
Packit fcad23
{
Packit fcad23
    u_int err = mysql_errno(_sql.conn);
Packit fcad23
    snmp_log(LOG_ERR, "%s\n", message);
Packit fcad23
    if (_sql.conn != NULL) {
Packit fcad23
#if MYSQL_VERSION_ID >= 40101
Packit fcad23
        snmp_log(LOG_ERR, "Error %u (%s): %s\n",
Packit fcad23
                 err, mysql_sqlstate(_sql.conn), mysql_error(_sql.conn));
Packit fcad23
#else
Packit fcad23
        snmp(LOG_ERR, "Error %u: %s\n",
Packit fcad23
             mysql_errno(_sql.conn), mysql_error(_sql.conn));
Packit fcad23
#endif
Packit fcad23
    }
Packit fcad23
    if (CR_SERVER_GONE_ERROR == err)
Packit fcad23
        netsnmp_sql_disconnected();
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * convenience function to log mysql statement errors
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
netsnmp_sql_stmt_error (MYSQL_STMT *stmt, const char *message)
Packit fcad23
{
Packit fcad23
    u_int err = mysql_errno(_sql.conn);
Packit fcad23
Packit fcad23
    snmp_log(LOG_ERR, "%s\n", message);
Packit fcad23
    if (stmt) {
Packit fcad23
        snmp_log(LOG_ERR, "SQL Error %u (%s): %s\n",
Packit fcad23
                 mysql_stmt_errno(stmt), mysql_stmt_sqlstate(stmt),
Packit fcad23
                 mysql_stmt_error(stmt));
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (CR_SERVER_GONE_ERROR == err)
Packit fcad23
        netsnmp_sql_disconnected();
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * sql cleanup function, called at exit
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
netsnmp_mysql_cleanup(void)
Packit fcad23
{
Packit fcad23
    DEBUGMSGTL(("sql:cleanup"," called\n"));
Packit fcad23
Packit fcad23
    /** unregister alarm */
Packit fcad23
    if (_sql.alarm_id)
Packit fcad23
        snmp_alarm_unregister(_sql.alarm_id);
Packit fcad23
Packit fcad23
    /** save any queued traps */
Packit fcad23
    if (CONTAINER_SIZE(_sql.queue))
Packit fcad23
        _sql_process_queue(0,NULL);
Packit fcad23
Packit fcad23
    CONTAINER_FREE(_sql.queue);
Packit fcad23
    _sql.queue = NULL;
Packit fcad23
Packit fcad23
    if (_sql.trap_stmt) {
Packit fcad23
        mysql_stmt_close(_sql.trap_stmt);
Packit fcad23
        _sql.trap_stmt = NULL;
Packit fcad23
    }
Packit fcad23
    if (_sql.vb_stmt) {
Packit fcad23
        mysql_stmt_close(_sql.vb_stmt);
Packit fcad23
        _sql.vb_stmt = NULL;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    /** disconnect from server */
Packit fcad23
    netsnmp_sql_disconnected();
Packit fcad23
Packit fcad23
    if (_sql.conn) {
Packit fcad23
        mysql_close(_sql.conn);
Packit fcad23
        _sql.conn = NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    mysql_library_end();
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * setup (initialize, prepare and bind) a prepared statement
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
netsnmp_mysql_bind(const char *text, size_t text_size, MYSQL_STMT **stmt,
Packit fcad23
                   MYSQL_BIND *bind)
Packit fcad23
{
Packit fcad23
    if ((NULL == text) || (NULL == stmt) || (NULL == bind)) {
Packit fcad23
        snmp_log(LOG_ERR,"invalid paramaters to netsnmp_mysql_bind()\n");
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    *stmt = mysql_stmt_init(_sql.conn);
Packit fcad23
    if (NULL == *stmt) {
Packit fcad23
        netsnmp_sql_error("could not initialize trap statement handler");
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (mysql_stmt_prepare(*stmt, text, text_size) != 0) {
Packit fcad23
        netsnmp_sql_stmt_error(*stmt, "Could not prepare INSERT");
Packit fcad23
        mysql_stmt_close(*stmt);
Packit fcad23
        *stmt = NULL;
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * connect to the database and do initial setup
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
netsnmp_mysql_connect(void)
Packit fcad23
{
Packit fcad23
    char trap_stmt[] = "INSERT INTO notifications "
Packit fcad23
        "(date_time, host, auth, type, version, request_id, snmpTrapOID, transport, security_model, v3msgid, v3security_level, v3context_name, v3context_engine, v3security_name, v3security_engine) "
Packit fcad23
        "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
Packit fcad23
    char vb_stmt[] = "INSERT INTO varbinds "
Packit fcad23
        "(trap_id, oid, type, value) VALUES (?,?,?,?)";
Packit fcad23
Packit fcad23
    /** initialize connection handler */
Packit fcad23
    if (_sql.connected)
Packit fcad23
        return 0;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("sql:connection","connecting\n"));
Packit fcad23
Packit fcad23
    /** connect to server */
Packit fcad23
    if (mysql_real_connect (_sql.conn, _sql.host_name, _sql.user_name,
Packit fcad23
                            _sql.password, _sql.db_name, _sql.port_num,
Packit fcad23
                            _sql.socket_name, _sql.flags) == NULL) {
Packit fcad23
        netsnmp_sql_error("mysql_real_connect() failed");
Packit fcad23
        goto err;
Packit fcad23
    }
Packit fcad23
    _sql.connected = 1;
Packit fcad23
Packit fcad23
    /** disable autocommit */
Packit fcad23
    if(0 != mysql_autocommit(_sql.conn, 0)) {
Packit fcad23
        netsnmp_sql_error("mysql_autocommit(0) failed");
Packit fcad23
        goto err;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    netsnmp_assert((_sql.trap_stmt == NULL) && (_sql.vb_stmt == NULL));
Packit fcad23
Packit fcad23
    /** prepared statement for inserts */
Packit fcad23
    if (0 != netsnmp_mysql_bind(trap_stmt,sizeof(trap_stmt), &_sql.trap_stmt,
Packit fcad23
                                _tbind))
Packit fcad23
        goto err;
Packit fcad23
Packit fcad23
    if (0 != netsnmp_mysql_bind(vb_stmt,sizeof(vb_stmt),&_sql.vb_stmt,
Packit fcad23
                                _vbind)) {
Packit fcad23
        mysql_stmt_close(_sql.trap_stmt);
Packit fcad23
        _sql.trap_stmt = NULL;
Packit fcad23
        goto err;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
Packit fcad23
  err:
Packit fcad23
    if (_sql.connected)
Packit fcad23
        _sql.connected = 0;
Packit fcad23
Packit fcad23
    return -1;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** one-time initialization for mysql */
Packit fcad23
int
Packit fcad23
netsnmp_mysql_init(void)
Packit fcad23
{
Packit fcad23
    int not_argc = 0, i;
Packit fcad23
    char *not_args[] = { NULL };
Packit fcad23
    char **not_argv = not_args;
Packit fcad23
    netsnmp_trapd_handler *traph;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("sql:init","called\n"));
Packit fcad23
Packit fcad23
    /** negative or 0 interval disables sql logging */
Packit fcad23
    if (_sql.queue_interval <= 0) {
Packit fcad23
        DEBUGMSGTL(("sql:init",
Packit fcad23
                    "mysql not enabled (sqlSaveInterval is <= 0)\n"));
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /** create queue for storing traps til they are written to the db */
Packit fcad23
    _sql.queue = netsnmp_container_find("fifo");
Packit fcad23
    if (NULL == _sql.queue) {
Packit fcad23
        snmp_log(LOG_ERR, "Could not allocate sql buf container\n");
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
#if defined(HAVE_MYSQL_INIT)
Packit fcad23
    mysql_init(NULL);
Packit fcad23
#elif defined(HAVE_MY_INIT)
Packit fcad23
    MY_INIT("snmptrapd");
Packit fcad23
#else
Packit fcad23
    my_init();
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    /** load .my.cnf values */
Packit fcad23
#if HAVE_MY_LOAD_DEFAULTS
Packit fcad23
    my_load_defaults ("my", _sql.groups, &not_argc, &not_argv, 0);
Packit fcad23
#elif defined(HAVE_LOAD_DEFAULTS)
Packit fcad23
    load_defaults ("my", _sql.groups, &not_argc, &not_argv);
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    for(i=0; i < not_argc; ++i) {
Packit fcad23
        if (NULL == not_argv[i])
Packit fcad23
            continue;
Packit fcad23
        if (strncmp(not_argv[i],"--password=",11) == 0)
Packit fcad23
            _sql.password = &not_argv[i][11];
Packit fcad23
        else if (strncmp(not_argv[i],"--host=",7) == 0)
Packit fcad23
            _sql.host_name = &not_argv[i][7];
Packit fcad23
        else if (strncmp(not_argv[i],"--user=",7) == 0)
Packit fcad23
            _sql.user_name = &not_argv[i][7];
Packit fcad23
        else if (strncmp(not_argv[i],"--port=",7) == 0)
Packit fcad23
            _sql.port_num = atoi(&not_argv[i][7]);
Packit fcad23
        else if (strncmp(not_argv[i],"--socket=",9) == 0)
Packit fcad23
            _sql.socket_name = &not_argv[i][9];
Packit fcad23
        else if (strncmp(not_argv[i],"--database=",11) == 0)
Packit fcad23
            _sql.db_name = &not_argv[i][11];
Packit fcad23
        else
Packit fcad23
            snmp_log(LOG_WARNING, "unknown argument[%d] %s\n", i, not_argv[i]);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /** init bind structures */
Packit fcad23
    memset(_tbind, 0x0, sizeof(_tbind));
Packit fcad23
    memset(_vbind, 0x0, sizeof(_vbind));
Packit fcad23
Packit fcad23
    /** trap static bindings */
Packit fcad23
    _tbind[TBIND_HOST].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_HOST].length = &_tbind[TBIND_HOST].buffer_length;
Packit fcad23
Packit fcad23
    _tbind[TBIND_OID].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_OID].length = &_tbind[TBIND_OID].buffer_length;
Packit fcad23
Packit fcad23
    _tbind[TBIND_REQID].buffer_type = MYSQL_TYPE_LONG;
Packit fcad23
    _tbind[TBIND_REQID].is_unsigned = 1;
Packit fcad23
Packit fcad23
    _tbind[TBIND_VER].buffer_type = MYSQL_TYPE_SHORT;
Packit fcad23
    _tbind[TBIND_VER].is_unsigned = 1;
Packit fcad23
Packit fcad23
    _tbind[TBIND_TYPE].buffer_type = MYSQL_TYPE_SHORT;
Packit fcad23
    _tbind[TBIND_TYPE].is_unsigned = 1;
Packit fcad23
Packit fcad23
    _tbind[TBIND_DATE].buffer_type = MYSQL_TYPE_DATETIME;
Packit fcad23
Packit fcad23
    _tbind[TBIND_USER].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_USER].length = &_tbind[TBIND_USER].buffer_length;
Packit fcad23
Packit fcad23
    _tbind[TBIND_TRANSPORT].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_TRANSPORT].length = &_tbind[TBIND_TRANSPORT].buffer_length;
Packit fcad23
Packit fcad23
    _tbind[TBIND_SECURITY_MODEL].buffer_type = MYSQL_TYPE_SHORT;
Packit fcad23
    _tbind[TBIND_SECURITY_MODEL].is_unsigned = 1;
Packit fcad23
Packit fcad23
    _tbind[TBIND_v3_MSGID].buffer_type = MYSQL_TYPE_LONG;
Packit fcad23
    _tbind[TBIND_v3_MSGID].is_unsigned = 1;
Packit fcad23
    _tbind[TBIND_v3_SECURITY_LEVEL].buffer_type = MYSQL_TYPE_SHORT;
Packit fcad23
    _tbind[TBIND_v3_SECURITY_LEVEL].is_unsigned = 1;
Packit fcad23
    _tbind[TBIND_v3_CONTEXT_NAME].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_v3_CONTEXT_ENGINE].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_v3_SECURITY_NAME].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_v3_SECURITY_NAME].length =
Packit fcad23
        &_tbind[TBIND_v3_SECURITY_NAME].buffer_length;
Packit fcad23
    _tbind[TBIND_v3_CONTEXT_NAME].length =
Packit fcad23
        &_tbind[TBIND_v3_CONTEXT_NAME].buffer_length;
Packit fcad23
    _tbind[TBIND_v3_SECURITY_ENGINE].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _tbind[TBIND_v3_SECURITY_ENGINE].length =
Packit fcad23
        &_tbind[TBIND_v3_SECURITY_ENGINE].buffer_length;
Packit fcad23
    _tbind[TBIND_v3_CONTEXT_ENGINE].length =
Packit fcad23
        &_tbind[TBIND_v3_CONTEXT_ENGINE].buffer_length;
Packit fcad23
Packit fcad23
    _tbind[TBIND_v3_MSGID].is_null =
Packit fcad23
        _tbind[TBIND_v3_SECURITY_LEVEL].is_null =
Packit fcad23
        _tbind[TBIND_v3_CONTEXT_NAME].is_null =
Packit fcad23
        _tbind[TBIND_v3_CONTEXT_ENGINE].is_null =
Packit fcad23
        _tbind[TBIND_v3_SECURITY_NAME].is_null =
Packit fcad23
        _tbind[TBIND_v3_SECURITY_ENGINE].is_null = &_no_v3;
Packit fcad23
    
Packit fcad23
    /** variable static bindings */
Packit fcad23
    _vbind[VBIND_ID].buffer_type = MYSQL_TYPE_LONG;
Packit fcad23
    _vbind[VBIND_ID].is_unsigned = 1;
Packit fcad23
Packit fcad23
    _vbind[VBIND_OID].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
    _vbind[VBIND_OID].length = &_vbind[VBIND_OID].buffer_length;
Packit fcad23
Packit fcad23
    _vbind[VBIND_TYPE].buffer_type = MYSQL_TYPE_SHORT;
Packit fcad23
    _vbind[VBIND_TYPE].is_unsigned = 1;
Packit fcad23
Packit fcad23
#ifdef NETSNMP_MYSQL_TRAP_VALUE_TEXT
Packit fcad23
    _vbind[VBIND_VAL].buffer_type = MYSQL_TYPE_STRING;
Packit fcad23
#else
Packit fcad23
    _vbind[VBIND_VAL].buffer_type = MYSQL_TYPE_BLOB;
Packit fcad23
#endif
Packit fcad23
    _vbind[VBIND_VAL].length = &_vbind[VBIND_VAL].buffer_length;
Packit fcad23
Packit fcad23
    _sql.conn = mysql_init (NULL);
Packit fcad23
    if (_sql.conn == NULL) {
Packit fcad23
        netsnmp_sql_error("mysql_init() failed (out of memory?)");
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
#if MYSQL_VERSION_ID >= 100000
Packit fcad23
    mysql_options(_sql.conn, MYSQL_READ_DEFAULT_GROUP, "snmptrapd");
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    /** try to connect; we'll try again later if we fail */
Packit fcad23
    (void) netsnmp_mysql_connect();
Packit fcad23
Packit fcad23
    /** register periodic queue save */
Packit fcad23
    _sql.alarm_id = snmp_alarm_register(_sql.queue_interval, /* seconds */
Packit fcad23
                                        1,                   /* repeat */
Packit fcad23
                                        _sql_process_queue,  /* function */
Packit fcad23
                                        NULL);               /* client args */
Packit fcad23
Packit fcad23
    /** add handler */
Packit fcad23
    traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
Packit fcad23
                                           mysql_handler);
Packit fcad23
    if (NULL == traph) {
Packit fcad23
        snmp_log(LOG_ERR, "Could not allocate sql trap handler\n");
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
    traph->authtypes = TRAP_AUTH_LOG;
Packit fcad23
Packit fcad23
    atexit(netsnmp_mysql_cleanup);
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * log CSV version of trap.
Packit fcad23
 * dontcare param is there so this function can be passed directly
Packit fcad23
 * to CONTAINER_FOR_EACH.
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_sql_log(sql_buf *sqlb, void* dontcare)
Packit fcad23
{
Packit fcad23
    netsnmp_iterator     *it;
Packit fcad23
    sql_vb_buf           *sqlvb;
Packit fcad23
Packit fcad23
    if ((NULL == sqlb) || sqlb->logged)
Packit fcad23
        return;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * log trap info
Packit fcad23
     * nothing done to protect against data insertion attacks with
Packit fcad23
     * respect to bad data (commas, newlines, etc)
Packit fcad23
     */
Packit fcad23
    snmp_log(LOG_ERR,
Packit fcad23
             "trap:%d-%d-%d %d:%d:%d,%s,%d,%d,%d,%s,%s,%d,%d,%d,%s,%s,%s,%s\n",
Packit fcad23
             sqlb->time.year,sqlb->time.month,sqlb->time.day,
Packit fcad23
             sqlb->time.hour,sqlb->time.minute,sqlb->time.second,
Packit fcad23
             sqlb->user,
Packit fcad23
             sqlb->type, sqlb->version, sqlb->reqid, sqlb->oid,
Packit fcad23
             sqlb->transport, sqlb->security_model, sqlb->msgid,
Packit fcad23
             sqlb->security_level, sqlb->context,
Packit fcad23
             sqlb->context_engine, sqlb->security_name,
Packit fcad23
             sqlb->security_engine);
Packit fcad23
Packit fcad23
    sqlb->logged = 1; /* prevent multiple logging */
Packit fcad23
Packit fcad23
    it = CONTAINER_ITERATOR(sqlb->varbinds);
Packit fcad23
    if (NULL == it) {
Packit fcad23
        snmp_log(LOG_ERR,
Packit fcad23
                 "error creating iterator; incomplete trap logged\n");
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /** log varbind info */
Packit fcad23
    for( sqlvb = ITERATOR_FIRST(it); sqlvb; sqlvb = ITERATOR_NEXT(it)) {
Packit fcad23
#ifdef NETSNMP_MYSQL_TRAP_VALUE_TEXT
Packit fcad23
        snmp_log(LOG_ERR,"varbind:%s,%s\n", sqlvb->oid, sqlvb->val);
Packit fcad23
#else
Packit fcad23
        char *hex;
Packit fcad23
        int len = binary_to_hex(sqlvb->val, sqlvb->val_len, &hex;;
Packit fcad23
        if (hex) {
Packit fcad23
            snmp_log(LOG_ERR,"varbind:%d,%s,%s\n", sqlvb->oid, hex);
Packit fcad23
            free(hex);
Packit fcad23
        }
Packit fcad23
        else {
Packit fcad23
            snmp_log(LOG_ERR,"malloc failed for varbind hex value\n");
Packit fcad23
            snmp_log(LOG_ERR,"varbind:%s,\n", sqlvb->oid);
Packit fcad23
        }
Packit fcad23
#endif
Packit fcad23
    }
Packit fcad23
    ITERATOR_RELEASE(it);
Packit fcad23
   
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * free a buffer
Packit fcad23
 * dontcare param is there so this function can be passed directly
Packit fcad23
 * to CONTAINER_FOR_EACH.
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_sql_vb_buf_free(sql_vb_buf *sqlvb, void* dontcare)
Packit fcad23
{
Packit fcad23
    if (NULL == sqlvb)
Packit fcad23
        return;
Packit fcad23
Packit fcad23
    SNMP_FREE(sqlvb->oid);
Packit fcad23
    SNMP_FREE(sqlvb->val);
Packit fcad23
Packit fcad23
    free(sqlvb);
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * free a buffer
Packit fcad23
 * dontcare param is there so this function can be passed directly
Packit fcad23
 * to CONTAINER_FOR_EACH.
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_sql_buf_free(sql_buf *sqlb, void* dontcare)
Packit fcad23
{
Packit fcad23
    if (NULL == sqlb)
Packit fcad23
        return;
Packit fcad23
Packit fcad23
    /** do varbinds first */
Packit fcad23
    if (sqlb->varbinds) {
Packit fcad23
        CONTAINER_CLEAR(sqlb->varbinds,
Packit fcad23
                        (netsnmp_container_obj_func*)_sql_vb_buf_free, NULL);
Packit fcad23
        CONTAINER_FREE(sqlb->varbinds);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    SNMP_FREE(sqlb->host);
Packit fcad23
    SNMP_FREE(sqlb->oid);
Packit fcad23
    SNMP_FREE(sqlb->user);
Packit fcad23
Packit fcad23
    SNMP_FREE(sqlb->context);
Packit fcad23
    SNMP_FREE(sqlb->security_name);
Packit fcad23
    SNMP_FREE(sqlb->context_engine);
Packit fcad23
    SNMP_FREE(sqlb->security_engine);
Packit fcad23
    SNMP_FREE(sqlb->transport);
Packit fcad23
Packit fcad23
    free(sqlb);
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * allocate buffer to store trap and varbinds
Packit fcad23
 */
Packit fcad23
static sql_buf *
Packit fcad23
_sql_buf_get(void)
Packit fcad23
{
Packit fcad23
    sql_buf *sqlb;
Packit fcad23
Packit fcad23
    /** buffer for trap info */
Packit fcad23
    sqlb = SNMP_MALLOC_TYPEDEF(sql_buf);
Packit fcad23
    if (NULL == sqlb)
Packit fcad23
        return NULL;
Packit fcad23
    
Packit fcad23
    /** fifo for varbinds */
Packit fcad23
    sqlb->varbinds = netsnmp_container_find("fifo");
Packit fcad23
    if (NULL == sqlb->varbinds) {
Packit fcad23
        free(sqlb);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return sqlb;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * save info from incoming trap
Packit fcad23
 *
Packit fcad23
 * return 0 on success, anything else is an error
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
_sql_save_trap_info(sql_buf *sqlb, netsnmp_pdu  *pdu,
Packit fcad23
                    netsnmp_transport     *transport)
Packit fcad23
{
Packit fcad23
    static oid   trapoids[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5, 0 };
Packit fcad23
    oid         *trap_oid, tmp_oid[MAX_OID_LEN];
Packit fcad23
    time_t       now;
Packit fcad23
    struct tm   *cur_time;
Packit fcad23
    size_t       tmp_size;
Packit fcad23
    size_t       buf_host_len_t, buf_oid_len_t, buf_user_len_t;
Packit fcad23
    int          oid_overflow, trap_oid_len;
Packit fcad23
    netsnmp_variable_list *vars;
Packit fcad23
Packit fcad23
    if ((NULL == sqlb) || (NULL == pdu) || (NULL == transport))
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("sql:queue", "queueing incoming trap\n"));
Packit fcad23
Packit fcad23
    /** time */
Packit fcad23
    (void) time(&now;;
Packit fcad23
    cur_time = localtime(&now;;
Packit fcad23
    sqlb->time.year = cur_time->tm_year + 1900;
Packit fcad23
    sqlb->time.month = cur_time->tm_mon + 1;
Packit fcad23
    sqlb->time.day = cur_time->tm_mday;
Packit fcad23
    sqlb->time.hour = cur_time->tm_hour;
Packit fcad23
    sqlb->time.minute = cur_time->tm_min;
Packit fcad23
    sqlb->time.second = cur_time->tm_sec;
Packit fcad23
    sqlb->time.second_part = 0;
Packit fcad23
    sqlb->time.neg = 0;
Packit fcad23
Packit fcad23
    /** host name */
Packit fcad23
    buf_host_len_t = 0;
Packit fcad23
    tmp_size = 0;
Packit fcad23
    realloc_format_trap((u_char**)&sqlb->host, &tmp_size,
Packit fcad23
                        &buf_host_len_t, 1, "%B", pdu, transport);
Packit fcad23
    sqlb->host_len = buf_host_len_t;
Packit fcad23
Packit fcad23
    /* snmpTrapOID */
Packit fcad23
    if (pdu->command == SNMP_MSG_TRAP) {
Packit fcad23
        /*
Packit fcad23
         * convert a v1 trap to a v2 varbind
Packit fcad23
         */
Packit fcad23
        if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
Packit fcad23
            trap_oid_len = pdu->enterprise_length;
Packit fcad23
            memcpy(tmp_oid, pdu->enterprise, sizeof(oid) * trap_oid_len);
Packit fcad23
            if (tmp_oid[trap_oid_len - 1] != 0)
Packit fcad23
                tmp_oid[trap_oid_len++] = 0;
Packit fcad23
            tmp_oid[trap_oid_len++] = pdu->specific_type;
Packit fcad23
            trap_oid = tmp_oid;
Packit fcad23
        } else {
Packit fcad23
            trapoids[9] = pdu->trap_type + 1;
Packit fcad23
            trap_oid = trapoids;
Packit fcad23
            trap_oid_len = OID_LENGTH(trapoids);
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    else {
Packit fcad23
        vars = pdu->variables;
Packit fcad23
        if (vars && vars->next_variable) {
Packit fcad23
            trap_oid_len = vars->next_variable->val_len / sizeof(oid);
Packit fcad23
            trap_oid = vars->next_variable->val.objid;
Packit fcad23
        }
Packit fcad23
        else {
Packit fcad23
            static oid null_oid[] = { 0, 0 };
Packit fcad23
            trap_oid_len = OID_LENGTH(null_oid);
Packit fcad23
            trap_oid = null_oid;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    tmp_size = 0;
Packit fcad23
    buf_oid_len_t = oid_overflow = 0;
Packit fcad23
    netsnmp_sprint_realloc_objid_tree((u_char**)&sqlb->oid,&tmp_size,
Packit fcad23
                                      &buf_oid_len_t, 1, &oid_overflow,
Packit fcad23
                                      trap_oid, trap_oid_len);
Packit fcad23
    sqlb->oid_len = buf_oid_len_t;
Packit fcad23
    if (oid_overflow)
Packit fcad23
        snmp_log(LOG_WARNING,"OID truncated in sql buffer\n");
Packit fcad23
Packit fcad23
    /** request id */
Packit fcad23
    sqlb->reqid = pdu->reqid;
Packit fcad23
Packit fcad23
    /** version (convert to 1 based, for sql enum) */
Packit fcad23
    sqlb->version = pdu->version + 1;
Packit fcad23
Packit fcad23
    /** command type (convert to 1 based, for sql enum) */
Packit fcad23
    sqlb->type = pdu->command - 159;
Packit fcad23
Packit fcad23
    /** community string/user name */
Packit fcad23
    tmp_size = 0;
Packit fcad23
    buf_user_len_t = 0;
Packit fcad23
    realloc_format_trap((u_char**)&sqlb->user, &tmp_size,
Packit fcad23
                        &buf_user_len_t, 1, "%u", pdu, transport);
Packit fcad23
    sqlb->user_len = buf_user_len_t;
Packit fcad23
Packit fcad23
    /** transport */
Packit fcad23
    sqlb->transport = transport->f_fmtaddr(transport, pdu->transport_data,
Packit fcad23
                                           pdu->transport_data_length);
Packit fcad23
Packit fcad23
    /** security model */
Packit fcad23
    sqlb->security_model = pdu->securityModel;
Packit fcad23
Packit fcad23
    if ((SNMP_MP_MODEL_SNMPv3+1) == sqlb->version) {
Packit fcad23
Packit fcad23
        sqlb->msgid = pdu->msgid;
Packit fcad23
        sqlb->security_level = pdu->securityLevel;
Packit fcad23
Packit fcad23
        if (pdu->contextName) {
Packit fcad23
            sqlb->context = netsnmp_strdup_and_null((u_char*)pdu->contextName,
Packit fcad23
                                                    pdu->contextNameLen);
Packit fcad23
            sqlb->context_len = pdu->contextNameLen;
Packit fcad23
        }
Packit fcad23
        if (pdu->contextEngineID) {
Packit fcad23
            sqlb->context_engine_len = 
Packit fcad23
                binary_to_hex(pdu->contextEngineID, pdu->contextEngineIDLen,
Packit fcad23
                              &sqlb->context_engine);
Packit fcad23
        }
Packit fcad23
Packit fcad23
        if (pdu->securityName) {
Packit fcad23
            sqlb->security_name =
Packit fcad23
                netsnmp_strdup_and_null((u_char*)pdu->securityName,
Packit fcad23
                                        pdu->securityNameLen);
Packit fcad23
            sqlb->security_name_len = pdu->securityNameLen;
Packit fcad23
        }
Packit fcad23
        if (pdu->securityEngineID) {
Packit fcad23
            sqlb->security_engine_len = 
Packit fcad23
                binary_to_hex(pdu->securityEngineID, pdu->securityEngineIDLen,
Packit fcad23
                              &sqlb->security_engine);
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * save varbind info from incoming trap
Packit fcad23
 *
Packit fcad23
 * return 0 on success, anything else is an error
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
_sql_save_varbind_info(sql_buf *sqlb, netsnmp_pdu  *pdu)
Packit fcad23
{
Packit fcad23
    netsnmp_variable_list *var;
Packit fcad23
    sql_vb_buf       *sqlvb;
Packit fcad23
    size_t            tmp_size, buf_oid_len_t;
Packit fcad23
    int               oid_overflow, rc;
Packit fcad23
#ifdef NETSNMP_MYSQL_TRAP_VALUE_TEXT
Packit fcad23
    size_t            buf_val_len_t;
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    if ((NULL == sqlb) || (NULL == pdu))
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    var = pdu->variables;
Packit fcad23
    while(var) {
Packit fcad23
        sqlvb = SNMP_MALLOC_TYPEDEF(sql_vb_buf);
Packit fcad23
        if (NULL == sqlvb)
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        /** OID */
Packit fcad23
        tmp_size = 0;
Packit fcad23
        buf_oid_len_t = oid_overflow = 0;
Packit fcad23
        netsnmp_sprint_realloc_objid_tree((u_char**)&sqlvb->oid, &tmp_size,
Packit fcad23
                                          &buf_oid_len_t,
Packit fcad23
                                          1, &oid_overflow, var->name,
Packit fcad23
                                          var->name_length);
Packit fcad23
        sqlvb->oid_len = buf_oid_len_t;
Packit fcad23
        if (oid_overflow)
Packit fcad23
            snmp_log(LOG_WARNING,"OID truncated in sql insert\n");
Packit fcad23
        
Packit fcad23
        /** type */
Packit fcad23
        if (var->type > ASN_OBJECT_ID)
Packit fcad23
            /** convert application types to sql enum */
Packit fcad23
            sqlvb->type = ASN_OBJECT_ID + 1 + (var->type & ~ASN_APPLICATION);
Packit fcad23
        else
Packit fcad23
            sqlvb->type = var->type;
Packit fcad23
Packit fcad23
        /** value */
Packit fcad23
#ifdef NETSNMP_MYSQL_TRAP_VALUE_TEXT
Packit fcad23
        tmp_size = 0;
Packit fcad23
        buf_val_len_t = 0;
Packit fcad23
        sprint_realloc_by_type((u_char**)&sqlvb->val, &tmp_size,
Packit fcad23
                               &buf_val_len_t, 1, var, NULL, NULL, NULL);
Packit fcad23
        sqlvb->val_len = buf_val_len_t;
Packit fcad23
#else
Packit fcad23
        sqlvb->val = netsnmp_memdup(var->val.string, var->val_len);
Packit fcad23
        sqlvb->val_len = var->val_len;
Packit fcad23
#endif
Packit fcad23
Packit fcad23
        var = var->next_variable;
Packit fcad23
Packit fcad23
        /** insert into container */
Packit fcad23
        rc = CONTAINER_INSERT(sqlb->varbinds,sqlvb);
Packit fcad23
        if(rc)
Packit fcad23
            snmp_log(LOG_ERR, "couldn't insert varbind into trap container\n");
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * sql trap handler
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
mysql_handler(netsnmp_pdu           *pdu,
Packit fcad23
              netsnmp_transport     *transport,
Packit fcad23
              netsnmp_trapd_handler *handler)
Packit fcad23
{
Packit fcad23
    sql_buf     *sqlb;
Packit fcad23
    int          old_format, rc;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("sql:handler", "called\n"));
Packit fcad23
Packit fcad23
    /** allocate a buffer to save data */
Packit fcad23
    sqlb = _sql_buf_get();
Packit fcad23
    if (NULL == sqlb) {
Packit fcad23
        snmp_log(LOG_ERR, "Could not allocate trap sql buffer\n");
Packit fcad23
        return syslog_handler( pdu, transport, handler );
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /** save OID output format and change to numeric */
Packit fcad23
    old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                                    NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
Packit fcad23
    netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
Packit fcad23
                       NETSNMP_OID_OUTPUT_NUMERIC);
Packit fcad23
Packit fcad23
Packit fcad23
    rc = _sql_save_trap_info(sqlb, pdu, transport);
Packit fcad23
    rc = _sql_save_varbind_info(sqlb, pdu);
Packit fcad23
Packit fcad23
    /** restore previous OID output format */
Packit fcad23
    netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
Packit fcad23
                       old_format);
Packit fcad23
Packit fcad23
    /** insert into queue */
Packit fcad23
    rc = CONTAINER_INSERT(_sql.queue, sqlb);
Packit fcad23
    if(rc) {
Packit fcad23
        snmp_log(LOG_ERR, "Could not log queue sql trap buffer\n");
Packit fcad23
        _sql_log(sqlb, NULL);
Packit fcad23
        _sql_buf_free(sqlb, NULL);
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /** save queue if size is > max */
Packit fcad23
    if (CONTAINER_SIZE(_sql.queue) >= _sql.queue_max)
Packit fcad23
        _sql_process_queue(0,NULL);
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * save a buffered trap to sql database
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_sql_save(sql_buf *sqlb, void *dontcare)
Packit fcad23
{
Packit fcad23
    netsnmp_iterator     *it;
Packit fcad23
    sql_vb_buf           *sqlvb;
Packit fcad23
    u_long                trap_id;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * don't even try if we don't have a database connection
Packit fcad23
     */
Packit fcad23
    if (0 == _sql.connected) {
Packit fcad23
        _sql_log(sqlb, NULL);
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * the prepared statements are bound to the static buffer objects,
Packit fcad23
     * so copy the queued data to the static version.
Packit fcad23
     */
Packit fcad23
    _tbind[TBIND_HOST].buffer = sqlb->host;
Packit fcad23
    _tbind[TBIND_HOST].buffer_length = sqlb->host_len;
Packit fcad23
Packit fcad23
    _tbind[TBIND_OID].buffer = sqlb->oid;
Packit fcad23
    _tbind[TBIND_OID].buffer_length = sqlb->oid_len;
Packit fcad23
Packit fcad23
    _tbind[TBIND_REQID].buffer = (void *)&sqlb->reqid;
Packit fcad23
    _tbind[TBIND_VER].buffer = (void *)&sqlb->version;
Packit fcad23
    _tbind[TBIND_TYPE].buffer = (void *)&sqlb->type;
Packit fcad23
    _tbind[TBIND_SECURITY_MODEL].buffer = (void *)&sqlb->security_model;
Packit fcad23
Packit fcad23
    _tbind[TBIND_DATE].buffer = (void *)&sqlb->time;
Packit fcad23
Packit fcad23
    _tbind[TBIND_USER].buffer = sqlb->user;
Packit fcad23
    _tbind[TBIND_USER].buffer_length = sqlb->user_len;
Packit fcad23
Packit fcad23
    _tbind[TBIND_TRANSPORT].buffer = sqlb->transport;
Packit fcad23
    if (sqlb->transport)
Packit fcad23
        _tbind[TBIND_TRANSPORT].buffer_length = strlen(sqlb->transport);
Packit fcad23
    else
Packit fcad23
        _tbind[TBIND_TRANSPORT].buffer_length = 0;
Packit fcad23
Packit fcad23
Packit fcad23
    if ((SNMP_MP_MODEL_SNMPv3+1) == sqlb->version) {
Packit fcad23
        _no_v3 = 0;
Packit fcad23
Packit fcad23
        _tbind[TBIND_v3_MSGID].buffer = &sqlb->msgid;
Packit fcad23
        
Packit fcad23
        _tbind[TBIND_v3_SECURITY_LEVEL].buffer = &sqlb->security_level;
Packit fcad23
        
Packit fcad23
        _tbind[TBIND_v3_CONTEXT_NAME].buffer = sqlb->context;
Packit fcad23
        _tbind[TBIND_v3_CONTEXT_NAME].buffer_length = sqlb->context_len;
Packit fcad23
Packit fcad23
        _tbind[TBIND_v3_CONTEXT_ENGINE].buffer = sqlb->context_engine;
Packit fcad23
        _tbind[TBIND_v3_CONTEXT_ENGINE].buffer_length =
Packit fcad23
            sqlb->context_engine_len;
Packit fcad23
Packit fcad23
        _tbind[TBIND_v3_SECURITY_NAME].buffer = sqlb->security_name;
Packit fcad23
        _tbind[TBIND_v3_SECURITY_NAME].buffer_length = sqlb->security_name_len;
Packit fcad23
Packit fcad23
        _tbind[TBIND_v3_SECURITY_ENGINE].buffer = sqlb->security_engine;
Packit fcad23
        _tbind[TBIND_v3_SECURITY_ENGINE].buffer_length =
Packit fcad23
            sqlb->security_engine_len;
Packit fcad23
    }
Packit fcad23
    else {
Packit fcad23
        _no_v3 = 1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (mysql_stmt_bind_param(_sql.trap_stmt, _tbind) != 0) {
Packit fcad23
        netsnmp_sql_stmt_error(_sql.trap_stmt,
Packit fcad23
                               "Could not bind parameters for INSERT");
Packit fcad23
        _sql_log(sqlb, NULL);
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /** execute the prepared statement */
Packit fcad23
    if (mysql_stmt_execute(_sql.trap_stmt) != 0) {
Packit fcad23
        netsnmp_sql_stmt_error(_sql.trap_stmt,
Packit fcad23
                               "Could not execute insert statement for trap");
Packit fcad23
        _sql_log(sqlb, NULL);
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
    trap_id = mysql_insert_id(_sql.conn);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * iterate over the varbinds, copy data and insert
Packit fcad23
     */
Packit fcad23
    it = CONTAINER_ITERATOR(sqlb->varbinds);
Packit fcad23
    if (NULL == it) {
Packit fcad23
        snmp_log(LOG_ERR,"Could not allocate iterator\n");
Packit fcad23
        _sql_log(sqlb, NULL);
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    for( sqlvb = ITERATOR_FIRST(it); sqlvb; sqlvb = ITERATOR_NEXT(it)) {
Packit fcad23
Packit fcad23
        _vbind[VBIND_ID].buffer = (void *)&trap_id;
Packit fcad23
        _vbind[VBIND_TYPE].buffer = (void *)&sqlvb->type;
Packit fcad23
Packit fcad23
        _vbind[VBIND_OID].buffer = sqlvb->oid;
Packit fcad23
        _vbind[VBIND_OID].buffer_length = sqlvb->oid_len;
Packit fcad23
Packit fcad23
        _vbind[VBIND_VAL].buffer = sqlvb->val;
Packit fcad23
        _vbind[VBIND_VAL].buffer_length = sqlvb->val_len;
Packit fcad23
Packit fcad23
        if (mysql_stmt_bind_param(_sql.vb_stmt, _vbind) != 0) {
Packit fcad23
            netsnmp_sql_stmt_error(_sql.vb_stmt,
Packit fcad23
                                   "Could not bind parameters for INSERT");
Packit fcad23
            _sql_log(sqlb, NULL);
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        if (mysql_stmt_execute(_sql.vb_stmt) != 0) {
Packit fcad23
            netsnmp_sql_stmt_error(_sql.vb_stmt,
Packit fcad23
                                   "Could not execute insert statement for varbind");
Packit fcad23
            _sql_log(sqlb, NULL);
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    ITERATOR_RELEASE(it);
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * process (save) queued items to sql database.
Packit fcad23
 *
Packit fcad23
 * dontcare & meeither are dummy params so this function can be used
Packit fcad23
 * as a netsnmp_alarm callback function.
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_sql_process_queue(u_int dontcare, void *meeither)
Packit fcad23
{
Packit fcad23
    int        rc;
Packit fcad23
Packit fcad23
    /** bail if the queue is empty */
Packit fcad23
    if( 0 == CONTAINER_SIZE(_sql.queue))
Packit fcad23
        return;
Packit fcad23
Packit fcad23
    DEBUGMSGT(("sql:process", "processing %d queued traps\n",
Packit fcad23
               (int)CONTAINER_SIZE(_sql.queue)));
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if we don't have a database connection, try to reconnect. We
Packit fcad23
     * don't care if we fail - traps will be logged in that case.
Packit fcad23
     */
Packit fcad23
    if (0 == _sql.connected) {
Packit fcad23
        DEBUGMSGT(("sql:process", "no sql connection; reconnecting\n"));
Packit fcad23
        (void) netsnmp_mysql_connect();
Packit fcad23
    }
Packit fcad23
Packit fcad23
    CONTAINER_FOR_EACH(_sql.queue, (netsnmp_container_obj_func*)_sql_save,
Packit fcad23
                       NULL);
Packit fcad23
Packit fcad23
    if (_sql.connected) {
Packit fcad23
        rc = mysql_commit(_sql.conn);
Packit fcad23
        if (rc) { /* nuts... now what? */
Packit fcad23
            netsnmp_sql_error("commit failed");
Packit fcad23
            CONTAINER_FOR_EACH(_sql.queue,
Packit fcad23
                               (netsnmp_container_obj_func*)_sql_log,
Packit fcad23
                               NULL);
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    CONTAINER_CLEAR(_sql.queue, (netsnmp_container_obj_func*)_sql_buf_free,
Packit fcad23
                    NULL);
Packit fcad23
}
Packit fcad23
Packit fcad23
#else
Packit fcad23
int unused;	/* Suppress "empty translation unit" warning */
Packit fcad23
#endif /* NETSNMP_USE_MYSQL */