Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into dmapi-integration
[nivanova/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         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,
288                                 TDB_CONTEXT *tdb,
289                                 int recno)
290 {
291         Eventlog_entry *ee = NULL;
292         TDB_DATA ret, key;
293
294         int srecno;
295         int reclen;
296         int len;
297
298         char *wpsource = NULL;
299         char *wpcomputer = NULL;
300         char *wpsid = NULL;
301         char *wpstrs = NULL;
302         char *puserdata = NULL;
303
304         key.dsize = sizeof(int32);
305
306         srecno = recno;
307         key.dptr = ( uint8 * ) &srecno;
308
309         ret = tdb_fetch( tdb, key );
310
311         if ( ret.dsize == 0 ) {
312                 DEBUG( 8,
313                        ( "Can't find a record for the key, record %d\n",
314                          recno ) );
315                 return NULL;
316         }
317
318         len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
319
320         DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
321
322         if ( !len )
323                 return NULL;
324
325         ee = TALLOC_ARRAY(ps->mem_ctx, Eventlog_entry, 1);
326         if (!ee) {
327                 return NULL;
328         }
329         ZERO_STRUCTP(ee);
330
331         len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
332                           &ee->record.length, &ee->record.reserved1,
333                           &ee->record.record_number,
334                           &ee->record.time_generated,
335                           &ee->record.time_written, &ee->record.event_id,
336                           &ee->record.event_type, &ee->record.num_strings,
337                           &ee->record.event_category, &ee->record.reserved2,
338                           &ee->record.closing_record_number,
339                           &ee->record.string_offset,
340                           &ee->record.user_sid_length,
341                           &ee->record.user_sid_offset,
342                           &ee->record.data_length, &ee->record.data_offset,
343                           &ee->data_record.source_name_len, &wpsource,
344                           &ee->data_record.computer_name_len, &wpcomputer,
345                           &ee->data_record.sid_padding,
346                           &ee->record.user_sid_length, &wpsid,
347                           &ee->data_record.strings_len, &wpstrs,
348                           &ee->data_record.user_data_len, &puserdata,
349                           &ee->data_record.data_padding );
350         DEBUG( 10,
351                ( "Read record %d, len in tdb was %d\n",
352                  ee->record.record_number, len ) );
353
354         /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
355            into it's 2nd argment for 'B' */
356
357         if (wpcomputer) {
358                 ee->data_record.computer_name = (smb_ucs2_t *)TALLOC_MEMDUP(
359                         ee, wpcomputer, ee->data_record.computer_name_len);
360                 if (!ee->data_record.computer_name) {
361                         TALLOC_FREE(ee);
362                         goto out;
363                 }
364         }
365         if (wpsource) {
366                 ee->data_record.source_name = (smb_ucs2_t *)TALLOC_MEMDUP(
367                         ee, wpsource, ee->data_record.source_name_len);
368                 if (!ee->data_record.source_name) {
369                         TALLOC_FREE(ee);
370                         goto out;
371                 }
372         }
373
374         if (wpsid) {
375                 ee->data_record.sid = (smb_ucs2_t *)TALLOC_MEMDUP(
376                         ee, wpsid, ee->record.user_sid_length);
377                 if (!ee->data_record.sid) {
378                         TALLOC_FREE(ee);
379                         goto out;
380                 }
381         }
382         if (wpstrs) {
383                 ee->data_record.strings = (smb_ucs2_t *)TALLOC_MEMDUP(
384                         ee, wpstrs, ee->data_record.strings_len);
385                 if (!ee->data_record.strings) {
386                         TALLOC_FREE(ee);
387                         goto out;
388                 }
389         }
390
391         if (puserdata) {
392                 ee->data_record.user_data = (char *)TALLOC_MEMDUP(
393                         ee, puserdata, ee->data_record.user_data_len);
394                 if (!ee->data_record.user_data) {
395                         TALLOC_FREE(ee);
396                         goto out;
397                 }
398         }
399
400   out:
401
402         SAFE_FREE(wpcomputer);
403         SAFE_FREE(wpsource);
404         SAFE_FREE(wpsid);
405         SAFE_FREE(wpstrs);
406         SAFE_FREE(puserdata);
407
408         DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
409         DEBUG( 10,
410                ( "get_eventlog_record: computer_name %d is ",
411                  ee->data_record.computer_name_len ) );
412         SAFE_FREE(ret.dptr);
413         return ee;
414 }
415
416 /********************************************************************
417  note that this can only be called AFTER the table is constructed, 
418  since it uses the table to find the tdb handle
419  ********************************************************************/
420
421 static bool sync_eventlog_params( EVENTLOG_INFO *info )
422 {
423         char *path = NULL;
424         uint32 uiMaxSize;
425         uint32 uiRetention;
426         struct registry_key *key;
427         struct registry_value *value;
428         WERROR wresult;
429         char *elogname = info->logname;
430         TALLOC_CTX *ctx = talloc_tos();
431         bool ret = false;
432
433         DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
434
435         if ( !info->etdb ) {
436                 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
437                 return False;
438         }
439         /* set resonable defaults.  512Kb on size and 1 week on time */
440
441         uiMaxSize = 0x80000;
442         uiRetention = 604800;
443
444         /* the general idea is to internally open the registry 
445            key and retrieve the values.  That way we can continue 
446            to use the same fetch/store api that we use in 
447            srv_reg_nt.c */
448
449         path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
450         if (!path) {
451                 return false;
452         }
453
454         wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
455                                 &key);
456
457         if ( !W_ERROR_IS_OK( wresult ) ) {
458                 DEBUG( 4,
459                        ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
460                          path, dos_errstr( wresult ) ) );
461                 return false;
462         }
463
464         wresult = reg_queryvalue(key, key, "Retention", &value);
465         if (!W_ERROR_IS_OK(wresult)) {
466                 DEBUG(4, ("Failed to query value \"Retention\": %s\n",
467                           dos_errstr(wresult)));
468                 ret = false;
469                 goto done;
470         }
471         uiRetention = value->v.dword;
472
473         wresult = reg_queryvalue(key, key, "MaxSize", &value);
474         if (!W_ERROR_IS_OK(wresult)) {
475                 DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
476                           dos_errstr(wresult)));
477                 ret = false;
478                 goto done;
479         }
480         uiMaxSize = value->v.dword;
481
482         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
483         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
484
485         ret = true;
486
487 done:
488         TALLOC_FREE(ctx);
489         return ret;
490 }
491
492 /********************************************************************
493  ********************************************************************/
494
495 static Eventlog_entry *read_package_entry( prs_struct * ps,
496                                            EVENTLOG_Q_READ_EVENTLOG * q_u,
497                                            EVENTLOG_R_READ_EVENTLOG * r_u,
498                                            Eventlog_entry * entry )
499 {
500         uint8 *offset;
501         Eventlog_entry *ee_new = NULL;
502
503         ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
504         if ( ee_new == NULL ) {
505                 return NULL;
506         }
507
508         entry->data_record.sid_padding =
509                 ( ( 4 -
510                     ( ( entry->data_record.source_name_len +
511                         entry->data_record.computer_name_len ) % 4 ) ) % 4 );
512         entry->data_record.data_padding =
513                 ( 4 -
514                   ( ( entry->data_record.strings_len +
515                       entry->data_record.user_data_len ) % 4 ) ) % 4;
516         entry->record.length = sizeof( Eventlog_record );
517         entry->record.length += entry->data_record.source_name_len;
518         entry->record.length += entry->data_record.computer_name_len;
519         if ( entry->record.user_sid_length == 0 ) {
520                 /* Should not pad to a DWORD boundary for writing out the sid if there is
521                    no SID, so just propagate the padding to pad the data */
522                 entry->data_record.data_padding +=
523                         entry->data_record.sid_padding;
524                 entry->data_record.sid_padding = 0;
525         }
526         DEBUG( 10,
527                ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
528         DEBUG( 10,
529                ( "data_padding is [%d].\n",
530                  entry->data_record.data_padding ) );
531
532         entry->record.length += entry->data_record.sid_padding;
533         entry->record.length += entry->record.user_sid_length;
534         entry->record.length += entry->data_record.strings_len;
535         entry->record.length += entry->data_record.user_data_len;
536         entry->record.length += entry->data_record.data_padding;
537         /* need another copy of length at the end of the data */
538         entry->record.length += sizeof( entry->record.length );
539         DEBUG( 10,
540                ( "entry->record.length is [%d].\n", entry->record.length ) );
541         entry->data =
542                 PRS_ALLOC_MEM( ps, uint8,
543                                entry->record.length -
544                                sizeof( Eventlog_record ) -
545                                sizeof( entry->record.length ) );
546         if ( entry->data == NULL ) {
547                 return NULL;
548         }
549         offset = entry->data;
550         memcpy( offset, &( entry->data_record.source_name ),
551                 entry->data_record.source_name_len );
552         offset += entry->data_record.source_name_len;
553         memcpy( offset, &( entry->data_record.computer_name ),
554                 entry->data_record.computer_name_len );
555         offset += entry->data_record.computer_name_len;
556         /* SID needs to be DWORD-aligned */
557         offset += entry->data_record.sid_padding;
558         entry->record.user_sid_offset =
559                 sizeof( Eventlog_record ) + ( offset - entry->data );
560         memcpy( offset, &( entry->data_record.sid ),
561                 entry->record.user_sid_length );
562         offset += entry->record.user_sid_length;
563         /* Now do the strings */
564         entry->record.string_offset =
565                 sizeof( Eventlog_record ) + ( offset - entry->data );
566         memcpy( offset, &( entry->data_record.strings ),
567                 entry->data_record.strings_len );
568         offset += entry->data_record.strings_len;
569         /* Now do the data */
570         entry->record.data_length = entry->data_record.user_data_len;
571         entry->record.data_offset =
572                 sizeof( Eventlog_record ) + ( offset - entry->data );
573         memcpy( offset, &( entry->data_record.user_data ),
574                 entry->data_record.user_data_len );
575         offset += entry->data_record.user_data_len;
576
577         memcpy( &( ee_new->record ), &entry->record,
578                 sizeof( Eventlog_record ) );
579         memcpy( &( ee_new->data_record ), &entry->data_record,
580                 sizeof( Eventlog_data_record ) );
581         ee_new->data = entry->data;
582
583         return ee_new;
584 }
585
586 /********************************************************************
587  ********************************************************************/
588
589 static bool add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
590                                 Eventlog_entry * ee_new )
591 {
592         Eventlog_entry *insert_point;
593
594         insert_point = r_u->entry;
595
596         if ( NULL == insert_point ) {
597                 r_u->entry = ee_new;
598                 ee_new->next = NULL;
599         } else {
600                 while ( ( NULL != insert_point->next ) ) {
601                         insert_point = insert_point->next;
602                 }
603                 ee_new->next = NULL;
604                 insert_point->next = ee_new;
605         }
606         r_u->num_records++;
607         r_u->num_bytes_in_resp += ee_new->record.length;
608
609         return True;
610 }
611
612 /********************************************************************
613  ********************************************************************/
614
615 NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
616                                 EVENTLOG_Q_OPEN_EVENTLOG * q_u,
617                                 EVENTLOG_R_OPEN_EVENTLOG * r_u )
618 {
619         fstring servername, logname;
620         EVENTLOG_INFO *info;
621         NTSTATUS result;
622
623         fstrcpy( servername, "" );
624         if ( q_u->servername.string ) {
625                 rpcstr_pull( servername, q_u->servername.string->buffer,
626                              sizeof( servername ),
627                              q_u->servername.string->uni_str_len * 2, 0 );
628         }
629
630         fstrcpy( logname, "" );
631         if ( q_u->logname.string ) {
632                 rpcstr_pull( logname, q_u->logname.string->buffer,
633                              sizeof( logname ),
634                              q_u->logname.string->uni_str_len * 2, 0 );
635         }
636         
637         DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
638                 servername, logname ));
639                 
640         /* according to MSDN, if the logfile cannot be found, we should
641           default to the "Application" log */
642           
643         if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) )
644                 return result;
645
646         if ( !(info = find_eventlog_info_by_hnd( p, &r_u->handle )) ) {
647                 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
648                         logname ));
649                 elog_close( p, &r_u->handle );
650                 return NT_STATUS_INVALID_HANDLE;
651         }
652
653         DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
654
655         sync_eventlog_params( info );
656         prune_eventlog( ELOG_TDB_CTX(info->etdb) );
657
658         return NT_STATUS_OK;
659 }
660
661 /********************************************************************
662  This call still needs some work
663  ********************************************************************/
664
665 NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
666                                  EVENTLOG_Q_CLEAR_EVENTLOG * q_u,
667                                  EVENTLOG_R_CLEAR_EVENTLOG * r_u )
668 {
669         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
670         char *backup_file_name = NULL;
671
672         if ( !info )
673                 return NT_STATUS_INVALID_HANDLE;
674
675         if (q_u->backupfile.string) {
676                 size_t len = rpcstr_pull_talloc(p->mem_ctx,
677                                 &backup_file_name,
678                                 q_u->backupfile.string->buffer,
679                                 q_u->backupfile.string->uni_str_len * 2,
680                                 0 );
681                 if (len == (size_t)-1 || !backup_file_name) {
682                         return NT_STATUS_INVALID_PARAMETER;
683                 }
684
685                 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
686                         "file name for log [%s].",
687                          backup_file_name, info->logname ) );
688         }
689
690         /* check for WRITE access to the file */
691
692         if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
693                 return NT_STATUS_ACCESS_DENIED;
694
695         /* Force a close and reopen */
696
697         elog_close_tdb( info->etdb, True );
698         become_root();
699         info->etdb = elog_open_tdb( info->logname, True );
700         unbecome_root();
701
702         if ( !info->etdb )
703                 return NT_STATUS_ACCESS_DENIED;
704
705         return NT_STATUS_OK;
706 }
707
708 /********************************************************************
709  ********************************************************************/
710
711 NTSTATUS _eventlog_CloseEventLog( pipes_struct * p, struct eventlog_CloseEventLog *r )
712 {
713         return elog_close( p, r->in.handle );
714 }
715
716 /********************************************************************
717  ********************************************************************/
718
719 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
720                                 EVENTLOG_Q_READ_EVENTLOG * q_u,
721                                 EVENTLOG_R_READ_EVENTLOG * r_u )
722 {
723         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
724         Eventlog_entry *entry = NULL, *ee_new = NULL;
725         uint32 num_records_read = 0;
726         prs_struct *ps;
727         int bytes_left, record_number;
728         uint32 elog_read_type, elog_read_dir;
729
730         if (info == NULL) {
731                 return NT_STATUS_INVALID_HANDLE;
732         }
733
734         info->flags = q_u->flags;
735         ps = &p->out_data.rdata;
736
737         bytes_left = q_u->max_read_size;
738
739         if ( !info->etdb )
740                 return NT_STATUS_ACCESS_DENIED;
741
742         /* check for valid flags.  Can't use the sequential and seek flags together */
743
744         elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
745         elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
746
747         if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) 
748                 ||  elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
749         {
750                 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
751                 return NT_STATUS_INVALID_PARAMETER;
752         }
753
754         /* a sequential read should ignore the offset */
755
756         if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
757                 record_number = info->current_record;
758         else
759                 record_number = q_u->offset;
760
761         while ( bytes_left > 0 ) {
762
763                 /* assume that when the record fetch fails, that we are done */
764
765                 entry = get_eventlog_record (ps, ELOG_TDB_CTX(info->etdb), record_number);
766                 if (!entry) {
767                         break;
768                 }
769
770                 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
771
772                 /* Now see if there is enough room to add */
773
774                 if ( !(ee_new = read_package_entry( ps, q_u, r_u, entry )) )
775                         return NT_STATUS_NO_MEMORY;
776
777                 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
778                         r_u->bytes_in_next_record = ee_new->record.length;
779
780                         /* response would be too big to fit in client-size buffer */
781
782                         bytes_left = 0;
783                         break;
784                 }
785
786                 add_record_to_resp( r_u, ee_new );
787                 bytes_left -= ee_new->record.length;
788                 TALLOC_FREE(entry);
789                 num_records_read = r_u->num_records - num_records_read;
790
791                 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
792                         "of [%d] records using [%d] bytes out of a max of [%d].\n",
793                          num_records_read, r_u->num_records,
794                          r_u->num_bytes_in_resp,
795                          q_u->max_read_size ) );
796
797                 if ( info->flags & EVENTLOG_FORWARDS_READ )
798                         record_number++;
799                 else
800                         record_number--;
801
802                 /* update the eventlog record pointer */
803
804                 info->current_record = record_number;
805         }
806
807         /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
808            say when there are no more records */
809
810         return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
811 }
812
813 /********************************************************************
814  ********************************************************************/
815
816 NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p,
817                                    EVENTLOG_Q_GET_OLDEST_ENTRY * q_u,
818                                    EVENTLOG_R_GET_OLDEST_ENTRY * r_u )
819 {
820         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
821
822         if (info == NULL) {
823                 return NT_STATUS_INVALID_HANDLE;
824         }
825
826         if ( !( get_oldest_entry_hook( info ) ) )
827                 return NT_STATUS_ACCESS_DENIED;
828
829         r_u->oldest_entry = info->oldest_entry;
830
831         return NT_STATUS_OK;
832 }
833
834 /********************************************************************
835  ********************************************************************/
836
837 NTSTATUS _eventlog_get_num_records( pipes_struct * p,
838                                   EVENTLOG_Q_GET_NUM_RECORDS * q_u,
839                                   EVENTLOG_R_GET_NUM_RECORDS * r_u )
840 {
841         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
842
843         if (info == NULL) {
844                 return NT_STATUS_INVALID_HANDLE;
845         }
846
847         if ( !( get_num_records_hook( info ) ) )
848                 return NT_STATUS_ACCESS_DENIED;
849
850         r_u->num_records = info->num_records;
851
852         return NT_STATUS_OK;
853 }
854
855 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p, struct eventlog_ClearEventLogW *r)
856 {
857         p->rng_fault_state = True;
858         return NT_STATUS_NOT_IMPLEMENTED;
859 }
860
861 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
862 {
863         p->rng_fault_state = True;
864         return NT_STATUS_NOT_IMPLEMENTED;
865 }
866
867 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
868 {
869         p->rng_fault_state = True;
870         return NT_STATUS_NOT_IMPLEMENTED;
871 }
872
873 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p, struct eventlog_GetNumRecords *r)
874 {
875         p->rng_fault_state = True;
876         return NT_STATUS_NOT_IMPLEMENTED;
877 }
878
879 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p, struct eventlog_GetOldestRecord *r)
880 {
881         p->rng_fault_state = True;
882         return NT_STATUS_NOT_IMPLEMENTED;
883 }
884
885 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
886 {
887         p->rng_fault_state = True;
888         return NT_STATUS_NOT_IMPLEMENTED;
889 }
890
891 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p, struct eventlog_OpenEventLogW *r)
892 {
893         p->rng_fault_state = True;
894         return NT_STATUS_NOT_IMPLEMENTED;
895 }
896
897 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
898 {
899         p->rng_fault_state = True;
900         return NT_STATUS_NOT_IMPLEMENTED;
901 }
902
903 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
904 {
905         p->rng_fault_state = True;
906         return NT_STATUS_NOT_IMPLEMENTED;
907 }
908
909 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
910 {
911         p->rng_fault_state = True;
912         return NT_STATUS_NOT_IMPLEMENTED;
913 }
914
915 NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
916 {
917         p->rng_fault_state = True;
918         return NT_STATUS_NOT_IMPLEMENTED;
919 }
920
921 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
922 {
923         p->rng_fault_state = True;
924         return NT_STATUS_NOT_IMPLEMENTED;
925 }
926
927 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
928 {
929         p->rng_fault_state = True;
930         return NT_STATUS_NOT_IMPLEMENTED;
931 }
932
933 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
934 {
935         p->rng_fault_state = True;
936         return NT_STATUS_NOT_IMPLEMENTED;
937 }
938
939 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
940 {
941         p->rng_fault_state = True;
942         return NT_STATUS_NOT_IMPLEMENTED;
943 }
944
945 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
946 {
947         p->rng_fault_state = True;
948         return NT_STATUS_NOT_IMPLEMENTED;
949 }
950
951 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
952 {
953         p->rng_fault_state = True;
954         return NT_STATUS_NOT_IMPLEMENTED;
955 }
956
957 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
958 {
959         p->rng_fault_state = True;
960         return NT_STATUS_NOT_IMPLEMENTED;
961 }
962
963 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
964 {
965         p->rng_fault_state = True;
966         return NT_STATUS_NOT_IMPLEMENTED;
967 }
968
969 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
970 {
971         p->rng_fault_state = True;
972         return NT_STATUS_NOT_IMPLEMENTED;
973 }
974
975 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
976 {
977         p->rng_fault_state = True;
978         return NT_STATUS_NOT_IMPLEMENTED;
979 }
980
981 NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
982 {
983         p->rng_fault_state = True;
984         return NT_STATUS_NOT_IMPLEMENTED;
985 }
986
987 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
988 {
989         p->rng_fault_state = True;
990         return NT_STATUS_NOT_IMPLEMENTED;
991 }
992