source: trunk/src/sh_database.c

Last change on this file was 554, checked in by katerina, 17 months ago

Fix for ticket #444 (read mysql option file).

File size: 49.6 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, 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      mysql_options(db_conn, MYSQL_READ_DEFAULT_GROUP, _("samhain"));
1126
1127      status = 0;
1128 
1129      if (NULL == mysql_real_connect(db_conn, 
1130                                     db_host[0] == '\0'     ? NULL : db_host, 
1131                                     db_user[0] == '\0'     ? NULL : db_user, 
1132                                     db_password[0] == '\0' ? NULL : db_password,
1133                                     db_name[0] == '\0'     ? NULL : db_name, 
1134                                     0, NULL, 0))
1135        {
1136          sh_timer.flag_ok = S_FALSE;
1137          if (S_TRUE == sh_util_timeout_check(&sh_timer))
1138            {
1139              goto err_out;
1140            }
1141          else
1142            {
1143              SL_RETURN(0, _("sh_database_query"));
1144            }
1145        }
1146     
1147      connection_status = S_TRUE;
1148    }
1149  else
1150    {
1151      if (0 != mysql_ping(db_conn))
1152        {
1153          connection_status = S_FALSE;
1154          sh_timer.flag_ok = S_FALSE;
1155          if (S_TRUE == sh_util_timeout_check(&sh_timer))
1156            {
1157              goto err_out;
1158            }
1159          else
1160            {
1161              SL_RETURN(0, _("sh_database_query"));
1162            }
1163        }
1164    }
1165 
1166  if (0 != mysql_query(db_conn, query))
1167    {
1168      goto err_out;
1169    }
1170
1171  if (flag_err_debug == S_TRUE)
1172    {
1173      p = mysql_info (db_conn);
1174      if (p != NULL)
1175        {
1176          sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1177                          p, 
1178                          _("sh_database_query"));
1179        }
1180    }
1181
1182  *id = (long) mysql_insert_id(db_conn);
1183  if (S_FALSE == sh_persistent_dbconn)
1184    {
1185      if (db_conn)
1186        mysql_close(db_conn);
1187      db_conn = NULL;
1188      connection_status = S_FALSE;
1189    }
1190  SL_RETURN(0, _("sh_database_query"));
1191
1192 err_out:
1193
1194  if (db_conn)
1195    {
1196      p      = mysql_error (db_conn);
1197      status = (int) mysql_errno (db_conn);
1198    }
1199  else
1200    {
1201      p = NULL; p = 0;
1202    }
1203
1204 alt_out:
1205
1206  *id = 0;
1207  sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1208                  (p == NULL ? _("(null)") : p), 
1209                  _("sh_database_query"));
1210  if (db_conn)
1211    mysql_close(db_conn);
1212  db_conn = NULL;
1213  connection_status = S_FALSE;
1214  SL_RETURN(status, _("sh_database_query"));
1215}
1216#endif
1217
1218static
1219char * null_or_val (char * end,   char * val,   int * size, int flag)
1220{
1221  long len;
1222
1223  if (!((end == NULL) || (val == NULL) || (size == NULL)))
1224    {
1225      if (val[0] != '\0')
1226        {
1227          if (*size > 1)
1228            {
1229              *end = ','; ++end; (*size) -= 1;
1230              if (flag == 1) { *end = '\''; ++end; (*size) -= 1; }
1231              *end = '\0';
1232            }
1233          len = (long) strlen(val);
1234          if ((long) *size > (len+1))
1235            {
1236              (void) sl_strlcat(end, val, (size_t) *size);
1237              end   += len; (*size) -= len;
1238              if (flag == 1) { *end = '\''; ++end;  (*size) -= 1; }
1239              *end = '\0'; 
1240            }
1241        }
1242    }
1243 
1244  return end;
1245}
1246
1247#define SH_QUERY_MAX SH_MSG_BUF
1248/* define SH_QUERY_MAX 16383 */
1249
1250static
1251long sh_database_entry (dbins * db_entry, long id)
1252{
1253  /* This does not need to be re-entrant
1254   */
1255  char * query;
1256  static char   columns[1024];
1257  char * values;
1258
1259  long   the_id;
1260  int    size;
1261  char * end;
1262  int    c_size;
1263  char * c_end;
1264  char * p;
1265  int    i;
1266  char   num[64];
1267
1268  md5Param crc;
1269  unsigned char md5buffer[16];
1270  char md5out[33];
1271  int  cnt;
1272
1273  size_t len_val;
1274  size_t len_col;
1275
1276  SL_ENTER(_("sh_database_entry"));
1277
1278  query  = SH_ALLOC(SH_QUERY_MAX+1);
1279  values = SH_ALLOC(SH_QUERY_MAX+1);
1280
1281  (void) md5Reset(&crc);
1282
1283  if (db_entry->host[0] == '\0')
1284    {
1285      if (sh.host.name[0] == '\0')
1286        (void) strcpy (db_entry->host, _("localhost"));  /* known to fit  */
1287      else
1288        (void) sl_strlcpy (db_entry->host, sh.host.name, 64); 
1289    }
1290
1291  /*@-bufferoverflowhigh@*/
1292  if (id >= 0)
1293    sprintf(num, "%ld", id);                       /* known to fit  */
1294  /*@+bufferoverflowhigh@*/
1295
1296#if defined(WITH_ORACLE)
1297  /* Oracle needs some help for the time format (fix by Michael Somers)
1298   */
1299  (void)
1300  sl_snprintf (values, SH_QUERY_MAX, 
1301               _("(:1,%s,%c%s%c,to_date(%c%s%c,'YYYY-MM-DD HH24:MI:SS'),%c%s%c,%c%s%c"),
1302               id >= 0 ? num : _("NULL"),
1303               '\'', db_entry->host,'\'', 
1304               '\'', db_entry->time,'\'', 
1305               '\'', db_entry->sev, '\'',
1306               '\'', 
1307               (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg),
1308               '\'');
1309  (void) sl_snprintf (columns, 1023, 
1310                      _("(log_index,log_ref,log_host,log_time,log_sev,log_msg"));
1311#elif defined(WITH_POSTGRES)
1312  /* Prepare query for PQexecParams
1313   */
1314  (void)
1315  sl_snprintf (values, SH_QUERY_MAX, 
1316               _("($1,%s,%c%s%c,%c%s%c,%c%s%c,%c%s%c"),
1317               id >= 0 ? num : _("NULL"),
1318               '\'', db_entry->host,'\'', 
1319               '\'', db_entry->time,'\'', 
1320               '\'', db_entry->sev, '\'',
1321               '\'', 
1322               (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg), 
1323               '\'');
1324  (void) sl_snprintf (columns, 1023, 
1325                      _("(log_index,log_ref,log_host,log_time,log_sev,log_msg"));
1326#else
1327  (void)
1328  sl_snprintf (values, SH_QUERY_MAX, _("(%s,%c%s%c,%c%s%c,%c%s%c,%c%s%c"),
1329               id >= 0 ? num : _("NULL"),
1330               '\'', db_entry->host,'\'', 
1331               '\'', db_entry->time,'\'', 
1332               '\'', db_entry->sev, '\'',
1333               '\'', 
1334               (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg), 
1335               '\'');
1336  (void) sl_snprintf (columns, 1023, 
1337                      _("(log_ref,log_host,log_time,log_sev,log_msg"));
1338#endif
1339
1340
1341  /*@-type@*//* byte* versus char[..] */
1342  if (attr_tab[0].inHash == 1) 
1343    (void) md5Update(&crc, (sh_byte*) db_entry->sev, 
1344                     (int) strlen(db_entry->sev));
1345  if (attr_tab[1].inHash == 1) 
1346    (void) md5Update(&crc, (sh_byte*) db_entry->time, 
1347                     (int) strlen(db_entry->time));
1348  if (attr_tab[2].inHash == 1) 
1349    (void) md5Update(&crc, (sh_byte*) db_entry->host, 
1350                     (int) strlen(db_entry->host));
1351  if (attr_tab[3].inHash == 1 && db_entry->msg[0] != '\0') 
1352    (void) md5Update(&crc, (sh_byte*) db_entry->msg, 
1353                     (int) strlen(db_entry->sev));
1354  /*@+type@*/
1355
1356  len_val = strlen(values);
1357  size    =  (int) (SH_QUERY_MAX - len_val);
1358  end     =  values + len_val;
1359
1360  len_col = strlen(columns);
1361  c_size  =  1023   - (int) len_col; /* sizeof(colums) == 1024 */
1362  c_end   =  columns + len_col;
1363
1364  i = 4;
1365
1366  while (attr_tab[i].attr != NULL)
1367    {
1368      if (SH_SLOT_CHECKFLAGS == attr_tab[i].val) {
1369        if (db_entry->ulong_data[attr_tab[i].val-START_SEC_LONGS] == 0 &&
1370            db_entry->ulong_data[attr_tab[i+1].val-START_SEC_LONGS] == 0)
1371          { i+= 2; continue; } 
1372      }
1373
1374      if (attr_tab[i].size != 0)
1375        {
1376          if (attr_tab[i].val > 40 && attr_tab[i].val < 47)
1377            {
1378              /* remove the 'T' between date and time
1379               */
1380              p = (char *)(db_entry)+attr_tab[i].off;
1381              p = strchr(p, 'T');
1382              if (p) *p = ' ';
1383            }
1384          p = end;
1385          end = null_or_val(end,((char *)(db_entry)+attr_tab[i].off),&size,1);
1386          if (p != end)
1387            {
1388              if ((attr_tab[i].val != SH_SLOT_HOST) &&
1389                  (attr_tab[i].val != SH_SLOT_GROUP))
1390                {
1391                  c_end = null_or_val (c_end, attr_tab[i].attr, &c_size,0);
1392                }
1393              else
1394                {
1395                  /*
1396                   * 'host' is a reserved word in SQL
1397                   */
1398                  if (attr_tab[i].val == SH_SLOT_HOST)
1399                    c_end = null_or_val (c_end, _("fromhost"), &c_size,0);
1400                  /*
1401                   * 'group' is a reserved word in SQL
1402                   */
1403                  else /* if (attr_tab[i].val == SH_SLOT_GROUP) */
1404                    c_end = null_or_val (c_end, _("grp"), &c_size,0);
1405                }
1406            }
1407          /*@-type@*//* byte* versus char[..] */
1408          if (attr_tab[i].inHash == 1 && 
1409              *((char *)(db_entry)+attr_tab[i].off) != '\0')
1410            {
1411              (void)md5Update(&crc, 
1412                              (sh_byte*) ((char *)(db_entry)+attr_tab[i].off), 
1413                              (int)strlen((char *)(db_entry)+attr_tab[i].off));
1414            }
1415          /*@+type@*/
1416        }
1417      else if (attr_tab[i].val >= START_SEC_LONGS &&
1418               attr_tab[i].val <= END_SEC_LONGS)
1419        {
1420          (void)
1421          sl_snprintf(end, (size_t)(size-1), _(",\'%lu\'"), 
1422                      db_entry->ulong_data[attr_tab[i].val-START_SEC_LONGS]);
1423          while (*end != '\0') { ++end; --size; }
1424          (void) sl_snprintf(c_end, (size_t)(c_size-1), 
1425                             _(",%s"), attr_tab[i].attr);
1426          while (*c_end != '\0') { ++c_end; --c_size; }
1427          if (attr_tab[i].inHash == 1) 
1428            {
1429              /*@-type@*//* byte* versus char[..] */
1430              (void)
1431              md5Update(&crc,
1432                        (sh_byte *) db_entry->ulong_data[attr_tab[i].val-START_SEC_LONGS], 
1433                        sizeof(long));
1434              /*@+type@*/
1435            }
1436        }
1437
1438      ++i;
1439    }
1440
1441  (void) md5Digest(&crc, (uint32 *) md5buffer);
1442  /*@-bufferoverflowhigh -usedef@*/
1443  for (cnt = 0; cnt < 16; ++cnt)
1444    sprintf (&md5out[cnt*2], _("%02X"),            /* known to fit  */
1445             (unsigned int) md5buffer[cnt]); 
1446  /*@+bufferoverflowhigh +usedef@*/
1447  md5out[32] = '\0';
1448
1449  (void) sl_snprintf(end, (size_t) (size-1), _(",%c%s%c"), '\'', md5out, '\'');
1450  while (*end != '\0') { ++end; --size; }
1451  (void) sl_snprintf(c_end, (size_t) (c_size-1),_(",log_hash"));
1452  while (*c_end != '\0') { ++c_end; --c_size; }
1453
1454
1455  if (size > 1)   { *end   = ')'; ++end;   *end   = '\0'; }
1456  if (c_size > 1) { *c_end = ')'; ++c_end; *c_end = '\0'; }
1457
1458  if (db_table[0]    == '\0')
1459    (void) sl_strlcpy(db_table, _("log"),       64);
1460
1461  (void) sl_snprintf (query, SH_QUERY_MAX,
1462                      _("INSERT INTO %s %s VALUES %s"),
1463                      db_table, columns, values);
1464
1465  sh_database_query (query, &the_id);
1466
1467  /*@-usedef@*//* no, 'values' is allocated here */
1468  SH_FREE(values);
1469  /*@+usedef@*/
1470  SH_FREE(query);
1471 
1472  SL_RETURN(the_id, _("sh_database_entry"));
1473}
1474 
1475static int sh_database_comp_attr (const void *m1, const void *m2) 
1476{
1477  const my_attr *mi1 = (const my_attr *) m1;
1478  const my_attr *mi2 = (const my_attr *) m2;
1479  return strcmp(mi1->attr, mi2->attr);
1480}
1481
1482
1483static void init_attr_table(void)
1484{
1485  static  int first = S_TRUE;
1486  int         i, j;
1487
1488#ifdef SH_STEALTH
1489  int     k;
1490
1491  if (first == S_FALSE)
1492    return;
1493
1494  i = 0;
1495  while (attr_tab[i].attr_o != NULL)
1496    {
1497      j = strlen(attr_tab[i].attr_o);
1498      attr_tab[i].attr = calloc(1, j+1); /* only once */
1499      if (NULL == attr_tab[i].attr)
1500        return;
1501      for (k = 0; k < j; ++k)
1502        attr_tab[i].attr[k] = attr_tab[i].attr_o[k] ^ XOR_CODE;
1503      attr_tab[i].attr[j] = '\0';
1504      attr_tab[i].alen = strlen(attr_tab[i].attr_o);
1505      ++i;
1506    }
1507  first = S_FALSE;
1508
1509#else
1510
1511  if (first == S_FALSE)
1512    return;
1513
1514  i = 0;
1515  while (attr_tab[i].attr_o != NULL)
1516    {
1517      attr_tab[i].attr = attr_tab[i].attr_o;
1518      attr_tab[i].alen = strlen(attr_tab[i].attr_o);
1519      ++i;
1520    }
1521  first = S_FALSE;
1522
1523#endif
1524
1525  /* create a sorted table for binary search
1526   */
1527  attr_tab_srch = SH_ALLOC(i * sizeof(my_attr));
1528  for (j=0; j<i; ++j)
1529    memcpy(&attr_tab_srch[j], &attr_tab[j], sizeof(my_attr));
1530  qsort(attr_tab_srch, i, sizeof(my_attr), sh_database_comp_attr);
1531  attr_tab_srch_siz = i;
1532
1533  return;
1534}
1535
1536int sh_database_add_to_hash  (const char * str)
1537{
1538  int i;
1539
1540  if (!str)
1541    return -1;
1542  init_attr_table();
1543  if (0 == strcmp(str, _("log_msg")))  { attr_tab[3].inHash = 1; return 0;}
1544  if (0 == strcmp(str, _("log_sev")))  { attr_tab[0].inHash = 1; return 0;}
1545  if (0 == strcmp(str, _("log_time"))) { attr_tab[1].inHash = 1; return 0;}
1546  if (0 == strcmp(str, _("log_host"))) { attr_tab[2].inHash = 1; return 0;}
1547  i = 4;
1548  while (attr_tab[i].attr != NULL)
1549    {
1550      if (0 == strcmp(str, attr_tab[i].attr)) 
1551        { attr_tab[i].inHash = 1; return 0; }
1552      ++i;
1553    }
1554  return -1;
1555}
1556
1557static int is_escaped(char * p_in) {
1558
1559  int    escp = 0;
1560  int    retv = S_TRUE;
1561  unsigned char * p = (unsigned char *) p_in;
1562
1563  if (*p != '\0')
1564    {
1565      do 
1566        {
1567          if (*p <=  126 && *p >= 32)
1568            {
1569              if (escp == 0)
1570                {
1571                  if      (!((*p == '\'') || (*p == '\"') || (*p == '\\'))) 
1572                    /* do nothing */;
1573                  else if (*p == '\\') 
1574                    {
1575#ifndef WITH_MYSQL
1576                      if (p[1] == '\'')
1577                        {
1578                          *p = '\'';
1579                        }
1580#endif
1581                      escp = 1;
1582                    }
1583                  else 
1584                    retv = S_FALSE; /* (*p == '\'' || *p == '\"') */
1585                }
1586              else /* escp == 1 */
1587                {
1588                  escp = 0;
1589                }
1590            }
1591          else /* *p > 126 || *p < 32 */
1592            {
1593              retv = S_FALSE;
1594            }
1595         
1596          ++p;
1597         
1598        } 
1599      while (*p != '\0');
1600    }
1601
1602  if (escp == 0)
1603    return retv;
1604  else
1605    return S_FALSE;
1606}
1607
1608/* this is not a real XML parser, but it copes with the XML format of
1609 * the log messages provided by sh_error_handle()
1610 */
1611static
1612char *  sh_database_parse (char * message, dbins * db_entry)
1613{
1614  static  int first = S_TRUE;
1615  char  * p;
1616  char  * q;
1617  char  * z;
1618  dbins * new;
1619  int     i;
1620  size_t  j;
1621  my_attr * res;
1622  my_attr key;
1623  char    key_str[64];
1624
1625  SL_ENTER(_("sh_database_parse"));
1626
1627  if (!message || *message == '\0')
1628    SL_RETURN (NULL, _("sh_database_parse"));
1629
1630  if (first == S_TRUE)
1631    {
1632      init_attr_table();
1633      first = S_FALSE;
1634    }
1635
1636  p = strchr (message, '<');
1637  if (!p)
1638    SL_RETURN (NULL, _("sh_database_parse"));
1639
1640  while ((*p != '\0') && (*p != '>'))
1641    {
1642      if (p[0] == 'l' && p[1] == 'o' && p[2] == 'g' &&
1643          (p[3] == ' ' || p[3] == '>'))
1644        {
1645          p = &p[4];
1646          goto parse;
1647        }
1648      else if (p[0] == '/' && p[1] == '>')
1649        SL_RETURN (&p[2], _("sh_database_parse"));
1650      else if (p[0] == '/' && p[1] == 'l' && p[2] == 'o' && 
1651          p[3] == 'g' && p[4] == '>')
1652        SL_RETURN (&p[5], _("sh_database_parse"));
1653      ++p;
1654    }
1655  SL_RETURN(NULL, _("sh_database_parse")); 
1656
1657 parse:
1658
1659  while (*p == ' ' || *p == '>')
1660    ++p;
1661
1662  if (*p == '\0')
1663    SL_RETURN(NULL, _("sh_database_parse"));
1664
1665  if (*p != '<' && *p != '/')
1666    goto par2;
1667
1668  if (p[0] == '<' && p[1] == 'l' &&
1669      p[2] == 'o' && p[3] == 'g')
1670    {
1671      /*
1672       * recursive call
1673       */
1674      new       = SH_ALLOC(sizeof(dbins));
1675      init_db_entry(new);
1676      db_entry->next = new;
1677      p = sh_database_parse (p, new);
1678    }
1679
1680  if (p[0] == '/' && p[1] == '>')
1681    SL_RETURN (&p[1], _("sh_database_parse"));
1682 
1683  if (p[0] == '<' && p[1] == '/' && p[2] == 'l' &&
1684      p[3] == 'o' && p[4] == 'g' && p[5] == '>')
1685    SL_RETURN (&p[5], _("sh_database_parse"));
1686
1687 par2:
1688
1689  /* non-whitespace
1690   */
1691  for (i=0; i < 64; ++i)
1692    {
1693      if (p[i] != '=')
1694        {
1695          key_str[i] = p[i];
1696        }
1697      else
1698        {
1699          key_str[i] = '\0';
1700          break;
1701        }
1702    }
1703  key_str[63] = '\0';
1704  key.attr = &key_str[0];
1705
1706  res = bsearch(&key, attr_tab_srch, attr_tab_srch_siz,
1707                sizeof(my_attr), sh_database_comp_attr);
1708
1709  if (res != NULL)
1710    {
1711      j = res->alen; /* strlen(attr_tab[i].attr); */
1712      if (p[j] == '=' && p[j+1] == '"')
1713        {
1714          q = strchr(&p[j+2], '"');
1715          if (q)
1716            {
1717              *q = '\0';
1718
1719              if (S_TRUE == is_escaped(&p[j+2])) {
1720
1721                if      (res->val == 1)
1722                  (void) sl_strlcpy(db_entry->sev, &p[j+2], 
1723                                    (size_t)res->size);
1724                else if (res->val == 2)
1725                  {
1726                    z = strchr(&p[j+2], 'T');
1727                    if (z) *z = ' ';
1728                    (void) sl_strlcpy(db_entry->time, &p[j+2],  20);
1729                  }
1730                else if (res->val == 3)
1731                  (void) sl_strlcpy(db_entry->host, &p[j+2], 
1732                                    (size_t) res->size);
1733                else if (res->val == 4)
1734                  (void) sl_strlcpy(db_entry->msg,  &p[j+2], 
1735                                    (size_t) res->size);
1736                else if (res->size != 0)
1737                  {
1738                    (void) sl_strlcpy( (((char *)(db_entry))+ res->off),
1739                                       &p[j+2], 
1740                                       (size_t) res->size);
1741                  }
1742                else if (res->val >= START_SEC_LONGS && res->val <= END_SEC_LONGS)
1743                  {
1744                    db_entry->ulong_data[res->val-START_SEC_LONGS]
1745                      = strtoul(&p[j+2], (char **) NULL, 0);
1746                  }
1747
1748                *q = '"';
1749                p  = q; 
1750                ++p;
1751
1752                goto parse;
1753              }
1754              else { /* S_FALSE == is_escaped(&p[j+2]) */
1755                sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1756                                _("Message not properly escaped"), 
1757                                _("sh_database_parse"));
1758                SL_RETURN(NULL, _("sh_database_parse"));
1759              }
1760            }
1761          else /* q == NULL */
1762            {
1763              SL_RETURN(NULL, _("sh_database_parse"));
1764            }
1765        }
1766    }
1767
1768  /* unknown attribute, skip
1769   */
1770  while ((p != NULL) && (*p != '\0') && (*p != ' '))
1771    ++p;
1772
1773  goto parse;
1774}
1775
1776static int enter_wrapper = 1;
1777
1778int set_enter_wrapper (const char * str)
1779{
1780  return sh_util_flagval(str, &enter_wrapper);
1781}
1782
1783/* recursively enter linked list of messages into database, last first
1784 * - last is client (if this is a client message received by client)
1785 */
1786long sh_database_insert_rec (dbins * curr, int depth, char * host)
1787{
1788  unsigned long    id = 0;
1789
1790  SL_ENTER(_("sh_database_insert_rec"));
1791
1792  if (curr->next)
1793    {
1794      /*
1795      prev = curr->next;
1796      sl_strlcpy(prev->host, curr->host, 64);
1797      id = sh_database_insert_rec (curr->next, (depth + 1));
1798      */
1799      ++depth;
1800      id = sh_database_insert_rec (curr->next, depth, curr->host);
1801    }
1802
1803  if (host) 
1804    sl_strlcpy(curr->host, host, 64);
1805
1806  if (id != 0)                       /* this is a server wrapper          */
1807    {
1808      if (enter_wrapper != 0)
1809        {
1810          id = sh_database_entry (curr, id);
1811        }
1812    }
1813  else
1814    {
1815      /*
1816       * id = -1 is the client message; log_ref will be NULL
1817       */
1818      if (depth > 0)                  /* this is a client message         */
1819        id = sh_database_entry (curr, -1);
1820      else                            /* this is a generic server message */
1821        id = sh_database_entry (curr, 0);
1822    }
1823
1824  SH_FREE(curr);
1825
1826  SL_RETURN(id, _("sh_database_insert_rec"));
1827}
1828
1829int sh_database_insert (char * message)
1830{
1831  dbins * db_entry;
1832
1833  SL_ENTER(_("sh_database_insert"));
1834
1835  db_entry        = SH_ALLOC(sizeof(dbins));
1836  init_db_entry(db_entry);
1837
1838  /* recursively parse the message into a linked list
1839   */
1840  (void) sh_database_parse (message, db_entry);
1841
1842  /* recursively enter the linked list into the database
1843   */
1844  (void) sh_database_insert_rec (db_entry, 0, NULL);
1845
1846  SL_RETURN(0, _("sh_database_insert"));
1847}
1848
1849#endif
Note: See TracBrowser for help on using the repository browser.