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