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