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