[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / rpc_server / srv_eventlog_nt.c
blobe3d6fff2ab087b233a55d4d6f9cbb10f59abb2b9
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 if (!elogs) {
127 return False;
130 for ( i=0; elogs[i]; i++ ) {
131 if ( strequal( name, elogs[i] ) )
132 return True;
135 return False;
138 /********************************************************************
139 ********************************************************************/
141 static BOOL get_num_records_hook( EVENTLOG_INFO * info )
143 int next_record;
144 int oldest_record;
146 if ( !info->etdb ) {
147 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
148 return False;
151 /* lock the tdb since we have to get 2 records */
153 tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
154 next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
155 oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
156 tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
158 DEBUG( 8,
159 ( "Oldest Record %d; Next Record %d\n", oldest_record,
160 next_record ) );
162 info->num_records = ( next_record - oldest_record );
163 info->oldest_entry = oldest_record;
165 return True;
168 /********************************************************************
169 ********************************************************************/
171 static BOOL get_oldest_entry_hook( EVENTLOG_INFO * info )
173 /* it's the same thing */
174 return get_num_records_hook( info );
177 /********************************************************************
178 ********************************************************************/
180 static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
182 EVENTLOG_INFO *elog;
184 /* first thing is to validate the eventlog name */
186 if ( !elog_validate_logname( logname ) )
187 return NT_STATUS_OBJECT_PATH_INVALID;
189 if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
190 return NT_STATUS_NO_MEMORY;
192 elog->logname = talloc_strdup( elog, logname );
194 /* Open the tdb first (so that we can create any new tdbs if necessary).
195 We have to do this as root and then use an internal access check
196 on the file permissions since you can only have a tdb open once
197 in a single process */
199 become_root();
200 elog->etdb = elog_open_tdb( elog->logname, False );
201 unbecome_root();
203 if ( !elog->etdb ) {
204 /* according to MSDN, if the logfile cannot be found, we should
205 default to the "Application" log */
207 if ( !strequal( logname, ELOG_APPL ) ) {
209 TALLOC_FREE( elog->logname );
211 elog->logname = talloc_strdup( elog, ELOG_APPL );
213 /* do the access check */
214 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
215 TALLOC_FREE( elog );
216 return NT_STATUS_ACCESS_DENIED;
219 become_root();
220 elog->etdb = elog_open_tdb( elog->logname, False );
221 unbecome_root();
224 if ( !elog->etdb ) {
225 TALLOC_FREE( elog );
226 return NT_STATUS_ACCESS_DENIED; /* ??? */
230 /* now do the access check. Close the tdb if we fail here */
232 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
233 elog_close_tdb( elog->etdb, False );
234 TALLOC_FREE( elog );
235 return NT_STATUS_ACCESS_DENIED;
238 /* create the policy handle */
240 if ( !create_policy_hnd
241 ( p, hnd, free_eventlog_info, ( void * ) elog ) ) {
242 free_eventlog_info( elog );
243 return NT_STATUS_NO_MEMORY;
246 /* set the initial current_record pointer */
248 if ( !get_oldest_entry_hook( elog ) ) {
249 DEBUG(3,("elog_open: Successfully opened eventlog but can't "
250 "get any information on internal records!\n"));
253 elog->current_record = elog->oldest_entry;
255 return NT_STATUS_OK;
258 /********************************************************************
259 ********************************************************************/
261 static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
263 if ( !( close_policy_hnd( p, hnd ) ) ) {
264 return NT_STATUS_INVALID_HANDLE;
267 return NT_STATUS_OK;
270 /*******************************************************************
271 *******************************************************************/
273 static int elog_size( EVENTLOG_INFO *info )
275 if ( !info || !info->etdb ) {
276 DEBUG(0,("elog_size: Invalid info* structure!\n"));
277 return 0;
280 return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
283 /********************************************************************
284 For the given tdb, get the next eventlog record into the passed
285 Eventlog_entry. returns NULL if it can't get the record for some reason.
286 ********************************************************************/
288 static Eventlog_entry *get_eventlog_record( prs_struct * ps, TDB_CONTEXT * tdb,
289 int recno, Eventlog_entry * ee )
291 TDB_DATA ret, key;
293 int srecno;
294 int reclen;
295 int len;
297 pstring *wpsource, *wpcomputer, *wpsid, *wpstrs, *puserdata;
299 key.dsize = sizeof( int32 );
301 srecno = recno;
302 key.dptr = ( char * ) &srecno;
304 ret = tdb_fetch( tdb, key );
306 if ( ret.dsize == 0 ) {
307 DEBUG( 8,
308 ( "Can't find a record for the key, record %d\n",
309 recno ) );
310 return NULL;
313 len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
315 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
317 if ( !len )
318 return NULL;
320 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
322 if ( !ee )
323 return NULL;
325 len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
326 &ee->record.length, &ee->record.reserved1,
327 &ee->record.record_number,
328 &ee->record.time_generated,
329 &ee->record.time_written, &ee->record.event_id,
330 &ee->record.event_type, &ee->record.num_strings,
331 &ee->record.event_category, &ee->record.reserved2,
332 &ee->record.closing_record_number,
333 &ee->record.string_offset,
334 &ee->record.user_sid_length,
335 &ee->record.user_sid_offset,
336 &ee->record.data_length, &ee->record.data_offset,
337 &ee->data_record.source_name_len, &wpsource,
338 &ee->data_record.computer_name_len, &wpcomputer,
339 &ee->data_record.sid_padding,
340 &ee->record.user_sid_length, &wpsid,
341 &ee->data_record.strings_len, &wpstrs,
342 &ee->data_record.user_data_len, &puserdata,
343 &ee->data_record.data_padding );
344 DEBUG( 10,
345 ( "Read record %d, len in tdb was %d\n",
346 ee->record.record_number, len ) );
348 /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
349 into it's 2nd argment for 'B' */
351 if ( wpcomputer )
352 memcpy( ee->data_record.computer_name, wpcomputer,
353 ee->data_record.computer_name_len );
354 if ( wpsource )
355 memcpy( ee->data_record.source_name, wpsource,
356 ee->data_record.source_name_len );
358 if ( wpsid )
359 memcpy( ee->data_record.sid, wpsid,
360 ee->record.user_sid_length );
361 if ( wpstrs )
362 memcpy( ee->data_record.strings, wpstrs,
363 ee->data_record.strings_len );
365 /* note that userdata is a pstring */
366 if ( puserdata )
367 memcpy( ee->data_record.user_data, puserdata,
368 ee->data_record.user_data_len );
370 SAFE_FREE( wpcomputer );
371 SAFE_FREE( wpsource );
372 SAFE_FREE( wpsid );
373 SAFE_FREE( wpstrs );
374 SAFE_FREE( puserdata );
376 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
377 DEBUG( 10,
378 ( "get_eventlog_record: computer_name %d is ",
379 ee->data_record.computer_name_len ) );
380 SAFE_FREE( ret.dptr );
381 return ee;
384 /********************************************************************
385 note that this can only be called AFTER the table is constructed,
386 since it uses the table to find the tdb handle
387 ********************************************************************/
389 static BOOL sync_eventlog_params( EVENTLOG_INFO *info )
391 pstring path;
392 uint32 uiMaxSize;
393 uint32 uiRetention;
394 REGISTRY_KEY *keyinfo;
395 REGISTRY_VALUE *val;
396 REGVAL_CTR *values;
397 WERROR wresult;
398 char *elogname = info->logname;
400 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
402 if ( !info->etdb ) {
403 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
404 return False;
406 /* set resonable defaults. 512Kb on size and 1 week on time */
408 uiMaxSize = 0x80000;
409 uiRetention = 604800;
411 /* the general idea is to internally open the registry
412 key and retreive the values. That way we can continue
413 to use the same fetch/store api that we use in
414 srv_reg_nt.c */
416 pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname );
418 wresult =
419 regkey_open_internal( &keyinfo, path, get_root_nt_token( ),
420 REG_KEY_READ );
422 if ( !W_ERROR_IS_OK( wresult ) ) {
423 DEBUG( 4,
424 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
425 path, dos_errstr( wresult ) ) );
426 return False;
429 if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) {
430 TALLOC_FREE( keyinfo );
431 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
433 return False;
435 fetch_reg_values( keyinfo, values );
437 if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL )
438 uiRetention = IVAL( regval_data_p( val ), 0 );
440 if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL )
441 uiMaxSize = IVAL( regval_data_p( val ), 0 );
443 regkey_close_internal( keyinfo );
445 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
446 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
448 return True;
451 /********************************************************************
452 ********************************************************************/
454 static Eventlog_entry *read_package_entry( prs_struct * ps,
455 EVENTLOG_Q_READ_EVENTLOG * q_u,
456 EVENTLOG_R_READ_EVENTLOG * r_u,
457 Eventlog_entry * entry )
459 uint8 *offset;
460 Eventlog_entry *ee_new = NULL;
462 ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
463 if ( ee_new == NULL ) {
464 return NULL;
467 entry->data_record.sid_padding =
468 ( ( 4 -
469 ( ( entry->data_record.source_name_len +
470 entry->data_record.computer_name_len ) % 4 ) ) % 4 );
471 entry->data_record.data_padding =
472 ( 4 -
473 ( ( entry->data_record.strings_len +
474 entry->data_record.user_data_len ) % 4 ) ) % 4;
475 entry->record.length = sizeof( Eventlog_record );
476 entry->record.length += entry->data_record.source_name_len;
477 entry->record.length += entry->data_record.computer_name_len;
478 if ( entry->record.user_sid_length == 0 ) {
479 /* Should not pad to a DWORD boundary for writing out the sid if there is
480 no SID, so just propagate the padding to pad the data */
481 entry->data_record.data_padding +=
482 entry->data_record.sid_padding;
483 entry->data_record.sid_padding = 0;
485 DEBUG( 10,
486 ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
487 DEBUG( 10,
488 ( "data_padding is [%d].\n",
489 entry->data_record.data_padding ) );
491 entry->record.length += entry->data_record.sid_padding;
492 entry->record.length += entry->record.user_sid_length;
493 entry->record.length += entry->data_record.strings_len;
494 entry->record.length += entry->data_record.user_data_len;
495 entry->record.length += entry->data_record.data_padding;
496 /* need another copy of length at the end of the data */
497 entry->record.length += sizeof( entry->record.length );
498 DEBUG( 10,
499 ( "entry->record.length is [%d].\n", entry->record.length ) );
500 entry->data =
501 PRS_ALLOC_MEM( ps, uint8,
502 entry->record.length -
503 sizeof( Eventlog_record ) -
504 sizeof( entry->record.length ) );
505 if ( entry->data == NULL ) {
506 return NULL;
508 offset = entry->data;
509 memcpy( offset, &( entry->data_record.source_name ),
510 entry->data_record.source_name_len );
511 offset += entry->data_record.source_name_len;
512 memcpy( offset, &( entry->data_record.computer_name ),
513 entry->data_record.computer_name_len );
514 offset += entry->data_record.computer_name_len;
515 /* SID needs to be DWORD-aligned */
516 offset += entry->data_record.sid_padding;
517 entry->record.user_sid_offset =
518 sizeof( Eventlog_record ) + ( offset - entry->data );
519 memcpy( offset, &( entry->data_record.sid ),
520 entry->record.user_sid_length );
521 offset += entry->record.user_sid_length;
522 /* Now do the strings */
523 entry->record.string_offset =
524 sizeof( Eventlog_record ) + ( offset - entry->data );
525 memcpy( offset, &( entry->data_record.strings ),
526 entry->data_record.strings_len );
527 offset += entry->data_record.strings_len;
528 /* Now do the data */
529 entry->record.data_length = entry->data_record.user_data_len;
530 entry->record.data_offset =
531 sizeof( Eventlog_record ) + ( offset - entry->data );
532 memcpy( offset, &( entry->data_record.user_data ),
533 entry->data_record.user_data_len );
534 offset += entry->data_record.user_data_len;
536 memcpy( &( ee_new->record ), &entry->record,
537 sizeof( Eventlog_record ) );
538 memcpy( &( ee_new->data_record ), &entry->data_record,
539 sizeof( Eventlog_data_record ) );
540 ee_new->data = entry->data;
542 return ee_new;
545 /********************************************************************
546 ********************************************************************/
548 static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
549 Eventlog_entry * ee_new )
551 Eventlog_entry *insert_point;
553 insert_point = r_u->entry;
555 if ( NULL == insert_point ) {
556 r_u->entry = ee_new;
557 ee_new->next = NULL;
558 } else {
559 while ( ( NULL != insert_point->next ) ) {
560 insert_point = insert_point->next;
562 ee_new->next = NULL;
563 insert_point->next = ee_new;
565 r_u->num_records++;
566 r_u->num_bytes_in_resp += ee_new->record.length;
568 return True;
571 /********************************************************************
572 ********************************************************************/
574 NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
575 EVENTLOG_Q_OPEN_EVENTLOG * q_u,
576 EVENTLOG_R_OPEN_EVENTLOG * r_u )
578 fstring servername, logname;
579 EVENTLOG_INFO *info;
580 NTSTATUS result;
582 fstrcpy( servername, "" );
583 if ( q_u->servername.string ) {
584 rpcstr_pull( servername, q_u->servername.string->buffer,
585 sizeof( servername ),
586 q_u->servername.string->uni_str_len * 2, 0 );
589 fstrcpy( logname, "" );
590 if ( q_u->logname.string ) {
591 rpcstr_pull( logname, q_u->logname.string->buffer,
592 sizeof( logname ),
593 q_u->logname.string->uni_str_len * 2, 0 );
596 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
597 servername, logname ));
599 /* according to MSDN, if the logfile cannot be found, we should
600 default to the "Application" log */
602 if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) )
603 return result;
605 if ( !(info = find_eventlog_info_by_hnd( p, &r_u->handle )) ) {
606 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
607 logname ));
608 elog_close( p, &r_u->handle );
609 return NT_STATUS_INVALID_HANDLE;
612 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
614 sync_eventlog_params( info );
615 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
617 return NT_STATUS_OK;
620 /********************************************************************
621 This call still needs some work
622 ********************************************************************/
624 NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
625 EVENTLOG_Q_CLEAR_EVENTLOG * q_u,
626 EVENTLOG_R_CLEAR_EVENTLOG * r_u )
628 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
629 pstring backup_file_name;
631 if ( !info )
632 return NT_STATUS_INVALID_HANDLE;
634 pstrcpy( backup_file_name, "" );
635 if ( q_u->backupfile.string ) {
636 rpcstr_pull( backup_file_name, q_u->backupfile.string->buffer,
637 sizeof( backup_file_name ),
638 q_u->backupfile.string->uni_str_len * 2, 0 );
640 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
641 "file name for log [%s].",
642 backup_file_name, info->logname ) );
645 /* check for WRITE access to the file */
647 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
648 return NT_STATUS_ACCESS_DENIED;
650 /* Force a close and reopen */
652 elog_close_tdb( info->etdb, True );
653 become_root();
654 info->etdb = elog_open_tdb( info->logname, True );
655 unbecome_root();
657 if ( !info->etdb )
658 return NT_STATUS_ACCESS_DENIED;
660 return NT_STATUS_OK;
663 /********************************************************************
664 ********************************************************************/
666 NTSTATUS _eventlog_close_eventlog( pipes_struct * p,
667 EVENTLOG_Q_CLOSE_EVENTLOG * q_u,
668 EVENTLOG_R_CLOSE_EVENTLOG * r_u )
670 return elog_close( p, &q_u->handle );
673 /********************************************************************
674 ********************************************************************/
676 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
677 EVENTLOG_Q_READ_EVENTLOG * q_u,
678 EVENTLOG_R_READ_EVENTLOG * r_u )
680 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
681 Eventlog_entry entry, *ee_new;
682 uint32 num_records_read = 0;
683 prs_struct *ps;
684 int bytes_left, record_number;
685 uint32 elog_read_type, elog_read_dir;
687 if (info == NULL) {
688 return NT_STATUS_INVALID_HANDLE;
691 info->flags = q_u->flags;
692 ps = &p->out_data.rdata;
694 bytes_left = q_u->max_read_size;
696 if ( !info->etdb )
697 return NT_STATUS_ACCESS_DENIED;
699 /* check for valid flags. Can't use the sequential and seek flags together */
701 elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
702 elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
704 if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
705 || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
707 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
708 return NT_STATUS_INVALID_PARAMETER;
711 /* a sequential read should ignore the offset */
713 if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
714 record_number = info->current_record;
715 else
716 record_number = q_u->offset;
718 while ( bytes_left > 0 ) {
720 /* assume that when the record fetch fails, that we are done */
722 if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) )
723 break;
725 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
727 /* Now see if there is enough room to add */
729 if ( !(ee_new = read_package_entry( ps, q_u, r_u,&entry )) )
730 return NT_STATUS_NO_MEMORY;
732 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
733 r_u->bytes_in_next_record = ee_new->record.length;
735 /* response would be too big to fit in client-size buffer */
737 bytes_left = 0;
738 break;
741 add_record_to_resp( r_u, ee_new );
742 bytes_left -= ee_new->record.length;
743 ZERO_STRUCT( entry );
744 num_records_read = r_u->num_records - num_records_read;
746 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
747 "of [%d] records using [%d] bytes out of a max of [%d].\n",
748 num_records_read, r_u->num_records,
749 r_u->num_bytes_in_resp,
750 q_u->max_read_size ) );
752 if ( info->flags & EVENTLOG_FORWARDS_READ )
753 record_number++;
754 else
755 record_number--;
757 /* update the eventlog record pointer */
759 info->current_record = record_number;
762 /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
763 say when there are no more records */
765 return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
768 /********************************************************************
769 ********************************************************************/
771 NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p,
772 EVENTLOG_Q_GET_OLDEST_ENTRY * q_u,
773 EVENTLOG_R_GET_OLDEST_ENTRY * r_u )
775 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
777 if (info == NULL) {
778 return NT_STATUS_INVALID_HANDLE;
781 if ( !( get_oldest_entry_hook( info ) ) )
782 return NT_STATUS_ACCESS_DENIED;
784 r_u->oldest_entry = info->oldest_entry;
786 return NT_STATUS_OK;
789 /********************************************************************
790 ********************************************************************/
792 NTSTATUS _eventlog_get_num_records( pipes_struct * p,
793 EVENTLOG_Q_GET_NUM_RECORDS * q_u,
794 EVENTLOG_R_GET_NUM_RECORDS * r_u )
796 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
798 if (info == NULL) {
799 return NT_STATUS_INVALID_HANDLE;
802 if ( !( get_num_records_hook( info ) ) )
803 return NT_STATUS_ACCESS_DENIED;
805 r_u->num_records = info->num_records;
807 return NT_STATUS_OK;