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
34 uint32 access_granted
;
37 /********************************************************************
38 ********************************************************************/
40 static void free_eventlog_info( void *ptr
)
42 EVENTLOG_INFO
*elog
= (EVENTLOG_INFO
*)ptr
;
45 elog_close_tdb( elog
->tdb
);
50 /********************************************************************
51 ********************************************************************/
53 static EVENTLOG_INFO
*find_eventlog_info_by_hnd( pipes_struct
* p
,
58 if ( !find_policy_by_hnd( p
, handle
, ( void ** ) &info
) ) {
60 ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
67 /********************************************************************
68 ********************************************************************/
70 static BOOL
elog_check_access( EVENTLOG_INFO
*info
, NT_USER_TOKEN
*token
)
72 char *tdbname
= elog_tdbname( info
->logname
);
80 /* get the security descriptor for the file */
82 sec_desc
= get_nt_acl_no_snum( info
, tdbname
);
86 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
91 /* run the check, try for the max allowed */
93 ret
= se_access_check( sec_desc
, token
, MAXIMUM_ALLOWED_ACCESS
,
94 &info
->access_granted
, &ntstatus
);
97 TALLOC_FREE( sec_desc
);
100 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
101 nt_errstr( ntstatus
)));
105 /* we have to have READ permission for a successful open */
107 return ( info
->access_granted
& SA_RIGHT_FILE_READ_DATA
);
110 /********************************************************************
111 ********************************************************************/
113 static BOOL
elog_validate_logname( const char *name
)
116 const char **elogs
= lp_eventlog_list();
118 for ( i
=0; elogs
[i
]; i
++ ) {
119 if ( strequal( name
, elogs
[i
] ) )
126 /********************************************************************
127 ********************************************************************/
129 static WERROR
elog_open( pipes_struct
* p
, const char *logname
, POLICY_HND
*hnd
)
133 /* first thing is to validate the eventlog name */
135 if ( !elog_validate_logname( logname
) )
136 return WERR_OBJECT_PATH_INVALID
;
138 if ( !(elog
= TALLOC_ZERO_P( NULL
, EVENTLOG_INFO
)) )
141 elog
->logname
= talloc_strdup( elog
, logname
);
143 /* Open the tdb first (so that we can create any new tdbs if necessary).
144 We have to do this as root and then use an internal access check
145 on the file permissions since you can only have a tdb open once
146 in a single process */
149 elog
->tdb
= elog_open_tdb( elog
->logname
);
153 /* according to MSDN, if the logfile cannot be found, we should
154 default to the "Application" log */
156 if ( !strequal( logname
, ELOG_APPL
) ) {
158 TALLOC_FREE( elog
->logname
);
160 elog
->logname
= talloc_strdup( elog
, ELOG_APPL
);
162 /* do the access check */
163 if ( !elog_check_access( elog
, p
->pipe_user
.nt_user_token
) ) {
165 return WERR_ACCESS_DENIED
;
169 elog
->tdb
= elog_open_tdb( elog
->logname
);
175 return WERR_ACCESS_DENIED
; /* ??? */
179 /* now do the access check. Close the tdb if we fail here */
181 if ( !elog_check_access( elog
, p
->pipe_user
.nt_user_token
) ) {
182 elog_close_tdb( elog
->tdb
);
184 return WERR_ACCESS_DENIED
;
187 /* create the policy handle */
189 if ( !create_policy_hnd
190 ( p
, hnd
, free_eventlog_info
, ( void * ) elog
) ) {
191 free_eventlog_info( elog
);
198 /********************************************************************
199 ********************************************************************/
201 static WERROR
elog_close( pipes_struct
*p
, POLICY_HND
*hnd
)
203 if ( !( close_policy_hnd( p
, hnd
) ) ) {
210 /*******************************************************************
211 *******************************************************************/
213 static int elog_size( EVENTLOG_INFO
*info
)
215 if ( !info
|| !info
->tdb
) {
216 DEBUG(0,("elog_size: Invalid info* structure!\n"));
220 return elog_tdb_size( info
->tdb
, NULL
, NULL
);
223 /********************************************************************
224 For the given tdb, get the next eventlog record into the passed
225 Eventlog_entry. returns NULL if it can't get the record for some reason.
226 ********************************************************************/
228 Eventlog_entry
*get_eventlog_record( prs_struct
* ps
, TDB_CONTEXT
* tdb
,
229 int recno
, Eventlog_entry
* ee
)
238 pstring
*wpsource
, *wpcomputer
, *wpsid
, *wpstrs
, *puserdata
;
240 key
.dsize
= sizeof( int32
);
244 key
.dptr
= ( char * ) &srecno
;
246 ret
= tdb_fetch( tdb
, key
);
248 if ( ret
.dsize
== 0 ) {
250 ( "Can't find a record for the key, record %d\n",
255 len
= tdb_unpack( ret
.dptr
, ret
.dsize
, "d", &reclen
);
257 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno
, len
) );
262 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
267 len
= tdb_unpack( ret
.dptr
, ret
.dsize
, "ddddddwwwwddddddBBdBBBd",
268 &ee
->record
.length
, &ee
->record
.reserved1
,
269 &ee
->record
.record_number
,
270 &ee
->record
.time_generated
,
271 &ee
->record
.time_written
, &ee
->record
.event_id
,
272 &ee
->record
.event_type
, &ee
->record
.num_strings
,
273 &ee
->record
.event_category
, &ee
->record
.reserved2
,
274 &ee
->record
.closing_record_number
,
275 &ee
->record
.string_offset
,
276 &ee
->record
.user_sid_length
,
277 &ee
->record
.user_sid_offset
,
278 &ee
->record
.data_length
, &ee
->record
.data_offset
,
279 &ee
->data_record
.source_name_len
, &wpsource
,
280 &ee
->data_record
.computer_name_len
, &wpcomputer
,
281 &ee
->data_record
.sid_padding
,
282 &ee
->record
.user_sid_length
, &wpsid
,
283 &ee
->data_record
.strings_len
, &wpstrs
,
284 &ee
->data_record
.user_data_len
, &puserdata
,
285 &ee
->data_record
.data_padding
);
287 ( "Read record %d, len in tdb was %d\n",
288 ee
->record
.record_number
, len
) );
290 /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
291 into it's 2nd argment for 'B' */
294 memcpy( ee
->data_record
.computer_name
, wpcomputer
,
295 ee
->data_record
.computer_name_len
);
297 memcpy( ee
->data_record
.source_name
, wpsource
,
298 ee
->data_record
.source_name_len
);
301 memcpy( ee
->data_record
.sid
, wpsid
,
302 ee
->record
.user_sid_length
);
304 memcpy( ee
->data_record
.strings
, wpstrs
,
305 ee
->data_record
.strings_len
);
307 /* note that userdata is a pstring */
309 memcpy( ee
->data_record
.user_data
, puserdata
,
310 ee
->data_record
.user_data_len
);
312 SAFE_FREE( wpcomputer
);
313 SAFE_FREE( wpsource
);
316 SAFE_FREE( puserdata
);
318 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len
) );
320 ( "get_eventlog_record: computer_name %d is ",
321 ee
->data_record
.computer_name_len
) );
322 SAFE_FREE( ret
.dptr
);
326 /********************************************************************
327 note that this can only be called AFTER the table is constructed,
328 since it uses the table to find the tdb handle
329 ********************************************************************/
331 static BOOL
sync_eventlog_params( EVENTLOG_INFO
*info
)
336 REGISTRY_KEY
*keyinfo
;
340 char *elogname
= info
->logname
;
342 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname
) );
345 DEBUG( 4, ( "No open tdb! (%s)\n", info
->logname
) );
348 /* set resonable defaults. 512Kb on size and 1 week on time */
351 uiRetention
= 604800;
353 /* the general idea is to internally open the registry
354 key and retreive the values. That way we can continue
355 to use the same fetch/store api that we use in
358 pstr_sprintf( path
, "%s/%s", KEY_EVENTLOG
, elogname
);
361 regkey_open_internal( &keyinfo
, path
, get_root_nt_token( ),
364 if ( !W_ERROR_IS_OK( wresult
) ) {
366 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
367 path
, dos_errstr( wresult
) ) );
371 if ( !( values
= TALLOC_ZERO_P( keyinfo
, REGVAL_CTR
) ) ) {
372 TALLOC_FREE( keyinfo
);
373 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
377 fetch_reg_values( keyinfo
, values
);
379 if ( ( val
= regval_ctr_getvalue( values
, "Retention" ) ) != NULL
)
380 uiRetention
= IVAL( regval_data_p( val
), 0 );
382 if ( ( val
= regval_ctr_getvalue( values
, "MaxSize" ) ) != NULL
)
383 uiMaxSize
= IVAL( regval_data_p( val
), 0 );
385 regkey_close_internal( keyinfo
);
387 tdb_store_int32( info
->tdb
, EVT_MAXSIZE
, uiMaxSize
);
388 tdb_store_int32( info
->tdb
, EVT_RETENTION
, uiRetention
);
393 /********************************************************************
394 ********************************************************************/
396 static BOOL
get_num_records_hook( EVENTLOG_INFO
* info
)
402 DEBUG( 10, ( "No open tdb for %s\n", info
->logname
) );
406 /* lock the tdb since we have to get 2 records */
408 tdb_lock_bystring( info
->tdb
, EVT_NEXT_RECORD
, 1 );
409 next_record
= tdb_fetch_int32( info
->tdb
, EVT_NEXT_RECORD
);
410 oldest_record
= tdb_fetch_int32( info
->tdb
, EVT_OLDEST_ENTRY
);
411 tdb_unlock_bystring( info
->tdb
, EVT_NEXT_RECORD
);
414 ( "Oldest Record %d; Next Record %d\n", oldest_record
,
417 info
->num_records
= ( next_record
- oldest_record
);
418 info
->oldest_entry
= oldest_record
;
423 /********************************************************************
424 ********************************************************************/
426 static BOOL
get_oldest_entry_hook( EVENTLOG_INFO
* info
)
429 /* it's the same thing */
430 return get_num_records_hook( info
);
433 /********************************************************************
434 ********************************************************************/
436 static Eventlog_entry
*read_package_entry( prs_struct
* ps
,
437 EVENTLOG_Q_READ_EVENTLOG
* q_u
,
438 EVENTLOG_R_READ_EVENTLOG
* r_u
,
439 Eventlog_entry
* entry
)
442 Eventlog_entry
*ee_new
= NULL
;
444 ee_new
= PRS_ALLOC_MEM( ps
, Eventlog_entry
, 1 );
445 if ( ee_new
== NULL
) {
449 entry
->data_record
.sid_padding
=
451 ( ( entry
->data_record
.source_name_len
+
452 entry
->data_record
.computer_name_len
) % 4 ) ) % 4 );
453 entry
->data_record
.data_padding
=
455 ( ( entry
->data_record
.strings_len
+
456 entry
->data_record
.user_data_len
) % 4 ) ) % 4;
457 entry
->record
.length
= sizeof( Eventlog_record
);
458 entry
->record
.length
+= entry
->data_record
.source_name_len
;
459 entry
->record
.length
+= entry
->data_record
.computer_name_len
;
460 if ( entry
->record
.user_sid_length
== 0 ) {
461 /* Should not pad to a DWORD boundary for writing out the sid if there is
462 no SID, so just propagate the padding to pad the data */
463 entry
->data_record
.data_padding
+=
464 entry
->data_record
.sid_padding
;
465 entry
->data_record
.sid_padding
= 0;
468 ( "sid_padding is [%d].\n", entry
->data_record
.sid_padding
) );
470 ( "data_padding is [%d].\n",
471 entry
->data_record
.data_padding
) );
473 entry
->record
.length
+= entry
->data_record
.sid_padding
;
474 entry
->record
.length
+= entry
->record
.user_sid_length
;
475 entry
->record
.length
+= entry
->data_record
.strings_len
;
476 entry
->record
.length
+= entry
->data_record
.user_data_len
;
477 entry
->record
.length
+= entry
->data_record
.data_padding
;
478 /* need another copy of length at the end of the data */
479 entry
->record
.length
+= sizeof( entry
->record
.length
);
481 ( "entry->record.length is [%d].\n", entry
->record
.length
) );
483 PRS_ALLOC_MEM( ps
, uint8
,
484 entry
->record
.length
-
485 sizeof( Eventlog_record
) -
486 sizeof( entry
->record
.length
) );
487 if ( entry
->data
== NULL
) {
490 offset
= entry
->data
;
491 memcpy( offset
, &( entry
->data_record
.source_name
),
492 entry
->data_record
.source_name_len
);
493 offset
+= entry
->data_record
.source_name_len
;
494 memcpy( offset
, &( entry
->data_record
.computer_name
),
495 entry
->data_record
.computer_name_len
);
496 offset
+= entry
->data_record
.computer_name_len
;
497 /* SID needs to be DWORD-aligned */
498 offset
+= entry
->data_record
.sid_padding
;
499 entry
->record
.user_sid_offset
=
500 sizeof( Eventlog_record
) + ( offset
- entry
->data
);
501 memcpy( offset
, &( entry
->data_record
.sid
),
502 entry
->record
.user_sid_length
);
503 offset
+= entry
->record
.user_sid_length
;
504 /* Now do the strings */
505 entry
->record
.string_offset
=
506 sizeof( Eventlog_record
) + ( offset
- entry
->data
);
507 memcpy( offset
, &( entry
->data_record
.strings
),
508 entry
->data_record
.strings_len
);
509 offset
+= entry
->data_record
.strings_len
;
510 /* Now do the data */
511 entry
->record
.data_length
= entry
->data_record
.user_data_len
;
512 entry
->record
.data_offset
=
513 sizeof( Eventlog_record
) + ( offset
- entry
->data
);
514 memcpy( offset
, &( entry
->data_record
.user_data
),
515 entry
->data_record
.user_data_len
);
516 offset
+= entry
->data_record
.user_data_len
;
518 memcpy( &( ee_new
->record
), &entry
->record
,
519 sizeof( Eventlog_record
) );
520 memcpy( &( ee_new
->data_record
), &entry
->data_record
,
521 sizeof( Eventlog_data_record
) );
522 ee_new
->data
= entry
->data
;
527 /********************************************************************
528 ********************************************************************/
530 static BOOL
add_record_to_resp( EVENTLOG_R_READ_EVENTLOG
* r_u
,
531 Eventlog_entry
* ee_new
)
533 Eventlog_entry
*insert_point
;
535 insert_point
= r_u
->entry
;
537 if ( NULL
== insert_point
) {
541 while ( ( NULL
!= insert_point
->next
) ) {
542 insert_point
= insert_point
->next
;
545 insert_point
->next
= ee_new
;
548 r_u
->num_bytes_in_resp
+= ee_new
->record
.length
;
553 /********************************************************************
554 ********************************************************************/
556 WERROR
_eventlog_open_eventlog( pipes_struct
* p
,
557 EVENTLOG_Q_OPEN_EVENTLOG
* q_u
,
558 EVENTLOG_R_OPEN_EVENTLOG
* r_u
)
560 fstring servername
, logname
;
564 fstrcpy( servername
, "" );
565 if ( q_u
->servername
.string
) {
566 rpcstr_pull( servername
, q_u
->servername
.string
->buffer
,
567 sizeof( servername
),
568 q_u
->servername
.string
->uni_str_len
* 2, 0 );
571 fstrcpy( logname
, "" );
572 if ( q_u
->logname
.string
) {
573 rpcstr_pull( logname
, q_u
->logname
.string
->buffer
,
575 q_u
->logname
.string
->uni_str_len
* 2, 0 );
578 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
579 servername
, logname
));
581 /* according to MSDN, if the logfile cannot be found, we should
582 default to the "Application" log */
584 if ( !W_ERROR_IS_OK( wresult
= elog_open( p
, logname
, &r_u
->handle
)) )
587 if ( !(info
= find_eventlog_info_by_hnd( p
, &r_u
->handle
)) ) {
588 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
590 elog_close( p
, &r_u
->handle
);
594 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info
)));
596 sync_eventlog_params( info
);
597 prune_eventlog( info
->tdb
);
602 /********************************************************************
603 This call still needs some work
604 ********************************************************************/
606 WERROR
_eventlog_clear_eventlog( pipes_struct
* p
,
607 EVENTLOG_Q_CLEAR_EVENTLOG
* q_u
,
608 EVENTLOG_R_CLEAR_EVENTLOG
* r_u
)
610 EVENTLOG_INFO
*info
= find_eventlog_info_by_hnd( p
, &q_u
->handle
);
611 pstring backup_file_name
;
616 pstrcpy( backup_file_name
, "" );
617 if ( q_u
->backupfile
.string
) {
618 rpcstr_pull( backup_file_name
, q_u
->backupfile
.string
->buffer
,
619 sizeof( backup_file_name
),
620 q_u
->backupfile
.string
->uni_str_len
* 2, 0 );
624 ( "_eventlog_clear_eventlog: Using [%s] as the backup file name for log [%s].",
625 backup_file_name
, info
->logname
) );
628 /* close the current one, reinit */
630 tdb_close( info
->tdb
);
632 if ( !(info
->tdb
= elog_init_tdb( ttdb
[i
].tdbfname
)) )
633 return WERR_ACCESS_DENIED
;
639 /********************************************************************
640 ********************************************************************/
642 WERROR
_eventlog_close_eventlog( pipes_struct
* p
,
643 EVENTLOG_Q_CLOSE_EVENTLOG
* q_u
,
644 EVENTLOG_R_CLOSE_EVENTLOG
* r_u
)
646 return elog_close( p
, &q_u
->handle
);
649 /********************************************************************
650 ********************************************************************/
652 WERROR
_eventlog_read_eventlog( pipes_struct
* p
,
653 EVENTLOG_Q_READ_EVENTLOG
* q_u
,
654 EVENTLOG_R_READ_EVENTLOG
* r_u
)
656 EVENTLOG_INFO
*info
= find_eventlog_info_by_hnd( p
, &q_u
->handle
);
657 Eventlog_entry entry
, *ee_new
;
659 uint32 num_records_read
= 0;
661 int bytes_left
, record_number
;
664 info
->flags
= q_u
->flags
;
665 ps
= &p
->out_data
.rdata
;
667 bytes_left
= q_u
->max_read_size
;
670 return WERR_EVENTLOG_FILE_CORRUPT
;
673 /* DEBUG(8,("Bytes left is %d\n",bytes_left)); */
675 record_number
= q_u
->offset
;
677 while ( bytes_left
> 0 ) {
678 if ( get_eventlog_record
679 ( ps
, tdb
, record_number
, &entry
) ) {
681 ( "Retrieved record %d\n", record_number
) );
683 /* Now see if there is enough room to add */
684 ee_new
= read_package_entry( ps
, q_u
, r_u
,&entry
);
688 if ( r_u
->num_bytes_in_resp
+ ee_new
->record
.length
>
689 q_u
->max_read_size
) {
690 r_u
->bytes_in_next_record
=
691 ee_new
->record
.length
;
693 /* response would be too big to fit in client-size buffer */
699 add_record_to_resp( r_u
, ee_new
);
700 bytes_left
-= ee_new
->record
.length
;
701 ZERO_STRUCT( entry
);
703 r_u
->num_records
- num_records_read
;
706 ( "_eventlog_read_eventlog: read [%d] records for a total of [%d] records using [%d] bytes out of a max of [%d].\n",
707 num_records_read
, r_u
->num_records
,
708 r_u
->num_bytes_in_resp
,
709 q_u
->max_read_size
) );
711 DEBUG( 8, ( "get_eventlog_record returned NULL\n" ) );
712 return WERR_NOMEM
; /* wrong error - but return one anyway */
716 if ( info
->flags
& EVENTLOG_FORWARDS_READ
)
725 /********************************************************************
726 ********************************************************************/
728 WERROR
_eventlog_get_oldest_entry( pipes_struct
* p
,
729 EVENTLOG_Q_GET_OLDEST_ENTRY
* q_u
,
730 EVENTLOG_R_GET_OLDEST_ENTRY
* r_u
)
732 EVENTLOG_INFO
*info
= find_eventlog_info_by_hnd( p
, &q_u
->handle
);
734 if ( !( get_oldest_entry_hook( info
) ) )
737 r_u
->oldest_entry
= info
->oldest_entry
;
742 /********************************************************************
743 ********************************************************************/
745 WERROR
_eventlog_get_num_records( pipes_struct
* p
,
746 EVENTLOG_Q_GET_NUM_RECORDS
* q_u
,
747 EVENTLOG_R_GET_NUM_RECORDS
* r_u
)
749 EVENTLOG_INFO
*info
= find_eventlog_info_by_hnd( p
, &q_u
->handle
);
751 if ( !( get_num_records_hook( info
) ) )
754 r_u
->num_records
= info
->num_records
;