s3-registry: avoid using registry_value union.
[nivanova/samba-autobuild/.git] / source3 / rpc_server / srv_eventlog_nt.c
index 145b4600f94422c969565dd4ab2176129645ed19..19d0514717251c0a308724e6a887b5a4a10a10b9 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) Marcin Krzysztof Porwit    2005,
  *  Copyright (C) Brian Moran                2005,
  *  Copyright (C) Gerald (Jerry) Carter      2005.
+ *  Copyright (C) Guenther Deschner          2009.
  *
  *  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
@@ -20,6 +21,9 @@
  */
 
 #include "includes.h"
+#include "../librpc/gen_ndr/srv_eventlog.h"
+#include "lib/eventlog/eventlog.h"
+#include "registry.h"
 
 #undef  DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
@@ -49,7 +53,7 @@ static int eventlog_info_destructor(EVENTLOG_INFO *elog)
  ********************************************************************/
 
 static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
-                                               POLICY_HND * handle )
+                                               struct policy_handle * handle )
 {
        EVENTLOG_INFO *info;
 
@@ -68,7 +72,8 @@ static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
 static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
 {
        char *tdbname = elog_tdbname(talloc_tos(), info->logname );
-       SEC_DESC *sec_desc;
+       struct security_descriptor *sec_desc;
+       struct security_ace *ace;
        NTSTATUS status;
 
        if ( !tdbname )
@@ -85,11 +90,28 @@ static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
                return False;
        }
 
+       ace = talloc_zero(sec_desc, struct security_ace);
+       if (ace == NULL) {
+               TALLOC_FREE(sec_desc);
+               return false;
+       }
+
+       ace->type               = SEC_ACE_TYPE_ACCESS_ALLOWED;
+       ace->flags              = 0;
+       ace->access_mask        = REG_KEY_ALL;
+       ace->trustee            = global_sid_System;
+
+       status = security_descriptor_dacl_add(sec_desc, ace);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(sec_desc);
+               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();
+               DEBUG(5,("elog_check_access: running as root, using system token\n"));
+               token = get_system_token();
        }
 
        /* run the check, try for the max allowed */
@@ -97,8 +119,7 @@ static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
        status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
                &info->access_granted);
 
-       if ( sec_desc )
-               TALLOC_FREE( sec_desc );
+       TALLOC_FREE(sec_desc);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(8,("elog_check_access: se_access_check() return %s\n",
@@ -108,7 +129,7 @@ static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
 
        /* we have to have READ permission for a successful open */
 
-       return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
+       return ( info->access_granted & SEC_FILE_READ_DATA );
 }
 
 /********************************************************************
@@ -173,12 +194,12 @@ static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
 /********************************************************************
  ********************************************************************/
 
-static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
+static NTSTATUS elog_open( pipes_struct * p, const char *logname, struct policy_handle *hnd )
 {
        EVENTLOG_INFO *elog;
 
        /* first thing is to validate the eventlog name */
-       
+
        if ( !elog_validate_logname( logname ) )
                return NT_STATUS_OBJECT_PATH_INVALID;
 
@@ -194,7 +215,7 @@ static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hn
           in a single process */
 
        become_root();
-       elog->etdb = elog_open_tdb( elog->logname, False );
+       elog->etdb = elog_open_tdb( elog->logname, False, False );
        unbecome_root();
 
        if ( !elog->etdb ) {
@@ -214,7 +235,7 @@ static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hn
                        }
 
                        become_root();
-                       elog->etdb = elog_open_tdb( elog->logname, False );
+                       elog->etdb = elog_open_tdb( elog->logname, False, False );
                        unbecome_root();
                }
 
@@ -253,7 +274,7 @@ static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hn
 /********************************************************************
  ********************************************************************/
 
-static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
+static NTSTATUS elog_close( pipes_struct *p, struct policy_handle *hnd )
 {
         if ( !( close_policy_hnd( p, hnd ) ) ) {
                 return NT_STATUS_INVALID_HANDLE;
@@ -275,140 +296,6 @@ static int elog_size( EVENTLOG_INFO *info )
        return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
 }
 
-/********************************************************************
-  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_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;
-
-       key.dsize = sizeof(int32_t);
-
-       srecno = recno;
-       key.dptr = (unsigned char *)&srecno;
-
-       ret = tdb_fetch( tdb, key );
-
-       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;
-}
-
 /********************************************************************
  note that this can only be called AFTER the table is constructed,
  since it uses the table to find the tdb handle
@@ -417,8 +304,8 @@ static Eventlog_entry *get_eventlog_record(TALLOC_CTX *mem_ctx,
 static bool sync_eventlog_params( EVENTLOG_INFO *info )
 {
        char *path = NULL;
-       uint32 uiMaxSize;
-       uint32 uiRetention;
+       uint32_t uiMaxSize = 0;
+       uint32_t uiRetention = 0;
        struct registry_key *key;
        struct registry_value *value;
        WERROR wresult;
@@ -442,12 +329,12 @@ static bool sync_eventlog_params( EVENTLOG_INFO *info )
           to use the same fetch/store api that we use in
           srv_reg_nt.c */
 
-       path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
+       path = talloc_asprintf(ctx, "%s\\%s", KEY_EVENTLOG, elogname);
        if (!path) {
                goto done;
        }
 
-       wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
+       wresult = reg_open_path(ctx, path, REG_KEY_READ, get_system_token(),
                                &key);
 
        if ( !W_ERROR_IS_OK( wresult ) ) {
@@ -463,7 +350,10 @@ static bool sync_eventlog_params( EVENTLOG_INFO *info )
                          win_errstr(wresult)));
                goto done;
        }
