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();
126 for ( i
=0; elogs
[i
]; i
++ ) {
127 if ( strequal( name
, elogs
[i
] ) )
134 /********************************************************************
135 ********************************************************************/
137 static BOOL
get_num_records_hook( EVENTLOG_INFO
* info
)
143 DEBUG( 10, ( "No open tdb for %s\n", info
->logname
) );
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
);
155 ( "Oldest Record %d; Next Record %d\n", oldest_record
,
158 info
->num_records
= ( next_record
- oldest_record
);
159 info
->oldest_entry
= oldest_record
;
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
)
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 */
196 elog
->etdb
= elog_open_tdb( elog
->logname
, False
);
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
) ) {
212 return NT_STATUS_ACCESS_DENIED
;
216 elog
->etdb
= elog_open_tdb( elog
->logname
, False
);
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
);
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
;
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
;
266 /*******************************************************************
267 *******************************************************************/
269 static int elog_size( EVENTLOG_INFO
*info
)
271 if ( !info
|| !info
->etdb
) {
272 DEBUG(0,("elog_size: Invalid info* structure!\n"));
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
)
293 pstring
*wpsource
, *wpcomputer
, *wpsid
, *wpstrs
, *puserdata
;
295 key
.dsize
= sizeof( int32
);
298 key
.dptr
= ( char * ) &srecno
;
300 ret
= tdb_fetch( tdb
, key
);
302 if ( ret
.dsize
== 0 ) {
304 ( "Can't find a record for the key, record %d\n",
309 len
= tdb_unpack( ret
.dptr
, ret
.dsize
, "d", &reclen
);
311 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno
, len
) );
316 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
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
);
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' */
348 memcpy( ee
->data_record
.computer_name
, wpcomputer
,
349 ee
->data_record
.computer_name_len
);
351 memcpy( ee
->data_record
.source_name
, wpsource
,
352 ee
->data_record
.source_name_len
);
355 memcpy( ee
->data_record
.sid
, wpsid
,
356 ee
->record
.user_sid_length
);
358 memcpy( ee
->data_record
.strings
, wpstrs
,
359 ee
->data_record
.strings_len
);
361 /* note that userdata is a pstring */
363 memcpy( ee
->data_record
.user_data
, puserdata
,
364 ee
->data_record
.user_data_len
);
366 SAFE_FREE( wpcomputer
);
367 SAFE_FREE( wpsource
);
370 SAFE_FREE( puserdata
);
372 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len
) );
374 ( "get_eventlog_record: computer_name %d is ",
375 ee
->data_record
.computer_name_len
) );
376 SAFE_FREE( ret
.dptr
);
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
)
390 REGISTRY_KEY
*keyinfo
;
394 char *elogname
= info
->logname
;
396 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname
) );
399 DEBUG( 4, ( "No open tdb! (%s)\n", info
->logname
) );
402 /* set resonable defaults. 512Kb on size and 1 week on time */
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
412 pstr_sprintf( path
, "%s/%s", KEY_EVENTLOG
, elogname
);
415 regkey_open_internal( &keyinfo
, path
, get_root_nt_token( ),
418 if ( !W_ERROR_IS_OK( wresult
) ) {
420 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
421 path
, dos_errstr( wresult
) ) );
425 if ( !( values
= TALLOC_ZERO_P( keyinfo
, REGVAL_CTR
) ) ) {
426 TALLOC_FREE( keyinfo
);
427 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
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
);
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
)
456 Eventlog_entry
*ee_new
= NULL
;
458 ee_new
= PRS_ALLOC_MEM( ps
, Eventlog_entry
, 1 );
459 if ( ee_new
== NULL
) {
463 entry
->data_record
.sid_padding
=
465 ( ( entry
->data_record
.source_name_len
+
466 entry
->data_record
.computer_name_len
) % 4 ) ) % 4 );
467 entry
->data_record
.data_padding
=
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;
482 ( "sid_padding is [%d].\n", entry
->data_record
.sid_padding
) );
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
);
495 ( "entry->record.length is [%d].\n", entry
->record
.length
) );
497 PRS_ALLOC_MEM( ps
, uint8
,
498 entry
->record
.length
-
499 sizeof( Eventlog_record
) -
500 sizeof( entry
->record
.length
) );
501 if ( entry
->data
== 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
;
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
) {
555 while ( ( NULL
!= insert_point
->next
) ) {
556 insert_point
= insert_point
->next
;
559 insert_point
->next
= ee_new
;
562 r_u
->num_bytes_in_resp
+= ee_new
->record
.length
;
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
;
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
,
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
)) )
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",
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
) );
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
;
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
);
650 info
->etdb
= elog_open_tdb( info
->logname
, True
);
654 return NT_STATUS_ACCESS_DENIED
;
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;
680 int bytes_left
, record_number
;
681 uint32 elog_read_type
, elog_read_dir
;
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
;
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
;
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
) )
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 */
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
)
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
);
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
;
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
);
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
;