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 * Copyright (C) Guenther Deschner 2009.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #include "../librpc/gen_ndr/srv_eventlog.h"
25 #include "lib/eventlog/eventlog.h"
29 #define DBGC_CLASS DBGC_RPC_SRV
34 uint32 current_record;
38 uint32 access_granted;
41 /********************************************************************
42 ********************************************************************/
44 static int eventlog_info_destructor(EVENTLOG_INFO *elog)
47 elog_close_tdb(elog->etdb, false);
52 /********************************************************************
53 ********************************************************************/
55 static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
56 struct policy_handle * handle )
60 if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
62 ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
69 /********************************************************************
70 ********************************************************************/
72 static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
74 char *tdbname = elog_tdbname(talloc_tos(), info->logname );
75 struct security_descriptor *sec_desc;
76 struct security_ace *ace;
82 /* get the security descriptor for the file */
84 sec_desc = get_nt_acl_no_snum( info, tdbname );
85 TALLOC_FREE( tdbname );
88 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
93 ace = talloc_zero(sec_desc, struct security_ace);
95 TALLOC_FREE(sec_desc);
99 ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
101 ace->access_mask = REG_KEY_ALL;
102 ace->trustee = global_sid_System;
104 status = security_descriptor_dacl_add(sec_desc, ace);
105 if (!NT_STATUS_IS_OK(status)) {
106 TALLOC_FREE(sec_desc);
112 if ( geteuid() == sec_initial_uid() ) {
113 DEBUG(5,("elog_check_access: running as root, using system token\n"));
114 token = get_system_token();
117 /* run the check, try for the max allowed */
119 status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
120 &info->access_granted);
122 TALLOC_FREE(sec_desc);
124 if (!NT_STATUS_IS_OK(status)) {
125 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
130 /* we have to have READ permission for a successful open */
132 return ( info->access_granted & SEC_FILE_READ_DATA );
135 /********************************************************************
136 ********************************************************************/
138 static bool elog_validate_logname( const char *name )
141 const char **elogs = lp_eventlog_list();
147 for ( i=0; elogs[i]; i++ ) {
148 if ( strequal( name, elogs[i] ) )
155 /********************************************************************
156 ********************************************************************/
158 static bool get_num_records_hook( EVENTLOG_INFO * info )
164 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
168 /* lock the tdb since we have to get 2 records */
170 tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
171 next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
172 oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
173 tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
176 ( "Oldest Record %d; Next Record %d\n", oldest_record,
179 info->num_records = ( next_record - oldest_record );
180 info->oldest_entry = oldest_record;
185 /********************************************************************
186 ********************************************************************/
188 static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
190 /* it's the same thing */
191 return get_num_records_hook( info );
194 /********************************************************************
195 ********************************************************************/
197 static NTSTATUS elog_open( pipes_struct * p, const char *logname, struct policy_handle *hnd )
201 /* first thing is to validate the eventlog name */
203 if ( !elog_validate_logname( logname ) )
204 return NT_STATUS_OBJECT_PATH_INVALID;
206 if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
207 return NT_STATUS_NO_MEMORY;
208 talloc_set_destructor(elog, eventlog_info_destructor);
210 elog->logname = talloc_strdup( elog, logname );
212 /* Open the tdb first (so that we can create any new tdbs if necessary).
213 We have to do this as root and then use an internal access check
214 on the file permissions since you can only have a tdb open once
215 in a single process */
218 elog->etdb = elog_open_tdb( elog->logname, False, False );
222 /* according to MSDN, if the logfile cannot be found, we should
223 default to the "Application" log */
225 if ( !strequal( logname, ELOG_APPL ) ) {
227 TALLOC_FREE( elog->logname );
229 elog->logname = talloc_strdup( elog, ELOG_APPL );
231 /* do the access check */
232 if ( !elog_check_access( elog, p->server_info->ptok ) ) {
234 return NT_STATUS_ACCESS_DENIED;
238 elog->etdb = elog_open_tdb( elog->logname, False, False );
244 return NT_STATUS_ACCESS_DENIED; /* ??? */
248 /* now do the access check. Close the tdb if we fail here */
250 if ( !elog_check_access( elog, p->server_info->ptok ) ) {
252 return NT_STATUS_ACCESS_DENIED;
255 /* create the policy handle */
257 if ( !create_policy_hnd( p, hnd, elog ) ) {
259 return NT_STATUS_NO_MEMORY;
262 /* set the initial current_record pointer */
264 if ( !get_oldest_entry_hook( elog ) ) {
265 DEBUG(3,("elog_open: Successfully opened eventlog but can't "
266 "get any information on internal records!\n"));
269 elog->current_record = elog->oldest_entry;
274 /********************************************************************
275 ********************************************************************/
277 static NTSTATUS elog_close( pipes_struct *p, struct policy_handle *hnd )
279 if ( !( close_policy_hnd( p, hnd ) ) ) {
280 return NT_STATUS_INVALID_HANDLE;
286 /*******************************************************************
287 *******************************************************************/
289 static int elog_size( EVENTLOG_INFO *info )
291 if ( !info || !info->etdb ) {
292 DEBUG(0,("elog_size: Invalid info* structure!\n"));
296 return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
299 /********************************************************************
300 note that this can only be called AFTER the table is constructed,
301 since it uses the table to find the tdb handle
302 ********************************************************************/
304 static bool sync_eventlog_params( EVENTLOG_INFO *info )
309 struct registry_key *key;
310 struct registry_value *value;
312 char *elogname = info->logname;
313 TALLOC_CTX *ctx = talloc_stackframe();
316 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
319 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
322 /* set resonable defaults. 512Kb on size and 1 week on time */
325 uiRetention = 604800;
327 /* the general idea is to internally open the registry
328 key and retrieve the values. That way we can continue
329 to use the same fetch/store api that we use in
332 path = talloc_asprintf(ctx, "%s\\%s", KEY_EVENTLOG, elogname);
337 wresult = reg_open_path(ctx, path, REG_KEY_READ, get_system_token(),
340 if ( !W_ERROR_IS_OK( wresult ) ) {
342 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
343 path, win_errstr( wresult ) ) );
347 wresult = reg_queryvalue(key, key, "Retention", &value);
348 if (!W_ERROR_IS_OK(wresult)) {
349 DEBUG(4, ("Failed to query value \"Retention\": %s\n",
350 win_errstr(wresult)));
353 uiRetention = value->v.dword;
355 wresult = reg_queryvalue(key, key, "MaxSize", &value);
356 if (!W_ERROR_IS_OK(wresult)) {
357 DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
358 win_errstr(wresult)));
361 uiMaxSize = value->v.dword;
363 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
364 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
373 /********************************************************************
374 _eventlog_OpenEventLogW
375 ********************************************************************/
377 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
378 struct eventlog_OpenEventLogW *r)
383 DEBUG( 10,("_eventlog_OpenEventLogW: Server [%s], Log [%s]\n",
384 r->in.servername->string, r->in.logname->string ));
386 /* according to MSDN, if the logfile cannot be found, we should
387 default to the "Application" log */
389 if ( !NT_STATUS_IS_OK( result = elog_open( p, r->in.logname->string, r->out.handle )) )
392 if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
393 DEBUG(0,("_eventlog_OpenEventLogW: eventlog (%s) opened but unable to find handle!\n",
394 r->in.logname->string ));
395 elog_close( p, r->out.handle );
396 return NT_STATUS_INVALID_HANDLE;
399 DEBUG(10,("_eventlog_OpenEventLogW: Size [%d]\n", elog_size( info )));
401 if (!sync_eventlog_params(info)) {
402 elog_close(p, r->out.handle);
403 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
405 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
410 /********************************************************************
411 _eventlog_ClearEventLogW
412 This call still needs some work
413 ********************************************************************/
414 /** The windows client seems to be doing something funny with the file name
416 ClearEventLog(handle, "backup_file")
417 on the client side will result in the backup file name looking like this on the
419 \??\${CWD of client}\backup_file
420 If an absolute path gets specified, such as
421 ClearEventLog(handle, "C:\\temp\\backup_file")
422 then it is still mangled by the client into this:
423 \??\C:\temp\backup_file
424 when it is on the wire.
425 I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
426 would be added in given that the backup file gets written on the server side. */
428 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
429 struct eventlog_ClearEventLogW *r)
431 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
434 return NT_STATUS_INVALID_HANDLE;
436 if (r->in.backupfile && r->in.backupfile->string) {
438 DEBUG(8,( "_eventlog_ClearEventLogW: Using [%s] as the backup "
439 "file name for log [%s].",
440 r->in.backupfile->string, info->logname ) );
443 /* check for WRITE access to the file */
445 if ( !(info->access_granted & SEC_FILE_WRITE_DATA) )
446 return NT_STATUS_ACCESS_DENIED;
448 /* Force a close and reopen */
450 elog_close_tdb( info->etdb, True );
452 info->etdb = elog_open_tdb( info->logname, True, False );
456 return NT_STATUS_ACCESS_DENIED;
461 /********************************************************************
462 _eventlog_CloseEventLog
463 ********************************************************************/
465 NTSTATUS _eventlog_CloseEventLog(pipes_struct * p,
466 struct eventlog_CloseEventLog *r)
470 status = elog_close( p, r->in.handle );
471 if (!NT_STATUS_IS_OK(status)) {
475 ZERO_STRUCTP(r->out.handle);
480 /********************************************************************
481 _eventlog_ReadEventLogW
482 ********************************************************************/
484 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p,
485 struct eventlog_ReadEventLogW *r)
487 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
488 uint32_t num_records_read = 0;
489 int bytes_left, record_number;
490 uint32_t elog_read_type, elog_read_dir;
493 return NT_STATUS_INVALID_HANDLE;
496 info->flags = r->in.flags;
497 bytes_left = r->in.number_of_bytes;
500 return NT_STATUS_ACCESS_DENIED;
503 /* check for valid flags. Can't use the sequential and seek flags together */
505 elog_read_type = r->in.flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
506 elog_read_dir = r->in.flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
508 if (r->in.flags == 0 ||
509 elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) ||
510 elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ))
512 DEBUG(3,("_eventlog_ReadEventLogW: "
513 "Invalid flags [0x%08x] for ReadEventLog\n",
515 return NT_STATUS_INVALID_PARAMETER;
518 /* a sequential read should ignore the offset */
520 if (elog_read_type & EVENTLOG_SEQUENTIAL_READ) {
521 record_number = info->current_record;
523 record_number = r->in.offset;
526 if (r->in.number_of_bytes == 0) {
527 struct EVENTLOGRECORD *e;
528 e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb),
531 return NT_STATUS_END_OF_FILE;
533 *r->out.real_size = e->Length;
534 return NT_STATUS_BUFFER_TOO_SMALL;
537 while (bytes_left > 0) {
540 enum ndr_err_code ndr_err;
541 struct EVENTLOGRECORD *e;
543 e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb),
549 ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, e,
550 (ndr_push_flags_fn_t)ndr_push_EVENTLOGRECORD);
551 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
552 return ndr_map_error2ntstatus(ndr_err);
555 if (DEBUGLEVEL >= 10) {
556 NDR_PRINT_DEBUG(EVENTLOGRECORD, e);
559 if (blob.length > r->in.number_of_bytes) {
560 *r->out.real_size = blob.length;
561 return NT_STATUS_BUFFER_TOO_SMALL;
564 if (*r->out.sent_size + blob.length > r->in.number_of_bytes) {
568 bytes_left -= blob.length;
570 if (info->flags & EVENTLOG_FORWARDS_READ) {
576 /* update the eventlog record pointer */
578 info->current_record = record_number;
580 memcpy(&r->out.data[*(r->out.sent_size)],
581 blob.data, blob.length);
582 *(r->out.sent_size) += blob.length;
587 if (r->in.offset == 0 && record_number == 0 && *r->out.sent_size == 0) {
588 return NT_STATUS_END_OF_FILE;
594 /********************************************************************
595 _eventlog_GetOldestRecord
596 ********************************************************************/
598 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
599 struct eventlog_GetOldestRecord *r)
601 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
604 return NT_STATUS_INVALID_HANDLE;
607 if ( !( get_oldest_entry_hook( info ) ) )
608 return NT_STATUS_ACCESS_DENIED;
610 *r->out.oldest_entry = info->oldest_entry;
615 /********************************************************************
616 _eventlog_GetNumRecords
617 ********************************************************************/
619 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
620 struct eventlog_GetNumRecords *r)
622 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
625 return NT_STATUS_INVALID_HANDLE;
628 if ( !( get_num_records_hook( info ) ) )
629 return NT_STATUS_ACCESS_DENIED;
631 *r->out.number = info->num_records;
636 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
638 p->rng_fault_state = True;
639 return NT_STATUS_NOT_IMPLEMENTED;
642 /********************************************************************
643 _eventlog_GetLogInformation
644 ********************************************************************/
646 NTSTATUS _eventlog_GetLogInformation(pipes_struct *p,
647 struct eventlog_GetLogInformation *r)
649 EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
650 struct EVENTLOG_FULL_INFORMATION f;
651 enum ndr_err_code ndr_err;
655 return NT_STATUS_INVALID_HANDLE;
658 if (r->in.level != 0) {
659 return NT_STATUS_INVALID_LEVEL;
662 *r->out.bytes_needed = 4;
664 if (r->in.buf_size < 4) {
665 return NT_STATUS_BUFFER_TOO_SMALL;
668 /* FIXME: this should be retrieved from the handle */
671 ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &f,
672 (ndr_push_flags_fn_t)ndr_push_EVENTLOG_FULL_INFORMATION);
673 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
674 return ndr_map_error2ntstatus(ndr_err);
677 if (DEBUGLEVEL >= 10) {
678 NDR_PRINT_DEBUG(EVENTLOG_FULL_INFORMATION, &f);
681 memcpy(r->out.buffer, blob.data, 4);
686 /********************************************************************
687 _eventlog_FlushEventLog
688 ********************************************************************/
690 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p,
691 struct eventlog_FlushEventLog *r)
693 EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
695 return NT_STATUS_INVALID_HANDLE;
698 return NT_STATUS_ACCESS_DENIED;
701 /********************************************************************
702 ********************************************************************/
704 static NTSTATUS evlog_report_to_record(TALLOC_CTX *mem_ctx,
705 const struct eventlog_ReportEventW *r,
707 struct EVENTLOGRECORD *e)
712 e->TimeGenerated = r->in.timestamp;
713 e->TimeWritten = time(NULL);
714 e->EventID = r->in.event_id;
715 e->EventType = r->in.event_type;
716 e->NumStrings = r->in.num_of_strings;
717 e->EventCategory = r->in.event_category;
718 e->ReservedFlags = r->in.flags;
719 e->DataLength = r->in.data_size;
720 e->SourceName = talloc_strdup(mem_ctx, logname);
721 NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
722 if (r->in.servername->string) {
723 e->Computername = r->in.servername->string;
725 e->Computername = talloc_strdup(mem_ctx, "");
726 NT_STATUS_HAVE_NO_MEMORY(e->Computername);
728 if (r->in.user_sid) {
729 e->UserSid = *r->in.user_sid;
731 e->Strings = talloc_array(mem_ctx, const char *, e->NumStrings);
732 NT_STATUS_HAVE_NO_MEMORY(e->Strings);
734 for (i=0; i < e->NumStrings; i++) {
735 e->Strings[i] = talloc_strdup(e->Strings,
736 r->in.strings[i]->string);
737 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
739 e->Data = r->in.data;
744 /********************************************************************
745 _eventlog_ReportEventW
746 ********************************************************************/
748 NTSTATUS _eventlog_ReportEventW(pipes_struct *p,
749 struct eventlog_ReportEventW *r)
752 struct EVENTLOGRECORD record;
754 EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
756 return NT_STATUS_INVALID_HANDLE;
759 status = evlog_report_to_record(p->mem_ctx, r, info->logname, &record);
760 if (!NT_STATUS_IS_OK(status)) {
764 status = evlog_push_record(p->mem_ctx,
765 ELOG_TDB_CTX(info->etdb),
767 r->out.record_number);
768 if (!NT_STATUS_IS_OK(status)) {
775 /********************************************************************
776 ********************************************************************/
778 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
780 p->rng_fault_state = True;
781 return NT_STATUS_NOT_IMPLEMENTED;
784 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
786 p->rng_fault_state = True;
787 return NT_STATUS_NOT_IMPLEMENTED;
790 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
792 p->rng_fault_state = True;
793 return NT_STATUS_NOT_IMPLEMENTED;
796 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
798 p->rng_fault_state = True;
799 return NT_STATUS_NOT_IMPLEMENTED;
802 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
804 p->rng_fault_state = True;
805 return NT_STATUS_NOT_IMPLEMENTED;
808 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
810 p->rng_fault_state = True;
811 return NT_STATUS_NOT_IMPLEMENTED;
814 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
816 p->rng_fault_state = True;
817 return NT_STATUS_NOT_IMPLEMENTED;
820 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
822 p->rng_fault_state = True;
823 return NT_STATUS_NOT_IMPLEMENTED;
826 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
828 p->rng_fault_state = True;
829 return NT_STATUS_NOT_IMPLEMENTED;
832 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
834 p->rng_fault_state = True;
835 return NT_STATUS_NOT_IMPLEMENTED;
838 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
840 p->rng_fault_state = True;
841 return NT_STATUS_NOT_IMPLEMENTED;
844 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
846 p->rng_fault_state = True;
847 return NT_STATUS_NOT_IMPLEMENTED;
850 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
852 p->rng_fault_state = True;
853 return NT_STATUS_NOT_IMPLEMENTED;
856 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
858 p->rng_fault_state = True;
859 return NT_STATUS_NOT_IMPLEMENTED;
862 NTSTATUS _eventlog_ReportEventAndSourceW(pipes_struct *p, struct eventlog_ReportEventAndSourceW *r)
864 p->rng_fault_state = True;
865 return NT_STATUS_NOT_IMPLEMENTED;