r11761: * fix clearing of event logs by truncating the tdb.
authorGerald Carter <jerry@samba.org>
Thu, 17 Nov 2005 20:08:59 +0000 (20:08 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:05:26 +0000 (11:05 -0500)
  This feature got broken in some of the other updates.
  Now each open handle stores an pointer to an open tdb
  data structure (not the tdb pointer itself).
  Clearing can be done with a simple elog_close_tdb( elog, True )
  to force a close and then calling elog_open_tdb( logname, True )
  to force an tdb truncate.  Permissions on existing tdbs are
  maintained which is important.

* We don't currently handle backup.  Haven't looked at the
  format of a backuped up eventlog to know what the deal is.
(This used to be commit 2df34c9403446d12f1ceeac38cbda5d3ba805b02)

source3/include/rpc_eventlog.h
source3/rpc_server/srv_eventlog_lib.c
source3/rpc_server/srv_eventlog_nt.c
source3/script/mkproto.awk

index 67e03edbc6e393b87da72f7347fb14a2864c4873..5bede97d1c9ca5886e8b736ac96cb3f19a729913 100644 (file)
 #define ELOG_SYS       "System"
 #define ELOG_SEC       "Security"
 
+typedef struct elog_tdb {
+       struct elog_tdb *prev, *next;
+       char *name;
+       TDB_CONTEXT *tdb;
+       int ref_count;
+} ELOG_TDB;
+
+#define ELOG_TDB_CTX(x) ((x)->tdb)
+
+
 #define  EVENTLOG_DATABASE_VERSION_V1    1
 
 /***********************************/
index b21c2a2529fd6158713b675e884b180f370d5f2c..ec5edf2f3478db77f1c2f0583b5165b4f7317dfd 100644 (file)
 
 /* maintain a list of open eventlog tdbs with reference counts */
 
-struct elog_open_tdb {
-       struct elog_open_tdb *prev, *next;
-       char *name;
-       TDB_CONTEXT *tdb;
-       int ref_count;
-};
-
-static struct elog_open_tdb *open_elog_list;
+static ELOG_TDB *open_elog_list;
 
 /********************************************************************
  Init an Eventlog TDB, and return it. If null, something bad 
@@ -317,14 +310,14 @@ BOOL can_write_to_eventlog( TDB_CONTEXT * tdb, int32 needed )
 /*******************************************************************
 *******************************************************************/
 
-TDB_CONTEXT *elog_open_tdb( char *logname )
+ELOG_TDB *elog_open_tdb( char *logname, BOOL force_clear )
 {
-       TDB_CONTEXT *tdb;
+       TDB_CONTEXT *tdb = NULL;
        uint32 vers_id;
-       struct elog_open_tdb *ptr;
+       ELOG_TDB *ptr;
        char *tdbfilename;
        pstring tdbpath;
-       struct elog_open_tdb *tdb_node;
+       ELOG_TDB *tdb_node = NULL;
        char *eventlogdir;
 
        /* first see if we have an open context */
@@ -332,7 +325,19 @@ TDB_CONTEXT *elog_open_tdb( char *logname )
        for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
                if ( strequal( ptr->name, logname ) ) {
                        ptr->ref_count++;
-                       return ptr->tdb;                
+
+                       /* trick to alow clearing of the eventlog tdb.
+                          The force_clear flag should imply that someone
+                          has done a force close.  So make sure the tdb 
+                          is NULL.  If this is a normal open, then just 
+                          return the existing reference */
+
+                       if ( force_clear ) {
+                               SMB_ASSERT( ptr->tdb == NULL );
+                               break;
+                       }
+                       else
+                               return ptr;
                }
        }
        
@@ -348,27 +353,41 @@ TDB_CONTEXT *elog_open_tdb( char *logname )
        pstrcpy( tdbpath, tdbfilename );
        SAFE_FREE( tdbfilename );
 
-       DEBUG(7,("elog_open_tdb: Opening %s...\n", tdbpath ));
+       DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n", 
+               tdbpath, force_clear?"True":"False" ));
+               
+       /* the tdb wasn't already open or this is a forced clear open */
 
-       tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, O_RDWR , 0 );      
-       if ( tdb ) {
-               vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
+       if ( !force_clear ) {
 
-               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 );
+               tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, O_RDWR , 0 );      
+               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 );
+                       }
                }
        }
