source: trunk/src/sh_database.c@ 487

Last change on this file since 487 was 481, checked in by katerina, 9 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

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