-       uiRetention = value->v.dword;
+
+       if (value->data.length >= 4) {
+               uiRetention = IVAL(value->data.data, 0);
+       }
 
        wresult = reg_queryvalue(key, key, "MaxSize", &value);
        if (!W_ERROR_IS_OK(wresult)) {
@@ -471,7 +361,9 @@ static bool sync_eventlog_params( EVENTLOG_INFO *info )
                          win_errstr(wresult)));
                goto done;
        }
-       uiMaxSize = value->v.dword;
+       if (value->data.length >= 4) {
+               uiMaxSize = IVAL(value->data.data, 0);
+       }
 
        tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
        tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
@@ -483,126 +375,6 @@ done:
        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;
-       }
-
-       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 =
-               TALLOC_ZERO_ARRAY(mem_ctx, uint8_t,
-                                 entry->record.length -
-                                 sizeof( Eventlog_record ) -
-                                 sizeof( entry->record.length ));
-       if ( entry->data == NULL ) {
-               return NULL;
-       }
-       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;
-}
-
 /********************************************************************
  _eventlog_OpenEventLogW
  ********************************************************************/
@@ -610,38 +382,31 @@ static bool add_record_to_resp( Eventlog_entry *entry,
 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
                                 struct eventlog_OpenEventLogW *r)
 {
-       const char *servername = "";
-       const char *logname = "";
        EVENTLOG_INFO *info;
        NTSTATUS result;
 
-       if (r->in.servername->string) {
-               servername = r->in.servername->string;
-       }
-
-       if (r->in.logname->string) {
-               logname = r->in.logname->string;
-       }
-
-       DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
-               servername, logname ));
+       DEBUG( 10,("_eventlog_OpenEventLogW: Server [%s], Log [%s]\n",
+               r->in.servername->string, r->in.logname->string ));
 
        /* 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 )) )
+       if ( !NT_STATUS_IS_OK( result = elog_open( p, r->in.logname->string, 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 ));
+               DEBUG(0,("_eventlog_OpenEventLogW: eventlog (%s) opened but unable to find handle!\n",
+                       r->in.logname->string ));
                elog_close( p, r->out.handle );
                return NT_STATUS_INVALID_HANDLE;
        }
 
-       DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
+       DEBUG(10,("_eventlog_OpenEventLogW: Size [%d]\n", elog_size( info )));
 
-       sync_eventlog_params( info );
+       if (!sync_eventlog_params(info)) {
+               elog_close(p, r->out.handle);
+               return NT_STATUS_EVENTLOG_FILE_CORRUPT;
+       }
        prune_eventlog( ELOG_TDB_CTX(info->etdb) );
 
        return NT_STATUS_OK;
@@ -669,30 +434,27 @@ NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
                                  struct eventlog_ClearEventLogW *r)
 {
        EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
-       const char *backup_file_name = NULL;
 
        if ( !info )
                return NT_STATUS_INVALID_HANDLE;
 
        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 "
+               DEBUG(8,( "_eventlog_ClearEventLogW: Using [%s] as the backup "
                        "file name for log [%s].",
-                        backup_file_name, info->logname ) );
+                        r->in.backupfile->string, info->logname ) );
        }
 
        /* check for WRITE access to the file */
 
