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.
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.
26 #define DBGC_CLASS DBGC_RPC_SRV
31 uint32 current_record
;
35 uint32 access_granted
;
38 /********************************************************************
39 ********************************************************************/
41 static void free_eventlog_info( void *ptr
)
43 EVENTLOG_INFO
*elog
= (EVENTLOG_INFO
*)ptr
;
46 elog_close_tdb( elog
->etdb
, False
);
51 /********************************************************************
52 ********************************************************************/
54 static EVENTLOG_INFO
*find_eventlog_info_by_hnd( pipes_struct
* p
,
59 if ( !find_policy_by_hnd( p
, handle
, (void **)(void *)&info
) ) {
61 ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
68 /********************************************************************
69 ********************************************************************/
71 static BOOL
elog_check_access( EVENTLOG_INFO
*info
, NT_USER_TOKEN
*token
)
73 char *tdbname
= elog_tdbname( info
->logname
);
81 /* get the security descriptor for the file */
83 sec_desc
= get_nt_acl_no_snum( info
, tdbname
);
87 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
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
);
105 TALLOC_FREE( sec_desc
);
108 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
109 nt_errstr( ntstatus
)));
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
)
124 const char **elogs
= lp_eventlog_list();
130 for ( i
=0; elogs
[i
]; i
++ ) {
131 if ( strequal( name
, elogs
[i
] ) )
138 /********************************************************************
139 ********************************************************************/
141 static BOOL
get_num_records_hook( EVENTLOG_INFO
* info
)
147 DEBUG( 10, ( "No open tdb for %s\n", info
->logname
) );
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
);
159 ( "Oldest Record %d; Next Record %d\n", oldest_record
,
162 info
->num_records
= ( next_record
- oldest_record
);
163 info
->oldest_entry
= oldest_record
;
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
)
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 */
200 elog
->etdb
= elog_open_tdb( elog
->logname
, False
);
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
) ) {
216 return NT_STATUS_ACCESS_DENIED
;
220 elog
->etdb
= elog_open_tdb( elog
->logname
, False
);
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
);
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
;
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
;
270 /*******************************************************************
271 *******************************************************************/
273 static int elog_size( EVENTLOG_INFO
*info
)
275 if ( !info
|| !info
->etdb
) {
276 DEBUG(0,("elog_size: Invalid info* structure!\n"));
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
)
297 pstring
*wpsource
, *wpcomputer
, *wpsid
, *wpstrs
, *puserdata
;
299 key
.dsize
= sizeof( int32
);
302 key
.dptr
= ( char * ) &srecno
;
304 ret
= tdb_fetch( tdb
, key
);
306 if ( ret
.dsize
== 0 ) {
308 ( "Can't find a record for the key, record %d\n",
313 len
= tdb_unpack( ret
.dptr
, ret
.dsize
, "d", &reclen
);
315 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno
, len
) );
320 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
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
);
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' */
352 memcpy( ee
->data_record
.computer_name
, wpcomputer
,
353 ee
->data_record
.computer_name_len
);
355 memcpy( ee
->data_record
.source_name
, wpsource
,
356 ee
->data_record
.source_name_len
);
359 memcpy( ee
->data_record
.sid
, wpsid
,
360 ee
->record
.user_sid_length
);
362 memcpy( ee
->data_record
.strings
, wpstrs
,
363 ee
->data_record
.strings_len
);
365 /* note that userdata is a pstring */
367 memcpy( ee
->data_record
.user_data
, puserdata
,
368 ee
->data_record
.user_data_len
);
370 SAFE_FREE( wpcomputer
);
371 SAFE_FREE( wpsource
);
374 SAFE_FREE( puserdata
);
376 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len
) );
378 ( "get_eventlog_record: computer_name %d is ",
379 ee
->data_record
.computer_name_len
) );
380 SAFE_FREE( ret
.dptr
);
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
)
394 REGISTRY_KEY
*keyinfo
;
398 char *elogname
= info
->logname
;
400 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname
) );
403 DEBUG( 4, ( "No open tdb! (%s)\n", info
->logname
) );
406 /* set resonable defaults. 512Kb on size and 1 week on time */
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
416 pstr_sprintf( path
, "%s/%s", KEY_EVENTLOG
, elogname
);
419 regkey_open_internal( &keyinfo
, path
, get_root_nt_token( ),
422 if ( !W_ERROR_IS_OK( wresult
) ) {
424 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
425 path
, dos_errstr( wresult
) ) );
429 if ( !( values
= TALLOC_ZERO_P( keyinfo
, REGVAL_CTR
) ) ) {
430 TALLOC_FREE( keyinfo
);
431 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
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
);
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
)
460 Eventlog_entry
*ee_new
= NULL
;
462 ee_new
= PRS_ALLOC_MEM( ps
, Eventlog_entry
, 1 );
463 if ( ee_new
== NULL
) {
467 entry
->data_record
.sid_padding
=
469 ( ( entry
->data_record
.source_name_len
+
470 entry
->data_record
.computer_name_len
) % 4 ) ) % 4 );
471 entry
->data_record
.data_padding
=
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;
486 ( "sid_padding is [%d].\n", entry
->data_record
.sid_padding
) );
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
);
499 ( "entry->record.length is [%d].\n", entry
->record
.length
) );
501 PRS_ALLOC_MEM( ps
, uint8
,
502 entry
->record
.length
-
503 sizeof( Eventlog_record
) -
504 sizeof( entry
->record
.length
) );
505 if ( entry
->data
== 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
;
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
) {
559 while ( ( NULL
!= insert_point
->next
) ) {
560 insert_point
= insert_point
->next
;
563 insert_point
->next
= ee_new
;
566 r_u
->num_bytes_in_resp
+= ee_new
->record
.length
;
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
;
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
,
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
)) )
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",
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
) );
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
;
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
);
654 info
->etdb
= elog_open_tdb( info
->logname
, True
);
658 return NT_STATUS_ACCESS_DENIED
;
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;
684 int bytes_left
, record_number
;
685 uint32 elog_read_type
, elog_read_dir
;
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
;
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
;
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
) )
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 */
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
)
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
);
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
;
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
);
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
;