r13704: Janitor for tpot.
[Samba.git] / source / rpc_server / srv_eventlog_nt.c
bloba8b9c66717e75929a9288a632ea1d42c275200be
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 2 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, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_RPC_SRV
28 typedef struct {
29 char *logname;
30 ELOG_TDB *etdb;
31 uint32 current_record;
32 uint32 num_records;
33 uint32 oldest_entry;
34 uint32 flags;
35 uint32 access_granted;
36 } EVENTLOG_INFO;
38 /********************************************************************
39 ********************************************************************/
41 static void free_eventlog_info( void *ptr )
43 EVENTLOG_INFO *elog = (EVENTLOG_INFO *)ptr;
45 if ( elog->etdb )
46 elog_close_tdb( elog->etdb, False );
48 TALLOC_FREE( elog );
51 /********************************************************************
52 ********************************************************************/
54 static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
55 POLICY_HND * handle )
57 EVENTLOG_INFO *info;
59 if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
60 DEBUG( 2,
61 ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
62 return NULL;
65 return info;
68 /********************************************************************
69 ********************************************************************/
71 static BOOL elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
73 char *tdbname = elog_tdbname( info->logname );
74 SEC_DESC *sec_desc;
75 BOOL ret;
76 NTSTATUS ntstatus;
78 if ( !tdbname )
79 return False;
81 /* get the security descriptor for the file */
83 sec_desc = get_nt_acl_no_snum( info, tdbname );
84 SAFE_FREE( tdbname );
86 if ( !sec_desc ) {
87 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
88 tdbname));
89 return False;
92 /* root free pass */
94 if ( geteuid() == sec_initial_uid() ) {
95 DEBUG(5,("elog_check_access: using root's token\n"));
96 token = get_root_nt_token();
99 /* run the check, try for the max allowed */
101 ret = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
102 &info->access_granted, &ntstatus );
104 if ( sec_desc )
105 TALLOC_FREE( sec_desc );
107 if ( !ret ) {
108 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
109 nt_errstr( ntstatus)));
110 return False;
113 /* we have to have READ permission for a successful open */
115 return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
118 /********************************************************************
119 ********************************************************************/
121 static BOOL elog_validate_logname( const char *name )
123 int i;
124 const char **elogs = lp_eventlog_list();
126 for ( i=0; elogs[i]; i++ ) {
127 if ( strequal( name, elogs[i] ) )
128 return True;
131 return False;
134 /********************************************************************
135 ********************************************************************/
137 static BOOL get_num_records_hook( EVENTLOG_INFO * info )
139 int next_record;
140 int oldest_record;
142 if ( !info->etdb ) {
143 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
144 return False;
147 /* lock the tdb since we have to get 2 records */
149 tdb_lock_bystring( 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);
154 DEBUG( 8,
155 ( "Oldest Record %d; Next Record %d\n", oldest_record,
156 next_record ) );
158 info->num_records = ( next_record - oldest_record );
159 info->oldest_entry = oldest_record;
161 return True;
164 /********************************************************************
165 ********************************************************************/
167 static BOOL get_oldest_entry_hook( EVENTLOG_INFO * info )
169 /* it's the same thing */
170 return get_num_records_hook( info );
173 /********************************************************************
174 ********************************************************************/
176 static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
178 EVENTLOG_INFO *elog;
180 /* first thing is to validate the eventlog name */
182 if ( !elog_validate_logname( logname ) )
183 return NT_STATUS_OBJECT_PATH_INVALID;
185 if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
186 return NT_STATUS_NO_MEMORY;
188 elog->logname = talloc_strdup( elog, logname );
190 /* Open the tdb first (so that we can create any new tdbs if necessary).
191 We have to do this as root and then use an internal access check
192 on the file permissions since you can only have a tdb open once
193 in a single process */
195 become_root();
196 elog->etdb = elog_open_tdb( elog->logname, False );
197 unbecome_root();
199 if ( !elog->etdb ) {
200 /* according to MSDN, if the logfile cannot be found, we should
201 default to the "Application" log */
203 if ( !strequal( logname, ELOG_APPL ) ) {
205 TALLOC_FREE( elog->logname );
207 elog->logname = talloc_strdup( elog, ELOG_APPL );
209 /* do the access check */
210 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
211 TALLOC_FREE( elog );
212 return NT_STATUS_ACCESS_DENIED;
215 become_root();
216 elog->etdb = elog_open_tdb( elog->logname, False );
217 unbecome_root();
220 if ( !elog->etdb ) {
221 TALLOC_FREE( elog );
222 return NT_STATUS_ACCESS_DENIED; /* ??? */
226 /* now do the access check. Close the tdb if we fail here */
228 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
229 elog_close_tdb( elog->etdb, False );
230 TALLOC_FREE( elog );
231 return NT_STATUS_ACCESS_DENIED;
234 /* create the policy handle */
236 if ( !create_policy_hnd
237 ( p, hnd, free_eventlog_info, ( void * ) elog ) ) {
238 free_eventlog_info( elog );
239 return NT_STATUS_NO_MEMORY;
242 /* set the initial current_record pointer */
244 if ( !get_oldest_entry_hook( elog ) ) {
245 DEBUG(3,("elog_open: Successfully opened eventlog but can't "
246 "get any information on internal records!\n"));
249 elog->current_record = elog->oldest_entry;
251 return NT_STATUS_OK;
254 /********************************************************************
255 ********************************************************************/
257 static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
259 if ( !( close_policy_hnd( p, hnd ) ) ) {
260 return NT_STATUS_INVALID_HANDLE;
263 return NT_STATUS_OK;
266 /*******************************************************************
267 *******************************************************************/
269 static int elog_size( EVENTLOG_INFO *info )
271 if ( !info || !info->etdb ) {
272 DEBUG(0,("elog_size: Invalid info* structure!\n"));
273 return 0;
276 return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
279 /********************************************************************
280 For the given tdb, get the next eventlog record into the passed
281 Eventlog_entry. returns NULL if it can't get the record for some reason.
282 ********************************************************************/
284 Eventlog_entry *get_eventlog_record( prs_struct * ps, TDB_CONTEXT * tdb,
285 int recno, Eventlog_entry * ee )
287 TDB_DATA ret, key;
289 int srecno;
290 int reclen;
291 int len;
292 uint8 *rbuff;
294 pstring *wpsource, *wpcomputer, *wpsid, *wpstrs, *puserdata;
296 key.dsize = sizeof( int32 );
297 rbuff = NULL;
299 srecno = recno;
300 key.dptr = ( char * ) &srecno;
302 ret = tdb_fetch( tdb, key );
304 if ( ret.dsize == 0 ) {
305 DEBUG( 8,
306 ( "Can't find a record for the key, record %d\n",
307 recno ) );
308 return NULL;
311 len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
313 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
315 if ( !len )
316 return NULL;
318 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
320 if ( !ee )
321 return NULL;
323 len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
324 &ee->record.length, &ee->record.reserved1,
325 &ee->record.record_number,
326 &ee->record.time_generated,
327 &ee->record.time_written, &ee->record.event_id,
328 &ee->record.event_type, &ee->record.num_strings,
329 &ee->record.event_category, &ee->record.reserved2,
330 &ee->record.closing_record_number,
331 &ee->record.string_offset,
332 &ee->record.user_sid_length,
333 &ee->record.user_sid_offset,
334 &ee->record.data_length, &ee->record.data_offset,
335 &ee->data_record.source_name_len, &wpsource,
336 &ee->data_record.computer_name_len, &wpcomputer,
337 &ee->data_record.sid_padding,
338 &ee->record.user_sid_length, &wpsid,
339 &ee->data_record.strings_len, &wpstrs,
340 &ee->data_record.user_data_len, &puserdata,
341 &ee->data_record.data_padding );
342 DEBUG( 10,
343 ( "Read record %d, len in tdb was %d\n",
344 ee->record.record_number, len ) );
346 /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
347 into it's 2nd argment for 'B' */
349 if ( wpcomputer )
350 memcpy( ee->data_record.computer_name, wpcomputer,
351 ee->data_record.computer_name_len );
352 if ( wpsource )
353 memcpy( ee->data_record.source_name, wpsource,
354 ee->data_record.source_name_len );
356 if ( wpsid )
357 memcpy( ee->data_record.sid, wpsid,
358 ee->record.user_sid_length );
359 if ( wpstrs )
360 memcpy( ee->data_record.strings, wpstrs,
361 ee->data_record.strings_len );
363 /* note that userdata is a pstring */
364 if ( puserdata )
365 memcpy( ee->data_record.user_data, puserdata,
366 ee->data_record.user_data_len );
368 SAFE_FREE( wpcomputer );
369 SAFE_FREE( wpsource );
370 SAFE_FREE( wpsid );
371 SAFE_FREE( wpstrs );
372 SAFE_FREE( puserdata );
374 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
375 DEBUG( 10,
376 ( "get_eventlog_record: computer_name %d is ",
377 ee->data_record.computer_name_len ) );
378 SAFE_FREE( ret.dptr );
379 return ee;
382 /********************************************************************
383 note that this can only be called AFTER the table is constructed,
384 since it uses the table to find the tdb handle
385 ********************************************************************/
387 static BOOL sync_eventlog_params( EVENTLOG_INFO *info )
389 pstring path;
390 uint32 uiMaxSize;
391 uint32 uiRetention;
392 REGISTRY_KEY *keyinfo;
393 REGISTRY_VALUE *val;
394 REGVAL_CTR *values;
395 WERROR wresult;
396 char *elogname = info->logname;
398 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
400 if ( !info->etdb ) {
401 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
402 return False;
404 /* set resonable defaults. 512Kb on size and 1 week on time */
406 uiMaxSize = 0x80000;
407 uiRetention = 604800;
409 /* the general idea is to internally open the registry
410 key and retreive the values. That way we can continue
411 to use the same fetch/store api that we use in
412 srv_reg_nt.c */
414 pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname );
416 wresult =
417 regkey_open_internal( &keyinfo, path, get_root_nt_token( ),
418 REG_KEY_READ );
420 if ( !W_ERROR_IS_OK( wresult ) ) {
421 DEBUG( 4,
422 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
423 path, dos_errstr( wresult ) ) );
424 return False;
427 if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) {
428 TALLOC_FREE( keyinfo );
429 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
431 return False;
433 fetch_reg_values( keyinfo, values );
435 if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL )
436 uiRetention = IVAL( regval_data_p( val ), 0 );
438 if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL )
439 uiMaxSize = IVAL( regval_data_p( val ), 0 );
441 regkey_close_internal( keyinfo );
443 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
444 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
446 return True;
449 /********************************************************************
450 ********************************************************************/
452 static Eventlog_entry *read_package_entry( prs_struct * ps,
453 EVENTLOG_Q_READ_EVENTLOG * q_u,
454 EVENTLOG_R_READ_EVENTLOG * r_u,
455 Eventlog_entry * entry )
457 uint8 *offset;
458 Eventlog_entry *ee_new = NULL;
460 ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
461 if ( ee_new == NULL ) {
462 return NULL;
465 entry->data_record.sid_padding =
466 ( ( 4 -
467 ( ( entry->data_record.source_name_len +
468 entry->data_record.computer_name_len ) % 4 ) ) % 4 );
469 entry->data_record.data_padding =
470 ( 4 -
471 ( ( entry->data_record.strings_len +
472 entry->data_record.user_data_len ) % 4 ) ) % 4;
473 entry->record.length = sizeof( Eventlog_record );
474 entry->record.length += entry->data_record.source_name_len;
475 entry->record.length += entry->data_record.computer_name_len;
476 if ( entry->record.user_sid_length == 0 ) {
477 /* Should not pad to a DWORD boundary for writing out the sid if there is
478 no SID, so just propagate the padding to pad the data */
479 entry->data_record.data_padding +=
480 entry->data_record.sid_padding;
481 entry->data_record.sid_padding = 0;
483 DEBUG( 10,
484 ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
485 DEBUG( 10,
486 ( "data_padding is [%d].\n",
487 entry->data_record.data_padding ) );
489 entry->record.length += entry->data_record.sid_padding;
490 entry->record.length += entry->record.user_sid_length;
491 entry->record.length += entry->data_record.strings_len;
492 entry->record.length += entry->data_record.user_data_len;
493 entry->record.length += entry->data_record.data_padding;
494 /* need another copy of length at the end of the data */
495 entry->record.length += sizeof( entry->record.length );
496 DEBUG( 10,
497 ( "entry->record.length is [%d].\n", entry->record.length ) );
498 entry->data =
499 PRS_ALLOC_MEM( ps, uint8,
500 entry->record.length -
501 sizeof( Eventlog_record ) -
502 sizeof( entry->record.length ) );
503 if ( entry->data == NULL ) {
504 return NULL;
506 offset = entry->data;
507 memcpy( offset, &( entry->data_record.source_name ),
508 entry->data_record.source_name_len );
509 offset += entry->data_record.source_name_len;
510 memcpy( offset, &( entry->data_record.computer_name ),
511 entry->data_record.computer_name_len );
512 offset += entry->data_record.computer_name_len;
513 /* SID needs to be DWORD-aligned */
514 offset += entry->data_record.sid_padding;
515 entry->record.user_sid_offset =
516 sizeof( Eventlog_record ) + ( offset - entry->data );
517 memcpy( offset, &( entry->data_record.sid ),
518 entry->record.user_sid_length );
519 offset += entry->record.user_sid_length;
520 /* Now do the strings */
521 entry->record.string_offset =
522 sizeof( Eventlog_record ) + ( offset - entry->data );
523 memcpy( offset, &( entry->data_record.strings ),
524 entry->data_record.strings_len );
525 offset += entry->data_record.strings_len;
526 /* Now do the data */
527 entry->record.data_length = entry->data_record.user_data_len;
528 entry->record.data_offset =
529 sizeof( Eventlog_record ) + ( offset - entry->data );
530 memcpy( offset, &( entry->data_record.user_data ),
531 entry->data_record.user_data_len );
532 offset += entry->data_record.user_data_len;
534 memcpy( &( ee_new->record ), &entry->record,
535 sizeof( Eventlog_record ) );
536 memcpy( &( ee_new->data_record ), &entry->data_record,
537 sizeof( Eventlog_data_record ) );
538 ee_new->data = entry->data;
540 return ee_new;
543 /********************************************************************
544 ********************************************************************/
546 static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
547 Eventlog_entry * ee_new )
549 Eventlog_entry *insert_point;
551 insert_point = r_u->entry;
553 if ( NULL == insert_point ) {
554 r_u->entry = ee_new;
555 ee_new->next = NULL;
556 } else {
557 while ( ( NULL != insert_point->next ) ) {
558 insert_point = insert_point->next;
560 ee_new->next = NULL;
561 insert_point->next = ee_new;
563 r_u->num_records++;
564 r_u->num_bytes_in_resp += ee_new->record.length;
566 return True;
569 /********************************************************************
570 ********************************************************************/
572 NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
573 EVENTLOG_Q_OPEN_EVENTLOG * q_u,
574 EVENTLOG_R_OPEN_EVENTLOG * r_u )
576 fstring servername, logname;
577 EVENTLOG_INFO *info;
578 NTSTATUS result;
580 fstrcpy( servername, "" );
581 if ( q_u->servername.string ) {
582 rpcstr_pull( servername, q_u->servername.string->buffer,
583 sizeof( servername ),
584 q_u->servername.string->uni_str_len * 2, 0 );
587 fstrcpy( logname, "" );
588 if ( q_u->logname.string ) {
589 rpcstr_pull( logname, q_u->logname.string->buffer,
590 sizeof( logname ),
591 q_u->logname.string->uni_str_len * 2, 0 );
594 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
595 servername, logname ));
597 /* according to MSDN, if the logfile cannot be found, we should
598 default to the "Application" log */
600 if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) )
601 return result;
603 if ( !(info = find_eventlog_info_by_hnd( p, &r_u->handle )) ) {
604 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
605 logname ));
606 elog_close( p, &r_u->handle );
607 return NT_STATUS_INVALID_HANDLE;
610 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
612 sync_eventlog_params( info );
613 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
615 return NT_STATUS_OK;
618 /********************************************************************
619 This call still needs some work
620 ********************************************************************/
622 NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
623 EVENTLOG_Q_CLEAR_EVENTLOG * q_u,
624 EVENTLOG_R_CLEAR_EVENTLOG * r_u )
626 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
627 pstring backup_file_name;
629 if ( !info )
630 return NT_STATUS_INVALID_HANDLE;
632 pstrcpy( backup_file_name, "" );
633 if ( q_u->backupfile.string ) {
634 rpcstr_pull( backup_file_name, q_u->backupfile.string->buffer,
635 sizeof( backup_file_name ),
636 q_u->backupfile.string->uni_str_len * 2, 0 );
638 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
639 "file name for log [%s].",
640 backup_file_name, info->logname ) );
643 /* check for WRITE access to the file */
645 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
646 return NT_STATUS_ACCESS_DENIED;
648 /* Force a close and reopen */
650 elog_close_tdb( info->etdb, True );
651 become_root();
652 info->etdb = elog_open_tdb( info->logname, True );
653 unbecome_root();
655 if ( !info->etdb )
656 return NT_STATUS_ACCESS_DENIED;
658 return NT_STATUS_OK;
661 /********************************************************************
662 ********************************************************************/
664 NTSTATUS _eventlog_close_eventlog( pipes_struct * p,
665 EVENTLOG_Q_CLOSE_EVENTLOG * q_u,
666 EVENTLOG_R_CLOSE_EVENTLOG * r_u )
668 return elog_close( p, &q_u->handle );
671 /********************************************************************
672 ********************************************************************/
674 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
675 EVENTLOG_Q_READ_EVENTLOG * q_u,
676 EVENTLOG_R_READ_EVENTLOG * r_u )
678 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
679 Eventlog_entry entry, *ee_new;
680 uint32 num_records_read = 0;
681 prs_struct *ps;
682 int bytes_left, record_number;
683 uint32 elog_read_type, elog_read_dir;
685 info->flags = q_u->flags;
686 ps = &p->out_data.rdata;
688 bytes_left = q_u->max_read_size;
690 if ( !info->etdb )
691 return NT_STATUS_ACCESS_DENIED;
693 /* check for valid flags. Can't use the sequential and seek flags together */
695 elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
696 elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
698 if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
699 || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
701 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
702 return NT_STATUS_INVALID_PARAMETER;
705 /* a sequential read should ignore the offset */
707 if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
708 record_number = info->current_record;
709 else
710 record_number = q_u->offset;
712 while ( bytes_left > 0 ) {
714 /* assume that when the record fetch fails, that we are done */
716 if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) )
717 break;
719 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
721 /* Now see if there is enough room to add */
723 if ( !(ee_new = read_package_entry( ps, q_u, r_u,&entry )) )
724 return NT_STATUS_NO_MEMORY;
726 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
727 r_u->bytes_in_next_record = ee_new->record.length;
729 /* response would be too big to fit in client-size buffer */
731 bytes_left = 0;
732 break;
735 add_record_to_resp( r_u, ee_new );
736 bytes_left -= ee_new->record.length;
737 ZERO_STRUCT( entry );
738 num_records_read = r_u->num_records - num_records_read;
740 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
741 "of [%d] records using [%d] bytes out of a max of [%d].\n",
742 num_records_read, r_u->num_records,
743 r_u->num_bytes_in_resp,
744 q_u->max_read_size ) );
746 if ( info->flags & EVENTLOG_FORWARDS_READ )
747 record_number++;
748 else
749 record_number--;
751 /* update the eventlog record pointer */
753 info->current_record = record_number;
756 /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
757 say when there are no more records */
759 return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
762 /********************************************************************
763 ********************************************************************/
765 NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p,
766 EVENTLOG_Q_GET_OLDEST_ENTRY * q_u,
767 EVENTLOG_R_GET_OLDEST_ENTRY * r_u )
769 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
771 if ( !( get_oldest_entry_hook( info ) ) )
772 return NT_STATUS_ACCESS_DENIED;
774 r_u->oldest_entry = info->oldest_entry;
776 return NT_STATUS_OK;
779 /********************************************************************
780 ********************************************************************/
782 NTSTATUS _eventlog_get_num_records( pipes_struct * p,
783 EVENTLOG_Q_GET_NUM_RECORDS * q_u,
784 EVENTLOG_R_GET_NUM_RECORDS * r_u )
786 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
788 if ( !( get_num_records_hook( info ) ) )
789 return NT_STATUS_ACCESS_DENIED;
791 r_u->num_records = info->num_records;
793 return NT_STATUS_OK;