/* * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. * * Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved. * 2013 Heiko Hund */ #include "service.h" #include #include #include openvpn_service_t openvpn_service[_service_max]; BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status) { static DWORD dwCheckPoint = 1; BOOL res = TRUE; if (status->dwCurrentState == SERVICE_START_PENDING) { status->dwControlsAccepted = 0; } else { status->dwControlsAccepted = SERVICE_ACCEPT_STOP; } if (status->dwCurrentState == SERVICE_RUNNING || status->dwCurrentState == SERVICE_STOPPED) { status->dwCheckPoint = 0; } else { status->dwCheckPoint = dwCheckPoint++; } /* Report the status of the service to the service control manager. */ res = SetServiceStatus(service, status); if (!res) { MsgToEventLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus")); } return res; } static int CmdInstallServices() { SC_HANDLE service; SC_HANDLE svc_ctl_mgr; TCHAR path[512]; int i, ret = _service_max; if (GetModuleFileName(NULL, path + 1, 510) == 0) { _tprintf(TEXT("Unable to install service - %s\n"), GetLastErrorText()); return 1; } path[0] = TEXT('\"'); _tcscat(path, TEXT("\"")); svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); if (svc_ctl_mgr == NULL) { _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText()); return 1; } for (i = 0; i < _service_max; i++) { service = CreateService(svc_ctl_mgr, openvpn_service[i].name, openvpn_service[i].display_name, SERVICE_QUERY_STATUS, SERVICE_WIN32_SHARE_PROCESS, openvpn_service[i].start_type, SERVICE_ERROR_NORMAL, path, NULL, NULL, openvpn_service[i].dependencies, NULL, NULL); if (service) { _tprintf(TEXT("%s installed.\n"), openvpn_service[i].display_name); CloseServiceHandle(service); --ret; } else { _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText()); } } CloseServiceHandle(svc_ctl_mgr); return ret; } static int CmdStartService(openvpn_service_type type) { int ret = 1; SC_HANDLE svc_ctl_mgr; SC_HANDLE service; svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (svc_ctl_mgr == NULL) { _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText()); return 1; } service = OpenService(svc_ctl_mgr, openvpn_service[type].name, SERVICE_ALL_ACCESS); if (service) { if (StartService(service, 0, NULL)) { _tprintf(TEXT("Service Started\n")); ret = 0; } else { _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText()); } CloseServiceHandle(service); } else { _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText()); } CloseServiceHandle(svc_ctl_mgr); return ret; } static int CmdRemoveServices() { SC_HANDLE service; SC_HANDLE svc_ctl_mgr; SERVICE_STATUS status; int i, ret = _service_max; svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (svc_ctl_mgr == NULL) { _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText()); return 1; } for (i = 0; i < _service_max; i++) { openvpn_service_t *ovpn_svc = &openvpn_service[i]; service = OpenService(svc_ctl_mgr, ovpn_svc->name, DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS); if (service == NULL) { _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText()); goto out; } /* try to stop the service */ if (ControlService(service, SERVICE_CONTROL_STOP, &status)) { _tprintf(TEXT("Stopping %s."), ovpn_svc->display_name); Sleep(1000); while (QueryServiceStatus(service, &status)) { if (status.dwCurrentState == SERVICE_STOP_PENDING) { _tprintf(TEXT(".")); Sleep(1000); } else { break; } } if (status.dwCurrentState == SERVICE_STOPPED) { _tprintf(TEXT("\n%s stopped.\n"), ovpn_svc->display_name); } else { _tprintf(TEXT("\n%s failed to stop.\n"), ovpn_svc->display_name); } } /* now remove the service */ if (DeleteService(service)) { _tprintf(TEXT("%s removed.\n"), ovpn_svc->display_name); --ret; } else { _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText()); } CloseServiceHandle(service); } out: CloseServiceHandle(svc_ctl_mgr); return ret; } int _tmain(int argc, TCHAR *argv[]) { /* * Automatic + Interactive service (as a SERVICE_WIN32_SHARE_PROCESS) * This is the default. */ const SERVICE_TABLE_ENTRY dispatchTable_shared[] = { { automatic_service.name, ServiceStartAutomatic }, { interactive_service.name, ServiceStartInteractive }, { NULL, NULL } }; /* Automatic service only (as a SERVICE_WIN32_OWN_PROCESS) */ const SERVICE_TABLE_ENTRY dispatchTable_automatic[] = { { TEXT(""), ServiceStartAutomaticOwn }, { NULL, NULL } }; /* Interactive service only (as a SERVICE_WIN32_OWN_PROCESS) */ const SERVICE_TABLE_ENTRY dispatchTable_interactive[] = { { TEXT(""), ServiceStartInteractiveOwn }, { NULL, NULL } }; const SERVICE_TABLE_ENTRY *dispatchTable = dispatchTable_shared; openvpn_service[0] = automatic_service; openvpn_service[1] = interactive_service; for (int i = 1; i < argc; i++) { if (*argv[i] == TEXT('-') || *argv[i] == TEXT('/')) { if (_tcsicmp(TEXT("install"), argv[i] + 1) == 0) { return CmdInstallServices(); } else if (_tcsicmp(TEXT("remove"), argv[i] + 1) == 0) { return CmdRemoveServices(); } else if (_tcsicmp(TEXT("start"), argv[i] + 1) == 0) { BOOL is_auto = argc < i + 2 || _tcsicmp(TEXT("interactive"), argv[i + 1]) != 0; return CmdStartService(is_auto ? automatic : interactive); } else if (argc > i + 2 && _tcsicmp(TEXT("instance"), argv[i] + 1) == 0) { dispatchTable = _tcsicmp(TEXT("interactive"), argv[i + 1]) != 0 ? dispatchTable_automatic : dispatchTable_interactive; service_instance = argv[i + 2]; i += 2; } else { _tprintf(TEXT("%s -install to install the services\n"), APPNAME); _tprintf(TEXT("%s -start to start a service (\"automatic\" or \"interactive\")\n"), APPNAME); _tprintf(TEXT("%s -remove to remove the services\n"), APPNAME); _tprintf(TEXT("\nService run-time parameters:\n")); _tprintf(TEXT("-instance \n") TEXT(" Runs the service as an alternate instance. can be \"automatic\" or\n") TEXT(" \"interactive\". The service settings will be loaded from\n") TEXT(" HKLM\\Software\\" PACKAGE_NAME " registry key, and the interactive service will accept\n") TEXT(" requests on \\\\.\\pipe\\" PACKAGE "\\service named pipe.\n")); return 0; } } } /* If it doesn't match any of the above parameters * the service control manager may be starting the service * so we must call StartServiceCtrlDispatcher */ _tprintf(TEXT("\nStartServiceCtrlDispatcher being called.\n")); _tprintf(TEXT("This may take several seconds. Please wait.\n")); if (!StartServiceCtrlDispatcher(dispatchTable)) { MsgToEventLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed.")); } return 0; }