s3-eventlog: use main talloc context in eventlog read call.
[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 int eventlog_info_destructor(EVENTLOG_INFO *elog)
41 {
42         if (elog->etdb) {
43                 elog_close_tdb(elog->etdb, false);
44         }
45         return 0;
46 }
47
48 /********************************************************************
49  ********************************************************************/
50
51 static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
52                                                 POLICY_HND * handle )
53 {
54         EVENTLOG_INFO *info;
55
56         if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
57                 DEBUG( 2,
58                        ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
59                 return NULL;
60         }
61
62         return info;
63 }
64
65 /********************************************************************
66 ********************************************************************/
67
68 static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
69 {
70         char *tdbname = elog_tdbname(talloc_tos(), info->logname );
71         SEC_DESC *sec_desc;
72         NTSTATUS status;
73
74         if ( !tdbname )
75                 return False;
76
77         /* get the security descriptor for the file */
78
79         sec_desc = get_nt_acl_no_snum( info, tdbname );
80         TALLOC_FREE( tdbname );
81
82         if ( !sec_desc ) {
83                 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
84                         tdbname));
85                 return False;
86         }
87
88         /* root free pass */
89
90         if ( geteuid() == sec_initial_uid() ) {
91                 DEBUG(5,("elog_check_access: using root's token\n"));
92                 token = get_root_nt_token();
93         }
94
95         /* run the check, try for the max allowed */
96
97         status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
98                 &info->access_granted);
99
100         if ( sec_desc )
101                 TALLOC_FREE( sec_desc );
102
103         if (!NT_STATUS_IS_OK(status)) {
104                 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
105                         nt_errstr(status)));
106                 return False;
107         }
108
109         /* we have to have READ permission for a successful open */
110
111         return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
112 }
113
114 /********************************************************************
115  ********************************************************************/
116
117 static bool elog_validate_logname( const char *name )
118 {
119         int i;
120         const char **elogs = lp_eventlog_list();
121
122         if (!elogs) {
123                 return False;
124         }
125
126         for ( i=0; elogs[i]; i++ ) {
127                 if ( strequal( name, elogs[i] ) )
128                         return True;
129         }
130
131         return False;
132 }
133
134 /********************************************************************
135 ********************************************************************/
136
137 static bool get_num_records_hook( EVENTLOG_INFO * info )
138 {
139         int next_record;
140         int oldest_record;
141
142         if ( !info->etdb ) {
143                 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
144                 return False;
145         }
146
147         /* lock the tdb since we have to get 2 records */
148
149         tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
150         next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
151         oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
152         tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
153
154         DEBUG( 8,
155                ( "Oldest Record %d; Next Record %d\n", oldest_record,
156                  next_record ) );
157
158         info->num_records = ( next_record - oldest_record );
159         info->oldest_entry = oldest_record;
160
161         return True;
162 }
163
164 /********************************************************************
165  ********************************************************************/
166
167 static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
168 {
169         /* it's the same thing */
170         return get_num_records_hook( info );
171 }
172
173 /********************************************************************
174  ********************************************************************/
175
176 static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
177 {
178         EVENTLOG_INFO *elog;
179
180         /* first thing is to validate the eventlog name */
181         
182         if ( !elog_validate_logname( logname ) )
183                 return NT_STATUS_OBJECT_PATH_INVALID;
184
185         if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
186                 return NT_STATUS_NO_MEMORY;
187         talloc_set_destructor(elog, eventlog_info_destructor);
188
189         elog->logname = talloc_strdup( elog, logname );
190
191         /* Open the tdb first (so that we can create any new tdbs if necessary).
192            We have to do this as root and then use an internal access check
193            on the file permissions since you can only have a tdb open once
194            in a single process */
195
196         become_root();
197         elog->etdb = elog_open_tdb( elog->logname, False );
198         unbecome_root();
199
200         if ( !elog->etdb ) {
201                 /* according to MSDN, if the logfile cannot be found, we should
202                   default to the "Application" log */
203
204                 if ( !strequal( logname, ELOG_APPL ) ) {
205
206                         TALLOC_FREE( elog->logname );
207
208                         elog->logname = talloc_strdup( elog, ELOG_APPL );
209
210                         /* do the access check */
211                         if ( !elog_check_access( elog, p->server_info->ptok ) ) {
212                                 TALLOC_FREE( elog );
213                                 return NT_STATUS_ACCESS_DENIED;
214                         }
215
216                         become_root();
217                         elog->etdb = elog_open_tdb( elog->logname, False );
218                         unbecome_root();
219                 }
220
221                 if ( !elog->etdb ) {
222                         TALLOC_FREE( elog );
223                         return NT_STATUS_ACCESS_DENIED; /* ??? */
224                 }
225         }
226
227         /* now do the access check.  Close the tdb if we fail here */
228
229         if ( !elog_check_access( elog, p->server_info->ptok ) ) {
230                 TALLOC_FREE( elog );
231                 return NT_STATUS_ACCESS_DENIED;
232         }
233
234         /* create the policy handle */
235
236         if ( !create_policy_hnd( p, hnd, elog ) ) {
237                 TALLOC_FREE(elog);
238                 return NT_STATUS_NO_MEMORY;
239         }
240
241         /* set the initial current_record pointer */
242
243         if ( !get_oldest_entry_hook( elog ) ) {
244                 DEBUG(3,("elog_open: Successfully opened eventlog but can't "
245                         "get any information on internal records!\n"));
246         }
247
248         elog->current_record = elog->oldest_entry;
249
250         return NT_STATUS_OK;
251 }
252
253 /********************************************************************
254  ********************************************************************/
255
256 static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
257 {
258         if ( !( close_policy_hnd( p, hnd ) ) ) {
259                 return NT_STATUS_INVALID_HANDLE;
260         }
261
262         return NT_STATUS_OK;
263 }
264
265 /*******************************************************************
266  *******************************************************************/
267
268 static int elog_size( EVENTLOG_INFO *info )
269 {
270         if ( !info || !info->etdb ) {
271                 DEBUG(0,("elog_size: Invalid info* structure!\n"));
272                 return 0;
273         }
274
275         return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
276 }
277
278 /********************************************************************
279   For the given tdb, get the next eventlog record into the passed
280   Eventlog_entry.  returns NULL if it can't get the record for some reason.
281  ********************************************************************/
282
283 static Eventlog_entry *get_eventlog_record(TALLOC_CTX *mem_ctx,
284                                 TDB_CONTEXT *tdb,
285                                 int recno)
286 {
287         Eventlog_entry *ee = NULL;
288         TDB_DATA ret, key;
289
290         int32_t srecno;
291         int32_t reclen;
292         int len;
293
294         char *wpsource = NULL;
295         char *wpcomputer = NULL;
296         char *wpsid = NULL;
297         char *wpstrs = NULL;
298         char *puserdata = NULL;
299
300         key.dsize = sizeof(int32_t);
301
302         srecno = recno;
303         key.dptr = (unsigned char *)&srecno;
304
305         ret = tdb_fetch( tdb, key );
306
307         if ( ret.dsize == 0 ) {
308                 DEBUG( 8,
309                        ( "Can't find a record for the key, record %d\n",
310                          recno ) );
311                 return NULL;
312         }
313
314         len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
315
316         DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
317
318         if ( !len )
319                 return NULL;
320
321         ee = TALLOC_ARRAY(mem_ctx, Eventlog_entry, 1);
322         if (!ee) {
323                 return NULL;
324         }
325         ZERO_STRUCTP(ee);
326
327         len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
328                           &ee->record.length, &ee->record.reserved1,
329                           &ee->record.record_number,
330                           &ee->record.time_generated,
331                           &ee->record.time_written, &ee->record.event_id,
332                           &ee->record.event_type, &ee->record.num_strings,
333                           &ee->record.event_category, &ee->record.reserved2,
334                           &ee->record.closing_record_number,
335                           &ee->record.string_offset,
336                           &ee->record.user_sid_length,
337                           &ee->record.user_sid_offset,
338                           &ee->record.data_length, &ee->record.data_offset,
339                           &ee->data_record.source_name_len, &wpsource,
340                           &ee->data_record.computer_name_len, &wpcomputer,
341                           &ee->data_record.sid_padding,
342                           &ee->record.user_sid_length, &wpsid,
343                           &ee->data_record.strings_len, &wpstrs,
344                           &ee->data_record.user_data_len, &puserdata,
345                           &ee->data_record.data_padding );
346         DEBUG( 10,
347                ( "Read record %d, len in tdb was %d\n",
348                  ee->record.record_number, len ) );
349
350         /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
351            into it's 2nd argment for 'B' */
352
353         if (wpcomputer) {
354                 ee->data_record.computer_name = (smb_ucs2_t *)TALLOC_MEMDUP(
355                         ee, wpcomputer, ee->data_record.computer_name_len);
356                 if (!ee->data_record.computer_name) {
357                         TALLOC_FREE(ee);
358                         goto out;
359                 }
360         }
361         if (wpsource) {
362                 ee->data_record.source_name = (smb_ucs2_t *)TALLOC_MEMDUP(
363                         ee, wpsource, ee->data_record.source_name_len);
364                 if (!ee->data_record.source_name) {
365                         TALLOC_FREE(ee);
366                         goto out;
367                 }
368         }
369
370         if (wpsid) {
371                 ee->data_record.sid = (smb_ucs2_t *)TALLOC_MEMDUP(
372                         ee, wpsid, ee->record.user_sid_length);
373                 if (!ee->data_record.sid) {
374                         TALLOC_FREE(ee);
375                         goto out;
376                 }
377         }
378         if (wpstrs) {
379                 ee->data_record.strings = (smb_ucs2_t *)TALLOC_MEMDUP(
380                         ee, wpstrs, ee->data_record.strings_len);
381                 if (!ee->data_record.strings) {
382                         TALLOC_FREE(ee);
383                         goto out;
384                 }
385         }
386
387         if (puserdata) {
388                 ee->data_record.user_data = (char *)TALLOC_MEMDUP(
389                         ee, puserdata, ee->data_record.user_data_len);
390                 if (!ee->data_record.user_data) {
391                         TALLOC_FREE(ee);
392                         goto out;
393                 }
394         }
395
396   out:
397
398         SAFE_FREE(wpcomputer);
399         SAFE_FREE(wpsource);
400         SAFE_FREE(wpsid);
401         SAFE_FREE(wpstrs);
402         SAFE_FREE(puserdata);
403
404         DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
405         DEBUG( 10,
406                ( "get_eventlog_record: computer_name %d is ",
407                  ee->data_record.computer_name_len ) );
408         SAFE_FREE(ret.dptr);
409         return ee;
410 }
411
412 /********************************************************************
413  note that this can only be called AFTER the table is constructed,
414  since it uses the table to find the tdb handle
415  ********************************************************************/
416
417 static bool sync_eventlog_params( EVENTLOG_INFO *info )
418 {
419         char *path = NULL;
420         uint32 uiMaxSize;
421         uint32 uiRetention;
422         struct registry_key *key;
423         struct registry_value *value;
424         WERROR wresult;
425         char *elogname = info->logname;
426         TALLOC_CTX *ctx = talloc_stackframe();
427         bool ret = false;
428
429         DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
430
431         if ( !info->etdb ) {
432                 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
433                 goto done;
434         }
435         /* set resonable defaults.  512Kb on size and 1 week on time */
436
437         uiMaxSize = 0x80000;
438         uiRetention = 604800;
439
440         /* the general idea is to internally open the registry
441            key and retrieve the values.  That way we can continue
442            to use the same fetch/store api that we use in
443            srv_reg_nt.c */
444
445         path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
446         if (!path) {
447                 goto done;
448         }
449
450         wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
451                                 &key);
452
453         if ( !W_ERROR_IS_OK( wresult ) ) {
454                 DEBUG( 4,
455                        ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
456                          path, win_errstr( wresult ) ) );
457                 goto done;
458         }
459
460         wresult = reg_queryvalue(key, key, "Retention", &value);
461         if (!W_ERROR_IS_OK(wresult)) {
462                 DEBUG(4, ("Failed to query value \"Retention\": %s\n",
463                           win_errstr(wresult)));
464                 goto done;
465         }
466         uiRetention = value->v.dword;
467
468         wresult = reg_queryvalue(key, key, "MaxSize", &value);
469         if (!W_ERROR_IS_OK(wresult)) {
470                 DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
471                           win_errstr(wresult)));
472                 goto done;
473         }
474         uiMaxSize = value->v.dword;
475
476         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
477         tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
478
479         ret = true;
480
481 done:
482         TALLOC_FREE(ctx);
483         return ret;
484 }
485
486 /********************************************************************
487  ********************************************************************/
488
489 static Eventlog_entry *read_package_entry( TALLOC_CTX *mem_ctx,
490                                            Eventlog_entry * entry )
491 {
492         uint8 *offset;
493         Eventlog_entry *ee_new = NULL;
494
495         ee_new = TALLOC_ZERO_ARRAY(mem_ctx, Eventlog_entry, 1 );
496         if ( ee_new == NULL ) {
497                 return NULL;
498         }
499
500         entry->data_record.sid_padding =
501                 ( ( 4 -
502                     ( ( entry->data_record.source_name_len +
503                         entry->data_record.computer_name_len ) % 4 ) ) % 4 );
504         entry->data_record.data_padding =
505                 ( 4 -
506                   ( ( entry->data_record.strings_len +
507                       entry->data_record.user_data_len ) % 4 ) ) % 4;
508         entry->record.length = sizeof( Eventlog_record );
509         entry->record.length += entry->data_record.source_name_len;
510         entry->record.length += entry->data_record.computer_name_len;
511         if ( entry->record.user_sid_length == 0 ) {
512                 /* Should not pad to a DWORD boundary for writing out the sid if there is
513                    no SID, so just propagate the padding to pad the data */
514                 entry->data_record.data_padding +=
515                         entry->data_record.sid_padding;
516                 entry->data_record.sid_padding = 0;
517         }
518         DEBUG( 10,
519                ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
520         DEBUG( 10,
521                ( "data_padding is [%d].\n",
522                  entry->data_record.data_padding ) );
523
524         entry->record.length += entry->data_record.sid_padding;
525         entry->record.length += entry->record.user_sid_length;
526         entry->record.length += entry->data_record.strings_len;
527         entry->record.length += entry->data_record.user_data_len;
528         entry->record.length += entry->data_record.data_padding;
529         /* need another copy of length at the end of the data */
530         entry->record.length += sizeof( entry->record.length );
531         DEBUG( 10,
532                ( "entry->record.length is [%d].\n", entry->record.length ) );
533         entry->data =
534                 TALLOC_ZERO_ARRAY(mem_ctx, uint8_t,
535                                   entry->record.length -
536                                   sizeof( Eventlog_record ) -
537                                   sizeof( entry->record.length ));
538         if ( entry->data == NULL ) {
539                 return NULL;
540         }
541         offset = entry->data;
542         memcpy( offset, &( entry->data_record.source_name ),
543                 entry->data_record.source_name_len );
544         offset += entry->data_record.source_name_len;
545         memcpy( offset, &( entry->data_record.computer_name ),
546                 entry->data_record.computer_name_len );
547         offset += entry->data_record.computer_name_len;
548         /* SID needs to be DWORD-aligned */
549         offset += entry->data_record.sid_padding;
550         entry->record.user_sid_offset =
551                 sizeof( Eventlog_record ) + ( offset - entry->data );
552         memcpy( offset, &( entry->data_record.sid ),
553                 entry->record.user_sid_length );
554         offset += entry->record.user_sid_length;
555         /* Now do the strings */
556         entry->record.string_offset =
557                 sizeof( Eventlog_record ) + ( offset - entry->data );
558         memcpy( offset, &( entry->data_record.strings ),
559                 entry->data_record.strings_len );
560         offset += entry->data_record.strings_len;
561         /* Now do the data */
562         entry->record.data_length = entry->data_record.user_data_len;
563         entry->record.data_offset =
564                 sizeof( Eventlog_record ) + ( offset - entry->data );
565         memcpy( offset, &( entry->data_record.user_data ),
566                 entry->data_record.user_data_len );
567         offset += entry->data_record.user_data_len;
568
569         memcpy( &( ee_new->record ), &entry->record,
570                 sizeof( Eventlog_record ) );
571         memcpy( &( ee_new->data_record ), &entry->data_record,
572                 sizeof( Eventlog_data_record ) );
573         ee_new->data = entry->data;
574
575         return ee_new;
576 }
577
578 /********************************************************************
579  ********************************************************************/
580
581 static bool add_record_to_resp( Eventlog_entry *entry,
582                                 uint32_t *num_records,
583                                 uint32_t *num_bytes_in_resp,
584                                 Eventlog_entry * ee_new )
585 {
586         Eventlog_entry *insert_point;
587
588         insert_point = entry;
589
590         if ( NULL == insert_point ) {
591                 entry = ee_new;
592                 ee_new->next = NULL;
593         } else {
594                 while ( ( NULL != insert_point->next ) ) {
595                         insert_point = insert_point->next;
596                 }
597                 ee_new->next = NULL;
598                 insert_point->next = ee_new;
599         }
600         (*num_records)++;
601         *num_bytes_in_resp += ee_new->record.length;
602
603         return True;
604 }
605
606 /********************************************************************
607  _eventlog_OpenEventLogW
608  ********************************************************************/
609
610 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
611                                  struct eventlog_OpenEventLogW *r)
612 {
613         const char *servername = "";
614         const char *logname = "";
615         EVENTLOG_INFO *info;
616         NTSTATUS result;
617
618         if (r->in.servername->string) {
619                 servername = r->in.servername->string;
620         }
621
622         if (r->in.logname->string) {
623                 logname = r->in.logname->string;
624         }
625
626         DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
627                 servername, logname ));
628
629         /* according to MSDN, if the logfile cannot be found, we should
630           default to the "Application" log */
631
632         if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, r->out.handle )) )
633                 return result;
634
635         if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
636                 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
637                         logname ));
638                 elog_close( p, r->out.handle );
639                 return NT_STATUS_INVALID_HANDLE;
640         }
641
642         DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
643
644         sync_eventlog_params( info );
645         prune_eventlog( ELOG_TDB_CTX(info->etdb) );
646
647         return NT_STATUS_OK;
648 }
649
650 /********************************************************************
651  _eventlog_ClearEventLogW
652  This call still needs some work
653  ********************************************************************/
654 /** The windows client seems to be doing something funny with the file name
655    A call like
656       ClearEventLog(handle, "backup_file")
657    on the client side will result in the backup file name looking like this on the
658    server side:
659       \??\${CWD of client}\backup_file
660    If an absolute path gets specified, such as
661       ClearEventLog(handle, "C:\\temp\\backup_file")
662    then it is still mangled by the client into this:
663       \??\C:\temp\backup_file
664    when it is on the wire.
665    I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
666    would be added in given that the backup file gets written on the server side. */
667
668 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
669                                   struct eventlog_ClearEventLogW *r)
670 {
671         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
672         const char *backup_file_name = NULL;
673
674         if ( !info )
675                 return NT_STATUS_INVALID_HANDLE;
676
677         if (r->in.backupfile && r->in.backupfile->string) {
678
679                 backup_file_name = r->in.backupfile->string;
680
681                 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
682                         "file name for log [%s].",
683                          backup_file_name, info->logname ) );
684         }
685
686         /* check for WRITE access to the file */
687
688         if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
689                 return NT_STATUS_ACCESS_DENIED;
690
691         /* Force a close and reopen */
692
693         elog_close_tdb( info->etdb, True );
694         become_root();
695         info->etdb = elog_open_tdb( info->logname, True );
696         unbecome_root();
697
698         if ( !info->etdb )
699                 return NT_STATUS_ACCESS_DENIED;
700
701         return NT_STATUS_OK;
702 }
703
704 /********************************************************************
705  _eventlog_CloseEventLog
706  ********************************************************************/
707
708 NTSTATUS _eventlog_CloseEventLog(pipes_struct * p,
709                                  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         int bytes_left, record_number;
725         uint32 elog_read_type, elog_read_dir;
726
727         if (info == NULL) {
728                 return NT_STATUS_INVALID_HANDLE;
729         }
730
731         info->flags = q_u->flags;
732         ps = &p->out_data.rdata;
733
734         bytes_left = q_u->max_read_size;
735
736         if ( !info->etdb )
737                 return NT_STATUS_ACCESS_DENIED;
738
739         /* check for valid flags.  Can't use the sequential and seek flags together */
740
741         elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
742         elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
743
744         if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) 
745                 ||  elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
746         {
747                 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
748                 return NT_STATUS_INVALID_PARAMETER;
749         }
750
751         /* a sequential read should ignore the offset */
752
753         if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
754                 record_number = info->current_record;
755         else
756                 record_number = q_u->offset;
757
758         while ( bytes_left > 0 ) {
759
760                 /* assume that when the record fetch fails, that we are done */
761
762                 entry = get_eventlog_record (p->mem_ctx, ELOG_TDB_CTX(info->etdb), record_number);
763                 if (!entry) {
764                         break;
765                 }
766
767                 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
768
769                 /* Now see if there is enough room to add */
770
771                 if ( !(ee_new = read_package_entry( p->mem_ctx, entry )) )
772                         return NT_STATUS_NO_MEMORY;
773
774                 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
775                         r_u->bytes_in_next_record = ee_new->record.length;
776
777                         /* response would be too big to fit in client-size buffer */
778
779                         bytes_left = 0;
780                         break;
781                 }
782
783                 add_record_to_resp( r_u->entry,
784                                     &r_u->num_records, &r_u->num_bytes_in_resp,
785                                     ee_new );
786
787                 bytes_left -= ee_new->record.length;
788                 TALLOC_FREE(entry);
789                 num_records_read = r_u->num_records - num_records_read;
790
791                 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
792                         "of [%d] records using [%d] bytes out of a max of [%d].\n",
793                          num_records_read, r_u->num_records,
794                          r_u->num_bytes_in_resp,
795                          q_u->max_read_size ) );
796
797                 if ( info->flags & EVENTLOG_FORWARDS_READ )
798                         record_number++;
799                 else
800                         record_number--;
801
802                 /* update the eventlog record pointer */
803
804                 info->current_record = record_number;
805         }
806
807         /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
808            say when there are no more records */
809
810         return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
811 }
812
813 /********************************************************************
814  _eventlog_GetOldestRecord
815  ********************************************************************/
816
817 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
818                                    struct eventlog_GetOldestRecord *r)
819 {
820         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
821
822         if (info == NULL) {
823                 return NT_STATUS_INVALID_HANDLE;
824         }
825
826         if ( !( get_oldest_entry_hook( info ) ) )
827                 return NT_STATUS_ACCESS_DENIED;
828
829         *r->out.oldest_entry = info->oldest_entry;
830
831         return NT_STATUS_OK;
832 }
833
834 /********************************************************************
835 _eventlog_GetNumRecords
836  ********************************************************************/
837
838 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
839                                  struct eventlog_GetNumRecords *r)
840 {
841         EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
842
843         if (info == NULL) {
844                 return NT_STATUS_INVALID_HANDLE;
845         }
846
847         if ( !( get_num_records_hook( info ) ) )
848                 return NT_STATUS_ACCESS_DENIED;
849
850         *r->out.number = info->num_records;
851
852         return NT_STATUS_OK;
853 }
854
855 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
856 {
857         p->rng_fault_state = True;
858         return NT_STATUS_NOT_IMPLEMENTED;
859 }
860
861 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
862 {
863         p->rng_fault_state = True;
864         return NT_STATUS_NOT_IMPLEMENTED;
865 }
866
867 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
868 {
869         p->rng_fault_state = True;
870         return NT_STATUS_NOT_IMPLEMENTED;
871 }
872
873 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
874 {
875         p->rng_fault_state = True;
876         return NT_STATUS_NOT_IMPLEMENTED;
877 }
878
879 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
880 {
881         p->rng_fault_state = True;
882         return NT_STATUS_NOT_IMPLEMENTED;
883 }
884
885 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
886 {
887         p->rng_fault_state = True;
888         return NT_STATUS_NOT_IMPLEMENTED;
889 }
890
891 NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
892 {
893         p->rng_fault_state = True;
894         return NT_STATUS_NOT_IMPLEMENTED;
895 }
896
897 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
898 {
899         p->rng_fault_state = True;
900         return NT_STATUS_NOT_IMPLEMENTED;
901 }
902
903 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
904 {
905         p->rng_fault_state = True;
906         return NT_STATUS_NOT_IMPLEMENTED;
907 }
908
909 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
910 {
911         p->rng_fault_state = True;
912         return NT_STATUS_NOT_IMPLEMENTED;
913 }
914
915 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
916 {
917         p->rng_fault_state = True;
918         return NT_STATUS_NOT_IMPLEMENTED;
919 }
920
921 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
922 {
923         p->rng_fault_state = True;
924         return NT_STATUS_NOT_IMPLEMENTED;
925 }
926
927 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
928 {
929         p->rng_fault_state = True;
930         return NT_STATUS_NOT_IMPLEMENTED;
931 }
932
933 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
934 {
935         p->rng_fault_state = True;
936         return NT_STATUS_NOT_IMPLEMENTED;
937 }
938
939 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
940 {
941         p->rng_fault_state = True;
942         return NT_STATUS_NOT_IMPLEMENTED;
943 }
944
945 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
946 {
947         p->rng_fault_state = True;
948         return NT_STATUS_NOT_IMPLEMENTED;
949 }
950
951 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
952 {
953         p->rng_fault_state = True;
954         return NT_STATUS_NOT_IMPLEMENTED;
955 }
956
957 NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
958 {
959         p->rng_fault_state = True;
960         return NT_STATUS_NOT_IMPLEMENTED;
961 }
962
963 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
964 {
965         p->rng_fault_state = True;
966         return NT_STATUS_NOT_IMPLEMENTED;
967 }
968