diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/rpc_server/eventlog | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | source3/rpc_server/eventlog/srv_eventlog_nt.c | 1047 | ||||
-rw-r--r-- | source3/rpc_server/eventlog/srv_eventlog_reg.c | 267 | ||||
-rw-r--r-- | source3/rpc_server/eventlog/srv_eventlog_reg.h | 29 |
3 files changed, 1343 insertions, 0 deletions
diff --git a/source3/rpc_server/eventlog/srv_eventlog_nt.c b/source3/rpc_server/eventlog/srv_eventlog_nt.c new file mode 100644 index 0000000..a946c57 --- /dev/null +++ b/source3/rpc_server/eventlog/srv_eventlog_nt.c @@ -0,0 +1,1047 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Marcin Krzysztof Porwit 2005, + * Copyright (C) Brian Moran 2005, + * Copyright (C) Gerald (Jerry) Carter 2005. + * Copyright (C) Guenther Deschner 2009. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "system/passwd.h" /* uid_wrapper */ +#include "ntdomain.h" +#include "lib/eventlog/eventlog.h" +#include "../libcli/security/security.h" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "rpc_client/cli_winreg_int.h" +#include "rpc_client/cli_winreg.h" +#include "smbd/smbd.h" +#include "auth.h" +#include "util_tdb.h" + +#include "rpc_server/rpc_server.h" +#include "librpc/rpc/dcesrv_core.h" +#include "librpc/gen_ndr/ndr_eventlog_scompat.h" +#include "rpc_server/eventlog/srv_eventlog_reg.h" +#include "lib/global_contexts.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +#define TOP_LEVEL_EVENTLOG_KEY "SYSTEM\\CurrentControlSet\\Services\\Eventlog" + +typedef struct { + char *logname; + ELOG_TDB *etdb; + uint32_t current_record; + uint32_t num_records; + uint32_t oldest_entry; + uint32_t flags; + uint32_t access_granted; +} EVENTLOG_INFO; + +/******************************************************************** + ********************************************************************/ + +static int eventlog_info_destructor(EVENTLOG_INFO *elog) +{ + if (elog->etdb) { + elog_close_tdb(elog->etdb, false); + } + return 0; +} + +/******************************************************************** + ********************************************************************/ + +static EVENTLOG_INFO *find_eventlog_info_by_hnd( struct pipes_struct * p, + struct policy_handle * handle ) +{ + EVENTLOG_INFO *info; + NTSTATUS status; + + info = find_policy_by_hnd(p, + handle, + DCESRV_HANDLE_ANY, + EVENTLOG_INFO, + &status); + if (!NT_STATUS_IS_OK(status)) { + DEBUG( 2, + ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) ); + return NULL; + } + + return info; +} + +/******************************************************************** + Pull the NT ACL from a file on disk or the OpenEventlog() access + check. Caller is responsible for freeing the returned security + descriptor via TALLOC_FREE(). This is designed for dealing with + user space access checks in smbd outside of the VFS. For example, + checking access rights in OpenEventlog() or from python. + +********************************************************************/ + +static NTSTATUS get_nt_acl_no_snum(TALLOC_CTX *ctx, + struct auth_session_info *session_info, + const char *fname, + uint32_t security_info_wanted, + struct security_descriptor **sd) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct conn_struct_tos *c = NULL; + NTSTATUS status = NT_STATUS_OK; + struct smb_filename *pathref_fname = NULL; + + if (!posix_locking_init(false)) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + status = create_conn_struct_tos(global_messaging_context(), + -1, + "/", + session_info, + &c); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("create_conn_struct_tos() returned %s.\n", + nt_errstr(status)); + TALLOC_FREE(frame); + return status; + } + + status = synthetic_pathref(talloc_tos(), + c->conn->cwd_fsp, + fname, + NULL, + NULL, + 0, + 0, + &pathref_fname); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("synthetic_pathref for file %s returned %s.\n", + fname, nt_errstr(status)); + TALLOC_FREE(frame); + return status; + } + status = SMB_VFS_FGET_NT_ACL(pathref_fname->fsp, + security_info_wanted, + ctx, + sd); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("SMB_VFS_FGET_NT_ACL for file %s returned %s.\n", + fname, nt_errstr(status)); + } + + TALLOC_FREE(frame); + + return status; +} + +/******************************************************************** +********************************************************************/ + +static bool elog_check_access(EVENTLOG_INFO *info, + struct auth_session_info *session_info) +{ + const struct security_token *token = session_info->security_token; + char *tdbname = elog_tdbname(talloc_tos(), info->logname ); + struct security_descriptor *sec_desc; + struct security_ace *ace; + NTSTATUS status; + + if ( !tdbname ) + return False; + + /* get the security descriptor for the file */ + + status = get_nt_acl_no_snum( info, + session_info, + tdbname, + SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL, + &sec_desc); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(5,("elog_check_access: Unable to get NT ACL for %s: %s\n", + tdbname, nt_errstr(status))); + TALLOC_FREE(tdbname); + return False; + } + TALLOC_FREE(tdbname); + + ace = talloc_zero(sec_desc, struct security_ace); + if (ace == NULL) { + TALLOC_FREE(sec_desc); + return false; + } + + ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED; + ace->flags = 0; + ace->access_mask = REG_KEY_ALL; + ace->trustee = global_sid_System; + + status = security_descriptor_dacl_add(sec_desc, ace); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(sec_desc); + return false; + } + + /* root free pass */ + + if ( geteuid() == sec_initial_uid() ) { + DEBUG(5,("elog_check_access: running as root, using system token\n")); + token = get_system_token(); + } + + /* run the check, try for the max allowed */ + + status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS, + &info->access_granted); + + TALLOC_FREE(sec_desc); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(8,("elog_check_access: se_access_check() return %s\n", + nt_errstr(status))); + return False; + } + + /* we have to have READ permission for a successful open */ + + return ( info->access_granted & SEC_FILE_READ_DATA ); +} + +/******************************************************************** + ********************************************************************/ + +static bool elog_validate_logname( const char *name ) +{ + int i; + const char **elogs = lp_eventlog_list(); + + if (!elogs) { + return False; + } + + for ( i=0; elogs[i]; i++ ) { + if ( strequal( name, elogs[i] ) ) + return True; + } + + return False; +} + +/******************************************************************** +********************************************************************/ + +static bool get_num_records_hook( EVENTLOG_INFO * info ) +{ + int next_record; + int oldest_record; + + if ( !info->etdb ) { + DEBUG( 10, ( "No open tdb for %s\n", info->logname ) ); + return False; + } + + /* lock the tdb since we have to get 2 records */ + + tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 ); + next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD); + oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY); + tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD); + + DEBUG( 8, + ( "Oldest Record %d; Next Record %d\n", oldest_record, + next_record ) ); + + info->num_records = ( next_record - oldest_record ); + info->oldest_entry = oldest_record; + + return True; +} + +/******************************************************************** + ********************************************************************/ + +static bool get_oldest_entry_hook( EVENTLOG_INFO * info ) +{ + /* it's the same thing */ + return get_num_records_hook( info ); +} + +/******************************************************************** + ********************************************************************/ + +static NTSTATUS elog_open( struct pipes_struct * p, const char *logname, struct policy_handle *hnd ) +{ + struct dcesrv_call_state *dce_call = p->dce_call; + struct auth_session_info *session_info = + dcesrv_call_session_info(dce_call); + EVENTLOG_INFO *elog; + + /* first thing is to validate the eventlog name */ + + if ( !elog_validate_logname( logname ) ) + return NT_STATUS_OBJECT_PATH_INVALID; + + if ( !(elog = talloc_zero( NULL, EVENTLOG_INFO )) ) + return NT_STATUS_NO_MEMORY; + talloc_set_destructor(elog, eventlog_info_destructor); + + elog->logname = talloc_strdup( elog, logname ); + + /* Open the tdb first (so that we can create any new tdbs if necessary). + We have to do this as root and then use an internal access check + on the file permissions since you can only have a tdb open once + in a single process */ + + become_root(); + elog->etdb = elog_open_tdb( elog->logname, False, False ); + unbecome_root(); + + if ( !elog->etdb ) { + /* according to MSDN, if the logfile cannot be found, we should + default to the "Application" log */ + + if ( !strequal( logname, ELOG_APPL ) ) { + + TALLOC_FREE( elog->logname ); + + elog->logname = talloc_strdup( elog, ELOG_APPL ); + + /* do the access check */ + if ( !elog_check_access( elog, session_info) ) { + TALLOC_FREE( elog ); + return NT_STATUS_ACCESS_DENIED; + } + + become_root(); + elog->etdb = elog_open_tdb( elog->logname, False, False ); + unbecome_root(); + } + + if ( !elog->etdb ) { + TALLOC_FREE( elog ); + return NT_STATUS_ACCESS_DENIED; /* ??? */ + } + } + + /* now do the access check. Close the tdb if we fail here */ + + if ( !elog_check_access( elog, session_info) ) { + TALLOC_FREE( elog ); + return NT_STATUS_ACCESS_DENIED; + } + + /* create the policy handle */ + + if ( !create_policy_hnd( p, hnd, 0, elog ) ) { + TALLOC_FREE(elog); + return NT_STATUS_NO_MEMORY; + } + + /* set the initial current_record pointer */ + + if ( !get_oldest_entry_hook( elog ) ) { + DEBUG(3,("elog_open: Successfully opened eventlog but can't " + "get any information on internal records!\n")); + } + + elog->current_record = elog->oldest_entry; + + return NT_STATUS_OK; +} + +/******************************************************************** + ********************************************************************/ + +static NTSTATUS elog_close( struct pipes_struct *p, struct policy_handle *hnd ) +{ + if ( !( close_policy_hnd( p, hnd ) ) ) { + return NT_STATUS_INVALID_HANDLE; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + *******************************************************************/ + +static int elog_size( EVENTLOG_INFO *info ) +{ + if ( !info || !info->etdb ) { + DEBUG(0,("elog_size: Invalid info* structure!\n")); + return 0; + } + + return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL ); +} + +/******************************************************************** + note that this can only be called AFTER the table is constructed, + since it uses the table to find the tdb handle + ********************************************************************/ + +static bool sync_eventlog_params(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + EVENTLOG_INFO *info) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + uint32_t uiMaxSize = 0; + uint32_t uiRetention = 0; + char *path = NULL; + NTSTATUS status; + WERROR wresult = WERR_OK; + char *elogname = info->logname; + TALLOC_CTX *ctx; + bool ret = false; + + ctx = talloc_stackframe(); + if (ctx == NULL) { + return false; + } + + DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) ); + + if ( !info->etdb ) { + DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) ); + goto done; + } + /* set reasonable defaults. 512Kb on size and 1 week on time */ + + uiMaxSize = 0x80000; + uiRetention = 604800; + + /* the general idea is to internally open the registry + key and retrieve the values. That way we can continue + to use the same fetch/store api that we use in + srv_reg_nt.c */ + path = talloc_asprintf(ctx, "%s\\%s", TOP_LEVEL_EVENTLOG_KEY, elogname); + if (!path) { + goto done; + } + + status = dcerpc_winreg_int_hklm_openkey(ctx, + get_session_info_system(), + msg_ctx, + &h, + path, + false, + access_mask, + &hive_hnd, + &key_hnd, + &wresult); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(4,("sync_eventlog_params: Failed to open key [%s] (%s)\n", + path, nt_errstr(status))); + goto done; + } + if ( !W_ERROR_IS_OK( wresult ) ) { + DEBUG( 4, + ( "sync_eventlog_params: Failed to open key [%s] (%s)\n", + path, win_errstr( wresult ) ) ); + goto done; + } + + status = dcerpc_winreg_query_dword(ctx, + h, + &key_hnd, + "Retention", + &uiRetention, + &wresult); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(4, ("Failed to query value \"Retention\": %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(wresult)) { + DEBUG(4, ("Failed to query value \"Retention\": %s\n", + win_errstr(wresult))); + goto done; + } + + status = dcerpc_winreg_query_dword(ctx, + h, + &key_hnd, + "MaxSize", + &uiMaxSize, + &wresult); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(4, ("Failed to query value \"Retention\": %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(wresult)) { + DEBUG(4, ("Failed to query value \"MaxSize\": %s\n", + win_errstr(wresult))); + goto done; + } + + tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize ); + tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention ); + + ret = true; + +done: + if (h != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(h, ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(ctx); + return ret; +} + +/******************************************************************** + _eventlog_OpenEventLogW + ********************************************************************/ + +NTSTATUS _eventlog_OpenEventLogW(struct pipes_struct *p, + struct eventlog_OpenEventLogW *r) +{ + EVENTLOG_INFO *info; + NTSTATUS result; + + DEBUG( 10,("_eventlog_OpenEventLogW: Server [%s], Log [%s]\n", + r->in.servername->string, r->in.logname->string )); + + /* according to MSDN, if the logfile cannot be found, we should + default to the "Application" log */ + + if ( !NT_STATUS_IS_OK( result = elog_open( p, r->in.logname->string, r->out.handle )) ) + return result; + + if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) { + DEBUG(0,("_eventlog_OpenEventLogW: eventlog (%s) opened but unable to find handle!\n", + r->in.logname->string )); + elog_close( p, r->out.handle ); + return NT_STATUS_INVALID_HANDLE; + } + + DEBUG(10,("_eventlog_OpenEventLogW: Size [%d]\n", elog_size( info ))); + + if (!sync_eventlog_params(p->mem_ctx, + p->msg_ctx, + info)) { + elog_close(p, r->out.handle); + return NT_STATUS_EVENTLOG_FILE_CORRUPT; + } + prune_eventlog( ELOG_TDB_CTX(info->etdb) ); + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_ClearEventLogW + This call still needs some work + ********************************************************************/ +/** The windows client seems to be doing something funny with the file name + A call like + ClearEventLog(handle, "backup_file") + on the client side will result in the backup file name looking like this on the + server side: + \??\${CWD of client}\backup_file + If an absolute path gets specified, such as + ClearEventLog(handle, "C:\\temp\\backup_file") + then it is still mangled by the client into this: + \??\C:\temp\backup_file + when it is on the wire. + I'm not sure where the \?? is coming from, or why the ${CWD} of the client process + would be added in given that the backup file gets written on the server side. */ + +NTSTATUS _eventlog_ClearEventLogW(struct pipes_struct *p, + struct eventlog_ClearEventLogW *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + + if ( !info ) + return NT_STATUS_INVALID_HANDLE; + + if (r->in.backupfile && r->in.backupfile->string) { + + DEBUG(8,( "_eventlog_ClearEventLogW: Using [%s] as the backup " + "file name for log [%s].\n", + r->in.backupfile->string, info->logname ) ); + } + + /* check for WRITE access to the file */ + + if ( !(info->access_granted & SEC_FILE_WRITE_DATA) ) + return NT_STATUS_ACCESS_DENIED; + + /* Force a close and reopen */ + + elog_close_tdb( info->etdb, True ); + become_root(); + info->etdb = elog_open_tdb( info->logname, True, False ); + unbecome_root(); + + if ( !info->etdb ) + return NT_STATUS_ACCESS_DENIED; + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_CloseEventLog + ********************************************************************/ + +NTSTATUS _eventlog_CloseEventLog(struct pipes_struct * p, + struct eventlog_CloseEventLog *r) +{ + NTSTATUS status; + + status = elog_close( p, r->in.handle ); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + ZERO_STRUCTP(r->out.handle); + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_ReadEventLogW + ********************************************************************/ + +NTSTATUS _eventlog_ReadEventLogW(struct pipes_struct *p, + struct eventlog_ReadEventLogW *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + int bytes_left, record_number; + uint32_t elog_read_type, elog_read_dir; + + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + info->flags = r->in.flags; + bytes_left = r->in.number_of_bytes; + + if (!info->etdb) { + return NT_STATUS_ACCESS_DENIED; + } + + /* check for valid flags. Can't use the sequential and seek flags together */ + + elog_read_type = r->in.flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ); + elog_read_dir = r->in.flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ); + + if (r->in.flags == 0 || + elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) || + elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ)) + { + DEBUG(3,("_eventlog_ReadEventLogW: " + "Invalid flags [0x%08x] for ReadEventLog\n", + r->in.flags)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* a sequential read should ignore the offset */ + + if (elog_read_type & EVENTLOG_SEQUENTIAL_READ) { + record_number = info->current_record; + } else { + record_number = r->in.offset; + } + + if (r->in.number_of_bytes == 0) { + struct EVENTLOGRECORD *e; + e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb), + record_number); + if (!e) { + return NT_STATUS_END_OF_FILE; + } + *r->out.real_size = e->Length; + return NT_STATUS_BUFFER_TOO_SMALL; + } + + while (bytes_left > 0) { + + DATA_BLOB blob; + enum ndr_err_code ndr_err; + struct EVENTLOGRECORD *e; + + e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb), + record_number); + if (!e) { + break; + } + + ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, e, + (ndr_push_flags_fn_t)ndr_push_EVENTLOGRECORD); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(EVENTLOGRECORD, e); + } + + if (blob.length > r->in.number_of_bytes) { + *r->out.real_size = blob.length; + return NT_STATUS_BUFFER_TOO_SMALL; + } + + if (*r->out.sent_size + blob.length > r->in.number_of_bytes) { + break; + } + + bytes_left -= blob.length; + + if (info->flags & EVENTLOG_FORWARDS_READ) { + record_number++; + } else { + record_number--; + } + + /* update the eventlog record pointer */ + + info->current_record = record_number; + + memcpy(&r->out.data[*(r->out.sent_size)], + blob.data, blob.length); + *(r->out.sent_size) += blob.length; + } + + if (r->in.offset == 0 && record_number == 0 && *r->out.sent_size == 0) { + return NT_STATUS_END_OF_FILE; + } + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_GetOldestRecord + ********************************************************************/ + +NTSTATUS _eventlog_GetOldestRecord(struct pipes_struct *p, + struct eventlog_GetOldestRecord *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + + if (info == NULL) { + return NT_STATUS_INVALID_HANDLE; + } + + if ( !( get_oldest_entry_hook( info ) ) ) + return NT_STATUS_ACCESS_DENIED; + + *r->out.oldest_entry = info->oldest_entry; + + return NT_STATUS_OK; +} + +/******************************************************************** +_eventlog_GetNumRecords + ********************************************************************/ + +NTSTATUS _eventlog_GetNumRecords(struct pipes_struct *p, + struct eventlog_GetNumRecords *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + + if (info == NULL) { + return NT_STATUS_INVALID_HANDLE; + } + + if ( !( get_num_records_hook( info ) ) ) + return NT_STATUS_ACCESS_DENIED; + + *r->out.number = info->num_records; + + return NT_STATUS_OK; +} + +NTSTATUS _eventlog_BackupEventLogW(struct pipes_struct *p, struct eventlog_BackupEventLogW *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/******************************************************************** +_eventlog_GetLogInformation + ********************************************************************/ + +NTSTATUS _eventlog_GetLogInformation(struct pipes_struct *p, + struct eventlog_GetLogInformation *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); + struct EVENTLOG_FULL_INFORMATION f; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + if (r->in.level != 0) { + return NT_STATUS_INVALID_LEVEL; + } + + *r->out.bytes_needed = 4; + + if (r->in.buf_size < 4) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + /* FIXME: this should be retrieved from the handle */ + f.full = false; + + ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &f, + (ndr_push_flags_fn_t)ndr_push_EVENTLOG_FULL_INFORMATION); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(EVENTLOG_FULL_INFORMATION, &f); + } + + memcpy(r->out.buffer, blob.data, 4); + + return NT_STATUS_OK; +} + +/******************************************************************** +_eventlog_FlushEventLog + ********************************************************************/ + +NTSTATUS _eventlog_FlushEventLog(struct pipes_struct *p, + struct eventlog_FlushEventLog *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + return NT_STATUS_ACCESS_DENIED; +} + +/******************************************************************** + ********************************************************************/ + +static NTSTATUS evlog_report_to_record(TALLOC_CTX *mem_ctx, + const struct eventlog_ReportEventW *r, + const char *logname, + struct EVENTLOGRECORD *e) +{ + uint32_t i; + ZERO_STRUCTP(e); + + e->TimeGenerated = r->in.timestamp; + e->TimeWritten = time(NULL); + e->EventID = r->in.event_id; + e->EventType = r->in.event_type; + e->NumStrings = r->in.num_of_strings; + e->EventCategory = r->in.event_category; + e->ReservedFlags = r->in.flags; + e->DataLength = r->in.data_size; + e->SourceName = talloc_strdup(mem_ctx, logname); + NT_STATUS_HAVE_NO_MEMORY(e->SourceName); + if (r->in.servername->string) { + e->Computername = r->in.servername->string; + } else { + e->Computername = talloc_strdup(mem_ctx, ""); + NT_STATUS_HAVE_NO_MEMORY(e->Computername); + } + if (r->in.user_sid) { + e->UserSid = *r->in.user_sid; + } + e->Strings = talloc_array(mem_ctx, const char *, e->NumStrings); + NT_STATUS_HAVE_NO_MEMORY(e->Strings); + + for (i=0; i < e->NumStrings; i++) { + e->Strings[i] = talloc_strdup(e->Strings, + r->in.strings[i]->string); + NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]); + } + e->Data = r->in.data; + + return NT_STATUS_OK; +} + +/******************************************************************** +_eventlog_ReportEventW + ********************************************************************/ + +NTSTATUS _eventlog_ReportEventW(struct pipes_struct *p, + struct eventlog_ReportEventW *r) +{ + NTSTATUS status; + struct EVENTLOGRECORD record; + + EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + status = evlog_report_to_record(p->mem_ctx, r, info->logname, &record); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = evlog_push_record(p->mem_ctx, + ELOG_TDB_CTX(info->etdb), + &record, + r->out.record_number); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +/******************************************************************** + ********************************************************************/ + +NTSTATUS _eventlog_DeregisterEventSource(struct pipes_struct *p, + struct eventlog_DeregisterEventSource *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ChangeNotify(struct pipes_struct *p, + struct eventlog_ChangeNotify *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_RegisterEventSourceW(struct pipes_struct *p, + struct eventlog_RegisterEventSourceW *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_OpenBackupEventLogW(struct pipes_struct *p, + struct eventlog_OpenBackupEventLogW *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ClearEventLogA(struct pipes_struct *p, + struct eventlog_ClearEventLogA *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_BackupEventLogA(struct pipes_struct *p, + struct eventlog_BackupEventLogA *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_OpenEventLogA(struct pipes_struct *p, + struct eventlog_OpenEventLogA *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_RegisterEventSourceA(struct pipes_struct *p, + struct eventlog_RegisterEventSourceA *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_OpenBackupEventLogA(struct pipes_struct *p, + struct eventlog_OpenBackupEventLogA *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ReadEventLogA(struct pipes_struct *p, + struct eventlog_ReadEventLogA *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ReportEventA(struct pipes_struct *p, + struct eventlog_ReportEventA *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_RegisterClusterSvc(struct pipes_struct *p, + struct eventlog_RegisterClusterSvc *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_DeregisterClusterSvc(struct pipes_struct *p, + struct eventlog_DeregisterClusterSvc *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_WriteClusterEvents(struct pipes_struct *p, + struct eventlog_WriteClusterEvents *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ReportEventAndSourceW(struct pipes_struct *p, + struct eventlog_ReportEventAndSourceW *r) +{ + p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS eventlog__op_init_server(struct dcesrv_context *dce_ctx, + const struct dcesrv_endpoint_server *ep_server); + +#define DCESRV_INTERFACE_EVENTLOG_INIT_SERVER \ + eventlog_init_server + +static NTSTATUS eventlog_init_server(struct dcesrv_context *dce_ctx, + const struct dcesrv_endpoint_server *ep_server) +{ + struct messaging_context *msg_ctx = global_messaging_context(); + bool ok; + + ok = eventlog_init_winreg(msg_ctx); + if (!ok) { + return NT_STATUS_UNSUCCESSFUL; + } + + return eventlog__op_init_server(dce_ctx, ep_server); +} + +/* include the generated boilerplate */ +#include "librpc/gen_ndr/ndr_eventlog_scompat.c" diff --git a/source3/rpc_server/eventlog/srv_eventlog_reg.c b/source3/rpc_server/eventlog/srv_eventlog_reg.c new file mode 100644 index 0000000..513dd0f --- /dev/null +++ b/source3/rpc_server/eventlog/srv_eventlog_reg.c @@ -0,0 +1,267 @@ +/* + * Unix SMB/CIFS implementation. + * + * Eventlog RPC server keys initialization + * + * Copyright (c) 2005 Marcin Krzysztof Porwit + * Copyright (c) 2005 Brian Moran + * Copyright (c) 2005 Gerald (Jerry) Carter + * Copyright (c) 2011 Andreas Schneider <asn@samba.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "rpc_client/cli_winreg_int.h" +#include "rpc_client/cli_winreg.h" +#include "rpc_server/eventlog/srv_eventlog_reg.h" +#include "auth.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_REGISTRY + +#define TOP_LEVEL_EVENTLOG_KEY "SYSTEM\\CurrentControlSet\\Services\\Eventlog" + +bool eventlog_init_winreg(struct messaging_context *msg_ctx) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + uint32_t uiMaxSize = 0x00080000; + uint32_t uiRetention = 0x93A80; + const char **elogs = lp_eventlog_list(); + const char **subkeys = NULL; + uint32_t num_subkeys = 0; + uint32_t i; + char *key = NULL; + NTSTATUS status; + WERROR result = WERR_OK; + bool ok = false; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return false; + } + + DEBUG(3, ("Initialise the eventlog registry keys if needed.\n")); + + key = talloc_strdup(tmp_ctx, TOP_LEVEL_EVENTLOG_KEY); + + status = dcerpc_winreg_int_hklm_openkey(tmp_ctx, + get_session_info_system(), + msg_ctx, + &h, + key, + false, + access_mask, + &hive_hnd, + &key_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg: Could not open %s - %s\n", + key, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg: Could not open %s - %s\n", + key, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_enum_keys(tmp_ctx, + h, + &key_hnd, + &num_subkeys, + &subkeys, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg: Could enum keys at %s - %s\n", + key, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg: Could enum keys at %s - %s\n", + key, win_errstr(result))); + goto done; + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + + /* create subkeys if they don't exist */ + while (elogs && *elogs) { + enum winreg_CreateAction action = REG_ACTION_NONE; + char *evt_tdb = NULL; + struct winreg_String wkey; + struct winreg_String wkeyclass; + bool skip = false; + + for (i = 0; i < num_subkeys; i++) { + if (strequal(subkeys[i], *elogs)) { + skip = true; + } + } + + if (skip) { + elogs++; + continue; + } + + ZERO_STRUCT(key_hnd); + ZERO_STRUCT(wkey); + + wkey.name = talloc_asprintf(tmp_ctx, "%s\\%s", key, *elogs); + if (wkey.name == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + ZERO_STRUCT(wkeyclass); + wkeyclass.name = ""; + + + status = dcerpc_winreg_CreateKey(h, + tmp_ctx, + &hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + h, + &key_hnd, + "MaxSize", + uiMaxSize, + &result); + + status = dcerpc_winreg_set_dword(tmp_ctx, + h, + &key_hnd, + "Retention", + uiRetention, + &result); + + status = dcerpc_winreg_set_sz(tmp_ctx, + h, + &key_hnd, + "PrimaryModule", + *elogs, + &result); + + evt_tdb = talloc_asprintf(tmp_ctx, + "%%SystemRoot%%\\system32\\config\\%s.tdb", + *elogs); + if (evt_tdb == NULL) { + goto done; + } + status = dcerpc_winreg_set_expand_sz(tmp_ctx, + h, + &key_hnd, + "File", + evt_tdb, + &result); + TALLOC_FREE(evt_tdb); + + status = dcerpc_winreg_add_multi_sz(tmp_ctx, + h, + &key_hnd, + "Sources", + *elogs, + &result); + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + + /* sub-subkeys */ + { + uint32_t uiCategoryCount = 0x00000007; + + wkey.name = talloc_asprintf(tmp_ctx, + "%s\\%s", + wkey.name, *elogs); + if (wkey.name == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + status = dcerpc_winreg_CreateKey(h, + tmp_ctx, + &hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + h, + &key_hnd, + "CategoryCount", + uiCategoryCount, + &result); + + status = dcerpc_winreg_set_expand_sz(tmp_ctx, + h, + &key_hnd, + "CategoryMessageFile", + "%SystemRoot%\\system32\\eventlog.dll", + &result); + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + } + + elogs++; + } /* loop */ + + ok = true; +done: + TALLOC_FREE(tmp_ctx); + return ok; +} + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/eventlog/srv_eventlog_reg.h b/source3/rpc_server/eventlog/srv_eventlog_reg.h new file mode 100644 index 0000000..02c2792 --- /dev/null +++ b/source3/rpc_server/eventlog/srv_eventlog_reg.h @@ -0,0 +1,29 @@ +/* + * Unix SMB/CIFS implementation. + * + * WINREG client routines + * + * Copyright (c) 2011 Andreas Schneider <asn@samba.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SRV_EVENTLOG_REG_H +#define SRV_EVENTLOG_REG_H + +bool eventlog_init_winreg(struct messaging_context *msg_ctx); + +#endif /* SRV_EVENTLOG_REG_H */ + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ |