s3-eventlog: use main talloc context in eventlog read call.
[metze/samba/wip.git] / source3 / rpc_server / srv_eventlog_nt.c
index 7501434a134033e8917115c7fbe327595c0074c7..8f5c0e8aa2cdcbce920d2be8ef7cfd828e56b3e7 100644 (file)
-/* 
+/*
  *  Unix SMB/CIFS implementation.
  *  RPC Pipe client / server routines
- *  Copyright (C) Marcin Krzysztof Porwit    2005.
- *  
+ *  Copyright (C) Marcin Krzysztof Porwit    2005,
+ *  Copyright (C) Brian Moran                2005,
+ *  Copyright (C) Gerald (Jerry) Carter      2005.
+ *
  *  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
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation; either version 3 of the License, or
  *  (at your option) any later version.
- *  
+ *
  *  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.
- *  
+ *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
+
 #include "includes.h"
 
-#undef DBGC_CLASS
+#undef  DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
 
-typedef struct eventlog_info
-{
-    /* for use by the \PIPE\eventlog policy */
-    fstring source_log_file_name;
-    fstring source_server_name;
-    fstring handle_string;
-    uint32 num_records;
-    uint32 oldest_entry;
-} Eventlog_info;
-
-static void free_eventlog_info(void *ptr)
-{
-    struct eventlog_info *info = (struct eventlog_info *)ptr;
-    memset(info->source_log_file_name, '0', sizeof(*(info->source_log_file_name)));
-    memset(info->source_server_name, '0', sizeof(*(info->source_server_name)));
-    memset(info->handle_string, '0', sizeof(*(info->handle_string)));
-    memset(info, 0, sizeof(*(info)));
-    SAFE_FREE(info);
-}
-
-static Eventlog_info *find_eventlog_info_by_hnd(pipes_struct *p,
-                                               POLICY_HND *handle)
-{
-    Eventlog_info *info = NULL;
-    
-    if(!(find_policy_by_hnd(p,handle,(void **)&info)))
-    {
-       DEBUG(2,("find_eventlog_info_by_hnd: eventlog not found.\n"));
-    }
-
-    return info;
-}
-
-void policy_handle_to_string(POLICY_HND *handle, fstring *dest)
-{
-    memset(dest, 0, sizeof(*dest));
-    snprintf((char *)dest, sizeof(*dest), "%08X-%08X-%04X-%04X-%02X%02X%02X%02X%02X",
-            handle->data1,
-            handle->data2,
-            handle->data3,
-            handle->data4,
-            handle->data5[0],
-            handle->data5[1],
-            handle->data5[2],
-            handle->data5[3],
-            handle->data5[4]);
-}
-
-/**
- * Callout to open the specified event log
- * 
- *   smbrun calling convention --
- *     INPUT: <open_cmd> <log name> <policy handle>
- *     OUTPUT: the string "SUCCESS" if the command succeeded
- *             no such string if there was a failure.
- */
-static BOOL _eventlog_open_eventlog_hook(Eventlog_info *info)
-{
-    char *cmd = lp_eventlog_open_cmd();
-    char **qlines;
-    pstring command;
-    int numlines = 0;
-    int ret;
-    int fd = -1;
-
-    if(cmd == NULL || strlen(cmd) == 0)
-    {
-       DEBUG(0, ("Must define an \"eventlog open command\" entry in the config.\n"));
-       return False;
-    }
-
-    memset(command, 0, sizeof(command));
-    slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"",
-            cmd,
-            info->source_log_file_name,
-            info->handle_string);
-
-    DEBUG(10, ("Running [%s]\n", command));
-    ret = smbrun(command, &fd);
-    DEBUGADD(10, ("returned [%d]\n", ret));
-
-    if(ret != 0)
-    {
-       if(fd != -1)
-           close(fd);
-       return False;
-    }
+typedef struct {
+       char *logname;
+       ELOG_TDB *etdb;
+       uint32 current_record;
+       uint32 num_records;
+       uint32 oldest_entry;
+       uint32 flags;
+       uint32 access_granted;
+} EVENTLOG_INFO;
 
-    qlines = fd_lines_load(fd, &numlines);
-    DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
-    close(fd);
+/********************************************************************
+ ********************************************************************/
 
-    if(numlines)
-    {
-       DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
-       if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS")))
-       {
-           DEBUGADD(10, ("Able to open [%s].\n", info->source_log_file_name));
-           file_lines_free(qlines);
-           return True;
-       }
-    }
-
-    file_lines_free(qlines);
-    return False;
-}
-
-WERROR _eventlog_open_eventlog(pipes_struct *p,
-                              EVENTLOG_Q_OPEN_EVENTLOG *q_u,
-                              EVENTLOG_R_OPEN_EVENTLOG *r_u)
-{
-    Eventlog_info *info = NULL;
-    
-    if(!q_u || !r_u)
-       return WERR_NOMEM;
-    
-    if((info = SMB_MALLOC_P(Eventlog_info)) == NULL)
-       return WERR_NOMEM;
-    
-    ZERO_STRUCTP(info);
-
-    if(q_u->servername_ptr != 0)
-    {
-       unistr2_to_ascii(info->source_server_name, &(q_u->servername), sizeof(info->source_server_name));
-    }
-    else
-    {
-       /* if servername == NULL, use the local computer */
-       fstrcpy(info->source_server_name, global_myname());
-    }
-    DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the server name.\n", info->source_server_name));
-
-    if(q_u->sourcename_ptr != 0)
-    {
-       unistr2_to_ascii(info->source_log_file_name, &(q_u->sourcename), sizeof(info->source_log_file_name));
-    }
-    else
-    {
-        /* if sourcename == NULL, default to "Application" log */
-       fstrcpy(info->source_log_file_name, "Application");
-    }
-    DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the source log file.\n", info->source_log_file_name));
-
-    if(!create_policy_hnd(p, &(r_u->handle), free_eventlog_info, (void *)info))
-       return WERR_NOMEM;
-
-    policy_handle_to_string(&r_u->handle, &info->handle_string);
-
-    if(!(_eventlog_open_eventlog_hook(info)))
-       return WERR_BADFILE;
-
-    return WERR_OK;
-}
-/**
- * Callout to get the number of records in the specified event log
- * 
- *   smbrun calling convention --
- *     INPUT: <get_num_records_cmd> <log name> <policy handle>
- *     OUTPUT: A single line with a single integer containing the number of
- *             entries in the log. If there are no entries in the log, return 0.
- */
-static BOOL _eventlog_get_num_records_hook(Eventlog_info *info)
-{
-    char *cmd = lp_eventlog_num_records_cmd();
-    char **qlines;
-    pstring command;
-    int numlines = 0;
-    int ret;
-    int fd = -1;
-
-    if(cmd == NULL || strlen(cmd) == 0)
-    {
-       DEBUG(0, ("Must define an \"eventlog num records command\" entry in the config.\n"));
-       return False;
-    }
-
-    memset(command, 0, sizeof(command));
-    slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"", 
-            cmd,
-            info->source_log_file_name,
-            info->handle_string);
-
-    DEBUG(10, ("Running [%s]\n", command));
-    ret = smbrun(command, &fd);
-    DEBUGADD(10, ("returned [%d]\n", ret));
-
-    if(ret != 0)
-    {
-       if(fd != -1)
-           close(fd);
-       return False;
-    }
+static int eventlog_info_destructor(EVENTLOG_INFO *elog)
+{
+       if (elog->etdb) {
+               elog_close_tdb(elog->etdb, false);
+       }
+       return 0;
+}
 
