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