source: trunk/src/sh_database.c@ 35

Last change on this file since 35 was 35, checked in by rainer, 18 years ago

Fix concurrent inserts with postgres

File size: 47.0 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2001 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <stddef.h>
26#include <string.h>
27#include <ctype.h>
28#include <sys/types.h>
29
30#ifdef WITH_DATABASE
31
32/* define this if you want to debug the Oracle database support */
33/* #define DB_DEBUG */
34
35#define SH_REAL_SET
36
37#include "samhain.h"
38
39#include "sh_cat.h"
40#include "sh_error.h"
41#include "sh_utils.h"
42
43#undef FIL__
44#define FIL__ _("sh_database.c")
45
46typedef struct my_attr_
47{
48 char * attr;
49 char * attr_o;
50 int inHash;
51 int val;
52 int size;
53 int alen;
54 size_t off;
55} my_attr;
56
57typedef struct dbins_ {
58 struct dbins_ * next;
59 char host[64];
60 char time[20];
61 char msg[1024];
62 char sev[8];
63 char path[12288];
64 char user[9];
65 char group[9];
66 char program[8];
67 char subroutine[16];
68 char status[12];
69 char hash[50];
70 char path_data[1024];
71 char hash_data[50];
72 char key_uid[64];
73 char key_uid_data[64];
74 char key_id[16];
75 char module[8];
76 char syscall[16];
77 char ip[16];
78 char tty[16];
79 char peer[64];
80 char fromhost[64];
81 char obj[1024];
82 char interface[64];
83 char ltime[64];
84 char dir[1024];
85 char linked_path[1024];
86 char service[64];
87 char facility[32];
88 char priority[32];
89 char syslog_msg[1024];
90
91 char mode_old[16];
92 char mode_new[16];
93 char attr_old[16];
94 char attr_new[16];
95 char device_old[16];
96 char device_new[16];
97 char owner_old[9];
98 char owner_new[9];
99 char group_old[9];
100 char group_new[9];
101 char ctime_old[20];
102 char ctime_new[20];
103 char atime_old[20];
104 char atime_new[20];
105 char mtime_old[20];
106 char mtime_new[20];
107 char chksum_old[50];
108 char chksum_new[50];
109 char link_old[1024];
110 char link_new[1024];
111
112 long long_data[20];
113
114 /*
115 long size_old;
116 long size_new;
117 long hardlinks_old;
118 long hardlinks_new;
119 long inode_old;
120 long inode_new;
121 */
122
123} dbins;
124
125static my_attr * attr_tab_srch = NULL;
126static int attr_tab_srch_siz = 0;
127
128static my_attr attr_tab[] = {
129 { NULL, N_("sev"), 0, 1, 8, 0, offsetof(struct dbins_, sev) },
130 { NULL, N_("tstamp"), 0, 2, 16, 0, offsetof(struct dbins_, time) },
131 { NULL, N_("remote_host"), 0, 3, 64, 0, offsetof(struct dbins_, host) },
132 { NULL, N_("msg"), 0, 4, 1024, 0, offsetof(struct dbins_, msg) },
133
134 { NULL, N_("path"), 0, 5,12288, 0, offsetof(struct dbins_, path) },
135 /* username -> userid; replace (long) 'userid' - below - by 'dummy' */
136 { NULL, N_("userid"), 0, 6, 9, 0, offsetof(struct dbins_, user) },
137 { NULL, N_("group"), 0, 7, 9, 0, offsetof(struct dbins_, group) },
138 { NULL, N_("program"), 0, 8, 8, 0, offsetof(struct dbins_, program) },
139 { NULL, N_("subroutine"), 0, 9, 16, 0, offsetof(struct dbins_, subroutine)},
140 { NULL, N_("status"), 0, 10, 12, 0, offsetof(struct dbins_, status) },
141 { NULL, N_("hash"), 0, 11, 50, 0, offsetof(struct dbins_, hash) },
142 { NULL, N_("path_data"), 0, 12, 1024, 0, offsetof(struct dbins_, path_data) },
143 { NULL, N_("hash_data"), 0, 13, 50, 0, offsetof(struct dbins_, hash_data) },
144 { NULL, N_("key_uid"), 0, 14, 64, 0, offsetof(struct dbins_, key_uid) },
145 { NULL, N_("key_uid_data"),0, 15, 64, 0, offsetof(struct dbins_, key_uid_data)},
146 { NULL, N_("key_id"), 0, 16, 16, 0, offsetof(struct dbins_, key_id) },
147 { NULL, N_("module"), 0, 17, 8, 0, offsetof(struct dbins_, module) },
148 { NULL, N_("syscall"), 0, 19, 16, 0, offsetof(struct dbins_, syscall) },
149 { NULL, N_("ip"), 0, 20, 16, 0, offsetof(struct dbins_, ip) },
150 { NULL, N_("tty"), 0, 21, 16, 0, offsetof(struct dbins_, tty) },
151 { NULL, N_("peer"), 0, 22, 64, 0, offsetof(struct dbins_, peer) },
152 { NULL, N_("obj"), 0, 23, 1024, 0, offsetof(struct dbins_, obj) },
153 { NULL, N_("interface"), 0, 24, 64, 0, offsetof(struct dbins_, interface)},
154 { NULL, N_("time"), 0, 25, 64, 0, offsetof(struct dbins_, ltime) },
155 { NULL, N_("dir"), 0, 26, 1024, 0, offsetof(struct dbins_, dir) },
156 { NULL, N_("linked_path"), 0, 27, 1024, 0, offsetof(struct dbins_, linked_path)},
157 { NULL, N_("service"), 0, 29, 64, 0, offsetof(struct dbins_, service)},
158 { NULL, N_("facility"), 0, 30, 32, 0, offsetof(struct dbins_, facility) },
159 { NULL, N_("priority"), 0, 31, 32, 0, offsetof(struct dbins_, priority) },
160 { NULL, N_("syslog_msg"), 0, 32, 1024, 0, offsetof(struct dbins_, syslog_msg) },
161
162 { NULL, N_("mode_old"), 0, 33, 16, 0, offsetof(struct dbins_, mode_old) },
163 { NULL, N_("mode_new"), 0, 34, 16, 0, offsetof(struct dbins_, mode_new) },
164 { NULL, N_("device_old"), 0, 35, 16, 0, offsetof(struct dbins_, device_old)},
165 { NULL, N_("device_new"), 0, 36, 16, 0, offsetof(struct dbins_, device_new)},
166 { NULL, N_("owner_old"), 0, 37, 9, 0, offsetof(struct dbins_, owner_old)},
167 { NULL, N_("owner_new"), 0, 38, 9, 0, offsetof(struct dbins_, owner_new)},
168 { NULL, N_("group_old"), 0, 39, 9, 0, offsetof(struct dbins_, group_old)},
169 { NULL, N_("group_new"), 0, 40, 9, 0, offsetof(struct dbins_, group_new)},
170 { NULL, N_("ctime_old"), 0, 41, 20, 0, offsetof(struct dbins_, ctime_old)},
171 { NULL, N_("ctime_new"), 0, 42, 20, 0, offsetof(struct dbins_, ctime_new)},
172 { NULL, N_("atime_old"), 0, 43, 20, 0, offsetof(struct dbins_, atime_old)},
173 { NULL, N_("atime_new"), 0, 44, 20, 0, offsetof(struct dbins_, atime_new)},
174 { NULL, N_("mtime_old"), 0, 45, 20, 0, offsetof(struct dbins_, mtime_old)},
175 { NULL, N_("mtime_new"), 0, 46, 20, 0, offsetof(struct dbins_, mtime_new)},
176 { NULL, N_("chksum_old"), 0, 47, 50, 0, offsetof(struct dbins_, chksum_old)},
177 { NULL, N_("chksum_new"), 0, 48, 50, 0, offsetof(struct dbins_, chksum_new)},
178 { NULL, N_("link_old"), 0, 49, 1024, 0, offsetof(struct dbins_, link_old)},
179 { NULL, N_("link_new"), 0, 50, 1024, 0, offsetof(struct dbins_, link_new)},
180
181 { NULL, N_("size_old"), 0, 51, 0, 0, 0 },
182 { NULL, N_("size_new"), 0, 52, 0, 0, 0 },
183 { NULL, N_("hardlinks_old"),0, 53, 0, 0, 0 },
184 { NULL, N_("hardlinks_new"),0, 54, 0, 0, 0 },
185 { NULL, N_("inode_old"), 0, 55, 0, 0, 0 },
186 { NULL, N_("inode_new"), 0, 56, 0, 0, 0 },
187
188 { NULL, N_("imode_old"), 0, 57, 0, 0, 0 },
189 { NULL, N_("imode_new"), 0, 58, 0, 0, 0 },
190 { NULL, N_("iattr_old"), 0, 59, 0, 0, 0 },
191 { NULL, N_("iattr_new"), 0, 60, 0, 0, 0 },
192 { NULL, N_("idevice_old"), 0, 61, 0, 0, 0 },
193 { NULL, N_("idevice_new"), 0, 62, 0, 0, 0 },
194 { NULL, N_("iowner_old"), 0, 63, 0, 0, 0 },
195 { NULL, N_("iowner_new"), 0, 64, 0, 0, 0 },
196 { NULL, N_("igroup_old"), 0, 65, 0, 0, 0 },
197 { NULL, N_("igroup_new"), 0, 66, 0, 0, 0 },
198
199 { NULL, N_("port"), 0, 67, 0, 0, 0 },
200 { NULL, N_("return_code"), 0, 68, 0, 0, 0 },
201 /* { NULL, N_("userid"), 0, 69, 0, 0 }, old 'userid', 1.8.1 */
202
203 { NULL, N_("host"), 0, 70, 64, 0, offsetof(struct dbins_, fromhost)},
204 { NULL, N_("attr_old"), 0, 71, 16, 0, offsetof(struct dbins_, attr_old)},
205 { NULL, N_("attr_new"), 0, 72, 16, 0, offsetof(struct dbins_, attr_new)},
206
207 { NULL, NULL, 0, 0, 0, 0, 0 }
208};
209
210#define SH_SLOT_HOST 70
211#define SH_SLOT_GROUP 7
212#define START_SEC_LONGS 51
213#define END_SEC_LONGS 68
214
215#if defined(HAVE_INT_32)
216typedef unsigned int uint32;
217#elif defined(HAVE_LONG_32)
218typedef unsigned long uint32;
219#elif defined(HAVE_SHORT_32)
220typedef unsigned short uint32;
221#else
222#error No 32 byte type found !
223#endif
224
225typedef unsigned char uint8;
226
227typedef struct md5_ctx
228{
229 uint32 A;
230 uint32 B;
231 uint32 C;
232 uint32 D;
233
234 uint32 total[2];
235 uint32 buflen;
236 char buffer[128];
237} md5Param;
238
239
240typedef unsigned char sh_byte;
241
242
243extern int md5Reset(register md5Param* p);
244extern int md5Update(md5Param* p, const sh_byte* data, int size);
245extern int md5Digest(md5Param* p, uint32* data);
246
247static char db_name[64] = "";
248static char db_table[64] = "";
249static char db_host[64] = "";
250static char db_user[64] = "";
251static char db_password[64] = "";
252
253static int sh_persistent_dbconn = S_TRUE;
254
255int sh_database_use_persistent (const char * str)
256{
257 return sh_util_flagval (str, &sh_persistent_dbconn);
258}
259
260static int insert_value (char * ptr, const char * str)
261{
262 if (!ptr || !str)
263 return -1;
264 if (strlen(str) > 63)
265 return -1;
266 (void) sl_strlcpy(ptr, str, 64);
267 return 0;
268}
269
270static void init_db_entry (dbins * ptr)
271{
272 memset (ptr, (int) '\0', sizeof(dbins));
273 ptr->next = NULL;
274 return;
275}
276
277
278int sh_database_set_database (const char * str)
279{
280 return insert_value (db_name, str);
281}
282int sh_database_set_table (const char * str)
283{
284 return insert_value (db_table, str);
285}
286int sh_database_set_host (const char * str)
287{
288 return insert_value (db_host, str);
289}
290int sh_database_set_user (const char * str)
291{
292 return insert_value (db_user, str);
293}
294int sh_database_set_password (const char * str)
295{
296 return insert_value (db_password, str);
297}
298
299/******************************************************************
300 *
301 * Oracle and unixODBC stuff, only Oracle tested untested
302 *
303 * Based on the code in the snort output plugin (spo_database.c).
304 * Copyright/license statement in spo_database.c:
305 *
306 * Portions Copyright (C) 2000,2001,2002 Carnegie Mellon University
307 * Copyright (C) 2001 Jed Pickel <jed@pickel.net>
308 * Portions Copyright (C) 2001 Andrew R. Baker <andrewb@farm9.com>
309 *
310 * This program is free software; you can redistribute it and/or modify
311 * it under the terms of the GNU General Public License as published by
312 * the Free Software Foundation; either version 2 of the License, or
313 * (at your option) any later version.
314 *
315 * This program is distributed in the hope that it will be useful,
316 * but WITHOUT ANY WARRANTY; without even the implied warranty of
317 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
318 * GNU General Public License for more details.
319 *
320 * You should have received a copy of the GNU General Public License
321 * along with this program; if not, write to the Free Software
322 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
323 *
324 ******************************************************************/
325#ifdef WITH_ODBC
326
327#include <sql.h>
328#include <sqlext.h>
329#include <sqltypes.h>
330
331static SQLHENV u_handle;
332static SQLHDBC u_connection;
333static SQLHSTMT u_statement;
334static SQLINTEGER u_col;
335static SQLINTEGER u_rows;
336
337void sh_database_reset()
338{
339 return;
340}
341
342static
343int sh_database_query (char * query, /*@out@*/ long * id)
344{
345 static int fatal_error = 0;
346 int result = 0;
347 char row_query[128];
348 long result_call;
349
350 SL_ENTER(_("sh_database_query"));
351
352 *id = 0;
353
354 if (fatal_error == 1)
355 {
356 SL_RETURN((-1), _("sh_database_query"));
357 }
358
359 /* Connect
360 */
361 if (db_name[0] == '\0')
362 sl_strlcpy(db_name, _("samhain"), 64);
363
364 if (db_user[0] == '\0')
365 sl_strlcpy(db_user, _("samhain"), 64);
366
367 result_call = SQLAllocEnv(&u_handle);
368 if ((result_call != SQL_SUCCESS) && (result_call != SQL_SUCCESS_WITH_INFO))
369 {
370 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, result_call,
371 MSG_E_SUBGEN,
372 _("Error in SQLAllocEnv when connecting to ODBC data source"),
373 _("sh_database_query"));
374 fatal_error = 1;
375 SL_RETURN((-1), _("sh_database_query"));
376 }
377 result_call = SQLAllocConnect(u_handle, &u_connection);
378 if ((result_call != SQL_SUCCESS) && (result_call != SQL_SUCCESS_WITH_INFO))
379 {
380 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, result_call,
381 MSG_E_SUBGEN,
382 _("Error in SQLAllocEnv when connecting to ODBC data source"),
383 _("sh_database_query"));
384 fatal_error = 1;
385 SL_RETURN((-1), _("sh_database_query"));
386 }
387 result_call = SQLConnect(u_connection, db_name, SQL_NTS,
388 db_user, SQL_NTS, db_password, SQL_NTS);
389 if ((result_call != SQL_SUCCESS) && (result_call != SQL_SUCCESS_WITH_INFO))
390 {
391 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, result_call,
392 MSG_E_SUBGEN,
393 _("Error in SQLAllocEnv when connecting to ODBC data source"),
394 _("sh_database_query"));
395 fatal_error = 1;
396 SL_RETURN((-1), _("sh_database_query"));
397 }
398
399 /* Insert
400 */
401 result_call = SQLAllocStmt(u_connection, &u_statement);
402 if ((result_call == SQL_SUCCESS) || (result_call == SQL_SUCCESS_WITH_INFO))
403 {
404 result_call = SQLPrepare(u_statement, query, SQL_NTS);
405 if ((result_call == SQL_SUCCESS) ||
406 (result_call == SQL_SUCCESS_WITH_INFO))
407 {
408 result_call = SQLExecute(u_statement);
409 if((result_call == SQL_SUCCESS) ||
410 (result_call == SQL_SUCCESS_WITH_INFO))
411 {
412 result = 1;
413 }
414 }
415 }
416
417 if (result == 0)
418 {
419 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
420 _("Error inserting into ODBC data source"),
421 _("sh_database_query"));
422 goto odbc_disconnect;
423 }
424
425 /* Select
426 */
427 result = 0;
428
429 sl_strlcpy (row_query, _("SELECT MAX(log_index) FROM "), 128);
430 sl_strlcat (row_query, db_table, 128);
431
432 result_call = SQLAllocStmt(u_connection, &u_statement);
433 if ((result_call == SQL_SUCCESS) ||
434 (result_call == SQL_SUCCESS_WITH_INFO))
435 {
436 result_call = SQLPrepare(u_statement, row_query, SQL_NTS);
437 if ((result_call == SQL_SUCCESS) ||
438 (result_call == SQL_SUCCESS_WITH_INFO))
439 {
440 result_call = SQLExecute(u_statement);
441 if ((result_call == SQL_SUCCESS) ||
442 (result_call == SQL_SUCCESS_WITH_INFO))
443 {
444 result_call = SQLRowCount(u_statement, &u_rows);
445 if ((result_call == SQL_SUCCESS) ||
446 (result_call == SQL_SUCCESS_WITH_INFO))
447 {
448 if((u_rows) && (u_rows == 1))
449 {
450 result_call = SQLFetch(u_statement);
451 if ((result_call == SQL_SUCCESS) ||
452 (result_call == SQL_SUCCESS_WITH_INFO))
453 {
454 result_call = SQLGetData(u_statement, 1,
455 SQL_INTEGER, &u_col,
456 sizeof(u_col), NULL);
457 if ((result_call == SQL_SUCCESS) ||
458 (result_call == SQL_SUCCESS_WITH_INFO))
459 {
460 *id = (long int) u_col;
461 result = 1;
462 }
463 }
464 }
465 }
466 }
467 }
468 }
469
470 if (result == 0)
471 {
472 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
473 _("Error selecting MAX(log_index) from ODBC data source"),
474 _("sh_database_query"));
475 }
476
477 odbc_disconnect:
478 SQLFreeHandle(SQL_HANDLE_STMT, u_statement);
479 SQLDisconnect(u_connection);
480 SQLFreeHandle(SQL_HANDLE_DBC, u_connection);
481 SQLFreeHandle(SQL_HANDLE_ENV, u_handle);
482
483 SL_RETURN(((result == 0) ? -1 : 0), _("sh_database_query"));
484
485}
486
487/* #ifdef WITH_ODBC */
488#endif
489
490#ifdef WITH_ORACLE
491
492#include <oci.h>
493
494static OCIDefine * o_define;
495static OCIEnv * o_environment;
496static OCISvcCtx * o_servicecontext;
497static OCIError * o_error = NULL;
498static OCIStmt * o_statement;
499static text o_errormsg[512];
500static sb4 o_errorcode;
501
502static int connected = 0;
503
504void sh_database_reset()
505{
506 if (connected == 1)
507 {
508 OCILogoff(o_servicecontext, o_error);
509 OCIHandleFree((dvoid *) o_statement, OCI_HTYPE_STMT);
510 OCIHandleFree((dvoid *) o_servicecontext, OCI_HTYPE_SVCCTX);
511 OCIHandleFree((dvoid *) o_error, OCI_HTYPE_ERROR);
512 o_error = NULL;
513 }
514 connected = 0;
515 return;
516}
517
518static char * sh_stripnl (char * str)
519{
520 size_t len = sl_strlen(str);
521 if (len > 0)
522 {
523 if (str[len-1] == '\n')
524 str[len-1] == '\0';
525 }
526 return str;
527}
528
529static
530int sh_database_query (char * query, /*@out@*/ long * id)
531{
532 static int bad_init = 0;
533 int result = 0;
534 char row_query[128];
535 int retry = 0;
536
537 SL_ENTER(_("sh_database_query"));
538
539 *id = 0;
540
541 if (bad_init == 1) {
542 SL_RETURN(-1, _("sh_database_query"));
543 }
544 else if (connected == 1) {
545 goto oracle_connected;
546 }
547
548 /*
549 * Connect
550 */
551#define PRINT_ORACLE_ERR(func_name) \
552 do { \
553 OCIErrorGet(o_error, 1, NULL, &o_errorcode, \
554 o_errormsg, sizeof(o_errormsg), \
555 OCI_HTYPE_ERROR); \
556 sh_stripnl (o_errormsg); \
557 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN, \
558 o_errormsg, _("sh_database_query")); \
559 sl_snprintf(row_query, 127, \
560 _("%s: Connection to database '%s' failed"), \
561 func_name, db_name); \
562 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN, \
563 row_query, _("sh_database_query")); \
564 bad_init = 1; \
565 SL_RETURN(-1, _("sh_database_query")); \
566 } while (1 == 0)
567
568 oracle_doconnect:
569
570 if (!getenv("ORACLE_HOME")) /* flawfinder: ignore */
571 {
572 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
573 _("ORACLE_HOME environment variable not set"),
574 _("sh_database_query"));
575 }
576 if (db_name[0] == '\0')
577 {
578 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
579 _("database name not set, using default 'samhain'"),
580 _("sh_database_query"));
581 sl_strlcpy(db_name, _("samhain"), 64);
582 }
583 if (db_user[0] == '\0')
584 {
585 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
586 _("database user not set, using default 'samhain'"),
587 _("sh_database_query"));
588 sl_strlcpy(db_user, _("samhain"), 64);
589 }
590 if (db_password[0] == '\0')
591 {
592 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
593 _("database password not set, cannot proceed"),
594 _("sh_database_query"));
595 bad_init = 1;
596 SL_RETURN(-1, _("sh_database_query"));
597 }
598
599
600#ifdef DB_DEBUG
601 sl_snprintf(row_query, 127,
602 _("Conncting to oracle database '%s'"),
603 db_name);
604 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
605 row_query,
606 _("sh_database_query"));
607#endif
608
609 /* a) Oracle says use OCIEnvCreate instead of OCIInitialize/OCIEnvcreate
610 * b) why two times OCIEnvInit() ???
611 */
612 if (OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL))
613 PRINT_ORACLE_ERR("OCIInitialize");
614
615 if (OCIEnvInit(&o_environment, OCI_DEFAULT, 0, NULL))
616 PRINT_ORACLE_ERR("OCIEnvInit");
617
618 if (OCIEnvInit(&o_environment, OCI_DEFAULT, 0, NULL))
619 PRINT_ORACLE_ERR("OCIEnvInit (2)");
620
621 /* allocate and initialize the error handle
622 */
623 if (OCIHandleAlloc(o_environment, (dvoid **)&o_error,
624 OCI_HTYPE_ERROR, (size_t) 0, NULL))
625 PRINT_ORACLE_ERR("OCIHandleAlloc");
626
627 /* logon and allocate the service context handle
628 */
629 if (OCILogon(o_environment, o_error, &o_servicecontext,
630 (OraText*) db_user, sl_strlen(db_user),
631 (OraText*) db_password, sl_strlen(db_password),
632 (OraText*) db_name, sl_strlen(db_name)))
633 {
634 OCIErrorGet(o_error, 1, NULL, &o_errorcode,
635 o_errormsg, sizeof(o_errormsg), OCI_HTYPE_ERROR);
636 sh_stripnl (o_errormsg);
637 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
638 o_errormsg,
639 _("sh_database_query"));
640 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
641 _("check database is listed in tnsnames.ora"),
642 _("sh_database_query"));
643 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
644 _("check tnsnames.ora readable"),
645 _("sh_database_query"));
646 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
647 _("check database accessible with sqlplus"),
648 _("sh_database_query"));
649 sl_snprintf(row_query, 127,
650 _("OCILogon: Connection to database '%s' failed"),
651 db_name);
652 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
653 row_query, _("sh_database_query"));
654 bad_init = 1;
655 SL_RETURN(-1, _("sh_database_query"));
656 }
657
658 if (OCIHandleAlloc(o_environment, (dvoid **)&o_statement,
659 OCI_HTYPE_STMT, 0, NULL))
660 PRINT_ORACLE_ERR("OCIHandleAlloc (2)");
661
662 /* Flag connection status
663 */
664 connected = 1;
665
666 oracle_connected:
667
668 /*
669 * Insert
670 */
671#ifdef DB_DEBUG
672 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
673 query,
674 _("sh_database_query"));
675#endif
676
677 if (OCIStmtPrepare(o_statement, o_error,
678 (OraText*) query, sl_strlen(query),
679 OCI_NTV_SYNTAX, OCI_DEFAULT))
680 {
681 OCIErrorGet(o_error, 1, NULL,
682 &o_errorcode, o_errormsg, sizeof(o_errormsg),
683 OCI_HTYPE_ERROR);
684 sh_stripnl (o_errormsg);
685 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
686 o_errormsg,
687 _("sh_database_query"));
688 if (retry == 0 &&
689 (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9))
690 {
691 ++retry; sh_database_reset(); goto oracle_doconnect;
692 }
693 goto err_out;
694 }
695
696 if (OCIStmtExecute(o_servicecontext,
697 o_statement, o_error, 1, 0,
698 NULL, NULL, OCI_COMMIT_ON_SUCCESS))
699 {
700 OCIErrorGet(o_error, 1, NULL,
701 &o_errorcode, o_errormsg, sizeof(o_errormsg),
702 OCI_HTYPE_ERROR);
703 sh_stripnl (o_errormsg);
704 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
705 o_errormsg,
706 _("sh_database_query"));
707 if (retry == 0 &&
708 (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9))
709 {
710 ++retry; sh_database_reset(); goto oracle_doconnect;
711 }
712 goto err_out;
713 }
714
715#ifdef DB_DEBUG
716 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
717 _("No error on insert"),
718 _("sh_database_query"));
719#endif
720
721 /* Get row index
722 */
723 sl_strlcpy (row_query, _("SELECT MAX(log_index) FROM "), 128);
724 sl_strlcat (row_query, db_table, 128);
725
726#ifdef DB_DEBUG
727 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
728 row_query,
729 _("sh_database_query"));
730#endif
731
732 if (OCIStmtPrepare(o_statement, o_error,
733 (OraText*) row_query, sl_strlen(row_query),
734 OCI_NTV_SYNTAX, OCI_DEFAULT))
735 {
736 OCIErrorGet(o_error, 1, NULL,
737 &o_errorcode, o_errormsg, sizeof(o_errormsg),
738 OCI_HTYPE_ERROR);
739 sh_stripnl (o_errormsg);
740 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
741 o_errormsg,
742 _("sh_database_query"));
743 if (retry == 0 &&
744 (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9))
745 {
746 ++retry; sh_database_reset(); goto oracle_doconnect;
747 }
748 goto err_out;
749 }
750
751 if (OCIStmtExecute(o_servicecontext, o_statement, o_error,
752 0, 0, NULL, NULL, OCI_DEFAULT))
753 {
754 OCIErrorGet(o_error, 1, NULL,
755 &o_errorcode, o_errormsg, sizeof(o_errormsg),
756 OCI_HTYPE_ERROR);
757 sh_stripnl (o_errormsg);
758 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
759 o_errormsg,
760 _("sh_database_query"));
761 if (retry == 0 &&
762 (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9))
763 {
764 ++retry; sh_database_reset(); goto oracle_doconnect;
765 }
766 goto err_out;
767 }
768
769 if (OCIDefineByPos (o_statement, &o_define, o_error, 1,
770 &result, sizeof(result),
771 SQLT_INT, 0, 0, 0, OCI_DEFAULT))
772 {
773 OCIErrorGet(o_error, 1, NULL,
774 &o_errorcode, o_errormsg, sizeof(o_errormsg),
775 OCI_HTYPE_ERROR);
776 sh_stripnl (o_errormsg);
777 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
778 o_errormsg,
779 _("sh_database_query"));
780 if (retry == 0 &&
781 (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9))
782 {
783 ++retry; sh_database_reset(); goto oracle_doconnect;
784 }
785 goto err_out;
786 }
787 if (OCIStmtFetch (o_statement, o_error, 1, OCI_FETCH_NEXT, OCI_DEFAULT))
788 {
789 OCIErrorGet(o_error, 1, NULL,
790 &o_errorcode, o_errormsg, sizeof(o_errormsg),
791 OCI_HTYPE_ERROR);
792 sh_stripnl (o_errormsg);
793 sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
794 o_errormsg,
795 _("sh_database_query"));
796 if (retry == 0 &&
797 (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9))
798 {
799 ++retry; sh_database_reset(); goto oracle_doconnect;
800 }
801 goto err_out;
802 }
803
804#ifdef DB_DEBUG
805 sl_snprintf(row_query, 127, _("Returned value: %d"), result);
806 sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
807 row_query,
808 _("sh_database_query"));
809#endif
810
811 *id = result;
812
813 if (sh_persistent_dbconn == S_FALSE)
814 {
815 OCILogoff(o_servicecontext, o_error);
816 OCIHandleFree((dvoid *) o_statement, OCI_HTYPE_STMT);
817 OCIHandleFree((dvoid *) o_servicecontext, OCI_HTYPE_SVCCTX);
818 OCIHandleFree((dvoid *) o_error, OCI_HTYPE_ERROR);
819 o_error = NULL;
820 connected = 0;
821 }
822 SL_RETURN(0, _("sh_database_query"));
823
824 err_out:
825 /*
826 * Error
827 */
828 if (sh_persistent_dbconn == S_FALSE)
829 {
830 OCILogoff(o_servicecontext, o_error);
831 OCIHandleFree((dvoid *) o_statement, OCI_HTYPE_STMT);
832 OCIHandleFree((dvoid *) o_servicecontext, OCI_HTYPE_SVCCTX);
833 OCIHandleFree((dvoid *) o_error, OCI_HTYPE_ERROR);
834 o_error = NULL;
835 connected = 0;
836 }
837 SL_RETURN(-1, _("sh_database_query"));
838}
839
840/* #ifdef WITH_ORACLE */
841#endif
842
843#ifdef WITH_POSTGRES
844/******************************************************************
845 *
846 * Postgresql stuff, tested
847 *
848 ******************************************************************/
849
850#ifdef HAVE_PGSQL_LIBPQ_FE_H
851#include <pgsql/libpq-fe.h>
852#else
853#include <libpq-fe.h>
854#endif
855
856static int connection_status = S_FALSE;
857
858void sh_database_reset()
859{
860 connection_status = S_FALSE;
861 return;
862}
863
864static
865int sh_database_query (char * query, /*@out@*/ long * id)
866{
867 char conninfo[256];
868 char * p;
869 static PGconn * conn = NULL;
870 PGresult * res;
871 unsigned int i;
872 const char * params[1];
873 char id_param[32];
874 static SH_TIMEOUT sh_timer = { 0, 3600, S_TRUE };
875
876 SL_ENTER(_("sh_database_query"));
877
878 *id = 0;
879
880 p = &conninfo[0];
881
882 if (db_host[0] == '\0')
883 sl_strlcpy(db_host, _("localhost"), 64);
884 if (db_name[0] == '\0')
885 sl_strlcpy(db_name, _("samhain"), 64);
886 if (db_user[0] == '\0')
887 sl_strlcpy(db_user, _("samhain"), 64);
888
889 if (db_host[0] != '\0' && NULL != strchr(db_host, '.'))
890 {
891 sl_snprintf(p, 255, "hostaddr=%s ", db_host);
892 p = &conninfo[strlen(conninfo)];
893 }
894 if (db_name[0] != '\0')
895 {
896 sl_snprintf(p, 255 - strlen(conninfo), "dbname=%s ", db_name);
897 p = &conninfo[strlen(conninfo)];
898 }
899
900 if (db_user[0] != '\0')
901 {
902 sl_snprintf(p, 255 - strlen(conninfo), "user=%s ", db_user);
903 p = &conninfo[strlen(conninfo)];
904 }
905
906 if (db_password[0] != '\0')
907 {
908 sl_snprintf(p, 255 - strlen(conninfo), "password=%s ", db_password);
909 }
910
911 if (connection_status == S_FALSE)
912 {
913 if (conn)
914 PQfinish(conn);
915 conn = NULL;
916 conn = PQconnectdb(conninfo);
917 }
918 else
919 {
920 if (PQstatus(conn) == CONNECTION_BAD)
921 PQreset(conn);
922 }
923
924 if ((conn == NULL) || (PQstatus(conn) == CONNECTION_BAD))
925 {
926 connection_status = S_FALSE;
927
928 sh_timer.flag_ok = S_FALSE;
929 if (S_TRUE == sh_util_timeout_check(&sh_timer))
930 {
931 goto err_out;
932 }
933 else
934 {
935 if (conn)
936 PQfinish(conn);
937 conn = NULL;
938 SL_RETURN(0, _("sh_database_query"));
939 }
940 }
941 connection_status = S_TRUE;
942
943
944 /* get the unique row index
945 */
946 res = PQexec(conn, _("SELECT NEXTVAL('log_log_index_seq')"));
947 if (PQresultStatus(res) != PGRES_TUPLES_OK)
948 {
949 PQclear(res);
950 goto err_out;
951 }
952
953 *id = atoi (PQgetvalue(res, 0, 0));
954 PQclear(res);
955
956 sl_snprintf(id_param, 32, "%ld", *id);
957 params[0] = id_param;
958
959 /* do the insert
960 */
961 res = PQexecParams(conn, query, 1, NULL, params, NULL, NULL, 1);
962 if (PQresultStatus(res) != PGRES_COMMAND_OK)
963 {
964 PQclear(res);
965 goto err_out;
966 }
967 PQclear(res);
968
969 if (S_FALSE == sh_persistent_dbconn)
970 {
971 if (conn)
972 PQfinish(conn);
973 conn = NULL;
974 connection_status = S_FALSE;
975 }
976 SL_RETURN(0, _("sh_database_query"));
977
978
979 err_out:
980 if (conn)
981 {
982 p = PQerrorMessage(conn);
983 for (i = 0; i < sl_strlen(p); ++i)
984 if (p[i] == '\n') p[i] = ' ';
985 }
986 else
987 {
988 p = NULL;
989 }
990 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
991 (p == NULL ? _("(null)") : p),
992 _("sh_database_query"));
993 if (conn)
994 PQfinish(conn);
995 conn = NULL;
996 connection_status = S_FALSE;
997 SL_RETURN(-1, _("sh_database_query"));
998}
999#endif
1000
1001
1002#ifdef WITH_MYSQL
1003
1004#ifdef HAVE_MYSQL_MYSQL_H
1005#include <mysql/mysql.h>
1006#else
1007#include <mysql.h>
1008#endif
1009
1010extern int flag_err_debug;
1011
1012static int connection_status = S_FALSE;
1013
1014void sh_database_reset()
1015{
1016 connection_status = S_FALSE;
1017 return;
1018}
1019
1020static
1021int sh_database_query (char * query, /*@out@*/ long * id)
1022{
1023 int status = 0;
1024 const char * p;
1025 static MYSQL * db_conn = NULL;
1026 static SH_TIMEOUT sh_timer = { 0, 3600, S_TRUE };
1027
1028 SL_ENTER(_("sh_database_query"));
1029
1030 *id = 0;
1031
1032 if (query == NULL)
1033 {
1034 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1035 _("NULL query"),
1036 _("sh_database_query"));
1037 SL_RETURN(0, _("sh_database_query"));
1038 }
1039
1040 if (db_host[0] == '\0')
1041 (void) sl_strlcpy(db_host, _("localhost"), 64);
1042 if (db_name[0] == '\0')
1043 (void) sl_strlcpy(db_name, _("samhain"), 64);
1044 if (db_user[0] == '\0')
1045 (void) sl_strlcpy(db_user, _("samhain"), 64);
1046
1047 if ((db_conn == NULL) || (connection_status == S_FALSE))
1048 {
1049 if (db_conn)
1050 {
1051 mysql_close(db_conn);
1052 db_conn = NULL;
1053 }
1054 connection_status = S_FALSE;
1055
1056 db_conn = mysql_init(NULL);
1057 if (NULL == db_conn)
1058 {
1059 p = NULL; status = 0;
1060 sh_timer.flag_ok = S_FALSE;
1061 if (S_TRUE == sh_util_timeout_check(&sh_timer))
1062 {
1063 goto alt_out;
1064 }
1065 else
1066 {
1067 SL_RETURN(0, _("sh_database_query"));
1068 }
1069 }
1070
1071 /* Read in defaults from /etc/my.cnf and associated files,
1072 * suggested by arjones at simultan dyndns org
1073 * see: - http://dev.mysql.com/doc/refman/5.0/en/option-files.html
1074 * for the my.cnf format,
1075 * - http://dev.mysql.com/doc/refman/5.0/en/mysql-options.html
1076 * for possible options
1077 * We don't check the return value because it's useless (failure due
1078 * to lack of access permission is not reported).
1079 */
1080 mysql_options(db_conn, MYSQL_READ_DEFAULT_GROUP, _("samhain"));
1081
1082 status = 0;
1083
1084 if (NULL == mysql_real_connect(db_conn,
1085 db_host[0] == '\0' ? NULL : db_host,
1086 db_user[0] == '\0' ? NULL : db_user,
1087 db_password[0] == '\0' ? NULL : db_password,
1088 db_name[0] == '\0' ? NULL : db_name,
1089 0, NULL, 0))
1090 {
1091 sh_timer.flag_ok = S_FALSE;
1092 if (S_TRUE == sh_util_timeout_check(&sh_timer))
1093 {
1094 goto err_out;
1095 }
1096 else
1097 {
1098 SL_RETURN(0, _("sh_database_query"));
1099 }
1100 }
1101 connection_status = S_TRUE;
1102 }
1103 else
1104 {
1105 if (0 != mysql_ping(db_conn))
1106 {
1107 connection_status = S_FALSE;
1108 sh_timer.flag_ok = S_FALSE;
1109 if (S_TRUE == sh_util_timeout_check(&sh_timer))
1110 {
1111 goto err_out;
1112 }
1113 else
1114 {
1115 SL_RETURN(0, _("sh_database_query"));
1116 }
1117 }
1118 }
1119
1120 if (0 != mysql_query(db_conn, query))
1121 {
1122 goto err_out;
1123 }
1124
1125 if (flag_err_debug == SL_TRUE)
1126 {
1127 p = mysql_info (db_conn);
1128 if (p != NULL)
1129 {
1130 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1131 p,
1132 _("sh_database_query"));
1133 }
1134 }
1135
1136 *id = (long) mysql_insert_id(db_conn);
1137 if (S_FALSE == sh_persistent_dbconn)
1138 {
1139 if (db_conn)
1140 mysql_close(db_conn);
1141 db_conn = NULL;
1142 connection_status = S_FALSE;
1143 }
1144 SL_RETURN(0, _("sh_database_query"));
1145
1146 err_out:
1147
1148 if (db_conn)
1149 {
1150 p = mysql_error (db_conn);
1151 status = (int) mysql_errno (db_conn);
1152 }
1153 else
1154 {
1155 p = NULL; p = 0;
1156 }
1157
1158 alt_out:
1159
1160 *id = 0;
1161 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1162 (p == NULL ? _("(null)") : p),
1163 _("sh_database_query"));
1164 if (db_conn)
1165 mysql_close(db_conn);
1166 db_conn = NULL;
1167 connection_status = S_FALSE;
1168 SL_RETURN(status, _("sh_database_query"));
1169}
1170#endif
1171
1172static
1173char * null_or_val (char * end, char * val, int * size, int flag)
1174{
1175 long len;
1176
1177 if (!end || !val || !size)
1178 return end;
1179
1180 if (val[0] == '\0')
1181 {
1182 return end;
1183 }
1184 else
1185 {
1186 if (*size > 1)
1187 {
1188 *end = ','; ++end; (*size) -= 1;
1189 if (flag == 1) { *end = '\''; ++end; (*size) -= 1; }
1190 *end = '\0';
1191 }
1192 len = (long) strlen(val);
1193 if ((long) *size > (len+1))
1194 {
1195 (void) sl_strlcat(end, val, (size_t) *size);
1196 end += len; (*size) -= len;
1197 if (flag == 1) { *end = '\''; ++end; (*size) -= 1; }
1198 *end = '\0';
1199 }
1200 }
1201
1202 return end;
1203}
1204
1205#define SH_QUERY_MAX 16383
1206
1207static
1208long sh_database_entry (dbins * db_entry, long id)
1209{
1210 /* This does not need to be re-entrant
1211 */
1212 char * query;
1213 static char columns[1024];
1214 char * values;
1215
1216 int status;
1217 long the_id;
1218 int size;
1219 char * end;
1220 int c_size;
1221 char * c_end;
1222 char * p;
1223 int i;
1224 char num[64];
1225
1226 md5Param crc;
1227 unsigned char md5buffer[16];
1228 char md5out[33];
1229 int cnt;
1230
1231 SL_ENTER(_("sh_database_entry"));
1232
1233 query = SH_ALLOC(SH_QUERY_MAX+1);
1234 values = SH_ALLOC(SH_QUERY_MAX+1);
1235
1236 (void) md5Reset(&crc);
1237
1238 if (db_entry->host[0] == '\0')
1239 {
1240 if (sh.host.name[0] == '\0')
1241 (void) strcpy (db_entry->host, _("localhost")); /* known to fit */
1242 else
1243 (void) sl_strlcpy (db_entry->host, sh.host.name, 64);
1244 }
1245
1246 /*@-bufferoverflowhigh@*/
1247 if (id >= 0)
1248 sprintf(num, "%ld", id); /* known to fit */
1249 /*@+bufferoverflowhigh@*/
1250
1251#if defined(WITH_ORACLE)
1252 /* Oracle needs some help for the time format (fix by Michael Somers)
1253 */
1254 (void)
1255 sl_snprintf (values, SH_QUERY_MAX,
1256 _("(%s,%c%s%c,to_date(%c%s%c,'YYYY-MM-DD HH24:MI:SS'),%c%s%c,%c%s%c"),
1257 id >= 0 ? num : _("NULL"),
1258 '\'', db_entry->host,'\'',
1259 '\'', db_entry->time,'\'',
1260 '\'', db_entry->sev, '\'',
1261 '\'',
1262 (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg),
1263 '\'');
1264 (void) sl_snprintf (columns, 1023,
1265 _("(log_ref,log_host,log_time,log_sev,log_msg"));
1266#elif defined(WITH_POSTGRES)
1267 /* Prepare query for PQexecParams
1268 */
1269 (void)
1270 sl_snprintf (values, SH_QUERY_MAX,
1271 _("($1,%s,%c%s%c,%c%s%c,%c%s%c,%c%s%c"),
1272 id >= 0 ? num : _("NULL"),
1273 '\'', db_entry->host,'\'',
1274 '\'', db_entry->time,'\'',
1275 '\'', db_entry->sev, '\'',
1276 '\'',
1277 (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg),
1278 '\'');
1279 (void) sl_snprintf (columns, 1023,
1280 _("(log_index,log_ref,log_host,log_time,log_sev,log_msg"));
1281#else
1282 (void)
1283 sl_snprintf (values, SH_QUERY_MAX, _("(%s,%c%s%c,%c%s%c,%c%s%c,%c%s%c"),
1284 id >= 0 ? num : _("NULL"),
1285 '\'', db_entry->host,'\'',
1286 '\'', db_entry->time,'\'',
1287 '\'', db_entry->sev, '\'',
1288 '\'',
1289 (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg),
1290 '\'');
1291 (void) sl_snprintf (columns, 1023,
1292 _("(log_ref,log_host,log_time,log_sev,log_msg"));
1293#endif
1294
1295
1296 /*@-type@*//* byte* versus char[..] */
1297 if (attr_tab[0].inHash == 1)
1298 (void) md5Update(&crc, (sh_byte*) db_entry->sev,
1299 (int) strlen(db_entry->sev));
1300 if (attr_tab[1].inHash == 1)
1301 (void) md5Update(&crc, (sh_byte*) db_entry->time,
1302 (int) strlen(db_entry->time));
1303 if (attr_tab[2].inHash == 1)
1304 (void) md5Update(&crc, (sh_byte*) db_entry->host,
1305 (int) strlen(db_entry->host));
1306 if (attr_tab[3].inHash == 1 && db_entry->msg[0] != '\0')
1307 (void) md5Update(&crc, (sh_byte*) db_entry->msg,
1308 (int) strlen(db_entry->sev));
1309 /*@+type@*/
1310
1311 size = (int) (SH_QUERY_MAX - strlen(values));
1312 end = values + strlen(values);
1313 c_size = 1023 - (int) strlen(columns); /* sizeof(colums) == 1024 */
1314 c_end = columns + strlen(columns);
1315
1316 i = 4;
1317
1318 while (attr_tab[i].attr != NULL)
1319 {
1320 if (attr_tab[i].size != 0)
1321 {
1322 if (attr_tab[i].val > 40 && attr_tab[i].val < 47)
1323 {
1324 /* remove the 'T' between date and time
1325 */
1326 p = (char *)(db_entry)+attr_tab[i].off;
1327 p = strchr(p, 'T');
1328 if (p) *p = ' ';
1329 }
1330 p = end;
1331 end = null_or_val(end,((char *)(db_entry)+attr_tab[i].off),&size,1);
1332 if (p != end)
1333 {
1334 /*
1335 * 'host' is a reserved word in SQL
1336 */
1337 if (attr_tab[i].val == SH_SLOT_HOST)
1338 c_end = null_or_val (c_end, _("fromhost"), &c_size,0);
1339 /*
1340 * 'group' is a reserved word in SQL
1341 */
1342 else if (attr_tab[i].val == SH_SLOT_GROUP)
1343 c_end = null_or_val (c_end, _("grp"), &c_size,0);
1344 else
1345 c_end = null_or_val (c_end, attr_tab[i].attr, &c_size,0);
1346 }
1347 /*@-type@*//* byte* versus char[..] */
1348 if (attr_tab[i].inHash == 1 &&
1349 ((char *)(db_entry)+attr_tab[i].off) != '\0')
1350 {
1351 (void)md5Update(&crc,
1352 (sh_byte*) ((char *)(db_entry)+attr_tab[i].off),
1353 (int)strlen((char *)(db_entry)+attr_tab[i].off));
1354 }
1355 /*@+type@*/
1356 }
1357 else if (attr_tab[i].val >= START_SEC_LONGS &&
1358 attr_tab[i].val <= END_SEC_LONGS)
1359 {
1360 (void)
1361 sl_snprintf(end, (size_t)(size-1), _(",\'%ld\'"),
1362 db_entry->long_data[attr_tab[i].val-START_SEC_LONGS]);
1363 while (*end != '\0') { ++end; --size; }
1364 (void) sl_snprintf(c_end, (size_t)(c_size-1),
1365 _(",%s"), attr_tab[i].attr);
1366 while (*c_end != '\0') { ++c_end; --c_size; }
1367 if (attr_tab[i].inHash == 1)
1368 {
1369 /*@-type@*//* byte* versus char[..] */
1370 (void)
1371 md5Update(&crc,
1372 (sh_byte *) db_entry->long_data[attr_tab[i].val-START_SEC_LONGS],
1373 sizeof(long));
1374 /*@+type@*/
1375 }
1376 }
1377
1378 ++i;
1379 }
1380
1381 (void) md5Digest(&crc, (uint32 *) md5buffer);
1382 /*@-bufferoverflowhigh -usedef@*/
1383 for (cnt = 0; cnt < 16; ++cnt)
1384 sprintf (&md5out[cnt*2], _("%02X"), /* known to fit */
1385 (unsigned int) md5buffer[cnt]);
1386 /*@+bufferoverflowhigh +usedef@*/
1387 md5out[32] = '\0';
1388
1389 (void) sl_snprintf(end, (size_t) (size-1), _(",%c%s%c"), '\'', md5out, '\'');
1390 while (*end != '\0') { ++end; --size; }
1391 (void) sl_snprintf(c_end, (size_t) (c_size-1),_(",log_hash"));
1392 while (*c_end != '\0') { ++c_end; --c_size; }
1393
1394
1395 if (size > 1) { *end = ')'; ++end; *end = '\0'; }
1396 if (c_size > 1) { *c_end = ')'; ++c_end; *c_end = '\0'; }
1397
1398 if (db_table[0] == '\0')
1399 (void) sl_strlcpy(db_table, _("log"), 64);
1400
1401 (void) sl_snprintf (query, SH_QUERY_MAX,
1402 _("INSERT INTO %s %s VALUES %s"),
1403 db_table, columns, values);
1404
1405 status = sh_database_query (query, &the_id);
1406
1407 /*@-usedef@*//* no, 'values' is allocated here */
1408 SH_FREE(values);
1409 /*@+usedef@*/
1410 SH_FREE(query);
1411
1412 SL_RETURN(the_id, _("sh_database_entry"));
1413}
1414
1415static int sh_database_comp_attr (const void *m1, const void *m2)
1416{
1417 my_attr *mi1 = (my_attr *) m1;
1418 my_attr *mi2 = (my_attr *) m2;
1419 return strcmp(mi1->attr, mi2->attr);
1420}
1421
1422
1423static void init_attr_table()
1424{
1425 static int first = S_TRUE;
1426 int i, j;
1427
1428#ifdef SH_STEALTH
1429 int j, k;
1430
1431 if (first == S_FALSE)
1432 return;
1433
1434 i = 0;
1435 while (attr_tab[i].attr_o != NULL)
1436 {
1437 j = strlen(attr_tab[i].attr_o);
1438 attr_tab[i].attr = malloc (j+1); /* only once */
1439 if (NULL == attr_tab[i].attr)
1440 return;
1441 for (k = 0; k < j; ++k)
1442 attr_tab[i].attr[k] = attr_tab[i].attr_o[k] ^ XOR_CODE;
1443 attr_tab[i].attr[j] = '\0';
1444 attr_tab[i].alen = strlen(attr_tab[i].attr_o);
1445 ++i;
1446 }
1447 first = S_FALSE;
1448
1449#else
1450
1451 i = 0;
1452 while (attr_tab[i].attr_o != NULL)
1453 {
1454 attr_tab[i].attr = attr_tab[i].attr_o;
1455 attr_tab[i].alen = strlen(attr_tab[i].attr_o);
1456 ++i;
1457 }
1458 first = S_FALSE;
1459
1460#endif
1461
1462 /* create a sorted table for binary search
1463 */
1464 attr_tab_srch = SH_ALLOC(i * sizeof(my_attr));
1465 for (j=0; j<i; ++j)
1466 memcpy(&attr_tab_srch[j], &attr_tab[j], sizeof(my_attr));
1467 qsort(attr_tab_srch, i, sizeof(my_attr), sh_database_comp_attr);
1468 attr_tab_srch_siz = i;
1469
1470 return;
1471}
1472
1473int sh_database_add_to_hash (const char * str)
1474{
1475 int i;
1476
1477 if (!str)
1478 return -1;
1479 init_attr_table();
1480 if (0 == strcmp(str, _("log_msg"))) { attr_tab[3].inHash = 1; return 0;}
1481 if (0 == strcmp(str, _("log_sev"))) { attr_tab[0].inHash = 1; return 0;}
1482 if (0 == strcmp(str, _("log_time"))) { attr_tab[1].inHash = 1; return 0;}
1483 if (0 == strcmp(str, _("log_host"))) { attr_tab[2].inHash = 1; return 0;}
1484 i = 4;
1485 while (attr_tab[i].attr != NULL)
1486 {
1487 if (0 == strcmp(str, attr_tab[i].attr))
1488 { attr_tab[i].inHash = 1; return 0; }
1489 ++i;
1490 }
1491 return -1;
1492}
1493
1494static int is_escaped(char * p) {
1495
1496 int escp = 0;
1497 int retv = S_TRUE;
1498
1499 while (*p != '\0')
1500 {
1501 if (*p == '\\')
1502 {
1503 escp = (escp == 1) ? 0 : 1;
1504 }
1505 else if ((*p == '\'' || *p == '\"') && escp == 0)
1506 {
1507 retv = S_FALSE;
1508 }
1509 else
1510 {
1511 escp = 0;
1512 }
1513 ++p;
1514 }
1515 if (escp == 1)
1516 retv = S_FALSE;
1517 return retv;
1518}
1519
1520/* this is not a real XML parser, but it copes with the XML format of
1521 * the log messages provided by sh_error_handle()
1522 */
1523static
1524char * sh_database_parse (char * message, dbins * db_entry)
1525{
1526 static int first = S_TRUE;
1527 char * p;
1528 char * q;
1529 char * z;
1530 dbins * new;
1531 int i;
1532 size_t j;
1533 my_attr * res;
1534 my_attr key;
1535 char key_str[64];
1536
1537 SL_ENTER(_("sh_database_parse"));
1538
1539 if (!message || *message == '\0')
1540 SL_RETURN (NULL, _("sh_database_parse"));
1541
1542 if (first == S_TRUE)
1543 {
1544 init_attr_table();
1545 first = S_FALSE;
1546 }
1547
1548 p = strchr (message, '<');
1549 if (!p)
1550 SL_RETURN (NULL, _("sh_database_parse"));
1551
1552 while ((p != NULL) && (*p != '\0') && (*p != '>'))
1553 {
1554 if (p[0] == 'l' && p[1] == 'o' && p[2] == 'g' &&
1555 (p[3] == ' ' || p[3] == '>'))
1556 {
1557 p = &p[4];
1558 goto parse;
1559 }
1560 else if (p[0] == '/' && p[1] == '>')
1561 SL_RETURN (&p[2], _("sh_database_parse"));
1562 else if (p[0] == '/' && p[1] == 'l' && p[2] == 'o' &&
1563 p[3] == 'g' && p[4] == '>')
1564 SL_RETURN (&p[5], _("sh_database_parse"));
1565 ++p;
1566 }
1567 SL_RETURN(NULL, _("sh_database_parse"));
1568
1569 parse:
1570
1571 while (*p == ' ' || *p == '>')
1572 ++p;
1573
1574 if (*p == '\0')
1575 SL_RETURN(NULL, _("sh_database_parse"));
1576
1577 if (*p != '<' && *p != '/')
1578 goto par2;
1579
1580 if (p[0] == '<' && p[1] == 'l' &&
1581 p[2] == 'o' && p[3] == 'g')
1582 {
1583 new = SH_ALLOC(sizeof(dbins));
1584 init_db_entry(new);
1585 db_entry->next = new;
1586 p = sh_database_parse (p, new);
1587 }
1588
1589 if (p[0] == '/' && p[1] == '>')
1590 SL_RETURN (&p[1], _("sh_database_parse"));
1591
1592 if (p[0] == '<' && p[1] == '/' && p[2] == 'l' &&
1593 p[3] == 'o' && p[4] == 'g' && p[5] == '>')
1594 SL_RETURN (&p[5], _("sh_database_parse"));
1595
1596 par2:
1597
1598 /* non-whitespace
1599 */
1600 i = 0;
1601 for (i=0; i < 64; ++i)
1602 {
1603 key_str[i] = p[i];
1604 if (p[i] == '=')
1605 {
1606 key_str[i] = '\0';
1607 break;
1608 }
1609 }
1610 key_str[63] = '\0';
1611 key.attr = &key_str[0];
1612
1613 res = bsearch(&key, attr_tab_srch, attr_tab_srch_siz,
1614 sizeof(my_attr), sh_database_comp_attr);
1615
1616 if (res != NULL)
1617 {
1618 j = res->alen; /* strlen(attr_tab[i].attr); */
1619 if (p[j] == '=' && p[j+1] == '"')
1620 {
1621 q = strchr(&p[j+2], '"');
1622 if (!q)
1623 {
1624 SL_RETURN(NULL, _("sh_database_parse"));
1625 }
1626 else
1627 {
1628 *q = '\0';
1629
1630 if (S_FALSE == is_escaped(&p[j+2])) {
1631 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1632 _("Message not properly escaped"),
1633 _("sh_database_parse"));
1634 SL_RETURN(NULL, _("sh_database_parse"));
1635 }
1636
1637 if (res->val == 1)
1638 (void) sl_strlcpy(db_entry->sev, &p[j+2],
1639 (size_t)res->size);
1640 else if (res->val == 2)
1641 {
1642 z = strchr(&p[j+2], 'T');
1643 if (z) *z = ' ';
1644 (void) sl_strlcpy(db_entry->time, &p[j+2], 20);
1645 }
1646 else if (res->val == 3)
1647 (void) sl_strlcpy(db_entry->host, &p[j+2],
1648 (size_t) res->size);
1649 else if (res->val == 4)
1650 (void) sl_strlcpy(db_entry->msg, &p[j+2],
1651 (size_t) res->size);
1652 else if (res->size != 0)
1653 {
1654 (void) sl_strlcpy( (((char *)(db_entry))+ res->off),
1655 &p[j+2],
1656 (size_t) res->size);
1657 }
1658 else if (res->val >= START_SEC_LONGS)
1659 {
1660 db_entry->long_data[res->val-START_SEC_LONGS]
1661 = atol(&p[j+2]);
1662 }
1663
1664 *q = '"';
1665 p = q;
1666 ++p;
1667
1668 goto parse;
1669 }
1670 }
1671 }
1672
1673 /* unknown attribute, skip
1674 */
1675 while ((p != NULL) && (*p != '\0') && (*p != ' '))
1676 ++p;
1677
1678 goto parse;
1679}
1680
1681static int enter_wrapper = 1;
1682
1683int set_enter_wrapper (const char * str)
1684{
1685 return sh_util_flagval(str, &enter_wrapper);
1686}
1687
1688/* recursively enter linked list of messages into database, last first
1689 */
1690long sh_database_insert_rec (dbins * curr, int depth)
1691{
1692 unsigned long id = 0;
1693 dbins * prev;
1694
1695 SL_ENTER(_("sh_database_insert_rec"));
1696
1697 if (curr->next)
1698 {
1699 prev = curr->next;
1700 sl_strlcpy(prev->host, curr->host, 64);
1701 id = sh_database_insert_rec (curr->next, (depth + 1));
1702 }
1703
1704 if (id != 0) /* this is a server wrapper */
1705 {
1706 if (enter_wrapper != 0)
1707 {
1708 id = sh_database_entry (curr, id);
1709 }
1710 }
1711 else
1712 {
1713 /*
1714 * id = -1 is the client message; log_ref will be NULL
1715 */
1716 if (depth > 0) /* this is a client message */
1717 id = sh_database_entry (curr, -1);
1718 else /* this is a generic server message */
1719 id = sh_database_entry (curr, 0);
1720 }
1721
1722 SH_FREE(curr);
1723
1724 SL_RETURN(id, _("sh_database_insert_rec"));
1725}
1726
1727int sh_database_insert (char * message)
1728{
1729 dbins * db_entry;
1730
1731 SL_ENTER(_("sh_database_insert"));
1732
1733 db_entry = SH_ALLOC(sizeof(dbins));
1734 init_db_entry(db_entry);
1735
1736 /* recursively parse the message into a linked list
1737 */
1738 (void) sh_database_parse (message, db_entry);
1739
1740 /* recursively enter the linked list into the database
1741 */
1742 (void) sh_database_insert_rec (db_entry, 0);
1743
1744 SL_RETURN(0, _("sh_database_insert"));
1745}
1746
1747#endif
Note: See TracBrowser for help on using the repository browser.