-    qlines = fd_lines_load(fd, &numlines);
-    DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
-    close(fd);
+/********************************************************************
+ ********************************************************************/
 
-    if(numlines)
-    {
-       DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
-       sscanf(qlines[0], "%d", &(info->num_records));
-       file_lines_free(qlines);
-       return True;
-    }
+static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
+                                               POLICY_HND * handle )
+{
+       EVENTLOG_INFO *info;
 
-    file_lines_free(qlines);
-    return False;
+       if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
+               DEBUG( 2,
+                      ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
+               return NULL;
+       }
+
+       return info;
 }
 
-WERROR _eventlog_get_num_records(pipes_struct *p,
-                                EVENTLOG_Q_GET_NUM_RECORDS *q_u,
-                                EVENTLOG_R_GET_NUM_RECORDS *r_u)
+/********************************************************************
+********************************************************************/
+
+static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
 {
-    Eventlog_info *info = NULL;
-    POLICY_HND *handle = NULL;
+       char *tdbname = elog_tdbname(talloc_tos(), info->logname );
+       SEC_DESC *sec_desc;
+       NTSTATUS status;
+
+       if ( !tdbname )
+               return False;
+
+       /* get the security descriptor for the file */
 
-    if(!q_u || !r_u)
-       return WERR_NOMEM;
+       sec_desc = get_nt_acl_no_snum( info, tdbname );
+       TALLOC_FREE( tdbname );
 
-    handle = &(q_u->handle);
-    info = find_eventlog_info_by_hnd(p, handle);
+       if ( !sec_desc ) {
+               DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
+                       tdbname));
+               return False;
+       }
+
+       /* root free pass */
+
+       if ( geteuid() == sec_initial_uid() ) {
+               DEBUG(5,("elog_check_access: using root's token\n"));
+               token = get_root_nt_token();
+       }
 
-    if(!(_eventlog_get_num_records_hook(info)))
-       return WERR_BADFILE;
+       /* run the check, try for the max allowed */
 
-    r_u->num_records = info->num_records;
+       status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
+               &info->access_granted);
 
-    return WERR_OK;
+       if ( sec_desc )
+               TALLOC_FREE( sec_desc );
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(8,("elog_check_access: se_access_check() return %s\n",
+                       nt_errstr(status)));
+               return False;
+       }
+
+       /* we have to have READ permission for a successful open */
+
+       return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
 }
-/**
- * Callout to find the oldest record in the log
- * 
- *   smbrun calling convention --
- *     INPUT: <oldest_entry_cmd> <log name> <policy handle>
- *     OUTPUT: If there are entries in the event log, the index of the
- *             oldest entry. Must be 1 or greater.
- *             If there are no entries in the log, returns a 0
- */
-static BOOL _eventlog_get_oldest_entry_hook(Eventlog_info *info)
-{
-    char *cmd = lp_eventlog_oldest_record_cmd();
-    char **qlines;
-    pstring command;
-    int numlines = 0;
-    int ret;
-    int fd = -1;
-
-    if(cmd == NULL || strlen(cmd) == 0)
-    {
-       DEBUG(0, ("Must define an \"eventlog oldest record command\" entry in the config.\n"));
-       return False;
-    }
-
-    memset(command, 0, sizeof(command));
-    slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"", 
-            cmd,
-            info->source_log_file_name,
-            info->handle_string);
-
-    DEBUG(10, ("Running [%s]\n", command));
-    ret = smbrun(command, &fd);
-    DEBUGADD(10, ("returned [%d]\n", ret));
-
-    if(ret != 0)
-    {
-       if(fd != -1)
-           close(fd);
+
+/********************************************************************
+ ********************************************************************/
+
+static bool elog_validate_logname( const char *name )
+{
+       int i;
+       const char **elogs = lp_eventlog_list();
+
+       if (!elogs) {
+               return False;
+       }
+
+       for ( i=0; elogs[i]; i++ ) {
+               if ( strequal( name, elogs[i] ) )
+                       return True;
+       }
+
        return False;
-    }
+}
 
-    qlines = fd_lines_load(fd, &numlines);
-    DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
-    close(fd);
+/********************************************************************
+********************************************************************/
+
+static bool get_num_records_hook( EVENTLOG_INFO * info )
+{
+       int next_record;
+       int oldest_record;
+
+       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_with_timeout( 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,
+                next_record ) );
+
+       info->num_records = ( next_record - oldest_record );
+       info->oldest_entry = oldest_record;
 
-    if(numlines)
-    {
-       DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
-       sscanf(qlines[0], "%d", &(info->oldest_entry));
-       file_lines_free(qlines);
        return True;
-    }
+}
+
+/********************************************************************
+ ********************************************************************/
 
-    file_lines_free(qlines);
-    return False;
+static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
+{
+       /* it's the same thing */
+       return get_num_records_hook( info );
 }
 
