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 
46 typedef 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 
57 typedef 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 
127 static my_attr * attr_tab_srch = NULL;
128 static int       attr_tab_srch_siz = 0;
129 
130 static 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)
230 typedef unsigned int uint32;
231 #elif defined(HAVE_LONG_32)
232 typedef unsigned long uint32;
233 #elif defined(HAVE_SHORT_32)
234 typedef unsigned short uint32;
235 #else
236 #error No 32 byte type found !
237 #endif
238 
239 typedef unsigned char uint8;
240 
241 typedef 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 
254 typedef unsigned char        sh_byte;
255 
256 
257 extern int md5Reset(register md5Param* p);
258 extern int md5Update(md5Param* p, const sh_byte* data, int size);
259 extern int md5Digest(md5Param* p, uint32* data);
260 
261 static char db_name[64]     = "";
262 static char db_table[64]    = "";
263 static char db_host[64]     = "";
264 static char db_user[64]     = "";
265 static char db_password[64] = "";
266 
267 static int  sh_persistent_dbconn = S_TRUE;
268 
sh_database_use_persistent(const char * str)269 int sh_database_use_persistent (const char * str)
270 {
271   return sh_util_flagval (str, &sh_persistent_dbconn);
272 }
273 
insert_value(char * ptr,const char * str)274 static 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 
init_db_entry(dbins * ptr)284 static void init_db_entry (dbins * ptr)
285 {
286   memset (ptr, 0, sizeof(dbins));
287   ptr->next = NULL;
288   return;
289 }
290 
291 
sh_database_set_database(const char * str)292 int sh_database_set_database (const char * str)
293 {
294   return insert_value (db_name, str);
295 }
sh_database_set_table(const char * str)296 int sh_database_set_table (const char * str)
297 {
298   return insert_value (db_table, str);
299 }
sh_database_set_host(const char * str)300 int sh_database_set_host (const char * str)
301 {
302   return insert_value (db_host, str);
303 }
sh_database_set_user(const char * str)304 int sh_database_set_user (const char * str)
305 {
306   return insert_value (db_user, str);
307 }
sh_database_set_password(const char * str)308 int 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 
345 static    SQLHENV     u_handle;
346 static    SQLHDBC     u_connection;
347 static    SQLHSTMT    u_statement;
348 static    SQLINTEGER  u_col;
349 static    SQLINTEGER  u_rows;
350 
sh_database_reset()351 void sh_database_reset()
352 {
353   return;
354 }
355 
356 static
sh_database_query(char * query,long * id)357 int 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 
508 static    OCIDefine * o_define;
509 static    OCIEnv    * o_environment;
510 static    OCISvcCtx * o_servicecontext;
511 static    OCIError  * o_error = NULL;
512 static    OCIStmt   * o_statement;
513 static    OCIBind   * o_bind = (OCIBind *) 0;
514 static    text        o_errormsg[512];
515 static    sb4         o_errorcode;
516 
517 static  int  connected = 0;
518 
sh_database_reset()519 void 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 
sh_stripnl(char * str)533 static 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 
544 static
sh_database_query(char * query,long * id)545 int 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 
901 static int        connection_status = S_FALSE;
902 
sh_database_reset()903 void sh_database_reset()
904 {
905   connection_status = S_FALSE;
906   return;
907 }
908 
909 static
sh_database_query(char * query,long * id)910 int 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 
1055 extern int flag_err_debug;
1056 
1057 static int        connection_status = S_FALSE;
1058 
sh_database_reset(void)1059 void sh_database_reset(void)
1060 {
1061   connection_status = S_FALSE;
1062   return;
1063 }
1064 
1065 static
sh_database_query(char * query,long * id)1066 int 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 
1218 static
null_or_val(char * end,char * val,int * size,int flag)1219 char * 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 
1250 static
sh_database_entry(dbins * db_entry,long id)1251 long 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 
sh_database_comp_attr(const void * m1,const void * m2)1475 static 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 
init_attr_table(void)1483 static 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 
sh_database_add_to_hash(const char * str)1536 int 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 
is_escaped(char * p_in)1557 static 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  */
1611 static
sh_database_parse(char * message,dbins * db_entry)1612 char *  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 
1776 static int enter_wrapper = 1;
1777 
set_enter_wrapper(const char * str)1778 int 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  */
sh_database_insert_rec(dbins * curr,int depth,char * host)1786 long 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 
sh_database_insert(char * message)1829 int 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
1850