-       if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
+       if ( !(info->access_granted & SEC_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 );
+       info->etdb = elog_open_tdb( info->logname, True, False );
        unbecome_root();
 
        if ( !info->etdb )
@@ -708,107 +470,130 @@ NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
 NTSTATUS _eventlog_CloseEventLog(pipes_struct * p,
                                 struct eventlog_CloseEventLog *r)
 {
-       return elog_close( p, r->in.handle );
+       NTSTATUS status;
+
+       status = elog_close( p, r->in.handle );
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       ZERO_STRUCTP(r->out.handle);
+
+       return NT_STATUS_OK;
 }
 
 /********************************************************************
+ _eventlog_ReadEventLogW
  ********************************************************************/
 
-NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
-                               EVENTLOG_Q_READ_EVENTLOG * q_u,
-                               EVENTLOG_R_READ_EVENTLOG * r_u )
+NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p,
+                                struct eventlog_ReadEventLogW *r)
 {
-       EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
-       Eventlog_entry *entry = NULL, *ee_new = NULL;
-       uint32 num_records_read = 0;
-       prs_struct *ps;
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
+       uint32_t num_records_read = 0;
        int bytes_left, record_number;
-       uint32 elog_read_type, elog_read_dir;
+       uint32_t elog_read_type, elog_read_dir;
 
-       if (info == NULL) {
+       if (!info) {
                return NT_STATUS_INVALID_HANDLE;
        }
 
-       info->flags = q_u->flags;
-       ps = &p->out_data.rdata;
+       info->flags     = r->in.flags;
+       bytes_left      = r->in.number_of_bytes;
 
-       bytes_left = q_u->max_read_size;
-
-       if ( !info->etdb )
+       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);
+       elog_read_type = r->in.flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
+       elog_read_dir  = r->in.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) )
+       if (r->in.flags == 0 ||
+           elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) ||
+           elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ))
        {
-               DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
+               DEBUG(3,("_eventlog_ReadEventLogW: "
+                       "Invalid flags [0x%08x] for ReadEventLog\n",
+                       r->in.flags));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        /* a sequential read should ignore the offset */
 
-       if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
+       if (elog_read_type & EVENTLOG_SEQUENTIAL_READ) {
                record_number = info->current_record;
-       else
-               record_number = q_u->offset;
+       } else {
+               record_number = r->in.offset;
+       }
 
-       while ( bytes_left > 0 ) {
+       if (r->in.number_of_bytes == 0) {
+               struct EVENTLOGRECORD *e;
+               e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb),
+                                     record_number);
+               if (!e) {
+                       return NT_STATUS_END_OF_FILE;
+               }
+               *r->out.real_size = e->Length;
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       while (bytes_left > 0) {
 
-               /* assume that when the record fetch fails, that we are done */
+               DATA_BLOB blob;
+               enum ndr_err_code ndr_err;
+               struct EVENTLOGRECORD *e;
 
-               entry = get_eventlog_record (ps->mem_ctx, ELOG_TDB_CTX(info->etdb), record_number);
-               if (!entry) {
+               e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb),
+                                     record_number);
+               if (!e) {
                        break;
                }
 
-               DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
-
-               /* Now see if there is enough room to add */
-
-               if ( !(ee_new = read_package_entry( ps->mem_ctx, entry )) )
-                       return NT_STATUS_NO_MEMORY;
+               ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, e,
+                             (ndr_push_flags_fn_t)ndr_push_EVENTLOGRECORD);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return ndr_map_error2ntstatus(ndr_err);
+               }
 
-               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;
+               if (DEBUGLEVEL >= 10) {
+                       NDR_PRINT_DEBUG(EVENTLOGRECORD, e);
+               }
 
-                       /* response would be too big to fit in client-size buffer */
+               if (blob.length > r->in.number_of_bytes) {
+                       *r->out.real_size = blob.length;
+                       return NT_STATUS_BUFFER_TOO_SMALL;
+               }
 
-                       bytes_left = 0;
+               if (*r->out.sent_size + blob.length > r->in.number_of_bytes) {
                        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;
+               bytes_left -= blob.length;
 
-               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 )
+               if (info->flags & EVENTLOG_FORWARDS_READ) {
                        record_number++;
-               else
+               } else {
                        record_number--;
+               }
 
                /* update the eventlog record pointer */
 
                info->current_record = record_number;
+
+               memcpy(&r->out.data[*(r->out.sent_size)],
+                      blob.data, blob.length);
+               *(r->out.sent_size) += blob.length;
+
+               num_records_read++;
        }
 
-       /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
-          say when there are no more records */
+       if (r->in.offset == 0 && record_number == 0 && *r->out.sent_size == 0) {
+               return NT_STATUS_END_OF_FILE;
+       }
 
