1/* 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. 7 * 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. 12 * 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. 17 * 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. 21 */ 22 23#include "includes.h" 24 25#undef DBGC_CLASS 26#define DBGC_CLASS DBGC_RPC_SRV 27 28typedef struct { 29 char *logname; 30 ELOG_TDB *etdb; 31 uint32 current_record; 32 uint32 num_records; 33 uint32 oldest_entry; 34 uint32 flags; 35 uint32 access_granted; 36} EVENTLOG_INFO; 37 38/******************************************************************** 39 ********************************************************************/ 40 41static void free_eventlog_info( void *ptr ) 42{ 43 EVENTLOG_INFO *elog = (EVENTLOG_INFO *)ptr; 44 45 if ( elog->etdb ) 46 elog_close_tdb( elog->etdb, False ); 47 48 TALLOC_FREE( elog ); 49} 50 51/******************************************************************** 52 ********************************************************************/ 53 54static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p, 55 POLICY_HND * handle ) 56{ 57 EVENTLOG_INFO *info; 58 59 if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) { 60 DEBUG( 2, 61 ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) ); 62 return NULL; 63 } 64 65 return info; 66} 67 68/******************************************************************** 69********************************************************************/ 70 71static BOOL elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token ) 72{ 73 char *tdbname = elog_tdbname( info->logname ); 74 SEC_DESC *sec_desc; 75 BOOL ret; 76 NTSTATUS ntstatus; 77 78 if ( !tdbname ) 79 return False; 80 81 /* get the security descriptor for the file */ 82 83 sec_desc = get_nt_acl_no_snum( info, tdbname ); 84 SAFE_FREE( tdbname ); 85 86 if ( !sec_desc ) { 87 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n", 88 tdbname)); 89 return False; 90 } 91 92 /* root free pass */ 93 94 if ( geteuid() == sec_initial_uid() ) { 95 DEBUG(5,("elog_check_access: using root's token\n")); 96 token = get_root_nt_token(); 97 } 98 99 /* run the check, try for the max allowed */ 100 101 ret = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS, 102 &info->access_granted, &ntstatus ); 103 104 if ( sec_desc ) 105 TALLOC_FREE( sec_desc ); 106 107 if ( !ret ) { 108 DEBUG(8,("elog_check_access: se_access_check() return %s\n", 109 nt_errstr( ntstatus))); 110 return False; 111 } 112 113 /* we have to have READ permission for a successful open */ 114 115 return ( info->access_granted & SA_RIGHT_FILE_READ_DATA ); 116} 117 118/******************************************************************** 119 ********************************************************************/ 120 121static BOOL elog_validate_logname( const char *name ) 122{ 123 int i; 124 const char **elogs = lp_eventlog_list(); 125 126 if (!elogs) { 127 return False; 128 } 129 130 for ( i=0; elogs[i]; i++ ) { 131 if ( strequal( name, elogs[i] ) ) 132 return True; 133 } 134 135 return False; 136} 137 138/******************************************************************** 139********************************************************************/ 140 141static BOOL get_num_records_hook( EVENTLOG_INFO * info ) 142{ 143 int next_record; 144 int oldest_record; 145 146 if ( !info->etdb ) { 147 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) ); 148 return False; 149 } 150 151 /* lock the tdb since we have to get 2 records */ 152 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); 157 158 DEBUG( 8, 159 ( "Oldest Record %d; Next Record %d\n", oldest_record, 160 next_record ) ); 161 162 info->num_records = ( next_record - oldest_record ); 163 info->oldest_entry = oldest_record; 164 165 return True; 166} 167 168/******************************************************************** 169 ********************************************************************/ 170 171static BOOL get_oldest_entry_hook( EVENTLOG_INFO * info ) 172{ 173 /* it's the same thing */ 174 return get_num_records_hook( info ); 175} 176 177/******************************************************************** 178 ********************************************************************/ 179 180static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd ) 181{ 182 EVENTLOG_INFO *elog; 183 184 /* first thing is to validate the eventlog name */ 185 186 if ( !elog_validate_logname( logname ) ) 187 return NT_STATUS_OBJECT_PATH_INVALID; 188 189 if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) ) 190 return NT_STATUS_NO_MEMORY; 191 192 elog->logname = talloc_strdup( elog, logname ); 193 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 */ 198 199 become_root(); 200 elog->etdb = elog_open_tdb( elog->logname, False ); 201 unbecome_root(); 202 203 if ( !elog->etdb ) { 204 /* according to MSDN, if the logfile cannot be found, we should 205 default to the "Application" log */ 206 207 if ( !strequal( logname, ELOG_APPL ) ) { 208 209 TALLOC_FREE( elog->logname ); 210 211 elog->logname = talloc_strdup( elog, ELOG_APPL ); 212 213 /* do the access check */ 214 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) { 215 TALLOC_FREE( elog ); 216 return NT_STATUS_ACCESS_DENIED; 217 } 218 219 become_root(); 220 elog->etdb = elog_open_tdb( elog->logname, False ); 221 unbecome_root(); 222 } 223 224 if ( !elog->etdb ) { 225 TALLOC_FREE( elog ); 226 return NT_STATUS_ACCESS_DENIED; /* ??? */ 227 } 228 } 229 230 /* now do the access check. Close the tdb if we fail here */ 231 232 if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) { 233 elog_close_tdb( elog->etdb, False ); 234 TALLOC_FREE( elog ); 235 return NT_STATUS_ACCESS_DENIED; 236 } 237 238 /* create the policy handle */ 239 240 if ( !create_policy_hnd 241 ( p, hnd, free_eventlog_info, ( void * ) elog ) ) { 242 free_eventlog_info( elog ); 243 return NT_STATUS_NO_MEMORY; 244 } 245 246 /* set the initial current_record pointer */ 247 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")); 251 } 252 253 elog->current_record = elog->oldest_entry; 254 255 return NT_STATUS_OK; 256} 257 258/******************************************************************** 259 ********************************************************************/ 260 261static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd ) 262{ 263 if ( !( close_policy_hnd( p, hnd ) ) ) { 264 return NT_STATUS_INVALID_HANDLE; 265 } 266 267 return NT_STATUS_OK; 268} 269 270/******************************************************************* 271 *******************************************************************/ 272 273static int elog_size( EVENTLOG_INFO *info ) 274{ 275 if ( !info || !info->etdb ) { 276 DEBUG(0,("elog_size: Invalid info* structure!\n")); 277 return 0; 278 } 279 280 return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL ); 281} 282 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 ********************************************************************/ 287 288static Eventlog_entry *get_eventlog_record( prs_struct * ps, TDB_CONTEXT * tdb, 289 int recno, Eventlog_entry * ee ) 290{ 291 TDB_DATA ret, key; 292 293 int srecno; 294 int reclen; 295 int len; 296 297 pstring *wpsource, *wpcomputer, *wpsid, *wpstrs, *puserdata; 298 299 key.dsize = sizeof( int32 ); 300 301 srecno = recno; 302 key.dptr = ( char * ) &srecno; 303 304 ret = tdb_fetch( tdb, key ); 305 306 if ( ret.dsize == 0 ) { 307 DEBUG( 8, 308 ( "Can't find a record for the key, record %d\n", 309 recno ) ); 310 return NULL; 311 } 312 313 len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen ); 314 315 DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) ); 316 317 if ( !len ) 318 return NULL; 319 320 /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */ 321 322 if ( !ee ) 323 return NULL; 324 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 ); 344 DEBUG( 10, 345 ( "Read record %d, len in tdb was %d\n", 346 ee->record.record_number, len ) ); 347 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' */ 350 351 if ( wpcomputer ) 352 memcpy( ee->data_record.computer_name, wpcomputer, 353 ee->data_record.computer_name_len ); 354 if ( wpsource ) 355 memcpy( ee->data_record.source_name, wpsource, 356 ee->data_record.source_name_len ); 357 358 if ( wpsid ) 359 memcpy( ee->data_record.sid, wpsid, 360 ee->record.user_sid_length ); 361 if ( wpstrs ) 362 memcpy( ee->data_record.strings, wpstrs, 363 ee->data_record.strings_len ); 364 365 /* note that userdata is a pstring */ 366 if ( puserdata ) 367 memcpy( ee->data_record.user_data, puserdata, 368 ee->data_record.user_data_len ); 369 370 SAFE_FREE( wpcomputer ); 371 SAFE_FREE( wpsource ); 372 SAFE_FREE( wpsid ); 373 SAFE_FREE( wpstrs ); 374 SAFE_FREE( puserdata ); 375 376 DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) ); 377 DEBUG( 10, 378 ( "get_eventlog_record: computer_name %d is ", 379 ee->data_record.computer_name_len ) ); 380 SAFE_FREE( ret.dptr ); 381 return ee; 382} 383 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 ********************************************************************/ 388 389static BOOL sync_eventlog_params( EVENTLOG_INFO *info ) 390{ 391 pstring path; 392 uint32 uiMaxSize; 393 uint32 uiRetention; 394 REGISTRY_KEY *keyinfo; 395 REGISTRY_VALUE *val; 396 REGVAL_CTR *values; 397 WERROR wresult; 398 char *elogname = info->logname; 399 400 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) ); 401 402 if ( !info->etdb ) { 403 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) ); 404 return False; 405 } 406 /* set resonable defaults. 512Kb on size and 1 week on time */ 407 408 uiMaxSize = 0x80000; 409 uiRetention = 604800; 410 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 414 srv_reg_nt.c */ 415 416 pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname ); 417 418 wresult = 419 regkey_open_internal( &keyinfo, path, get_root_nt_token( ), 420 REG_KEY_READ ); 421 422 if ( !W_ERROR_IS_OK( wresult ) ) { 423 DEBUG( 4, 424 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n", 425 path, dos_errstr( wresult ) ) ); 426 return False; 427 } 428 429 if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) { 430 TALLOC_FREE( keyinfo ); 431 DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) ); 432 433 return False; 434 } 435 fetch_reg_values( keyinfo, values ); 436 437 if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL ) 438 uiRetention = IVAL( regval_data_p( val ), 0 ); 439 440 if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL ) 441 uiMaxSize = IVAL( regval_data_p( val ), 0 ); 442 443 regkey_close_internal( keyinfo ); 444 445 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize ); 446 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention ); 447 448 return True; 449} 450 451/******************************************************************** 452 ********************************************************************/ 453 454static 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 ) 458{ 459 uint8 *offset; 460 Eventlog_entry *ee_new = NULL; 461 462 ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 ); 463 if ( ee_new == NULL ) { 464 return NULL; 465 } 466 467 entry->data_record.sid_padding = 468 ( ( 4 - 469 ( ( entry->data_record.source_name_len + 470 entry->data_record.computer_name_len ) % 4 ) ) % 4 ); 471 entry->data_record.data_padding = 472 ( 4 - 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; 484 } 485 DEBUG( 10, 486 ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) ); 487 DEBUG( 10, 488 ( "data_padding is [%d].\n", 489 entry->data_record.data_padding ) ); 490 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 ); 498 DEBUG( 10, 499 ( "entry->record.length is [%d].\n", entry->record.length ) ); 500 entry->data = 501 PRS_ALLOC_MEM( ps, uint8, 502 entry->record.length - 503 sizeof( Eventlog_record ) - 504 sizeof( entry->record.length ) ); 505 if ( entry->data == NULL ) { 506 return NULL; 507 } 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; 535 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; 541 542 return ee_new; 543} 544 545/******************************************************************** 546 ********************************************************************/ 547 548static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u, 549 Eventlog_entry * ee_new ) 550{ 551 Eventlog_entry *insert_point; 552 553 insert_point = r_u->entry; 554 555 if ( NULL == insert_point ) { 556 r_u->entry = ee_new; 557 ee_new->next = NULL; 558 } else { 559 while ( ( NULL != insert_point->next ) ) { 560 insert_point = insert_point->next; 561 } 562 ee_new->next = NULL; 563 insert_point->next = ee_new; 564 } 565 r_u->num_records++; 566 r_u->num_bytes_in_resp += ee_new->record.length; 567 568 return True; 569} 570 571/******************************************************************** 572 ********************************************************************/ 573 574NTSTATUS _eventlog_open_eventlog( pipes_struct * p, 575 EVENTLOG_Q_OPEN_EVENTLOG * q_u, 576 EVENTLOG_R_OPEN_EVENTLOG * r_u ) 577{ 578 fstring servername, logname; 579 EVENTLOG_INFO *info; 580 NTSTATUS result; 581 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 ); 587 } 588 589 fstrcpy( logname, "" ); 590 if ( q_u->logname.string ) { 591 rpcstr_pull( logname, q_u->logname.string->buffer, 592 sizeof( logname ), 593 q_u->logname.string->uni_str_len * 2, 0 ); 594 } 595 596 DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n", 597 servername, logname )); 598 599 /* according to MSDN, if the logfile cannot be found, we should 600 default to the "Application" log */ 601 602 if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) ) 603 return result; 604 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", 607 logname )); 608 elog_close( p, &r_u->handle ); 609 return NT_STATUS_INVALID_HANDLE; 610 } 611 612 DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info ))); 613 614 sync_eventlog_params( info ); 615 prune_eventlog( ELOG_TDB_CTX(info->etdb) ); 616 617 return NT_STATUS_OK; 618} 619 620/******************************************************************** 621 This call still needs some work 622 ********************************************************************/ 623 624NTSTATUS _eventlog_clear_eventlog( pipes_struct * p, 625 EVENTLOG_Q_CLEAR_EVENTLOG * q_u, 626 EVENTLOG_R_CLEAR_EVENTLOG * r_u ) 627{ 628 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle ); 629 pstring backup_file_name; 630 631 if ( !info ) 632 return NT_STATUS_INVALID_HANDLE; 633 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 ); 639 640 DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup " 641 "file name for log [%s].", 642 backup_file_name, info->logname ) ); 643 } 644 645 /* check for WRITE access to the file */ 646 647 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) ) 648 return NT_STATUS_ACCESS_DENIED; 649 650 /* Force a close and reopen */ 651 652 elog_close_tdb( info->etdb, True ); 653 become_root(); 654 info->etdb = elog_open_tdb( info->logname, True ); 655 unbecome_root(); 656 657 if ( !info->etdb ) 658 return NT_STATUS_ACCESS_DENIED; 659 660 return NT_STATUS_OK; 661} 662 663/******************************************************************** 664 ********************************************************************/ 665 666NTSTATUS _eventlog_close_eventlog( pipes_struct * p, 667 EVENTLOG_Q_CLOSE_EVENTLOG * q_u, 668 EVENTLOG_R_CLOSE_EVENTLOG * r_u ) 669{ 670 return elog_close( p, &q_u->handle ); 671} 672 673/******************************************************************** 674 ********************************************************************/ 675 676NTSTATUS _eventlog_read_eventlog( pipes_struct * p, 677 EVENTLOG_Q_READ_EVENTLOG * q_u, 678 EVENTLOG_R_READ_EVENTLOG * r_u ) 679{ 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; 683 prs_struct *ps; 684 int bytes_left, record_number; 685 uint32 elog_read_type, elog_read_dir; 686 687 if (info == NULL) { 688 return NT_STATUS_INVALID_HANDLE; 689 } 690 691 info->flags = q_u->flags; 692 ps = &p->out_data.rdata; 693 694 bytes_left = q_u->max_read_size; 695 696 if ( !info->etdb ) 697 return NT_STATUS_ACCESS_DENIED; 698 699 /* check for valid flags. Can't use the sequential and seek flags together */ 700 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); 703 704 if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) 705 || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) ) 706 { 707 DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags)); 708 return NT_STATUS_INVALID_PARAMETER; 709 } 710 711 /* a sequential read should ignore the offset */ 712 713 if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ ) 714 record_number = info->current_record; 715 else 716 record_number = q_u->offset; 717 718 while ( bytes_left > 0 ) { 719 720 /* assume that when the record fetch fails, that we are done */ 721 722 if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) ) 723 break; 724 725 DEBUG( 8, ( "Retrieved record %d\n", record_number ) ); 726 727 /* Now see if there is enough room to add */ 728 729 if ( !(ee_new = read_package_entry( ps, q_u, r_u,&entry )) ) 730 return NT_STATUS_NO_MEMORY; 731 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; 734 735 /* response would be too big to fit in client-size buffer */ 736 737 bytes_left = 0; 738 break; 739 } 740 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; 745 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 ) ); 751 752 if ( info->flags & EVENTLOG_FORWARDS_READ ) 753 record_number++; 754 else 755 record_number--; 756 757 /* update the eventlog record pointer */ 758 759 info->current_record = record_number; 760 } 761 762 /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to 763 say when there are no more records */ 764 765 return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL); 766} 767 768/******************************************************************** 769 ********************************************************************/ 770 771NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p, 772 EVENTLOG_Q_GET_OLDEST_ENTRY * q_u, 773 EVENTLOG_R_GET_OLDEST_ENTRY * r_u ) 774{ 775 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle ); 776 777 if (info == NULL) { 778 return NT_STATUS_INVALID_HANDLE; 779 } 780 781 if ( !( get_oldest_entry_hook( info ) ) ) 782 return NT_STATUS_ACCESS_DENIED; 783 784 r_u->oldest_entry = info->oldest_entry; 785 786 return NT_STATUS_OK; 787} 788 789/******************************************************************** 790 ********************************************************************/ 791 792NTSTATUS _eventlog_get_num_records( pipes_struct * p, 793 EVENTLOG_Q_GET_NUM_RECORDS * q_u, 794 EVENTLOG_R_GET_NUM_RECORDS * r_u ) 795{ 796 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle ); 797 798 if (info == NULL) { 799 return NT_STATUS_INVALID_HANDLE; 800 } 801 802 if ( !( get_num_records_hook( info ) ) ) 803 return NT_STATUS_ACCESS_DENIED; 804 805 r_u->num_records = info->num_records; 806 807 return NT_STATUS_OK; 808} 809