-WERROR _eventlog_get_oldest_entry(pipes_struct *p,
-                                 EVENTLOG_Q_GET_OLDEST_ENTRY *q_u,
-                                 EVENTLOG_R_GET_OLDEST_ENTRY *r_u)
+/********************************************************************
+ ********************************************************************/
+
+static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
 {
-    Eventlog_info *info = NULL;
-    POLICY_HND *handle = NULL;
+       EVENTLOG_INFO *elog;
+
+       /* first thing is to validate the eventlog name */
+       
+       if ( !elog_validate_logname( logname ) )
+               return NT_STATUS_OBJECT_PATH_INVALID;
+
+       if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
+               return NT_STATUS_NO_MEMORY;
+       talloc_set_destructor(elog, eventlog_info_destructor);
+
+       elog->logname = talloc_strdup( elog, logname );
+
+       /* Open the tdb first (so that we can create any new tdbs if necessary).
+          We have to do this as root and then use an internal access check
+          on the file permissions since you can only have a tdb open once
+          in a single process */
+
+       become_root();
+       elog->etdb = elog_open_tdb( elog->logname, False );
+       unbecome_root();
+
+       if ( !elog->etdb ) {
+               /* according to MSDN, if the logfile cannot be found, we should
+                 default to the "Application" log */
+
+               if ( !strequal( logname, ELOG_APPL ) ) {
+
+                       TALLOC_FREE( elog->logname );
+
+                       elog->logname = talloc_strdup( elog, ELOG_APPL );
+
+                       /* do the access check */
+                       if ( !elog_check_access( elog, p->server_info->ptok ) ) {
+                               TALLOC_FREE( elog );
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+
+                       become_root();
+                       elog->etdb = elog_open_tdb( elog->logname, False );
+                       unbecome_root();
+               }
+
+               if ( !elog->etdb ) {
+                       TALLOC_FREE( elog );
+                       return NT_STATUS_ACCESS_DENIED; /* ??? */
+               }
+       }
+
+       /* now do the access check.  Close the tdb if we fail here */
 
-    if(!q_u || !r_u)
-       return WERR_NOMEM;
+       if ( !elog_check_access( elog, p->server_info->ptok ) ) {
+               TALLOC_FREE( elog );
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       /* create the policy handle */
 
-    handle = &(q_u->handle);
-    info = find_eventlog_info_by_hnd(p, handle);
+       if ( !create_policy_hnd( p, hnd, elog ) ) {
+               TALLOC_FREE(elog);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-    if(!(_eventlog_get_oldest_entry_hook(info)))
-       return WERR_BADFILE;
+       /* set the initial current_record pointer */
+
+       if ( !get_oldest_entry_hook( elog ) ) {
+               DEBUG(3,("elog_open: Successfully opened eventlog but can't "
+                       "get any information on internal records!\n"));
+       }
 
-    r_u->oldest_entry = info->oldest_entry;
+       elog->current_record = elog->oldest_entry;
 
-    return WERR_OK;
+       return NT_STATUS_OK;
 }
 
-/**
- * Callout to close the specified event log
- * 
- *   smbrun calling convention --
- *     INPUT: <close_cmd> <log name> <policy handle>
- *     OUTPUT: the string "SUCCESS" if the command succeeded
- *             no such string if there was a failure.
- */
-static BOOL _eventlog_close_eventlog_hook(Eventlog_info *info)
-{
-    char *cmd = lp_eventlog_close_cmd();
-    char **qlines;
-    pstring command;
-    int numlines = 0;
-    int ret;
-    int fd = -1;
-
-    if(cmd == NULL || strlen(cmd) == 0)
-    {
-       DEBUG(0, ("Must define an \"eventlog close command\" entry in the config.\n"));
-       return False;
-    }
-
-    memset(command, 0, sizeof(command));
-    slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"", 
-            cmd, 
-            info->source_log_file_name, 
-            info->handle_string);
-
-    DEBUG(10, ("Running [%s]\n", command));
-    ret = smbrun(command, &fd);
-    DEBUGADD(10, ("returned [%d]\n", ret));
-
-    if(ret != 0)
-    {
-       if(fd != -1)
-           close(fd);
-       return False;
-    }
+/********************************************************************
+ ********************************************************************/
 
-    qlines = fd_lines_load(fd, &numlines);
-    DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
-    close(fd);
+static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
+{
+        if ( !( close_policy_hnd( p, hnd ) ) ) {
+                return NT_STATUS_INVALID_HANDLE;
+        }
 
-    if(numlines)
-    {
-       DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
-       if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS")))
-       {
-           DEBUGADD(10, ("Able to close [%s].\n", info->source_log_file_name));
-           file_lines_free(qlines);
-           return True;
+       return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ *******************************************************************/
+
+static int elog_size( EVENTLOG_INFO *info )
+{
+       if ( !info || !info->etdb ) {
+               DEBUG(0,("elog_size: Invalid info* structure!\n"));
+               return 0;
        }
-    }
 
-    file_lines_free(qlines);
-    return False;
+       return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
 }
 
-WERROR _eventlog_close_eventlog(pipes_struct *p,
-                               EVENTLOG_Q_CLOSE_EVENTLOG *q_u,
-                               EVENTLOG_R_CLOSE_EVENTLOG *r_u)
+/********************************************************************
+  For the given tdb, get the next eventlog record into the passed
+  Eventlog_entry.  returns NULL if it can't get the record for some reason.
+ ********************************************************************/
+
+static Eventlog_entry *get_eventlog_record(TALLOC_CTX *mem_ctx,
+                               TDB_CONTEXT *tdb,
+                               int recno)
 {
-    Eventlog_info *info = NULL;
-    POLICY_HND *handle;
+       Eventlog_entry *ee = NULL;
+       TDB_DATA ret, key;
+
+       int32_t srecno;
+       int32_t reclen;
+       int len;
+
+       char *wpsource = NULL;
+       char *wpcomputer = NULL;
+       char *wpsid = NULL;
+       char *wpstrs = NULL;
+       char *puserdata = NULL;
 
-    if(!q_u || !r_u)
-       return WERR_NOMEM;
+       key.dsize = sizeof(int32_t);
 
-    handle = &(q_u->handle);
-    
-    info = find_eventlog_info_by_hnd(p, handle);
-    if(!(_eventlog_close_eventlog_hook(info)))
-       return WERR_BADFILE;
+       srecno = recno;
+       key.dptr = (unsigned char *)&srecno;
 
-    if(!(close_policy_hnd(p, handle)))
-    {
-       /* WERR_NOMEM is probably not the correct error, but until I figure out a better
-          one it will have to do */
-       return WERR_NOMEM;
-    }
+       ret = tdb_fetch( tdb, key );
 
-    return WERR_OK;
+       if ( ret.dsize == 0 ) {
+               DEBUG( 8,
+                      ( "Can't find a record for the key, record %d\n",
+                        recno ) );
+               return NULL;
+       }
+
+       len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
+
+       DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
+
+       if ( !len )
+               return NULL;
+
+       ee = TALLOC_ARRAY(mem_ctx, Eventlog_entry, 1);
+       if (!ee) {
+               return NULL;
+       }
+       ZERO_STRUCTP(ee);
+
+       len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
+                         &ee->record.length, &ee->record.reserved1,
+                         &ee->record.record_number,
+                         &ee->record.time_generated,
+                         &ee->record.time_written, &ee->record.event_id,
+                         &ee->record.event_type, &ee->record.num_strings,
+                         &ee->record.event_category, &ee->record.reserved2,
+                         &ee->record.closing_record_number,
+                         &ee->record.string_offset,
+                         &ee->record.user_sid_length,
+                         &ee->record.user_sid_offset,
+                         &ee->record.data_length, &ee->record.data_offset,
+                         &ee->data_record.source_name_len, &wpsource,
+                         &ee->data_record.computer_name_len, &wpcomputer,
+                         &ee->data_record.sid_padding,
+                         &ee->record.user_sid_length, &wpsid,
+                         &ee->data_record.strings_len, &wpstrs,
+                         &ee->data_record.user_data_len, &puserdata,
+                         &ee->data_record.data_padding );
+       DEBUG( 10,
+              ( "Read record %d, len in tdb was %d\n",
+                ee->record.record_number, len ) );
+
+       /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
+          into it's 2nd argment for 'B' */
+
+       if (wpcomputer) {
+               ee->data_record.computer_name = (smb_ucs2_t *)TALLOC_MEMDUP(
+                       ee, wpcomputer, ee->data_record.computer_name_len);
+               if (!ee->data_record.computer_name) {
+                       TALLOC_FREE(ee);
+                       goto out;
+               }
+       }
+       if (wpsource) {
+               ee->data_record.source_name = (smb_ucs2_t *)TALLOC_MEMDUP(
+                       ee, wpsource, ee->data_record.source_name_len);
+               if (!ee->data_record.source_name) {
+                       TALLOC_FREE(ee);
+                       goto out;
+               }
+       }
+
+       if (wpsid) {
+               ee->data_record.sid = (smb_ucs2_t *)TALLOC_MEMDUP(
+                       ee, wpsid, ee->record.user_sid_length);
+               if (!ee->data_record.sid) {
+                       TALLOC_FREE(ee);
+                       goto out;
+               }
+       }
+       if (wpstrs) {
+               ee->data_record.strings = (smb_ucs2_t *)TALLOC_MEMDUP(
+                       ee, wpstrs, ee->data_record.strings_len);
+               if (!ee->data_record.strings) {
+                       TALLOC_FREE(ee);
+                       goto out;
+               }
+       }
+
+       if (puserdata) {
+               ee->data_record.user_data = (char *)TALLOC_MEMDUP(
+                       ee, puserdata, ee->data_record.user_data_len);
+               if (!ee->data_record.user_data) {
+                       TALLOC_FREE(ee);
+                       goto out;
+               }
+       }
+
+  out:
+
+       SAFE_FREE(wpcomputer);
+       SAFE_FREE(wpsource);
+       SAFE_FREE(wpsid);
+       SAFE_FREE(wpstrs);
+       SAFE_FREE(puserdata);
+
+       DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
+       DEBUG( 10,
+              ( "get_eventlog_record: computer_name %d is ",
+                ee->data_record.computer_name_len ) );
+       SAFE_FREE(ret.dptr);
+       return ee;
 }
 
-static BOOL _eventlog_read_parse_line(char *line, Eventlog_entry *entry)
+/********************************************************************
+ note that this can only be called AFTER the table is constructed,
+ since it uses the table to find the tdb handle
+ ********************************************************************/
+
+static bool sync_eventlog_params( EVENTLOG_INFO *info )
 {
-    char *start = NULL, *stop = NULL;
-    pstring temp;
-    int temp_len = 0, i;
-    start = line;
+       char *path = NULL;
+       uint32 uiMaxSize;
+       uint32 uiRetention;
+       struct registry_key *key;
+       struct registry_value *value;
+       WERROR wresult;
+       char *elogname = info->logname;
+       TALLOC_CTX *ctx = talloc_stackframe();
+       bool ret = false;
+
+       DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
+
+       if ( !info->etdb ) {
+               DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
+               goto done;
+       }
+       /* set resonable defaults.  512Kb on size and 1 week on time */
 
-    if(start == NULL || strlen(start) == 0)
-       return False;
-    if(!(stop = strchr(line, ':')))
-       return False;
-    
-    DEBUG(6, ("_eventlog_read_parse_line: trying to parse [%s].\n", line));
-
-    if(0 == strncmp(start, "LEN", stop - start))
-    {
-       /* This will get recomputed later anyway -- probably not necessary */
-       entry->record.length = atoi(stop + 1);
-    }
-    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 */
-       entry->record.reserved1 = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "RCN", stop - start))
-    {
-       entry->record.record_number = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "TMG", stop - start))
-    {
-       entry->record.time_generated = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "TMW", stop - start))
-    {
-       entry->record.time_written = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "EID", stop - start))
-    {
-       entry->record.event_id = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "ETP", stop - start))
-    {
-       if(strstr(start, "ERROR"))
-       {
-           entry->record.event_type = EVENTLOG_ERROR_TYPE;
+       uiMaxSize = 0x80000;
+       uiRetention = 604800;
+
+       /* the general idea is to internally open the registry
+          key and retrieve the values.  That way we can continue
+          to use the same fetch/store api that we use in
+          srv_reg_nt.c */
+
+       path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
+       if (!path) {
+               goto done;
        }
-       else if(strstr(start, "WARNING"))
-       {
-           entry->record.event_type = EVENTLOG_WARNING_TYPE;
+
+       wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
+                               &key);
+
+       if ( !W_ERROR_IS_OK( wresult ) ) {
+               DEBUG( 4,
+                      ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
+                        path, win_errstr( wresult ) ) );
+               goto done;
        }
-       else if(strstr(start, "INFO"))
-       {
-           entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
+
+       wresult = reg_queryvalue(key, key, "Retention", &value);
+       if (!W_ERROR_IS_OK(wresult)) {
+               DEBUG(4, ("Failed to query value \"Retention\": %s\n",
+                         win_errstr(wresult)));
+               goto done;
        }
-       else if(strstr(start, "AUDIT_SUCCESS"))
-       {
-           entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
+       uiRetention = value->v.dword;
+
+       wresult = reg_queryvalue(key, key, "MaxSize", &value);
+       if (!W_ERROR_IS_OK(wresult)) {
+               DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
+                         win_errstr(wresult)));
+               goto done;
        }
-       else if(strstr(start, "AUDIT_FAILURE"))
-       {
-           entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
+       uiMaxSize = value->v.dword;
+
+       tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
+       tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
+
+       ret = true;
+
+done:
+       TALLOC_FREE(ctx);
+       return ret;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static Eventlog_entry *read_package_entry( TALLOC_CTX *mem_ctx,
+                                          Eventlog_entry * entry )
+{
+       uint8 *offset;
+       Eventlog_entry *ee_new = NULL;
+
+       ee_new = TALLOC_ZERO_ARRAY(mem_ctx, Eventlog_entry, 1 );
+       if ( ee_new == NULL ) {
+               return NULL;
        }
-       else if(strstr(start, "SUCCESS"))
-       {
-           entry->record.event_type = EVENTLOG_SUCCESS;
+
+       entry->data_record.sid_padding =
+               ( ( 4 -
+                   ( ( entry->data_record.source_name_len +
+                       entry->data_record.computer_name_len ) % 4 ) ) % 4 );
+       entry->data_record.data_padding =
+               ( 4 -
+                 ( ( entry->data_record.strings_len +
+                     entry->data_record.user_data_len ) % 4 ) ) % 4;
+       entry->record.length = sizeof( Eventlog_record );
+       entry->record.length += entry->data_record.source_name_len;
+       entry->record.length += entry->data_record.computer_name_len;
+       if ( entry->record.user_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 */
+               entry->data_record.data_padding +=
+                       entry->data_record.sid_padding;
+               entry->data_record.sid_padding = 0;
        }
-       else
-       {
-           /* some other eventlog type -- currently not defined in MSDN docs, so error out */
-           return False;
+       DEBUG( 10,
+              ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
+       DEBUG( 10,
+              ( "data_padding is [%d].\n",
+                entry->data_record.data_padding ) );
+
+       entry->record.length += entry->data_record.sid_padding;
+       entry->record.length += entry->record.user_sid_length;
+       entry->record.length += entry->data_record.strings_len;
+       entry->record.length += entry->data_record.user_data_len;
+       entry->record.length += entry->data_record.data_padding;
+       /* need another copy of length at the end of the data */
+       entry->record.length += sizeof( entry->record.length );
+       DEBUG( 10,
+              ( "entry->record.length is [%d].\n", entry->record.length ) );
+       entry->data =
+               TALLOC_ZERO_ARRAY(mem_ctx, uint8_t,
+                                 entry->record.length -
+                                 sizeof( Eventlog_record ) -
+                                 sizeof( entry->record.length ));
+       if ( entry->data == NULL ) {
+               return NULL;
        }
-    }
-/*
-    else if(0 == strncmp(start, "NST", stop - start))
-    {
-       entry->record.num_strings = atoi(stop + 1);
-    }
-*/
-    else if(0 == strncmp(start, "ECT", stop - start))
-    {
-       entry->record.event_category = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "RS2", stop - start))
-    {
-       entry->record.reserved2 = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "CRN", stop - start))
-    {
-       entry->record.closing_record_number = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "USL", stop - start))
-    {
-       entry->record.user_sid_length = atoi(stop + 1);
-    }
-    else if(0 == strncmp(start, "SRC", stop - start))
-    {
-       memset(temp, 0, sizeof(temp));
-       sscanf(stop+1, "%s", temp);
-       temp_len = strlen(temp);
-       rpcstr_push((void *)(entry->data_record.source_name), temp, 
-                   sizeof(entry->data_record.source_name), STR_TERMINATE);
-       entry->data_record.source_name_len = (strlen_w(entry->data_record.source_name)* 2) + 2;
-    }
-    else if(0 == strncmp(start, "SRN", stop - start))
-    {
-       memset(temp, 0, sizeof(temp));
-       sscanf(stop+1, "%s", temp);
-       temp_len = strlen(temp);
-       rpcstr_push((void *)(entry->data_record.computer_name), temp,
-                   sizeof(entry->data_record.computer_name), STR_TERMINATE);
-       entry->data_record.computer_name_len = (strlen_w(entry->data_record.computer_name)* 2) + 2;
-    }
-    else if(0 == strncmp(start, "SID", stop - start))
-    {
-       memset(temp, 0, sizeof(temp));
-       sscanf(stop+1, "%s", temp);
-       temp_len = strlen(temp);
-       rpcstr_push((void *)(entry->data_record.sid), temp,
-                   sizeof(entry->data_record.sid), STR_TERMINATE);
-       entry->record.user_sid_length = (strlen_w(entry->data_record.sid) * 2) + 2;
-    }
-    else if(0 == strncmp(start, "STR", stop - start))
-    {
-       /* skip past initial ":" */
-       stop++;
-       /* now skip any other leading whitespace */
-       while(isspace(stop[0]))
-           stop++;
-       temp_len = strlen(stop);
-       memset(temp, 0, sizeof(temp));
-       strncpy(temp, stop, temp_len);
-       rpcstr_push((void *)(entry->data_record.strings + entry->data_record.strings_len),
-                   temp,
-                   sizeof(entry->data_record.strings) - entry->data_record.strings_len, 
-                   STR_TERMINATE);
-       entry->data_record.strings_len += temp_len + 1;
-       fprintf(stderr, "Dumping strings:\n");
-       for(i = 0; i < entry->data_record.strings_len; i++)
-       {
-           fputc((char)entry->data_record.strings[i], stderr);
-       }
-       fprintf(stderr, "\nDone\n");
-       entry->record.num_strings++;
-    }
-    else if(0 == strncmp(start, "DAT", stop - start))
-    {
-       /* Now that we're done processing the STR data, adjust the length to account for
-          unicode, then proceed with the DAT data. */
-       entry->data_record.strings_len *= 2;
-       /* skip past initial ":" */
-       stop++;
-       /* now skip any other leading whitespace */
-       while(isspace(stop[0]))
-           stop++;
-       memset(temp, 0, sizeof(temp));
-       temp_len = strlen(stop);
-       strncpy(temp, stop, temp_len);
-       rpcstr_push((void *)(entry->data_record.user_data), temp,
-                   sizeof(entry->data_record.user_data), STR_TERMINATE);
-       entry->data_record.user_data_len = (strlen_w((const smb_ucs2_t *)entry->data_record.user_data) * 2) + 2;
-    }
-    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. */
+       offset = entry->data;
+       memcpy( offset, &( entry->data_record.source_name ),
+               entry->data_record.source_name_len );
+       offset += entry->data_record.source_name_len;
+       memcpy( offset, &( entry->data_record.computer_name ),
+               entry->data_record.computer_name_len );
+       offset += entry->data_record.computer_name_len;
+       /* SID needs to be DWORD-aligned */
+       offset += entry->data_record.sid_padding;
+       entry->record.user_sid_offset =
+               sizeof( Eventlog_record ) + ( offset - entry->data );
+       memcpy( offset, &( entry->data_record.sid ),
+               entry->record.user_sid_length );
+       offset += entry->record.user_sid_length;
+       /* Now do the strings */
+       entry->record.string_offset =
+               sizeof( Eventlog_record ) + ( offset - entry->data );
+       memcpy( offset, &( entry->data_record.strings ),
+               entry->data_record.strings_len );
+       offset += entry->data_record.strings_len;
+       /* Now do the data */
+       entry->record.data_length = entry->data_record.user_data_len;
+       entry->record.data_offset =
+               sizeof( Eventlog_record ) + ( offset - entry->data );
+       memcpy( offset, &( entry->data_record.user_data ),
+               entry->data_record.user_data_len );
+       offset += entry->data_record.user_data_len;
+
+       memcpy( &( ee_new->record ), &entry->record,
+               sizeof( Eventlog_record ) );
+       memcpy( &( ee_new->data_record ), &entry->data_record,
+               sizeof( Eventlog_data_record ) );
+       ee_new->data = entry->data;
+
+       return ee_new;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static bool add_record_to_resp( Eventlog_entry *entry,
+                               uint32_t *num_records,
+                               uint32_t *num_bytes_in_resp,
+                               Eventlog_entry * ee_new )
+{
+       Eventlog_entry *insert_point;
+
+       insert_point = entry;
+
+       if ( NULL == insert_point ) {
+               entry = ee_new;
+               ee_new->next = NULL;
+       } else {
+               while ( ( NULL != insert_point->next ) ) {
+                       insert_point = insert_point->next;
+               }
+               ee_new->next = NULL;
+               insert_point->next = ee_new;
+       }
+       (*num_records)++;
+       *num_bytes_in_resp += ee_new->record.length;
+
        return True;
-    }
-    return True;
 }
-/**
- * Callout to read entries from the specified event log
- *
- *   smbrun calling convention --
- *     INPUT: <read_cmd> <log name> <direction> <starting record> <buffer size> <policy handle>
- *            where direction is either "forward" or "backward", the starting record is somewhere
- *            between the oldest_record and oldest_record+num_records, and the buffer size is the
- *            maximum size of the buffer that the client can accomodate.
- *     OUTPUT: A buffer containing a set of entries, one to a line, of the format:
- *               line type:line data
- *             These are the allowed line types:
- *               RS1:(uint32) - reserved. All M$ entries seem to have int(1699505740) for now
- *               RCN:(uint32) - record number of the record, however it may be calculated by the script
- *               TMG:(uint32) - time generated, seconds since January 1, 1970, 0000 UTC
- *               TMW:(uint32) - time written, seconds since January 1, 1970, 0000 UTC
- *               EID:(uint32) - eventlog source defined event identifier. If there's a stringfile for the event, it is an index into that
- *               ETP:(uint16) - eventlog type - one of ERROR, WARNING, INFO, AUDIT_SUCCESS, AUDIT_FAILURE
- *               ECT:(uint16) - event category - depends on the eventlog generator... 
- *               RS2:(uint16) - reserved, make it 0000
- *               CRN:(uint32) - reserved, make it 00000000 for now
- *               USL:(uint32) - user SID length. No sid? Make this 0. Must match SID below
- *               SRC:[(uint8)] - Name of the source, for example ccPwdSvc, in hex bytes. Can not be multiline.
- *               SRN:[(uint8)] - Name of the computer on which this is generated, the short hostname usually.
- *               SID:[(uint8)] - User sid if one exists. Must be present even if there is no SID.
- *               STR:[(uint8)] - String data. One string per line. Multiple strings can be specified using consecutive "STR" lines,
- *                               up to a total aggregate string length of 1024 characters.
- *               DAT:[(uint8)] - The user-defined data portion of the event log. Can not be multiple lines.
- */
-static BOOL _eventlog_read_eventlog_hook(Eventlog_info *info, Eventlog_entry *entry, const char *direction, int starting_record, int buffer_size, BOOL *eof)
+
+/********************************************************************
+ _eventlog_OpenEventLogW
+ ********************************************************************/
+
+NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
+                                struct eventlog_OpenEventLogW *r)
 {
-    char *cmd = lp_eventlog_read_cmd();
-    char **qlines;
-    pstring command;
-    int numlines = 0;
-    int ret;
-    int fd = -1;
-    int i;
+       const char *servername = "";
+       const char *logname = "";
+       EVENTLOG_INFO *info;
+       NTSTATUS result;
 
-    if(info == NULL)
-       return False;
+       if (r->in.servername->string) {
+               servername = r->in.servername->string;
+       }
 
-    if(cmd == NULL || strlen(cmd) == 0)
-    {
-       DEBUG(0, ("Must define an \"eventlog read command\" entry in the config.\n"));
-       return False;
-    }
-
-    slprintf(command, sizeof(command)-1, "%s \"%s\" %s %d %d \"%s\"",
-            cmd,
-            info->source_log_file_name,
-            direction,
-            starting_record,
-            buffer_size,
-            info->handle_string);
-
-    DEBUG(10, ("Running [%s]\n", command));
-    ret = smbrun(command, &fd);
-    DEBUGADD(10, ("returned [%d]\n", ret));
-
-    if(ret != 0)
-    {
-       if(fd != -1)
-           close(fd);
-       return False;
-    }
-
-    qlines = fd_lines_load(fd, &numlines);
-    DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
-    close(fd);
-    
-    if(numlines)
-    {
-       for(i = 0; i < numlines; i++)
-       {
-           DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i]));
-           _eventlog_read_parse_line(qlines[i], entry);
+       if (r->in.logname->string) {
+               logname = r->in.logname->string;
        }
