Rename dos_errstr() to win_errstr() for consistency with Samba 4.
[sfrench/samba-autobuild/.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         SAFE_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(prs_struct *ps,
287                                 TDB_CONTEXT *tdb,
288                                 int recno)
289 {
290         Eventlog_entry *ee = NULL;
291         TDB_DATA ret, key;
292
293         int srecno;
294         int 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);
304
305         srecno = recno;
306         key.dptr = ( uint8 * ) &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(ps->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_tos();
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                 return False;
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                 return false;
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                 return false;
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                 ret = false;
468                 goto done;
469         }
470         uiRetention = value->v.dword;
471
472         wresult = reg_queryvalue(key, key, "MaxSize", &value);
473         if (!W_ERROR_IS_OK(wresult)) {
474                 DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
475                           win_errstr(wresult)));
476                 ret = false;
477                 goto done;
478         }
479         uiMaxSize = value->v.dword;
480
481         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
482         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
483
484         ret = true;
485
486 done:
487         TALLOC_FREE(ctx);
488         return ret;
489 }
490
491 /********************************************************************
492  ********************************************************************/
493
494 static Eventlog_entry *read_package_entry( prs_struct * ps,
495                                            Eventlog_entry * entry )
496 {
497         uint8 *offset;
498         Eventlog_entry *ee_new = NULL;
499
500         ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
501         if ( ee_new == NULL ) {
502                 return NULL;
503         }
504
505         entry->data_record.sid_padding =
506                 ( ( 4 -
507                     ( ( entry->data_record.source_name_len +
508                         entry->data_record.computer_name_len ) % 4 ) ) % 4 );
509         entry->data_record.data_padding =
510                 ( 4 -
511                   ( ( entry->data_record.strings_len +
512                       entry->data_record.user_data_len ) % 4 ) ) % 4;
513         entry->record.length = sizeof( Eventlog_record );
514         entry->record.length += entry->data_record.source_name_len;
515         entry->record.length += entry->data_record.computer_name_len;
516         if ( entry->record.user_sid_length == 0 ) {
517                 /* Should not pad to a DWORD boundary for writing out the sid if there is
518                    no SID, so just propagate the padding to pad the data */
519                 entry->data_record.data_padding +=
520                         entry->data_record.sid_padding;
521                 entry->data_record.sid_padding = 0;
522         }
523         DEBUG( 10,
524                ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
525         DEBUG( 10,
526                ( "data_padding is [%d].\n",
527                  entry->data_record.data_padding ) );
528
529         entry->record.length += entry->data_record.sid_padding;
530         entry->record.length += entry->record.user_sid_length;
531         entry->record.length += entry->data_record.strings_len;
532         entry->record.length += entry->data_record.user_data_len;
533         entry->record.length += entry->data_record.data_padding;
534         /* need another copy of length at the end of the data */
535         entry->record.length += sizeof( entry->record.length );
536         DEBUG( 10,
537                ( "entry->record.length is [%d].\n", entry->record.length ) );
538         entry->data =
539                 PRS_ALLOC_MEM( ps, uint8,
540                                entry->record.length -
541                                sizeof( Eventlog_record ) -
542                                sizeof( entry->record.length ) );
543         if ( entry->data == NULL ) {
544                 return NULL;
545         }
546         offset = entry->data;
547         memcpy( offset, &( entry->data_record.source_name ),
548                 entry->data_record.source_name_len );
549         offset += entry->data_record.source_name_len;
550         memcpy( offset, &( entry->data_record.computer_name ),
551                 entry->data_record.computer_name_len );
552         offset += entry->data_record.computer_name_len;
553         /* SID needs to be DWORD-aligned */
554         offset += entry->data_record.sid_padding;
555         entry->record.user_sid_offset =
556                 sizeof( Eventlog_record ) + ( offset - entry->data );
557         memcpy( offset, &( entry->data_record.sid ),
558                 entry->record.user_sid_length );
559         offset += entry->record.user_sid_length;
560         /* Now do the strings */
561         entry->record.string_offset =
562                 sizeof( Eventlog_record ) + ( offset - entry->data );
563         memcpy( offset, &( entry->data_record.strings ),
564                 entry->data_record.strings_len );
565         offset += entry->data_record.strings_len;
566         /* Now do the data */
567         entry->record.data_length = entry->data_record.user_data_len;
568         entry->record.data_offset =
569                 sizeof( Eventlog_record ) + ( offset - entry->data );
570         memcpy( offset, &( entry->data_record.user_data ),
571                 entry->data_record.user_data_len );
572         offset += entry->data_record.user_data_len;
573
574         memcpy( &( ee_new->record ), &entry->record,
575                 sizeof( Eventlog_record ) );
576         memcpy( &( ee_new->data_record ), &entry->data_record,
577                 sizeof( Eventlog_data_record ) );
578         ee_new->data = entry->data;
579
580         return ee_new;
581 }
582
583 /********************************************************************
584  ********************************************************************/
585
586 static bool add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
587                                 Eventlog_entry * ee_new )
588 {
589         Eventlog_entry *insert_point;
590
591         insert_point = r_u->entry;
592
593         if ( NULL == insert_point ) {
594                 r_u->entry = ee_new;
595                 ee_new->next = NULL;
596         } else {
597                 while ( ( NULL != insert_point->next ) ) {
598                         insert_point = insert_point->next;
599                 }
600                 ee_new->next = NULL;
601                 insert_point->next = ee_new;
602         }
603         r_u->num_records++;
604         r_u->num_bytes_in_resp += ee_new->record.length;
605
606         return True;
607 }
608
609 /********************************************************************
610  _eventlog_OpenEventLogW
611  ********************************************************************/
612
613 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
614                                  struct eventlog_OpenEventLogW *r)
615 {
616         const char *servername = "";
617         const char *logname = "";
618         EVENTLOG_INFO *info;
619         NTSTATUS result;
620
621         if (r->in.servername->string) {
622                 servername = r->in.servername->string;
623         }
624
625         if (r->in.logname->string) {
626                 logname = r->in.logname->string;
627         }
628         
629         DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
630                 servername, logname ));
631                 
632         /* according to MSDN, if the logfile cannot be found, we should
633           default to the "Application" log */
634           
635         if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, r->out.handle )) )
636                 return result;
637
638         if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
639                 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
640                         logname ));
641                 elog_close( p, r->out.handle );
642                 return NT_STATUS_INVALID_HANDLE;
643         }
644
645         DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
646
647         sync_eventlog_params( info );
648         prune_eventlog( ELOG_TDB_CTX(info->etdb) );
649
650         return NT_STATUS_OK;
651 }
652
653 /********************************************************************
654  _eventlog_ClearEventLogW
655  This call still needs some work
656  ********************************************************************/
657 /** The windows client seems to be doing something funny with the file name
658    A call like
659       ClearEventLog(handle, "backup_file")
660    on the client side will result in the backup file name looking like this on the
661    server side:
662       \??\${CWD of client}\backup_file
663    If an absolute path gets specified, such as
664       ClearEventLog(handle, "C:\\temp\\backup_file")
665    then it is still mangled by the client into this:
666       \??\C:\temp\backup_file
667    when it is on the wire.
668    I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
669    would be added in given that the backup file gets written on the server side. */
670
671 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
672                                   struct eventlog_ClearEventLogW *r)
673 {
674         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
675         const char *backup_file_name = NULL;
676
677         if ( !info )
678                 return NT_STATUS_INVALID_HANDLE;
679
680         if (r->in.backupfile && r->in.backupfile->string) {
681
682                 backup_file_name = r->in.backupfile->string;
683
684                 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
685                         "file name for log [%s].",
686                          backup_file_name, info->logname ) );
687         }
688
689         /* check for WRITE access to the file */
690
691         if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
692                 return NT_STATUS_ACCESS_DENIED;
693
694         /* Force a close and reopen */
695
696         elog_close_tdb( info->etdb, True );
697         become_root();
698         info->etdb = elog_open_tdb( info->logname, True );
699         unbecome_root();
700
701         if ( !info->etdb )
702                 return NT_STATUS_ACCESS_DENIED;
703
704         return NT_STATUS_OK;
705 }
706
707 /********************************************************************
708  ********************************************************************/
709
710 NTSTATUS _eventlog_CloseEventLog( pipes_struct * p, struct eventlog_CloseEventLog *r )
711 {
712         return elog_close( p, r->in.handle );
713 }
714
715 /********************************************************************
716  ********************************************************************/
717
718 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
719                                 EVENTLOG_Q_READ_EVENTLOG * q_u,
720                                 EVENTLOG_R_READ_EVENTLOG * r_u )
721 {
722         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
723         Eventlog_entry *entry = NULL, *ee_new = NULL;
724         uint32 num_records_read = 0;
725         prs_struct *ps;
726         int bytes_left, record_number;
727         uint32 elog_read_type, elog_read_dir;
728
729         if (info == NULL) {
730                 return NT_STATUS_INVALID_HANDLE;
731         }
732
733         info->flags = q_u->flags;
734         ps = &p->out_data.rdata;
735
736         bytes_left = q_u->max_read_size;
737
738         if ( !info->etdb )
739                 return NT_STATUS_ACCESS_DENIED;
740
741         /* check for valid flags.  Can't use the sequential and seek flags together */
742
743         elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
744         elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
745
746         if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) 
747                 ||  elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
748         {
749                 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
750                 return NT_STATUS_INVALID_PARAMETER;
751         }
752
753         /* a sequential read should ignore the offset */
754
755         if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
756                 record_number = info->current_record;
757         else
758                 record_number = q_u->offset;
759
760         while ( bytes_left > 0 ) {
761
762                 /* assume that when the record fetch fails, that we are done */
763
764                 entry = get_eventlog_record (ps, ELOG_TDB_CTX(info->etdb), record_number);
765                 if (!entry) {
766                         break;
767                 }
768
769                 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
770
771                 /* Now see if there is enough room to add */
772
773                 if ( !(ee_new = read_package_entry( ps, entry )) )
774                         return NT_STATUS_NO_MEMORY;
775
776                 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
777                         r_u->bytes_in_next_record = ee_new->record.length;
778
779                         /* response would be too big to fit in client-size buffer */
780
781                         bytes_left = 0;
782                         break;
783                 }
784
785                 add_record_to_resp( r_u, ee_new );
786                 bytes_left -= ee_new->record.length;
787                 TALLOC_FREE(entry);
788                 num_records_read = r_u->num_records - num_records_read;
789
790                 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
791                         "of [%d] records using [%d] bytes out of a max of [%d].\n",
792                          num_records_read, r_u->num_records,
793                          r_u->num_bytes_in_resp,
794                          q_u->max_read_size ) );
795
796                 if ( info->flags & EVENTLOG_FORWARDS_READ )
797                         record_number++;
798                 else
799                         record_number--;
800
801                 /* update the eventlog record pointer */
802
803                 info->current_record = record_number;
804         }
805
806         /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
807            say when there are no more records */
808
809         return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
810 }
811
812 /********************************************************************
813  _eventlog_GetOldestRecord
814  ********************************************************************/
815
816 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
817                                    struct eventlog_GetOldestRecord *r)
818 {
819         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
820
821         if (info == NULL) {
822                 return NT_STATUS_INVALID_HANDLE;
823         }
824
825         if ( !( get_oldest_entry_hook( info ) ) )
826                 return NT_STATUS_ACCESS_DENIED;
827
828         *r->out.oldest_entry = info->oldest_entry;
829
830         return NT_STATUS_OK;
831 }
832
833 /********************************************************************
834 _eventlog_GetNumRecords
835  ********************************************************************/
836
837 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
838                                  struct eventlog_GetNumRecords *r)
839 {
840         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
841
842         if (info == NULL) {
843                 return NT_STATUS_INVALID_HANDLE;
844         }
845
846         if ( !( get_num_records_hook( info ) ) )
847                 return NT_STATUS_ACCESS_DENIED;
848
849         *r->out.number = info->num_records;
850
851         return NT_STATUS_OK;
852 }
853
854 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
855 {
856         p->rng_fault_state = True;
857         return NT_STATUS_NOT_IMPLEMENTED;
858 }
859
860 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
861 {
862         p->rng_fault_state = True;
863         return NT_STATUS_NOT_IMPLEMENTED;
864 }
865
866 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
867 {
868         p->rng_fault_state = True;
869         return NT_STATUS_NOT_IMPLEMENTED;
870 }
871
872 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
873 {
874         p->rng_fault_state = True;
875         return NT_STATUS_NOT_IMPLEMENTED;
876 }
877
878 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
879 {
880         p->rng_fault_state = True;
881         return NT_STATUS_NOT_IMPLEMENTED;
882 }
883
884 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
885 {
886         p->rng_fault_state = True;
887         return NT_STATUS_NOT_IMPLEMENTED;
888 }
889
890 NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
891 {
892         p->rng_fault_state = True;
893         return NT_STATUS_NOT_IMPLEMENTED;
894 }
895
896 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
897 {
898         p->rng_fault_state = True;
899         return NT_STATUS_NOT_IMPLEMENTED;
900 }
901
902 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
903 {
904         p->rng_fault_state = True;
905         return NT_STATUS_NOT_IMPLEMENTED;
906 }
907
908 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
909 {
910         p->rng_fault_state = True;
911         return NT_STATUS_NOT_IMPLEMENTED;
912 }
913
914 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
915 {
916         p->rng_fault_state = True;
917         return NT_STATUS_NOT_IMPLEMENTED;
918 }
919
920 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
921 {
922         p->rng_fault_state = True;
923         return NT_STATUS_NOT_IMPLEMENTED;
924 }
925
926 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
927 {
928         p->rng_fault_state = True;
929         return NT_STATUS_NOT_IMPLEMENTED;
930 }
931
932 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
933 {
934         p->rng_fault_state = True;
935         return NT_STATUS_NOT_IMPLEMENTED;
936 }
937
938 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
939 {
940         p->rng_fault_state = True;
941         return NT_STATUS_NOT_IMPLEMENTED;
942 }
943
944 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
945 {
946         p->rng_fault_state = True;
947         return NT_STATUS_NOT_IMPLEMENTED;
948 }
949
950 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
951 {
952         p->rng_fault_state = True;
953         return NT_STATUS_NOT_IMPLEMENTED;
954 }
955
956 NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
957 {
958         p->rng_fault_state = True;
959         return NT_STATUS_NOT_IMPLEMENTED;
960 }
961
962 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
963 {
964         p->rng_fault_state = True;
965         return NT_STATUS_NOT_IMPLEMENTED;
966 }
967