Update WHATSNEW entry for pre3
[Samba.git] / source / rpc_server / srv_eventlog_nt.c
blob0e2bcf41269e4c3fcc4c11603c242f73aff54ca8
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.
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.
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/>.
22 #include "includes.h"
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_RPC_SRV
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;
37 /********************************************************************
38 ********************************************************************/
40 static void free_eventlog_info( void *ptr )
42 EVENTLOG_INFO *elog = (EVENTLOG_INFO *)ptr;
44 if ( elog->etdb )
45 elog_close_tdb( elog->etdb, False );
47 TALLOC_FREE( elog );
50 /********************************************************************
51 ********************************************************************/
53 static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
54 POLICY_HND * handle )
56 EVENTLOG_INFO *info;
58 if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
59 DEBUG( 2,
60 ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
61 return NULL;
64 return info;
67 /********************************************************************
68 ********************************************************************/
70 static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
72 char *tdbname = elog_tdbname(talloc_tos(), info->logname );
73 SEC_DESC *sec_desc;
74 bool ret;
75 NTSTATUS ntstatus;
77 if ( !tdbname )
78 return False;
80 /* get the security descriptor for the file */
82 sec_desc = get_nt_acl_no_snum( info, tdbname );
83 SAFE_FREE( tdbname );
85 if ( !sec_desc ) {
86 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
87 tdbname));
88 return False;
91 /* root free pass */
93 if ( geteuid() == sec_initial_uid() ) {
94 DEBUG(5,("elog_check_access: using root's token\n"));
95 token = get_root_nt_token();
98 /* run the check, try for the max allowed */
100 ret = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
101 &info->access_granted, &ntstatus );
103 if ( sec_desc )
104 TALLOC_FREE( sec_desc );
106 if ( !ret ) {
107 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
108 nt_errstr( ntstatus)));
109 return False;
112 /* we have to have READ permission for a successful open */
114 return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
117 /********************************************************************
118 ********************************************************************/
120 static bool elog_validate_logname( const char *name )
122 int i;
123 const char **elogs = lp_eventlog_list();
125 if (!elogs) {
126 return False;
129 for ( i=0; elogs[i]; i++ ) {
130 if ( strequal( name, elogs[i] ) )
131 return True;
134 return False;
137 /********************************************************************
138 ********************************************************************/
140 static bool get_num_records_hook( EVENTLOG_INFO * info )
142 int next_record;
143 int oldest_record;
145 if ( !info->etdb ) {
146 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
147 return False;
150 /* lock the tdb since we have to get 2 records */
152 tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
153 next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
154 oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
155 tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
157 DEBUG( 8,
158 ( "Oldest Record %d; Next Record %d\n", oldest_record,
159 next_record ) );
161 info->num_records = ( next_record - oldest_record );
162 info->oldest_entry = oldest_record;
164 return True;
167 /********************************************************************
168 ********************************************************************/
170 static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
172 /* it's the same thing */
173 return get_num_records_hook( info );
176 /********************************************************************
177 ********************************************************************/
179 static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
181 EVENTLOG_INFO *elog;
183 /* first thing is to validate the eventlog name */
185 if ( !elog_validate_logname( logname ) )
186 return NT_STATUS_OBJECT_PATH_INVALID;
188 if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
189 return NT_STATUS_NO_MEMORY;
191 elog->logname = talloc_strdup( elog, logname );
193 /* Open the tdb first (so that we can create any new tdbs if necessary).
194 We have to do this as root and then use an internal access check
195 on the file permissions since you can only have a tdb open once
196 in a single process */
198 become_root();
199 elog->etdb = elog_open_tdb( elog->logname, False );
200 unbecome_root();
202 if ( !elog->etdb ) {
203 /* according to MSDN, if the logfile cannot be found, we should
204 default to the "Application" log */
206 if ( !strequal( logname, ELOG_APPL ) ) {
208 TALLOC_FREE( elog->logname );
210 elog->logname = talloc_strdup( elog, ELOG_APPL );
212 /* do the access check */
213 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
214 TALLOC_FREE( elog );
215 return NT_STATUS_ACCESS_DENIED;
218 become_root();
219 elog->etdb = elog_open_tdb( elog->logname, False );
220 unbecome_root();
223 if ( !elog->etdb ) {
224 TALLOC_FREE( elog );
225 return NT_STATUS_ACCESS_DENIED; /* ??? */
229 /* now do the access check. Close the tdb if we fail here */
231 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
232 elog_close_tdb( elog->etdb, False );
233 TALLOC_FREE( elog );
234 return NT_STATUS_ACCESS_DENIED;
237 /* create the policy handle */
239 if ( !create_policy_hnd
240 ( p, hnd, free_eventlog_info, ( void * ) elog ) ) {
241 free_eventlog_info( elog );
242 return NT_STATUS_NO_MEMORY;
245 /* set the initial current_record pointer */
247 if ( !get_oldest_entry_hook( elog ) ) {
248 DEBUG(3,("elog_open: Successfully opened eventlog but can't "
249 "get any information on internal records!\n"));
252 elog->current_record = elog->oldest_entry;
254 return NT_STATUS_OK;
257 /********************************************************************
258 ********************************************************************/
260 static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
262 if ( !( close_policy_hnd( p, hnd ) ) ) {
263 return NT_STATUS_INVALID_HANDLE;
266 return NT_STATUS_OK;
269 /*******************************************************************
270 *******************************************************************/
272 static int elog_size( EVENTLOG_INFO *info )
274 if ( !info || !info->etdb ) {
275 DEBUG(0,("elog_size: Invalid info* structure!\n"));
276 return 0;
279 return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
282 /********************************************************************
283 For the given tdb, get the next eventlog record into the passed
284 Eventlog_entry. returns NULL if it can't get the record for some reason.
285 ********************************************************************/
287 static Eventlog_entry *get_eventlog_record(prs_struct *ps,
288 TDB_CONTEXT *tdb,
289 int recno)
291 Eventlog_entry *ee = NULL;
292 TDB_DATA ret, key;
294 int srecno;
295 int reclen;
296 int len;
298 char *wpsource = NULL;
299 char *wpcomputer = NULL;
300 char *wpsid = NULL;
301 char *wpstrs = NULL;
302 char *puserdata = NULL;
304 key.dsize = sizeof(int32);
306 srecno = recno;
307 key.dptr = ( uint8 * ) &srecno;
309 ret = tdb_fetch( tdb, key );
311 if ( ret.dsize == 0 ) {
312 DEBUG( 8,
313 ( "Can't find a record for the key, record %d\n",
314 recno ) );
315 return NULL;
318 len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
320 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
322 if ( !len )
323 return NULL;
325 ee = TALLOC_ARRAY(ps->mem_ctx, Eventlog_entry, 1);
326 if (!ee) {
327 return NULL;
329 ZERO_STRUCTP(ee);
331 len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
332 &ee->record.length, &ee->record.reserved1,
333 &ee->record.record_number,
334 &ee->record.time_generated,
335 &ee->record.time_written, &ee->record.event_id,
336 &ee->record.event_type, &ee->record.num_strings,
337 &ee->record.event_category, &ee->record.reserved2,
338 &ee->record.closing_record_number,
339 &ee->record.string_offset,
340 &ee->record.user_sid_length,
341 &ee->record.user_sid_offset,
342 &ee->record.data_length, &ee->record.data_offset,
343 &ee->data_record.source_name_len, &wpsource,
344 &ee->data_record.computer_name_len, &wpcomputer,
345 &ee->data_record.sid_padding,
346 &ee->record.user_sid_length, &wpsid,
347 &ee->data_record.strings_len, &wpstrs,
348 &ee->data_record.user_data_len, &puserdata,
349 &ee->data_record.data_padding );
350 DEBUG( 10,
351 ( "Read record %d, len in tdb was %d\n",
352 ee->record.record_number, len ) );
354 /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
355 into it's 2nd argment for 'B' */
357 if (wpcomputer) {
358 ee->data_record.computer_name = (smb_ucs2_t *)TALLOC_MEMDUP(
359 ee, wpcomputer, ee->data_record.computer_name_len);
360 if (!ee->data_record.computer_name) {
361 TALLOC_FREE(ee);
362 goto out;
365 if (wpsource) {
366 ee->data_record.source_name = (smb_ucs2_t *)TALLOC_MEMDUP(
367 ee, wpsource, ee->data_record.source_name_len);
368 if (!ee->data_record.source_name) {
369 TALLOC_FREE(ee);
370 goto out;
374 if (wpsid) {
375 ee->data_record.sid = (smb_ucs2_t *)TALLOC_MEMDUP(
376 ee, wpsid, ee->record.user_sid_length);
377 if (!ee->data_record.sid) {
378 TALLOC_FREE(ee);
379 goto out;
382 if (wpstrs) {
383 ee->data_record.strings = (smb_ucs2_t *)TALLOC_MEMDUP(
384 ee, wpstrs, ee->data_record.strings_len);
385 if (!ee->data_record.strings) {
386 TALLOC_FREE(ee);
387 goto out;
391 if (puserdata) {
392 ee->data_record.user_data = (char *)TALLOC_MEMDUP(
393 ee, puserdata, ee->data_record.user_data_len);
394 if (!ee->data_record.user_data) {
395 TALLOC_FREE(ee);
396 goto out;
400 out:
402 SAFE_FREE(wpcomputer);
403 SAFE_FREE(wpsource);
404 SAFE_FREE(wpsid);
405 SAFE_FREE(wpstrs);
406 SAFE_FREE(puserdata);
408 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
409 DEBUG( 10,
410 ( "get_eventlog_record: computer_name %d is ",
411 ee->data_record.computer_name_len ) );
412 SAFE_FREE(ret.dptr);
413 return ee;
416 /********************************************************************
417 note that this can only be called AFTER the table is constructed,
418 since it uses the table to find the tdb handle
419 ********************************************************************/
421 static bool sync_eventlog_params( EVENTLOG_INFO *info )
423 char *path = NULL;
424 uint32 uiMaxSize;
425 uint32 uiRetention;
426 struct registry_key *key;
427 struct registry_value *value;
428 WERROR wresult;
429 char *elogname = info->logname;
430 TALLOC_CTX *ctx = talloc_tos();
431 bool ret = false;
433 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
435 if ( !info->etdb ) {
436 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
437 return False;
439 /* set resonable defaults. 512Kb on size and 1 week on time */
441 uiMaxSize = 0x80000;
442 uiRetention = 604800;
444 /* the general idea is to internally open the registry
445 key and retrieve the values. That way we can continue
446 to use the same fetch/store api that we use in
447 srv_reg_nt.c */
449 path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
450 if (!path) {
451 return false;
454 wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
455 &key);
457 if ( !W_ERROR_IS_OK( wresult ) ) {
458 DEBUG( 4,
459 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
460 path, dos_errstr( wresult ) ) );
461 return false;
464 wresult = reg_queryvalue(key, key, "Retention", &value);
465 if (!W_ERROR_IS_OK(wresult)) {
466 DEBUG(4, ("Failed to query value \"Retention\": %s\n",
467 dos_errstr(wresult)));
468 ret = false;
469 goto done;
471 uiRetention = value->v.dword;
473 wresult = reg_queryvalue(key, key, "MaxSize", &value);
474 if (!W_ERROR_IS_OK(wresult)) {
475 DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
476 dos_errstr(wresult)));
477 ret = false;
478 goto done;
480 uiMaxSize = value->v.dword;
482 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
483 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
485 ret = true;
487 done:
488 TALLOC_FREE(ctx);
489 return ret;
492 /********************************************************************
493 ********************************************************************/
495 static Eventlog_entry *read_package_entry( prs_struct * ps,
496 Eventlog_entry * entry )
498 uint8 *offset;
499 Eventlog_entry *ee_new = NULL;
501 ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
502 if ( ee_new == NULL ) {
503 return NULL;
506 entry->data_record.sid_padding =
507 ( ( 4 -
508 ( ( entry->data_record.source_name_len +
509 entry->data_record.computer_name_len ) % 4 ) ) % 4 );
510 entry->data_record.data_padding =
511 ( 4 -
512 ( ( entry->data_record.strings_len +
513 entry->data_record.user_data_len ) % 4 ) ) % 4;
514 entry->record.length = sizeof( Eventlog_record );
515 entry->record.length += entry->data_record.source_name_len;
516 entry->record.length += entry->data_record.computer_name_len;
517 if ( entry->record.user_sid_length == 0 ) {
518 /* Should not pad to a DWORD boundary for writing out the sid if there is
519 no SID, so just propagate the padding to pad the data */
520 entry->data_record.data_padding +=
521 entry->data_record.sid_padding;
522 entry->data_record.sid_padding = 0;
524 DEBUG( 10,
525 ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
526 DEBUG( 10,
527 ( "data_padding is [%d].\n",
528 entry->data_record.data_padding ) );
530 entry->record.length += entry->data_record.sid_padding;
531 entry->record.length += entry->record.user_sid_length;
532 entry->record.length += entry->data_record.strings_len;
533 entry->record.length += entry->data_record.user_data_len;
534 entry->record.length += entry->data_record.data_padding;
535 /* need another copy of length at the end of the data */
536 entry->record.length += sizeof( entry->record.length );
537 DEBUG( 10,
538 ( "entry->record.length is [%d].\n", entry->record.length ) );
539 entry->data =
540 PRS_ALLOC_MEM( ps, uint8,
541 entry->record.length -
542 sizeof( Eventlog_record ) -
543 sizeof( entry->record.length ) );
544 if ( entry->data == NULL ) {
545 return NULL;
547 offset = entry->data;
548 memcpy( offset, &( entry->data_record.source_name ),
549 entry->data_record.source_name_len );
550 offset += entry->data_record.source_name_len;
551 memcpy( offset, &( entry->data_record.computer_name ),
552 entry->data_record.computer_name_len );
553 offset += entry->data_record.computer_name_len;
554 /* SID needs to be DWORD-aligned */
555 offset += entry->data_record.sid_padding;
556 entry->record.user_sid_offset =
557 sizeof( Eventlog_record ) + ( offset - entry->data );
558 memcpy( offset, &( entry->data_record.sid ),
559 entry->record.user_sid_length );
560 offset += entry->record.user_sid_length;
561 /* Now do the strings */
562 entry->record.string_offset =
563 sizeof( Eventlog_record ) + ( offset - entry->data );
564 memcpy( offset, &( entry->data_record.strings ),
565 entry->data_record.strings_len );
566 offset += entry->data_record.strings_len;
567 /* Now do the data */
568 entry->record.data_length = entry->data_record.user_data_len;
569 entry->record.data_offset =
570 sizeof( Eventlog_record ) + ( offset - entry->data );
571 memcpy( offset, &( entry->data_record.user_data ),
572 entry->data_record.user_data_len );
573 offset += entry->data_record.user_data_len;
575 memcpy( &( ee_new->record ), &entry->record,
576 sizeof( Eventlog_record ) );
577 memcpy( &( ee_new->data_record ), &entry->data_record,
578 sizeof( Eventlog_data_record ) );
579 ee_new->data = entry->data;
581 return ee_new;
584 /********************************************************************
585 ********************************************************************/
587 static bool add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
588 Eventlog_entry * ee_new )
590 Eventlog_entry *insert_point;
592 insert_point = r_u->entry;
594 if ( NULL == insert_point ) {
595 r_u->entry = ee_new;
596 ee_new->next = NULL;
597 } else {
598 while ( ( NULL != insert_point->next ) ) {
599 insert_point = insert_point->next;
601 ee_new->next = NULL;
602 insert_point->next = ee_new;
604 r_u->num_records++;
605 r_u->num_bytes_in_resp += ee_new->record.length;
607 return True;
610 /********************************************************************
611 _eventlog_OpenEventLogW
612 ********************************************************************/
614 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
615 struct eventlog_OpenEventLogW *r)
617 const char *servername = "";
618 const char *logname = "";
619 EVENTLOG_INFO *info;
620 NTSTATUS result;
622 if (r->in.servername->string) {
623 servername = r->in.servername->string;
626 if (r->in.logname->string) {
627 logname = r->in.logname->string;
630 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
631 servername, logname ));
633 /* according to MSDN, if the logfile cannot be found, we should
634 default to the "Application" log */
636 if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, r->out.handle )) )
637 return result;
639 if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
640 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
641 logname ));
642 elog_close( p, r->out.handle );
643 return NT_STATUS_INVALID_HANDLE;
646 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
648 sync_eventlog_params( info );
649 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
651 return NT_STATUS_OK;
654 /********************************************************************
655 _eventlog_ClearEventLogW
656 This call still needs some work
657 ********************************************************************/
658 /** The windows client seems to be doing something funny with the file name
659 A call like
660 ClearEventLog(handle, "backup_file")
661 on the client side will result in the backup file name looking like this on the
662 server side:
663 \??\${CWD of client}\backup_file
664 If an absolute path gets specified, such as
665 ClearEventLog(handle, "C:\\temp\\backup_file")
666 then it is still mangled by the client into this:
667 \??\C:\temp\backup_file
668 when it is on the wire.
669 I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
670 would be added in given that the backup file gets written on the server side. */
672 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
673 struct eventlog_ClearEventLogW *r)
675 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
676 const char *backup_file_name = NULL;
678 if ( !info )
679 return NT_STATUS_INVALID_HANDLE;
681 if (r->in.backupfile && r->in.backupfile->string) {
683 backup_file_name = r->in.backupfile->string;
685 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
686 "file name for log [%s].",
687 backup_file_name, info->logname ) );
690 /* check for WRITE access to the file */
692 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
693 return NT_STATUS_ACCESS_DENIED;
695 /* Force a close and reopen */
697 elog_close_tdb( info->etdb, True );
698 become_root();
699 info->etdb = elog_open_tdb( info->logname, True );
700 unbecome_root();
702 if ( !info->etdb )
703 return NT_STATUS_ACCESS_DENIED;
705 return NT_STATUS_OK;
708 /********************************************************************
709 ********************************************************************/
711 NTSTATUS _eventlog_CloseEventLog( pipes_struct * p, struct eventlog_CloseEventLog *r )
713 return elog_close( p, r->in.handle );
716 /********************************************************************
717 ********************************************************************/
719 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
720 EVENTLOG_Q_READ_EVENTLOG * q_u,
721 EVENTLOG_R_READ_EVENTLOG * r_u )
723 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
724 Eventlog_entry *entry = NULL, *ee_new = NULL;
725 uint32 num_records_read = 0;
726 prs_struct *ps;
727 int bytes_left, record_number;
728 uint32 elog_read_type, elog_read_dir;
730 if (info == NULL) {
731 return NT_STATUS_INVALID_HANDLE;
734 info->flags = q_u->flags;
735 ps = &p->out_data.rdata;
737 bytes_left = q_u->max_read_size;
739 if ( !info->etdb )
740 return NT_STATUS_ACCESS_DENIED;
742 /* check for valid flags. Can't use the sequential and seek flags together */
744 elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
745 elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
747 if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
748 || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
750 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
751 return NT_STATUS_INVALID_PARAMETER;
754 /* a sequential read should ignore the offset */
756 if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
757 record_number = info->current_record;
758 else
759 record_number = q_u->offset;
761 while ( bytes_left > 0 ) {
763 /* assume that when the record fetch fails, that we are done */
765 entry = get_eventlog_record (ps, ELOG_TDB_CTX(info->etdb), record_number);
766 if (!entry) {
767 break;
770 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
772 /* Now see if there is enough room to add */
774 if ( !(ee_new = read_package_entry( ps, entry )) )
775 return NT_STATUS_NO_MEMORY;
777 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
778 r_u->bytes_in_next_record = ee_new->record.length;
780 /* response would be too big to fit in client-size buffer */
782 bytes_left = 0;
783 break;
786 add_record_to_resp( r_u, ee_new );
787 bytes_left -= ee_new->record.length;
788 TALLOC_FREE(entry);
789 num_records_read = r_u->num_records - num_records_read;
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 ) );
797 if ( info->flags & EVENTLOG_FORWARDS_READ )
798 record_number++;
799 else
800 record_number--;
802 /* update the eventlog record pointer */
804 info->current_record = record_number;
807 /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
808 say when there are no more records */
810 return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
813 /********************************************************************
814 _eventlog_GetOldestRecord
815 ********************************************************************/
817 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
818 struct eventlog_GetOldestRecord *r)
820 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
822 if (info == NULL) {
823 return NT_STATUS_INVALID_HANDLE;
826 if ( !( get_oldest_entry_hook( info ) ) )
827 return NT_STATUS_ACCESS_DENIED;
829 *r->out.oldest_entry = info->oldest_entry;
831 return NT_STATUS_OK;
834 /********************************************************************
835 _eventlog_GetNumRecords
836 ********************************************************************/
838 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
839 struct eventlog_GetNumRecords *r)
841 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
843 if (info == NULL) {
844 return NT_STATUS_INVALID_HANDLE;
847 if ( !( get_num_records_hook( info ) ) )
848 return NT_STATUS_ACCESS_DENIED;
850 *r->out.number = info->num_records;
852 return NT_STATUS_OK;
855 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
857 p->rng_fault_state = True;
858 return NT_STATUS_NOT_IMPLEMENTED;
861 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
863 p->rng_fault_state = True;
864 return NT_STATUS_NOT_IMPLEMENTED;
867 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
869 p->rng_fault_state = True;
870 return NT_STATUS_NOT_IMPLEMENTED;
873 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
875 p->rng_fault_state = True;
876 return NT_STATUS_NOT_IMPLEMENTED;
879 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
881 p->rng_fault_state = True;
882 return NT_STATUS_NOT_IMPLEMENTED;
885 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
887 p->rng_fault_state = True;
888 return NT_STATUS_NOT_IMPLEMENTED;
891 NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
893 p->rng_fault_state = True;
894 return NT_STATUS_NOT_IMPLEMENTED;
897 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
899 p->rng_fault_state = True;
900 return NT_STATUS_NOT_IMPLEMENTED;
903 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
905 p->rng_fault_state = True;
906 return NT_STATUS_NOT_IMPLEMENTED;
909 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
911 p->rng_fault_state = True;
912 return NT_STATUS_NOT_IMPLEMENTED;
915 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
917 p->rng_fault_state = True;
918 return NT_STATUS_NOT_IMPLEMENTED;
921 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
923 p->rng_fault_state = True;
924 return NT_STATUS_NOT_IMPLEMENTED;
927 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
929 p->rng_fault_state = True;
930 return NT_STATUS_NOT_IMPLEMENTED;
933 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
935 p->rng_fault_state = True;
936 return NT_STATUS_NOT_IMPLEMENTED;
939 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
941 p->rng_fault_state = True;
942 return NT_STATUS_NOT_IMPLEMENTED;
945 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
947 p->rng_fault_state = True;
948 return NT_STATUS_NOT_IMPLEMENTED;
951 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
953 p->rng_fault_state = True;
954 return NT_STATUS_NOT_IMPLEMENTED;
957 NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
959 p->rng_fault_state = True;
960 return NT_STATUS_NOT_IMPLEMENTED;
963 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
965 p->rng_fault_state = True;
966 return NT_STATUS_NOT_IMPLEMENTED;