00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #define ENABLE_DB_TRANSACTIONS
00046
00047
00048
00049 #ifdef HAVE_CONFIG_H
00050 #include "config.h"
00051 #endif
00052
00053 #include <sys/types.h>
00054 #include <stdlib.h>
00055 #include <string.h>
00056
00057 #include "event.h"
00058 #include "decode.h"
00059 #include "rules.h"
00060 #include "plugbase.h"
00061 #include "spo_plugbase.h"
00062 #include "parser.h"
00063 #include "debug.h"
00064 #include "util.h"
00065
00066 #include "snort.h"
00067 #include "inline.h"
00068
00069 #ifdef ENABLE_POSTGRESQL
00070 #include <libpq-fe.h>
00071 #endif
00072 #ifdef ENABLE_MYSQL
00073 #if defined(_WIN32) || defined(_WIN64)
00074 #include <windows.h>
00075 #endif
00076 #include <mysql.h>
00077 #endif
00078 #ifdef ENABLE_ODBC
00079 #include <sql.h>
00080 #include <sqlext.h>
00081 #include <sqltypes.h>
00082
00083
00084
00085
00086
00087
00088 typedef SQLRETURN ODBC_SQLRETURN;
00089 typedef SQLCHAR ODBC_SQLCHAR;
00090 #endif
00091 #ifdef ENABLE_ORACLE
00092 #include <oci.h>
00093 #endif
00094 #ifdef ENABLE_MSSQL
00095 #define DBNTWIN32
00096 #include <windows.h>
00097 #include <sqlfront.h>
00098 #include <sqldb.h>
00099 #endif
00100
00101
00102
00103
00104 enum db_types_en
00105 {
00106 DB_UNDEFINED = 0,
00107 DB_MYSQL = 1,
00108 DB_POSTGRESQL = 2,
00109 DB_MSSQL = 3,
00110 DB_ORACLE = 4,
00111 DB_ODBC = 5
00112 };
00113 typedef enum db_types_en dbtype_t;
00114
00115
00116 typedef struct _SQLQuery
00117 {
00118 char * val;
00119 struct _SQLQuery * next;
00120 } SQLQuery;
00121
00122
00123
00124
00125 typedef struct _SharedDatabaseData
00126 {
00127 dbtype_t dbtype_id;
00128 char *dbname;
00129 char *host;
00130 int sid;
00131 int cid;
00132 int reference;
00133 } SharedDatabaseData;
00134
00135 typedef struct _DatabaseData
00136 {
00137 SharedDatabaseData *shared;
00138 char *facility;
00139 char *password;
00140 char *user;
00141 char *port;
00142 char *sensor_name;
00143 int encoding;
00144 int detail;
00145 int ignore_bpf;
00146 int tz;
00147 int DBschema_version;
00148 #ifdef ENABLE_POSTGRESQL
00149 PGconn * p_connection;
00150 PGresult * p_result;
00151 #endif
00152 #ifdef ENABLE_MYSQL
00153 MYSQL * m_sock;
00154 MYSQL_RES * m_result;
00155 MYSQL_ROW m_row;
00156 #endif
00157 #ifdef ENABLE_ODBC
00158 SQLHENV u_handle;
00159 SQLHDBC u_connection;
00160 SQLHSTMT u_statement;
00161 SQLINTEGER u_col;
00162 SQLINTEGER u_rows;
00163 dbtype_t u_underlying_dbtype_id;
00164 #endif
00165 #ifdef ENABLE_ORACLE
00166 OCIEnv *o_environment;
00167 OCISvcCtx *o_servicecontext;
00168 OCIError *o_error;
00169 OCIStmt *o_statement;
00170 OCIDefine *o_define;
00171 text o_errormsg[512];
00172 sb4 o_errorcode;
00173 #endif
00174 #ifdef ENABLE_MSSQL
00175 PDBPROCESS ms_dbproc;
00176 PLOGINREC ms_login;
00177 DBINT ms_col;
00178 #endif
00179 } DatabaseData;
00180
00181
00182 typedef struct _SharedDatabaseDataNode
00183 {
00184 SharedDatabaseData *data;
00185 struct _SharedDatabaseDataNode *next;
00186 } SharedDatabaseDataNode;
00187
00188
00189
00190
00191 #define MAX_QUERY_LENGTH 8192
00192 #define KEYWORD_POSTGRESQL "postgresql"
00193 #define KEYWORD_MYSQL "mysql"
00194 #define KEYWORD_ODBC "odbc"
00195 #define KEYWORD_ORACLE "oracle"
00196 #define KEYWORD_MSSQL "mssql"
00197
00198 #define KEYWORD_HOST "host"
00199 #define KEYWORD_PORT "port"
00200 #define KEYWORD_USER "user"
00201 #define KEYWORD_PASSWORD "password"
00202 #define KEYWORD_DBNAME "dbname"
00203 #define KEYWORD_SENSORNAME "sensor_name"
00204 #define KEYWORD_ENCODING "encoding"
00205 #define KEYWORD_ENCODING_HEX "hex"
00206 #define KEYWORD_ENCODING_BASE64 "base64"
00207 #define KEYWORD_ENCODING_ASCII "ascii"
00208 #define KEYWORD_DETAIL "detail"
00209 #define KEYWORD_DETAIL_FULL "full"
00210 #define KEYWORD_DETAIL_FAST "fast"
00211 #define KEYWORD_IGNOREBPF "ignore_bpf"
00212 #define KEYWORD_IGNOREBPF_NO "no"
00213 #define KEYWORD_IGNOREBPF_ZERO "0"
00214 #define KEYWORD_IGNOREBPF_YES "yes"
00215 #define KEYWORD_IGNOREBPF_ONE "1"
00216
00217
00218 #define LATEST_DB_SCHEMA_VERSION 106
00219
00220
00221
00222 void DatabaseInit(u_char *);
00223 DatabaseData *ParseDatabaseArgs(char *);
00224 void Database(Packet *, char *, void *, Event *);
00225 char * snort_escape_string(char *, DatabaseData *);
00226 void SpoDatabaseCleanExitFunction(int, void *);
00227 void SpoDatabaseRestartFunction(int, void *);
00228 void InitDatabase();
00229 int UpdateLastCid(DatabaseData *, int, int);
00230 int GetLastCid(DatabaseData *, int);
00231 int CheckDBVersion(DatabaseData *);
00232 void BeginTransaction(DatabaseData * data);
00233 void CommitTransaction(DatabaseData * data);
00234 void RollbackTransaction(DatabaseData * data);
00235 int Insert(char *, DatabaseData *);
00236 int Select(char *, DatabaseData *);
00237 void Connect(DatabaseData *);
00238 void DatabasePrintUsage();
00239 void FreeSharedDataList();
00240
00241
00242
00243 extern PV pv;
00244 extern OptTreeNode *otn_tmp;
00245
00246 static SharedDatabaseDataNode *sharedDataList = NULL;
00247 static int instances = 0;
00248
00249
00250
00251
00252 #ifdef ENABLE_MSSQL
00253
00254
00255
00256 #define ENABLE_MSSQL_DEBUG
00257
00258 #if defined(DEBUG) || defined(ENABLE_MSSQL_DEBUG)
00259
00260 static char g_CurrentStatement[2048];
00261 #define SAVESTATEMENT(str) strncpy(g_CurrentStatement, str, sizeof(g_CurrentStatement) - 1);
00262 #define CLEARSTATEMENT() bzero((char *) g_CurrentStatement, sizeof(g_CurrentStatement));
00263 #else
00264 #define SAVESTATEMENT(str) NULL;
00265 #define CLEARSTATEMENT() NULL;
00266 #endif
00267
00268
00269
00270
00271 static int mssql_err_handler(PDBPROCESS dbproc, int severity, int dberr,
00272 int oserr, LPCSTR dberrstr, LPCSTR oserrstr);
00273 static int mssql_msg_handler(PDBPROCESS dbproc, DBINT msgno, int msgstate,
00274 int severity, LPCSTR msgtext, LPCSTR srvname, LPCSTR procname,
00275 DBUSMALLINT line);
00276 #endif
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 void DatabaseSetup()
00291 {
00292
00293
00294 RegisterOutputPlugin("database", NT_OUTPUT_ALERT, DatabaseInit);
00295
00296 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "database(debug): database plugin is registered...\n"););
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 void DatabaseInit(u_char *args)
00311 {
00312 DatabaseData *data = NULL;
00313 char * select_sensor_id = NULL;
00314 char * select_max_sensor_id = NULL;
00315 char * insert_into_sensor = NULL;
00316 int foundEntry = 0, sensor_cid, event_cid;
00317 SharedDatabaseDataNode *current = NULL;
00318 char * escapedSensorName = NULL;
00319 char * escapedInterfaceName = NULL;
00320
00321
00322
00323 data = ParseDatabaseArgs(args);
00324
00325
00326 if(!data->sensor_name)
00327 {
00328 data->sensor_name = GetUniqueName((char *)PRINT_INTERFACE(pv.interface));
00329 if ( data->sensor_name )
00330 {
00331 if( data->sensor_name[strlen(data->sensor_name)-1] == '\n' )
00332 {
00333 data->sensor_name[strlen(data->sensor_name)-1] = '\0';
00334 }
00335
00336 if( !pv.quiet_flag )
00337 {
00338 printf("database: sensor name = %s\n", data->sensor_name);
00339 }
00340 }
00341 }
00342
00343 data->tz = GetLocalTimezone();
00344
00345
00346 select_sensor_id = (char *)SnortAlloc(MAX_QUERY_LENGTH);
00347 select_max_sensor_id = (char *)SnortAlloc(MAX_QUERY_LENGTH);
00348 insert_into_sensor = (char *)SnortAlloc(MAX_QUERY_LENGTH);
00349
00350 escapedSensorName = snort_escape_string(data->sensor_name, data);
00351 if(pv.interface != NULL)
00352 {
00353 escapedInterfaceName = snort_escape_string(PRINT_INTERFACE(pv.interface), data);
00354 }
00355 else
00356 {
00357 if(InlineMode())
00358 {
00359 escapedInterfaceName = snort_escape_string("inline", data);
00360 }
00361 }
00362 if( data->ignore_bpf == 0 )
00363 {
00364 if(pv.pcap_cmd == NULL)
00365 {
00366 snprintf(insert_into_sensor, MAX_QUERY_LENGTH,
00367 "INSERT INTO sensor (hostname, interface, detail, encoding, last_cid) "
00368 "VALUES ('%s','%s','%u','%u', '0')",
00369 escapedSensorName,
00370 escapedInterfaceName,
00371 data->detail,
00372 data->encoding);
00373 snprintf(select_sensor_id, MAX_QUERY_LENGTH,
00374 "SELECT sid "
00375 " FROM sensor "
00376 " WHERE hostname = '%s' "
00377 " AND interface = '%s' "
00378 " AND detail = '%u' "
00379 " AND encoding = '%u' "
00380 " AND filter IS NULL",
00381 escapedSensorName,
00382 escapedInterfaceName,
00383 data->detail,
00384 data->encoding);
00385 }
00386 else
00387 {
00388 snprintf(insert_into_sensor, MAX_QUERY_LENGTH,
00389 "INSERT INTO sensor (hostname, interface, filter, detail, encoding, last_cid) "
00390 "VALUES ('%s','%s','%s','%u','%u', '0')",
00391 escapedSensorName,
00392 escapedInterfaceName,
00393 pv.pcap_cmd,
00394 data->detail,
00395 data->encoding);
00396 snprintf(select_sensor_id, MAX_QUERY_LENGTH,
00397 "SELECT sid "
00398 " FROM sensor "
00399 " WHERE hostname = '%s' "
00400 " AND interface = '%s' "
00401 " AND filter ='%s' "
00402 " AND detail = '%u' "
00403 " AND encoding = '%u'",
00404 escapedSensorName,
00405 escapedInterfaceName,
00406 pv.pcap_cmd,
00407 data->detail,
00408 data->encoding);
00409 }
00410 }
00411 else
00412 {
00413 if(pv.pcap_cmd == NULL)
00414 {
00415 snprintf(insert_into_sensor, MAX_QUERY_LENGTH,
00416 "INSERT INTO sensor (hostname, interface, detail, encoding) "
00417 "VALUES ('%s','%s','%u','%u')",
00418 escapedSensorName,
00419 escapedInterfaceName,
00420 data->detail,
00421 data->encoding);
00422 snprintf(select_sensor_id, MAX_QUERY_LENGTH,
00423 "SELECT sid "
00424 " FROM sensor "
00425 " WHERE hostname = '%s' "
00426 " AND interface = '%s' "
00427 " AND detail = '%u' "
00428 " AND encoding = '%u'",
00429 escapedSensorName,
00430 escapedInterfaceName,
00431 data->detail,
00432 data->encoding);
00433 }
00434 else
00435 {
00436 snprintf(insert_into_sensor, MAX_QUERY_LENGTH,
00437 "INSERT INTO sensor (hostname, interface, filter, detail, encoding) "
00438 "VALUES ('%s','%s','%s','%u','%u')",
00439 escapedSensorName,
00440 escapedInterfaceName,
00441 pv.pcap_cmd,
00442 data->detail, data->encoding);
00443 snprintf(select_sensor_id, MAX_QUERY_LENGTH,
00444 "SELECT sid "
00445 " FROM sensor "
00446 " WHERE hostname = '%s' "
00447 " AND interface = '%s' "
00448 " AND detail = '%u' "
00449 " AND encoding = '%u'",
00450 escapedSensorName,
00451 escapedInterfaceName,
00452 data->detail,
00453 data->encoding);
00454 }
00455 }
00456
00457 Connect(data);
00458
00459 data->shared->sid = Select(select_sensor_id,data);
00460 if(data->shared->sid == 0)
00461 {
00462 Insert(insert_into_sensor,data);
00463 data->shared->sid = Select(select_sensor_id,data);
00464 if(data->shared->sid == 0)
00465 {
00466 ErrorMessage("database: Problem obtaining SENSOR ID (sid) from %s->sensor\n",
00467 data->shared->dbname);
00468 FatalError("\n"
00469 " When this plugin starts, a SELECT query is run to find the sensor id for the\n"
00470 " currently running sensor. If the sensor id is not found, the plugin will run\n"
00471 " an INSERT query to insert the proper data and generate a new sensor id. Then a\n"
00472 " SELECT query is run to get the newly allocated sensor id. If that fails then\n"
00473 " this error message is generated.\n"
00474 "\n"
00475 " Some possible causes for this error are:\n"
00476 " * the user does not have proper INSERT or SELECT privileges\n"
00477 " * the sensor table does not exist\n"
00478 "\n"
00479 " If you are _absolutely_ certain that you have the proper privileges set and\n"
00480 " that your database structure is built properly please let me know if you\n"
00481 " continue to get this error. You can contact me at (roman@danyliw.com).\n"
00482 "\n");
00483 }
00484 }
00485
00486 if( !pv.quiet_flag )
00487 {
00488 printf("database: sensor id = %u\n", data->shared->sid);
00489 }
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 current = sharedDataList;
00501 while(current != NULL)
00502 {
00503
00504 if((current->data->sid == data->shared->sid) &&
00505 (current->data->dbtype_id == data->shared->dbtype_id) &&
00506
00507 (strcasecmp(current->data->dbname, data->shared->dbname) == 0) &&
00508 (strcasecmp(current->data->host, data->shared->host) == 0))
00509 {
00510 foundEntry = 1;
00511 break;
00512 }
00513 current = current->next;
00514 }
00515
00516 if(foundEntry == 0)
00517 {
00518
00519 SharedDatabaseDataNode *newNode = (SharedDatabaseDataNode *)SnortAlloc(sizeof(SharedDatabaseDataNode));
00520 newNode->data = data->shared;
00521 newNode->next = NULL;
00522 if(sharedDataList == NULL)
00523 {
00524 sharedDataList = newNode;
00525 }
00526 else
00527 {
00528 current = sharedDataList;
00529 while(current->next != NULL)
00530 {
00531 current = current->next;
00532 }
00533 current->next = newNode;
00534 }
00535
00536
00537
00538
00539
00540
00541
00542 sensor_cid = GetLastCid(data, data->shared->sid);
00543
00544 snprintf(select_max_sensor_id, MAX_QUERY_LENGTH,
00545 "SELECT MAX(cid) "
00546 " FROM event "
00547 " WHERE sid = '%u'",
00548 data->shared->sid);
00549 event_cid = Select(select_max_sensor_id, data);
00550
00551 if ( event_cid > sensor_cid )
00552 {
00553 UpdateLastCid(data, data->shared->sid, event_cid);
00554 ErrorMessage("database: inconsistent cid information for sid=%u\n",
00555 data->shared->sid);
00556 ErrorMessage(" Recovering by rolling forward the cid=%u\n",
00557 event_cid);
00558 }
00559
00560 data->shared->cid = event_cid;
00561 ++(data->shared->cid);
00562 }
00563 else
00564 {
00565
00566 free(data->shared);
00567 data->shared = current->data;
00568 }
00569
00570
00571 free(select_sensor_id); select_sensor_id = NULL;
00572 free(select_max_sensor_id); select_max_sensor_id = NULL;
00573 free(insert_into_sensor); insert_into_sensor = NULL;
00574 free(escapedSensorName); escapedSensorName = NULL;
00575 free(escapedInterfaceName); escapedInterfaceName = NULL;
00576
00577
00578 data->DBschema_version = CheckDBVersion(data);
00579 if( !pv.quiet_flag ) printf("database: schema version = %d\n", data->DBschema_version);
00580
00581 if ( data->DBschema_version == 0 )
00582 {
00583 FatalError("database: The underlying database has not been initialized correctly. This\n"
00584 " version of Snort requires version %d of the DB schema. Your DB\n"
00585 " doesn't appear to have any records in the 'schema' table.\n"
00586 " Please re-run the appropriate DB creation script (e.g. create_mysql,\n"
00587 " create_postgresql, create_oracle, create_mssql) located in the\n"
00588 " contrib\\ directory.\n\n"
00589 " See the database documentation for cursory details (doc/README.database).\n"
00590 " and the URL to the most recent database plugin documentation.\n",
00591 LATEST_DB_SCHEMA_VERSION);
00592 }
00593 if ( data->DBschema_version < LATEST_DB_SCHEMA_VERSION )
00594 {
00595 FatalError("database: The underlying database seems to be running an older version of\n"
00596 " the DB schema (current version=%d, required minimum version= %d).\n\n"
00597 " If you have an existing database with events logged by a previous\n"
00598 " version of snort, this database must first be upgraded to the latest\n"
00599 " schema (see the snort-users mailing list archive or DB plugin\n"
00600 " documention for details).\n\n"
00601 " If migrating old data is not desired, merely create a new instance\n"
00602 " of the snort database using the appropriate DB creation script\n"
00603 " (e.g. create_mysql, create_postgresql, create_oracle, create_mssql)\n"
00604 " located in the contrib\\ directory.\n\n"
00605 " See the database documentation for cursory details (doc/README.database).\n"
00606 " and the URL to the most recent database plugin documentation.\n",
00607 data->DBschema_version, LATEST_DB_SCHEMA_VERSION);
00608 }
00609
00610
00611
00612
00613
00614
00615
00616
00617 if(!strncasecmp(data->facility,"log",3))
00618 {
00619 pv.log_plugin_active = 1;
00620 if( !pv.quiet_flag ) printf("database: using the \"log\" facility\n");
00621 AddFuncToOutputList(Database, NT_OUTPUT_LOG, data);
00622 }
00623 else
00624 {
00625 pv.alert_plugin_active = 1;
00626 if( !pv.quiet_flag ) printf("database: using the \"alert\" facility\n");
00627 AddFuncToOutputList(Database, NT_OUTPUT_ALERT, data);
00628 }
00629
00630 AddFuncToCleanExitList(SpoDatabaseCleanExitFunction, data);
00631 AddFuncToRestartList(SpoDatabaseRestartFunction, data);
00632 ++instances;
00633 }
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 DatabaseData *ParseDatabaseArgs(char *args)
00647 {
00648 DatabaseData *data;
00649 char *dbarg;
00650 char *a1;
00651 char *type;
00652 char *facility;
00653
00654 data = (DatabaseData *)SnortAlloc(sizeof(DatabaseData));
00655 data->shared = (SharedDatabaseData *)SnortAlloc(sizeof(SharedDatabaseData));
00656
00657 if(args == NULL)
00658 {
00659 ErrorMessage("database: you must supply arguments for database plugin\n");
00660 DatabasePrintUsage();
00661 FatalError("");
00662 }
00663
00664 data->shared->dbtype_id = DB_UNDEFINED;
00665 data->sensor_name = NULL;
00666 data->facility = NULL;
00667 data->encoding = ENCODING_HEX;
00668 data->detail = DETAIL_FULL;
00669 data->ignore_bpf = 0;
00670
00671 facility = strtok(args, ", ");
00672 if(facility != NULL)
00673 {
00674 if((!strncasecmp(facility,"log",3)) || (!strncasecmp(facility,"alert",5)))
00675 data->facility = facility;
00676 else
00677 {
00678 ErrorMessage("database: The first argument needs to be the logging facility\n");
00679 DatabasePrintUsage();
00680 FatalError("");
00681 }
00682 }
00683 else
00684 {
00685 ErrorMessage("database: Invalid format for first argment\n");
00686 DatabasePrintUsage();
00687 FatalError("");
00688 }
00689
00690 type = strtok(NULL, ", ");
00691
00692 if(type == NULL)
00693 {
00694 ErrorMessage("database: you must enter the database type in configuration file as the second argument\n");
00695 DatabasePrintUsage();
00696 FatalError("");
00697 }
00698
00699
00700 if( !pv.quiet_flag ) printf("database: compiled support for ( ");
00701
00702
00703 #ifdef ENABLE_MYSQL
00704 if( !pv.quiet_flag ) printf("%s ",KEYWORD_MYSQL);
00705 if(!strncasecmp(type,KEYWORD_MYSQL,strlen(KEYWORD_MYSQL)))
00706 data->shared->dbtype_id = DB_MYSQL;
00707 #endif
00708 #ifdef ENABLE_POSTGRESQL
00709 if( !pv.quiet_flag ) printf("%s ",KEYWORD_POSTGRESQL);
00710 if(!strncasecmp(type,KEYWORD_POSTGRESQL,strlen(KEYWORD_POSTGRESQL)))
00711 data->shared->dbtype_id = DB_POSTGRESQL;
00712 #endif
00713 #ifdef ENABLE_ODBC
00714 if( !pv.quiet_flag ) printf("%s ",KEYWORD_ODBC);
00715 if(!strncasecmp(type,KEYWORD_ODBC,strlen(KEYWORD_ODBC)))
00716 data->shared->dbtype_id = DB_ODBC;
00717 #endif
00718 #ifdef ENABLE_ORACLE
00719 if( !pv.quiet_flag ) printf("%s ",KEYWORD_ORACLE);
00720 if(!strncasecmp(type,KEYWORD_ORACLE,strlen(KEYWORD_ORACLE)))
00721 data->shared->dbtype_id = DB_ORACLE;
00722 #endif
00723 #ifdef ENABLE_MSSQL
00724 if( !pv.quiet_flag ) printf("%s ",KEYWORD_MSSQL);
00725 if(!strncasecmp(type,KEYWORD_MSSQL,strlen(KEYWORD_MSSQL)))
00726 data->shared->dbtype_id = DB_MSSQL;
00727 #endif
00728
00729 if( !pv.quiet_flag ) printf(")\n");
00730
00731 if( !pv.quiet_flag ) printf("database: configured to use %s\n", type);
00732
00733 if(data->shared->dbtype_id == 0)
00734 {
00735 if ( !strncasecmp(type, KEYWORD_MYSQL, strlen(KEYWORD_MYSQL)) ||
00736 !strncasecmp(type, KEYWORD_POSTGRESQL, strlen(KEYWORD_POSTGRESQL)) ||
00737 !strncasecmp(type, KEYWORD_ODBC, strlen(KEYWORD_ODBC)) ||
00738 !strncasecmp(type, KEYWORD_MSSQL, strlen(KEYWORD_MSSQL)) ||
00739 !strncasecmp(type, KEYWORD_ORACLE, strlen(KEYWORD_ORACLE)) )
00740 {
00741 ErrorMessage("database: '%s' support is not compiled into this build of snort\n\n", type);
00742 FatalError("If this build of snort was obtained as a binary distribution (e.g., rpm,\n"
00743 "or Windows), then check for alternate builds that contains the necessary\n"
00744 "'%s' support.\n\n"
00745 "If this build of snort was compiled by you, then re-run the\n"
00746 "the ./configure script using the '--with-%s' switch.\n"
00747 "For non-standard installations of a database, the '--with-%s=DIR'\n"
00748 "syntax may need to be used to specify the base directory of the DB install.\n\n"
00749 "See the database documentation for cursory details (doc/README.database).\n"
00750 "and the URL to the most recent database plugin documentation.\n",
00751 type, type, type);
00752 }
00753 else
00754 {
00755 FatalError("database: '%s' is an unknown database type. The supported\n"
00756 " databases include: MySQL (mysql), PostgreSQL (postgresql),\n"
00757 " ODBC (odbc), Oracle (oracle), and Microsoft SQL Server (mssql)\n",
00758 type);
00759 }
00760 }
00761
00762 dbarg = strtok(NULL, " =");
00763 while(dbarg != NULL)
00764 {
00765 a1 = NULL;
00766 a1 = strtok(NULL, ", ");
00767 if(!strncasecmp(dbarg,KEYWORD_HOST,strlen(KEYWORD_HOST)))
00768 {
00769 data->shared->host = a1;
00770 if( !pv.quiet_flag ) printf("database: host = %s\n", data->shared->host);
00771 }
00772 if(!strncasecmp(dbarg,KEYWORD_PORT,strlen(KEYWORD_PORT)))
00773 {
00774 data->port = a1;
00775 if( !pv.quiet_flag ) printf("database: port = %s\n", data->port);
00776 }
00777 if(!strncasecmp(dbarg,KEYWORD_USER,strlen(KEYWORD_USER)))
00778 {
00779 data->user = a1;
00780 if( !pv.quiet_flag ) printf("database: user = %s\n", data->user);
00781 }
00782 if(!strncasecmp(dbarg,KEYWORD_PASSWORD,strlen(KEYWORD_PASSWORD)))
00783 {
00784 if( !pv.quiet_flag ) printf("database: password is set\n");
00785 data->password = a1;
00786 }
00787 if(!strncasecmp(dbarg,KEYWORD_DBNAME,strlen(KEYWORD_DBNAME)))
00788 {
00789 data->shared->dbname = a1;
00790 if( !pv.quiet_flag ) printf("database: database name = %s\n", data->shared->dbname);
00791 }
00792 if(!strncasecmp(dbarg,KEYWORD_SENSORNAME,strlen(KEYWORD_SENSORNAME)))
00793 {
00794 data->sensor_name = a1;
00795 if( !pv.quiet_flag ) printf("database: sensor name = %s\n", data->sensor_name);
00796 }
00797 if(!strncasecmp(dbarg,KEYWORD_ENCODING,strlen(KEYWORD_ENCODING)))
00798 {
00799 if(!strncasecmp(a1, KEYWORD_ENCODING_HEX, strlen(KEYWORD_ENCODING_HEX)))
00800 {
00801 data->encoding = ENCODING_HEX;
00802 }
00803 else if(!strncasecmp(a1, KEYWORD_ENCODING_BASE64, strlen(KEYWORD_ENCODING_BASE64)))
00804 {
00805 data->encoding = ENCODING_BASE64;
00806 }
00807 else if(!strncasecmp(a1, KEYWORD_ENCODING_ASCII, strlen(KEYWORD_ENCODING_ASCII)))
00808 {
00809 data->encoding = ENCODING_ASCII;
00810 }
00811 else
00812 {
00813 FatalError("database: unknown (%s)", a1);
00814 }
00815 if( !pv.quiet_flag ) printf("database: data encoding = %s\n", a1);
00816 }
00817 if(!strncasecmp(dbarg,KEYWORD_DETAIL,strlen(KEYWORD_DETAIL)))
00818 {
00819 if(!strncasecmp(a1, KEYWORD_DETAIL_FULL, strlen(KEYWORD_DETAIL_FULL)))
00820 {
00821 data->detail = DETAIL_FULL;
00822 }
00823 else if(!strncasecmp(a1, KEYWORD_DETAIL_FAST, strlen(KEYWORD_DETAIL_FAST)))
00824 {
00825 data->detail = DETAIL_FAST;
00826 }
00827 else
00828 {
00829 FatalError("database: unknown detail level (%s)", a1);
00830 }
00831 if( !pv.quiet_flag ) printf("database: detail level = %s\n", a1);
00832 }
00833 if(!strncasecmp(dbarg,KEYWORD_IGNOREBPF,strlen(KEYWORD_IGNOREBPF)))
00834 {
00835 if(!strncasecmp(a1, KEYWORD_IGNOREBPF_NO, strlen(KEYWORD_IGNOREBPF_NO)) ||
00836 !strncasecmp(a1, KEYWORD_IGNOREBPF_ZERO, strlen(KEYWORD_IGNOREBPF_ZERO)))
00837 {
00838 data->ignore_bpf = 0;
00839 }
00840 else if(!strncasecmp(a1, KEYWORD_IGNOREBPF_YES, strlen(KEYWORD_IGNOREBPF_YES)) ||
00841 !strncasecmp(a1, KEYWORD_IGNOREBPF_ONE, strlen(KEYWORD_IGNOREBPF_ONE)))
00842 {
00843 data->ignore_bpf = 1;
00844 }
00845 else
00846 {
00847 FatalError("database: unknown ignore_bpf argument (%s)", a1);
00848 }
00849
00850 if( !pv.quiet_flag ) printf("database: ignore_bpf = %s\n", a1);
00851 }
00852 dbarg = strtok(NULL, "=");
00853 }
00854
00855 if(data->shared->dbname == NULL)
00856 {
00857 ErrorMessage("database: must enter database name in configuration file\n\n");
00858 DatabasePrintUsage();
00859 FatalError("");
00860 }
00861
00862 return data;
00863 }
00864
00865 void FreeQueryNode(SQLQuery * node)
00866 {
00867 if(node)
00868 {
00869 FreeQueryNode(node->next);
00870 node->next = NULL;
00871 free(node->val);
00872 node->val = NULL;
00873 free(node);
00874 }
00875 }
00876
00877 SQLQuery * NewQueryNode(SQLQuery * parent, int query_size)
00878 {
00879 SQLQuery * rval;
00880
00881 if(query_size == 0)
00882 {
00883 query_size = MAX_QUERY_LENGTH;
00884 }
00885
00886 if(parent)
00887 {
00888 while(parent->next)
00889 {
00890 parent = parent->next;
00891 }
00892
00893 parent->next = (SQLQuery *)SnortAlloc(sizeof(SQLQuery));
00894 rval = parent->next;
00895 }
00896 else
00897 {
00898 rval = (SQLQuery *)SnortAlloc(sizeof(SQLQuery));
00899 }
00900
00901 rval->val = (char *)SnortAlloc(query_size);
00902 rval->next = NULL;
00903
00904 return rval;
00905 }
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918 void Database(Packet *p, char *msg, void *arg, Event *event)
00919 {
00920 DatabaseData *data = (DatabaseData *)arg;
00921 SQLQuery * query;
00922 SQLQuery * root;
00923 char *timestamp_string
00924 , *insert_fields
00925 , *insert_values
00926 , *sig_name
00927 , *sig_class
00928 , *ref_system_name
00929 , *ref_node_id_string
00930 , *ref_tag
00931 , *packet_data
00932 , *packet_data_not_escaped;
00933 int i
00934 , insert_fields_len
00935 , insert_values_len
00936 , ok_transaction;
00937 char *select0 = NULL,
00938 *select1 = NULL,
00939 *insert0 = NULL;
00940 unsigned int sig_id;
00941 int ref_system_id;
00942 unsigned int ref_id, class_id=0;
00943 ClassType *class_ptr;
00944 ReferenceNode *refNode;
00945
00946 query = NewQueryNode(NULL, 0);
00947 root = query;
00948
00949 #ifdef ENABLE_DB_TRANSACTIONS
00950 BeginTransaction(data);
00951 #endif
00952
00953 if(msg == NULL)
00954 {
00955 msg = "";
00956 }
00957
00958
00959
00960
00961 if(p != NULL)
00962 {
00963 timestamp_string = GetTimestamp((struct timeval *) &p->pkth->ts, data->tz);
00964 }
00965 else
00966 {
00967 timestamp_string = GetCurrentTimestamp();
00968 }
00969
00970 #ifdef ENABLE_MSSQL
00971 if(data->shared->dbtype_id == DB_MSSQL)
00972 {
00973
00974
00975
00976
00977
00978
00979
00980
00981 if( timestamp_string!=NULL && strlen(timestamp_string)>20 )
00982 {
00983 timestamp_string[19] = '.';
00984 }
00985 if( timestamp_string!=NULL && strlen(timestamp_string)>24 )
00986 {
00987 timestamp_string[23] = '\0';
00988 }
00989 }
00990 #endif
00991 #ifdef ENABLE_ORACLE
00992 if (data->shared->dbtype_id == DB_ORACLE)
00993 {
00994
00995
00996
00997
00998
00999
01000
01001
01002 if ( timestamp_string!=NULL && strlen(timestamp_string)>20 )
01003 {
01004 timestamp_string[19] = '\0';
01005 }
01006 }
01007 #endif
01008 #ifdef ENABLE_ODBC
01009 if (data->shared->dbtype_id == DB_ODBC)
01010 {
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 if( timestamp_string!=NULL && strlen(timestamp_string)>20 )
01031 {
01032 timestamp_string[19] = '\0';
01033 }
01034 }
01035 #endif
01036 #ifdef ENABLE_POSTGRESQL
01037 if( data->shared->dbtype_id == DB_POSTGRESQL ){
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048 if( timestamp_string!=NULL && strlen(timestamp_string)>24 )
01049 {
01050 timestamp_string[23] = '\0';
01051 }
01052 }
01053 #endif
01054
01055
01056
01057
01058 select0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01059 sig_name = snort_escape_string(msg, data);
01060 if ( event->sig_rev == 0 )
01061 {
01062 if( event->sig_id == 0)
01063 {
01064 snprintf(select0, MAX_QUERY_LENGTH,
01065 "SELECT sig_id "
01066 " FROM signature "
01067 " WHERE sig_name = '%s' "
01068 " AND sig_rev IS NULL "
01069 " AND sig_sid IS NULL ",
01070 sig_name);
01071 }
01072 else
01073 {
01074 snprintf(select0, MAX_QUERY_LENGTH,
01075 "SELECT sig_id "
01076 " FROM signature "
01077 " WHERE sig_name = '%s' "
01078 " AND sig_rev IS NULL "
01079 " AND sig_sid = %u ",
01080 sig_name,
01081 event->sig_id);
01082 }
01083 }
01084 else
01085 {
01086 if( event->sig_id == 0)
01087 {
01088 snprintf(select0, MAX_QUERY_LENGTH,
01089 "SELECT sig_id "
01090 " FROM signature "
01091 " WHERE sig_name = '%s' "
01092 " AND sig_rev = %u "
01093 " AND sig_sid IS NULL ",
01094 sig_name,
01095 event->sig_rev);
01096 }
01097 else
01098 {
01099 snprintf(select0, MAX_QUERY_LENGTH,
01100 "SELECT sig_id "
01101 " FROM signature "
01102 " WHERE sig_name = '%s' "
01103 " AND sig_rev = %u "
01104 " AND sig_sid = %u ",
01105 sig_name,
01106 event->sig_rev,
01107 event->sig_id);
01108 }
01109 }
01110
01111 sig_id = Select(select0, data);
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124 if(sig_id == 0)
01125 {
01126
01127 if(otn_tmp)
01128 {
01129 class_ptr = otn_tmp->sigInfo.classType;
01130
01131 if(class_ptr)
01132 {
01133
01134 if(class_ptr->type)
01135 {
01136
01137 select1 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01138 sig_class = snort_escape_string(class_ptr->type, data);
01139
01140 snprintf(select1, MAX_QUERY_LENGTH,
01141 "SELECT sig_class_id "
01142 " FROM sig_class "
01143 " WHERE sig_class_name = '%s'",
01144 sig_class);
01145 class_id = Select(select1, data);
01146
01147 if ( !class_id )
01148 {
01149 insert0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01150 snprintf(insert0, MAX_QUERY_LENGTH,
01151 "INSERT INTO "
01152 "sig_class (sig_class_name) "
01153 "VALUES ('%s')",
01154 sig_class);
01155 Insert(insert0, data);
01156 free(insert0); insert0 = NULL;
01157 class_id = Select(select1, data);
01158 if ( !class_id )
01159 {
01160 ErrorMessage("database: unable to write classification\n");
01161 }
01162 }
01163 free(select1); select1 = NULL;
01164 free(sig_class); sig_class = NULL;
01165 }
01166 }
01167 }
01168
01169 insert0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01170 insert_fields = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01171 insert_values = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01172 insert_fields_len = 0;
01173 insert_values_len = 0;
01174
01175 snprintf(insert_fields, MAX_QUERY_LENGTH-insert_fields_len, "%s", "sig_name");
01176 snprintf(insert_values, MAX_QUERY_LENGTH-insert_values_len, "'%s'", sig_name);
01177 insert_fields_len = strlen(insert_fields);
01178 insert_values_len = strlen(insert_values);
01179
01180 if ( class_id > 0 )
01181 {
01182 snprintf(&insert_fields[insert_fields_len], MAX_QUERY_LENGTH-insert_fields_len, "%s", ",sig_class_id");
01183 snprintf(&insert_values[insert_values_len], MAX_QUERY_LENGTH-insert_values_len, ",%u", class_id);
01184 insert_fields_len = strlen(insert_fields);
01185 insert_values_len = strlen(insert_values);
01186 }
01187
01188 if ( event->priority > 0 )
01189 {
01190 snprintf(&insert_fields[insert_fields_len], MAX_QUERY_LENGTH-insert_fields_len, "%s", ",sig_priority");
01191 snprintf(&insert_values[insert_values_len], MAX_QUERY_LENGTH-insert_values_len, ",%u", event->priority);
01192 insert_fields_len = strlen(insert_fields);
01193 insert_values_len = strlen(insert_values);
01194 }
01195
01196 if ( event->sig_rev > 0 )
01197 {
01198 snprintf(&insert_fields[insert_fields_len], MAX_QUERY_LENGTH-insert_fields_len, "%s", ",sig_rev");
01199 snprintf(&insert_values[insert_values_len], MAX_QUERY_LENGTH-insert_values_len, ",%u", event->sig_rev);
01200 insert_fields_len = strlen(insert_fields);
01201 insert_values_len = strlen(insert_values);
01202 }
01203
01204 if ( event->sig_id > 0 )
01205 {
01206 snprintf(&insert_fields[insert_fields_len], MAX_QUERY_LENGTH-insert_fields_len, "%s", ",sig_sid");
01207 snprintf(&insert_values[insert_values_len], MAX_QUERY_LENGTH-insert_values_len, ",%u", event->sig_id);
01208 insert_fields_len = strlen(insert_fields);
01209 insert_values_len = strlen(insert_values);
01210 }
01211
01212 snprintf(insert0, MAX_QUERY_LENGTH,
01213 "INSERT INTO signature (%s) VALUES (%s)",
01214 insert_fields, insert_values);
01215
01216 Insert(insert0,data);
01217
01218 free(insert0); insert0 = NULL;
01219 free(insert_fields); insert_fields = NULL;
01220 free(insert_values); insert_values = NULL;
01221
01222 sig_id = Select(select0,data);
01223 if(sig_id == 0)
01224 {
01225 ErrorMessage("database: Problem inserting a new signature '%s'\n", msg);
01226 }
01227 free(select0); select0 = NULL;
01228
01229
01230 if(otn_tmp)
01231 {
01232 refNode = otn_tmp->sigInfo.refs;
01233 i = 1;
01234
01235 while(refNode)
01236 {
01237
01238 select0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01239 insert0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01240 ref_system_name = snort_escape_string(refNode->system->name, data);
01241
01242
01243
01244
01245 snprintf(select0, MAX_QUERY_LENGTH,
01246 "SELECT ref_system_id "
01247 " FROM reference_system "
01248 " WHERE ref_system_name = '%s'",
01249 ref_system_name);
01250 snprintf(insert0, MAX_QUERY_LENGTH,
01251 "INSERT INTO "
01252 "reference_system (ref_system_name) "
01253 "VALUES ('%s')",
01254 ref_system_name);
01255 ref_system_id = Select(select0, data);
01256 if ( ref_system_id == 0 )
01257 {
01258 Insert(insert0, data);
01259 ref_system_id = Select(select0, data);
01260 }
01261
01262 free(select0); select0 = NULL;
01263 free(insert0); insert0 = NULL;
01264 free(ref_system_name); ref_system_name = NULL;
01265
01266 if ( ref_system_id > 0 )
01267 {
01268 select0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01269 ref_tag = snort_escape_string(refNode->id, data);
01270 snprintf(select0, MAX_QUERY_LENGTH,
01271 "SELECT ref_id "
01272 " FROM reference "
01273 " WHERE ref_system_id = %d "
01274 " AND ref_tag = '%s'",
01275 ref_system_id, ref_tag);
01276 ref_id = Select(select0, data);
01277 free(ref_tag); ref_tag = NULL;
01278
01279
01280 if ( ref_id == 0 )
01281 {
01282
01283 ref_node_id_string = (char *) SnortAlloc(101);
01284 if ( data->DBschema_version == 103 )
01285 {
01286 snprintf(ref_node_id_string, 20, "%s", refNode->id);
01287 }
01288 else if ( data->DBschema_version >= 104 )
01289 {
01290 snprintf(ref_node_id_string, 100, "%s", refNode->id);
01291 }
01292
01293 insert0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01294 ref_tag = snort_escape_string(ref_node_id_string, data);
01295 snprintf(insert0, MAX_QUERY_LENGTH,
01296 "INSERT INTO "
01297 "reference (ref_system_id, ref_tag) "
01298 "VALUES (%d, '%s')",
01299 ref_system_id, ref_tag);
01300 Insert(insert0, data);
01301 ref_id = Select(select0, data);
01302 free(insert0); insert0 = NULL;
01303 free(ref_node_id_string); ref_node_id_string = NULL;
01304 free(ref_tag); ref_tag = NULL;
01305
01306 if ( ref_id == 0 )
01307 {
01308 ErrorMessage("database: Unable to insert the alert reference into the DB\n");
01309 }
01310 }
01311 free(select0); select0 = NULL;
01312
01313 insert0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01314 snprintf(insert0, MAX_QUERY_LENGTH,
01315 "INSERT INTO "
01316 "sig_reference (sig_id, ref_seq, ref_id) "
01317 "VALUES (%u, %d, %u)",
01318 sig_id, i, ref_id);
01319 Insert(insert0, data);
01320 free(insert0); insert0 = NULL;
01321 ++i;
01322 }
01323 else
01324 {
01325 ErrorMessage("database: Unable to insert unknown reference tag ('%s') used in rule.\n", refNode->id);
01326 }
01327
01328 refNode = refNode->next;
01329 }
01330 }
01331 }
01332 else
01333 {
01334 free(select0); select0 = NULL;
01335 }
01336
01337 free(sig_name); sig_name = NULL;
01338
01339 if ( (data->shared->dbtype_id == DB_ORACLE) &&
01340 (data->DBschema_version >= 105) )
01341 {
01342 snprintf(query->val, MAX_QUERY_LENGTH,
01343 "INSERT INTO "
01344 "event (sid,cid,signature,timestamp) "
01345 "VALUES ('%u', '%u', '%u', TO_DATE('%s', 'YYYY-MM-DD HH24:MI:SS'))",
01346 data->shared->sid, data->shared->cid, sig_id, timestamp_string);
01347 }
01348 else if(data->shared->dbtype_id == DB_ODBC)
01349 {
01350 snprintf(query->val, MAX_QUERY_LENGTH,
01351 "INSERT INTO "
01352 "event (sid,cid,signature,timestamp) "
01353 "VALUES ('%u', '%u', '%u', {ts '%s'})",
01354 data->shared->sid, data->shared->cid, sig_id, timestamp_string);
01355 }
01356 else
01357 {
01358 snprintf(query->val, MAX_QUERY_LENGTH,
01359 "INSERT INTO "
01360 "event (sid,cid,signature,timestamp) "
01361 "VALUES ('%u', '%u', '%u', '%s')",
01362 data->shared->sid, data->shared->cid, sig_id, timestamp_string);
01363 }
01364
01365 free(timestamp_string); timestamp_string = NULL;
01366
01367
01368
01369
01370 if(p != NULL)
01371 {
01372 if((!p->frag_flag) && (p->iph))
01373 {
01374
01375 if(p->iph->ip_proto == IPPROTO_ICMP && p->icmph)
01376 {
01377 query = NewQueryNode(query, 0);
01378
01379 if(data->detail)
01380 {
01381 if(p->icmph)
01382 {
01383 snprintf(query->val, MAX_QUERY_LENGTH,
01384 "INSERT INTO "
01385 "icmphdr (sid, cid, icmp_type, icmp_code, icmp_csum, icmp_id, icmp_seq) "
01386 "VALUES ('%u','%u','%u','%u','%u','%u','%u')",
01387 data->shared->sid,
01388 data->shared->cid,
01389 p->icmph->type,
01390 p->icmph->code,
01391 ntohs(p->icmph->csum),
01392 ntohs(p->icmph->s_icmp_id),
01393 ntohs(p->icmph->s_icmp_seq));
01394 }
01395 else
01396 {
01397 snprintf(query->val, MAX_QUERY_LENGTH,
01398 "INSERT INTO "
01399 "icmphdr (sid, cid, icmp_type, icmp_code, icmp_csum) "
01400 "VALUES ('%u','%u','%u','%u','%u')",
01401 data->shared->sid,
01402 data->shared->cid,
01403 p->icmph->type,
01404 p->icmph->code,
01405 ntohs(p->icmph->csum));
01406 }
01407 }
01408 else
01409 {
01410 snprintf(query->val, MAX_QUERY_LENGTH,
01411 "INSERT INTO "
01412 "icmphdr (sid, cid, icmp_type, icmp_code) "
01413 "VALUES ('%u','%u','%u','%u')",
01414 data->shared->sid,
01415 data->shared->cid,
01416 p->icmph->type,
01417 p->icmph->code);
01418 }
01419 }
01420 else if(p->iph->ip_proto == IPPROTO_TCP && p->tcph)
01421 {
01422 query = NewQueryNode(query, 0);
01423
01424 if(data->detail)
01425 {
01426 snprintf(query->val, MAX_QUERY_LENGTH,
01427 "INSERT INTO "
01428 "tcphdr (sid, cid, tcp_sport, tcp_dport, "
01429 " tcp_seq, tcp_ack, tcp_off, tcp_res, "
01430 " tcp_flags, tcp_win, tcp_csum, tcp_urp) "
01431 "VALUES ('%u','%u','%u','%u','%lu','%lu','%u','%u','%u','%u','%u','%u')",
01432 data->shared->sid,
01433 data->shared->cid,
01434 ntohs(p->tcph->th_sport),
01435 ntohs(p->tcph->th_dport),
01436 (u_long)ntohl(p->tcph->th_seq),
01437 (u_long)ntohl(p->tcph->th_ack),
01438 TCP_OFFSET(p->tcph),
01439 TCP_X2(p->tcph),
01440 p->tcph->th_flags,
01441 ntohs(p->tcph->th_win),
01442 ntohs(p->tcph->th_sum),
01443 ntohs(p->tcph->th_urp));
01444 }
01445 else
01446 {
01447 snprintf(query->val, MAX_QUERY_LENGTH,
01448 "INSERT INTO "
01449 "tcphdr (sid,cid,tcp_sport,tcp_dport,tcp_flags) "
01450 "VALUES ('%u','%u','%u','%u','%u')",
01451 data->shared->sid,
01452 data->shared->cid,
01453 ntohs(p->tcph->th_sport),
01454 ntohs(p->tcph->th_dport),
01455 p->tcph->th_flags);
01456 }
01457
01458
01459 if(data->detail)
01460 {
01461
01462 for(i=0; i < (int)(p->tcp_option_count); i++)
01463 {
01464 query = NewQueryNode(query, 0);
01465 if((data->encoding == ENCODING_HEX) || (data->encoding == ENCODING_ASCII))
01466 {
01467 packet_data = fasthex(p->tcp_options[i].data, p->tcp_options[i].len);
01468 }
01469 else
01470 {
01471 packet_data = base64(p->tcp_options[i].data, p->tcp_options[i].len);
01472 }
01473 snprintf(query->val, MAX_QUERY_LENGTH,
01474 "INSERT INTO "
01475 "opt (sid,cid,optid,opt_proto,opt_code,opt_len,opt_data) "
01476 "VALUES ('%u','%u','%u','%u','%u','%u','%s')",
01477 data->shared->sid,
01478 data->shared->cid,
01479 i,
01480 6,
01481 p->tcp_options[i].code,
01482 p->tcp_options[i].len,
01483 packet_data);
01484 free(packet_data); packet_data = NULL;
01485 }
01486 }
01487 }
01488 else if(p->iph->ip_proto == IPPROTO_UDP && p->udph)
01489 {
01490 query = NewQueryNode(query, 0);
01491
01492 if(data->detail)
01493 {
01494 snprintf(query->val, MAX_QUERY_LENGTH,
01495 "INSERT INTO "
01496 "udphdr (sid, cid, udp_sport, udp_dport, udp_len, udp_csum) "
01497 "VALUES ('%u', '%u', '%u', '%u', '%u', '%u')",
01498 data->shared->sid,
01499 data->shared->cid,
01500 ntohs(p->udph->uh_sport),
01501 ntohs(p->udph->uh_dport),
01502 ntohs(p->udph->uh_len),
01503 ntohs(p->udph->uh_chk));
01504 }
01505 else
01506 {
01507 snprintf(query->val, MAX_QUERY_LENGTH,
01508 "INSERT INTO "
01509 "udphdr (sid, cid, udp_sport, udp_dport) "
01510 "VALUES ('%u', '%u', '%u', '%u')",
01511 data->shared->sid,
01512 data->shared->cid,
01513 ntohs(p->udph->uh_sport),
01514 ntohs(p->udph->uh_dport));
01515 }
01516 }
01517 }
01518
01519
01520 if ( p->iph )
01521 {
01522 query = NewQueryNode(query, 0);
01523
01524 if(data->detail)
01525 {
01526 snprintf(query->val, MAX_QUERY_LENGTH,
01527 "INSERT INTO "
01528 "iphdr (sid, cid, ip_src, ip_dst, ip_ver, ip_hlen, "
01529 " ip_tos, ip_len, ip_id, ip_flags, ip_off,"
01530 " ip_ttl, ip_proto, ip_csum) "
01531 "VALUES ('%u','%u','%lu','%lu','%u','%u','%u','%u','%u','%u','%u','%u','%u','%u')",
01532 data->shared->sid,
01533 data->shared->cid,
01534 (u_long)ntohl(p->iph->ip_src.s_addr),
01535 (u_long)ntohl(p->iph->ip_dst.s_addr),
01536 IP_VER(p->iph),
01537 IP_HLEN(p->iph),
01538 p->iph->ip_tos,
01539 ntohs(p->iph->ip_len),
01540 ntohs(p->iph->ip_id),
01541 p->frag_flag,
01542 ntohs(p->frag_offset),
01543 p->iph->ip_ttl,
01544 p->iph->ip_proto,
01545 ntohs(p->iph->ip_csum));
01546 }
01547 else
01548 {
01549 snprintf(query->val, MAX_QUERY_LENGTH,
01550
01551 "INSERT INTO "
01552 "iphdr (sid, cid, ip_src, ip_dst, ip_proto) "
01553 "VALUES ('%u','%u','%lu','%lu','%u')",
01554 data->shared->sid,
01555 data->shared->cid,
01556 (u_long)ntohl(p->iph->ip_src.s_addr),
01557 (u_long)ntohl(p->iph->ip_dst.s_addr),
01558 p->iph->ip_proto);
01559 }
01560
01561
01562 if(data->detail)
01563 {
01564 for(i=0 ; i < (int)(p->ip_option_count); i++)
01565 {
01566 if(&p->ip_options[i])
01567 {
01568 query = NewQueryNode(query, 0);
01569 if((data->encoding == ENCODING_HEX) || (data->encoding == ENCODING_ASCII))
01570 {
01571 packet_data = fasthex(p->ip_options[i].data, p->ip_options[i].len);
01572 }
01573 else
01574 {
01575 packet_data = base64(p->ip_options[i].data, p->ip_options[i].len);
01576 }
01577
01578 snprintf(query->val, MAX_QUERY_LENGTH,
01579 "INSERT INTO "
01580 "opt (sid,cid,optid,opt_proto,opt_code,opt_len,opt_data) "
01581 "VALUES ('%u','%u','%u','%u','%u','%u','%s')",
01582 data->shared->sid,
01583 data->shared->cid,
01584 i,
01585 0,
01586 p->ip_options[i].code,
01587 p->ip_options[i].len,
01588 packet_data);
01589 free(packet_data); packet_data = NULL;
01590 }
01591 }
01592 }
01593 }
01594
01595
01596 if ( p->data )
01597 {
01598 if(data->detail)
01599 {
01600 if(p->dsize)
01601 {
01602 query = NewQueryNode(query, p->dsize * 2 + MAX_QUERY_LENGTH);
01603 memset(query->val, 0, p->dsize*2 + MAX_QUERY_LENGTH);
01604 if(data->encoding == ENCODING_BASE64)
01605 {
01606 packet_data_not_escaped = base64(p->data, p->dsize);
01607 }
01608 else if(data->encoding == ENCODING_ASCII)
01609 {
01610 packet_data_not_escaped = ascii(p->data, p->dsize);
01611 }
01612 else
01613 {
01614 packet_data_not_escaped = fasthex(p->data, p->dsize);
01615 }
01616
01617 packet_data = snort_escape_string(packet_data_not_escaped, data);
01618
01619 if(data->shared->dbtype_id == DB_ORACLE)
01620 {
01621 snprintf(query->val, (p->dsize * 2) + MAX_QUERY_LENGTH - 3,
01622 "INSERT INTO "
01623 "data (sid,cid,data_payload) "
01624 "VALUES ('%u','%u',utl_raw.cast_to_raw('%s",
01625 data->shared->sid,
01626 data->shared->cid,
01627 packet_data);
01628 strcat(query->val, "'))");
01629 free (packet_data); packet_data = NULL;
01630 free (packet_data_not_escaped); packet_data_not_escaped = NULL;
01631 }
01632 else
01633 {
01634 snprintf(query->val, (p->dsize * 2) + MAX_QUERY_LENGTH - 3,
01635 "INSERT INTO "
01636 "data (sid,cid,data_payload) "
01637 "VALUES ('%u','%u','%s",
01638 data->shared->sid,
01639 data->shared->cid,
01640 packet_data);
01641 strcat(query->val, "')");
01642 free (packet_data); packet_data = NULL;
01643 free (packet_data_not_escaped); packet_data_not_escaped = NULL;
01644 }
01645 }
01646 }
01647 }
01648 }
01649
01650
01651 query = root;
01652 ok_transaction = 1;
01653 while(query)
01654 {
01655 if ( Insert(query->val,data) == 0 )
01656 {
01657 #ifdef ENABLE_DB_TRANSACTIONS
01658 RollbackTransaction(data);
01659 #endif
01660 ok_transaction = 0;
01661 break;
01662 }
01663 else
01664 {
01665 query = query->next;
01666 }
01667 }
01668 FreeQueryNode(root);
01669 root = NULL;
01670
01671
01672 data->shared->cid++;
01673
01674 #ifdef ENABLE_DB_TRANSACTIONS
01675 if ( ok_transaction )
01676 {
01677 CommitTransaction(data);
01678 }
01679 #endif
01680
01681
01682 #ifdef ENABLE_ODBC
01683 if(data->shared->cid == 600)
01684 {
01685 data->shared->cid = 601;
01686 }
01687 #endif
01688 }
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700 char * snort_escape_string(char * from, DatabaseData * data)
01701 {
01702 char * to;
01703 char * to_start;
01704 char * end;
01705 int from_length;
01706
01707 from_length = (int)strlen(from);
01708
01709 to = (char *)SnortAlloc(strlen(from) * 2 + 1);
01710 to_start = to;
01711 #ifdef ENABLE_ORACLE
01712 if (data->shared->dbtype_id == DB_ORACLE)
01713 {
01714 for (end=from+from_length; from != end; from++)
01715 {
01716 switch(*from)
01717 {
01718 case '\'':
01719 *to++= '\'';
01720 *to++= '\'';
01721 break;
01722 case '\032':
01723 *to++= '\\';
01724 *to++= 'Z';
01725 break;
01726 default:
01727 *to++= *from;
01728 }
01729 }
01730 }
01731 else
01732 #endif
01733 #ifdef ENABLE_MSSQL
01734 if (data->shared->dbtype_id == DB_MSSQL)
01735 {
01736 for (end=from+from_length; from != end; from++)
01737 {
01738 switch(*from)
01739 {
01740 case '\'':
01741 *to++= '\'';
01742 *to++= '\'';
01743 break;
01744 default:
01745 *to++= *from;
01746 }
01747 }
01748 }
01749 else
01750 #endif
01751
01752
01753
01754 #if defined(ENABLE_MYSQL) || defined(ENABLE_POSTGRESQL)
01755 if (data->shared->dbtype_id == DB_MYSQL ||
01756 data->shared->dbtype_id == DB_POSTGRESQL)
01757 {
01758 for(end=from+from_length; from != end; from++)
01759 {
01760 switch(*from)
01761 {
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777 case 0:
01778 *to++= '\\';
01779 *to++= '0';
01780 break;
01781 case '\n':
01782 *to++= '\\';
01783 *to++= 'n';
01784 break;
01785 case '\r':
01786 *to++= '\\';
01787 *to++= 'r';
01788 break;
01789 case '\t':
01790 *to++= '\\';
01791 *to++= 't';
01792 break;
01793 case '\\':
01794 *to++= '\\';
01795 *to++= '\\';
01796 break;
01797 case '\'':
01798 *to++= '\\';
01799 *to++= '\'';
01800 break;
01801 case '"':
01802 *to++= '\\';
01803 *to++= '"';
01804 break;
01805 case '\032':
01806 if (data->shared->dbtype_id == DB_MYSQL)
01807 {
01808 *to++= '\\';
01809 *to++= 'Z';
01810 }
01811 else
01812 {
01813 *to++= *from;
01814 }
01815 break;
01816 default:
01817 *to++= *from;
01818 }
01819 }
01820 }
01821 else
01822 #endif
01823 {
01824 for (end=from+from_length; from != end; from++)
01825 {
01826 switch(*from)
01827 {
01828 case '\'':
01829 *to++= '\'';
01830 *to++= '\'';
01831 break;
01832 default:
01833 *to++= *from;
01834 }
01835 }
01836 }
01837 *to=0;
01838 return(char *)to_start;
01839 }
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853 int UpdateLastCid(DatabaseData *data, int sid, int cid)
01854 {
01855 char *insert0;
01856 int ret;
01857
01858 insert0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01859 snprintf(insert0, MAX_QUERY_LENGTH,
01860 "UPDATE sensor "
01861 " SET last_cid = %u "
01862 " WHERE sid = %u",
01863 cid, sid);
01864
01865 ret = Insert(insert0, data);
01866 free(insert0); insert0 = NULL;
01867 return ret;
01868 }
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881 int GetLastCid(DatabaseData *data, int sid)
01882 {
01883 char *select0;
01884 int tmp_cid;
01885
01886 select0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01887 snprintf(select0, MAX_QUERY_LENGTH,
01888 "SELECT last_cid "
01889 " FROM sensor "
01890 " WHERE sid = '%u'", sid);
01891
01892 tmp_cid = Select(select0,data);
01893 free(select0); select0 = NULL;
01894
01895 return tmp_cid;
01896 }
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908 int CheckDBVersion(DatabaseData * data)
01909 {
01910 char *select0;
01911 int schema_version;
01912
01913 select0 = (char *) SnortAlloc(MAX_QUERY_LENGTH+1);
01914
01915 #if defined(ENABLE_MSSQL) || defined(ENABLE_ODBC)
01916 if ( data->shared->dbtype_id == DB_MSSQL ||
01917 (data->shared->dbtype_id==DB_ODBC && data->u_underlying_dbtype_id==DB_MSSQL) )
01918 {
01919
01920
01921
01922 snprintf(select0, MAX_QUERY_LENGTH,
01923 "SELECT vseq "
01924 " FROM [schema]");
01925 }
01926 else
01927 #endif
01928 {
01929 #if defined(ENABLE_MYSQL)
01930 if (data->shared->dbtype_id == DB_MYSQL)
01931 {
01932
01933
01934
01935 snprintf(select0, MAX_QUERY_LENGTH,
01936 "SELECT vseq "
01937 "FROM `schema`");
01938 }
01939 else
01940 #endif
01941 {
01942 snprintf(select0, MAX_QUERY_LENGTH,
01943 "SELECT vseq "
01944 "FROM schema");
01945 }
01946 }
01947
01948 schema_version = Select(select0,data);
01949 free(select0); select0 = NULL;
01950
01951 return schema_version;
01952 }
01953
01954
01955
01956
01957
01958
01959
01960 void BeginTransaction(DatabaseData * data)
01961 {
01962 #ifdef ENABLE_ODBC
01963 if ( data->shared->dbtype_id == DB_ODBC )
01964 {
01965
01966 }
01967 else
01968 #endif
01969 #ifdef ENABLE_MSSQL
01970 if ( data->shared->dbtype_id == DB_MSSQL )
01971 {
01972 Insert("BEGIN TRANSACTION", data);
01973 }
01974 else
01975 #endif
01976 #ifdef ENABLE_ORACLE
01977 if ( data->shared->dbtype_id == DB_ORACLE )
01978 {
01979
01980 }
01981 else
01982 #endif
01983 {
01984 Insert("BEGIN", data);
01985 }
01986 }
01987
01988
01989
01990
01991
01992
01993
01994 void CommitTransaction(DatabaseData * data)
01995 {
01996 #ifdef ENABLE_ODBC
01997 if ( data->shared->dbtype_id == DB_ODBC )
01998 {
01999 if( SQLEndTran(SQL_HANDLE_DBC, data->u_connection, SQL_COMMIT) != SQL_SUCCESS )
02000 {
02001 ODBC_SQLRETURN ret;
02002 ODBC_SQLCHAR sqlState[6];
02003 ODBC_SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH];
02004 SQLINTEGER nativeError;
02005 SQLSMALLINT errorIndex = 1;
02006 SQLSMALLINT msgLen;
02007
02008 while ((ret = SQLGetDiagRec( SQL_HANDLE_DBC
02009 , data->u_connection
02010 , errorIndex
02011 , sqlState
02012 , &nativeError
02013 , msg
02014 , SQL_MAX_MESSAGE_LENGTH
02015 , &msgLen)) != SQL_NO_DATA)
02016 {
02017 DEBUG_WRAP(LogMessage("database commit: %s\n", msg););
02018 errorIndex++;
02019 }
02020 }
02021 }
02022 else
02023 #endif
02024 #ifdef ENABLE_MSSQL
02025 if ( data->shared->dbtype_id == DB_MSSQL )
02026 {
02027 Insert("COMMIT TRANSACTION", data);
02028 }
02029 else
02030 #endif
02031 #ifdef ENABLE_ORACLE
02032 if ( data->shared->dbtype_id == DB_ORACLE )
02033 {
02034 Insert("COMMIT WORK", data);
02035 }
02036 else
02037 #endif
02038 {
02039 Insert("COMMIT", data);
02040 }
02041 }
02042
02043
02044
02045
02046
02047
02048
02049 void RollbackTransaction(DatabaseData * data)
02050 {
02051 #ifdef ENABLE_ODBC
02052 if ( data->shared->dbtype_id == DB_ODBC )
02053 {
02054 if( SQLEndTran(SQL_HANDLE_DBC, data->u_connection, SQL_ROLLBACK) != SQL_SUCCESS )
02055 {
02056 ODBC_SQLRETURN ret;
02057 ODBC_SQLCHAR sqlState[6];
02058 ODBC_SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH];
02059 SQLINTEGER nativeError;
02060 SQLSMALLINT errorIndex = 1;
02061 SQLSMALLINT msgLen;
02062
02063 while ((ret = SQLGetDiagRec( SQL_HANDLE_DBC
02064 , data->u_connection
02065 , errorIndex
02066 , sqlState
02067 , &nativeError
02068 , msg
02069 , SQL_MAX_MESSAGE_LENGTH
02070 , &msgLen)) != SQL_NO_DATA)
02071 {
02072 DEBUG_WRAP(LogMessage("database rollback: %s\n", msg););
02073 errorIndex++;
02074 }
02075 }
02076 }
02077 else
02078 #endif
02079 #ifdef ENABLE_MSSQL
02080 if ( data->shared->dbtype_id == DB_MSSQL )
02081 {
02082 Insert("ROLLBACK TRANSACTION", data);
02083 }
02084 else
02085 #endif
02086 #ifdef ENABLE_ORACLE
02087 if ( data->shared->dbtype_id == DB_ORACLE )
02088 {
02089 Insert("ROLLBACK WORK", data);
02090 }
02091 else
02092 #endif
02093 {
02094 Insert("ROLLBACK", data);
02095 }
02096 }
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108 int Insert(char * query, DatabaseData * data)
02109 {
02110 int result = 0;
02111
02112 #ifdef ENABLE_POSTGRESQL
02113 if( data->shared->dbtype_id == DB_POSTGRESQL )
02114 {
02115 data->p_result = PQexec(data->p_connection,query);
02116 if(!(PQresultStatus(data->p_result) != PGRES_COMMAND_OK))
02117 {
02118 result = 1;
02119 }
02120 else
02121 {
02122 if(PQerrorMessage(data->p_connection)[0] != '\0')
02123 {
02124 ErrorMessage("database: postgresql_error: %s\n",
02125 PQerrorMessage(data->p_connection));
02126 }
02127 }
02128 PQclear(data->p_result);
02129 }
02130 #endif
02131
02132 #ifdef ENABLE_MYSQL
02133 if(data->shared->dbtype_id == DB_MYSQL)
02134 {
02135 if(!(mysql_query(data->m_sock,query)))
02136 {
02137 result = 1;
02138 }
02139 else
02140 {
02141 if(mysql_errno(data->m_sock))
02142 {
02143 ErrorMessage("database: mysql_error: %s\nSQL=%s\n",
02144 mysql_error(data->m_sock), query);
02145 }
02146 }
02147 }
02148 #endif
02149
02150 #ifdef ENABLE_ODBC
02151 if(data->shared->dbtype_id == DB_ODBC)
02152 {
02153 if(SQLAllocStmt(data->u_connection, &data->u_statement) == SQL_SUCCESS)
02154 if(SQLPrepare(data->u_statement, query, SQL_NTS) == SQL_SUCCESS)
02155 if(SQLExecute(data->u_statement) == SQL_SUCCESS)
02156 {
02157 result = 1;
02158 }
02159 else
02160 {
02161 ODBC_SQLRETURN ret;
02162 ODBC_SQLCHAR sqlState[6];
02163 ODBC_SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH];
02164 SQLINTEGER nativeError;
02165 SQLSMALLINT errorIndex = 1;
02166 SQLSMALLINT msgLen;
02167
02168
02169 while ((ret = SQLGetDiagRec( SQL_HANDLE_STMT
02170 , data->u_statement
02171 , errorIndex
02172 , sqlState
02173 , &nativeError
02174 , msg
02175 , SQL_MAX_MESSAGE_LENGTH
02176 , &msgLen)) != SQL_NO_DATA)
02177 {
02178 DEBUG_WRAP(LogMessage("database: %s\n", msg););
02179 errorIndex++;
02180 }
02181 }
02182 }
02183 #endif
02184
02185 #ifdef ENABLE_ORACLE
02186 if(data->shared->dbtype_id == DB_ORACLE)
02187 {
02188 if(OCI_SUCCESS == OCIStmtPrepare(data->o_statement
02189 , data->o_error
02190 , query
02191 , strlen(query)
02192 , OCI_NTV_SYNTAX
02193 , OCI_DEFAULT))
02194 {
02195 if(OCI_SUCCESS == OCIStmtExecute(data->o_servicecontext
02196 , data->o_statement
02197 , data->o_error
02198 , 1
02199 , 0
02200 , NULL
02201 , NULL
02202 , OCI_COMMIT_ON_SUCCESS))
02203 {
02204 result = 1;
02205 }
02206 }
02207
02208 if( result != 1 )
02209 {
02210 OCIErrorGet(data->o_error
02211 , 1
02212 , NULL
02213 , &data->o_errorcode
02214 , data->o_errormsg
02215 , sizeof(data->o_errormsg)
02216 , OCI_HTYPE_ERROR);
02217 ErrorMessage("database: oracle_error: %s\n", data->o_errormsg);
02218 ErrorMessage(" : query: %s\n", query);
02219 }
02220 }
02221 #endif
02222
02223 #ifdef ENABLE_MSSQL
02224 if(data->shared->dbtype_id == DB_MSSQL)
02225 {
02226 SAVESTATEMENT(query);
02227 dbfreebuf(data->ms_dbproc);
02228 if( dbcmd(data->ms_dbproc, query) == SUCCEED )
02229 if( dbsqlexec(data->ms_dbproc) == SUCCEED )
02230 if( dbresults(data->ms_dbproc) == SUCCEED )
02231 {
02232 while (dbnextrow(data->ms_dbproc) != NO_MORE_ROWS)
02233 {
02234 result = (int)data->ms_col;
02235 }
02236 result = 1;
02237 }
02238 CLEARSTATEMENT();
02239 }
02240 #endif
02241
02242 #ifdef DEBUG
02243 if(result)
02244 {
02245 DEBUG_WRAP(DebugMessage(DEBUG_LOG,"database(debug): (%s) executed\n", query););
02246 }
02247 else
02248 {
02249 DEBUG_WRAP(DebugMessage(DEBUG_LOG,"database(debug): (%s) failed\n", query););
02250 }
02251 #endif
02252
02253 return result;
02254 }
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267 int Select(char * query, DatabaseData * data)
02268 {
02269 int result = 0;
02270
02271 #ifdef ENABLE_POSTGRESQL
02272 if( data->shared->dbtype_id == DB_POSTGRESQL )
02273 {
02274 data->p_result = PQexec(data->p_connection,query);
02275 if((PQresultStatus(data->p_result) == PGRES_TUPLES_OK))
02276 {
02277 if(PQntuples(data->p_result))
02278 {
02279 if((PQntuples(data->p_result)) > 1)
02280 {
02281 ErrorMessage("database: warning (%s) returned more than one result\n",
02282 query);
02283 result = 0;
02284 }
02285 else
02286 {
02287 result = atoi(PQgetvalue(data->p_result,0,0));
02288 }
02289 }
02290 }
02291 if(!result)
02292 {
02293 if(PQerrorMessage(data->p_connection)[0] != '\0')
02294 {
02295 ErrorMessage("database: postgresql_error: %s\n",
02296 PQerrorMessage(data->p_connection));
02297 }
02298 }
02299 PQclear(data->p_result);
02300 }
02301 #endif
02302
02303 #ifdef ENABLE_MYSQL
02304 if(data->shared->dbtype_id == DB_MYSQL)
02305 {
02306 if(mysql_query(data->m_sock,query))
02307 {
02308 result = 0;
02309 }
02310 else
02311 {
02312 if(!(data->m_result = mysql_use_result(data->m_sock)))
02313 {
02314 result = 0;
02315 }
02316 else
02317 {
02318 if((data->m_row = mysql_fetch_row(data->m_result)))
02319 {
02320 if(data->m_row[0] != NULL)
02321 {
02322 result = atoi(data->m_row[0]);
02323 }
02324 }
02325 }
02326 mysql_free_result(data->m_result);
02327 }
02328 if(!result)
02329 {
02330 if(mysql_errno(data->m_sock))
02331 {
02332 ErrorMessage("database: mysql_error: %s\n", mysql_error(data->m_sock));
02333 }
02334 }
02335 }
02336 #endif
02337
02338 #ifdef ENABLE_ODBC
02339 if(data->shared->dbtype_id == DB_ODBC)
02340 {
02341 if(SQLAllocStmt(data->u_connection, &data->u_statement) == SQL_SUCCESS)
02342 if(SQLPrepare(data->u_statement, query, SQL_NTS) == SQL_SUCCESS)
02343 if(SQLExecute(data->u_statement) == SQL_SUCCESS)
02344 if(SQLRowCount(data->u_statement, &data->u_rows) == SQL_SUCCESS)
02345 if(data->u_rows)
02346 {
02347 if(data->u_rows > 1)
02348 {
02349 ErrorMessage("database: warning (%s) returned more than one result\n", query);
02350 result = 0;
02351 }
02352 else
02353 {
02354 if(SQLFetch(data->u_statement) == SQL_SUCCESS)
02355 if(SQLGetData(data->u_statement,1,SQL_INTEGER,&data->u_col,
02356 sizeof(data->u_col), NULL) == SQL_SUCCESS)
02357 result = (int)data->u_col;
02358 }
02359 }
02360 }
02361 #endif
02362
02363 #ifdef ENABLE_ORACLE
02364 if(data->shared->dbtype_id == DB_ORACLE)
02365 {
02366 int success = 0;
02367 if(OCI_SUCCESS == OCIStmtPrepare(data->o_statement
02368 , data->o_error
02369 , query
02370 , strlen(query)
02371 , OCI_NTV_SYNTAX
02372 , OCI_DEFAULT))
02373 {
02374 if(OCI_SUCCESS == OCIDefineByPos(data->o_statement
02375 , &data->o_define
02376 , data->o_error
02377 , 1
02378 , &result
02379 , sizeof(result)
02380 , SQLT_INT
02381 , 0
02382 , 0
02383 , 0
02384 , OCI_DEFAULT))
02385 {
02386 sword status;
02387 status = OCIStmtExecute(data->o_servicecontext
02388 , data->o_statement
02389 , data->o_error
02390 , 1
02391 , 0
02392 , NULL
02393 , NULL
02394 , OCI_DEFAULT);
02395 if( status==OCI_SUCCESS || status==OCI_NO_DATA )
02396 {
02397 success = 1;
02398 }
02399 }
02400 }
02401 if( ! success )
02402 {
02403 OCIErrorGet(data->o_error
02404 , 1
02405 , NULL
02406 , &data->o_errorcode
02407 , data->o_errormsg
02408 , sizeof(data->o_errormsg)
02409 , OCI_HTYPE_ERROR);
02410 ErrorMessage("database: oracle_error: %s\n", data->o_errormsg);
02411 ErrorMessage(" : query: %s\n", query);
02412 }
02413 }
02414 #endif
02415
02416 #ifdef ENABLE_MSSQL
02417 if(data->shared->dbtype_id == DB_MSSQL)
02418 {
02419 SAVESTATEMENT(query);
02420 dbfreebuf(data->ms_dbproc);
02421 if( dbcmd(data->ms_dbproc, query) == SUCCEED )
02422 if( dbsqlexec(data->ms_dbproc) == SUCCEED )
02423 if( dbresults(data->ms_dbproc) == SUCCEED )
02424 if( dbbind(data->ms_dbproc, 1, INTBIND, (DBINT) 0, (BYTE *) &data->ms_col) == SUCCEED )
02425 while (dbnextrow(data->ms_dbproc) != NO_MORE_ROWS)
02426 {
02427 result = (int)data->ms_col;
02428 }
02429 CLEARSTATEMENT();
02430 }
02431 #endif
02432
02433 #ifdef DEBUG
02434 if(result)
02435 {
02436 DEBUG_WRAP(DebugMessage(DEBUG_LOG,"database(debug): (%s) returned %u\n", query, result););
02437 }
02438 else
02439 {
02440 DEBUG_WRAP(DebugMessage(DEBUG_LOG,"database(debug): (%s) failed\n", query););
02441 }
02442 #endif
02443
02444 return result;
02445 }
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455 void Connect(DatabaseData * data)
02456 {
02457 #ifdef ENABLE_MYSQL
02458 int x;
02459 #endif
02460
02461 #ifdef ENABLE_POSTGRESQL
02462 if( data->shared->dbtype_id == DB_POSTGRESQL )
02463 {
02464 data->p_connection = PQsetdbLogin(data->shared->host,data->port,NULL,NULL,data->shared->dbname,data->user,data->password);
02465 if(PQstatus(data->p_connection) == CONNECTION_BAD)
02466 {
02467 PQfinish(data->p_connection);
02468 FatalError("database: Connection to database '%s' failed\n", data->shared->dbname);
02469 }
02470 }
02471 #endif
02472
02473 #ifdef ENABLE_MYSQL
02474 if(data->shared->dbtype_id == DB_MYSQL)
02475 {
02476 data->m_sock = mysql_init(NULL);
02477 if(data->m_sock == NULL)
02478 {
02479 FatalError("database: Connection to database '%s' failed\n", data->shared->dbname);
02480 }
02481 if(data->port != NULL)
02482 {
02483 x = atoi(data->port);
02484 }
02485 else
02486 {
02487 x = 0;
02488 }
02489 if(mysql_real_connect(data->m_sock, data->shared->host, data->user, data->password, data->shared->dbname, x, NULL, 0) == 0)
02490 {
02491 if(mysql_errno(data->m_sock))
02492 {
02493 FatalError("database: mysql_error: %s\n", mysql_error(data->m_sock));
02494 }
02495 FatalError("database: Failed to logon to database '%s'\n", data->shared->dbname);
02496 }
02497 }
02498 #endif
02499
02500 #ifdef ENABLE_ODBC
02501 if(data->shared->dbtype_id == DB_ODBC)
02502 {
02503 ODBC_SQLRETURN ret;
02504
02505 data->u_underlying_dbtype_id = DB_UNDEFINED;
02506
02507 if(!(SQLAllocEnv(&data->u_handle) == SQL_SUCCESS))
02508 {
02509 FatalError("database: unable to allocate ODBC environment\n");
02510 }
02511 if(!(SQLAllocConnect(data->u_handle, &data->u_connection) == SQL_SUCCESS))
02512 {
02513 FatalError("database: unable to allocate ODBC connection handle\n");
02514 }
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527 ret = SQLConnect( data->u_connection
02528 , data->shared->dbname
02529 , SQL_NTS
02530 , data->user
02531 , SQL_NTS
02532 , data->password
02533 , SQL_NTS);
02534 if( ret != SQL_SUCCESS )
02535 {
02536 int encounteredFailure = 1;
02537 char odbcError[2000];
02538 odbcError[0] = '\0';
02539
02540 if( ret == SQL_SUCCESS_WITH_INFO )
02541 {
02542 ODBC_SQLCHAR sqlState[6];
02543 ODBC_SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH];
02544 SQLINTEGER nativeError;
02545 SQLSMALLINT errorIndex = 1;
02546 SQLSMALLINT msgLen;
02547
02548
02549 encounteredFailure = 0;
02550
02551 while ((ret = SQLGetDiagRec( SQL_HANDLE_DBC
02552 , data->u_connection
02553 , errorIndex
02554 , sqlState
02555 , &nativeError
02556 , msg
02557 , SQL_MAX_MESSAGE_LENGTH
02558 , &msgLen)) != SQL_NO_DATA)
02559 {
02560 if( strstr(msg, "SQL Server") != NULL )
02561 {
02562 data->u_underlying_dbtype_id = DB_MSSQL;
02563 }
02564
02565 if( nativeError!=5701 && nativeError!=5703 )
02566 {
02567 encounteredFailure = 1;
02568 strncat(odbcError, msg, sizeof(odbcError));
02569 }
02570 errorIndex++;
02571 }
02572 }
02573 if( encounteredFailure )
02574 {
02575 FatalError("database: ODBC unable to connect. %s\n", odbcError);
02576 }
02577 }
02578 }
02579 #endif
02580
02581 #ifdef ENABLE_ORACLE
02582
02583 #define PRINT_ORACLE_ERR(func_name) \
02584 { \
02585 OCIErrorGet(data->o_error, 1, NULL, &data->o_errorcode, \
02586 data->o_errormsg, sizeof(data->o_errormsg), OCI_HTYPE_ERROR); \
02587 ErrorMessage("database: Oracle_error: %s\n", data->o_errormsg); \
02588 FatalError("database: %s : Connection to database '%s' failed\n", \
02589 func_name, data->shared->dbname); \
02590 }
02591
02592 if(data->shared->dbtype_id == DB_ORACLE)
02593 {
02594 if (!getenv("ORACLE_HOME"))
02595 {
02596 ErrorMessage("database : ORACLE_HOME environment variable not set\n");
02597 }
02598
02599 if (!data->user || !data->password || !data->shared->dbname)
02600 {
02601 ErrorMessage("database: user, password and dbname required for Oracle\n");
02602 ErrorMessage("database: dbname must also be in tnsnames.ora\n");
02603 }
02604
02605 if (data->shared->host)
02606 {
02607 ErrorMessage("database: hostname not required for Oracle, use dbname\n");
02608 ErrorMessage("database: dbname must be in tnsnames.ora\n");
02609 }
02610
02611 if (OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL))
02612 PRINT_ORACLE_ERR("OCIInitialize");
02613
02614 if (OCIEnvInit(&data->o_environment, OCI_DEFAULT, 0, NULL))
02615 PRINT_ORACLE_ERR("OCIEnvInit");
02616
02617 if (OCIEnvInit(&data->o_environment, OCI_DEFAULT, 0, NULL))
02618 PRINT_ORACLE_ERR("OCIEnvInit (2)");
02619
02620 if (OCIHandleAlloc(data->o_environment, (dvoid **)&data->o_error, OCI_HTYPE_ERROR, (size_t) 0, NULL))
02621 PRINT_ORACLE_ERR("OCIHandleAlloc");
02622
02623 if (OCILogon(data->o_environment, data->o_error, &data->o_servicecontext,
02624 data->user, strlen(data->user), data->password, strlen(data->password),
02625 data->shared->dbname, strlen(data->shared->dbname)))
02626 {
02627 OCIErrorGet(data->o_error, 1, NULL, &data->o_errorcode, data->o_errormsg, sizeof(data->o_errormsg), OCI_HTYPE_ERROR);
02628 ErrorMessage("database: oracle_error: %s\n", data->o_errormsg);
02629 ErrorMessage("database: Checklist: check database is listed in tnsnames.ora\n");
02630 ErrorMessage("database: check tnsnames.ora readable\n");
02631 ErrorMessage("database: check database accessible with sqlplus\n");
02632 FatalError("database: OCILogon : Connection to database '%s' failed\n", data->shared->dbname);
02633 }
02634
02635 if (OCIHandleAlloc(data->o_environment, (dvoid **)&data->o_statement, OCI_HTYPE_STMT, 0, NULL))
02636 PRINT_ORACLE_ERR("OCIHandleAlloc (2)");
02637 }
02638 #endif
02639
02640 #ifdef ENABLE_MSSQL
02641 if(data->shared->dbtype_id == DB_MSSQL)
02642 {
02643 CLEARSTATEMENT();
02644 dberrhandle(mssql_err_handler);
02645 dbmsghandle(mssql_msg_handler);
02646
02647 if( dbinit() != NULL )
02648 {
02649 data->ms_login = dblogin();
02650 if( data->ms_login == NULL )
02651 {
02652 FatalError("database: Failed to allocate login structure\n");
02653 }
02654
02655 DBSETLUSER (data->ms_login, data->user);
02656 DBSETLPWD (data->ms_login, data->password);
02657 DBSETLAPP (data->ms_login, "snort");
02658
02659 data->ms_dbproc = dbopen(data->ms_login, data->shared->host);
02660 if( data->ms_dbproc == NULL )
02661 {
02662 FatalError("database: Failed to logon to host '%s'\n", data->shared->host);
02663 }
02664 else
02665 {
02666 if( dbuse( data->ms_dbproc, data->shared->dbname ) != SUCCEED )
02667 {
02668 FatalError("database: Unable to change context to database '%s'\n", data->shared->dbname);
02669 }
02670 }
02671 }
02672 else
02673 {
02674 FatalError("database: Connection to database '%s' failed\n", data->shared->dbname);
02675 }
02676 CLEARSTATEMENT();
02677 }
02678 #endif
02679 }
02680
02681
02682
02683
02684
02685
02686
02687 void Disconnect(DatabaseData * data)
02688 {
02689 if( !pv.quiet_flag )
02690 {
02691 printf("database: Closing connection to database \"%s\"\n",
02692 data->shared->dbname);
02693 }
02694
02695 if(data)
02696 {
02697 #ifdef ENABLE_POSTGRESQL
02698 if(data->shared->dbtype_id == DB_POSTGRESQL)
02699 {
02700 if(data->p_connection)
02701 {
02702 PQfinish(data->p_connection);
02703 }
02704 }
02705 #endif
02706
02707 #ifdef ENABLE_MYSQL
02708 if(data->shared->dbtype_id == DB_MYSQL)
02709 {
02710 if(data->m_sock)
02711 {
02712 mysql_close(data->m_sock);
02713 }
02714 }
02715 #endif
02716
02717 #ifdef ENABLE_ODBC
02718 if(data->shared->dbtype_id == DB_ODBC)
02719 {
02720 if(data->u_handle)
02721 {
02722 SQLDisconnect(data->u_connection);
02723 SQLFreeHandle(SQL_HANDLE_ENV, data->u_handle);
02724 }
02725 }
02726 #endif
02727
02728 #ifdef ENABLE_MSSQL
02729 if(data->shared->dbtype_id == DB_MSSQL)
02730 {
02731 CLEARSTATEMENT();
02732 if( data->ms_dbproc != NULL )
02733 {
02734 dbfreelogin(data->ms_login);
02735 data->ms_login = NULL;
02736 dbclose(data->ms_dbproc);
02737 data->ms_dbproc = NULL;
02738 }
02739 }
02740 #endif
02741 }
02742 }
02743
02744 void DatabasePrintUsage()
02745 {
02746 puts("\nUSAGE: database plugin\n");
02747
02748 puts(" output database: [log | alert], [type of database], [parameter list]\n");
02749 puts(" [log | alert] selects whether the plugin will use the alert or");
02750 puts(" log facility.\n");
02751
02752 puts(" For the first argument, you must supply the type of database.");
02753 puts(" The possible values are mysql, postgresql, odbc, oracle and");
02754 puts(" mssql ");
02755
02756 puts(" The parameter list consists of key value pairs. The proper");
02757 puts(" format is a list of key=value pairs each separated a space.\n");
02758
02759 puts(" The only parameter that is absolutely necessary is \"dbname\".");
02760 puts(" All other parameters are optional but may be necessary");
02761 puts(" depending on how you have configured your RDBMS.\n");
02762
02763 puts(" dbname - the name of the database you are connecting to\n");
02764
02765 puts(" host - the host the RDBMS is on\n");
02766
02767 puts(" port - the port number the RDBMS is listening on\n");
02768
02769 puts(" user - connect to the database as this user\n");
02770
02771 puts(" password - the password for given user\n");
02772
02773 puts(" sensor_name - specify your own name for this snort sensor. If you");
02774 puts(" do not specify a name one will be generated automatically\n");
02775
02776 puts(" encoding - specify a data encoding type (hex, base64, or ascii)\n");
02777
02778 puts(" detail - specify a detail level (full or fast)\n");
02779
02780 puts(" ignore_bpf - specify if you want to ignore the BPF part for a sensor\n");
02781 puts(" definition (yes or no, no is default)\n");
02782
02783 puts(" FOR EXAMPLE:");
02784 puts(" The configuration I am currently using is MySQL with the database");
02785 puts(" name of \"snort\". The user \"snortusr@localhost\" has INSERT and SELECT");
02786 puts(" privileges on the \"snort\" database and does not require a password.");
02787 puts(" The following line enables snort to log to this database.\n");
02788
02789 puts(" output database: log, mysql, dbname=snort user=snortusr host=localhost\n");
02790 }
02791
02792 void SpoDatabaseCleanExitFunction(int signal, void *arg)
02793 {
02794 DatabaseData *data = (DatabaseData *)arg;
02795
02796 DEBUG_WRAP(DebugMessage(DEBUG_LOG,"database(debug): entered SpoDatabaseCleanExitFunction\n"););
02797
02798 UpdateLastCid(data, data->shared->sid, data->shared->cid-1);
02799 Disconnect(data);
02800 if(data != NULL)
02801 {
02802 free(data);
02803 data = NULL;
02804 }
02805
02806 if(--instances == 0)
02807 {
02808 FreeSharedDataList();
02809 }
02810 }
02811
02812 void SpoDatabaseRestartFunction(int signal, void *arg)
02813 {
02814 DatabaseData *data = (DatabaseData *)arg;
02815
02816 DEBUG_WRAP(DebugMessage(DEBUG_LOG,"database(debug): entered SpoDatabaseRestartFunction\n"););
02817
02818 UpdateLastCid(data, data->shared->sid, data->shared->cid-1);
02819 Disconnect(data);
02820 if(data != NULL)
02821 {
02822 free(data);
02823 data = NULL;
02824 }
02825
02826 if(--instances == 0)
02827 {
02828 FreeSharedDataList();
02829 }
02830 }
02831
02832 void FreeSharedDataList()
02833 {
02834 SharedDatabaseDataNode *current;
02835
02836 while(sharedDataList != NULL)
02837 {
02838 current = sharedDataList;
02839 free(current->data);
02840 current->data = NULL;
02841 sharedDataList = current->next;
02842 free(current);
02843 current = NULL;
02844 }
02845 }
02846
02847 #ifdef ENABLE_MSSQL
02848
02849
02850
02851
02852
02853
02854 static int mssql_err_handler(PDBPROCESS dbproc, int severity, int dberr, int oserr,
02855 LPCSTR dberrstr, LPCSTR oserrstr)
02856 {
02857 int retval;
02858 ErrorMessage("database: DB-Library error:\n\t%s\n", dberrstr);
02859
02860 if ( severity == EXCOMM && (oserr != DBNOERR || oserrstr) )
02861 ErrorMessage("database: Net-Lib error %d: %s\n", oserr, oserrstr);
02862 if ( oserr != DBNOERR )
02863 ErrorMessage("database: Operating-system error:\n\t%s\n", oserrstr);
02864 #ifdef ENABLE_MSSQL_DEBUG
02865 if( strlen(g_CurrentStatement) > 0 )
02866 ErrorMessage("database: The above error was caused by the following statement:\n%s\n", g_CurrentStatement);
02867 #endif
02868 if ( (dbproc == NULL) || DBDEAD(dbproc) )
02869 retval = INT_EXIT;
02870 else
02871 retval = INT_CANCEL;
02872 return(retval);
02873 }
02874
02875
02876 static int mssql_msg_handler(PDBPROCESS dbproc, DBINT msgno, int msgstate, int severity,
02877 LPCSTR msgtext, LPCSTR srvname, LPCSTR procname, DBUSMALLINT line)
02878 {
02879 ErrorMessage("database: SQL Server message %ld, state %d, severity %d: \n\t%s\n",
02880 msgno, msgstate, severity, msgtext);
02881 if ( (srvname!=NULL) && strlen(srvname)!=0 )
02882 ErrorMessage("Server '%s', ", srvname);
02883 if ( (procname!=NULL) && strlen(procname)!=0 )
02884 ErrorMessage("Procedure '%s', ", procname);
02885 if (line !=0)
02886 ErrorMessage("Line %d", line);
02887 ErrorMessage("\n");
02888 #ifdef ENABLE_MSSQL_DEBUG
02889 if( strlen(g_CurrentStatement) > 0 )
02890 ErrorMessage("database: The above error was caused by the following statement:\n%s\n", g_CurrentStatement);
02891 #endif
02892
02893 return(0);
02894 }
02895 #endif