8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-01 14:40:39 +01:00
firebird-mirror/src/utilities/install/services.cpp

365 lines
9.5 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Windows NT service control panel installation program
* MODULE: services.c
* DESCRIPTION: Functions which update the Windows service manager for IB
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
2002-06-29 10:49:39 +02:00
*
* 01-Feb-2002 Paul Reeves: Removed hard-coded registry path
*
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ib_stdio.h"
#include <windows.h>
#include <ntsecapi.h>
2001-05-23 15:26:42 +02:00
#include "../jrd/common.h"
#include "../jrd/license.h"
2003-07-15 04:43:36 +02:00
#include "../utilities/install/install_nt.h"
#include "../utilities/install/servi_proto.h"
#include "../utilities/install/registry.h"
2001-05-23 15:26:42 +02:00
/* Defines */
#define RUNAS_SERVICE " -s"
static void grant_logon_right(TEXT* account);
2001-05-23 15:26:42 +02:00
USHORT SERVICES_install(SC_HANDLE manager,
TEXT * service_name,
TEXT * display_name,
TEXT * executable,
TEXT * directory,
TEXT * dependencies,
USHORT sw_startup,
TEXT * nt_user_name,
TEXT * nt_user_password,
USHORT(*err_handler)(SLONG, TEXT *, SC_HANDLE))
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S E R V I C E S _ i n s t a l l
*
**************************************
*
* Functional description
* Install a service in the service control panel.
*
**************************************/
SC_HANDLE service;
TEXT path_name[MAXPATHLEN];
TEXT full_user_name[128];
2001-05-23 15:26:42 +02:00
USHORT len;
DWORD errnum;
DWORD dwServiceType;
2001-05-23 15:26:42 +02:00
strcpy(path_name, directory);
len = strlen(path_name);
if (len && path_name[len - 1] != '/' && path_name[len - 1] != '\\')
{
2001-05-23 15:26:42 +02:00
path_name[len++] = '\\';
path_name[len] = 0;
}
2001-05-23 15:26:42 +02:00
strcpy(path_name + len, executable);
strcat(path_name, ".exe");
2001-05-23 15:26:42 +02:00
strcat(path_name, RUNAS_SERVICE);
dwServiceType = SERVICE_WIN32_OWN_PROCESS;
if (nt_user_name != 0)
{
TEXT *p = nt_user_name;
while (*p != '\0' && *p != '\\') ++p;
if (*p == '\0')
{
DWORD cnlen = sizeof(full_user_name);
GetComputerName(full_user_name, &cnlen);
strcat(full_user_name, "\\");
strncat(full_user_name, nt_user_name, sizeof(full_user_name) - (cnlen + 1));
}
else
strncpy(full_user_name, nt_user_name, sizeof(full_user_name));
full_user_name[sizeof(full_user_name) -1] = '\0';
if (nt_user_password == 0)
nt_user_password = "";
nt_user_name = full_user_name;
// Let's grant "Logon as a Service" right to the -login user
grant_logon_right(nt_user_name);
}
else
dwServiceType |= SERVICE_INTERACTIVE_PROCESS;
2001-05-23 15:26:42 +02:00
service = CreateService(manager,
service_name,
display_name,
SERVICE_ALL_ACCESS,
dwServiceType,
2001-05-23 15:26:42 +02:00
(sw_startup ==
STARTUP_DEMAND) ? SERVICE_DEMAND_START :
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
path_name, NULL, NULL, dependencies,
nt_user_name, nt_user_password);
2001-05-23 15:26:42 +02:00
if (service == NULL)
{
2001-05-23 15:26:42 +02:00
errnum = GetLastError();
if (errnum == ERROR_DUP_NAME || errnum == ERROR_SERVICE_EXISTS)
return IB_SERVICE_ALREADY_DEFINED;
else
return (*err_handler) (errnum, "CreateService", NULL);
}
CloseServiceHandle(service);
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
USHORT SERVICES_remove(SC_HANDLE manager,
TEXT * service_name,
TEXT * display_name,
USHORT(*err_handler)(SLONG, TEXT *, SC_HANDLE))
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S E R V I C E S _ r e m o v e
*
**************************************
*
* Functional description
* Remove a service from the service control panel.
*
**************************************/
SC_HANDLE service;
SERVICE_STATUS service_status;
service = OpenService(manager, service_name, SERVICE_ALL_ACCESS);
if (service == NULL)
return (*err_handler) (GetLastError(), "OpenService", NULL);
if (!QueryServiceStatus(service, &service_status))
2001-05-23 15:26:42 +02:00
return (*err_handler) (GetLastError(), "QueryServiceStatus", service);
if (service_status.dwCurrentState != SERVICE_STOPPED)
{
2001-05-23 15:26:42 +02:00
CloseServiceHandle(service);
return IB_SERVICE_RUNNING;
}
if (!DeleteService(service))
2001-05-23 15:26:42 +02:00
return (*err_handler) (GetLastError(), "DeleteService", service);
CloseServiceHandle(service);
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
USHORT SERVICES_start(SC_HANDLE manager,
TEXT * service_name,
TEXT * display_name,
USHORT sw_mode,
USHORT(*err_handler)(SLONG, TEXT *, SC_HANDLE))
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S E R V I C E S _ s t a r t
*
**************************************
*
* Functional description
* Start an installed service.
*
**************************************/
SC_HANDLE service;
SERVICE_STATUS service_status;
2003-02-13 10:33:26 +01:00
const TEXT *mode;
DWORD errnum;
2001-05-23 15:26:42 +02:00
service = OpenService(manager, service_name, SERVICE_ALL_ACCESS);
if (service == NULL)
return (*err_handler) (GetLastError(), "OpenService", NULL);
switch (sw_mode)
{
case DEFAULT_PRIORITY:
mode = NULL;
break;
case NORMAL_PRIORITY:
mode = "-r";
break;
case HIGH_PRIORITY:
mode = "-b";
break;
2001-05-23 15:26:42 +02:00
}
if (!StartService(service, (mode) ? 1 : 0, &mode))
{
errnum = GetLastError();
2001-05-23 15:26:42 +02:00
CloseServiceHandle(service);
if (errnum == ERROR_SERVICE_ALREADY_RUNNING)
return FB_SUCCESS;
else
return (*err_handler) (errnum, "StartService", NULL);
2001-05-23 15:26:42 +02:00
}
/* Wait for the service to actually start before returning. */
do
{
if (!QueryServiceStatus(service, &service_status))
return (*err_handler) (GetLastError(), "QueryServiceStatus", service);
Sleep(100); // Don't loop too quickly (would be useless)
}
while (service_status.dwCurrentState == SERVICE_START_PENDING);
if (service_status.dwCurrentState != SERVICE_RUNNING)
return (*err_handler) (0, "Service failed to complete its startup sequence.", service);
2001-05-23 15:26:42 +02:00
CloseServiceHandle(service);
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
USHORT SERVICES_stop(SC_HANDLE manager,
TEXT * service_name,
TEXT * display_name,
USHORT(*err_handler)(SLONG, TEXT *, SC_HANDLE))
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S E R V I C E S _ s t o p
*
**************************************
*
* Functional description
* Start a running service.
*
**************************************/
SC_HANDLE service;
SERVICE_STATUS service_status;
DWORD errnum;
service = OpenService(manager, service_name, SERVICE_ALL_ACCESS);
if (service == NULL)
return (*err_handler) (GetLastError(), "OpenService", NULL);
if (!ControlService(service, SERVICE_CONTROL_STOP, &service_status))
{
2001-05-23 15:26:42 +02:00
errnum = GetLastError();
CloseServiceHandle(service);
2001-05-23 15:26:42 +02:00
if (errnum == ERROR_SERVICE_NOT_ACTIVE)
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
else
return (*err_handler) (errnum, "ControlService", NULL);
2001-05-23 15:26:42 +02:00
}
/* Wait for the service to actually stop before returning. */
do
{
if (!QueryServiceStatus(service, &service_status))
return (*err_handler) (GetLastError(), "QueryServiceStatus", service);
Sleep(100); // Don't loop too quickly (would be useless)
2001-05-23 15:26:42 +02:00
}
while (service_status.dwCurrentState == SERVICE_STOP_PENDING);
if (service_status.dwCurrentState != SERVICE_STOPPED)
return (*err_handler) (0, "Service failed to complete its stop sequence", service);
2001-05-23 15:26:42 +02:00
CloseServiceHandle(service);
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
static void grant_logon_right(TEXT* account)
{
/**************************************
*
* g r a n t _ l o g o n _ r i g h t
*
**************************************
*
* Functional description
* Grants the "Log on as a service" right to account.
* This is a Windows NT, 2000, XP, 2003 security thing.
* To run a service under an account other than LocalSystem, the account
* must have this right. To succeed granting the right, the current user
* must be an Administrator.
* This function does not report errors, which will happen if the right
* as been granted already.
* OM - August 2003
*
**************************************/
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE PolicyHandle;
PSID pSid;
DWORD cbSid;
TEXT *pDomain;
DWORD cchDomain;
SID_NAME_USE peUse;
LSA_UNICODE_STRING PrivilegeString;
// Open the policy on the local machine.
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
if (LsaOpenPolicy(NULL, &ObjectAttributes,
POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, &PolicyHandle)
!= (NTSTATUS)0)
{
return;
}
// Obtain the SID of the user/group. First get required buffer sizes.
cbSid = cchDomain = 0;
LookupAccountName(NULL, account, NULL, &cbSid, NULL, &cchDomain, &peUse);
pSid = (PSID)LocalAlloc(LMEM_ZEROINIT, cbSid);
if (pSid == 0)
{
LsaClose(PolicyHandle);
return;
}
pDomain = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cchDomain);
if (pDomain == 0)
{
LsaClose(PolicyHandle);
LocalFree(pSid);
return;
}
// Now, really obtain the SID of the user/group.
if (LookupAccountName(NULL, account, pSid, &cbSid,
pDomain, &cchDomain, &peUse) != 0)
{
// Grant the SeServiceLogonRight to users represented by pSid.
PrivilegeString.Buffer = L"SeServiceLogonRight";
PrivilegeString.Length = (USHORT) 19 * sizeof(WCHAR); // 19 : char len of Buffer
PrivilegeString.MaximumLength=(USHORT)(19 + 1) * sizeof(WCHAR);
// No need to check the result.
LsaAddAccountRights(PolicyHandle, pSid, &PrivilegeString, 1);
}
LsaClose(PolicyHandle);
LocalFree(pSid);
LocalFree(pDomain);
return;
}
//
// EOF
//