-       return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
+       return NT_STATUS_OK;
 }
 
 /********************************************************************
@@ -859,37 +644,161 @@ NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventL
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
+/********************************************************************
+_eventlog_GetLogInformation
+ ********************************************************************/
+
+NTSTATUS _eventlog_GetLogInformation(pipes_struct *p,
+                                    struct eventlog_GetLogInformation *r)
 {
-       p->rng_fault_state = True;
-       return NT_STATUS_NOT_IMPLEMENTED;
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
+       struct EVENTLOG_FULL_INFORMATION f;
+       enum ndr_err_code ndr_err;
+       DATA_BLOB blob;
+
+       if (!info) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       if (r->in.level != 0) {
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
+       *r->out.bytes_needed = 4;
+
+       if (r->in.buf_size < 4) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       /* FIXME: this should be retrieved from the handle */
+       f.full = false;
+
+       ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &f,
+                     (ndr_push_flags_fn_t)ndr_push_EVENTLOG_FULL_INFORMATION);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return ndr_map_error2ntstatus(ndr_err);
+       }
+
+       if (DEBUGLEVEL >= 10) {
+               NDR_PRINT_DEBUG(EVENTLOG_FULL_INFORMATION, &f);
+       }
+
+       memcpy(r->out.buffer, blob.data, 4);
+
+       return NT_STATUS_OK;
 }
 
-NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
+/********************************************************************
+_eventlog_FlushEventLog
+ ********************************************************************/
+
+NTSTATUS _eventlog_FlushEventLog(pipes_struct *p,
+                                struct eventlog_FlushEventLog *r)
 {
-       p->rng_fault_state = True;
-       return NT_STATUS_NOT_IMPLEMENTED;
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
+       if (!info) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       return NT_STATUS_ACCESS_DENIED;
 }
 
-NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
+/********************************************************************
+ ********************************************************************/
+
+static NTSTATUS evlog_report_to_record(TALLOC_CTX *mem_ctx,
+                                      const struct eventlog_ReportEventW *r,
+                                      const char *logname,
+                                      struct EVENTLOGRECORD *e)
+{
+       uint32_t i;
+       ZERO_STRUCTP(e);
+
+       e->TimeGenerated        = r->in.timestamp;
+       e->TimeWritten          = time(NULL);
+       e->EventID              = r->in.event_id;
+       e->EventType            = r->in.event_type;
+       e->NumStrings           = r->in.num_of_strings;
+       e->EventCategory        = r->in.event_category;
+       e->ReservedFlags        = r->in.flags;
+       e->DataLength           = r->in.data_size;
+       e->SourceName           = talloc_strdup(mem_ctx, logname);
+       NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
+       if (r->in.servername->string) {
+               e->Computername = r->in.servername->string;
+       } else {
+               e->Computername = talloc_strdup(mem_ctx, "");
+               NT_STATUS_HAVE_NO_MEMORY(e->Computername);
+       }
+       if (r->in.user_sid) {
+               e->UserSid      = *r->in.user_sid;
+       }
+       e->Strings              = talloc_array(mem_ctx, const char *, e->NumStrings);
+       NT_STATUS_HAVE_NO_MEMORY(e->Strings);
+
+       for (i=0; i < e->NumStrings; i++) {
+               e->Strings[i] = talloc_strdup(e->Strings,
+                                             r->in.strings[i]->string);
+               NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
+       }
+       e->Data                 = r->in.data;
+
+       return NT_STATUS_OK;
+}
+
+/********************************************************************
+_eventlog_ReportEventW
+ ********************************************************************/
+
+NTSTATUS _eventlog_ReportEventW(pipes_struct *p,
+                               struct eventlog_ReportEventW *r)
+{
+       NTSTATUS status;
+       struct EVENTLOGRECORD record;
+
+       EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
+       if (!info) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       status = evlog_report_to_record(p->mem_ctx, r, info->logname, &record);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = evlog_push_record(p->mem_ctx,
+                                  ELOG_TDB_CTX(info->etdb),
+                                  &record,
+                                  r->out.record_number);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
 {
        p->rng_fault_state = True;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
+NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
 {
        p->rng_fault_state = True;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
+NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
 {
        p->rng_fault_state = True;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
+NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
 {
        p->rng_fault_state = True;
        return NT_STATUS_NOT_IMPLEMENTED;
@@ -955,15 +864,8 @@ NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClus
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
+NTSTATUS _eventlog_ReportEventAndSourceW(pipes_struct *p, struct eventlog_ReportEventAndSourceW *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;
-}
-