-       file_lines_free(qlines);
-       return True;
-    }
-    else
-       *eof = True;
 
-    file_lines_free(qlines);
-    return False;
+       DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
+               servername, logname ));
+
+       /* according to MSDN, if the logfile cannot be found, we should
+         default to the "Application" log */
+
+       if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, r->out.handle )) )
+               return result;
+
+       if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
+               DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
+                       logname ));
+               elog_close( p, r->out.handle );
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
+
+       sync_eventlog_params( info );
+       prune_eventlog( ELOG_TDB_CTX(info->etdb) );
+
+       return NT_STATUS_OK;
 }
-       
-static BOOL _eventlog_read_prepare_data_buffer(prs_struct *ps,
-                                              EVENTLOG_Q_READ_EVENTLOG *q_u,
-                                              EVENTLOG_R_READ_EVENTLOG *r_u,
-                                              Eventlog_entry *entry)
+
+/********************************************************************
+ _eventlog_ClearEventLogW
+ This call still needs some work
+ ********************************************************************/
+/** The windows client seems to be doing something funny with the file name
+   A call like
+      ClearEventLog(handle, "backup_file")
+   on the client side will result in the backup file name looking like this on the
+   server side:
+      \??\${CWD of client}\backup_file
+   If an absolute path gets specified, such as
+      ClearEventLog(handle, "C:\\temp\\backup_file")
+   then it is still mangled by the client into this:
+      \??\C:\temp\backup_file
+   when it is on the wire.
+   I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
+   would be added in given that the backup file gets written on the server side. */
+
+NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
+                                 struct eventlog_ClearEventLogW *r)
 {
-    uint8 *offset;
-    Eventlog_entry *new = NULL, *insert_point = NULL;
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
+       const char *backup_file_name = NULL;
 
-    new = PRS_ALLOC_MEM(ps, Eventlog_entry, 1);
-    if(new == NULL)
-       return False;
+       if ( !info )
+               return NT_STATUS_INVALID_HANDLE;
 
-    entry->data_record.sid_padding = ((4 - ((entry->data_record.source_name_len 
-                                     + entry->data_record.computer_name_len) % 4)) %4);
-    entry->data_record.data_padding = (4 - ((entry->data_record.strings_len 
-                                          + entry->data_record.user_data_len) % 4)) % 4;
-    entry->record.length = sizeof(Eventlog_record);
-    entry->record.length += entry->data_record.source_name_len;
-    entry->record.length += entry->data_record.computer_name_len;
-    if(entry->record.user_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 */
-       entry->data_record.data_padding += entry->data_record.sid_padding;
-       entry->data_record.sid_padding = 0;
-    }
-    DEBUG(10, ("sid_padding is [%d].\n", entry->data_record.sid_padding));
-    DEBUG(10, ("data_padding is [%d].\n", entry->data_record.data_padding));
-
-    entry->record.length += entry->data_record.sid_padding;
-    entry->record.length += entry->record.user_sid_length;
-    entry->record.length += entry->data_record.strings_len;
-    entry->record.length += entry->data_record.user_data_len;
-    entry->record.length += entry->data_record.data_padding;
-    /* need another copy of length at the end of the data */
-    entry->record.length += sizeof(entry->record.length);
-    DEBUG(10, ("entry->record.length is [%d].\n", entry->record.length));
-    entry->data = PRS_ALLOC_MEM(ps, uint8, entry->record.length - sizeof(Eventlog_record) - sizeof(entry->record.length));
-    if(entry->data == NULL)
-       return False;
-    offset = entry->data;
-    memcpy(offset, &(entry->data_record.source_name), entry->data_record.source_name_len);
-    offset += entry->data_record.source_name_len;
-    memcpy(offset, &(entry->data_record.computer_name), entry->data_record.computer_name_len);
-    offset += entry->data_record.computer_name_len;
-    /* SID needs to be DWORD-aligned */
-    offset += entry->data_record.sid_padding;
-    entry->record.user_sid_offset = sizeof(Eventlog_record) + (offset - entry->data);
-    memcpy(offset, &(entry->data_record.sid), entry->record.user_sid_length);
-    offset += entry->record.user_sid_length;
-    /* Now do the strings */
-    entry->record.string_offset = sizeof(Eventlog_record) + (offset - entry->data);
-    memcpy(offset, &(entry->data_record.strings), entry->data_record.strings_len);
-    offset += entry->data_record.strings_len;
-    /* Now do the data */
-    entry->record.data_length = entry->data_record.user_data_len;
-    entry->record.data_offset = sizeof(Eventlog_record) + (offset - entry->data);
-    memcpy(offset, &(entry->data_record.user_data), entry->data_record.user_data_len);
-    offset += entry->data_record.user_data_len;
-    /* Now that we've massaged the current entry, copy it into the new entry and add it
-       to end of the list */
-    insert_point=r_u->entry;
-
-    if (NULL == insert_point) 
-    {
-       r_u->entry = new;
-       new->next = NULL;
-    } 
-    else
-    {
-       while ((NULL != insert_point->next)) 
-       {
-           insert_point=insert_point->next;
-       }
-       new->next = NULL;
-       insert_point->next = new;
-    }
-
-    memcpy(&(new->record), &entry->record, sizeof(Eventlog_record));
-    memcpy(&(new->data_record), &entry->data_record, sizeof(Eventlog_data_record));
-    new->data = entry->data;
-
-    r_u->num_records++; 
-    r_u->num_bytes_in_resp += entry->record.length;
-
-    return True;
-}
-
-WERROR _eventlog_read_eventlog(pipes_struct *p,
-                              EVENTLOG_Q_READ_EVENTLOG *q_u,
-                              EVENTLOG_R_READ_EVENTLOG *r_u)
-{
-    Eventlog_info *info = NULL;
-    POLICY_HND *handle;
-    Eventlog_entry entry;
-    BOOL eof = False;
-    const char *direction = "";
-    int starting_record;
-    prs_struct *ps;
-
-    if(!q_u || !r_u)
-       return WERR_NOMEM;
-
-    handle = &(q_u->handle);
-    info = find_eventlog_info_by_hnd(p, handle);
-    ps = &p->out_data.rdata;
-    /* Rather than checking the EVENTLOG_SEQUENTIAL_READ/EVENTLOG_SEEK_READ flags,
-       we'll just go to the offset specified in the request, or the oldest entry
-       if no offset is specified */
-    if(q_u->offset > 0)
-       starting_record = q_u->offset;
-    else
-       starting_record = info->oldest_entry;
-    if(q_u->flags & EVENTLOG_FORWARDS_READ)
-       direction = "forward";
-    else if(q_u->flags & EVENTLOG_BACKWARDS_READ)
-       direction = "backward";
-
-    do
-    {
-       ZERO_STRUCT(entry);
-       if(!(_eventlog_read_eventlog_hook(info, &entry, direction, starting_record, q_u->max_read_size, &eof)))
-       {
-           if(eof == False)
-               return WERR_NOMEM;
+       if (r->in.backupfile && r->in.backupfile->string) {
+
+               backup_file_name = r->in.backupfile->string;
+
+               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;
+
+       /* Force a close and reopen */
+
+       elog_close_tdb( info->etdb, True );
+       become_root();
+       info->etdb = elog_open_tdb( info->logname, True );
+       unbecome_root();
+
+       if ( !info->etdb )
+               return NT_STATUS_ACCESS_DENIED;
+
+       return NT_STATUS_OK;
+}
+
+/********************************************************************
+ _eventlog_CloseEventLog
+ ********************************************************************/
+
+NTSTATUS _eventlog_CloseEventLog(pipes_struct * p,
+                                struct eventlog_CloseEventLog *r)
+{
+       return elog_close( p, r->in.handle );
+}
+
+/********************************************************************
+ ********************************************************************/
+
+NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
+                               EVENTLOG_Q_READ_EVENTLOG * q_u,
+                               EVENTLOG_R_READ_EVENTLOG * r_u )
+{
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
+       Eventlog_entry *entry = NULL, *ee_new = NULL;
+       uint32 num_records_read = 0;
+       int bytes_left, record_number;
+       uint32 elog_read_type, elog_read_dir;
+
+       if (info == NULL) {
+               return NT_STATUS_INVALID_HANDLE;
        }
-       if(eof == False)
+
+       info->flags = q_u->flags;
+       ps = &p->out_data.rdata;
+
+       bytes_left = q_u->max_read_size;
+
+       if ( !info->etdb )
+               return NT_STATUS_ACCESS_DENIED;
+
+       /* check for valid flags.  Can't use the sequential and seek flags together */
+
+       elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
+       elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
+
+       if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) 
+               ||  elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
        {
-           /* only if the read hook returned data */
-           if(!(_eventlog_read_prepare_data_buffer(ps, q_u, r_u, &entry)))
-               return WERR_NOMEM;
-           DEBUG(10, ("_eventlog_read_eventlog: read [%d] bytes out of a max of [%d].\n",
-                      r_u->num_bytes_in_resp,
-                      q_u->max_read_size));
+               DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* a sequential read should ignore the offset */
+
+       if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
+               record_number = info->current_record;
+       else
+               record_number = q_u->offset;
+
+       while ( bytes_left > 0 ) {
+
+               /* assume that when the record fetch fails, that we are done */
+
+               entry = get_eventlog_record (p->mem_ctx, ELOG_TDB_CTX(info->etdb), record_number);
+               if (!entry) {
+                       break;
+               }
+
+               DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
+
+               /* Now see if there is enough room to add */
+
+               if ( !(ee_new = read_package_entry( p->mem_ctx, entry )) )
+                       return NT_STATUS_NO_MEMORY;
+
+               if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
+                       r_u->bytes_in_next_record = ee_new->record.length;
+
+                       /* response would be too big to fit in client-size buffer */
+
+                       bytes_left = 0;
+                       break;
+               }
+
+               add_record_to_resp( r_u->entry,
+                                   &r_u->num_records, &r_u->num_bytes_in_resp,
+                                   ee_new );
+
+               bytes_left -= ee_new->record.length;
+               TALLOC_FREE(entry);
+               num_records_read = r_u->num_records - num_records_read;
+
+               DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
+                       "of [%d] records using [%d] bytes out of a max of [%d].\n",
+                        num_records_read, r_u->num_records,
+                        r_u->num_bytes_in_resp,
+                        q_u->max_read_size ) );
+
+               if ( info->flags & EVENTLOG_FORWARDS_READ )
+                       record_number++;
+               else
+                       record_number--;
+
+               /* update the eventlog record pointer */
+
+               info->current_record = record_number;
        }
