Second part of fix for bug #5891 - smbd crashed when viewing the eventlog exported...
[metze/samba/wip.git] / source3 / rpc_server / srv_eventlog_nt.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Marcin Krzysztof Porwit    2005,
5  *  Copyright (C) Brian Moran                2005,
6  *  Copyright (C) Gerald (Jerry) Carter      2005.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23
24 #undef  DBGC_CLASS
25 #define DBGC_CLASS DBGC_RPC_SRV
26
27 typedef struct {
28         char *logname;
29         ELOG_TDB *etdb;
30         uint32 current_record;
31         uint32 num_records;
32         uint32 oldest_entry;
33         uint32 flags;
34         uint32 access_granted;
35 } EVENTLOG_INFO;
36
37 /********************************************************************
38  ********************************************************************/
39
40 static void free_eventlog_info( void *ptr )
41 {
42         EVENTLOG_INFO *elog = (EVENTLOG_INFO *)ptr;
43
44         if ( elog->etdb )
45                 elog_close_tdb( elog->etdb, False );
46
47         TALLOC_FREE( elog );
48 }
49
50 /********************************************************************
51  ********************************************************************/
52
53 static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
54                                                 POLICY_HND * handle )
55 {
56         EVENTLOG_INFO *info;
57
58         if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
59                 DEBUG( 2,
60                        ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
61                 return NULL;
62         }
63
64         return info;
65 }
66
67 /********************************************************************
68 ********************************************************************/
69
70 static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
71 {
72         char *tdbname = elog_tdbname(talloc_tos(), info->logname );
73         SEC_DESC *sec_desc;
74         NTSTATUS status;
75
76         if ( !tdbname )
77                 return False;
78
79         /* get the security descriptor for the file */
80
81         sec_desc = get_nt_acl_no_snum( info, tdbname );
82         TALLOC_FREE( tdbname );
83
84         if ( !sec_desc ) {
85                 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
86                         tdbname));
87                 return False;
88         }
89
90         /* root free pass */
91
92         if ( geteuid() == sec_initial_uid() ) {
93                 DEBUG(5,("elog_check_access: using root's token\n"));
94                 token = get_root_nt_token();
95         }
96
97         /* run the check, try for the max allowed */
98
99         status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
100                 &info->access_granted);
101
102         if ( sec_desc )
103                 TALLOC_FREE( sec_desc );
104
105         if (!NT_STATUS_IS_OK(status)) {
106                 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
107                         nt_errstr(status)));
108                 return False;
109         }
110
111         /* we have to have READ permission for a successful open */
112
113         return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
114 }
115
116 /********************************************************************
117  ********************************************************************/
118
119 static bool elog_validate_logname( const char *name )
120 {
121         int i;
122         const char **elogs = lp_eventlog_list();
123
124         if (!elogs) {
125                 return False;
126         }
127
128         for ( i=0; elogs[i]; i++ ) {
129                 if ( strequal( name, elogs[i] ) )
130                         return True;
131         }
132
133         return False;
134 }
135
136 /********************************************************************
137 ********************************************************************/
138
139 static bool get_num_records_hook( EVENTLOG_INFO * info )
140 {
141         int next_record;
142         int oldest_record;
143
144         if ( !info->etdb ) {
145                 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
146                 return False;
147         }
148
149         /* lock the tdb since we have to get 2 records */
150
151         tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
152         next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
153         oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
154         tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
155
156         DEBUG( 8,
157                ( "Oldest Record %d; Next Record %d\n", oldest_record,
158                  next_record ) );
159
160         info->num_records = ( next_record - oldest_record );
161         info->oldest_entry = oldest_record;
162
163         return True;
164 }
165
166 /********************************************************************
167  ********************************************************************/
168
169 static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
170 {
171         /* it's the same thing */
172         return get_num_records_hook( info );
173 }
174
175 /********************************************************************
176  ********************************************************************/
177
178 static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
179 {
180         EVENTLOG_INFO *elog;
181
182         /* first thing is to validate the eventlog name */
183         
184         if ( !elog_validate_logname( logname ) )
185                 return NT_STATUS_OBJECT_PATH_INVALID;
186
187         if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
188                 return NT_STATUS_NO_MEMORY;
189
190         elog->logname = talloc_strdup( elog, logname );
191
192         /* Open the tdb first (so that we can create any new tdbs if necessary).
193            We have to do this as root and then use an internal access check
194            on the file permissions since you can only have a tdb open once
195            in a single process */
196
197         become_root();
198         elog->etdb = elog_open_tdb( elog->logname, False );
199         unbecome_root();
200
201         if ( !elog->etdb ) {
202                 /* according to MSDN, if the logfile cannot be found, we should
203                   default to the "Application" log */
204
205                 if ( !strequal( logname, ELOG_APPL ) ) {
206
207                         TALLOC_FREE( elog->logname );
208
209                         elog->logname = talloc_strdup( elog, ELOG_APPL );
210
211                         /* do the access check */
212                         if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
213                                 TALLOC_FREE( elog );
214                                 return NT_STATUS_ACCESS_DENIED;
215                         }
216
217                         become_root();
218                         elog->etdb = elog_open_tdb( elog->logname, False );
219                         unbecome_root();
220                 }
221
222                 if ( !elog->etdb ) {
223                         TALLOC_FREE( elog );
224                         return NT_STATUS_ACCESS_DENIED; /* ??? */
225                 }
226         }
227
228         /* now do the access check.  Close the tdb if we fail here */
229
230         if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
231                 elog_close_tdb( elog->etdb, False );
232                 TALLOC_FREE( elog );
233                 return NT_STATUS_ACCESS_DENIED;
234         }
235
236         /* create the policy handle */
237
238         if ( !create_policy_hnd
239              ( p, hnd, free_eventlog_info, ( void * ) elog ) ) {
240                 free_eventlog_info( elog );
241                 return NT_STATUS_NO_MEMORY;
242         }
243
244         /* set the initial current_record pointer */
245
246         if ( !get_oldest_entry_hook( elog ) ) {
247                 DEBUG(3,("elog_open: Successfully opened eventlog but can't "
248                         "get any information on internal records!\n"));
249         }
250
251         elog->current_record = elog->oldest_entry;
252
253         return NT_STATUS_OK;
254 }
255
256 /********************************************************************
257  ********************************************************************/
258
259 static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
260 {
261         if ( !( close_policy_hnd( p, hnd ) ) ) {
262                 return NT_STATUS_INVALID_HANDLE;
263         }
264
265         return NT_STATUS_OK;
266 }
267
268 /*******************************************************************
269  *******************************************************************/
270
271 static int elog_size( EVENTLOG_INFO *info )
272 {
273         if ( !info || !info->etdb ) {
274                 DEBUG(0,("elog_size: Invalid info* structure!\n"));
275                 return 0;
276         }
277
278         return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
279 }
280
281 /********************************************************************
282   For the given tdb, get the next eventlog record into the passed
283   Eventlog_entry.  returns NULL if it can't get the record for some reason.
284  ********************************************************************/
285
286 static Eventlog_entry *get_eventlog_record(TALLOC_CTX *mem_ctx,
287                                 TDB_CONTEXT *tdb,
288                                 int recno)
289 {
290         Eventlog_entry *ee = NULL;
291         TDB_DATA ret, key;
292
293         int32_t srecno;
294         int32_t reclen;
295         int len;
296
297         char *wpsource = NULL;
298         char *wpcomputer = NULL;
299         char *wpsid = NULL;
300         char *wpstrs = NULL;
301         char *puserdata = NULL;
302
303         key.dsize = sizeof(int32_t);
304
305         srecno = recno;
306         key.dptr = (unsigned char *)&srecno;
307
308         ret = tdb_fetch( tdb, key );
309
310         if ( ret.dsize == 0 ) {
311                 DEBUG( 8,
312                        ( "Can't find a record for the key, record %d\n",
313                          recno ) );
314                 return NULL;
315         }
316
317         len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
318
319         DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
320
321         if ( !len )
322                 return NULL;
323
324         ee = TALLOC_ARRAY(mem_ctx, Eventlog_entry, 1);
325         if (!ee) {
326                 return NULL;
327         }
328         ZERO_STRUCTP(ee);
329
330         len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
331                           &ee->record.length, &ee->record.reserved1,
332                           &ee->record.record_number,
333                           &ee->record.time_generated,
334                           &ee->record.time_written, &ee->record.event_id,
335                           &ee->record.event_type, &ee->record.num_strings,
336                           &ee->record.event_category, &ee->record.reserved2,
337                           &ee->record.closing_record_number,
338                           &ee->record.string_offset,
339                           &ee->record.user_sid_length,
340                           &ee->record.user_sid_offset,
341                           &ee->record.data_length, &ee->record.data_offset,
342                           &ee->data_record.source_name_len, &wpsource,
343                           &ee->data_record.computer_name_len, &wpcomputer,
344                           &ee->data_record.sid_padding,
345                           &ee->record.user_sid_length, &wpsid,
346                           &ee->data_record.strings_len, &wpstrs,
347                           &ee->data_record.user_data_len, &puserdata,
348                           &ee->data_record.data_padding );
349         DEBUG( 10,
350                ( "Read record %d, len in tdb was %d\n",
351                  ee->record.record_number, len ) );
352
353         /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
354            into it's 2nd argment for 'B' */
355
356         if (wpcomputer) {
357                 ee->data_record.computer_name = (smb_ucs2_t *)TALLOC_MEMDUP(
358                         ee, wpcomputer, ee->data_record.computer_name_len);
359                 if (!ee->data_record.computer_name) {
360                         TALLOC_FREE(ee);
361                         goto out;
362                 }
363         }
364         if (wpsource) {
365                 ee->data_record.source_name = (smb_ucs2_t *)TALLOC_MEMDUP(
366                         ee, wpsource, ee->data_record.source_name_len);
367                 if (!ee->data_record.source_name) {
368                         TALLOC_FREE(ee);
369                         goto out;
370                 }
371         }
372
373         if (wpsid) {
374                 ee->data_record.sid = (smb_ucs2_t *)TALLOC_MEMDUP(
375                         ee, wpsid, ee->record.user_sid_length);
376                 if (!ee->data_record.sid) {
377                         TALLOC_FREE(ee);
378                         goto out;
379                 }
380         }
381         if (wpstrs) {
382                 ee->data_record.strings = (smb_ucs2_t *)TALLOC_MEMDUP(
383                         ee, wpstrs, ee->data_record.strings_len);
384                 if (!ee->data_record.strings) {
385                         TALLOC_FREE(ee);
386                         goto out;
387                 }
388         }
389
390         if (puserdata) {
391                 ee->data_record.user_data = (char *)TALLOC_MEMDUP(
392                         ee, puserdata, ee->data_record.user_data_len);
393                 if (!ee->data_record.user_data) {
394                         TALLOC_FREE(ee);
395                         goto out;
396                 }
397         }
398
399   out:
400
401         SAFE_FREE(wpcomputer);
402         SAFE_FREE(wpsource);
403         SAFE_FREE(wpsid);
404         SAFE_FREE(wpstrs);
405         SAFE_FREE(puserdata);
406
407         DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
408         DEBUG( 10,
409                ( "get_eventlog_record: computer_name %d is ",
410                  ee->data_record.computer_name_len ) );
411         SAFE_FREE(ret.dptr);
412         return ee;
413 }
414
415 /********************************************************************
416  note that this can only be called AFTER the table is constructed,
417  since it uses the table to find the tdb handle
418  ********************************************************************/
419
420 static bool sync_eventlog_params( EVENTLOG_INFO *info )
421 {
422         char *path = NULL;
423         uint32 uiMaxSize;
424         uint32 uiRetention;
425         struct registry_key *key;
426         struct registry_value *value;
427         WERROR wresult;
428         char *elogname = info->logname;
429         TALLOC_CTX *ctx = talloc_stackframe();
430         bool ret = false;
431
432         DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
433
434         if ( !info->etdb ) {
435                 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
436                 goto done;
437         }
438         /* set resonable defaults.  512Kb on size and 1 week on time */
439
440         uiMaxSize = 0x80000;
441         uiRetention = 604800;
442
443         /* the general idea is to internally open the registry
444            key and retrieve the values.  That way we can continue
445            to use the same fetch/store api that we use in
446            srv_reg_nt.c */
447
448         path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
449         if (!path) {
450                 goto done;
451         }
452
453         wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
454                                 &key);
455
456         if ( !W_ERROR_IS_OK( wresult ) ) {
457                 DEBUG( 4,
458                        ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
459                          path, win_errstr( wresult ) ) );
460                 goto done;
461         }
462
463         wresult = reg_queryvalue(key, key, "Retention", &value);
464         if (!W_ERROR_IS_OK(wresult)) {
465                 DEBUG(4, ("Failed to query value \"Retention\": %s\n",
466                           win_errstr(wresult)));
467                 goto done;
468         }
469         uiRetention = value->v.dword;
470
471         wresult = reg_queryvalue(key, key, "MaxSize", &value);
472         if (!W_ERROR_IS_OK(wresult)) {
473                 DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
474                           win_errstr(wresult)));
475                 goto done;
476         }
477         uiMaxSize = value->v.dword;
478
479         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
480         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
481
482         ret = true;
483
484 done:
485         TALLOC_FREE(ctx);
486         return ret;
487 }
488
489 /********************************************************************
490  ********************************************************************/
491
492 static Eventlog_entry *read_package_entry( TALLOC_CTX *mem_ctx,
493                                            Eventlog_entry * entry )
494 {
495         uint8 *offset;
496         Eventlog_entry *ee_new = NULL;
497
498         ee_new = TALLOC_ZERO_ARRAY(mem_ctx, Eventlog_entry, 1 );
499         if ( ee_new == NULL ) {
500                 return NULL;
501         }
502
503         entry->data_record.sid_padding =
504                 ( ( 4 -
505                     ( ( entry->data_record.source_name_len +
506                         entry->data_record.computer_name_len ) % 4 ) ) % 4 );
507         entry->data_record.data_padding =
508                 ( 4 -
509                   ( ( entry->data_record.strings_len +
510                       entry->data_record.user_data_len ) % 4 ) ) % 4;
511         entry->record.length = sizeof( Eventlog_record );
512         entry->record.length += entry->data_record.source_name_len;
513         entry->record.length += entry->data_record.computer_name_len;
514         if ( entry->record.user_sid_length == 0 ) {
515                 /* Should not pad to a DWORD boundary for writing out the sid if there is
516                    no SID, so just propagate the padding to pad the data */
517                 entry->data_record.data_padding +=
518                         entry->data_record.sid_padding;
519                 entry->data_record.sid_padding = 0;
520         }
521         DEBUG( 10,
522                ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
523         DEBUG( 10,
524                ( "data_padding is [%d].\n",
525                  entry->data_record.data_padding ) );
526
527         entry->record.length += entry->data_record.sid_padding;
528         entry->record.length += entry->record.user_sid_length;
529         entry->record.length += entry->data_record.strings_len;
530         entry->record.length += entry->data_record.user_data_len;
531         entry->record.length += entry->data_record.data_padding;
532         /* need another copy of length at the end of the data */
533         entry->record.length += sizeof( entry->record.length );
534         DEBUG( 10,
535                ( "entry->record.length is [%d].\n", entry->record.length ) );
536         entry->data =
537                 TALLOC_ZERO_ARRAY(mem_ctx, uint8_t,
538                                   entry->record.length -
539                                   sizeof( Eventlog_record ) -
540                                   sizeof( entry->record.length ));
541         if ( entry->data == NULL ) {
542                 return NULL;
543         }
544         offset = entry->data;
545         memcpy( offset, &( entry->data_record.source_name ),
546                 entry->data_record.source_name_len );
547         offset += entry->data_record.source_name_len;
548         memcpy( offset, &( entry->data_record.computer_name ),
549                 entry->data_record.computer_name_len );
550         offset += entry->data_record.computer_name_len;
551         /* SID needs to be DWORD-aligned */
552         offset += entry->data_record.sid_padding;
553         entry->record.user_sid_offset =
554                 sizeof( Eventlog_record ) + ( offset - entry->data );
555         memcpy( offset, &( entry->data_record.sid ),
556                 entry->record.user_sid_length );
557         offset += entry->record.user_sid_length;
558         /* Now do the strings */
559         entry->record.string_offset =
560                 sizeof( Eventlog_record ) + ( offset - entry->data );
561         memcpy( offset, &( entry->data_record.strings ),
562                 entry->data_record.strings_len );
563         offset += entry->data_record.strings_len;
564         /* Now do the data */
565         entry->record.data_length = entry->data_record.user_data_len;
566         entry->record.data_offset =
567                 sizeof( Eventlog_record ) + ( offset - entry->data );
568         memcpy( offset, &( entry->data_record.user_data ),
569                 entry->data_record.user_data_len );
570         offset += entry->data_record.user_data_len;
571
572         memcpy( &( ee_new->record ), &entry->record,
573                 sizeof( Eventlog_record ) );
574         memcpy( &( ee_new->data_record ), &entry->data_record,
575                 sizeof( Eventlog_data_record ) );
576         ee_new->data = entry->data;
577
578         return ee_new;
579 }
580
581 /********************************************************************
582  ********************************************************************/
583
584 static bool add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
585                                 Eventlog_entry * ee_new )
586 {
587         Eventlog_entry *insert_point;
588
589         insert_point = r_u->entry;
590
591         if ( NULL == insert_point ) {
592                 r_u->entry = ee_new;
593                 ee_new->next = NULL;
594         } else {
595                 while ( ( NULL != insert_point->next ) ) {
596                         insert_point = insert_point->next;
597                 }
598                 ee_new->next = NULL;
599                 insert_point->next = ee_new;
600         }
601         r_u->num_records++;
602         r_u->num_bytes_in_resp += ee_new->record.length;
603
604         return True;
605 }
606
607 /********************************************************************
608  _eventlog_OpenEventLogW
609  ********************************************************************/
610
611 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
612                                  struct eventlog_OpenEventLogW *r)
613 {
614         const char *servername = "";
615         const char *logname = "";
616         EVENTLOG_INFO *info;
617         NTSTATUS result;
618
619         if (r->in.servername->string) {
620                 servername = r->in.servername->string;
621         }
622
623         if (r->in.logname->string) {
624                 logname = r->in.logname->string;
625         }
626
627         DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
628                 servername, logname ));
629
630         /* according to MSDN, if the logfile cannot be found, we should
631           default to the "Application" log */
632
633         if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, r->out.handle )) )
634                 return result;
635
636         if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
637                 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
638                         logname ));
639                 elog_close( p, r->out.handle );
640                 return NT_STATUS_INVALID_HANDLE;
641         }
642
643         DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
644
645         sync_eventlog_params( info );
646         prune_eventlog( ELOG_TDB_CTX(info->etdb) );
647
648         return NT_STATUS_OK;
649 }
650
651 /********************************************************************
652  _eventlog_ClearEventLogW
653  This call still needs some work
654  ********************************************************************/
655 /** The windows client seems to be doing something funny with the file name
656    A call like
657       ClearEventLog(handle, "backup_file")
658    on the client side will result in the backup file name looking like this on the
659    server side:
660       \??\${CWD of client}\backup_file
661    If an absolute path gets specified, such as
662       ClearEventLog(handle, "C:\\temp\\backup_file")
663    then it is still mangled by the client into this:
664       \??\C:\temp\backup_file
665    when it is on the wire.
666    I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
667    would be added in given that the backup file gets written on the server side. */
668
669 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
670                                   struct eventlog_ClearEventLogW *r)
671 {
672         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
673         const char *backup_file_name = NULL;
674
675         if ( !info )
676                 return NT_STATUS_INVALID_HANDLE;
677
678         if (r->in.backupfile && r->in.backupfile->string) {
679
680                 backup_file_name = r->in.backupfile->string;
681
682                 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
683                         "file name for log [%s].",
684                          backup_file_name, info->logname ) );
685         }
686
687         /* check for WRITE access to the file */
688
689         if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
690                 return NT_STATUS_ACCESS_DENIED;
691
692         /* Force a close and reopen */
693
694         elog_close_tdb( info->etdb, True );
695         become_root();
696         info->etdb = elog_open_tdb( info->logname, True );
697         unbecome_root();
698
699         if ( !info->etdb )
700                 return NT_STATUS_ACCESS_DENIED;
701
702         return NT_STATUS_OK;
703 }
704
705 /********************************************************************
706  ********************************************************************/
707
708 NTSTATUS _eventlog_CloseEventLog( pipes_struct * p, struct eventlog_CloseEventLog *r )
709 {
710         return elog_close( p, r->in.handle );
711 }
712
713 /********************************************************************
714  ********************************************************************/
715
716 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
717                                 EVENTLOG_Q_READ_EVENTLOG * q_u,
718                                 EVENTLOG_R_READ_EVENTLOG * r_u )
719 {
720         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
721         Eventlog_entry *entry = NULL, *ee_new = NULL;
722         uint32 num_records_read = 0;
723         prs_struct *ps;
724         int bytes_left, record_number;
725         uint32 elog_read_type, elog_read_dir;
726
727         if (info == NULL) {
728                 return NT_STATUS_INVALID_HANDLE;
729         }
730
731         info->flags = q_u->flags;
732         ps = &p->out_data.rdata;
733
734         bytes_left = q_u->max_read_size;
735
736         if ( !info->etdb )
737                 return NT_STATUS_ACCESS_DENIED;
738
739         /* check for valid flags.  Can't use the sequential and seek flags together */
740
741         elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
742         elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
743
744         if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) 
745                 ||  elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
746         {
747                 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
748                 return NT_STATUS_INVALID_PARAMETER;
749         }
750
751         /* a sequential read should ignore the offset */
752
753         if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
754                 record_number = info->current_record;
755         else
756                 record_number = q_u->offset;
757
758         while ( bytes_left > 0 ) {
759
760                 /* assume that when the record fetch fails, that we are done */
761
762                 entry = get_eventlog_record (ps->mem_ctx, ELOG_TDB_CTX(info->etdb), record_number);
763                 if (!entry) {
764                         break;
765                 }
766
767                 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
768
769                 /* Now see if there is enough room to add */
770
771                 if ( !(ee_new = read_package_entry( ps->mem_ctx, entry )) )
772                         return NT_STATUS_NO_MEMORY;
773
774                 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
775                         r_u->bytes_in_next_record = ee_new->record.length;
776
777                         /* response would be too big to fit in client-size buffer */
778
779                         bytes_left = 0;
780                         break;
781                 }
782
783                 add_record_to_resp( r_u, ee_new );
784                 bytes_left -= ee_new->record.length;
785                 TALLOC_FREE(entry);
786                 num_records_read = r_u->num_records - num_records_read;
787
788                 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
789                         "of [%d] records using [%d] bytes out of a max of [%d].\n",
790                          num_records_read, r_u->num_records,
791                          r_u->num_bytes_in_resp,
792                          q_u->max_read_size ) );
793
794                 if ( info->flags & EVENTLOG_FORWARDS_READ )
795                         record_number++;
796                 else
797                         record_number--;
798
799                 /* update the eventlog record pointer */
800
801                 info->current_record = record_number;
802         }
803
804         /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
805            say when there are no more records */
806
807         return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
808 }
809
810 /********************************************************************
811  _eventlog_GetOldestRecord
812  ********************************************************************/
813
814 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
815                                    struct eventlog_GetOldestRecord *r)
816 {
817         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
818
819         if (info == NULL) {
820                 return NT_STATUS_INVALID_HANDLE;
821         }
822
823         if ( !( get_oldest_entry_hook( info ) ) )
824                 return NT_STATUS_ACCESS_DENIED;
825
826         *r->out.oldest_entry = info->oldest_entry;
827
828         return NT_STATUS_OK;
829 }
830
831 /********************************************************************
832 _eventlog_GetNumRecords
833  ********************************************************************/
834
835 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
836                                  struct eventlog_GetNumRecords *r)
837 {
838         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
839
840         if (info == NULL) {
841                 return NT_STATUS_INVALID_HANDLE;
842         }
843
844         if ( !( get_num_records_hook( info ) ) )
845                 return NT_STATUS_ACCESS_DENIED;
846
847         *r->out.number = info->num_records;
848
849         return NT_STATUS_OK;
850 }
851
852 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
853 {
854         p->rng_fault_state = True;
855         return NT_STATUS_NOT_IMPLEMENTED;
856 }
857
858 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
859 {
860         p->rng_fault_state = True;
861         return NT_STATUS_NOT_IMPLEMENTED;
862 }
863
864 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
865 {
866         p->rng_fault_state = True;
867         return NT_STATUS_NOT_IMPLEMENTED;
868 }
869
870 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
871 {
872         p->rng_fault_state = True;
873         return NT_STATUS_NOT_IMPLEMENTED;
874 }
875
876 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
877 {
878         p->rng_fault_state = True;
879         return NT_STATUS_NOT_IMPLEMENTED;
880 }
881
882 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
883 {
884         p->rng_fault_state = True;
885         return NT_STATUS_NOT_IMPLEMENTED;
886 }
887
888 NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
889 {
890         p->rng_fault_state = True;
891         return NT_STATUS_NOT_IMPLEMENTED;
892 }
893
894 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
895 {
896         p->rng_fault_state = True;
897         return NT_STATUS_NOT_IMPLEMENTED;
898 }
899
900 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
901 {
902         p->rng_fault_state = True;
903         return NT_STATUS_NOT_IMPLEMENTED;
904 }
905
906 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
907 {
908         p->rng_fault_state = True;
909         return NT_STATUS_NOT_IMPLEMENTED;
910 }
911
912 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
913 {
914         p->rng_fault_state = True;
915         return NT_STATUS_NOT_IMPLEMENTED;
916 }
917
918 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
919 {
920         p->rng_fault_state = True;
921         return NT_STATUS_NOT_IMPLEMENTED;
922 }
923
924 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
925 {
926         p->rng_fault_state = True;
927         return NT_STATUS_NOT_IMPLEMENTED;
928 }
929
930 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
931 {
932         p->rng_fault_state = True;
933         return NT_STATUS_NOT_IMPLEMENTED;
934 }
935
936 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
937 {
938         p->rng_fault_state = True;
939         return NT_STATUS_NOT_IMPLEMENTED;
940 }
941
942 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
943 {
944         p->rng_fault_state = True;
945         return NT_STATUS_NOT_IMPLEMENTED;
946 }
947
948 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
949 {
950         p->rng_fault_state = True;
951         return NT_STATUS_NOT_IMPLEMENTED;
952 }
953
954 NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
955 {
956         p->rng_fault_state = True;
957         return NT_STATUS_NOT_IMPLEMENTED;
958 }
959
960 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
961 {
962         p->rng_fault_state = True;
963         return NT_STATUS_NOT_IMPLEMENTED;
964 }
965