r21585: Start syncing the monster that will become 3.0.25pre1
[Samba.git] / source / rpc_server / srv_eventlog_nt.c
blob0684276015459625bbebae37a9a60f76ee2e3e95
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_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);
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 static 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;
293 pstring *wpsource, *wpcomputer, *wpsid, *wpstrs, *puserdata;
295 key.dsize = sizeof( int32 );
297 srecno = recno;
298 key.dptr = ( char * ) &srecno;
300 ret = tdb_fetch( tdb, key );
302 if ( ret.dsize == 0 ) {
303 DEBUG( 8,
304 ( "Can't find a record for the key, record %d\n",
305 recno ) );
306 return NULL;
309 len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
311 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
313 if ( !len )
314 return NULL;
316 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
318 if ( !ee )
319 return NULL;
321 len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
322 &ee->record.length, &ee->record.reserved1,
323 &ee->record.record_number,
324 &ee->record.time_generated,
325 &ee->record.time_written, &ee->record.event_id,
326 &ee->record.event_type, &ee->record.num_strings,
327 &ee->record.event_category, &ee->record.reserved2,
328 &ee->record.closing_record_number,
329 &ee->record.string_offset,
330 &ee->record.user_sid_length,
331 &ee->record.user_sid_offset,
332 &ee->record.data_length, &ee->record.data_offset,
333 &ee->data_record.source_name_len, &wpsource,
334 &ee->data_record.computer_name_len, &wpcomputer,
335 &ee->data_record.sid_padding,
336 &ee->record.user_sid_length, &wpsid,
337 &ee->data_record.strings_len, &wpstrs,
338 &ee->data_record.user_data_len, &puserdata,
339 &ee->data_record.data_padding );
340 DEBUG( 10,
341 ( "Read record %d, len in tdb was %d\n",
342 ee->record.record_number, len ) );
344 /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
345 into it's 2nd argment for 'B' */
347 if ( wpcomputer )
348 memcpy( ee->data_record.computer_name, wpcomputer,
349 ee->data_record.computer_name_len );
350 if ( wpsource )
351 memcpy( ee->data_record.source_name, wpsource,
352 ee->data_record.source_name_len );
354 if ( wpsid )
355 memcpy( ee->data_record.sid, wpsid,
356 ee->record.user_sid_length );
357 if ( wpstrs )
358 memcpy( ee->data_record.strings, wpstrs,
359 ee->data_record.strings_len );
361 /* note that userdata is a pstring */
362 if ( puserdata )
363 memcpy( ee->data_record.user_data, puserdata,
364 ee->data_record.user_data_len );
366 SAFE_FREE( wpcomputer );
367 SAFE_FREE( wpsource );
368 SAFE_FREE( wpsid );
369 SAFE_FREE( wpstrs );
370 SAFE_FREE( puserdata );
372 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
373 DEBUG( 10,
374 ( "get_eventlog_record: computer_name %d is ",
375 ee->data_record.computer_name_len ) );
376 SAFE_FREE( ret.dptr );
377 return ee;
380 /********************************************************************
381 note that this can only be called AFTER the table is constructed,
382 since it uses the table to find the tdb handle
383 ********************************************************************/
385 static BOOL sync_eventlog_params( EVENTLOG_INFO *info )
387 pstring path;
388 uint32 uiMaxSize;
389 uint32 uiRetention;
390 REGISTRY_KEY *keyinfo;
391 REGISTRY_VALUE *val;
392 REGVAL_CTR *values;
393 WERROR wresult;
394 char *elogname = info->logname;
396 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
398 if ( !info->etdb ) {
399 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
400 return False;
402 /* set resonable defaults. 512Kb on size and 1 week on time */
404 uiMaxSize = 0x80000;
405 uiRetention = 604800;
407 /* the general idea is to internally open the registry
408 key and retreive the values. That way we can continue
409 to use the same fetch/store api that we use in
410 srv_reg_nt.c */
412 pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname );
414 wresult =
415 regkey_open_internal( &keyinfo, path, get_root_nt_token( ),
416 REG_KEY_READ );
418 if ( !W_ERROR_IS_OK( wresult ) ) {
419 DEBUG( 4,
420 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
421 path, dos_errstr( wresult ) ) );
422 return False;
425 if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) {
426 TALLOC_FREE( keyinfo );
427 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
429 return False;
431 fetch_reg_values( keyinfo, values );
433 if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL )
434 uiRetention = IVAL( regval_data_p( val ), 0 );
436 if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL )
437 uiMaxSize = IVAL( regval_data_p( val ), 0 );
439 regkey_close_internal( keyinfo );
441 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
442 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
444 return True;
447 /********************************************************************
448 ********************************************************************/
450 static Eventlog_entry *read_package_entry( prs_struct * ps,
451 EVENTLOG_Q_READ_EVENTLOG * q_u,
452 EVENTLOG_R_READ_EVENTLOG * r_u,
453 Eventlog_entry * entry )
455 uint8 *offset;
456 Eventlog_entry *ee_new = NULL;
458 ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
459 if ( ee_new == NULL ) {
460 return NULL;
463 entry->data_record.sid_padding =
464 ( ( 4 -
465 ( ( entry->data_record.source_name_len +
466 entry->data_record.computer_name_len ) % 4 ) ) % 4 );
467 entry->data_record.data_padding =
468 ( 4 -
469 ( ( entry->data_record.strings_len +
470 entry->data_record.user_data_len ) % 4 ) ) % 4;
471 entry->record.length = sizeof( Eventlog_record );
472 entry->record.length += entry->data_record.source_name_len;
473 entry->record.length += entry->data_record.computer_name_len;
474 if ( entry->record.user_sid_length == 0 ) {
475 /* Should not pad to a DWORD boundary for writing out the sid if there is
476 no SID, so just propagate the padding to pad the data */
477 entry->data_record.data_padding +=
478 entry->data_record.sid_padding;
479 entry->data_record.sid_padding = 0;
481 DEBUG( 10,
482 ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
483 DEBUG( 10,
484 ( "data_padding is [%d].\n",
485 entry->data_record.data_padding ) );
487 entry->record.length += entry->data_record.sid_padding;
488 entry->record.length += entry->record.user_sid_length;
489 entry->record.length += entry->data_record.strings_len;
490 entry->record.length += entry->data_record.user_data_len;
491 entry->record.length += entry->data_record.data_padding;
492 /* need another copy of length at the end of the data */
493 entry->record.length += sizeof( entry->record.length );
494 DEBUG( 10,
495 ( "entry->record.length is [%d].\n", entry->record.length ) );
496 entry->data =
497 PRS_ALLOC_MEM( ps, uint8,
498 entry->record.length -
499 sizeof( Eventlog_record ) -
500 sizeof( entry->record.length ) );
501 if ( entry->data == NULL ) {
502 return NULL;
504 offset = entry->data;
505 memcpy( offset, &( entry->data_record.source_name ),
506 entry->data_record.source_name_len );
507 offset += entry->data_record.source_name_len;
508 memcpy( offset, &( entry->data_record.computer_name ),
509 entry->data_record.computer_name_len );
510 offset += entry->data_record.computer_name_len;
511 /* SID needs to be DWORD-aligned */
512 offset += entry->data_record.sid_padding;
513 entry->record.user_sid_offset =
514 sizeof( Eventlog_record ) + ( offset - entry->data );
515 memcpy( offset, &( entry->data_record.sid ),
516 entry->record.user_sid_length );
517 offset += entry->record.user_sid_length;
518 /* Now do the strings */
519 entry->record.string_offset =
520 sizeof( Eventlog_record ) + ( offset - entry->data );
521 memcpy( offset, &( entry->data_record.strings ),
522 entry->data_record.strings_len );
523 offset += entry->data_record.strings_len;
524 /* Now do the data */
525 entry->record.data_length = entry->data_record.user_data_len;
526 entry->record.data_offset =
527 sizeof( Eventlog_record ) + ( offset - entry->data );
528 memcpy( offset, &( entry->data_record.user_data ),
529 entry->data_record.user_data_len );
530 offset += entry->data_record.user_data_len;
532 memcpy( &( ee_new->record ), &entry->record,
533 sizeof( Eventlog_record ) );
534 memcpy( &( ee_new->data_record ), &entry->data_record,
535 sizeof( Eventlog_data_record ) );
536 ee_new->data = entry->data;
538 return ee_new;
541 /********************************************************************
542 ********************************************************************/
544 static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
545 Eventlog_entry * ee_new )
547 Eventlog_entry *insert_point;
549 insert_point = r_u->entry;
551 if ( NULL == insert_point ) {
552 r_u->entry = ee_new;
553 ee_new->next = NULL;
554 } else {
555 while ( ( NULL != insert_point->next ) ) {
556 insert_point = insert_point->next;
558 ee_new->next = NULL;
559 insert_point->next = ee_new;
561 r_u->num_records++;
562 r_u->num_bytes_in_resp += ee_new->record.length;
564 return True;
567 /********************************************************************
568 ********************************************************************/
570 NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
571 EVENTLOG_Q_OPEN_EVENTLOG * q_u,
572 EVENTLOG_R_OPEN_EVENTLOG * r_u )
574 fstring servername, logname;
575 EVENTLOG_INFO *info;
576 NTSTATUS result;
578 fstrcpy( servername, "" );
579 if ( q_u->servername.string ) {
580 rpcstr_pull( servername, q_u->servername.string->buffer,
581 sizeof( servername ),
582 q_u->servername.string->uni_str_len * 2, 0 );
585 fstrcpy( logname, "" );
586 if ( q_u->logname.string ) {
587 rpcstr_pull( logname, q_u->logname.string->buffer,
588 sizeof( logname ),
589 q_u->logname.string->uni_str_len * 2, 0 );
592 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
593 servername, logname ));
595 /* according to MSDN, if the logfile cannot be found, we should
596 default to the "Application" log */
598 if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) )
599 return result;
601 if ( !(info = find_eventlog_info_by_hnd( p, &r_u->handle )) ) {
602 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
603 logname ));
604 elog_close( p, &r_u->handle );
605 return NT_STATUS_INVALID_HANDLE;
608 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
610 sync_eventlog_params( info );
611 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
613 return NT_STATUS_OK;
616 /********************************************************************
617 This call still needs some work
618 ********************************************************************/
620 NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
621 EVENTLOG_Q_CLEAR_EVENTLOG * q_u,
622 EVENTLOG_R_CLEAR_EVENTLOG * r_u )
624 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
625 pstring backup_file_name;
627 if ( !info )
628 return NT_STATUS_INVALID_HANDLE;
630 pstrcpy( backup_file_name, "" );
631 if ( q_u->backupfile.string ) {
632 rpcstr_pull( backup_file_name, q_u->backupfile.string->buffer,
633 sizeof( backup_file_name ),
634 q_u->backupfile.string->uni_str_len * 2, 0 );
636 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
637 "file name for log [%s].",
638 backup_file_name, info->logname ) );
641 /* check for WRITE access to the file */
643 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
644 return NT_STATUS_ACCESS_DENIED;
646 /* Force a close and reopen */
648 elog_close_tdb( info->etdb, True );
649 become_root();
650 info->etdb = elog_open_tdb( info->logname, True );
651 unbecome_root();
653 if ( !info->etdb )
654 return NT_STATUS_ACCESS_DENIED;
656 return NT_STATUS_OK;
659 /********************************************************************
660 ********************************************************************/
662 NTSTATUS _eventlog_close_eventlog( pipes_struct * p,
663 EVENTLOG_Q_CLOSE_EVENTLOG * q_u,
664 EVENTLOG_R_CLOSE_EVENTLOG * r_u )
666 return elog_close( p, &q_u->handle );
669 /********************************************************************
670 ********************************************************************/
672 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
673 EVENTLOG_Q_READ_EVENTLOG * q_u,
674 EVENTLOG_R_READ_EVENTLOG * r_u )
676 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
677 Eventlog_entry entry, *ee_new;
678 uint32 num_records_read = 0;
679 prs_struct *ps;
680 int bytes_left, record_number;
681 uint32 elog_read_type, elog_read_dir;
683 if (info == NULL) {
684 return NT_STATUS_INVALID_HANDLE;
687 info->flags = q_u->flags;
688 ps = &p->out_data.rdata;
690 bytes_left = q_u->max_read_size;
692 if ( !info->etdb )
693 return NT_STATUS_ACCESS_DENIED;
695 /* check for valid flags. Can't use the sequential and seek flags together */
697 elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
698 elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
700 if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
701 || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
703 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
704 return NT_STATUS_INVALID_PARAMETER;
707 /* a sequential read should ignore the offset */
709 if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
710 record_number = info->current_record;
711 else
712 record_number = q_u->offset;
714 while ( bytes_left > 0 ) {
716 /* assume that when the record fetch fails, that we are done */
718 if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) )
719 break;
721 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
723 /* Now see if there is enough room to add */
725 if ( !(ee_new = read_package_entry( ps, q_u, r_u,&entry )) )
726 return NT_STATUS_NO_MEMORY;
728 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
729 r_u->bytes_in_next_record = ee_new->record.length;
731 /* response would be too big to fit in client-size buffer */
733 bytes_left = 0;
734 break;
737 add_record_to_resp( r_u, ee_new );
738 bytes_left -= ee_new->record.length;
739 ZERO_STRUCT( entry );
740 num_records_read = r_u->num_records - num_records_read;
742 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
743 "of [%d] records using [%d] bytes out of a max of [%d].\n",
744 num_records_read, r_u->num_records,
745 r_u->num_bytes_in_resp,
746 q_u->max_read_size ) );
748 if ( info->flags & EVENTLOG_FORWARDS_READ )
749 record_number++;
750 else
751 record_number--;
753 /* update the eventlog record pointer */
755 info->current_record = record_number;
758 /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
759 say when there are no more records */
761 return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
764 /********************************************************************
765 ********************************************************************/
767 NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p,
768 EVENTLOG_Q_GET_OLDEST_ENTRY * q_u,
769 EVENTLOG_R_GET_OLDEST_ENTRY * r_u )
771 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
773 if (info == NULL) {
774 return NT_STATUS_INVALID_HANDLE;
777 if ( !( get_oldest_entry_hook( info ) ) )
778 return NT_STATUS_ACCESS_DENIED;
780 r_u->oldest_entry = info->oldest_entry;
782 return NT_STATUS_OK;
785 /********************************************************************
786 ********************************************************************/
788 NTSTATUS _eventlog_get_num_records( pipes_struct * p,
789 EVENTLOG_Q_GET_NUM_RECORDS * q_u,
790 EVENTLOG_R_GET_NUM_RECORDS * r_u )
792 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
794 if (info == NULL) {
795 return NT_STATUS_INVALID_HANDLE;
798 if ( !( get_num_records_hook( info ) ) )
799 return NT_STATUS_ACCESS_DENIED;
801 r_u->num_records = info->num_records;
803 return NT_STATUS_OK;