-    } while((r_u->num_bytes_in_resp <= q_u->max_read_size) && (eof != True));
 
-    return WERR_OK;
+       /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
+          say when there are no more records */
+
+       return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
 }
-/**
- * Callout to clear (and optionally backup) a specified event log
- *
- *   smbrun calling convention --
- *     INPUT:  <clear_eventlog_cmd> <log name> <policy handle>
- *     OUTPUT: A single line with the string "SUCCESS" if the command succeeded.
- *             Otherwise it is assumed to have failed
- *
- *     INPUT:  <clear_eventlog_cmd> <log name> <backup file> <policy handle>
- *     OUTPUT: A single line with the string "SUCCESS" if the command succeeded.
- *             Otherwise it is assumed to have failed
- *             The given log is copied to that location on the server. See comments for
- *               eventlog_io_q_clear_eventlog for info about odd file name behavior
- */
-static BOOL _eventlog_clear_eventlog_hook(Eventlog_info *info,
-                                         pstring backup_file_name)
-{
-    char *cmd = lp_eventlog_clear_cmd();
-    char **qlines;
-    pstring command;
-    int numlines = 0;
-    int ret;
-    int fd = -1;
-
-    if(cmd == NULL || strlen(cmd) == 0)
-    {
-       DEBUG(0, ("Must define an \"eventlog clear command\" entry in the config.\n"));
-       return False;
-    }
-
-    memset(command, 0, sizeof(command));
-    if(strlen(backup_file_name) > 0)
-       slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\"",
-                cmd,
-                info->source_log_file_name,
-                backup_file_name,
-                info->handle_string);
-    else
-       slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"", 
-                cmd, 
-                info->source_log_file_name, 
-                info->handle_string);
-
-    DEBUG(10, ("Running [%s]\n", command));
-    ret = smbrun(command, &fd);
-    DEBUGADD(10, ("returned [%d]\n", ret));
-
-    if(ret != 0)
-    {
-       if(fd != -1)
-           close(fd);
-       return False;
-    }
 
