2009-01-15 20:01:30 +01:00
/*
2005-10-06 17:48:03 +00:00
* Unix SMB / CIFS implementation .
* Eventlog utility routines
* Copyright ( C ) Marcin Krzysztof Porwit 2005 ,
2005-10-14 16:07:00 +00:00
* Copyright ( C ) Brian Moran 2005.
2005-10-06 17:48:03 +00:00
* Copyright ( C ) Gerald ( Jerry ) Carter 2005.
2009-01-16 12:48:11 +01:00
* Copyright ( C ) Guenther Deschner 2009.
2009-01-15 20:01:30 +01:00
*
2005-10-06 17:48:03 +00:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
2007-07-09 19:25:36 +00:00
* the Free Software Foundation ; either version 3 of the License , or
2005-10-06 17:48:03 +00:00
* ( at your option ) any later version .
2009-01-15 20:01:30 +01:00
*
2005-10-06 17:48:03 +00:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2009-01-15 20:01:30 +01:00
*
2005-10-06 17:48:03 +00:00
* You should have received a copy of the GNU General Public License
2007-07-10 05:23:25 +00:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2005-10-06 17:48:03 +00:00
*/
# include "includes.h"
2005-10-14 16:07:00 +00:00
/* maintain a list of open eventlog tdbs with reference counts */
2005-10-06 17:48:03 +00:00
2005-11-17 20:08:59 +00:00
static ELOG_TDB * open_elog_list ;
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
/********************************************************************
2009-01-15 20:01:30 +01:00
Init an Eventlog TDB , and return it . If null , something bad
2005-10-14 16:07:00 +00:00
happened .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
TDB_CONTEXT * elog_init_tdb ( char * tdbfilename )
2005-10-06 17:48:03 +00:00
{
2005-10-14 16:07:00 +00:00
TDB_CONTEXT * tdb ;
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
DEBUG ( 10 , ( " elog_init_tdb: Initializing eventlog tdb (%s) \n " ,
tdbfilename ) ) ;
2005-10-06 17:48:03 +00:00
2009-01-15 20:01:30 +01:00
tdb = tdb_open_log ( tdbfilename , 0 , TDB_DEFAULT ,
2006-05-01 18:54:53 +00:00
O_RDWR | O_CREAT | O_TRUNC , 0660 ) ;
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
if ( ! tdb ) {
DEBUG ( 0 , ( " Can't open tdb for [%s] \n " , tdbfilename ) ) ;
2005-10-06 17:48:03 +00:00
return NULL ;
}
2005-10-14 16:07:00 +00:00
/* initialize with defaults, copy real values in here from registry */
tdb_store_int32 ( tdb , EVT_OLDEST_ENTRY , 1 ) ;
tdb_store_int32 ( tdb , EVT_NEXT_RECORD , 1 ) ;
tdb_store_int32 ( tdb , EVT_MAXSIZE , 0x80000 ) ;
tdb_store_int32 ( tdb , EVT_RETENTION , 0x93A80 ) ;
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
tdb_store_int32 ( tdb , EVT_VERSION , EVENTLOG_DATABASE_VERSION_V1 ) ;
return tdb ;
2005-10-06 17:48:03 +00:00
}
2005-10-14 16:07:00 +00:00
/********************************************************************
2009-01-15 20:01:30 +01:00
make the tdb file name for an event log , given destination buffer
2005-10-14 16:07:00 +00:00
and size . Caller must free memory .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-27 11:22:58 -08:00
char * elog_tdbname ( TALLOC_CTX * ctx , const char * name )
2005-10-14 16:07:00 +00:00
{
2007-11-27 11:22:58 -08:00
char * path = talloc_asprintf ( ctx , " %s/%s.tdb " ,
state_path ( " eventlog " ) ,
name ) ;
if ( ! path ) {
return NULL ;
}
strlower_m ( path ) ;
return path ;
2005-10-14 16:07:00 +00:00
}
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
/********************************************************************
2009-01-15 20:01:30 +01:00
this function is used to count up the number of bytes in a
2005-10-14 16:07:00 +00:00
particular TDB
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
struct trav_size_struct {
int size ;
int rec_count ;
} ;
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
static int eventlog_tdb_size_fn ( TDB_CONTEXT * tdb , TDB_DATA key , TDB_DATA data ,
2005-10-06 17:48:03 +00:00
void * state )
{
2006-07-30 16:36:56 +00:00
struct trav_size_struct * tsize = ( struct trav_size_struct * ) state ;
2009-01-15 20:01:30 +01:00
2005-10-14 16:07:00 +00:00
tsize - > size + = data . dsize ;
tsize - > rec_count + + ;
2009-01-15 20:01:30 +01:00
2005-10-06 17:48:03 +00:00
return 0 ;
}
2005-10-14 16:07:00 +00:00
/********************************************************************
2009-01-15 20:01:30 +01:00
returns the size of the eventlog , and if MaxSize is a non - null
ptr , puts the MaxSize there . This is purely a way not to have yet
another function that solely reads the maxsize of the eventlog .
2005-10-14 16:07:00 +00:00
Yeah , that ' s it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
int elog_tdb_size ( TDB_CONTEXT * tdb , int * MaxSize , int * Retention )
2005-10-06 17:48:03 +00:00
{
2005-10-14 16:07:00 +00:00
struct trav_size_struct tsize ;
2009-01-15 20:01:30 +01:00
2005-10-06 17:48:03 +00:00
if ( ! tdb )
return 0 ;
2009-01-15 20:01:30 +01:00
2005-10-14 16:07:00 +00:00
ZERO_STRUCT ( tsize ) ;
2005-10-06 17:48:03 +00:00
2005-10-14 16:07:00 +00:00
tdb_traverse ( tdb , eventlog_tdb_size_fn , & tsize ) ;
2005-10-06 17:48:03 +00:00
if ( MaxSize ! = NULL ) {
2005-10-14 16:07:00 +00:00
* MaxSize = tdb_fetch_int32 ( tdb , EVT_MAXSIZE ) ;
2005-10-06 17:48:03 +00:00
}
if ( Retention ! = NULL ) {
2005-10-14 16:07:00 +00:00
* Retention = tdb_fetch_int32 ( tdb , EVT_RETENTION ) ;
2005-10-06 17:48:03 +00:00
}
DEBUG ( 1 ,
2005-10-14 16:07:00 +00:00
( " eventlog size: [%d] for [%d] records \n " , tsize . size ,
tsize . rec_count ) ) ;
return tsize . size ;
2005-10-06 17:48:03 +00:00
}
2005-10-14 16:07:00 +00:00
/********************************************************************
Discard early event logs until we have enough for ' needed ' bytes . . .
2009-01-15 20:01:30 +01:00
NO checking done beforehand to see that we actually need to do
this , and it ' s going to pluck records one - by - one . So , it ' s best
to determine that this needs to be done before doing it .
2005-10-14 16:07:00 +00:00
2009-01-15 20:01:30 +01:00
Setting whack_by_date to True indicates that eventlogs falling
2005-10-14 16:07:00 +00:00
outside of the retention range need to go . . .
2009-01-15 20:01:30 +01:00
2005-10-14 16:07:00 +00:00
return True if we made enough room to accommodate needed bytes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-06 17:48:03 +00:00
2008-11-19 16:49:03 -08:00
static bool make_way_for_eventlogs ( TDB_CONTEXT * the_tdb , int32_t needed ,
2008-01-29 15:08:37 -06:00
bool whack_by_date )
2005-10-06 17:48:03 +00:00
{
2008-11-19 16:49:03 -08:00
int32_t start_record , i , new_start ;
int32_t end_record ;
int32_t reclen , tresv1 , trecnum , timegen , timewr ;
int nbytes , len , Retention , MaxSize ;
2005-10-06 17:48:03 +00:00
TDB_DATA key , ret ;
time_t current_time , exp_time ;
/* discard some eventlogs */
/* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
although records not necessarily guaranteed to have successive times */
/* */
/* lock */
2006-04-17 11:49:06 +00:00
tdb_lock_bystring_with_timeout ( the_tdb , EVT_NEXT_RECORD , 1 ) ;
2005-10-06 17:48:03 +00:00
/* read */
2005-10-14 16:07:00 +00:00
end_record = tdb_fetch_int32 ( the_tdb , EVT_NEXT_RECORD ) ;
start_record = tdb_fetch_int32 ( the_tdb , EVT_OLDEST_ENTRY ) ;
Retention = tdb_fetch_int32 ( the_tdb , EVT_RETENTION ) ;
MaxSize = tdb_fetch_int32 ( the_tdb , EVT_MAXSIZE ) ;
2005-10-06 17:48:03 +00:00
time ( & current_time ) ;
/* calculate ... */
exp_time = current_time - Retention ; /* discard older than exp_time */
/* todo - check for sanity in next_record */
nbytes = 0 ;
DEBUG ( 3 ,
2008-11-19 16:49:03 -08:00
( " MaxSize [%d] Retention [%d] Current Time [%u] exp_time [%u] \n " ,
MaxSize , Retention , ( unsigned int ) current_time , ( unsigned int ) exp_time ) ) ;
2005-10-06 17:48:03 +00:00
DEBUG ( 3 ,
2008-11-19 16:49:03 -08:00
( " Start Record [%u] End Record [%u] \n " ,
( unsigned int ) start_record ,
( unsigned int ) end_record ) ) ;
2005-10-06 17:48:03 +00:00
for ( i = start_record ; i < end_record ; i + + ) {
/* read a record, add the amt to nbytes */
2008-11-19 16:49:03 -08:00
key . dsize = sizeof ( int32_t ) ;
key . dptr = ( unsigned char * ) & i ;
2005-10-06 17:48:03 +00:00
ret = tdb_fetch ( the_tdb , key ) ;
if ( ret . dsize = = 0 ) {
DEBUG ( 8 ,
( " Can't find a record for the key, record [%d] \n " ,
i ) ) ;
2005-10-14 16:07:00 +00:00
tdb_unlock_bystring ( the_tdb , EVT_NEXT_RECORD ) ;
2005-10-06 17:48:03 +00:00
return False ;
}
nbytes + = ret . dsize ; /* note this includes overhead */
len = tdb_unpack ( ret . dptr , ret . dsize , " ddddd " , & reclen ,
& tresv1 , & trecnum , & timegen , & timewr ) ;
2006-06-27 00:42:24 +00:00
if ( len = = - 1 ) {
DEBUG ( 10 , ( " make_way_for_eventlogs: tdb_unpack failed. \n " ) ) ;
tdb_unlock_bystring ( the_tdb , EVT_NEXT_RECORD ) ;
2008-11-19 16:49:03 -08:00
SAFE_FREE ( ret . dptr ) ;
2006-06-27 00:42:24 +00:00
return False ;
}
2005-10-06 17:48:03 +00:00
DEBUG ( 8 ,
2008-11-19 16:49:03 -08:00
( " read record %u, record size is [%d], total so far [%d] \n " ,
( unsigned int ) i , reclen , nbytes ) ) ;
2005-10-06 17:48:03 +00:00
SAFE_FREE ( ret . dptr ) ;
/* note that other servers may just stop writing records when the size limit
2009-01-15 20:01:30 +01:00
is reached , and there are no records older than ' retention ' . This doesn ' t
like a very useful thing to do , so instead we whack ( as in sleeps with the
2005-10-06 17:48:03 +00:00
fishes ) just enough records to fit the what we need . This behavior could
be changed to ' match ' , if the need arises . */
if ( ! whack_by_date & & ( nbytes > = needed ) )
break ; /* done */
if ( whack_by_date & & ( timegen > = exp_time ) )
break ; /* done */
}
DEBUG ( 3 ,
2008-11-19 16:49:03 -08:00
( " nbytes [%d] needed [%d] start_record is [%u], should be set to [%u] \n " ,
nbytes , needed , ( unsigned int ) start_record , ( unsigned int ) i ) ) ;
2005-10-06 17:48:03 +00:00
/* todo - remove eventlog entries here and set starting record to start_record... */
new_start = i ;
if ( start_record ! = new_start ) {
for ( i = start_record ; i < new_start ; i + + ) {
2008-11-19 16:49:03 -08:00
key . dsize = sizeof ( int32_t ) ;
key . dptr = ( unsigned char * ) & i ;
2005-10-06 17:48:03 +00:00
tdb_delete ( the_tdb , key ) ;
}
2005-10-14 16:07:00 +00:00
tdb_store_int32 ( the_tdb , EVT_OLDEST_ENTRY , new_start ) ;
2005-10-06 17:48:03 +00:00
}
2005-10-14 16:07:00 +00:00
tdb_unlock_bystring ( the_tdb , EVT_NEXT_RECORD ) ;
2005-10-06 17:48:03 +00:00
return True ;
}
2005-10-14 16:07:00 +00:00
/********************************************************************
2009-01-15 20:01:30 +01:00
some hygiene for an eventlog - see how big it is , and then
calculate how many bytes we need to remove
2005-10-14 16:07:00 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-06 17:48:03 +00:00
2007-10-18 17:40:25 -07:00
bool prune_eventlog ( TDB_CONTEXT * tdb )
2005-10-06 17:48:03 +00:00
{
int MaxSize , Retention , CalcdSize ;
if ( ! tdb ) {
DEBUG ( 4 , ( " No eventlog tdb handle \n " ) ) ;
return False ;
}
2005-10-14 16:07:00 +00:00
CalcdSize = elog_tdb_size ( tdb , & MaxSize , & Retention ) ;
2005-10-06 17:48:03 +00:00
DEBUG ( 3 ,
( " Calculated size [%d] MaxSize [%d] \n " , CalcdSize ,
MaxSize ) ) ;
if ( CalcdSize > MaxSize ) {
return make_way_for_eventlogs ( tdb , CalcdSize - MaxSize ,
False ) ;
}
return make_way_for_eventlogs ( tdb , 0 , True ) ;
}
2005-10-14 16:07:00 +00:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-03 20:48:43 +01:00
static bool can_write_to_eventlog ( TDB_CONTEXT * tdb , int32_t needed )
2005-10-06 17:48:03 +00:00
{
int calcd_size ;
int MaxSize , Retention ;
/* see if we can write to the eventlog -- do a policy enforcement */
if ( ! tdb )
return False ; /* tdb is null, so we can't write to it */
if ( needed < 0 )
return False ;
MaxSize = 0 ;
Retention = 0 ;
2005-10-14 16:07:00 +00:00
calcd_size = elog_tdb_size ( tdb , & MaxSize , & Retention ) ;
2005-10-06 17:48:03 +00:00
if ( calcd_size < = MaxSize )
return True ; /* you betcha */
if ( calcd_size + needed < MaxSize )
return True ;
if ( Retention = = 0xffffffff ) {
return False ; /* see msdn - we can't write no room, discard */
}
/*
note don ' t have to test , but always good to show intent , in case changes needed
later
*/
if ( Retention = = 0x00000000 ) {
/* discard record(s) */
/* todo - decide when to remove a bunch vs. just what we need... */
return make_way_for_eventlogs ( tdb , calcd_size - MaxSize ,
True ) ;
}
return make_way_for_eventlogs ( tdb , calcd_size - MaxSize , False ) ;
}
2005-10-14 16:07:00 +00:00
/*******************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-02 14:00:01 +01:00
ELOG_TDB * elog_open_tdb ( const char * logname , bool force_clear , bool read_only )
2005-10-14 16:07:00 +00:00
{
2005-11-17 20:08:59 +00:00
TDB_CONTEXT * tdb = NULL ;
2008-11-19 16:49:03 -08:00
uint32_t vers_id ;
2005-11-17 20:08:59 +00:00
ELOG_TDB * ptr ;
2007-11-27 11:22:58 -08:00
char * tdbpath = NULL ;
2005-11-17 20:08:59 +00:00
ELOG_TDB * tdb_node = NULL ;
2005-10-14 16:07:00 +00:00
char * eventlogdir ;
2007-11-27 11:22:58 -08:00
TALLOC_CTX * ctx = talloc_tos ( ) ;
2005-10-14 16:07:00 +00:00
2009-01-22 19:46:14 +01:00
/* check for invalid options */
if ( force_clear & & read_only ) {
DEBUG ( 1 , ( " elog_open_tdb: Invalid flags \n " ) ) ;
return NULL ;
}
2005-10-14 16:07:00 +00:00
/* first see if we have an open context */
2007-11-27 11:22:58 -08:00
2005-10-14 16:07:00 +00:00
for ( ptr = open_elog_list ; ptr ; ptr = ptr - > next ) {
if ( strequal ( ptr - > name , logname ) ) {
ptr - > ref_count + + ;
2005-11-17 20:08:59 +00:00
/* trick to alow clearing of the eventlog tdb.
The force_clear flag should imply that someone
2009-01-15 20:01:30 +01:00
has done a force close . So make sure the tdb
is NULL . If this is a normal open , then just
2005-11-17 20:08:59 +00:00
return the existing reference */
if ( force_clear ) {
SMB_ASSERT ( ptr - > tdb = = NULL ) ;
break ;
}
else
return ptr ;
2005-10-14 16:07:00 +00:00
}
}
2007-11-27 11:22:58 -08:00
2005-10-14 16:07:00 +00:00
/* make sure that the eventlog dir exists */
2007-11-27 11:22:58 -08:00
2007-11-01 15:53:44 -04:00
eventlogdir = state_path ( " eventlog " ) ;
2008-10-17 12:48:19 +02:00
if ( ! directory_exist ( eventlogdir ) )
2007-11-27 11:22:58 -08:00
mkdir ( eventlogdir , 0755 ) ;
2005-10-14 16:07:00 +00:00
/* get the path on disk */
2007-11-27 11:22:58 -08:00
tdbpath = elog_tdbname ( ctx , logname ) ;
if ( ! tdbpath ) {
return NULL ;
}
DEBUG ( 7 , ( " elog_open_tdb: Opening %s...(force_clear == %s) \n " ,
2005-11-17 20:08:59 +00:00
tdbpath , force_clear ? " True " : " False " ) ) ;
2007-11-27 11:22:58 -08:00
2005-11-17 20:08:59 +00:00
/* the tdb wasn't already open or this is a forced clear open */
2005-10-14 16:07:00 +00:00
2005-11-17 20:08:59 +00:00
if ( ! force_clear ) {
2005-10-14 16:07:00 +00:00
2009-01-22 19:46:14 +01:00
tdb = tdb_open_log ( tdbpath , 0 , TDB_DEFAULT , read_only ? O_RDONLY : O_RDWR , 0 ) ;
2005-11-17 20:08:59 +00:00
if ( tdb ) {
vers_id = tdb_fetch_int32 ( tdb , EVT_VERSION ) ;
if ( vers_id ! = EVENTLOG_DATABASE_VERSION_V1 ) {
DEBUG ( 1 , ( " elog_open_tdb: Invalid version [%d] on file [%s]. \n " ,
vers_id , tdbpath ) ) ;
tdb_close ( tdb ) ;
tdb = elog_init_tdb ( tdbpath ) ;
}
2005-10-14 16:07:00 +00:00
}
}
2009-01-15 20:01:30 +01:00
2005-11-17 20:08:59 +00:00
if ( ! tdb )
2005-10-14 16:07:00 +00:00
tdb = elog_init_tdb ( tdbpath ) ;
2009-01-15 20:01:30 +01:00
2005-10-14 16:07:00 +00:00
/* if we got a valid context, then add it to the list */
2009-01-15 20:01:30 +01:00
2005-10-14 16:07:00 +00:00
if ( tdb ) {
2005-11-17 20:08:59 +00:00
/* on a forced clear, just reset the tdb context if we already
have an open entry in the list */
if ( ptr ) {
ptr - > tdb = tdb ;
return ptr ;
}
if ( ! ( tdb_node = TALLOC_ZERO_P ( NULL , ELOG_TDB ) ) ) {
2005-10-14 16:07:00 +00:00
DEBUG ( 0 , ( " elog_open_tdb: talloc() failure! \n " ) ) ;
tdb_close ( tdb ) ;
return NULL ;
}
2009-01-15 20:01:30 +01:00
2005-10-14 16:07:00 +00:00
tdb_node - > name = talloc_strdup ( tdb_node , logname ) ;
tdb_node - > tdb = tdb ;
tdb_node - > ref_count = 1 ;
2009-01-15 20:01:30 +01:00
2005-10-14 16:07:00 +00:00
DLIST_ADD ( open_elog_list , tdb_node ) ;
}
2005-11-17 20:08:59 +00:00
return tdb_node ;
2005-10-14 16:07:00 +00:00
}
/*******************************************************************
Wrapper to handle reference counts to the tdb
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-18 17:40:25 -07:00
int elog_close_tdb ( ELOG_TDB * etdb , bool force_close )
2005-10-06 17:48:03 +00:00
{
2005-11-17 20:08:59 +00:00
TDB_CONTEXT * tdb ;
2005-10-06 17:48:03 +00:00
2005-11-17 20:08:59 +00:00
if ( ! etdb )
2005-10-14 16:07:00 +00:00
return 0 ;
2009-01-15 20:01:30 +01:00
2005-11-17 20:08:59 +00:00
etdb - > ref_count - - ;
2009-01-15 20:01:30 +01:00
2005-11-17 20:08:59 +00:00
SMB_ASSERT ( etdb - > ref_count > = 0 ) ;
if ( etdb - > ref_count = = 0 ) {
tdb = etdb - > tdb ;
DLIST_REMOVE ( open_elog_list , etdb ) ;
TALLOC_FREE ( etdb ) ;
2005-10-14 16:07:00 +00:00
return tdb_close ( tdb ) ;
2005-11-17 20:08:59 +00:00
}
2009-01-15 20:01:30 +01:00
2005-11-17 20:08:59 +00:00
if ( force_close ) {
tdb = etdb - > tdb ;
etdb - > tdb = NULL ;
2005-10-14 16:07:00 +00:00
return tdb_close ( tdb ) ;
2005-10-06 17:48:03 +00:00
}
2005-10-14 16:07:00 +00:00
return 0 ;
2005-10-06 17:48:03 +00:00
}
/********************************************************************
2009-01-15 20:01:30 +01:00
Note that it ' s a pretty good idea to initialize the Eventlog_entry
structure to zero ' s before calling parse_logentry on an batch of
lines that may resolve to a record . ALSO , it ' s a good idea to
remove any linefeeds ( that ' s EOL to you and me ) on the lines
2005-10-14 16:07:00 +00:00
going in .
2005-10-06 17:48:03 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-02 17:24:28 +01:00
bool parse_logentry ( TALLOC_CTX * mem_ctx , char * line , struct eventlog_Record_tdb * entry , bool * eor )
2005-10-06 17:48:03 +00:00
{
char * start = NULL , * stop = NULL ;
start = line ;
/* empty line signyfiying record delimeter, or we're at the end of the buffer */
if ( start = = NULL | | strlen ( start ) = = 0 ) {
DEBUG ( 6 ,
( " parse_logentry: found end-of-record indicator. \n " ) ) ;
* eor = True ;
return True ;
}
if ( ! ( stop = strchr ( line , ' : ' ) ) ) {
return False ;
}
DEBUG ( 6 , ( " parse_logentry: trying to parse [%s]. \n " , line ) ) ;
if ( 0 = = strncmp ( start , " LEN " , stop - start ) ) {
/* This will get recomputed later anyway -- probably not necessary */
2009-02-02 17:24:28 +01:00
entry - > size = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " RS1 " , stop - start ) ) {
/* For now all these reserved entries seem to have the same value,
which can be hardcoded to int ( 1699505740 ) for now */
2009-02-02 17:24:28 +01:00
entry - > reserved = talloc_strdup ( mem_ctx , " eLfL " ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " RCN " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > record_number = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " TMG " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > time_generated = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " TMW " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > time_written = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " EID " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_id = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " ETP " , stop - start ) ) {
if ( strstr ( start , " ERROR " ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_type = EVENTLOG_ERROR_TYPE ;
2005-10-06 17:48:03 +00:00
} else if ( strstr ( start , " WARNING " ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_type = EVENTLOG_WARNING_TYPE ;
2005-10-06 17:48:03 +00:00
} else if ( strstr ( start , " INFO " ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_type = EVENTLOG_INFORMATION_TYPE ;
2005-10-06 17:48:03 +00:00
} else if ( strstr ( start , " AUDIT_SUCCESS " ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_type = EVENTLOG_AUDIT_SUCCESS ;
2005-10-06 17:48:03 +00:00
} else if ( strstr ( start , " AUDIT_FAILURE " ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_type = EVENTLOG_AUDIT_FAILURE ;
2005-10-06 17:48:03 +00:00
} else if ( strstr ( start , " SUCCESS " ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_type = EVENTLOG_SUCCESS ;
2005-10-06 17:48:03 +00:00
} else {
/* some other eventlog type -- currently not defined in MSDN docs, so error out */
return False ;
}
}
/*
else if ( 0 = = strncmp ( start , " NST " , stop - start ) )
{
2009-02-02 17:24:28 +01:00
entry - > num_of_strings = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
}
*/
else if ( 0 = = strncmp ( start , " ECT " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > event_category = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " RS2 " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > reserved_flags = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " CRN " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > closing_record_number = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " USL " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
entry - > sid_length = atoi ( stop + 1 ) ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " SRC " , stop - start ) ) {
stop + + ;
while ( isspace ( stop [ 0 ] ) ) {
stop + + ;
}
2009-02-02 17:24:28 +01:00
entry - > source_name_len = strlen_m_term ( stop ) ;
entry - > source_name = talloc_strdup ( mem_ctx , stop ) ;
if ( entry - > source_name_len = = ( uint32_t ) - 1 | |
entry - > source_name = = NULL ) {
2007-11-27 11:22:58 -08:00
return false ;
}
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " SRN " , stop - start ) ) {
stop + + ;
while ( isspace ( stop [ 0 ] ) ) {
stop + + ;
}
2009-02-02 17:24:28 +01:00
entry - > computer_name_len = strlen_m_term ( stop ) ;
entry - > computer_name = talloc_strdup ( mem_ctx , stop ) ;
if ( entry - > computer_name_len = = ( uint32_t ) - 1 | |
entry - > computer_name = = NULL ) {
2007-11-27 11:22:58 -08:00
return false ;
}
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " SID " , stop - start ) ) {
2009-02-02 17:24:28 +01:00
smb_ucs2_t * dummy = NULL ;
2005-10-06 17:48:03 +00:00
stop + + ;
while ( isspace ( stop [ 0 ] ) ) {
stop + + ;
}
2009-02-02 17:24:28 +01:00
entry - > sid_length = rpcstr_push_talloc ( mem_ctx ,
& dummy ,
2007-11-27 11:22:58 -08:00
stop ) ;
2009-02-05 16:36:44 +01:00
if ( entry - > sid_length = = ( uint32_t ) - 1 ) {
return false ;
}
2009-02-02 17:24:28 +01:00
entry - > sid = data_blob_talloc ( mem_ctx , dummy , entry - > sid_length ) ;
2009-02-05 16:36:44 +01:00
if ( entry - > sid . data = = NULL ) {
2007-11-27 11:22:58 -08:00
return false ;
}
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " STR " , stop - start ) ) {
2007-11-27 11:22:58 -08:00
size_t tmp_len ;
2009-02-14 18:01:20 +01:00
int num_of_strings ;
2005-10-06 17:48:03 +00:00
/* skip past initial ":" */
stop + + ;
/* now skip any other leading whitespace */
2007-11-27 11:22:58 -08:00
while ( isspace ( stop [ 0 ] ) ) {
2005-10-06 17:48:03 +00:00
stop + + ;
}
2009-02-02 17:24:28 +01:00
tmp_len = strlen_m_term ( stop ) ;
if ( tmp_len = = ( size_t ) - 1 ) {
2007-11-27 11:22:58 -08:00
return false ;
}
2009-02-14 18:01:20 +01:00
num_of_strings = entry - > num_of_strings ;
2009-02-02 17:24:28 +01:00
if ( ! add_string_to_array ( mem_ctx , stop , & entry - > strings ,
2009-02-14 18:01:20 +01:00
& num_of_strings ) ) {
2007-11-27 11:22:58 -08:00
return false ;
}
2009-02-14 18:01:20 +01:00
if ( num_of_strings > 0xffff ) {
return false ;
}
entry - > num_of_strings = num_of_strings ;
2009-02-02 17:24:28 +01:00
entry - > strings_len + = tmp_len ;
2005-10-06 17:48:03 +00:00
} else if ( 0 = = strncmp ( start , " DAT " , stop - start ) ) {
/* skip past initial ":" */
stop + + ;
/* now skip any other leading whitespace */
while ( isspace ( stop [ 0 ] ) ) {
stop + + ;
}
2009-02-02 17:24:28 +01:00
entry - > data_length = strlen_m ( stop ) ;
entry - > data = data_blob_talloc ( mem_ctx , stop , entry - > data_length ) ;
if ( ! entry - > data . data ) {
2007-11-27 11:22:58 -08:00
return false ;
2005-10-06 17:48:03 +00:00
}
} else {
/* some other eventlog entry -- not implemented, so dropping on the floor */
DEBUG ( 10 , ( " Unknown entry [%s]. Ignoring. \n " , line ) ) ;
/* For now return true so that we can keep on parsing this mess. Eventually
we will return False here . */
2007-11-27 11:22:58 -08:00
return true ;
2005-10-06 17:48:03 +00:00
}
2007-11-27 11:22:58 -08:00
return true ;
2005-10-06 17:48:03 +00:00
}
2009-01-15 20:28:30 +01:00
2009-02-04 10:01:38 +01:00
/*******************************************************************
calculate the correct fields etc for an eventlog entry
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
size_t fixup_eventlog_record_tdb ( struct eventlog_Record_tdb * r )
{
size_t size = 56 ; /* static size of integers before buffers start */
r - > source_name_len = strlen_m_term ( r - > source_name ) * 2 ;
r - > computer_name_len = strlen_m_term ( r - > computer_name ) * 2 ;
r - > strings_len = ndr_size_string_array ( r - > strings ,
r - > num_of_strings , LIBNDR_FLAG_STR_NULLTERM ) * 2 ;
/* fix up the eventlog entry structure as necessary */
r - > sid_padding = ( ( 4 - ( ( r - > source_name_len + r - > computer_name_len ) % 4 ) ) % 4 ) ;
r - > padding = ( 4 - ( ( r - > strings_len + r - > data_length ) % 4 ) ) % 4 ;
if ( r - > sid_length = = 0 ) {
/* Should not pad to a DWORD boundary for writing out the sid if there is
no SID , so just propagate the padding to pad the data */
r - > padding + = r - > sid_padding ;
r - > sid_padding = 0 ;
}
size + = r - > source_name_len ;
size + = r - > computer_name_len ;
size + = r - > sid_padding ;
size + = r - > sid_length ;
size + = r - > strings_len ;
size + = r - > data_length ;
size + = r - > padding ;
/* need another copy of length at the end of the data */
size + = sizeof ( r - > size ) ;
r - > size = size ;
return size ;
}
2009-01-15 20:28:30 +01:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct eventlog_Record_tdb * evlog_pull_record_tdb ( TALLOC_CTX * mem_ctx ,
TDB_CONTEXT * tdb ,
uint32_t record_number )
{
struct eventlog_Record_tdb * r ;
TDB_DATA data , key ;
int32_t srecno ;
enum ndr_err_code ndr_err ;
DATA_BLOB blob ;
srecno = record_number ;
key . dptr = ( unsigned char * ) & srecno ;
key . dsize = sizeof ( int32_t ) ;
data = tdb_fetch ( tdb , key ) ;
if ( data . dsize = = 0 ) {
DEBUG ( 8 , ( " evlog_pull_record_tdb: "
" Can't find a record for the key, record %d \n " ,
record_number ) ) ;
return NULL ;
}
r = talloc_zero ( mem_ctx , struct eventlog_Record_tdb ) ;
if ( ! r ) {
goto done ;
}
blob = data_blob_const ( data . dptr , data . dsize ) ;
ndr_err = ndr_pull_struct_blob ( & blob , mem_ctx , NULL , r ,
( ndr_pull_flags_fn_t ) ndr_pull_eventlog_Record_tdb ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 10 , ( " evlog_pull_record_tdb: failed to decode record %d \n " ,
record_number ) ) ;
TALLOC_FREE ( r ) ;
goto done ;
}
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( eventlog_Record_tdb , r ) ;
}
DEBUG ( 10 , ( " evlog_pull_record_tdb: retrieved entry for record %d \n " ,
record_number ) ) ;
done :
SAFE_FREE ( data . dptr ) ;
return r ;
}
2009-01-21 19:36:19 +01:00
2009-02-03 13:09:59 +01:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct EVENTLOGRECORD * evlog_pull_record ( TALLOC_CTX * mem_ctx ,
TDB_CONTEXT * tdb ,
uint32_t record_number )
{
struct eventlog_Record_tdb * t ;
struct EVENTLOGRECORD * r ;
NTSTATUS status ;
r = talloc_zero ( mem_ctx , struct EVENTLOGRECORD ) ;
if ( ! r ) {
return NULL ;
}
t = evlog_pull_record_tdb ( r , tdb , record_number ) ;
if ( ! t ) {
talloc_free ( r ) ;
return NULL ;
}
status = evlog_tdb_entry_to_evt_entry ( r , t , r ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( r ) ;
return NULL ;
}
r - > Length = r - > Length2 = ndr_size_EVENTLOGRECORD ( r , NULL , 0 ) ;
return r ;
}
2009-01-21 19:36:19 +01:00
/********************************************************************
write an eventlog entry . Note that we have to lock , read next
eventlog , increment , write , write the record , unlock
coming into this , ee has the eventlog record , and the auxilliary date
( computer name , etc . ) filled into the other structure . Before packing
into a record , this routine will calc the appropriate padding , etc . ,
and then blast out the record in a form that can be read back in
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS evlog_push_record_tdb ( TALLOC_CTX * mem_ctx ,
TDB_CONTEXT * tdb ,
struct eventlog_Record_tdb * r ,
uint32_t * record_number )
{
TDB_DATA kbuf , ebuf ;
DATA_BLOB blob ;
enum ndr_err_code ndr_err ;
int ret ;
if ( ! r ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ! can_write_to_eventlog ( tdb , r - > size ) ) {
return NT_STATUS_EVENTLOG_CANT_START ;
}
/* need to read the record number and insert it into the entry here */
/* lock */
ret = tdb_lock_bystring_with_timeout ( tdb , EVT_NEXT_RECORD , 1 ) ;
if ( ret = = - 1 ) {
return NT_STATUS_LOCK_NOT_GRANTED ;
}
/* read */
r - > record_number = tdb_fetch_int32 ( tdb , EVT_NEXT_RECORD ) ;
ndr_err = ndr_push_struct_blob ( & blob , mem_ctx , NULL , r ,
( ndr_push_flags_fn_t ) ndr_push_eventlog_Record_tdb ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
tdb_unlock_bystring ( tdb , EVT_NEXT_RECORD ) ;
return ndr_map_error2ntstatus ( ndr_err ) ;
}
/* increment the record count */
kbuf . dsize = sizeof ( int32_t ) ;
kbuf . dptr = ( uint8_t * ) & r - > record_number ;
ebuf . dsize = blob . length ;
ebuf . dptr = blob . data ;
ret = tdb_store ( tdb , kbuf , ebuf , 0 ) ;
if ( ret = = - 1 ) {
tdb_unlock_bystring ( tdb , EVT_NEXT_RECORD ) ;
return NT_STATUS_EVENTLOG_FILE_CORRUPT ;
}
ret = tdb_store_int32 ( tdb , EVT_NEXT_RECORD , r - > record_number + 1 ) ;
if ( ret = = - 1 ) {
tdb_unlock_bystring ( tdb , EVT_NEXT_RECORD ) ;
return NT_STATUS_EVENTLOG_FILE_CORRUPT ;
}
tdb_unlock_bystring ( tdb , EVT_NEXT_RECORD ) ;
if ( record_number ) {
* record_number = r - > record_number ;
}
return NT_STATUS_OK ;
}
2009-01-29 15:11:39 +01:00
2009-02-03 13:08:44 +01:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS evlog_push_record ( TALLOC_CTX * mem_ctx ,
TDB_CONTEXT * tdb ,
struct EVENTLOGRECORD * r ,
uint32_t * record_number )
{
struct eventlog_Record_tdb * t ;
NTSTATUS status ;
t = talloc_zero ( mem_ctx , struct eventlog_Record_tdb ) ;
if ( ! t ) {
return NT_STATUS_NO_MEMORY ;
}
status = evlog_evt_entry_to_tdb_entry ( t , r , t ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( t ) ;
return status ;
}
status = evlog_push_record_tdb ( mem_ctx , tdb , t , record_number ) ;
talloc_free ( t ) ;
return status ;
}
2009-01-29 15:11:39 +01:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS evlog_evt_entry_to_tdb_entry ( TALLOC_CTX * mem_ctx ,
const struct EVENTLOGRECORD * e ,
struct eventlog_Record_tdb * t )
{
uint32_t i ;
ZERO_STRUCTP ( t ) ;
t - > size = e - > Length ;
t - > reserved = e - > Reserved ;
t - > record_number = e - > RecordNumber ;
t - > time_generated = e - > TimeGenerated ;
t - > time_written = e - > TimeWritten ;
t - > event_id = e - > EventID ;
t - > event_type = e - > EventType ;
t - > num_of_strings = e - > NumStrings ;
t - > event_category = e - > EventCategory ;
t - > reserved_flags = e - > ReservedFlags ;
t - > closing_record_number = e - > ClosingRecordNumber ;
t - > stringoffset = e - > StringOffset ;
t - > sid_length = e - > UserSidLength ;
t - > sid_offset = e - > UserSidOffset ;
t - > data_length = e - > DataLength ;
t - > data_offset = e - > DataOffset ;
t - > source_name_len = 2 * strlen_m_term ( e - > SourceName ) ;
t - > source_name = talloc_strdup ( mem_ctx , e - > SourceName ) ;
NT_STATUS_HAVE_NO_MEMORY ( t - > source_name ) ;
t - > computer_name_len = 2 * strlen_m_term ( e - > Computername ) ;
t - > computer_name = talloc_strdup ( mem_ctx , e - > Computername ) ;
NT_STATUS_HAVE_NO_MEMORY ( t - > computer_name ) ;
/* t->sid_padding; */
if ( e - > UserSidLength > 0 ) {
const char * sid_str = NULL ;
smb_ucs2_t * dummy = NULL ;
sid_str = sid_string_talloc ( mem_ctx , & e - > UserSid ) ;
t - > sid_length = rpcstr_push_talloc ( mem_ctx , & dummy , sid_str ) ;
if ( t - > sid_length = = - 1 ) {
return NT_STATUS_NO_MEMORY ;
}
t - > sid = data_blob_talloc ( mem_ctx , ( uint8_t * ) dummy , t - > sid_length ) ;
NT_STATUS_HAVE_NO_MEMORY ( t - > sid . data ) ;
}
t - > strings = talloc_array ( mem_ctx , const char * , e - > NumStrings ) ;
for ( i = 0 ; i < e - > NumStrings ; i + + ) {
t - > strings [ i ] = talloc_strdup ( t - > strings , e - > Strings [ i ] ) ;
NT_STATUS_HAVE_NO_MEMORY ( t - > strings [ i ] ) ;
}
t - > strings_len = 2 * ndr_size_string_array ( t - > strings , t - > num_of_strings , LIBNDR_FLAG_STR_NULLTERM ) ;
t - > data = data_blob_talloc ( mem_ctx , e - > Data , e - > DataLength ) ;
/* t->padding = r->Pad; */
return NT_STATUS_OK ;
}
2009-02-04 18:31:04 +01:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS evlog_tdb_entry_to_evt_entry ( TALLOC_CTX * mem_ctx ,
const struct eventlog_Record_tdb * t ,
struct EVENTLOGRECORD * e )
{
uint32_t i ;
ZERO_STRUCTP ( e ) ;
e - > Length = t - > size ;
e - > Reserved = t - > reserved ;
e - > RecordNumber = t - > record_number ;
e - > TimeGenerated = t - > time_generated ;
e - > TimeWritten = t - > time_written ;
e - > EventID = t - > event_id ;
e - > EventType = t - > event_type ;
e - > NumStrings = t - > num_of_strings ;
e - > EventCategory = t - > event_category ;
e - > ReservedFlags = t - > reserved_flags ;
e - > ClosingRecordNumber = t - > closing_record_number ;
e - > StringOffset = t - > stringoffset ;
e - > UserSidLength = t - > sid_length ;
e - > UserSidOffset = t - > sid_offset ;
e - > DataLength = t - > data_length ;
e - > DataOffset = t - > data_offset ;
e - > SourceName = talloc_strdup ( mem_ctx , t - > source_name ) ;
NT_STATUS_HAVE_NO_MEMORY ( e - > SourceName ) ;
e - > Computername = talloc_strdup ( mem_ctx , t - > computer_name ) ;
NT_STATUS_HAVE_NO_MEMORY ( e - > Computername ) ;
if ( t - > sid_length > 0 ) {
const char * sid_str = NULL ;
size_t len ;
if ( ! convert_string_talloc ( mem_ctx , CH_UTF16 , CH_UNIX ,
t - > sid . data , t - > sid . length ,
2009-03-01 13:58:46 -08:00
( void * * ) & sid_str , & len , false ) ) {
2009-02-04 18:31:04 +01:00
return NT_STATUS_INVALID_SID ;
}
if ( len > 0 ) {
e - > UserSid = * string_sid_talloc ( mem_ctx , sid_str ) ;
}
}
e - > Strings = talloc_array ( mem_ctx , const char * , t - > num_of_strings ) ;
for ( i = 0 ; i < t - > num_of_strings ; i + + ) {
e - > Strings [ i ] = talloc_strdup ( e - > Strings , t - > strings [ i ] ) ;
NT_STATUS_HAVE_NO_MEMORY ( e - > Strings [ i ] ) ;
}
e - > Data = ( uint8_t * ) talloc_memdup ( mem_ctx , t - > data . data , t - > data_length ) ;
e - > Pad = talloc_strdup ( mem_ctx , " " ) ;
NT_STATUS_HAVE_NO_MEMORY ( e - > Pad ) ;
e - > Length2 = t - > size ;
return NT_STATUS_OK ;
}