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