mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-31 06:43:02 +01:00
476 lines
10 KiB
C++
476 lines
10 KiB
C++
/*
|
|
* PROGRAM: JRD Access Method - Win32 specific functions.
|
|
* MODULE: isc_win32.c
|
|
* DESCRIPTION: General purpose but non-user routines.
|
|
*
|
|
* 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): ______________________________________.
|
|
* Added TCP_NO_DELAY option for superserver on Linux
|
|
* FSG 16.03.2001
|
|
* Solaris x86 changes - Konstantin Kuznetsov, Neil McCalden
|
|
*/
|
|
/*
|
|
$Id: isc_win32.cpp,v 1.5 2002-08-27 11:07:36 dimitr Exp $
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include "../jrd/ib_stdio.h"
|
|
#include "../jrd/common.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <windows.h>
|
|
|
|
#include "gen/codes.h"
|
|
#include "../jrd/isc.h"
|
|
#include "../jrd/ibase.h"
|
|
#include "../jrd/jrd.h"
|
|
#include "../jrd/gds_proto.h"
|
|
#include "../jrd/isc_proto.h"
|
|
#include "../jrd/jrd_proto.h"
|
|
#include "../utilities/registry.h"
|
|
|
|
|
|
#include <windows.h>
|
|
#ifdef TEXT
|
|
#undef TEXT
|
|
#endif
|
|
#define TEXT SCHAR
|
|
|
|
#include <process.h>
|
|
#include <signal.h>
|
|
|
|
static USHORT os_type;
|
|
static SECURITY_ATTRIBUTES security_attr;
|
|
|
|
#ifdef MAXPATHLEN
|
|
#undef MAXPATHLEN
|
|
#endif
|
|
#define MAXPATHLEN 512
|
|
|
|
static TEXT interbase_directory[MAXPATHLEN];
|
|
|
|
void isc_internal_set_config_value(UCHAR, ULONG*, ULONG*);
|
|
static BOOLEAN check_user_privilege();
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Checks if the process indicated by the process id 'pid' exists.
|
|
// Returns TRUE if the indicated process exists, FALSE otherwise.
|
|
//
|
|
int DLL_EXPORT ISC_check_process_existence(SLONG pid,
|
|
SLONG xl_pid,
|
|
USHORT super_user)
|
|
{
|
|
HANDLE handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, (DWORD) pid);
|
|
|
|
if (!handle && GetLastError() != ERROR_ACCESS_DENIED)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(handle);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Get host name. Note that this is not the DNS (TCP/IP) hostname,
|
|
// it's the Win32 computer name.
|
|
//
|
|
TEXT* INTERNAL_API_ROUTINE ISC_get_host(TEXT * string, USHORT length)
|
|
{
|
|
DWORD host_len = length;
|
|
if (GetComputerName(string, &host_len))
|
|
{
|
|
string[host_len] = 0;
|
|
}
|
|
else
|
|
{
|
|
strcpy(string, "local");
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Returns the type of OS. TRUE for NT,
|
|
// FALSE for the 16-bit based ones (9x/ME, ...).
|
|
//
|
|
BOOLEAN ISC_is_WinNT()
|
|
{
|
|
OSVERSIONINFO OsVersionInfo;
|
|
|
|
if (!os_type)
|
|
{
|
|
os_type = 1; /* Default to NT */
|
|
/* The first time this routine is called we use the Windows API
|
|
call GetVersion to determine whether Windows/NT or Chicago
|
|
is running. */
|
|
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (GetVersionEx((LPOSVERSIONINFO) & OsVersionInfo))
|
|
{
|
|
os_type =
|
|
(OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 1 : 2;
|
|
}
|
|
|
|
}
|
|
|
|
return (os_type != 2) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Lookup a registry entry.
|
|
// Returns TRUE if the lookup was successful, FALSE otherwise.
|
|
//
|
|
SSHORT ISC_get_registry_var(TEXT* variable,
|
|
TEXT* buffer,
|
|
SSHORT buffer_length,
|
|
void** user_hkey)
|
|
{
|
|
HKEY hkey;
|
|
DWORD len, type;
|
|
|
|
if (!user_hkey)
|
|
{
|
|
LPCTSTR szKey = REG_KEY_ROOT_CUR_VER;
|
|
const LONG ret =
|
|
RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_QUERY_VALUE, &hkey);
|
|
if (ret != ERROR_SUCCESS)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hkey = *((PHKEY) user_hkey);
|
|
}
|
|
|
|
len = buffer_length;
|
|
|
|
#pragma FB_COMPILER_MESSAGE("Can/should we fix this cast?")
|
|
|
|
const LONG ret =
|
|
RegQueryValueEx(hkey, variable, NULL, &type, (LPBYTE) buffer, &len);
|
|
|
|
if (ret != ERROR_SUCCESS)
|
|
{
|
|
len = 0;
|
|
}
|
|
|
|
if (!user_hkey)
|
|
{
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return (SSHORT) len;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
//
|
|
LPSECURITY_ATTRIBUTES ISC_get_security_desc()
|
|
{
|
|
if (security_attr.lpSecurityDescriptor)
|
|
{
|
|
return &security_attr;
|
|
}
|
|
|
|
PSECURITY_DESCRIPTOR p_security_desc =
|
|
(PSECURITY_DESCRIPTOR) gds__alloc((SLONG)
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
/* FREE: apparently never freed */
|
|
if (!p_security_desc) /* NOMEM: */
|
|
{
|
|
return NULL;
|
|
}
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
gds_alloc_flag_unfreed((void *) p_security_desc);
|
|
#endif
|
|
|
|
if (!InitializeSecurityDescriptor( p_security_desc,
|
|
SECURITY_DESCRIPTOR_REVISION) ||
|
|
!SetSecurityDescriptorDacl(p_security_desc, TRUE, (PACL) NULL, FALSE))
|
|
{
|
|
gds__free(p_security_desc);
|
|
return NULL;
|
|
}
|
|
|
|
security_attr.nLength = sizeof(security_attr);
|
|
security_attr.lpSecurityDescriptor = p_security_desc;
|
|
security_attr.bInheritHandle = TRUE;
|
|
|
|
return &security_attr;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Find out who the user is.
|
|
//
|
|
int INTERNAL_API_ROUTINE ISC_get_user(TEXT* name,
|
|
int* id,
|
|
int* group,
|
|
TEXT* project,
|
|
TEXT* organization,
|
|
int* node,
|
|
TEXT* user_string)
|
|
{
|
|
if (id)
|
|
*id = -1;
|
|
|
|
if (group)
|
|
*group = -1;
|
|
|
|
if (project)
|
|
*project = 0;
|
|
|
|
if (organization)
|
|
*organization = 0;
|
|
|
|
if (node)
|
|
*node = 0;
|
|
|
|
if (name)
|
|
{
|
|
name[0] = 0;
|
|
DWORD name_len = 128;
|
|
if (GetUserName(name, &name_len))
|
|
{
|
|
name[name_len] = 0;
|
|
|
|
/* NT user name is case insensitive */
|
|
|
|
for (DWORD i = 0; i < name_len; i++)
|
|
{
|
|
name[i] = UPPER7(name[i]);
|
|
}
|
|
|
|
/* This check is not internationalized, the security model needs to be
|
|
* reengineered, especially on SUPERSERVER where none of these local
|
|
* user (in process) assumptions are valid.
|
|
*/
|
|
if (!strcmp(name, "ADMINISTRATOR"))
|
|
{
|
|
if (id)
|
|
*id = 0;
|
|
|
|
if (group)
|
|
*group = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return check_user_privilege();
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Check to see if the user belongs to the administrator group.
|
|
//
|
|
// This routine was adapted from code in routine RunningAsAdminstrator
|
|
// in \mstools\samples\regmpad\regdb.c.
|
|
//
|
|
static BOOLEAN check_user_privilege(void)
|
|
{
|
|
HANDLE tkhandle;
|
|
SID_IDENTIFIER_AUTHORITY system_sid_authority = SECURITY_NT_AUTHORITY;
|
|
|
|
// First we must open a handle to the access token for this thread.
|
|
|
|
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &tkhandle))
|
|
{
|
|
if (GetLastError() == ERROR_NO_TOKEN)
|
|
{
|
|
// If the thread does not have an access token, we'll examine the
|
|
// access token associated with the process.
|
|
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tkhandle))
|
|
{
|
|
CloseHandle(tkhandle);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
TOKEN_GROUPS* ptg = NULL;
|
|
DWORD token_len = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
/* Then we must query the size of the group information associated with
|
|
the token. This is guarenteed to fail the first time through
|
|
because there is no buffer. */
|
|
|
|
if (GetTokenInformation(tkhandle,
|
|
TokenGroups,
|
|
ptg,
|
|
token_len,
|
|
&token_len))
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* If there had been a buffer, it's either too small or something
|
|
else is wrong. Either way, we can dispose of it. */
|
|
|
|
if (ptg)
|
|
{
|
|
gds__free(ptg);
|
|
}
|
|
|
|
/* Here we verify that GetTokenInformation failed for lack of a large
|
|
enough buffer. */
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
CloseHandle(tkhandle);
|
|
return FALSE;
|
|
}
|
|
|
|
// Allocate a buffer for the group information.
|
|
ptg = (TOKEN_GROUPS *) gds__alloc((SLONG) token_len);
|
|
|
|
if (!ptg)
|
|
{
|
|
CloseHandle(tkhandle);
|
|
return FALSE; /* NOMEM: */
|
|
}
|
|
// FREE: earlier in this loop, and at procedure return
|
|
}
|
|
|
|
// Create a System Identifier for the Admin group.
|
|
|
|
PSID admin_sid;
|
|
|
|
if (!AllocateAndInitializeSid(&system_sid_authority, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0, &admin_sid))
|
|
{
|
|
gds__free(ptg);
|
|
CloseHandle(tkhandle);
|
|
return FALSE;
|
|
}
|
|
|
|
// Finally we'll iterate through the list of groups for this access
|
|
// token looking for a match against the SID we created above.
|
|
|
|
BOOLEAN admin_priv = FALSE;
|
|
|
|
for (DWORD i = 0; i < ptg->GroupCount; i++)
|
|
{
|
|
if (EqualSid(ptg->Groups[i].Sid, admin_sid))
|
|
{
|
|
admin_priv = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Deallocate the SID we created.
|
|
|
|
FreeSid(admin_sid);
|
|
gds__free(ptg);
|
|
CloseHandle(tkhandle);
|
|
return admin_priv;
|
|
}
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
//____________________________________________________________
|
|
//
|
|
//
|
|
void isc_internal_set_config_value(UCHAR key,
|
|
ULONG* value1_ptr,
|
|
ULONG* value2_ptr)
|
|
{
|
|
switch (key)
|
|
{
|
|
case ISCCFG_DBCACHE_KEY:
|
|
JRD_set_cache_default(value1_ptr);
|
|
break;
|
|
case ISCCFG_PRIORITY_KEY:
|
|
{
|
|
ULONG priority;
|
|
if (*value1_ptr == 2)
|
|
priority = HIGH_PRIORITY_CLASS;
|
|
else
|
|
priority = NORMAL_PRIORITY_CLASS;
|
|
|
|
if (!SetPriorityClass(GetCurrentProcess(), priority))
|
|
{
|
|
gds__log("Unable to set process priority.");
|
|
}
|
|
}
|
|
break;
|
|
case ISCCFG_MEMMAX_KEY:
|
|
case ISCCFG_MEMMIN_KEY:
|
|
if (*value1_ptr && *value2_ptr && ISC_is_WinNT())
|
|
{
|
|
HANDLE hndl =
|
|
OpenProcess(PROCESS_SET_QUOTA, FALSE, GetCurrentProcessId());
|
|
|
|
if (hndl) {
|
|
ULONG value1 = *value1_ptr * 1024;
|
|
ULONG value2 = *value2_ptr * 1024;
|
|
|
|
if (!SetProcessWorkingSetSize(hndl, value1, value2))
|
|
{
|
|
switch (GetLastError())
|
|
{
|
|
case ERROR_ACCESS_DENIED:
|
|
case ERROR_PRIVILEGE_NOT_HELD:
|
|
gds__log("Error setting process working set size, access denied.");
|
|
break;
|
|
case ERROR_INVALID_PARAMETER:
|
|
gds__log("Error setting process working set size, improper range.");
|
|
break;
|
|
case ERROR_NO_SYSTEM_RESOURCES:
|
|
gds__log("Error setting process working set size, insufficient memory.");
|
|
break;
|
|
default:
|
|
gds__log("Error setting process working set size, unknown problem.");
|
|
|
|
|
|
}
|
|
*value1_ptr = 0;
|
|
*value2_ptr = 0;
|
|
}
|
|
CloseHandle(hndl);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* SUPERSERVER */
|
|
|