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( 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 )
294 pstring *wpsource, *wpcomputer, *wpsid, *wpstrs, *puserdata;
296 key.dsize = sizeof( int32 );
300 key.dptr = ( char * ) &srecno;
302 ret = tdb_fetch( tdb, key );
304 if ( ret.dsize == 0 ) {
306 ( "Can't find a record for the key, record %d\n",
311 len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
313 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
318 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
323 len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
324 &ee->record.length, &ee->record.reserved1,
325 &ee->record.record_number,
326 &ee->record.time_generated,
327 &ee->record.time_written, &ee->record.event_id,
328 &ee->record.event_type, &ee->record.num_strings,
329 &ee->record.event_category, &ee->record.reserved2,
330 &ee->record.closing_record_number,
331 &ee->record.string_offset,
332 &ee->record.user_sid_length,
333 &ee->record.user_sid_offset,
334 &ee->record.data_length, &ee->record.data_offset,
335 &ee->data_record.source_name_len, &wpsource,
336 &ee->data_record.computer_name_len, &wpcomputer,
337 &ee->data_record.sid_padding,
338 &ee->record.user_sid_length, &wpsid,
339 &ee->data_record.strings_len, &wpstrs,
340 &ee->data_record.user_data_len, &puserdata,
341 &ee->data_record.data_padding );
343 ( "Read record %d, len in tdb was %d\n",
344 ee->record.record_number, len ) );
346 /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
347 into it's 2nd argment for 'B' */
350 memcpy( ee->data_record.computer_name, wpcomputer,
351 ee->data_record.computer_name_len );
353 memcpy( ee->data_record.source_name, wpsource,
354 ee->data_record.source_name_len );
357 memcpy( ee->data_record.sid, wpsid,
358 ee->record.user_sid_length );
360 memcpy( ee->data_record.strings, wpstrs,
361 ee->data_record.strings_len );
363 /* note that userdata is a pstring */
365 memcpy( ee->data_record.user_data, puserdata,
366 ee->data_record.user_data_len );
368 SAFE_FREE( wpcomputer );
369 SAFE_FREE( wpsource );
372 SAFE_FREE( puserdata );
374 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
376 ( "get_eventlog_record: computer_name %d is ",
377 ee->data_record.computer_name_len ) );
378 SAFE_FREE( ret.dptr );
382 /********************************************************************
383 note that this can only be called AFTER the table is constructed,
384 since it uses the table to find the tdb handle
385 ********************************************************************/
387 static BOOL sync_eventlog_params( EVENTLOG_INFO *info )
392 REGISTRY_KEY *keyinfo;
396 char *elogname = info->logname;
398 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
401 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
404 /* set resonable defaults. 512Kb on size and 1 week on time */
407 uiRetention = 604800;
409 /* the general idea is to internally open the registry
410 key and retreive the values. That way we can continue
411 to use the same fetch/store api that we use in
414 pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname );
417 regkey_open_internal( &keyinfo, path, get_root_nt_token( ),
420 if ( !W_ERROR_IS_OK( wresult ) ) {
422 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
423 path, dos_errstr( wresult ) ) );
427 if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) {
428 TALLOC_FREE( keyinfo );
429 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
433 fetch_reg_values( keyinfo, values );
435 if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL )
436 uiRetention = IVAL( regval_data_p( val ), 0 );
438 if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL )
439 uiMaxSize = IVAL( regval_data_p( val ), 0 );
441 regkey_close_internal( keyinfo );
443 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
444 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
449 /********************************************************************
450 ********************************************************************/
452 static Eventlog_entry *read_package_entry( prs_struct * ps,
453 EVENTLOG_Q_READ_EVENTLOG * q_u,
454 EVENTLOG_R_READ_EVENTLOG * r_u,
455 Eventlog_entry * entry )
458 Eventlog_entry *ee_new = NULL;
460 ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
461 if ( ee_new == NULL ) {
465 entry->data_record.sid_padding =
467 ( ( entry->data_record.source_name_len +
468 entry->data_record.computer_name_len ) % 4 ) ) % 4 );
469 entry->data_record.data_padding =
471 ( ( entry->data_record.strings_len +
472 entry->data_record.user_data_len ) % 4 ) ) % 4;
473 entry->record.length = sizeof( Eventlog_record );
474 entry->record.length += entry->data_record.source_name_len;
475 entry->record.length += entry->data_record.computer_name_len;
476 if ( entry->record.user_sid_length == 0 ) {
477 /* Should not pad to a DWORD boundary for writing out the sid if there is
478 no SID, so just propagate the padding to pad the data */
479 entry->data_record.data_padding +=
480 entry->data_record.sid_padding;
481 entry->data_record.sid_padding = 0;
484 ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
486 ( "data_padding is [%d].\n",
487 entry->data_record.data_padding ) );
489 entry->record.length += entry->data_record.sid_padding;
490 entry->record.length += entry->record.user_sid_length;
491 entry->record.length += entry->data_record.strings_len;
492 entry->record.length += entry->data_record.user_data_len;
493 entry->record.length += entry->data_record.data_padding;
494 /* need another copy of length at the end of the data */
495 entry->record.length += sizeof( entry->record.length );
497 ( "entry->record.length is [%d].\n", entry->record.length ) );
499 PRS_ALLOC_MEM( ps, uint8,
500 entry->record.length -
501 sizeof( Eventlog_record ) -
502 sizeof( entry->record.length ) );
503 if ( entry->data == NULL ) {
506 offset = entry->data;
507 memcpy( offset, &( entry->data_record.source_name ),
508 entry->data_record.source_name_len );
509 offset += entry->data_record.source_name_len;
510 memcpy( offset, &( entry->data_record.computer_name ),
511 entry->data_record.computer_name_len );
512 offset += entry->data_record.computer_name_len;
513 /* SID needs to be DWORD-aligned */
514 offset += entry->data_record.sid_padding;
515 entry->record.user_sid_offset =
516 sizeof( Eventlog_record ) + ( offset - entry->data );
517 memcpy( offset, &( entry->data_record.sid ),
518 entry->record.user_sid_length );
519 offset += entry->record.user_sid_length;
520 /* Now do the strings */
521 entry->record.string_offset =
522 sizeof( Eventlog_record ) + ( offset - entry->data );
523 memcpy( offset, &( entry->data_record.strings ),
524 entry->data_record.strings_len );
525 offset += entry->data_record.strings_len;
526 /* Now do the data */
527 entry->record.data_length = entry->data_record.user_data_len;
528 entry->record.data_offset =
529 sizeof( Eventlog_record ) + ( offset - entry->data );
530 memcpy( offset, &( entry->data_record.user_data ),
531 entry->data_record.user_data_len );
532 offset += entry->data_record.user_data_len;
534 memcpy( &( ee_new->record ), &entry->record,
535 sizeof( Eventlog_record ) );
536 memcpy( &( ee_new->data_record ), &entry->data_record,
537 sizeof( Eventlog_data_record ) );
538 ee_new->data = entry->data;
543 /********************************************************************
544 ********************************************************************/
546 static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
547 Eventlog_entry * ee_new )
549 Eventlog_entry *insert_point;
551 insert_point = r_u->entry;
553 if ( NULL == insert_point ) {
557 while ( ( NULL != insert_point->next ) ) {
558 insert_point = insert_point->next;
561 insert_point->next = ee_new;
564 r_u->num_bytes_in_resp += ee_new->record.length;
569 /********************************************************************
570 ********************************************************************/
572 NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
573 EVENTLOG_Q_OPEN_EVENTLOG * q_u,
574 EVENTLOG_R_OPEN_EVENTLOG * r_u )
576 fstring servername, logname;
580 fstrcpy( servername, "" );
581 if ( q_u->servername.string ) {
582 rpcstr_pull( servername, q_u->servername.string->buffer,
583 sizeof( servername ),
584 q_u->servername.string->uni_str_len * 2, 0 );
587 fstrcpy( logname, "" );
588 if ( q_u->logname.string ) {
589 rpcstr_pull( logname, q_u->logname.string->buffer,
591 q_u->logname.string->uni_str_len * 2, 0 );
594 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
595 servername, logname ));
597 /* according to MSDN, if the logfile cannot be found, we should
598 default to the "Application" log */
600 if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) )
603 if ( !(info = find_eventlog_info_by_hnd( p, &r_u->handle )) ) {
604 DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
606 elog_close( p, &r_u->handle );
607 return NT_STATUS_INVALID_HANDLE;
610 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
612 sync_eventlog_params( info );
613 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
618 /********************************************************************
619 This call still needs some work
620 ********************************************************************/
622 NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
623 EVENTLOG_Q_CLEAR_EVENTLOG * q_u,
624 EVENTLOG_R_CLEAR_EVENTLOG * r_u )
626 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
627 pstring backup_file_name;
630 return NT_STATUS_INVALID_HANDLE;
632 pstrcpy( backup_file_name, "" );
633 if ( q_u->backupfile.string ) {
634 rpcstr_pull( backup_file_name, q_u->backupfile.string->buffer,
635 sizeof( backup_file_name ),
636 q_u->backupfile.string->uni_str_len * 2, 0 );
638 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
639 "file name for log [%s].",
640 backup_file_name, info->logname ) );
643 /* check for WRITE access to the file */
645 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
646 return NT_STATUS_ACCESS_DENIED;
648 /* Force a close and reopen */
650 elog_close_tdb( info->etdb, True );
652 info->etdb = elog_open_tdb( info->logname, True );
656 return NT_STATUS_ACCESS_DENIED;
661 /********************************************************************
662 ********************************************************************/
664 NTSTATUS _eventlog_close_eventlog( pipes_struct * p,
665 EVENTLOG_Q_CLOSE_EVENTLOG * q_u,
666 EVENTLOG_R_CLOSE_EVENTLOG * r_u )
668 return elog_close( p, &q_u->handle );
671 /********************************************************************
672 ********************************************************************/
674 NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
675 EVENTLOG_Q_READ_EVENTLOG * q_u,
676 EVENTLOG_R_READ_EVENTLOG * r_u )
678 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
679 Eventlog_entry entry, *ee_new;
680 uint32 num_records_read = 0;
682 int bytes_left, record_number;
683 uint32 elog_read_type, elog_read_dir;
685 info->flags = q_u->flags;
686 ps = &p->out_data.rdata;
688 bytes_left = q_u->max_read_size;
691 return NT_STATUS_ACCESS_DENIED;
693 /* check for valid flags. Can't use the sequential and seek flags together */
695 elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
696 elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
698 if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
699 || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
701 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
702 return NT_STATUS_INVALID_PARAMETER;
705 /* a sequential read should ignore the offset */
707 if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
708 record_number = info->current_record;
710 record_number = q_u->offset;
712 while ( bytes_left > 0 ) {
714 /* assume that when the record fetch fails, that we are done */
716 if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) )
719 DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
721 /* Now see if there is enough room to add */
723 if ( !(ee_new = read_package_entry( ps, q_u, r_u,&entry )) )
724 return NT_STATUS_NO_MEMORY;
726 if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
727 r_u->bytes_in_next_record = ee_new->record.length;
729 /* response would be too big to fit in client-size buffer */
735 add_record_to_resp( r_u, ee_new );
736 bytes_left -= ee_new->record.length;
737 ZERO_STRUCT( entry );
738 num_records_read = r_u->num_records - num_records_read;
740 DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
741 "of [%d] records using [%d] bytes out of a max of [%d].\n",
742 num_records_read, r_u->num_records,
743 r_u->num_bytes_in_resp,
744 q_u->max_read_size ) );
746 if ( info->flags & EVENTLOG_FORWARDS_READ )
751 /* update the eventlog record pointer */
753 info->current_record = record_number;
756 /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
757 say when there are no more records */
759 return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
762 /********************************************************************
763 ********************************************************************/
765 NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p,
766 EVENTLOG_Q_GET_OLDEST_ENTRY * q_u,
767 EVENTLOG_R_GET_OLDEST_ENTRY * r_u )
769 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
771 if ( !( get_oldest_entry_hook( info ) ) )
772 return NT_STATUS_ACCESS_DENIED;
774 r_u->oldest_entry = info->oldest_entry;
779 /********************************************************************
780 ********************************************************************/
782 NTSTATUS _eventlog_get_num_records( pipes_struct * p,
783 EVENTLOG_Q_GET_NUM_RECORDS * q_u,
784 EVENTLOG_R_GET_NUM_RECORDS * r_u )
786 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
788 if ( !( get_num_records_hook( info ) ) )
789 return NT_STATUS_ACCESS_DENIED;
791 r_u->num_records = info->num_records;