Copy inline comment for _eventlog_ClearEventLogW() from rpc_parse to rpc_server.
[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  _eventlog_ClearEventLogW
663  This call still needs some work
664  ********************************************************************/
665 /** The windows client seems to be doing something funny with the file name
666    A call like
667       ClearEventLog(handle, "backup_file")
668    on the client side will result in the backup file name looking like this on the
669    server side:
670       \??\${CWD of client}\backup_file
671    If an absolute path gets specified, such as
672       ClearEventLog(handle, "C:\\temp\\backup_file")
673    then it is still mangled by the client into this:
674       \??\C:\temp\backup_file
675    when it is on the wire.
676    I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
677    would be added in given that the backup file gets written on the server side. */
678
679 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
680                                   struct eventlog_ClearEventLogW *r)
681 {
682         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
683         const char *backup_file_name = NULL;
684
685         if ( !info )
686                 return NT_STATUS_INVALID_HANDLE;
687
688         if (r->in.backupfile && r->in.backupfile->string) {
689
690                 backup_file_name = r->in.backupfile->string;
691
692                 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
693                         "file name for log [%s].",
694                          backup_file_name, info->logname ) );
695         }
696
697         /* check for WRITE access to the file */
698
699         if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
700                 return NT_STATUS_ACCESS_DENIED;
701
702         /* Force a close and reopen */
703
704         elog_close_tdb( info->etdb, True );
705         become_root();
706         info->etdb = elog_open_tdb( info->logname, True );
707         unbecome_root();
708
709         if ( !info->etdb )
710                 return NT_STATUS_ACCESS_DENIED;
711
712         return NT_STATUS_OK;
713 }
714
715 /********************************************************************
716  ********************************************************************/
717
718 NTSTATUS _eventlog_CloseEventLog( pipes_struct * p, struct eventlog_CloseEventLog *r )
719 {
720         return elog_close( p, r->in.handle );
721 }
722
723 /********************************************************************
724  ********************************************************************/
725
726 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
727                                 EVENTLOG_Q_READ_EVENTLOG * q_u,
728                                 EVENTLOG_R_READ_EVENTLOG * r_u )
729 {
730         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
731         Eventlog_entry *entry = NULL, *ee_new = NULL;
732         uint32 num_records_read = 0;
733         prs_struct *ps;
734         int bytes_left, record_number;
735         uint32 elog_read_type, elog_read_dir;
736
737         if (info == NULL) {
738                 return NT_STATUS_INVALID_HANDLE;
739         }
740
741         info->flags = q_u->flags;
742         ps = &p->out_data.rdata;
743
744         bytes_left = q_u->max_read_size;
745
746         if ( !info->etdb )
747                 return NT_STATUS_ACCESS_DENIED;
748
749         /* check for valid flags.  Can't use the sequential and seek flags together */
750
751         elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
752         elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
753
754         if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) 
755                 ||  elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
756         {
757                 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
758                 return NT_STATUS_INVALID_PARAMETER;
759         }
760
761         /* a sequential read should ignore the offset */
762
763         if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
764                 record_number = info->current_record;
765         else
766                 record_number = q_u->offset;
767
768         while ( bytes_left > 0 ) {
769
770                 /* assume that when the record fetch fails, that we are done */
771
772                 entry = get_eventlog_record (ps, ELOG_TDB_CTX(info->etdb), record_number);
773                 if (!entry) {
774                         break;
775                 }
776
777                 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
778
779                 /* Now see if there is enough room to add */
780
781                 if ( !(ee_new = read_package_entry( ps, q_u, r_u, entry )) )
782                         return NT_STATUS_NO_MEMORY;
783
784                 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
785                         r_u->bytes_in_next_record = ee_new->record.length;
786
787                         /* response would be too big to fit in client-size buffer */
788
789                         bytes_left = 0;
790                         break;
791                 }
792
793                 add_record_to_resp( r_u, ee_new );
794                 bytes_left -= ee_new->record.length;
795                 TALLOC_FREE(entry);
796                 num_records_read = r_u->num_records - num_records_read;
797
798                 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
799                         "of [%d] records using [%d] bytes out of a max of [%d].\n",
800                          num_records_read, r_u->num_records,
801                          r_u->num_bytes_in_resp,
802                          q_u->max_read_size ) );
803
804                 if ( info->flags & EVENTLOG_FORWARDS_READ )
805                         record_number++;
806                 else
807                         record_number--;
808
809                 /* update the eventlog record pointer */
810
811                 info->current_record = record_number;
812         }
813
814         /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
815            say when there are no more records */
816
817         return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
818 }
819
820 /********************************************************************
821  _eventlog_GetOldestRecord
822  ********************************************************************/
823
824 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
825                                    struct eventlog_GetOldestRecord *r)
826 {
827         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
828
829         if (info == NULL) {
830                 return NT_STATUS_INVALID_HANDLE;
831         }
832
833         if ( !( get_oldest_entry_hook( info ) ) )
834                 return NT_STATUS_ACCESS_DENIED;
835
836         *r->out.oldest_entry = info->oldest_entry;
837
838         return NT_STATUS_OK;
839 }
840
841 /********************************************************************
842 _eventlog_GetNumRecords
843  ********************************************************************/
844
845 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
846                                  struct eventlog_GetNumRecords *r)
847 {
848         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
849
850         if (info == NULL) {
851                 return NT_STATUS_INVALID_HANDLE;
852         }
853
854         if ( !( get_num_records_hook( info ) ) )
855                 return NT_STATUS_ACCESS_DENIED;
856
857         *r->out.number = info->num_records;
858
859         return NT_STATUS_OK;
860 }
861
862 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
863 {
864         p->rng_fault_state = True;
865         return NT_STATUS_NOT_IMPLEMENTED;
866 }
867
868 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
869 {
870         p->rng_fault_state = True;
871         return NT_STATUS_NOT_IMPLEMENTED;
872 }
873
874 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
875 {
876         p->rng_fault_state = True;
877         return NT_STATUS_NOT_IMPLEMENTED;
878 }
879
880 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p, struct eventlog_OpenEventLogW *r)
881 {
882         p->rng_fault_state = True;
883         return NT_STATUS_NOT_IMPLEMENTED;
884 }
885
886 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
887 {
888         p->rng_fault_state = True;
889         return NT_STATUS_NOT_IMPLEMENTED;
890 }
891
892 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
893 {
894         p->rng_fault_state = True;
895         return NT_STATUS_NOT_IMPLEMENTED;
896 }
897
898 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
899 {
900         p->rng_fault_state = True;
901         return NT_STATUS_NOT_IMPLEMENTED;
902 }
903
904 NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
905 {
906         p->rng_fault_state = True;
907         return NT_STATUS_NOT_IMPLEMENTED;
908 }
909
910 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
911 {
912         p->rng_fault_state = True;
913         return NT_STATUS_NOT_IMPLEMENTED;
914 }
915
916 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
917 {
918         p->rng_fault_state = True;
919         return NT_STATUS_NOT_IMPLEMENTED;
920 }
921
922 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
923 {
924         p->rng_fault_state = True;
925         return NT_STATUS_NOT_IMPLEMENTED;
926 }
927
928 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
929 {
930         p->rng_fault_state = True;
931         return NT_STATUS_NOT_IMPLEMENTED;
932 }
933
934 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
935 {
936         p->rng_fault_state = True;
937         return NT_STATUS_NOT_IMPLEMENTED;
938 }
939
940 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
941 {
942         p->rng_fault_state = True;
943         return NT_STATUS_NOT_IMPLEMENTED;
944 }
945
946 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
947 {
948         p->rng_fault_state = True;
949         return NT_STATUS_NOT_IMPLEMENTED;
950 }
951
952 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
953 {
954         p->rng_fault_state = True;
955         return NT_STATUS_NOT_IMPLEMENTED;
956 }
957
958 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
959 {
960         p->rng_fault_state = True;
961         return NT_STATUS_NOT_IMPLEMENTED;
962 }
963
964 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
965 {
966         p->rng_fault_state = True;
967         return NT_STATUS_NOT_IMPLEMENTED;
968 }
969
970 NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
971 {
972         p->rng_fault_state = True;
973         return NT_STATUS_NOT_IMPLEMENTED;
974 }
975
976 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
977 {
978         p->rng_fault_state = True;
979         return NT_STATUS_NOT_IMPLEMENTED;
980 }
981