-       else {
+       
+       if ( !tdb )
                tdb = elog_init_tdb( tdbpath );
-       }
        
        /* if we got a valid context, then add it to the list */
        
        if ( tdb ) {
-               if ( !(tdb_node = TALLOC_ZERO_P( NULL, struct elog_open_tdb )) ) {
+               /* 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)) ) {
                        DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
                        tdb_close( tdb );
                        return NULL;
@@ -381,42 +400,34 @@ TDB_CONTEXT *elog_open_tdb( char *logname )
                DLIST_ADD( open_elog_list, tdb_node );
        }
 
-       return tdb;
+       return tdb_node;
 }
 
 /*******************************************************************
  Wrapper to handle reference counts to the tdb
 *******************************************************************/
 
-int elog_close_tdb( TDB_CONTEXT *tdb )
+int elog_close_tdb( ELOG_TDB *etdb, BOOL force_close )
 {
-       struct elog_open_tdb *ptr;
+       TDB_CONTEXT *tdb;
 
-       if ( !tdb )
+       if ( !etdb )
                return 0;
                
-       /* See if we can just decrement the ref_count.
-          Just compare pointer values (not names ) */
-       
-       for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
-               if ( tdb == ptr->tdb ) {
-                       ptr->ref_count--;
-                       break;
-               }
-       }
+       etdb->ref_count--;
        
-       /* if we have a NULL pointer; it means we are trying to 
-          close a tdb not in the list of open eventlogs */
-          
-       SMB_ASSERT( ptr != NULL );
-       if ( !ptr )
+       SMB_ASSERT( etdb->ref_count >= 0 );
+
+       if ( etdb->ref_count == 0 ) {
+               tdb = etdb->tdb;
+               DLIST_REMOVE( open_elog_list, etdb );
+               TALLOC_FREE( etdb );
                return tdb_close( tdb );
+       }
        
-       SMB_ASSERT( ptr->ref_count >= 0 );
-
-       if ( ptr->ref_count == 0 ) {
-               DLIST_REMOVE( open_elog_list, ptr );
-               TALLOC_FREE( ptr );
+       if ( force_close ) {
+               tdb = etdb->tdb;
+               etdb->tdb = NULL;
                return tdb_close( tdb );
        }
 
index 0f0b73029ac25f8e285e63550d0efb7eb59780c7..05feb51f95064bb664724ac2bed87c929b485e43 100644 (file)
@@ -27,7 +27,7 @@
 
 typedef struct {
        char *logname;
-       TDB_CONTEXT *tdb;
+       ELOG_TDB *etdb;
        uint32 current_record;
        uint32 num_records;
        uint32 oldest_entry;
@@ -42,8 +42,8 @@ static void free_eventlog_info( void *ptr )
 {
        EVENTLOG_INFO *elog = (EVENTLOG_INFO *)ptr;
        
-       if ( elog->tdb )
-               elog_close_tdb( elog->tdb );
+       if ( elog->etdb )
+               elog_close_tdb( elog->etdb, False );
        
        TALLOC_FREE( elog );
 }
@@ -139,17 +139,17 @@ static BOOL get_num_records_hook( EVENTLOG_INFO * info )
        int next_record;
        int oldest_record;
 
-       if ( !info->tdb ) {
+       if ( !info->etdb ) {
                DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
                return False;
        }
 
        /* lock the tdb since we have to get 2 records */
 
-       tdb_lock_bystring( info->tdb, EVT_NEXT_RECORD, 1 );
-       next_record = tdb_fetch_int32( info->tdb, EVT_NEXT_RECORD);
-       oldest_record = tdb_fetch_int32( info->tdb, EVT_OLDEST_ENTRY);
-       tdb_unlock_bystring( info->tdb, EVT_NEXT_RECORD);
+       tdb_lock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
+       next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
+       oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
+       tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
 
        DEBUG( 8,
               ( "Oldest Record %d; Next Record %d\n", oldest_record,
@@ -193,10 +193,10 @@ static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hn
           in a single process */
 
        become_root();
-       elog->tdb = elog_open_tdb( elog->logname );
+       elog->etdb = elog_open_tdb( elog->logname, False );
        unbecome_root();
 
-       if ( !elog->tdb ) {
+       if ( !elog->etdb ) {
                /* according to MSDN, if the logfile cannot be found, we should
                  default to the "Application" log */
        
@@ -213,11 +213,11 @@ static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hn
                        }
        
                        become_root();
-                       elog->tdb = elog_open_tdb( elog->logname );
+                       elog->etdb = elog_open_tdb( elog->logname, False );
                        unbecome_root();
                }       
                
-               if ( !elog->tdb ) {
+               if ( !elog->etdb ) {
                        TALLOC_FREE( elog );
                        return NT_STATUS_ACCESS_DENIED; /* ??? */               
                }
@@ -226,7 +226,7 @@ static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hn
        /* now do the access check.  Close the tdb if we fail here */
 
        if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
-               elog_close_tdb( elog->tdb );
+               elog_close_tdb( elog->etdb, False );
                TALLOC_FREE( elog );
                return NT_STATUS_ACCESS_DENIED;
        }
@@ -268,12 +268,12 @@ static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
 
 static int elog_size( EVENTLOG_INFO *info )
 {
-       if ( !info || !info->tdb ) {
+       if ( !info || !info->etdb ) {
                DEBUG(0,("elog_size: Invalid info* structure!\n"));
                return 0;
        }
 
-       return elog_tdb_size( info->tdb, NULL, NULL );
+       return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
 }
 
 /********************************************************************
@@ -397,7 +397,7 @@ static BOOL sync_eventlog_params( EVENTLOG_INFO *info )
 
        DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
 
-       if ( !info->tdb ) {
+       if ( !info->etdb ) {
                DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
                return False;
        }
@@ -440,8 +440,8 @@ static BOOL sync_eventlog_params( EVENTLOG_INFO *info )
 
        regkey_close_internal( keyinfo );
 
-       tdb_store_int32( info->tdb, EVT_MAXSIZE, uiMaxSize );
-       tdb_store_int32( info->tdb, EVT_RETENTION, uiRetention );
+       tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
+       tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
 
        return True;
 }
@@ -610,7 +610,7 @@ NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
        DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
 
        sync_eventlog_params( info );
-       prune_eventlog( info->tdb );
+       prune_eventlog( ELOG_TDB_CTX(info->etdb) );
 
        return NT_STATUS_OK;
 }
@@ -634,20 +634,26 @@ NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
                rpcstr_pull( backup_file_name, q_u->backupfile.string->buffer,
                             sizeof( backup_file_name ),
                             q_u->backupfile.string->uni_str_len * 2, 0 );
+
+               DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
+                       "file name for log [%s].",
+                        backup_file_name, info->logname ) );
        }
 
-       DEBUG( 8,
-              ( "_eventlog_clear_eventlog: Using [%s] as the backup file name for log [%s].",
-                backup_file_name, info->logname ) );
+       /* check for WRITE access to the file */
+
+       if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
+               return NT_STATUS_ACCESS_DENIED;
 
-#if 0 
-       /* close the current one, reinit */
+       /* Force a close and reopen */
 
-       tdb_close( info->tdb ); 
+       elog_close_tdb( info->etdb, True ); 
+       become_root();
+       info->etdb = elog_open_tdb( info->logname, True );
+       unbecome_root();
 
-       if ( !(info->tdb = elog_init_tdb( ttdb[i].tdbfname )) )
+       if ( !info->etdb )
                return NT_STATUS_ACCESS_DENIED;
-#endif
 
        return NT_STATUS_OK;
 }
@@ -680,7 +686,7 @@ NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
 
        bytes_left = q_u->max_read_size;
 
-       if ( !info->tdb ) 
+       if ( !info->etdb ) 
                return NT_STATUS_ACCESS_DENIED;
                
        /* check for valid flags.  Can't use the sequential and seek flags together */
@@ -706,7 +712,7 @@ NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
 
                /* assume that when the record fetch fails, that we are done */
 
-               if ( !get_eventlog_record ( ps, info->tdb, record_number, &entry ) ) 
+               if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) ) 
                        break;
 
                DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
index 73a1c2b3f0a0f487aef2e20c163c7ce504109940..a0f3096c84207db4fc15241fe791c17172cbc991 100644 (file)
@@ -136,7 +136,7 @@ END {
     gotstart = 1;
   }
 
-  if( $0 ~ /^NODE_STATUS_STRUCT|SMB_STRUCT_DIR/ ) {
+  if( $0 ~ /^NODE_STATUS_STRUCT|SMB_STRUCT_DIR|ELOG_TDB/ ) {
     gotstart = 1;
   }