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