r19778: Make regkey_open_internal take a talloc ctx
[Samba.git] / source / rpc_server / srv_eventlog_nt.c
blobba366ed9832a20aa2df5386803c88c91a12c25a0
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 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 retrieve 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 = regkey_open_internal(
415 NULL, &keyinfo, path, get_root_nt_token(), REG_KEY_READ );
417 if ( !W_ERROR_IS_OK( wresult ) ) {
418 DEBUG( 4,
419 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
420 path, dos_errstr( wresult ) ) );
421 return False;
424 if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) {
425 TALLOC_FREE( keyinfo );
426 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
428 return False;
430 fetch_reg_values( keyinfo, values );
432 if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL )
433 uiRetention = IVAL( regval_data_p( val ), 0 );
435 if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL )
436 uiMaxSize = IVAL( regval_data_p( val ), 0 );
438 regkey_close_internal( keyinfo );
440 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
441 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
443 return True;
446 /********************************************************************
447 ********************************************************************/
449 static Eventlog_entry *read_package_entry( prs_struct * ps,
450 EVENTLOG_Q_READ_EVENTLOG * q_u,
451 EVENTLOG_R_READ_EVENTLOG * r_u,
452 Eventlog_entry * entry )
454 uint8 *offset;
455 Eventlog_entry *ee_new = NULL;
457 ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
458 if ( ee_new == NULL ) {
459 return NULL;
462 entry->data_record.sid_padding =
463 ( ( 4 -
464 ( ( entry->data_record.source_name_len +
465 entry->data_record.computer_name_len ) % 4 ) ) % 4 );
466 entry->data_record.data_padding =
467 ( 4 -
468 ( ( entry->data_record.strings_len +
469 entry->data_record.user_data_len ) % 4 ) ) % 4;
470 entry->record.length = sizeof( Eventlog_record );
471 entry->record.length += entry->data_record.source_name_len;
472 entry->record.length += entry->data_record.computer_name_len;
473 if ( entry->record.user_sid_length == 0 ) {
474 /* Should not pad to a DWORD boundary for writing out the sid if there is
475 no SID, so just propagate the padding to pad the data */
476 entry->data_record.data_padding +=
477 entry->data_record.sid_padding;
478 entry->data_record.sid_padding = 0;
480 DEBUG( 10,
481 ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
482 DEBUG( 10,
483 ( "data_padding is [%d].\n",
484 entry->data_record.data_padding ) );
486 entry->record.length += entry->data_record.sid_padding;
487 entry->record.length += entry->record.user_sid_length;
488 entry->record.length += entry->data_record.strings_len;
489 entry->record.length += entry->data_record.user_data_len;
490 entry->record.length += entry->data_record.data_padding;
491 /* need another copy of length at the end of the data */
492 entry->record.length += sizeof( entry->record.length );
493 DEBUG( 10,
494 ( "entry->record.length is [%d].\n", entry->record.length ) );
495 entry->data =
496 PRS_ALLOC_MEM( ps, uint8,
497 entry->record.length -
498 sizeof( Eventlog_record ) -
499 sizeof( entry->record.length ) );
500 if ( entry->data == NULL ) {
501 return NULL;
503 offset = entry->data;
504 memcpy( offset, &( entry->data_record.source_name ),
505 entry->data_record.source_name_len );
506 offset += entry->data_record.source_name_len;
507 memcpy( offset, &( entry->data_record.computer_name ),
508 entry->data_record.computer_name_len );
509 offset += entry->data_record.computer_name_len;
510 /* SID needs to be DWORD-aligned */
511 offset += entry->data_record.sid_padding;
512 entry->record.user_sid_offset =
513 sizeof( Eventlog_record ) + ( offset - entry->data );
514 memcpy( offset, &( entry->data_record.sid ),
515 entry->record.user_sid_length );
516 offset += entry->record.user_sid_length;
517 /* Now do the strings */
518 entry->record.string_offset =
519 sizeof( Eventlog_record ) + ( offset - entry->data );
520 memcpy( offset, &( entry->data_record.strings ),
521 entry->data_record.strings_len );
522 offset += entry->data_record.strings_len;
523 /* Now do the data */
524 entry->record.data_length = entry->data_record.user_data_len;
525 entry->record.data_offset =
526 sizeof( Eventlog_record ) + ( offset - entry->data );
527 memcpy( offset, &( entry->data_record.user_data ),
528 entry->data_record.user_data_len );
529 offset += entry->data_record.user_data_len;
531 memcpy( &( ee_new->record ), &entry->record,
532 sizeof( Eventlog_record ) );
533 memcpy( &( ee_new->data_record ), &entry->data_record,
534 sizeof( Eventlog_data_record ) );
535 ee_new->data = entry->data;
537 return ee_new;
540 /********************************************************************
541 ********************************************************************/
543 static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
544 Eventlog_entry * ee_new )
546 Eventlog_entry *insert_point;
548 insert_point = r_u->entry;
550 if ( NULL == insert_point ) {
551 r_u->entry = ee_new;
552 ee_new->next = NULL;
553 } else {
554 while ( ( NULL != insert_point->next ) ) {
555 insert_point = insert_point->next;
557 ee_new->next = NULL;
558 insert_point->next = ee_new;
560 r_u->num_records++;
561 r_u->num_bytes_in_resp += ee_new->record.length;
563 return True;
566 /********************************************************************
567 ********************************************************************/
569 NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
570 EVENTLOG_Q_OPEN_EVENTLOG * q_u,
571 EVENTLOG_R_OPEN_EVENTLOG * r_u )
573 fstring servername, logname;
574 EVENTLOG_INFO *info;
575 NTSTATUS result;
577 fstrcpy( servername, "" );
578 if ( q_u->servername.string ) {
579 rpcstr_pull( servername, q_u->servername.string->buffer,
580 sizeof( servername ),
581 q_u->servername.string->uni_str_len * 2, 0 );
584 fstrcpy( logname, "" );
585 if ( q_u->logname.string ) {
586 rpcstr_pull( logname, q_u->logname.string->buffer,
587 sizeof( logname ),
588 q_u->logname.string->uni_str_len * 2, 0 );
591 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
592 servername, logname ));
594 /* according to MSDN, if the logfile cannot be found, we should
595 default to the "Application" log */
597 if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) )
598 return result;
600 if ( !(info = find_eventlog_info_by_hnd( p, &r_u->handle )) ) {
601 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
602 logname ));
603 elog_close( p, &r_u->handle );
604 return NT_STATUS_INVALID_HANDLE;
607 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
609 sync_eventlog_params( info );
610 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
612 return NT_STATUS_OK;
615 /********************************************************************
616 This call still needs some work
617 ********************************************************************/
619 NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
620 EVENTLOG_Q_CLEAR_EVENTLOG * q_u,
621 EVENTLOG_R_CLEAR_EVENTLOG * r_u )
623 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
624 pstring backup_file_name;
626 if ( !info )
627 return NT_STATUS_INVALID_HANDLE;
629 pstrcpy( backup_file_name, "" );
630 if ( q_u->backupfile.string ) {
631 rpcstr_pull( backup_file_name, q_u->backupfile.string->buffer,
632 sizeof( backup_file_name ),
633 q_u->backupfile.string->uni_str_len * 2, 0 );
635 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
636 "file name for log [%s].",
637 backup_file_name, info->logname ) );
640 /* check for WRITE access to the file */
642 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
643 return NT_STATUS_ACCESS_DENIED;
645 /* Force a close and reopen */
647 elog_close_tdb( info->etdb, True );
648 become_root();
649 info->etdb = elog_open_tdb( info->logname, True );
650 unbecome_root();
652 if ( !info->etdb )
653 return NT_STATUS_ACCESS_DENIED;
655 return NT_STATUS_OK;
658 /********************************************************************
659 ********************************************************************/
661 NTSTATUS _eventlog_close_eventlog( pipes_struct * p,
662 EVENTLOG_Q_CLOSE_EVENTLOG * q_u,
663 EVENTLOG_R_CLOSE_EVENTLOG * r_u )
665 return elog_close( p, &q_u->handle );
668 /********************************************************************
669 ********************************************************************/
671 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
672 EVENTLOG_Q_READ_EVENTLOG * q_u,
673 EVENTLOG_R_READ_EVENTLOG * r_u )
675 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
676 Eventlog_entry entry, *ee_new;
677 uint32 num_records_read = 0;
678 prs_struct *ps;
679 int bytes_left, record_number;
680 uint32 elog_read_type, elog_read_dir;
682 if (info == NULL) {
683 return NT_STATUS_INVALID_HANDLE;
686 info->flags = q_u->flags;
687 ps = &p->out_data.rdata;
689 bytes_left = q_u->max_read_size;
691 if ( !info->etdb )
692 return NT_STATUS_ACCESS_DENIED;
694 /* check for valid flags. Can't use the sequential and seek flags together */
696 elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
697 elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
699 if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
700 || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
702 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
703 return NT_STATUS_INVALID_PARAMETER;
706 /* a sequential read should ignore the offset */
708 if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
709 record_number = info->current_record;
710 else
711 record_number = q_u->offset;
713 while ( bytes_left > 0 ) {
715 /* assume that when the record fetch fails, that we are done */
717 if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) )
718 break;
720 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
722 /* Now see if there is enough room to add */
724 if ( !(ee_new = read_package_entry( ps, q_u, r_u,&entry )) )
725 return NT_STATUS_NO_MEMORY;
727 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
728 r_u->bytes_in_next_record = ee_new->record.length;
730 /* response would be too big to fit in client-size buffer */
732 bytes_left = 0;
733 break;
736 add_record_to_resp( r_u, ee_new );
737 bytes_left -= ee_new->record.length;
738 ZERO_STRUCT( entry );
739 num_records_read = r_u->num_records - num_records_read;
741 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
742 "of [%d] records using [%d] bytes out of a max of [%d].\n",
743 num_records_read, r_u->num_records,
744 r_u->num_bytes_in_resp,
745 q_u->max_read_size ) );
747 if ( info->flags & EVENTLOG_FORWARDS_READ )
748 record_number++;
749 else
750 record_number--;
752 /* update the eventlog record pointer */
754 info->current_record = record_number;
757 /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
758 say when there are no more records */
760 return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
763 /********************************************************************
764 ********************************************************************/
766 NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p,
767 EVENTLOG_Q_GET_OLDEST_ENTRY * q_u,
768 EVENTLOG_R_GET_OLDEST_ENTRY * r_u )
770 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
772 if (info == NULL) {
773 return NT_STATUS_INVALID_HANDLE;
776 if ( !( get_oldest_entry_hook( info ) ) )
777 return NT_STATUS_ACCESS_DENIED;
779 r_u->oldest_entry = info->oldest_entry;
781 return NT_STATUS_OK;
784 /********************************************************************
785 ********************************************************************/
787 NTSTATUS _eventlog_get_num_records( pipes_struct * p,
788 EVENTLOG_Q_GET_NUM_RECORDS * q_u,
789 EVENTLOG_R_GET_NUM_RECORDS * r_u )
791 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
793 if (info == NULL) {
794 return NT_STATUS_INVALID_HANDLE;
797 if ( !( get_num_records_hook( info ) ) )
798 return NT_STATUS_ACCESS_DENIED;
800 r_u->num_records = info->num_records;
802 return NT_STATUS_OK;