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