From 0bf72b6e330a76bee502cb36c1cb80c46d47d33c Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Thu, 6 Oct 2005 17:48:03 +0000 Subject: r10781: merging eventlog and svcctl code from trunk (This used to be commit f10aa9fb84bfac4f1a22b74d63999668700ffaac) --- source3/Makefile.in | 5 +- source3/include/rpc_eventlog.h | 8 + source3/include/rpc_misc.h | 2 +- source3/include/rpc_svcctl.h | 17 - source3/param/loadparm.c | 37 +- source3/registry/reg_eventlog.c | 273 ++++---- source3/registry/reg_frontend.c | 8 +- source3/rpc_parse/parse_misc.c | 4 + source3/rpc_parse/parse_ntsvcs.c | 2 +- source3/rpc_server/srv_eventlog_lib.c | 620 +++++++++++++++++ source3/rpc_server/srv_eventlog_nt.c | 1225 ++++++++++++++++----------------- source3/rpc_server/srv_ntsvcs_nt.c | 6 +- source3/rpc_server/srv_reg_nt.c | 6 +- source3/rpc_server/srv_svcctl_nt.c | 19 +- source3/services/services_db.c | 238 ++++++- source3/services/svc_rcinit.c | 148 ---- source3/services/svc_wins.c | 66 ++ 17 files changed, 1641 insertions(+), 1043 deletions(-) create mode 100644 source3/rpc_server/srv_eventlog_lib.c create mode 100644 source3/services/svc_wins.c (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index 07c348bd84..4310f51bd5 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -283,7 +283,8 @@ RPC_WKS_OBJ = rpc_server/srv_wkssvc.o rpc_server/srv_wkssvc_nt.o RPC_SVCCTL_OBJ = rpc_server/srv_svcctl.o rpc_server/srv_svcctl_nt.o \ services/svc_spoolss.o services/svc_rcinit.o services/services_db.o \ - services/svc_netlogon.o services/svc_winreg.o + services/svc_netlogon.o services/svc_winreg.o \ + services/svc_wins.o RPC_NTSVCS_OBJ = rpc_server/srv_ntsvcs.o rpc_server/srv_ntsvcs_nt.o @@ -291,7 +292,7 @@ RPC_DFS_OBJ = rpc_server/srv_dfs.o rpc_server/srv_dfs_nt.o RPC_SPOOLSS_OBJ = rpc_server/srv_spoolss.o rpc_server/srv_spoolss_nt.o -RPC_EVENTLOG_OBJ = rpc_server/srv_eventlog.o rpc_server/srv_eventlog_nt.o +RPC_EVENTLOG_OBJ = rpc_server/srv_eventlog.o rpc_server/srv_eventlog_nt.o rpc_server/srv_eventlog_lib.o RPC_PIPE_OBJ = rpc_server/srv_pipe_hnd.o rpc_server/srv_util.o \ rpc_server/srv_pipe.o rpc_server/srv_lsa_hnd.o diff --git a/source3/include/rpc_eventlog.h b/source3/include/rpc_eventlog.h index 7ce1199b21..9f968fb54e 100644 --- a/source3/include/rpc_eventlog.h +++ b/source3/include/rpc_eventlog.h @@ -46,6 +46,14 @@ #define EVENTLOG_AUDIT_SUCCESS 0x0008 #define EVENTLOG_AUDIT_FAILURE 0x0010 +/* Defines for TDB keys */ +#define VN_oldest_entry "INFO/oldest_entry" +#define VN_next_record "INFO/next_record" +#define VN_version "INFO/version" +#define VN_maxsize "INFO/maxsize" +#define VN_retention "INFO/retention" + +#define EVENTLOG_DATABASE_VERSION_V1 1 /***********************************/ diff --git a/source3/include/rpc_misc.h b/source3/include/rpc_misc.h index e5d91c1b63..091ba3395e 100644 --- a/source3/include/rpc_misc.h +++ b/source3/include/rpc_misc.h @@ -27,7 +27,7 @@ #define SMB_RPC_INTERFACE_VERSION 1 #define PRS_POINTER_CAST BOOL (*)(const char*, prs_struct*, int, void*) -enum unistr2_term_codes { UNI_FLAGS_NONE = 0, UNI_STR_TERMINATE = 1, UNI_MAXLEN_TERMINATE = 2, UNI_BROKEN_NON_NULL = 3 }; +enum unistr2_term_codes { UNI_FLAGS_NONE = 0, UNI_STR_TERMINATE = 1, UNI_MAXLEN_TERMINATE = 2, UNI_BROKEN_NON_NULL = 3, UNI_STR_DBLTERMINATE = 4 }; diff --git a/source3/include/rpc_svcctl.h b/source3/include/rpc_svcctl.h index 443a6588a6..f5ad2afa1c 100644 --- a/source3/include/rpc_svcctl.h +++ b/source3/include/rpc_svcctl.h @@ -175,23 +175,6 @@ typedef struct { SC_ACTION *actions; } SERVICE_FAILURE_ACTIONS; -typedef struct Service_info_struct { - uint32 type; /* should be SVC_HANDLE_IS_SERVICE */ - pstring servicename; /* the name of the service */ - pstring servicetype; /* internal or external */ - pstring filename; /* what file name we can find this in, - as well as the "index" for what the - service name is */ - pstring provides; - pstring dependencies; - pstring shouldstart; - pstring shouldstop; - pstring requiredstart; - pstring requiredstop; - pstring shortdescription; - pstring description; -} Service_info; - /* * dispatch table of functions to handle the =ServiceControl API */ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 0a4f0556ae..126d70939c 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -183,13 +183,6 @@ typedef struct char *szAddShareCommand; char *szChangeShareCommand; char *szDeleteShareCommand; - char *szEventLogOpenCommand; - char *szEventLogReadCommand; - char *szEventLogClearCommand; - char *szEventLogNumRecordsCommand; - char *szEventLogOldestRecordCommand; - char *szEventLogCloseCommand; - char *szEventLogControlCommand; char **szEventLogs; char *szGuestaccount; char *szManglingMethod; @@ -608,7 +601,6 @@ static BOOL handle_netbios_scope( int snum, const char *pszParmValue, char **ptr static BOOL handle_charset( int snum, const char *pszParmValue, char **ptr ); static BOOL handle_acl_compatibility( int snum, const char *pszParmValue, char **ptr); static BOOL handle_printing( int snum, const char *pszParmValue, char **ptr); -static BOOL handle_eventlog( int snum, const char *pszParmValue, char **ptr); static void set_server_role(void); static void set_default_server_announce_type(void); @@ -1154,13 +1146,6 @@ static struct parm_struct parm_table[] = { {"delete share command", P_STRING, P_GLOBAL, &Globals.szDeleteShareCommand, NULL, NULL, FLAG_ADVANCED}, {N_("EventLog Options"), P_SEP, P_SEPARATOR}, - {"eventlog open command", P_STRING, P_GLOBAL, &Globals.szEventLogOpenCommand, handle_eventlog, NULL, FLAG_ADVANCED}, - {"eventlog read command", P_STRING, P_GLOBAL, &Globals.szEventLogReadCommand, handle_eventlog, NULL, FLAG_ADVANCED}, - {"eventlog clear command", P_STRING, P_GLOBAL, &Globals.szEventLogClearCommand, handle_eventlog, NULL, FLAG_ADVANCED}, - {"eventlog num records command", P_STRING, P_GLOBAL, &Globals.szEventLogNumRecordsCommand, handle_eventlog, NULL, FLAG_ADVANCED}, - {"eventlog oldest record command", P_STRING, P_GLOBAL, &Globals.szEventLogOldestRecordCommand, handle_eventlog, NULL, FLAG_ADVANCED}, - {"eventlog close command", P_STRING, P_GLOBAL, &Globals.szEventLogCloseCommand, handle_eventlog, NULL, FLAG_ADVANCED}, - {"eventlog control command", P_STRING, P_GLOBAL, &Globals.szEventLogControlCommand, handle_eventlog, NULL, FLAG_ADVANCED}, {"eventlog list", P_LIST, P_GLOBAL, &Globals.szEventLogs, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE}, {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL, NULL, FLAG_HIDE}, @@ -1581,14 +1566,6 @@ static void init_globals(void) string_set(&Globals.szCupsServer, ""); string_set(&Globals.szIPrintServer, ""); - string_set(&Globals.szEventLogOpenCommand, ""); - string_set(&Globals.szEventLogReadCommand, ""); - string_set(&Globals.szEventLogClearCommand, ""); - string_set(&Globals.szEventLogNumRecordsCommand, ""); - string_set(&Globals.szEventLogOldestRecordCommand, ""); - string_set(&Globals.szEventLogCloseCommand, ""); - string_set(&Globals.szEventLogControlCommand, ""); - Globals.winbind_cache_time = 300; /* 5 minutes */ Globals.bWinbindEnumUsers = True; Globals.bWinbindEnumGroups = True; @@ -1806,14 +1783,6 @@ FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand) FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand) FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand) -FN_GLOBAL_STRING(lp_eventlog_open_cmd, &Globals.szEventLogOpenCommand) -FN_GLOBAL_STRING(lp_eventlog_read_cmd, &Globals.szEventLogReadCommand) -FN_GLOBAL_STRING(lp_eventlog_clear_cmd, &Globals.szEventLogClearCommand) -FN_GLOBAL_STRING(lp_eventlog_num_records_cmd, &Globals.szEventLogNumRecordsCommand) -FN_GLOBAL_STRING(lp_eventlog_oldest_record_cmd, &Globals.szEventLogOldestRecordCommand) -FN_GLOBAL_STRING(lp_eventlog_close_cmd, &Globals.szEventLogCloseCommand) -FN_GLOBAL_STRING(lp_eventlog_control_cmd, &Globals.szEventLogControlCommand) - FN_GLOBAL_LIST(lp_eventlog_list, &Globals.szEventLogs) FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios) @@ -2908,11 +2877,7 @@ static BOOL handle_charset(int snum, const char *pszParmValue, char **ptr) return True; } -static BOOL handle_eventlog(int snum, const char *pszParmValue, char **ptr) -{ - string_set(ptr, pszParmValue); - return True; -} + static BOOL handle_workgroup(int snum, const char *pszParmValue, char **ptr) { diff --git a/source3/registry/reg_eventlog.c b/source3/registry/reg_eventlog.c index bed9e1d59a..204c4c6e1c 100644 --- a/source3/registry/reg_eventlog.c +++ b/source3/registry/reg_eventlog.c @@ -2,6 +2,7 @@ * Unix SMB/CIFS implementation. * Virtual Windows Registry Layer * Copyright (C) Marcin Krzysztof Porwit 2005, + * Copyright (C) Brian Moran 2005. * Copyright (C) Gerald (Jerry) Carter 2005. * * This program is free software; you can redistribute it and/or modify @@ -18,171 +19,135 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + #include "includes.h" /********************************************************************** - Enumerate registry subkey names given a registry path. + for an eventlog, add in the default values *********************************************************************/ -static int elog_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys ) +BOOL eventlog_init_keys( void ) { - const char **elogs = lp_eventlog_list(); - char *path; - int i; - - path = reg_remaining_path( key + strlen(KEY_EVENTLOG) ); - - DEBUG(10,("elog_fetch_keys: entire key => [%s], subkey => [%s]\n", - key, path)); - - if ( !path ) { - - if ( !elogs || !*elogs ) - return 0; - - DEBUG(10,("elog_fetch_keys: Adding eventlog subkeys from smb.conf\n")); - - for ( i=0; elogs[i]; i++ ) - regsubkey_ctr_addkey( subkeys, elogs[i] ); - - return regsubkey_ctr_numkeys( subkeys ); - } - - /* if we get / then we don't add anymore */ - - if ( strchr( path, '\\' ) ) { - DEBUG(10,("elog_fetch_keys: Not adding subkey to %s\n",path)); - return 0; - } - - /* add in a subkey with the same name as the eventlog... */ - - DEBUG(10,("elog_fetch_keys: Looking to add eventlog subkey to %s\n",path)); - - /* look for a match */ - - if ( !elogs ) - return -1; - - for ( i=0; elogs[i]; i++ ) { - /* just verify that the keyname is a valid log name */ - if ( strequal( path, elogs[i] ) ) - return 0; - } - - return -1; -} - -/********************************************************************** - Enumerate registry values given a registry path. - Caller is responsible for freeing memory -*********************************************************************/ - -static int elog_fetch_values( const char *key, REGVAL_CTR *values ) -{ - char *path; - uint32 uiDisplayNameId, uiMaxSize, uiRetention; - char *base, *new_path; + /* Find all of the eventlogs, add keys for each of them */ + const char **elogs = lp_eventlog_list( ); + pstring evtlogpath; + REGSUBKEY_CTR *subkeys; + REGVAL_CTR *values; + uint32 uiDisplayNameId; + uint32 uiMaxSize; + uint32 uiRetention; + uint32 uiCategoryCount; UNISTR2 data; - - DEBUG(10,("elog_fetch_values: key=>[%s]\n", key)); - - path = reg_remaining_path( key + strlen(KEY_EVENTLOG) ); - - /* check to see if we are dealing with the top level key */ - - if ( !path ) - return regdb_fetch_values( KEY_EVENTLOG, values ); - - /* deal with a log name */ - - reg_split_path( path, &base, &new_path ); - - /* MaxSize is limited to 0xFFFF0000 (UINT_MAX - USHRT_MAX) as per MSDN documentation */ - - - if ( !new_path ) { - - /* try to fetch from the registry */ - - regdb_fetch_values( key, values ); - - /* just verify one of the important keys. If this - fails, then assume the values have not been initialized */ - - if ( regval_ctr_getvalue( values, "Retention" ) ) - return regval_ctr_numvals( values ); - - /* hard code some initial values */ - - uiDisplayNameId = 0x00000100; - uiMaxSize = 0x00080000; - uiRetention = 0x93A80; - - regval_ctr_addvalue( values, "MaxSize", REG_DWORD, (char*)&uiMaxSize, sizeof(uint32)); - regval_ctr_addvalue( values, "Retention", REG_DWORD, (char *)&uiRetention, sizeof(uint32)); - - init_unistr2( &data, base, UNI_STR_TERMINATE); - regval_ctr_addvalue( values, "PrimaryModule", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); - - init_unistr2( &data, base, UNI_STR_TERMINATE); - regval_ctr_addvalue( values, "Sources", REG_MULTI_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); - - /* store them for later updates. Complain if this fails but continue on */ - - if ( !regdb_store_values( key, values ) ) { - DEBUG(0,("elog_fetch_values: Failed to store initial values for log [%s]\n", - base )); + + while ( elogs && *elogs ) { + if ( !( subkeys = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR ) ) ) { + DEBUG( 0, ( "talloc() failure!\n" ) ); + return False; } - - return regval_ctr_numvals( values ); - } - -#if 0 - /* hmmm....what to do here? A subkey underneath the log name ? */ - - uiDisplayNameId = 0x07; - regval_ctr_addvalue( values, "CategoryCount", REG_DWORD, (char*)&uiDisplayNameId, sizeof(uint32) ); - - init_unistr2( &data, "%SystemRoot%\\system32\\eventlog.dll", UNI_STR_TERMINATE); - regval_ctr_addvalue( values, "CategoryMessageFile", REG_EXPAND_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); -#endif - - return regval_ctr_numvals( values ); -} + regdb_fetch_keys( KEY_EVENTLOG, subkeys ); + regsubkey_ctr_addkey( subkeys, *elogs ); + if ( !regdb_store_keys( KEY_EVENTLOG, subkeys ) ) + return False; + TALLOC_FREE( subkeys ); + + /* add in the key of form KEY_EVENTLOG/Application */ + DEBUG( 5, + ( "Adding key of [%s] to path of [%s]\n", *elogs, + KEY_EVENTLOG ) ); + + slprintf( evtlogpath, sizeof( evtlogpath ) - 1, "%s\\%s", + KEY_EVENTLOG, *elogs ); + /* add in the key of form KEY_EVENTLOG/Application/Application */ + DEBUG( 5, + ( "Adding key of [%s] to path of [%s]\n", *elogs, + evtlogpath ) ); + if ( !( subkeys = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR ) ) ) { + DEBUG( 0, ( "talloc() failure!\n" ) ); + return False; + } + regdb_fetch_keys( evtlogpath, subkeys ); + regsubkey_ctr_addkey( subkeys, *elogs ); -/********************************************************************** -*********************************************************************/ + if ( !regdb_store_keys( evtlogpath, subkeys ) ) + return False; + TALLOC_FREE( subkeys ); -static BOOL elog_store_keys( const char *key, REGSUBKEY_CTR *subkeys ) -{ - /* cannot create any subkeys here */ - - return False; -} + /* now add the values to the KEY_EVENTLOG/Application form key */ + if ( !( values = TALLOC_ZERO_P( NULL, REGVAL_CTR ) ) ) { + DEBUG( 0, ( "talloc() failure!\n" ) ); + return False; + } + DEBUG( 5, + ( "Storing values to eventlog path of [%s]\n", + evtlogpath ) ); + regdb_fetch_values( evtlogpath, values ); + + if ( !regval_ctr_key_exists( values, "MaxSize" ) ) { + /* assume we have none, add them all */ + + /* hard code some initial values */ + + uiDisplayNameId = 0x00000100; + uiMaxSize = 0x00080000; + uiRetention = 0x93A80; + + regval_ctr_addvalue( values, "MaxSize", REG_DWORD, + ( char * ) &uiMaxSize, + sizeof( uint32 ) ); + regval_ctr_addvalue( values, "Retention", REG_DWORD, + ( char * ) &uiRetention, + sizeof( uint32 ) ); + init_unistr2( &data, *elogs, UNI_STR_TERMINATE ); + regval_ctr_addvalue( values, "PrimaryModule", REG_SZ, + ( char * ) data.buffer, + data.uni_str_len * + sizeof( uint16 ) ); + init_unistr2( &data, *elogs, UNI_STR_TERMINATE ); + + regval_ctr_addvalue( values, "Sources", REG_MULTI_SZ, + ( char * ) data.buffer, + data.uni_str_len * + sizeof( uint16 ) ); + regdb_store_values( evtlogpath, values ); -/********************************************************************** - Allow storing of particular values related to eventlog operation. -*********************************************************************/ + } -static BOOL elog_store_value( const char *key, REGVAL_CTR *values ) -{ - /* the client had to have a valid handle to get here - so just hand off to the registry tdb */ - - return regdb_store_values( key, values ); -} + TALLOC_FREE( values ); -/******************************************************************** - Table of function pointers for accessing eventlog data - *******************************************************************/ - -REGISTRY_OPS eventlog_ops = { - elog_fetch_keys, - elog_fetch_values, - elog_store_keys, - elog_store_value, - NULL -}; + /* now do the values under KEY_EVENTLOG/Application/Application */ + slprintf( evtlogpath, sizeof( evtlogpath ) - 1, "%s\\%s\\%s", + KEY_EVENTLOG, *elogs, *elogs ); + if ( !( values = TALLOC_ZERO_P( NULL, REGVAL_CTR ) ) ) { + DEBUG( 0, ( "talloc() failure!\n" ) ); + return False; + } + DEBUG( 5, + ( "Storing values to eventlog path of [%s]\n", + evtlogpath ) ); + regdb_fetch_values( evtlogpath, values ); + if ( !regval_ctr_key_exists( values, "CategoryCount" ) ) { + + /* hard code some initial values */ + + uiCategoryCount = 0x00000007; + regval_ctr_addvalue( values, "CategoryCount", + REG_DWORD, + ( char * ) &uiCategoryCount, + sizeof( uint32 ) ); + init_unistr2( &data, + "%SystemRoot%\\system32\\eventlog.dll", + UNI_STR_TERMINATE ); + + regval_ctr_addvalue( values, "CategoryMessageFile", + REG_EXPAND_SZ, + ( char * ) data.buffer, + data.uni_str_len * + sizeof( uint16 ) ); + regdb_store_values( evtlogpath, values ); + } + TALLOC_FREE( values ); + elogs++; + } + return True; +} diff --git a/source3/registry/reg_frontend.c b/source3/registry/reg_frontend.c index f41c5885bc..f5284e9e88 100644 --- a/source3/registry/reg_frontend.c +++ b/source3/registry/reg_frontend.c @@ -38,7 +38,6 @@ REGISTRY_HOOK reg_hooks[] = { { KEY_PRINTING, &printing_ops }, { KEY_PRINTING_2K, &printing_ops }, { KEY_PRINTING_PORTS, &printing_ops }, - { KEY_EVENTLOG, &eventlog_ops }, { KEY_SHARES, &shares_reg_ops }, #endif { NULL, NULL } @@ -128,13 +127,10 @@ BOOL init_registry( void ) if ( DEBUGLEVEL >= 20 ) reghook_dump_cache(20); - /* inform the external eventlog machinery of the change */ - - eventlog_refresh_external_parameters( get_root_nt_token() ); - - /* add any services keys */ + /* add any keys for other services */ svcctl_init_keys(); + eventlog_init_keys(); return True; } diff --git a/source3/rpc_parse/parse_misc.c b/source3/rpc_parse/parse_misc.c index 8bbb97f226..26da87b280 100644 --- a/source3/rpc_parse/parse_misc.c +++ b/source3/rpc_parse/parse_misc.c @@ -830,6 +830,8 @@ void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags) if (buf) { /* We always null terminate the copy. */ len = strlen(buf) + 1; + if ( flags == UNI_STR_DBLTERMINATE ) + len++; } else { /* no buffer -- nothing to do */ str->uni_max_len = 0; @@ -859,6 +861,8 @@ void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags) if (flags == UNI_STR_TERMINATE || flags == UNI_MAXLEN_TERMINATE) { num_chars++; } + if ( flags == UNI_STR_DBLTERMINATE ) + num_chars += 2; } str->uni_max_len = num_chars; diff --git a/source3/rpc_parse/parse_ntsvcs.c b/source3/rpc_parse/parse_ntsvcs.c index f2e4456025..24bf3a455b 100644 --- a/source3/rpc_parse/parse_ntsvcs.c +++ b/source3/rpc_parse/parse_ntsvcs.c @@ -79,7 +79,7 @@ BOOL ntsvcs_io_q_get_device_list_size(const char *desc, NTSVCS_Q_GET_DEVICE_LIST if ( !prs_pointer("devicename", ps, depth, (void**)&q_u->devicename, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2) ) return False; - if( !prs_align(ps) ) + if ( !prs_align(ps) ) return False; if ( !prs_uint32("flags", ps, depth, &q_u->flags) ) diff --git a/source3/rpc_server/srv_eventlog_lib.c b/source3/rpc_server/srv_eventlog_lib.c new file mode 100644 index 0000000000..a8c1ad51d2 --- /dev/null +++ b/source3/rpc_server/srv_eventlog_lib.c @@ -0,0 +1,620 @@ + +/* + * Unix SMB/CIFS implementation. + * Eventlog utility routines + * Copyright (C) Marcin Krzysztof Porwit 2005, + * Copyright (C) Gerald (Jerry) Carter 2005. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + + +/**************************************************************** +Init an Eventlog TDB, and return it. If null, something bad happened. +****************************************************************/ +TDB_CONTEXT *init_eventlog_tdb( char *tdbfilename ) +{ + TDB_CONTEXT *the_tdb; + + unlink( tdbfilename ); + + the_tdb = + tdb_open_log( tdbfilename, 0, TDB_DEFAULT, O_RDWR | O_CREAT, + 0664 ); + if ( the_tdb == NULL ) { + DEBUG( 1, ( "Can't open tdb for [%s]\n", tdbfilename ) ); + return NULL; + } + tdb_store_int32( the_tdb, VN_oldest_entry, 1 ); + tdb_store_int32( the_tdb, VN_next_record, 1 ); + + /* initialize with defaults, copy real values in here from registry */ + + tdb_store_int32( the_tdb, VN_maxsize, 0x80000 ); + tdb_store_int32( the_tdb, VN_retention, 0x93A80 ); + + tdb_store_int32( the_tdb, VN_version, EVENTLOG_DATABASE_VERSION_V1 ); + return the_tdb; +} + +/* make the tdb file name for an event log, given destination buffer and size */ +char *mk_tdbfilename( char *dest_buffer, char *eventlog_name, int size_dest ) +{ + if ( !dest_buffer ) + return NULL; + pstring ondisk_name; + + pstrcpy( ondisk_name, "EV" ); + pstrcat( ondisk_name, eventlog_name ); + pstrcat( ondisk_name, ".tdb" ); + + memset( dest_buffer, 0, size_dest ); + + /* BAD things could happen if the dest_buffer is not large enough... */ + if ( strlen( ondisk_name ) > size_dest ) { + DEBUG( 3, ( "Buffer not big enough for filename\n" ) ); + return NULL; + } + + strncpy( dest_buffer, ondisk_name, size_dest ); + + return dest_buffer; +} + + +/* count the number of bytes in the TDB */ + +/* Arg! Static Globals! */ + +static int eventlog_tdbcount; +static int eventlog_tdbsize; + +/* this function is used to count up the number of bytes in a particular TDB */ +int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data, + void *state ) +{ + eventlog_tdbsize += data.dsize; + eventlog_tdbcount++; + return 0; +} + +/* returns the size of the eventlog, and if MaxSize is a non-null ptr, puts + the MaxSize there. This is purely a way not to have yet another function that solely + reads the maxsize of the eventlog. Yeah, that's it. */ + +int eventlog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention ) +{ + if ( !tdb ) + return 0; + eventlog_tdbcount = 0; + eventlog_tdbsize = 0; + + tdb_traverse( tdb, eventlog_tdb_size_fn, NULL ); + + if ( MaxSize != NULL ) { + *MaxSize = tdb_fetch_int32( tdb, VN_maxsize ); + } + + if ( Retention != NULL ) { + *Retention = tdb_fetch_int32( tdb, VN_retention ); + } + + DEBUG( 1, + ( "eventlog size: [%d] for [%d] records\n", eventlog_tdbsize, + eventlog_tdbcount ) ); + return eventlog_tdbsize; +} + + +/* + Discard early event logs until we have enough for 'needed' bytes... + NO checking done beforehand to see that we actually need to do this, and + it's going to pluck records one-by-one. So, it's best to determine that this + needs to be done before doing it. + + Setting whack_by_date to True indicates that eventlogs falling outside of the + retention range need to go... + +*/ + +/* return True if we made enough room to accommodate needed bytes */ + +BOOL make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32 needed, + BOOL whack_by_date ) +{ + int start_record, i, new_start; + int end_record; + int nbytes, reclen, len, Retention, MaxSize; + + int tresv1, trecnum, timegen, timewr; + + TDB_DATA key, ret; + TALLOC_CTX *mem_ctx = NULL; + + time_t current_time, exp_time; + + /* discard some eventlogs */ + + /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos, + although records not necessarily guaranteed to have successive times */ + /* */ + mem_ctx = talloc_init( "make_way_for_eventlogs" ); /* Homage to BPG */ + + if ( mem_ctx == NULL ) + return False; /* can't allocate memory indicates bigger problems */ + /* lock */ + tdb_lock_bystring( the_tdb, VN_next_record, 1 ); + /* read */ + end_record = tdb_fetch_int32( the_tdb, VN_next_record ); + start_record = tdb_fetch_int32( the_tdb, VN_oldest_entry ); + Retention = tdb_fetch_int32( the_tdb, VN_retention ); + MaxSize = tdb_fetch_int32( the_tdb, VN_maxsize ); + + time( ¤t_time ); + + /* calculate ... */ + exp_time = current_time - Retention; /* discard older than exp_time */ + + /* todo - check for sanity in next_record */ + nbytes = 0; + + DEBUG( 3, + ( "MaxSize [%d] Retention [%d] Current Time [%d] exp_time [%d]\n", + MaxSize, Retention, (uint32)current_time, (uint32)exp_time ) ); + DEBUG( 3, + ( "Start Record [%d] End Record [%d]\n", start_record, + end_record ) ); + + for ( i = start_record; i < end_record; i++ ) { + /* read a record, add the amt to nbytes */ + key.dsize = sizeof( int32 ); + key.dptr = ( char * ) ( int32 * ) & i; + ret = tdb_fetch( the_tdb, key ); + if ( ret.dsize == 0 ) { + DEBUG( 8, + ( "Can't find a record for the key, record [%d]\n", + i ) ); + tdb_unlock_bystring( the_tdb, VN_next_record ); + return False; + } + nbytes += ret.dsize; /* note this includes overhead */ + + len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen, + &tresv1, &trecnum, &timegen, &timewr ); + DEBUG( 8, + ( "read record %d, record size is [%d], total so far [%d]\n", + i, reclen, nbytes ) ); + + SAFE_FREE( ret.dptr ); + + /* note that other servers may just stop writing records when the size limit + is reached, and there are no records older than 'retention'. This doesn't + like a very useful thing to do, so instead we whack (as in sleeps with the + fishes) just enough records to fit the what we need. This behavior could + be changed to 'match', if the need arises. */ + + if ( !whack_by_date && ( nbytes >= needed ) ) + break; /* done */ + if ( whack_by_date && ( timegen >= exp_time ) ) + break; /* done */ + } + + DEBUG( 3, + ( "nbytes [%d] needed [%d] start_record is [%d], should be set to [%d]\n", + nbytes, needed, start_record, i ) ); + /* todo - remove eventlog entries here and set starting record to start_record... */ + new_start = i; + if ( start_record != new_start ) { + for ( i = start_record; i < new_start; i++ ) { + key.dsize = sizeof( int32 ); + key.dptr = ( char * ) ( int32 * ) & i; + tdb_delete( the_tdb, key ); + } + + tdb_store_int32( the_tdb, VN_oldest_entry, new_start ); + } + tdb_unlock_bystring( the_tdb, VN_next_record ); + return True; +} + +/* + some hygiene for an eventlog - see how big it is, and then + calculate how many bytes we need to remove +*/ + +BOOL prune_eventlog( TDB_CONTEXT * tdb ) +{ + int MaxSize, Retention, CalcdSize; + + if ( !tdb ) { + DEBUG( 4, ( "No eventlog tdb handle\n" ) ); + return False; + } + + CalcdSize = eventlog_tdb_size( tdb, &MaxSize, &Retention ); + DEBUG( 3, + ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize, + MaxSize ) ); + + if ( CalcdSize > MaxSize ) { + return make_way_for_eventlogs( tdb, CalcdSize - MaxSize, + False ); + } + + return make_way_for_eventlogs( tdb, 0, True ); +} + +BOOL can_write_to_eventlog( TDB_CONTEXT * tdb, int32 needed ) +{ + int calcd_size; + int MaxSize, Retention; + + /* see if we can write to the eventlog -- do a policy enforcement */ + if ( !tdb ) + return False; /* tdb is null, so we can't write to it */ + + + if ( needed < 0 ) + return False; + MaxSize = 0; + Retention = 0; + + calcd_size = eventlog_tdb_size( tdb, &MaxSize, &Retention ); + + if ( calcd_size <= MaxSize ) + return True; /* you betcha */ + if ( calcd_size + needed < MaxSize ) + return True; + + if ( Retention == 0xffffffff ) { + return False; /* see msdn - we can't write no room, discard */ + } + /* + note don't have to test, but always good to show intent, in case changes needed + later + */ + + if ( Retention == 0x00000000 ) { + /* discard record(s) */ + /* todo - decide when to remove a bunch vs. just what we need... */ + return make_way_for_eventlogs( tdb, calcd_size - MaxSize, + True ); + } + + return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False ); +} + +TDB_CONTEXT *open_eventlog_tdb( char *tdbfilename ) +{ + TDB_CONTEXT *the_tdb; + + the_tdb = + tdb_open_log( tdbfilename, 0, TDB_DEFAULT, O_RDWR | O_CREAT, + 0664 ); + if ( the_tdb == NULL ) { + return init_eventlog_tdb( tdbfilename ); + } + if ( EVENTLOG_DATABASE_VERSION_V1 != + tdb_fetch_int32( the_tdb, VN_version ) ) { + tdb_close( the_tdb ); + return init_eventlog_tdb( tdbfilename ); + } + return the_tdb; +} + +/* write an eventlog entry. Note that we have to lock, read next eventlog, increment, write, write the record, unlock */ + +/* coming into this, ee has the eventlog record, and the auxilliary date (computer name, etc.) + filled into the other structure. Before packing into a record, this routine will calc the + appropriate padding, etc., and then blast out the record in a form that can be read back in */ +int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee ) +{ + int32 next_record; + uint8 *packed_ee; + TALLOC_CTX *mem_ctx = NULL; + TDB_DATA kbuf, ebuf; + uint32 n_packed; + + if ( !ee ) + return 0; + + mem_ctx = talloc_init( "write_eventlog_tdb" ); + + if ( mem_ctx == NULL ) + return 0; + + if ( !ee ) + return 0; + /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */ + if ( ee->record.time_generated == 0 ) + return 0; + +#define MARGIN 512 + + /* todo - check for sanity in next_record */ + + fixup_eventlog_entry( ee ); + + if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) { + DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) ); + talloc_destroy( mem_ctx ); + return 0; + } + + /* alloc mem for the packed version */ + packed_ee = TALLOC( mem_ctx, ee->record.length + MARGIN ); + if ( !packed_ee ) { + talloc_destroy( mem_ctx ); + return 0; + } + + /* need to read the record number and insert it into the entry here */ + + /* lock */ + tdb_lock_bystring( the_tdb, VN_next_record, 1 ); + /* read */ + next_record = tdb_fetch_int32( the_tdb, VN_next_record ); + + n_packed = + tdb_pack( packed_ee, ee->record.length + MARGIN, + "ddddddwwwwddddddBBdBBBd", ee->record.length, + ee->record.reserved1, next_record, + ee->record.time_generated, ee->record.time_written, + ee->record.event_id, ee->record.event_type, + ee->record.num_strings, ee->record.event_category, + ee->record.reserved2, + ee->record.closing_record_number, + ee->record.string_offset, + ee->record.user_sid_length, + ee->record.user_sid_offset, ee->record.data_length, + ee->record.data_offset, + ee->data_record.source_name_len, + ee->data_record.source_name, + ee->data_record.computer_name_len, + ee->data_record.computer_name, + ee->data_record.sid_padding, + ee->record.user_sid_length, ee->data_record.sid, + ee->data_record.strings_len, + ee->data_record.strings, + ee->data_record.user_data_len, + ee->data_record.user_data, + ee->data_record.data_padding ); + + /*DEBUG(3,("write_eventlog_tdb: packed into %d\n",n_packed)); */ + + /* increment the record count */ + + kbuf.dsize = sizeof( int32 ); + kbuf.dptr = ( uint8 * ) & next_record; + + ebuf.dsize = n_packed; + ebuf.dptr = packed_ee; + + if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) { + /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */ + tdb_unlock_bystring( the_tdb, VN_next_record ); + talloc_destroy( mem_ctx ); + return 0; + } + next_record++; + tdb_store_int32( the_tdb, VN_next_record, next_record ); + tdb_unlock_bystring( the_tdb, VN_next_record ); + talloc_destroy( mem_ctx ); + return ( next_record - 1 ); +} + +/* calculate the correct fields etc for an eventlog entry */ + +void fixup_eventlog_entry( Eventlog_entry * ee ) +{ + /* fix up the eventlog entry structure as necessary */ + + ee->data_record.sid_padding = + ( ( 4 - + ( ( ee->data_record.source_name_len + + ee->data_record.computer_name_len ) % 4 ) ) % 4 ); + ee->data_record.data_padding = + ( 4 - + ( ( ee->data_record.strings_len + + ee->data_record.user_data_len ) % 4 ) ) % 4; + ee->record.length = sizeof( Eventlog_record ); + ee->record.length += ee->data_record.source_name_len; + ee->record.length += ee->data_record.computer_name_len; + if ( ee->record.user_sid_length == 0 ) { + /* Should not pad to a DWORD boundary for writing out the sid if there is + no SID, so just propagate the padding to pad the data */ + ee->data_record.data_padding += ee->data_record.sid_padding; + ee->data_record.sid_padding = 0; + } + /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */ + /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */ + + ee->record.length += ee->data_record.sid_padding; + ee->record.length += ee->record.user_sid_length; + ee->record.length += ee->data_record.strings_len; + ee->record.length += ee->data_record.user_data_len; + ee->record.length += ee->data_record.data_padding; + /* need another copy of length at the end of the data */ + ee->record.length += sizeof( ee->record.length ); +} + +/******************************************************************** +Note that it's a pretty good idea to initialize the Eventlog_entry structure to zero's before +calling parse_logentry on an batch of lines that may resolve to a record. +ALSO, it's a good idea to remove any linefeeds (that's EOL to you and me) on the lines going in. + +********************************************************************/ + +BOOL parse_logentry( char *line, Eventlog_entry * entry, BOOL * eor ) +{ + char *start = NULL, *stop = NULL; + pstring temp; + int temp_len = 0; + + start = line; + + /* empty line signyfiying record delimeter, or we're at the end of the buffer */ + if ( start == NULL || strlen( start ) == 0 ) { + DEBUG( 6, + ( "parse_logentry: found end-of-record indicator.\n" ) ); + *eor = True; + return True; + } + if ( !( stop = strchr( line, ':' ) ) ) { + return False; + } + + DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) ); + + if ( 0 == strncmp( start, "LEN", stop - start ) ) { + /* This will get recomputed later anyway -- probably not necessary */ + entry->record.length = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "RS1", stop - start ) ) { + /* For now all these reserved entries seem to have the same value, + which can be hardcoded to int(1699505740) for now */ + entry->record.reserved1 = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "RCN", stop - start ) ) { + entry->record.record_number = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "TMG", stop - start ) ) { + entry->record.time_generated = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "TMW", stop - start ) ) { + entry->record.time_written = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "EID", stop - start ) ) { + entry->record.event_id = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "ETP", stop - start ) ) { + if ( strstr( start, "ERROR" ) ) { + entry->record.event_type = EVENTLOG_ERROR_TYPE; + } else if ( strstr( start, "WARNING" ) ) { + entry->record.event_type = EVENTLOG_WARNING_TYPE; + } else if ( strstr( start, "INFO" ) ) { + entry->record.event_type = EVENTLOG_INFORMATION_TYPE; + } else if ( strstr( start, "AUDIT_SUCCESS" ) ) { + entry->record.event_type = EVENTLOG_AUDIT_SUCCESS; + } else if ( strstr( start, "AUDIT_FAILURE" ) ) { + entry->record.event_type = EVENTLOG_AUDIT_FAILURE; + } else if ( strstr( start, "SUCCESS" ) ) { + entry->record.event_type = EVENTLOG_SUCCESS; + } else { + /* some other eventlog type -- currently not defined in MSDN docs, so error out */ + return False; + } + } + +/* + else if(0 == strncmp(start, "NST", stop - start)) + { + entry->record.num_strings = atoi(stop + 1); + } +*/ + else if ( 0 == strncmp( start, "ECT", stop - start ) ) { + entry->record.event_category = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "RS2", stop - start ) ) { + entry->record.reserved2 = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "CRN", stop - start ) ) { + entry->record.closing_record_number = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "USL", stop - start ) ) { + entry->record.user_sid_length = atoi( stop + 1 ); + } else if ( 0 == strncmp( start, "SRC", stop - start ) ) { + memset( temp, 0, sizeof( temp ) ); + stop++; + while ( isspace( stop[0] ) ) { + stop++; + } + temp_len = strlen( stop ); + strncpy( temp, stop, temp_len ); + rpcstr_push( ( void * ) ( entry->data_record.source_name ), + temp, sizeof( entry->data_record.source_name ), + STR_TERMINATE ); + entry->data_record.source_name_len = + ( strlen_w( entry->data_record.source_name ) * 2 ) + + 2; + } else if ( 0 == strncmp( start, "SRN", stop - start ) ) { + memset( temp, 0, sizeof( temp ) ); + stop++; + while ( isspace( stop[0] ) ) { + stop++; + } + temp_len = strlen( stop ); + strncpy( temp, stop, temp_len ); + rpcstr_push( ( void * ) ( entry->data_record.computer_name ), + temp, sizeof( entry->data_record.computer_name ), + STR_TERMINATE ); + entry->data_record.computer_name_len = + ( strlen_w( entry->data_record.computer_name ) * 2 ) + + 2; + } else if ( 0 == strncmp( start, "SID", stop - start ) ) { + memset( temp, 0, sizeof( temp ) ); + stop++; + while ( isspace( stop[0] ) ) { + stop++; + } + temp_len = strlen( stop ); + strncpy( temp, stop, temp_len ); + rpcstr_push( ( void * ) ( entry->data_record.sid ), temp, + sizeof( entry->data_record.sid ), + STR_TERMINATE ); + entry->record.user_sid_length = + ( strlen_w( entry->data_record.sid ) * 2 ) + 2; + } else if ( 0 == strncmp( start, "STR", stop - start ) ) { + /* skip past initial ":" */ + stop++; + /* now skip any other leading whitespace */ + while ( isspace( stop[0] ) ) { + stop++; + } + temp_len = strlen( stop ); + memset( temp, 0, sizeof( temp ) ); + strncpy( temp, stop, temp_len ); + rpcstr_push( ( void * ) ( entry->data_record.strings + + entry->data_record.strings_len ), + temp, + sizeof( entry->data_record.strings ) - + entry->data_record.strings_len, STR_TERMINATE ); + entry->data_record.strings_len += temp_len + 1; + entry->record.num_strings++; + } else if ( 0 == strncmp( start, "DAT", stop - start ) ) { + /* Now that we're done processing the STR data, adjust the length to account for + unicode, then proceed with the DAT data. */ + entry->data_record.strings_len *= 2; + /* skip past initial ":" */ + stop++; + /* now skip any other leading whitespace */ + while ( isspace( stop[0] ) ) { + stop++; + } + entry->data_record.user_data_len = strlen( stop ); + memset( entry->data_record.user_data, 0, + sizeof( entry->data_record.user_data ) ); + if ( entry->data_record.user_data_len > 0 ) { + /* copy no more than the first 1024 bytes */ + if ( entry->data_record.user_data_len > + sizeof( entry->data_record.user_data ) ) + entry->data_record.user_data_len = + sizeof( entry->data_record. + user_data ); + memcpy( entry->data_record.user_data, stop, + entry->data_record.user_data_len ); + } + } else { + /* some other eventlog entry -- not implemented, so dropping on the floor */ + DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) ); + /* For now return true so that we can keep on parsing this mess. Eventually + we will return False here. */ + return True; + } + return True; +} diff --git a/source3/rpc_server/srv_eventlog_nt.c b/source3/rpc_server/srv_eventlog_nt.c index 414c99d28e..6067c94fe8 100644 --- a/source3/rpc_server/srv_eventlog_nt.c +++ b/source3/rpc_server/srv_eventlog_nt.c @@ -2,6 +2,7 @@ * 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. * * This program is free software; you can redistribute it and/or modify @@ -18,12 +19,23 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + #include "includes.h" -#undef DBGC_CLASS +#undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV + +typedef struct { + pstring logname; /* rather than alloc on the fly what we need... (memory is cheap now) */ + pstring tdbfname; + TDB_CONTEXT *log_tdb; /* the pointer to the TDB_CONTEXT */ +} EventlogTDBInfo; + +static int nlogs; +static EventlogTDBInfo *ttdb = NULL; +static TALLOC_CTX *mem_ctx = NULL; + typedef struct { char *logname; char *servername; @@ -32,54 +44,295 @@ typedef struct { uint32 flags; } EventlogInfo; - + + +#if 0 /* UNUSED */ /******************************************************************** - Inform the external eventlog machinery of default values (on startup - probably) -********************************************************************/ + ********************************************************************/ + +void test_eventlog_tdb( TDB_CONTEXT * the_tdb ) +{ + Eventlog_entry ee; + + int i = 0; + + memset( &ee, 0, sizeof( Eventlog_entry ) ); + + if ( !the_tdb ) + return; + + for ( i = 0; i < 100; i++ ) { + ee.record.length = sizeof( ee.record ); + memset( &ee.data_record, 0, sizeof( ee.data_record ) ); + ee.record.reserved1 = 0xBEEFDEAD; + ee.record.record_number = 1000 - i; /* should get substituted */ + ee.record.time_generated = 0; + ee.record.time_written = 0; + ee.record.event_id = 500; + ee.record.event_type = 300; + ee.record.num_strings = 0; + ee.record.event_category = 0; + ee.record.reserved2 = ( i << 8 ) | i; + ee.record.closing_record_number = -1; + ee.record.string_offset = 0; + ee.record.user_sid_length = 0; + ee.record.user_sid_offset = 0; + ee.record.data_length = 0; + ee.record.data_offset = 0; + + rpcstr_push( ( void * ) ( ee.data_record.source_name ), + "SystemLog", + sizeof( ee.data_record.source_name ), + STR_TERMINATE ); + ee.data_record.source_name_len = + ( strlen_w( ee.data_record.source_name ) * 2 ) + 2; + + rpcstr_push( ( void * ) ( ee.data_record.computer_name ), + "DMLINUX", + sizeof( ee.data_record.computer_name ), + STR_TERMINATE ); + + ee.data_record.computer_name_len = + ( strlen_w( ee.data_record.computer_name ) * 2 ) + 2; + + write_eventlog_tdb( the_tdb, &ee ); + } +} +#endif /* UNUSED */ + +/******************************************************************** + ********************************************************************/ -void eventlog_refresh_external_parameters( NT_USER_TOKEN *token ) +static void refresh_eventlog_tdb_table( void ) { - const char **elogs = lp_eventlog_list(); - int i; + const char **elogs = lp_eventlog_list( ); + int i, j; if ( !elogs ) - return ; + return; - if ( !*lp_eventlog_control_cmd() ) + if ( !mem_ctx ) { + mem_ctx = talloc_init( "refresh_eventlog_tdb_table" ); + } + + if ( !mem_ctx ) { + DEBUG( 1, ( "Can't allocate memory\n" ) ); return; + } + + /* count them */ + for ( i = 0; elogs[i]; i++ ) { + } + /* number of logs in i */ + DEBUG( 10, ( "Number of eventlogs %d\n", i ) ); + /* check to see if we need to adjust our tables */ + + if ( ( ttdb != NULL ) ) { + if ( i != nlogs ) { + /* refresh the table, by closing and reconstructing */ + DEBUG( 10, ( "Closing existing table \n" ) ); + for ( j = 0; j < nlogs; j++ ) { + tdb_close( ttdb[j].log_tdb ); + } + TALLOC_FREE( ttdb ); + ttdb = NULL; + } else { /* i == nlogs */ + + for ( j = 0; j < nlogs; j++ ) { + if ( StrCaseCmp( ttdb[j].logname, elogs[i] ) ) { + /* something changed, have to discard */ + DEBUG( 10, + ( "Closing existing table \n" ) ); + for ( j = 0; j < nlogs; j++ ) { + tdb_close( ttdb[j].log_tdb ); + } + TALLOC_FREE( ttdb ); + ttdb = NULL; + break; + } + } + } + } - for ( i=0; elogs[i]; i++ ) { - - DEBUG(10,("eventlog_refresh_external_parameters: Refreshing =>[%s]\n", - elogs[i])); - - if ( !control_eventlog_hook( token, elogs[i] ) ) { - DEBUG(0,("eventlog_refresh_external_parameters: failed to refresh [%s]\n", - elogs[i])); + /* note that this might happen because of above */ + if ( ( i > 0 ) && ( ttdb == NULL ) ) { + /* alloc the room */ + DEBUG( 10, ( "Creating the table\n" ) ); + ttdb = TALLOC( mem_ctx, sizeof( EventlogTDBInfo ) * i ); + if ( !ttdb ) { + DEBUG( 10, + ( "Can't allocate table for tdb handles \n" ) ); + return; } - } - - return; + for ( j = 0; j < i; j++ ) { + pstrcpy( ttdb[j].tdbfname, + lock_path( mk_tdbfilename + ( ttdb[j].tdbfname, + ( char * ) elogs[j], + sizeof( pstring ) ) ) ); + pstrcpy( ttdb[j].logname, elogs[j] ); + DEBUG( 10, ( "Opening tdb for %s\n", elogs[j] ) ); + ttdb[j].log_tdb = + open_eventlog_tdb( ttdb[j].tdbfname ); + } + } + nlogs = i; } /******************************************************************** -********************************************************************/ + ********************************************************************/ -static void free_eventlog_info(void *ptr) +TDB_CONTEXT *tdb_of( char *eventlog_name ) +{ + int i; + + if ( !eventlog_name ) + return NULL; + + if ( !ttdb ) { + DEBUG( 10, ( "Refreshing list of eventlogs\n" ) ); + refresh_eventlog_tdb_table( ); + + if ( !ttdb ) { + DEBUG( 10, + ( "eventlog tdb table is NULL after a refresh!\n" ) ); + return NULL; + } + } + + DEBUG( 10, ( "Number of eventlogs %d\n", nlogs ) ); + + for ( i = 0; i < nlogs; i++ ) { + if ( strequal( eventlog_name, ttdb[i].logname ) ) + return ttdb[i].log_tdb; + } + + return NULL; +} + + +/******************************************************************** + For the given tdb, get the next eventlog record into the passed + Eventlog_entry. returns NULL if it can't get the record for some reason. + ********************************************************************/ + +Eventlog_entry *get_eventlog_record( prs_struct * ps, TDB_CONTEXT * tdb, + int recno, Eventlog_entry * ee ) +{ + TDB_DATA ret, key; + + int srecno; + int reclen; + int len; + uint8 *rbuff; + + pstring *wpsource, *wpcomputer, *wpsid, *wpstrs, *puserdata; + + key.dsize = sizeof( int32 ); + rbuff = NULL; + + srecno = recno; + key.dptr = ( char * ) &srecno; + + ret = tdb_fetch( tdb, key ); + + if ( ret.dsize == 0 ) { + DEBUG( 8, + ( "Can't find a record for the key, record %d\n", + recno ) ); + return NULL; + } + + len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen ); + + DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) ); + + if ( !len ) + return NULL; + + /* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */ + + if ( !ee ) + return NULL; + + len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd", + &ee->record.length, &ee->record.reserved1, + &ee->record.record_number, + &ee->record.time_generated, + &ee->record.time_written, &ee->record.event_id, + &ee->record.event_type, &ee->record.num_strings, + &ee->record.event_category, &ee->record.reserved2, + &ee->record.closing_record_number, + &ee->record.string_offset, + &ee->record.user_sid_length, + &ee->record.user_sid_offset, + &ee->record.data_length, &ee->record.data_offset, + &ee->data_record.source_name_len, &wpsource, + &ee->data_record.computer_name_len, &wpcomputer, + &ee->data_record.sid_padding, + &ee->record.user_sid_length, &wpsid, + &ee->data_record.strings_len, &wpstrs, + &ee->data_record.user_data_len, &puserdata, + &ee->data_record.data_padding ); + DEBUG( 10, + ( "Read record %d, len in tdb was %d\n", + ee->record.record_number, len ) ); + + /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff + into it's 2nd argment for 'B' */ + + if ( wpcomputer ) + memcpy( ee->data_record.computer_name, wpcomputer, + ee->data_record.computer_name_len ); + if ( wpsource ) + memcpy( ee->data_record.source_name, wpsource, + ee->data_record.source_name_len ); + + if ( wpsid ) + memcpy( ee->data_record.sid, wpsid, + ee->record.user_sid_length ); + if ( wpstrs ) + memcpy( ee->data_record.strings, wpstrs, + ee->data_record.strings_len ); + + /* note that userdata is a pstring */ + if ( puserdata ) + memcpy( ee->data_record.user_data, puserdata, + ee->data_record.user_data_len ); + + SAFE_FREE( wpcomputer ); + SAFE_FREE( wpsource ); + SAFE_FREE( wpsid ); + SAFE_FREE( wpstrs ); + SAFE_FREE( puserdata ); + + DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) ); + DEBUG( 10, + ( "get_eventlog_record: computer_name %d is ", + ee->data_record.computer_name_len ) ); + SAFE_FREE( ret.dptr ); + return ee; +} + +/******************************************************************** + ********************************************************************/ + +static void free_eventlog_info( void *ptr ) { TALLOC_FREE( ptr ); } /******************************************************************** -********************************************************************/ + ********************************************************************/ -static EventlogInfo *find_eventlog_info_by_hnd(pipes_struct *p, POLICY_HND *handle) +static EventlogInfo *find_eventlog_info_by_hnd( pipes_struct * p, + POLICY_HND * handle ) { EventlogInfo *info; - - if ( !find_policy_by_hnd(p,handle,(void **)&info) ) { - DEBUG(2,("find_eventlog_info_by_hnd: eventlog not found.\n")); + + if ( !find_policy_by_hnd( p, handle, ( void ** ) &info ) ) { + DEBUG( 2, + ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) ); return NULL; } @@ -87,144 +340,85 @@ static EventlogInfo *find_eventlog_info_by_hnd(pipes_struct *p, POLICY_HND *hand } /******************************************************************** - Callout to control the specified event log - passing out only - the MaxSize and Retention values, along with eventlog name - uses smbrun... - INPUT: - OUTPUT: nothing -********************************************************************/ + note that this can only be called AFTER the table is constructed, + since it uses the table to find the tdb handle + ********************************************************************/ -BOOL control_eventlog_hook(NT_USER_TOKEN *token, const char *elogname ) +static BOOL sync_eventlog_params( const char *elogname ) { - char *cmd = lp_eventlog_control_cmd(); - pstring command; - int ret; - int fd = -1; - uint32 uiMaxSize, uiRetention; pstring path; + uint32 uiMaxSize; + uint32 uiRetention; REGISTRY_KEY *keyinfo; REGISTRY_VALUE *val; REGVAL_CTR *values; WERROR wresult; + TDB_CONTEXT *the_tdb; + + the_tdb = tdb_of( ( char * ) elogname ); + + DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) ); - if ( !cmd || !*cmd ) { - DEBUG(0, ("control_eventlog_hook: No \"eventlog control command\" defined in smb.conf!\n")); + if ( !the_tdb ) { + DEBUG( 4, ( "Can't open tdb for %s\n", elogname ) ); return False; } - /* set resonable defaults. 512Kb on size and 1 week on time */ - + uiMaxSize = 0x80000; uiRetention = 604800; - + /* the general idea is to internally open the registry key and retreive the values. That way we can continue to use the same fetch/store api that we use in srv_reg_nt.c */ pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname ); - wresult = regkey_open_internal( &keyinfo, path, token, REG_KEY_READ ); - + + wresult = + regkey_open_internal( &keyinfo, path, get_root_nt_token( ), + REG_KEY_READ ); + if ( !W_ERROR_IS_OK( wresult ) ) { - DEBUG(4,("control_eventlog_hook: Failed to open key [%s] (%s)\n", - path, dos_errstr(wresult) )); + DEBUG( 4, + ( "sync_eventlog_params: Failed to open key [%s] (%s)\n", + path, dos_errstr( wresult ) ) ); return False; } - - if ( !(values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR )) ) { + + if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) { TALLOC_FREE( keyinfo ); - DEBUG(0,("control_eventlog_hook: talloc() failed!\n")); - + DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) ); + return False; } fetch_reg_values( keyinfo, values ); - - if ( (val = regval_ctr_getvalue( values, "Retention" )) != NULL ) - uiRetention = IVAL( regval_data_p(val), 0 ); - if ( (val = regval_ctr_getvalue( values, "MaxSize" )) != NULL ) - uiMaxSize = IVAL( regval_data_p(val), 0 ); - - TALLOC_FREE( keyinfo ); - - /* now run the command */ + if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL ) + uiRetention = IVAL( regval_data_p( val ), 0 ); - pstr_sprintf(command, "%s \"%s\" %u %u", cmd, elogname, uiRetention, uiMaxSize ); + if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL ) + uiMaxSize = IVAL( regval_data_p( val ), 0 ); - DEBUG(10, ("control_eventlog_hook: Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); + TALLOC_FREE( keyinfo ); - if ( ret != 0 ) { - DEBUG(10,("control_eventlog_hook: Command returned [%d]\n", ret)); - if (fd != -1 ) - close(fd); - return False; - } + tdb_store_int32( the_tdb, VN_maxsize, uiMaxSize ); + tdb_store_int32( the_tdb, VN_retention, uiRetention ); - close(fd); return True; } - /******************************************************************** -********************************************************************/ + ********************************************************************/ -/** - * Callout to open the specified event log - * - * smbrun calling convention -- - * INPUT: - * OUTPUT: the string "SUCCESS" if the command succeeded - * no such string if there was a failure. - */ -static BOOL open_eventlog_hook( EventlogInfo *info ) +static BOOL open_eventlog_hook( EventlogInfo * info ) { - char *cmd = lp_eventlog_open_cmd(); - char **qlines; - pstring command; - int numlines = 0; - int ret; - int fd = -1; - - if ( !cmd || !*cmd ) { - DEBUG(0, ("Must define an \"eventlog open command\" entry in the config.\n")); - return False; - } - - pstr_sprintf(command, "%s \"%s\"", cmd, info->logname ); - - DEBUG(10, ("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); - - if(ret != 0) { - if(fd != -1) { - close(fd); - } - return False; - } - - qlines = fd_lines_load(fd, &numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", numlines)); - close(fd); - - if(numlines) { - DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0])); - if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS"))) { - DEBUGADD(10, ("Able to open [%s].\n", info->logname)); - file_lines_free(qlines); - return True; - } - } - - file_lines_free(qlines); - - return False; + return True; } /******************************************************************** ********************************************************************/ + /** * Callout to get the number of records in the specified event log * @@ -234,50 +428,49 @@ static BOOL open_eventlog_hook( EventlogInfo *info ) * entries in the log. If there are no entries in the log, return 0. */ -static BOOL get_num_records_hook(EventlogInfo *info) + +static BOOL get_num_records_hook( EventlogInfo * info ) { - char *cmd = lp_eventlog_num_records_cmd(); - char **qlines; - pstring command; - int numlines = 0; - int ret; - int fd = -1; - - if ( !cmd || !*cmd ) { - DEBUG(0, ("Must define an \"eventlog num records command\" entry in the config.\n")); - return False; - } - pstr_sprintf( command, "%s \"%s\"", cmd, info->logname ); + TDB_CONTEXT *the_tdb = NULL; + int next_record; + int oldest_record; - DEBUG(10, ("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); - if(ret != 0) { - if(fd != -1) { - close(fd); - } + the_tdb = tdb_of( info->logname ); + + if ( !the_tdb ) { + DEBUG( 10, ( "Can't find tdb for %s\n", info->logname ) ); + info->num_records = 0; return False; } - qlines = fd_lines_load(fd, &numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", numlines)); - close(fd); + /* lock */ + tdb_lock_bystring( the_tdb, VN_next_record, 1 ); + + + /* read */ + next_record = tdb_fetch_int32( the_tdb, VN_next_record ); + oldest_record = tdb_fetch_int32( the_tdb, VN_oldest_entry ); + + + + 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; + tdb_unlock_bystring( the_tdb, VN_next_record ); + + + return True; - if(numlines) { - DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0])); - sscanf(qlines[0], "%d", &(info->num_records)); - file_lines_free(qlines); - return True; - } - file_lines_free(qlines); - return False; } /******************************************************************** -********************************************************************/ + ********************************************************************/ /** * Callout to find the oldest record in the log @@ -289,50 +482,17 @@ static BOOL get_num_records_hook(EventlogInfo *info) * If there are no entries in the log, returns a 0 */ -static BOOL get_oldest_entry_hook(EventlogInfo *info) +static BOOL get_oldest_entry_hook( EventlogInfo * info ) { - char *cmd = lp_eventlog_oldest_record_cmd(); - char **qlines; - pstring command; - int numlines = 0; - int ret; - int fd = -1; - - if ( !cmd || !*cmd ) { - DEBUG(0, ("Must define an \"eventlog oldest record command\" entry in the config.\n")); - return False; - } - - pstr_sprintf( command, "%s \"%s\"", cmd, info->logname ); - - DEBUG(10, ("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); - if(ret != 0) { - if(fd != -1) { - close(fd); - } - return False; - } - - qlines = fd_lines_load(fd, &numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", numlines)); - close(fd); - - if(numlines) { - DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0])); - sscanf(qlines[0], "%d", &(info->oldest_entry)); - file_lines_free(qlines); - return True; - } - - file_lines_free(qlines); - return False; + /* it's the same thing */ + return get_num_records_hook( info ); } + /******************************************************************** -********************************************************************/ + ********************************************************************/ + /** * Callout to close the specified event log * @@ -342,323 +502,51 @@ static BOOL get_oldest_entry_hook(EventlogInfo *info) * no such string if there was a failure. */ -static BOOL close_eventlog_hook(EventlogInfo *info) -{ - char *cmd = lp_eventlog_close_cmd(); - char **qlines; - pstring command; - int numlines = 0; - int ret; - int fd = -1; - - if ( !cmd || !*cmd ) { - DEBUG(0, ("Must define an \"eventlog close command\" entry in the config.\n")); - return False; - } - - pstr_sprintf( command, "%s \"%s\"", cmd, info->logname ); - - DEBUG(10, ("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); - - if(ret != 0) { - if(fd != -1) { - close(fd); - } - return False; - } - - qlines = fd_lines_load(fd, &numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", numlines)); - close(fd); - - if(numlines) { - DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0])); - if(0 == strncmp(qlines[0], "SUCCESS", 7)) { - DEBUGADD(10, ("Able to close [%s].\n", info->logname)); - file_lines_free(qlines); - return True; - } - } - - file_lines_free(qlines); - return False; -} - -/******************************************************************** -********************************************************************/ - -static BOOL parse_logentry(char *line, Eventlog_entry *entry, BOOL *eor) +static BOOL close_eventlog_hook( EventlogInfo * info ) { - char *start = NULL, *stop = NULL; - pstring temp; - int temp_len = 0, i; - - start = line; - /* empty line signyfiying record delimeter, or we're at the end of the buffer */ - if(start == NULL || strlen(start) == 0) { - DEBUG(6, ("parse_logentry: found end-of-record indicator.\n")); - *eor = True; - return True; - } - if(!(stop = strchr(line, ':'))) { - return False; - } - - DEBUG(6, ("parse_logentry: trying to parse [%s].\n", line)); - - if(0 == strncmp(start, "LEN", stop - start)) { - /* This will get recomputed later anyway -- probably not necessary */ - entry->record.length = atoi(stop + 1); - } else if(0 == strncmp(start, "RS1", stop - start)) { - /* For now all these reserved entries seem to have the same value, - which can be hardcoded to int(1699505740) for now */ - entry->record.reserved1 = atoi(stop + 1); - } else if(0 == strncmp(start, "RCN", stop - start)) { - entry->record.record_number = atoi(stop + 1); - } else if(0 == strncmp(start, "TMG", stop - start)) { - entry->record.time_generated = atoi(stop + 1); - } else if(0 == strncmp(start, "TMW", stop - start)) { - entry->record.time_written = atoi(stop + 1); - } else if(0 == strncmp(start, "EID", stop - start)) { - entry->record.event_id = atoi(stop + 1); - } else if(0 == strncmp(start, "ETP", stop - start)) { - if(strstr(start, "ERROR")) { - entry->record.event_type = EVENTLOG_ERROR_TYPE; - } else if(strstr(start, "WARNING")) { - entry->record.event_type = EVENTLOG_WARNING_TYPE; - } else if(strstr(start, "INFO")) { - entry->record.event_type = EVENTLOG_INFORMATION_TYPE; - } else if(strstr(start, "AUDIT_SUCCESS")) { - entry->record.event_type = EVENTLOG_AUDIT_SUCCESS; - } else if(strstr(start, "AUDIT_FAILURE")) { - entry->record.event_type = EVENTLOG_AUDIT_FAILURE; - } else if(strstr(start, "SUCCESS")) { - entry->record.event_type = EVENTLOG_SUCCESS; - } else { - /* some other eventlog type -- currently not defined in MSDN docs, so error out */ - return False; - } - } -/* - else if(0 == strncmp(start, "NST", stop - start)) - { - entry->record.num_strings = atoi(stop + 1); - } -*/ - else if(0 == strncmp(start, "ECT", stop - start)) { - entry->record.event_category = atoi(stop + 1); - } else if(0 == strncmp(start, "RS2", stop - start)) { - entry->record.reserved2 = atoi(stop + 1); - } else if(0 == strncmp(start, "CRN", stop - start)) { - entry->record.closing_record_number = atoi(stop + 1); - } else if(0 == strncmp(start, "USL", stop - start)) { - entry->record.user_sid_length = atoi(stop + 1); - } else if(0 == strncmp(start, "SRC", stop - start)) { - memset(temp, 0, sizeof(temp)); - stop++; - while(isspace(stop[0])) { - stop++; - } - temp_len = strlen(stop); - strncpy(temp, stop, temp_len); - rpcstr_push((void *)(entry->data_record.source_name), temp, - sizeof(entry->data_record.source_name), STR_TERMINATE); - entry->data_record.source_name_len = (strlen_w(entry->data_record.source_name)* 2) + 2; - } else if(0 == strncmp(start, "SRN", stop - start)) { - memset(temp, 0, sizeof(temp)); - stop++; - while(isspace(stop[0])) { - stop++; - } - temp_len = strlen(stop); - strncpy(temp, stop, temp_len); - rpcstr_push((void *)(entry->data_record.computer_name), temp, - sizeof(entry->data_record.computer_name), STR_TERMINATE); - entry->data_record.computer_name_len = (strlen_w(entry->data_record.computer_name)* 2) + 2; - } else if(0 == strncmp(start, "SID", stop - start)) { - memset(temp, 0, sizeof(temp)); - stop++; - while(isspace(stop[0])) { - stop++; - } - temp_len = strlen(stop); - strncpy(temp, stop, temp_len); - rpcstr_push((void *)(entry->data_record.sid), temp, - sizeof(entry->data_record.sid), STR_TERMINATE); - entry->record.user_sid_length = (strlen_w(entry->data_record.sid) * 2) + 2; - } else if(0 == strncmp(start, "STR", stop - start)) { - /* skip past initial ":" */ - stop++; - /* now skip any other leading whitespace */ - while(isspace(stop[0])) { - stop++; - } - temp_len = strlen(stop); - memset(temp, 0, sizeof(temp)); - strncpy(temp, stop, temp_len); - rpcstr_push((void *)(entry->data_record.strings + entry->data_record.strings_len), - temp, - sizeof(entry->data_record.strings) - entry->data_record.strings_len, - STR_TERMINATE); - entry->data_record.strings_len += temp_len + 1; - fprintf(stderr, "Dumping strings:\n"); - for(i = 0; i < entry->data_record.strings_len; i++) { - fputc((char)entry->data_record.strings[i], stderr); - } - fprintf(stderr, "\nDone\n"); - entry->record.num_strings++; - } else if(0 == strncmp(start, "DAT", stop - start)) { - /* Now that we're done processing the STR data, adjust the length to account for - unicode, then proceed with the DAT data. */ - entry->data_record.strings_len *= 2; - /* skip past initial ":" */ - stop++; - /* now skip any other leading whitespace */ - while(isspace(stop[0])) { - stop++; - } - entry->data_record.user_data_len = strlen(stop); - memset(entry->data_record.user_data, 0, sizeof(entry->data_record.user_data)); - if(entry->data_record.user_data_len > 0) { - /* copy no more than the first 1024 bytes */ - if(entry->data_record.user_data_len > sizeof(entry->data_record.user_data)) - entry->data_record.user_data_len = sizeof(entry->data_record.user_data); - memcpy(entry->data_record.user_data, stop, entry->data_record.user_data_len); - } - } else { - /* some other eventlog entry -- not implemented, so dropping on the floor */ - DEBUG(10, ("Unknown entry [%s]. Ignoring.\n", line)); - /* For now return true so that we can keep on parsing this mess. Eventually - we will return False here. */ - return True; - } return True; } /******************************************************************** -********************************************************************/ - -/** - * Callout to read entries from the specified event log - * - * smbrun calling convention -- - * INPUT: - * where direction is either "forward" or "backward", the starting record is somewhere - * between the oldest_record and oldest_record+num_records, and the buffer size is the - * maximum size of the buffer that the client can accomodate. - * OUTPUT: A buffer containing a set of entries, one to a line, of the format: - * Multiple log entries can be contained in the buffer, delimited by an empty line - * line type:line data - * These are the allowed line types: - * RS1:(uint32) - reserved. All M$ entries seem to have int(1699505740) for now - * RCN:(uint32) - record number of the record, however it may be calculated by the script - * TMG:(uint32) - time generated, seconds since January 1, 1970, 0000 UTC - * TMW:(uint32) - time written, seconds since January 1, 1970, 0000 UTC - * EID:(uint32) - eventlog source defined event identifier. If there's a stringfile for the event, it is an index into that - * ETP:(uint16) - eventlog type - one of ERROR, WARNING, INFO, AUDIT_SUCCESS, AUDIT_FAILURE - * ECT:(uint16) - event category - depends on the eventlog generator... - * RS2:(uint16) - reserved, make it 0000 - * CRN:(uint32) - reserved, make it 00000000 for now - * USL:(uint32) - user SID length. No sid? Make this 0. Must match SID below - * SRC:[(uint8)] - Name of the source, for example ccPwdSvc, in hex bytes. Can not be multiline. - * SRN:[(uint8)] - Name of the computer on which this is generated, the short hostname usually. - * SID:[(uint8)] - User sid if one exists. Must be present even if there is no SID. - * STR:[(uint8)] - String data. One string per line. Multiple strings can be specified using consecutive "STR" lines, - * up to a total aggregate string length of 1024 characters. - * DAT:[(uint8)] - The user-defined data portion of the event log. Can not be multiple lines. - * - end-of-record indicator - */ - -static BOOL read_eventlog_hook(EventlogInfo *info, Eventlog_entry *entry, - const char *direction, int starting_record, - int buffer_size, BOOL *eof, - char ***buffer, int *numlines) -{ - char *cmd = lp_eventlog_read_cmd(); - pstring command; - int ret; - int fd = -1; - - if ( !info ) - return False; - - if ( !cmd || !*cmd ) { - DEBUG(0, ("Must define an \"eventlog read command\" entry in the config.\n")); - return False; - } - - pstr_sprintf( command, "%s \"%s\" %s %d %d", - cmd, info->logname, direction, starting_record, buffer_size ); - - *numlines = 0; - - DEBUG(10, ("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); - - if(ret != 0) { - if(fd != -1) { - close(fd); - } - return False; - } - - *buffer = fd_lines_load(fd, numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", *numlines)); - close(fd); - - if(*numlines) { - /* - for(i = 0; i < numlines; i++) - { - DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i])); - parse_logentry(qlines[i], entry); - } - file_lines_free(qlines); - */ - *eof = False; - return True; - } - *eof = True; - -/* file_lines_free(qlines);*/ - return False; -} - -/******************************************************************** -********************************************************************/ + ********************************************************************/ -static Eventlog_entry *read_package_entry(prs_struct *ps, - EVENTLOG_Q_READ_EVENTLOG *q_u, - EVENTLOG_R_READ_EVENTLOG *r_u, - Eventlog_entry *entry) +static Eventlog_entry *read_package_entry( prs_struct * ps, + EVENTLOG_Q_READ_EVENTLOG * q_u, + EVENTLOG_R_READ_EVENTLOG * r_u, + Eventlog_entry * entry ) { uint8 *offset; Eventlog_entry *ee_new = NULL; - ee_new = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); - if(ee_new == NULL) { + ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 ); + if ( ee_new == NULL ) { return NULL; } - entry->data_record.sid_padding = ((4 - ((entry->data_record.source_name_len - + entry->data_record.computer_name_len) % 4)) %4); - entry->data_record.data_padding = (4 - ((entry->data_record.strings_len - + entry->data_record.user_data_len) % 4)) % 4; - entry->record.length = sizeof(Eventlog_record); + entry->data_record.sid_padding = + ( ( 4 - + ( ( entry->data_record.source_name_len + + entry->data_record.computer_name_len ) % 4 ) ) % 4 ); + entry->data_record.data_padding = + ( 4 - + ( ( entry->data_record.strings_len + + entry->data_record.user_data_len ) % 4 ) ) % 4; + entry->record.length = sizeof( Eventlog_record ); entry->record.length += entry->data_record.source_name_len; entry->record.length += entry->data_record.computer_name_len; - if(entry->record.user_sid_length == 0) { + if ( entry->record.user_sid_length == 0 ) { /* Should not pad to a DWORD boundary for writing out the sid if there is no SID, so just propagate the padding to pad the data */ - entry->data_record.data_padding += entry->data_record.sid_padding; + entry->data_record.data_padding += + entry->data_record.sid_padding; entry->data_record.sid_padding = 0; } - DEBUG(10, ("sid_padding is [%d].\n", entry->data_record.sid_padding)); - DEBUG(10, ("data_padding is [%d].\n", entry->data_record.data_padding)); + DEBUG( 10, + ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) ); + DEBUG( 10, + ( "data_padding is [%d].\n", + entry->data_record.data_padding ) ); entry->record.length += entry->data_record.sid_padding; entry->record.length += entry->record.user_sid_length; @@ -666,66 +554,82 @@ static Eventlog_entry *read_package_entry(prs_struct *ps, entry->record.length += entry->data_record.user_data_len; entry->record.length += entry->data_record.data_padding; /* need another copy of length at the end of the data */ - entry->record.length += sizeof(entry->record.length); - DEBUG(10, ("entry->record.length is [%d].\n", entry->record.length)); - entry->data = PRS_ALLOC_MEM(ps, uint8, entry->record.length - sizeof(Eventlog_record) - sizeof(entry->record.length)); - if(entry->data == NULL) { + entry->record.length += sizeof( entry->record.length ); + DEBUG( 10, + ( "entry->record.length is [%d].\n", entry->record.length ) ); + entry->data = + PRS_ALLOC_MEM( ps, uint8, + entry->record.length - + sizeof( Eventlog_record ) - + sizeof( entry->record.length ) ); + if ( entry->data == NULL ) { return NULL; } offset = entry->data; - memcpy(offset, &(entry->data_record.source_name), entry->data_record.source_name_len); + memcpy( offset, &( entry->data_record.source_name ), + entry->data_record.source_name_len ); offset += entry->data_record.source_name_len; - memcpy(offset, &(entry->data_record.computer_name), entry->data_record.computer_name_len); + memcpy( offset, &( entry->data_record.computer_name ), + entry->data_record.computer_name_len ); offset += entry->data_record.computer_name_len; /* SID needs to be DWORD-aligned */ offset += entry->data_record.sid_padding; - entry->record.user_sid_offset = sizeof(Eventlog_record) + (offset - entry->data); - memcpy(offset, &(entry->data_record.sid), entry->record.user_sid_length); + entry->record.user_sid_offset = + sizeof( Eventlog_record ) + ( offset - entry->data ); + memcpy( offset, &( entry->data_record.sid ), + entry->record.user_sid_length ); offset += entry->record.user_sid_length; /* Now do the strings */ - entry->record.string_offset = sizeof(Eventlog_record) + (offset - entry->data); - memcpy(offset, &(entry->data_record.strings), entry->data_record.strings_len); + entry->record.string_offset = + sizeof( Eventlog_record ) + ( offset - entry->data ); + memcpy( offset, &( entry->data_record.strings ), + entry->data_record.strings_len ); offset += entry->data_record.strings_len; /* Now do the data */ entry->record.data_length = entry->data_record.user_data_len; - entry->record.data_offset = sizeof(Eventlog_record) + (offset - entry->data); - memcpy(offset, &(entry->data_record.user_data), entry->data_record.user_data_len); + entry->record.data_offset = + sizeof( Eventlog_record ) + ( offset - entry->data ); + memcpy( offset, &( entry->data_record.user_data ), + entry->data_record.user_data_len ); offset += entry->data_record.user_data_len; - memcpy(&(ee_new->record), &entry->record, sizeof(Eventlog_record)); - memcpy(&(ee_new->data_record), &entry->data_record, sizeof(Eventlog_data_record)); + memcpy( &( ee_new->record ), &entry->record, + sizeof( Eventlog_record ) ); + memcpy( &( ee_new->data_record ), &entry->data_record, + sizeof( Eventlog_data_record ) ); ee_new->data = entry->data; return ee_new; } /******************************************************************** -********************************************************************/ + ********************************************************************/ -static BOOL add_record_to_resp(EVENTLOG_R_READ_EVENTLOG *r_u, Eventlog_entry *ee_new) +static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u, + Eventlog_entry * ee_new ) { Eventlog_entry *insert_point; - insert_point=r_u->entry; + insert_point = r_u->entry; - if (NULL == insert_point) { + if ( NULL == insert_point ) { r_u->entry = ee_new; ee_new->next = NULL; } else { - while ((NULL != insert_point->next)) { - insert_point=insert_point->next; + while ( ( NULL != insert_point->next ) ) { + insert_point = insert_point->next; } ee_new->next = NULL; insert_point->next = ee_new; } - r_u->num_records++; + r_u->num_records++; r_u->num_bytes_in_resp += ee_new->record.length; return True; } /******************************************************************** -********************************************************************/ + ********************************************************************/ /** * Callout to clear (and optionally backup) a specified event log @@ -741,128 +645,153 @@ static BOOL add_record_to_resp(EVENTLOG_R_READ_EVENTLOG *r_u, Eventlog_entry *ee * The given log is copied to that location on the server. See comments for * eventlog_io_q_clear_eventlog for info about odd file name behavior */ - -static BOOL clear_eventlog_hook(EventlogInfo *info, pstring backup_file_name) +static BOOL clear_eventlog_hook( EventlogInfo * info, + pstring backup_file_name ) { - char *cmd = lp_eventlog_clear_cmd(); - char **qlines; - pstring command; - int numlines = 0; - int ret; - int fd = -1; - - if ( !cmd || !*cmd ) { - DEBUG(0, ("Must define an \"eventlog clear command\" entry in the config.\n")); - return False; - } - if ( strlen(backup_file_name) ) - pstr_sprintf( command, "%s \"%s\" \"%s\"", cmd, info->logname, backup_file_name ); - else - pstr_sprintf( command, "%s \"%s\"", cmd, info->logname ); + int i; - DEBUG(10, ("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); - if(ret != 0) { - if(fd != -1) { - close(fd); - } + if ( !info ) return False; - } - - qlines = fd_lines_load(fd, &numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", numlines)); - close(fd); - - if(numlines) { - DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0])); - if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS"))) { - DEBUGADD(10, ("Able to clear [%s].\n", info->logname)); - file_lines_free(qlines); + DEBUG( 3, ( "There are %d event logs\n", nlogs ) ); + for ( i = 0; i < nlogs; i++ ) { + DEBUG( 3, + ( "Comparing Eventlog %s, %s\n", info->logname, + ttdb[i].logname ) ); + if ( !StrCaseCmp( info->logname, ttdb[i].logname ) ) { + /* close the current one, reinit */ + tdb_close( ttdb[i].log_tdb ); + DEBUG( 3, + ( "Closing Eventlog %s, file-on-disk %s\n", + info->logname, ttdb[i].tdbfname ) ); + ttdb[i].log_tdb = + init_eventlog_tdb( ttdb[i].tdbfname ); return True; } } - file_lines_free(qlines); - return False; + return False; /* not found */ + /* TODO- do something with the backup file name */ + } /******************************************************************* -*******************************************************************/ + *******************************************************************/ + +static int eventlog_size( char *eventlog_name ) +{ + TDB_CONTEXT *tdb; + + if ( !eventlog_name ) + return 0; + tdb = tdb_of( eventlog_name ); + if ( !tdb ) + return 0; + return eventlog_tdb_size( tdb, NULL, NULL ); +} + +/******************************************************************** + ********************************************************************/ -WERROR _eventlog_open_eventlog(pipes_struct *p, EVENTLOG_Q_OPEN_EVENTLOG *q_u, EVENTLOG_R_OPEN_EVENTLOG *r_u) +WERROR _eventlog_open_eventlog( pipes_struct * p, + EVENTLOG_Q_OPEN_EVENTLOG * q_u, + EVENTLOG_R_OPEN_EVENTLOG * r_u ) { EventlogInfo *info = NULL; fstring str; - - if ( !(info = TALLOC_ZERO_P(NULL, EventlogInfo)) ) + + if ( !( info = TALLOC_ZERO_P( NULL, EventlogInfo ) ) ) return WERR_NOMEM; - fstrcpy( str, global_myname() ); + fstrcpy( str, global_myname( ) ); if ( q_u->servername.string ) { - rpcstr_pull( str, q_u->servername.string->buffer, - sizeof(str), q_u->servername.string->uni_str_len*2, 0 ); - } + rpcstr_pull( str, q_u->servername.string->buffer, + sizeof( str ), + q_u->servername.string->uni_str_len * 2, 0 ); + } + info->servername = talloc_strdup( info, str ); fstrcpy( str, "Application" ); if ( q_u->logname.string ) { - rpcstr_pull( str, q_u->logname.string->buffer, - sizeof(str), q_u->logname.string->uni_str_len*2, 0 ); - } + rpcstr_pull( str, q_u->logname.string->buffer, + sizeof( str ), + q_u->logname.string->uni_str_len * 2, 0 ); + } + info->logname = talloc_strdup( info, str ); - DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the server name.\n", info->servername)); - DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the source log file.\n", info->logname)); + DEBUG( 1, + ( "Size of %s is %d\n", info->logname, + eventlog_size( info->logname ) ) ); - if ( !create_policy_hnd(p, &r_u->handle, free_eventlog_info, (void *)info) ) { - free_eventlog_info(info); + + + DEBUG( 10, + ( "_eventlog_open_eventlog: Using [%s] as the server name.\n", + info->servername ) ); + DEBUG( 10, + ( "_eventlog_open_eventlog: Using [%s] as the source log file.\n", + info->logname ) ); + + + if ( !create_policy_hnd + ( p, &r_u->handle, free_eventlog_info, ( void * ) info ) ) { + free_eventlog_info( info ); return WERR_NOMEM; } - - if ( !(open_eventlog_hook(info)) ) { - close_policy_hnd(p, &r_u->handle); + + if ( !open_eventlog_hook( info ) ) { + close_policy_hnd( p, &r_u->handle ); return WERR_BADFILE; } - + + sync_eventlog_params( info->logname ); + prune_eventlog( tdb_of( info->logname ) ); + return WERR_OK; } /******************************************************************** -********************************************************************/ + ********************************************************************/ -WERROR _eventlog_clear_eventlog(pipes_struct *p, EVENTLOG_Q_CLEAR_EVENTLOG *q_u, EVENTLOG_R_CLEAR_EVENTLOG *r_u) +WERROR _eventlog_clear_eventlog( pipes_struct * p, + EVENTLOG_Q_CLEAR_EVENTLOG * q_u, + EVENTLOG_R_CLEAR_EVENTLOG * r_u ) { - EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle); + EventlogInfo *info = find_eventlog_info_by_hnd( p, &q_u->handle ); pstring backup_file_name; pstrcpy( backup_file_name, "" ); - if ( q_u->backupfile.string ) - unistr2_to_ascii(backup_file_name, q_u->backupfile.string, sizeof(backup_file_name)); + if ( q_u->backupfile.string ) + unistr2_to_ascii( backup_file_name, q_u->backupfile.string, + sizeof( backup_file_name ) ); - DEBUG(10, ("_eventlog_clear_eventlog: Using [%s] as the backup file name for log [%s].", - backup_file_name, info->logname)); + DEBUG( 10, + ( "_eventlog_clear_eventlog: Using [%s] as the backup file name for log [%s].", + backup_file_name, info->logname ) ); - if ( !(clear_eventlog_hook(info, backup_file_name)) ) + if ( !( clear_eventlog_hook( info, backup_file_name ) ) ) return WERR_BADFILE; return WERR_OK; } /******************************************************************** -********************************************************************/ + ********************************************************************/ -WERROR _eventlog_close_eventlog(pipes_struct *p, EVENTLOG_Q_CLOSE_EVENTLOG *q_u, EVENTLOG_R_CLOSE_EVENTLOG *r_u) +WERROR _eventlog_close_eventlog( pipes_struct * p, + EVENTLOG_Q_CLOSE_EVENTLOG * q_u, + EVENTLOG_R_CLOSE_EVENTLOG * r_u ) { - EventlogInfo *info = find_eventlog_info_by_hnd(p,&q_u->handle); + EventlogInfo *info = find_eventlog_info_by_hnd( p, &q_u->handle ); - if ( !(close_eventlog_hook(info)) ) + if ( !( close_eventlog_hook( info ) ) ) return WERR_BADFILE; - if ( !(close_policy_hnd(p, &q_u->handle)) ) { + if ( !( close_policy_hnd( p, &q_u->handle ) ) ) { return WERR_BADFID; } @@ -870,76 +799,93 @@ WERROR _eventlog_close_eventlog(pipes_struct *p, EVENTLOG_Q_CLOSE_EVENTLOG *q_u, } /******************************************************************** -********************************************************************/ - -WERROR _eventlog_read_eventlog(pipes_struct *p, EVENTLOG_Q_READ_EVENTLOG *q_u, EVENTLOG_R_READ_EVENTLOG *r_u) + ********************************************************************/ + +WERROR _eventlog_read_eventlog( pipes_struct * p, + EVENTLOG_Q_READ_EVENTLOG * q_u, + EVENTLOG_R_READ_EVENTLOG * r_u ) { - EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle); + EventlogInfo *info = find_eventlog_info_by_hnd( p, &q_u->handle ); Eventlog_entry entry, *ee_new; - BOOL eof = False, eor = False; - const char *direction = ""; + uint32 num_records_read = 0; prs_struct *ps; - int numlines, i; - char **buffer; + int bytes_left, record_number; + TDB_CONTEXT *the_tdb; + info->flags = q_u->flags; ps = &p->out_data.rdata; - if ( info->flags & EVENTLOG_FORWARDS_READ ) - direction = "forward"; - else if ( info->flags & EVENTLOG_BACKWARDS_READ ) - direction = "backward"; - if ( !(read_eventlog_hook(info, &entry, direction, q_u->offset, q_u->max_read_size, &eof, &buffer, &numlines)) ) { - if(eof == False) { - return WERR_NOMEM; - } + bytes_left = q_u->max_read_size; + the_tdb = tdb_of( info->logname ); + if ( !the_tdb ) { + /* todo handle the error */ + } + /* DEBUG(8,("Bytes left is %d\n",bytes_left)); */ + + + record_number = q_u->offset; + + while ( bytes_left > 0 ) { + if ( get_eventlog_record + ( ps, the_tdb, record_number, &entry ) ) { + DEBUG( 8, + ( "Retrieved record %d\n", record_number ) ); + /* Now see if there is enough room to add */ + if ( ( ee_new = + read_package_entry( ps, q_u, r_u, + &entry ) ) == NULL ) { + return WERR_NOMEM; - if(numlines > 0) { - ZERO_STRUCT(entry); - for(i = 0; i < numlines; i++) { - num_records_read = r_u->num_records; - DEBUGADD(10, ("Line[%d] = [%s]\n", i, buffer[i])); - parse_logentry(buffer[i], &entry, &eor); - if(eor == True) { - /* package ee_new entry */ - if((ee_new = read_package_entry(ps, q_u, r_u, &entry)) == NULL) { - SAFE_FREE(buffer); - return WERR_NOMEM; - } - /* Now see if there is enough room to add */ - if(r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size) { - r_u->bytes_in_next_record = ee_new->record.length; - /* response would be too big to fit in client-size buffer */ - break; - } - add_record_to_resp(r_u, ee_new); - ZERO_STRUCT(entry); - eor=False; - num_records_read = r_u->num_records - num_records_read; - DEBUG(10, ("_eventlog_read_eventlog: read [%d] records for a total of [%d] records using [%d] bytes out of a max of [%d].\n", - num_records_read, - r_u->num_records, - r_u->num_bytes_in_resp, - q_u->max_read_size)); } + + if ( r_u->num_bytes_in_resp + ee_new->record.length > + q_u->max_read_size ) { + r_u->bytes_in_next_record = + ee_new->record.length; + /* response would be too big to fit in client-size buffer */ + bytes_left = 0; + break; + } + add_record_to_resp( r_u, ee_new ); + bytes_left -= ee_new->record.length; + ZERO_STRUCT( entry ); + num_records_read = + r_u->num_records - num_records_read; + DEBUG( 10, + ( "_eventlog_read_eventlog: read [%d] records for a total of [%d] records using [%d] bytes out of a max of [%d].\n", + num_records_read, r_u->num_records, + r_u->num_bytes_in_resp, + q_u->max_read_size ) ); + } else { + DEBUG( 8, ( "get_eventlog_record returned NULL\n" ) ); + return WERR_NOMEM; /* wrong error - but return one anyway */ } - SAFE_FREE(buffer); - } + + if ( info->flags & EVENTLOG_FORWARDS_READ ) { + record_number++; + } else { + record_number--; + } + + } return WERR_OK; } /******************************************************************** -********************************************************************/ + ********************************************************************/ -WERROR _eventlog_get_oldest_entry(pipes_struct *p, EVENTLOG_Q_GET_OLDEST_ENTRY *q_u, EVENTLOG_R_GET_OLDEST_ENTRY *r_u) +WERROR _eventlog_get_oldest_entry( pipes_struct * p, + EVENTLOG_Q_GET_OLDEST_ENTRY * q_u, + EVENTLOG_R_GET_OLDEST_ENTRY * r_u ) { - EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle); + EventlogInfo *info = find_eventlog_info_by_hnd( p, &q_u->handle ); - if ( !(get_oldest_entry_hook(info)) ) + if ( !( get_oldest_entry_hook( info ) ) ) return WERR_BADFILE; r_u->oldest_entry = info->oldest_entry; @@ -948,17 +894,18 @@ WERROR _eventlog_get_oldest_entry(pipes_struct *p, EVENTLOG_Q_GET_OLDEST_ENTRY * } /******************************************************************** -********************************************************************/ + ********************************************************************/ -WERROR _eventlog_get_num_records(pipes_struct *p, EVENTLOG_Q_GET_NUM_RECORDS *q_u, EVENTLOG_R_GET_NUM_RECORDS *r_u) +WERROR _eventlog_get_num_records( pipes_struct * p, + EVENTLOG_Q_GET_NUM_RECORDS * q_u, + EVENTLOG_R_GET_NUM_RECORDS * r_u ) { - EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle); + EventlogInfo *info = find_eventlog_info_by_hnd( p, &q_u->handle ); - if ( !(get_num_records_hook(info)) ) + if ( !( get_num_records_hook( info ) ) ) return WERR_BADFILE; r_u->num_records = info->num_records; return WERR_OK; } - diff --git a/source3/rpc_server/srv_ntsvcs_nt.c b/source3/rpc_server/srv_ntsvcs_nt.c index 0bb9154aaf..79259174fd 100644 --- a/source3/rpc_server/srv_ntsvcs_nt.c +++ b/source3/rpc_server/srv_ntsvcs_nt.c @@ -80,11 +80,9 @@ WERROR _ntsvcs_get_device_list( pipes_struct *p, NTSVCS_Q_GET_DEVICE_LIST *q_u, rpcstr_pull(device, q_u->devicename->buffer, sizeof(device), q_u->devicename->uni_str_len*2, 0); devicepath = get_device_path( device ); - /* From the packet traces I've see, I think this really should be an array - of UNISTR2's. But I've never seen more than one string in spite of the - fact that the string in double NULL terminated. -- jerry */ + /* This has to be DOUBLE NULL terminated */ - init_unistr2( &r_u->devicepath, devicepath, UNI_STR_TERMINATE ); + init_unistr2( &r_u->devicepath, devicepath, UNI_STR_DBLTERMINATE ); r_u->needed = r_u->devicepath.uni_str_len; return WERR_OK; diff --git a/source3/rpc_server/srv_reg_nt.c b/source3/rpc_server/srv_reg_nt.c index 4db5ed0ed6..0ba3e04b99 100644 --- a/source3/rpc_server/srv_reg_nt.c +++ b/source3/rpc_server/srv_reg_nt.c @@ -293,9 +293,11 @@ WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY SEC_RIGHTS_CREATE_SUBKEY| SEC_RIGHTS_QUERY_VALUE| SEC_RIGHTS_SET_VALUE); - - if ( !(parent->access_granted & check_rights) ) + + if ( !(parent->access_granted & check_rights) ) { + DEBUG(8,("Rights check failed, parent had %04x, check_rights %04x\n",parent->access_granted, check_rights)); return WERR_ACCESS_DENIED; + } /* * very crazy, but regedit.exe on Win2k will attempt to call diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c index e8df2acb22..19648f5e78 100644 --- a/source3/rpc_server/srv_svcctl_nt.c +++ b/source3/rpc_server/srv_svcctl_nt.c @@ -32,10 +32,21 @@ struct service_control_op { SERVICE_CONTROL_OPS *ops; }; -extern SERVICE_CONTROL_OPS spoolss_svc_ops; +#define SVCCTL_NUM_INTERNAL_SERVICES 4 + +/* handle external services */ extern SERVICE_CONTROL_OPS rcinit_svc_ops; + +/* builtin services (see service_db.c and services/svc_*.c */ +extern SERVICE_CONTROL_OPS spoolss_svc_ops; extern SERVICE_CONTROL_OPS netlogon_svc_ops; extern SERVICE_CONTROL_OPS winreg_svc_ops; +extern SERVICE_CONTROL_OPS wins_svc_ops; + +/* make sure this number patches the number of builtin + SERVICE_CONTROL_OPS structure listed above */ + +#define SVCCTL_NUM_INTERNAL_SERVICES 4 struct service_control_op *svcctl_ops; @@ -51,7 +62,7 @@ static struct generic_mapping svc_generic_map = BOOL init_service_op_table( void ) { const char **service_list = lp_svcctl_list(); - int num_services = 3 + str_list_count( service_list ); + int num_services = SVCCTL_NUM_INTERNAL_SERVICES + str_list_count( service_list ); int i; if ( !(svcctl_ops = TALLOC_ARRAY( NULL, struct service_control_op, num_services+1)) ) { @@ -80,6 +91,10 @@ BOOL init_service_op_table( void ) svcctl_ops[i].ops = &winreg_svc_ops; i++; + svcctl_ops[i].name = talloc_strdup( svcctl_ops, "WINS" ); + svcctl_ops[i].ops = &wins_svc_ops; + i++; + /* NULL terminate the array */ svcctl_ops[i].name = NULL; diff --git a/source3/services/services_db.c b/source3/services/services_db.c index b59cd5330e..7c75d41352 100644 --- a/source3/services/services_db.c +++ b/source3/services/services_db.c @@ -23,6 +23,58 @@ #include "includes.h" +struct rcinit_file_information { + char *description; +}; + +struct service_display_info { + const char *servicename; + const char *daemon; + const char *dispname; + const char *description; +}; + +struct service_display_info builtin_svcs[] = { + { "Spooler", "smbd", "Print Spooler", + "Internal service for spooling files to print devices" }, + { "NETLOGON", "smbd", "Net Logon", + "File service providing access to policy and profile data" }, + { "RemoteRegistry", "smbd", "Remote Registry Service", + "Internal service providing remote access to the Samba registry" }, + { "WINS", "nmbd", "Windows Internet Name Service (WINS)", + "Internal service providing a NetBIOS point-to-point name server" }, + { NULL, NULL, NULL, NULL } +}; + +struct service_display_info common_unix_svcs[] = { + { "cups", NULL, "Common Unix Printing System", NULL }, + { "postfix", NULL, "Internet Mail Service", NULL }, + { "sendmail", NULL, "Internet Mail Service", NULL }, + { "portmap", NULL, "TCP Port to RPC PortMapper", NULL }, + { "xinetd", NULL, "Internet Meta-Daemon", NULL }, + { "inet", NULL, "Internet Meta-Daemon", NULL }, + { "xntpd", NULL, "Network Time Service", NULL }, + { "ntpd", NULL, "Network Time Service", NULL }, + { "lpd", NULL, "BSD Print Spooler", NULL }, + { "nfsserver", NULL, "Network File Service", NULL }, + { "cron", NULL, "Scheduling Service", NULL }, + { "at", NULL, "Scheduling Service", NULL }, + { "nscd", NULL, "Name Service Cache Daemon", NULL }, + { "slapd", NULL, "LDAP Directory Service", NULL }, + { "ldap", NULL, "LDAP DIrectory Service", NULL }, + { "ypbind", NULL, "NIS Directory Service", NULL }, + { "courier-imap", NULL, "IMAP4 Mail Service", NULL }, + { "courier-pop3", NULL, "POP3 Mail Service", NULL }, + { "named", NULL, "Domain Name Service", NULL }, + { "bind", NULL, "Domain Name Service", NULL }, + { "httpd", NULL, "HTTP Server", NULL }, + { "apache", NULL, "HTTP Server", NULL }, + { "autofs", NULL, "Automounter", NULL }, + { "squid", NULL, "Web Cache Proxy ", NULL }, + { NULL, NULL, NULL, NULL } +}; + + /******************************************************************** ********************************************************************/ @@ -63,11 +115,122 @@ static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx ) Display name, Description, etc... ********************************************************************/ +static char *get_common_service_dispname( const char *servicename ) +{ + static fstring dispname; + int i; + + for ( i=0; common_unix_svcs[i].servicename; i++ ) { + if ( strequal( servicename, common_unix_svcs[i].servicename ) ) { + fstr_sprintf( dispname, "%s (%s)", + common_unix_svcs[i].dispname, + common_unix_svcs[i].servicename ); + + return dispname; + } + } + + fstrcpy( dispname, servicename ); + + return dispname; +} + +/******************************************************************** +********************************************************************/ + +static char* cleanup_string( const char *string ) +{ + static pstring clean; + char *begin, *end; + + pstrcpy( clean, string ); + begin = clean; + + /* trim any beginning whilespace */ + + while ( isspace(*begin) ) + begin++; + + if ( !begin ) + return NULL; + + /* trim any trailing whitespace or carriage returns. + Start at the end and move backwards */ + + end = begin + strlen(begin) - 1; + + while ( isspace(*end) || *end=='\n' || *end=='\r' ) { + *end = '\0'; + end--; + } + + return begin; +} + +/******************************************************************** +********************************************************************/ + +static BOOL read_init_file( const char *servicename, struct rcinit_file_information **service_info ) +{ + struct rcinit_file_information *info; + pstring filepath, str; + XFILE *f; + char *p, *s; + + if ( !(info = TALLOC_ZERO_P( NULL, struct rcinit_file_information ) ) ) + return False; + + /* attempt the file open */ + + pstr_sprintf( filepath, "%s/%s/%s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, servicename ); + if ( !(f = x_fopen( filepath, O_RDONLY, 0 )) ) { + DEBUG(0,("read_init_file: failed to open [%s]\n", filepath)); + TALLOC_FREE(info); + return False; + } + + while ( (s = x_fgets( str, sizeof(str)-1, f )) != NULL ) { + /* ignore everything that is not a full line + comment starting with a '#' */ + + if ( str[0] != '#' ) + continue; + + /* Look for a line like '^#.*Description:' */ + + if ( (p = strstr( str, "Description:" )) != NULL ) { + char *desc; + + p += strlen( "Description:" ) + 1; + if ( !p ) + break; + + if ( (desc = cleanup_string(p)) != NULL ) + info->description = talloc_strdup( info, desc ); + } + } + + x_fclose( f ); + + if ( !info->description ) + info->description = talloc_strdup( info, "External Unix Service" ); + + *service_info = info; + + return True; +} + +/******************************************************************** + This is where we do the dirty work of filling in things like the + Display name, Description, etc... +********************************************************************/ + static void fill_service_values( const char *name, REGVAL_CTR *values ) { UNISTR2 data, dname, ipath, description; uint32 dword; pstring pstr; + int i; /* These values are hardcoded in all QueryServiceConfig() replies. I'm just storing them here for cosmetic purposes */ @@ -88,30 +251,39 @@ static void fill_service_values( const char *name, REGVAL_CTR *values ) /* special considerations for internal services and the DisplayName value */ - if ( strequal(name, "Spooler") ) { - pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); - init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); - init_unistr2( &description, "Internal service for spooling files to print devices", UNI_STR_TERMINATE ); - init_unistr2( &dname, "Print Spooler", UNI_STR_TERMINATE ); - } - else if ( strequal(name, "NETLOGON") ) { - pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); - init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); - init_unistr2( &description, "File service providing access to policy and profile data", UNI_STR_TERMINATE ); - init_unistr2( &dname, "Net Logon", UNI_STR_TERMINATE ); + for ( i=0; builtin_svcs[i].servicename; i++ ) { + if ( strequal( name, builtin_svcs[i].servicename ) ) { + pstr_sprintf( pstr, "%s/%s/%s",dyn_LIBDIR, SVCCTL_SCRIPT_DIR, builtin_svcs[i].daemon ); + init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); + init_unistr2( &description, builtin_svcs[i].description, UNI_STR_TERMINATE ); + init_unistr2( &dname, builtin_svcs[i].dispname, UNI_STR_TERMINATE ); + break; + } } - else if ( strequal(name, "RemoteRegistry") ) { - pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); - init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); - init_unistr2( &description, "Internal service providing remote access to the Samba registry", UNI_STR_TERMINATE ); - init_unistr2( &dname, "Remote Registry Service", UNI_STR_TERMINATE ); - } - else { + + /* default to an external service if we haven't found a match */ + + if ( builtin_svcs[i].servicename == NULL ) { + struct rcinit_file_information *init_info = NULL; + pstr_sprintf( pstr, "%s/%s/%s",dyn_LIBDIR, SVCCTL_SCRIPT_DIR, name ); init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); - init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE ); - init_unistr2( &dname, name, UNI_STR_TERMINATE ); + + /* lookup common unix display names */ + init_unistr2( &dname, get_common_service_dispname( name ), UNI_STR_TERMINATE ); + + /* get info from init file itself */ + if ( read_init_file( name, &init_info ) ) { + init_unistr2( &description, init_info->description, UNI_STR_TERMINATE ); + TALLOC_FREE( init_info ); + } + else { + init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE ); + } } + + /* add the new values */ + regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2); regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2); regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2); @@ -248,9 +420,8 @@ void svcctl_init_keys( void ) /* the builting services exist */ - add_new_svc_name( key, subkeys, "Spooler" ); - add_new_svc_name( key, subkeys, "NETLOGON" ); - add_new_svc_name( key, subkeys, "RemoteRegistry" ); + for ( i=0; builtin_svcs[i].servicename; i++ ) + add_new_svc_name( key, subkeys, builtin_svcs[i].servicename ); for ( i=0; service_list[i]; i++ ) { @@ -352,29 +523,34 @@ char* svcctl_lookup_dispname( const char *name, NT_USER_TOKEN *token ) /* now add the security descriptor */ pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); - wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL ); + wresult = regkey_open_internal( &key, path, token, REG_KEY_READ ); if ( !W_ERROR_IS_OK(wresult) ) { DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", path, dos_errstr(wresult))); - return NULL; + goto fail; } if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) { DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n")); TALLOC_FREE( key ); - return NULL; + goto fail; } fetch_reg_values( key, values ); if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) ) - fstrcpy( display_name, name ); - else - rpcstr_pull( display_name, regval_data_p(val), sizeof(display_name), regval_size(val), 0 ); + goto fail; + + rpcstr_pull( display_name, regval_data_p(val), sizeof(display_name), regval_size(val), 0 ); TALLOC_FREE( key ); return display_name; + +fail: + /* default to returning the service name */ + fstrcpy( display_name, name ); + return display_name; } /******************************************************************** @@ -392,7 +568,7 @@ char* svcctl_lookup_description( const char *name, NT_USER_TOKEN *token ) /* now add the security descriptor */ pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); - wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL ); + wresult = regkey_open_internal( &key, path, token, REG_KEY_READ ); if ( !W_ERROR_IS_OK(wresult) ) { DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", path, dos_errstr(wresult))); @@ -431,7 +607,7 @@ REGVAL_CTR* svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token ) /* now add the security descriptor */ pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); - wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL ); + wresult = regkey_open_internal( &key, path, token, REG_KEY_READ ); if ( !W_ERROR_IS_OK(wresult) ) { DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n", path, dos_errstr(wresult))); diff --git a/source3/services/svc_rcinit.c b/source3/services/svc_rcinit.c index 5801d076c4..f60019601f 100644 --- a/source3/services/svc_rcinit.c +++ b/source3/services/svc_rcinit.c @@ -1,4 +1,3 @@ - /* * Unix SMB/CIFS implementation. * Service Control API Implementation @@ -21,153 +20,6 @@ #include "includes.h" -/* Implementation for LSB compliant init scripts */ - -/******************************************************************************* - Get the services information by reading and parsing the shell scripts. These - are symbolically linked into the SVCCTL_SCRIPT_DIR directory. - - Get the names of the services/scripts to read from the smb.conf file. -*******************************************************************************/ - -BOOL get_LSB_data(char *fname,Service_info *si ) -{ - pstring initdfile; - char mybuffer[256]; - const char *tokenptr; - char **qlines; - int fd = -1; - int nlines, *numlines,i,in_section,in_description; - - pstrcpy(si->servicename,""); - pstrcpy(si->servicetype,"EXTERNAL"); - pstrcpy(si->filename,fname); - pstrcpy(si->provides,""); - pstrcpy(si->dependencies,""); - pstrcpy(si->shouldstart,""); - pstrcpy(si->shouldstop,""); - pstrcpy(si->requiredstart,""); - pstrcpy(si->requiredstop,""); - pstrcpy(si->description,""); - pstrcpy(si->shortdescription,""); - - numlines = &nlines; - in_section = 0; - in_description = 0; - - - if( !fname || !*fname ) { - DEBUG(0, ("Must define an \"LSB-style init file\" to read.\n")); - return False; - } - pstrcpy(initdfile,dyn_LIBDIR); - pstrcat(initdfile,SVCCTL_SCRIPT_DIR); - pstrcat(initdfile,fname); - - /* TODO - should check to see if the file that we're trying to open is - actually a script. If it's NOT, we should do something like warn, - and not continue to try to find info we're looking for */ - - DEBUG(10, ("Opening [%s]\n", initdfile)); - fd = -1; - fd = open(initdfile,O_RDONLY); - *numlines = 0; - - if (fd == -1) { - DEBUG(10, ("Couldn't open [%s]\n", initdfile)); - return False; - } - - qlines = fd_lines_load(fd, numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", *numlines)); - close(fd); - - - if (*numlines) { - - for(i = 0; i < *numlines; i++) { - - DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i])); - if (!in_section && (0==strwicmp("### BEGIN INIT INFO", qlines[i]))) { - /* we now can look for params */ - DEBUGADD(10, ("Configuration information starts on line = [%d]\n", i)); - in_section = 1; - - } else if (in_section && (0==strwicmp("### END INIT INFO", qlines[i]))) { - DEBUGADD(10, ("Configuration information ends on line = [%d]\n", i)); - DEBUGADD(10, ("Description is [%s]\n", si->description)); - in_description = 0; - in_section = 0; - break; - } else if (in_section) { - tokenptr = qlines[i]; - if (in_description) { - DEBUGADD(10, ("Processing DESCRIPTION [%d]\n", *tokenptr)); - if (tokenptr && (*tokenptr=='#') && (*(tokenptr+1)=='\t')) { - DEBUGADD(10, ("Adding to DESCRIPTION [%d]\n", *tokenptr)); - pstrcat(si->description," "); - pstrcat(si->description,tokenptr+2); - continue; - } - in_description = 0; - DEBUGADD(10, ("Not a description!\n")); - } - if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) { - DEBUGADD(10, ("Invalid line [%d]\n", i)); - break; /* bad line? */ - } - if (0 != strncmp(mybuffer,"#",1)) { - DEBUGADD(10, ("Invalid line [%d], is %s\n", i,mybuffer)); - break; - } - if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) { - DEBUGADD(10, ("Invalid token on line [%d]\n", i)); - break; /* bad line? */ - } - DEBUGADD(10, ("Keyword is [%s]\n", mybuffer)); - if (0==strwicmp(mybuffer,"Description:")) { - while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { - tokenptr++; - } - pstrcpy(si->description,tokenptr); - DEBUGADD(10, ("FOUND DESCRIPTION! Data is [%s]\n", tokenptr)); - in_description = 1; - } else { - while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { - tokenptr++; - } - DEBUGADD(10, ("Data is [%s]\n", tokenptr)); - in_description = 0; - - /* save certain keywords, don't save others */ - if (0==strwicmp(mybuffer, "Provides:")) { - pstrcpy(si->provides,tokenptr); - pstrcpy(si->servicename,tokenptr); - } - - if (0==strwicmp(mybuffer, "Short-Description:")) { - pstrcpy(si->shortdescription,tokenptr); - } - - if (0==strwicmp(mybuffer, "Required-start:")) { - pstrcpy(si->requiredstart,tokenptr); - pstrcpy(si->dependencies,tokenptr); - } - - if (0==strwicmp(mybuffer, "Should-start:")) { - pstrcpy(si->shouldstart,tokenptr); - } - } - } - } - - file_lines_free(qlines); - return True; - } - - return False; -} - /********************************************************************* *********************************************************************/ diff --git a/source3/services/svc_wins.c b/source3/services/svc_wins.c new file mode 100644 index 0000000000..3a4650664d --- /dev/null +++ b/source3/services/svc_wins.c @@ -0,0 +1,66 @@ +/* + * Unix SMB/CIFS implementation. + * Service Control API Implementation + * Copyright (C) Gerald Carter 2005. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + +/* Implementation for internal wins service */ + +/********************************************************************* +*********************************************************************/ + +static WERROR wins_stop( const char *service, SERVICE_STATUS *service_status ) +{ + return WERR_ACCESS_DENIED; +} + +/********************************************************************* +*********************************************************************/ + +static WERROR wins_start( const char *service ) +{ + return WERR_ACCESS_DENIED; +} + +/********************************************************************* +*********************************************************************/ + +static WERROR wins_status( const char *service, SERVICE_STATUS *service_status ) +{ + ZERO_STRUCTP( service_status ); + + service_status->type = 0x10; + if ( lp_wins_support() ) + service_status->state = SVCCTL_RUNNING; + else + service_status->state = SVCCTL_STOPPED; + + return WERR_OK; +} + +/********************************************************************* +*********************************************************************/ + +/* struct for svcctl control to manipulate wins service */ + +SERVICE_CONTROL_OPS wins_svc_ops = { + wins_stop, + wins_start, + wins_status +}; -- cgit