From 3d6591dd63c23bcc0ae68e94a960c85fd53daad0 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Mon, 5 Jun 2006 04:30:35 +0000 Subject: more updates git-svn-id: svn://anonsvn.mit.edu/krb5/branches/ccapi@18082 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/ccapi/windows/NTMakefile | 35 ++ src/lib/ccapi/windows/cacheapi.def | 29 ++ src/lib/ccapi/windows/client.c | 120 +++++++ src/lib/ccapi/windows/dllmain.c | 15 + src/lib/ccapi/windows/ntccrpc.acf | 8 + src/lib/ccapi/windows/ntccrpc.idl | 31 ++ src/lib/ccapi/windows/server.c | 638 +++++++++++++++++++++++++++++++++++++ 7 files changed, 876 insertions(+) create mode 100644 src/lib/ccapi/windows/NTMakefile create mode 100644 src/lib/ccapi/windows/cacheapi.def create mode 100644 src/lib/ccapi/windows/client.c create mode 100644 src/lib/ccapi/windows/dllmain.c create mode 100644 src/lib/ccapi/windows/ntccrpc.acf create mode 100644 src/lib/ccapi/windows/ntccrpc.idl create mode 100644 src/lib/ccapi/windows/server.c (limited to 'src/lib/ccapi/windows') diff --git a/src/lib/ccapi/windows/NTMakefile b/src/lib/ccapi/windows/NTMakefile new file mode 100644 index 000000000..f6fee6f68 --- /dev/null +++ b/src/lib/ccapi/windows/NTMakefile @@ -0,0 +1,35 @@ +!include + +CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsmt) + +CCAPI_SERVER = ccapi_server.exe + +CCAPI_DLLFILE = krbcc32.dll + +WINLIBS = ws2_32.lib rpcrt4.lib $(guilibsdll) + +all: $(CCAPI_DLLFILE) $(CCAPI_SERVER) + +ntccrpc_c.c ntccrpc_s.c ntccrpc.h: ntccrpc.idl ntccrpc.acf + midl ntccrpc.idl /acf ntccrpc.acf + +CLIENT_OBJS = ntccrpc_c.obj client.obj dllmain.obj + +SERVER_OBJS = ntccrpc_s.obj server.obj + +CC_CLIENT_LIB = ..\client\cc_client.lib + +CC_COMMON_LIB = ..\common\cc_common.lib + +CC_SERVER_LIB = ..\server\cc_server.lib + +$(CCAPI_DLLFILE): $(CLIENT_OBJS) $(CC_CLIENT_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO /OUT:$@ $(ldebug) $(dlllflags) $(guilibsmt) -def:cacheapi.def $** $(WINLIBS) + +$(CCAPI_SERVER): $(SERVER_OBJS) $(CC_SERVER_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO $(conlibsmt) $(ldebug) $(conlflags) /OUT:$@ $** $(WINLIBS) + +clean: + del *.exe *.dll *.lib *.exp *.obj ntccrpc_c.c ntccrpc_s.c ntccrpc.h + + diff --git a/src/lib/ccapi/windows/cacheapi.def b/src/lib/ccapi/windows/cacheapi.def new file mode 100644 index 000000000..c54cc1106 --- /dev/null +++ b/src/lib/ccapi/windows/cacheapi.def @@ -0,0 +1,29 @@ +EXPORTS + ; ccapi v3 only exports one function + cc_initialize @14 + + ; ccapi v2 compatibility functions + cc_close @2 + cc_create @3 + cc_destroy @4 + cc_free_NC_info @5 + cc_free_creds @6 + cc_free_name @7 + cc_free_principal @8 + cc_get_NC_info @9 + cc_get_change_time @10 + cc_get_cred_version @11 + cc_get_name @12 + cc_get_principal @13 + cc_lock_request @15 + cc_open @16 + cc_remove_cred @17 + cc_seq_fetch_NCs_begin @18 + cc_seq_fetch_NCs_end @19 + cc_seq_fetch_NCs_next @20 + cc_seq_fetch_creds_begin @21 + cc_seq_fetch_creds_end @22 + cc_seq_fetch_creds_next @23 + cc_set_principal @24 + cc_shutdown @25 + cc_store @26 diff --git a/src/lib/ccapi/windows/client.c b/src/lib/ccapi/windows/client.c new file mode 100644 index 000000000..db0b63aec --- /dev/null +++ b/src/lib/ccapi/windows/client.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include "ntccrpc.h" +#include +#include "CredentialsCache.h" +#include "msg.h" + +static RPC_BINDING_HANDLE hRpcBinding; + +void * __RPC_USER MIDL_user_allocate(size_t s) { + return malloc(s); +} + +void __RPC_USER MIDL_user_free(void * p) { + free(p); +} + +int cc_rpc_init(void) { + RPC_STATUS status; + TCHAR * bindstring = NULL; + RPC_SECURITY_QOS sqos; + + status = RpcStringBindingCompose(NULL, + _T("ncalrpc"), + NULL, + NULL, + NULL, + &bindstring); + + if (status != RPC_S_OK) { + fprintf(stderr, "RpcStringBindingCompose failed: %d\n", + status); + return 1; + } + + status = RpcBindingFromStringBinding(bindstring, + &hRpcBinding); + + if (status != RPC_S_OK) { + fprintf(stderr, "RpcBindingFromStringBinding failed: %d\n", + status); + return 1; + } + + status = RpcStringFree(&bindstring); + + ZeroMemory(&sqos, sizeof(sqos)); + + sqos.Version = 1; + sqos.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT; + sqos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC; + sqos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE; + + status = RpcBindingSetAuthInfoEx(hRpcBinding, + NULL, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_AUTHN_WINNT, + NULL, + 0, + &sqos); + if (status != RPC_S_OK) { + fprintf(stderr, "RpcBindingSetAuthInfoEx failed: %d\n", + status); + return 1; + } + + return 0; +} + +int cc_rpc_cleanup(void) { + RPC_STATUS status; + + status = RpcBindingFree(&hRpcBinding); + + return 0; +} + +cc_int32 cci_set_thread_session_id(unsigned char * client_name, LUID luid) { + +} + +void cci_get_thread_session_id(unsigned char * client_name, int len, LUID *pluid) { + +} + + +/* __int32 ccapi_Message( + * [in] handle_t h, + * [string][in] unsigned char *client_name, + * [in] struct _LUID luid, + * [in] __int32 cb_buffer, + * [out] __int32 *cb_len, + * [size_is][string][out] unsigned char buffer[ ]); + */ + +cc_int32 cci_perform_rpc(cc_msg_t *request, cc_msg_t **response) +{ + __int32 rpc_code; + unsigned char client_name[256]; + LUID luid; + struct __LUID __luid; + unsigned char out_buf[MAXMSGLEN]; + __int32 out_len = MAXMSGLEN; + + if (!cc_rpc_init()) + return -1; + + cci_get_thread_session_id(client_name, sizeof(client_name), &luid); + + __luid.HighPart = luid.HighPart; + __luid.LowPart = luid.LowPart; + + rpc_code = ccapi_Message(hRpcBinding, client_name, __luid, + request->flat, request->flat_len, + out_buf, &out_len); + + return rpc_code; +} diff --git a/src/lib/ccapi/windows/dllmain.c b/src/lib/ccapi/windows/dllmain.c new file mode 100644 index 000000000..6b4d6bfdd --- /dev/null +++ b/src/lib/ccapi/windows/dllmain.c @@ -0,0 +1,15 @@ +#include + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + default: + return TRUE; + } +} + diff --git a/src/lib/ccapi/windows/ntccrpc.acf b/src/lib/ccapi/windows/ntccrpc.acf new file mode 100644 index 000000000..77216a9ea --- /dev/null +++ b/src/lib/ccapi/windows/ntccrpc.acf @@ -0,0 +1,8 @@ +[ + explicit_handle +] + +interface portable_ccapi +{ + +} \ No newline at end of file diff --git a/src/lib/ccapi/windows/ntccrpc.idl b/src/lib/ccapi/windows/ntccrpc.idl new file mode 100644 index 000000000..0dd038f6f --- /dev/null +++ b/src/lib/ccapi/windows/ntccrpc.idl @@ -0,0 +1,31 @@ +[ + uuid(c8b4a635-e9e4-4650-a073-b25610324950), + version(1.0), + endpoint("ncalrpc:[mit_nt_ccapi]"), + pointer_default(unique) +] + +interface portable_ccapi +{ + const short MAXMSGLEN = 65536; + + // Locally Unique Identifier + // + + struct __LUID { + __int32 LowPart; + long HighPart; + }; + + + // The Generic CCAPI Message RPC + + __int32 ccapi_Message ( + [in] handle_t h, + [in, string] unsigned char * client_name, + [in] struct __LUID luid, + [in, length_is(in_len), size_is(MAXMSGLEN)] unsigned char in_buf[], + [in] __int32 in_len, + [out, length_is(*out_len), size_is(MAXMSGLEN)] unsigned char out_buf[], + [out] __int32 * out_len); +} diff --git a/src/lib/ccapi/windows/server.c b/src/lib/ccapi/windows/server.c new file mode 100644 index 000000000..5ce8e6ebe --- /dev/null +++ b/src/lib/ccapi/windows/server.c @@ -0,0 +1,638 @@ + + +#include +#include "msg.h" +#include "marshall.h" +#include "serv_ops.h" +#include "datastore.h" +#include +#include +#include +#include +#include +#include "ntccrpc.h" +#include + +#define SVCNAME "MIT_CCAPI_NT_Service" + +SERVICE_STATUS_HANDLE h_service_status = NULL; +SERVICE_STATUS service_status; +FILE * logfile = NULL; + +/* Log File */ +void begin_log(void) { + char temppath[512]; + + temppath[0] = L'\0'; + + GetTempPathA(sizeof(temppath), temppath); + StringCbCatA(temppath, sizeof(temppath), "mit_nt_ccapi.log"); + logfile = fopen(temppath, "w"); +} + +void end_log(void) { + if (logfile) { + fclose(logfile); + logfile = NULL; + } +} + +BOOL report_status(DWORD state, + DWORD exit_code, + DWORD wait_hint) { + static DWORD checkpoint = 1; + BOOL rv = TRUE; + + if (state == SERVICE_START_PENDING) + service_status.dwControlsAccepted = 0; + else + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + service_status.dwCurrentState = state; + service_status.dwWin32ExitCode = exit_code; + service_status.dwWaitHint = wait_hint; + + if (state == SERVICE_RUNNING || + state == SERVICE_STOPPED) + service_status.dwCheckPoint = 0; + else + service_status.dwCheckPoint = checkpoint++; + + rv = SetServiceStatus(h_service_status, &service_status); + + return rv; +} + +void service_start(DWORD argc, LPTSTR * argv) { + RPC_STATUS status; + RPC_BINDING_VECTOR * bv; + + status = RpcServerUseProtseq("ncalrpc", + RPC_C_PROTSEQ_MAX_REQS_DEFAULT, + NULL); + + if (status != RPC_S_OK) { + return; + } + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerRegisterIf(portable_ccapi_v1_0_s_ifspec, + 0, 0); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerInqBindings(&bv); + + if (status != RPC_S_OK) + return; + + status = RpcEpRegister(portable_ccapi_v1_0_s_ifspec, + bv, 0, 0); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerRegisterAuthInfo(NULL, + RPC_C_AUTHN_WINNT, + 0, 0); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerListen(1, + RPC_C_LISTEN_MAX_CALLS_DEFAULT, + TRUE); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_RUNNING, NO_ERROR, 0); + + begin_log(); + + status = RpcMgmtWaitServerListen(); + + end_log(); + + RpcEpUnregister(portable_ccapi_v1_0_s_ifspec, bv, 0); + + RpcBindingVectorFree(&bv); +} + +void service_stop(void) { + RpcMgmtStopServerListening(0); +} + +void * __RPC_USER MIDL_user_allocate(size_t s) { + return malloc(s); +} + +void __RPC_USER MIDL_user_free(void * p) { + free(p); +} + +typedef struct tag_client_info { + char client_name[512]; + LUID luid; +} client_info_t; + +int obtain_auth_info(client_info_t * client_info, cc_auth_info_t ** pauth_info) +{ + *pauth_info = (cc_auth_info_t *)malloc(sizeof(cc_auth_info_t)); + if ( !*pauth_info ) + return ccErrNoMem; + + (*pauth_info)->len = strlen(client_info->client_name) + 1; + (*pauth_info)->info = malloc((*pauth_info)->len); + if ( !(*pauth_info)->info ) { + free(*pauth_info); + return ccErrNoMem; + } + + memcpy((*pauth_info)->info, client_info->client_name, (*pauth_info)->len); + + return 0; +} + +void destroy_auth_info(cc_auth_info_t *auth_info) +{ + free(auth_info->info); + free(auth_info); +} + +int obtain_session_info(client_info_t * client_info, cc_session_info_t ** psession_info) +{ + *psession_info = (cc_session_info_t *)malloc(sizeof(cc_session_info_t)); + if ( !*psession_info ) + return ccErrNoMem; + + (*psession_info)->len = sizeof(LUID); + (*psession_info)->info = malloc((*psession_info)->len); + if ( !(*psession_info)->info ) { + free(*psession_info); + return ccErrNoMem; + } + + memcpy((*psession_info)->info, &client_info->luid, (*psession_info)->len); + + return 0; +} + +void destroy_session_info(cc_session_info_t *session_info) +{ + free(session_info->info); + free(session_info); +} + +RPC_STATUS check_auth(handle_t h, client_info_t * client_info) { + RPC_BINDING_HANDLE bh = (RPC_BINDING_HANDLE) h; + RPC_STATUS status; + HANDLE htoken = NULL; + char name[256]; + char domain[256]; + DWORD name_len; + DWORD domain_len; + SID_NAME_USE snu = 0; + + struct { + TOKEN_ORIGIN origin; + char pad[512]; + } torigin; + + struct { + TOKEN_OWNER owner; + char pad[4096]; + } towner; + + DWORD len; + + status = RpcImpersonateClient(bh); + + if (status != RPC_S_OK) + return status; + + if (!OpenThreadToken(GetCurrentThread(), + TOKEN_READ | TOKEN_QUERY_SOURCE, + FALSE, + &htoken)) { + status = GetLastError(); + goto _cleanup; + } + + len = 0; + + if (!GetTokenInformation(htoken, + TokenOrigin, + &torigin.origin, + sizeof(torigin), + &len)) { + status = GetLastError(); + goto _cleanup; + } + + if (!GetTokenInformation(htoken, + TokenOwner, + &towner.owner, + sizeof(towner), + &len)) { + status = GetLastError(); + goto _cleanup; + } + + + name_len = sizeof(name)/sizeof(name[0]); + domain_len = sizeof(domain)/sizeof(domain[0]); + + if (!LookupAccountSidA(NULL, + towner.owner.Owner, + name, + &name_len, + domain, + &domain_len, + &snu)) { + status = GetLastError(); + goto _cleanup; + } + + client_info->luid = torigin.origin.OriginatingLogonSession; + StringCbPrintfA(client_info->client_name, + sizeof(client_info->client_name), + "%s\\%s", domain, name); + + status = 0; + + _cleanup: + + RpcRevertToSelf(); + + return status; +} + +__int32 ccapi_Message( + /* [in] */ handle_t h, + /* [string][in] */ unsigned char *client_name, + /* [in] */ struct __LUID luid, + /* [size_is][length_is][in] */ unsigned char in_buf[], + /* [in] */ __int32 in_len, + /* [size_is][length_is][out] */ unsigned char out_buf[], + /* [out] */ __int32 *out_len) +{ + client_info_t client_info; + cc_msg_t * msg; + cc_msg_t * resp; + cc_auth_info_t * auth_info; + cc_session_info_t * session_info; + cc_int32 code; + + if ( ccs_serv_initialize() != ccNoError ) { + code = ccErrServerUnavailable; + goto done; + } + + code = check_auth(h, &client_info); + if (code == 0) { + if (!strcmp("SYSTEM",client_info.client_name) && + client_info.luid.HighPart == 0 && + client_info.luid.LowPart == 0 && + client_name != NULL && + client_name[0] != '\0') { + StringCbPrintfA(client_info.client_name, + sizeof(client_info.client_name), + "%s", client_name); + client_info.luid.HighPart = luid.HighPart; + client_info.luid.LowPart = luid.LowPart; + } + } else { + code = ccErrServerCantBecomeUID; + goto done; + } + + /* allocate message */ + msg = (cc_msg_t *)malloc(sizeof(cc_msg_t)); + if (!msg) { + code = ccErrNoMem; + goto done; + } + + /* unflatten message */ + code = cci_msg_unflatten(in_buf, in_len, &msg); + if (code) + goto cleanup; + + /* obtain auth info */ + code = obtain_auth_info(&client_info, &auth_info); + if (code) + goto cleanup; + + /* obtain session info */ + code = obtain_session_info(&client_info, &session_info); + if (code) + goto cleanup; + + /* process message */ + code = ccs_serv_process_msg(msg, auth_info, session_info, &resp); + if (code) + goto cleanup; + + /* flatten response */ + code = cci_msg_flatten(resp, NULL); + if (code) + goto cleanup; + + /* send response */ + if (resp->flat_len > MAXMSGLEN) { + code = ccErrBadInternalMessage; + goto cleanup; + } + memcpy(out_buf, resp->flat, resp->flat_len); + *out_len = resp->flat_len; + code = ccNoError; + + cleanup: + if (auth_info) + destroy_auth_info(auth_info); + + if (session_info) + destroy_session_info(session_info); + + /* free message */ + if (msg) + cci_msg_destroy(msg); + + /* free response */ + if (resp) + cci_msg_destroy(resp); + + done: + return code ? -1 : 0; +} + +void WINAPI service_control(DWORD ctrl_code) { + switch(ctrl_code) { + case SERVICE_CONTROL_STOP: + report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); + service_stop(); + return; + + /* everything else falls through */ + } + + report_status(service_status.dwCurrentState, NO_ERROR, 0); +} + +void WINAPI service_main(DWORD argc, LPTSTR * argv) { + + h_service_status = RegisterServiceCtrlHandler( _T(SVCNAME), service_control); + + if (!h_service_status) + goto cleanup; + + ZeroMemory(&service_status, sizeof(service_status)); + + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + service_status.dwServiceSpecificExitCode = 0; + + if (!report_status(SERVICE_START_PENDING, + NO_ERROR, + 3000)) + goto cleanup; + + service_start(argc, argv); + + cleanup: + + if (h_service_status) { + report_status(SERVICE_STOPPED, NO_ERROR, 0); + } +} + + +BOOL +IsInstalled() +{ + BOOL bResult = FALSE; + SC_HANDLE hSCM; + SC_HANDLE hService; + + // Open the Service Control Manager + hSCM = OpenSCManager( NULL, // local machine + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access + if (hSCM) { + + // Try to open the service + hService = OpenService( hSCM, + SVCNAME, + SERVICE_QUERY_CONFIG); + if (hService) { + bResult = TRUE; + CloseServiceHandle(hService); + } + + CloseServiceHandle(hSCM); + } + + return bResult; +} + +BOOL +Install() +{ + char szFilePath[_MAX_PATH]; + SC_HANDLE hSCM; + SC_HANDLE hService; + TCHAR szKey[256]; + HKEY hKey = NULL; + DWORD dwData; + + // Open the Service Control Manager + hSCM = OpenSCManager( NULL, // local machine + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access + if (!hSCM) + return FALSE; + + // Get the executable file path + GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); + + // Create the service + hService = CreateService( hSCM, + SVCNAME, + SVCNAME, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, // start condition + SERVICE_ERROR_NORMAL, + szFilePath, + NULL, + NULL, + NULL, + NULL, + NULL); + if (!hService) { + CloseServiceHandle(hSCM); + return FALSE; + } + + // make registry entries to support logging messages + // Add the source name as a subkey under the Application + // key in the EventLog service portion of the registry. + StringCbCopyA(szKey, 256, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\IKSD"); + if (RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) { + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return FALSE; + } + + // Add the Event ID message-file name to the 'EventMessageFile' subkey. + RegSetValueEx( hKey, + "EventMessageFile", + 0, + REG_EXPAND_SZ, + (CONST BYTE*)szFilePath, + strlen(szFilePath) + 1); + + // Set the supported types flags. + dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; + RegSetValueEx( hKey, + "TypesSupported", + 0, + REG_DWORD, + (CONST BYTE*)&dwData, + sizeof(DWORD)); + RegCloseKey(hKey); + + // LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, SVCNAME); + + // tidy up + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return TRUE; +} + +BOOL +Uninstall() +{ + BOOL bResult = FALSE; + SC_HANDLE hService; + SC_HANDLE hSCM; + + // Open the Service Control Manager + hSCM = OpenSCManager( NULL, // local machine + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access + if (!hSCM) + return FALSE; + + hService = OpenService( hSCM, + _T(SVCNAME), + DELETE); + if (hService) { + if (DeleteService(hService)) { + // LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_REMOVED, SVCNAME); + bResult = TRUE; + } else { + // LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_NOTREMOVED, SVCNAME); + } + CloseServiceHandle(hService); + } + + CloseServiceHandle(hSCM); + return bResult; +} + + +// Returns TRUE if it found an arg it recognised, FALSE if not +// Note: processing some arguments causes output to stdout to be generated. +BOOL +ParseStandardArgs(int argc, char* argv[]) +{ + char szFilePath[_MAX_PATH]="not a file name"; + + // See if we have any command line args we recognize + if (argc <= 1) + return FALSE; + + if ( _stricmp(argv[1], "-h") == 0 || + _stricmp(argv[1], "-?") == 0 || + _stricmp(argv[1], "/h") == 0 || + _stricmp(argv[1], "/?") == 0) { + + // + GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); + fprintf(stderr, "usage: %s [-v | -i | -u | -h]\r\n",szFilePath); + return TRUE; + } else if (_stricmp(argv[1], "-v") == 0 || + _stricmp(argv[1], "/v") == 0 ) { + + // Spit out version info + fprintf(stderr, "%s Version 0.1\n",_T(SVCNAME)); + fprintf(stderr, "The service is %s installed\n", + IsInstalled() ? "currently" : "not"); + return TRUE; // say we processed the argument + + } else if (_stricmp(argv[1], "-i") == 0 || + _stricmp(argv[1], "/i") == 0) { + + // Request to install. + if (IsInstalled()) { + fprintf(stderr, "%s is already installed\n", _T(SVCNAME)); + } else { + // Try and install the copy that's running + if (Install()) { + fprintf(stderr, "%s installed\n", _T(SVCNAME)); + } else { + fprintf(stderr, "%s failed to install. Error %d\n", _T(SVCNAME), GetLastError()); + } + } + return TRUE; // say we processed the argument + + } else if (_stricmp(argv[1], "-u") == 0 || + _stricmp(argv[1], "/u") == 0) { + + // Request to uninstall. + if (!IsInstalled()) { + fprintf(stderr, "%s is not installed\n", _T(SVCNAME)); + } else { + // Try and remove the copy that's installed + if (Uninstall()) { + // Get the executable file path + GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); + fprintf(stderr, "%s removed. (You must delete the file (%s) yourself.)\n", + _T(SVCNAME), szFilePath); + } else { + fprintf(stderr, "Could not remove %s. Error %d\n", _T(SVCNAME), GetLastError()); + } + } + return TRUE; // say we processed the argument + + } + + // Don't recognise the args + return FALSE; +} + +int main(int argc, char ** argv) { + + SERVICE_TABLE_ENTRY dispatch_table[] = { + { _T(SVCNAME), (LPSERVICE_MAIN_FUNCTION) service_main }, + { NULL, NULL } + }; + + if ( ParseStandardArgs(argc, argv) ) + return 0; + + if (!StartServiceCtrlDispatcher(dispatch_table)) { + fprintf(stderr, "Can't start service control dispatcher\n"); + } + + return 0; +} -- cgit