-    qlines = fd_lines_load(fd, &numlines);
-    DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
-    close(fd);
+/********************************************************************
+ _eventlog_GetOldestRecord
+ ********************************************************************/
 
-    if(numlines)
-    {
-       DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
-       if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS")))
-       {
-           DEBUGADD(10, ("Able to clear [%s].\n", info->source_log_file_name));
-           file_lines_free(qlines);
-           return True;
+NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
+                                  struct eventlog_GetOldestRecord *r)
+{
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
+
+       if (info == NULL) {
+               return NT_STATUS_INVALID_HANDLE;
        }
-    }
 
-    file_lines_free(qlines);
-    return False;
+       if ( !( get_oldest_entry_hook( info ) ) )
+               return NT_STATUS_ACCESS_DENIED;
+
+       *r->out.oldest_entry = info->oldest_entry;
+
+       return NT_STATUS_OK;
+}
+
+/********************************************************************
+_eventlog_GetNumRecords
+ ********************************************************************/
+
+NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
+                                struct eventlog_GetNumRecords *r)
+{
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
+
+       if (info == NULL) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       if ( !( get_num_records_hook( info ) ) )
+               return NT_STATUS_ACCESS_DENIED;
+
+       *r->out.number = info->num_records;
+
+       return NT_STATUS_OK;
 }
 
