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 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 retrieve 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
);
414 wresult
= regkey_open_internal(
415 NULL
, &keyinfo
, path
, get_root_nt_token(), REG_KEY_READ
);
417 if ( !W_ERROR_IS_OK( wresult
) ) {
419 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
420 path
, dos_errstr( wresult
) ) );
424 if ( !( values
= TALLOC_ZERO_P( keyinfo
, REGVAL_CTR
) ) ) {
425 TALLOC_FREE( keyinfo
);
426 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
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
);
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
)
455 Eventlog_entry
*ee_new
= NULL
;
457 ee_new
= PRS_ALLOC_MEM( ps
, Eventlog_entry
, 1 );
458 if ( ee_new
== NULL
) {
462 entry
->data_record
.sid_padding
=
464 ( ( entry
->data_record
.source_name_len
+
465 entry
->data_record
.computer_name_len
) % 4 ) ) % 4 );
466 entry
->data_record
.data_padding
=
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;
481 ( "sid_padding is [%d].\n", entry
->data_record
.sid_padding
) );
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
);
494 ( "entry->record.length is [%d].\n", entry
->record
.length
) );
496 PRS_ALLOC_MEM( ps
, uint8
,
497 entry
->record
.length
-
498 sizeof( Eventlog_record
) -
499 sizeof( entry
->record
.length
) );
500 if ( entry
->data
== 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
;
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
) {
554 while ( ( NULL
!= insert_point
->next
) ) {
555 insert_point
= insert_point
->next
;
558 insert_point
->next
= ee_new
;
561 r_u
->num_bytes_in_resp
+= ee_new
->record
.length
;
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
;
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
,
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
)) )
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",
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
) );
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
;
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
);
649 info
->etdb
= elog_open_tdb( info
->logname
, True
);
653 return NT_STATUS_ACCESS_DENIED
;
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;
679 int bytes_left
, record_number
;
680 uint32 elog_read_type
, elog_read_dir
;
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
;
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
;
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
) )
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 */
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
)
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
);
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
;
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
);
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
;