-WERROR _eventlog_clear_eventlog(pipes_struct *p,
-                               EVENTLOG_Q_CLEAR_EVENTLOG *q_u,
-                               EVENTLOG_R_CLEAR_EVENTLOG *r_u)
+NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
 {
-    Eventlog_info *info = NULL;
-    pstring backup_file_name;
-    POLICY_HND *handle = NULL;
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
 
-    if(!q_u || !r_u)
-       return WERR_NOMEM;
+NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
 
-    handle = &(q_u->handle);
-    info = find_eventlog_info_by_hnd(p, handle);
-    memset(backup_file_name, 0, sizeof(backup_file_name));
+NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
 
-    if(q_u->backup_file_ptr != 0)
-    {
-       unistr2_to_ascii(backup_file_name, &(q_u->backup_file), sizeof(backup_file_name));
-       DEBUG(10, ("_eventlog_clear_eventlog: Using [%s] as the backup file name for log [%s].",
-                  backup_file_name,
-                  info->source_log_file_name));
-    }
-    else
-    {
-       /* if backup_file == NULL, do not back up the log before clearing it */
-       DEBUG(10, ("_eventlog_clear_eventlog: clearing [%s] log without making a backup.",
-                  info->source_log_file_name));
-    }
+NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
 
-    if(!(_eventlog_clear_eventlog_hook(info, backup_file_name)))
-       return WERR_BADFILE;
+NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
 
-    return WERR_OK;
+NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
 }
+
+NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
+{
+       p->rng_fault_state = True;
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+