Skip to content

Commit 28c2329

Browse files
authored
Clean up old Windows 9x/Windows NT 4 compatibility (#8646)
1 parent f6f05c4 commit 28c2329

File tree

1 file changed

+31
-277
lines changed

1 file changed

+31
-277
lines changed

src/common/utils.cpp

Lines changed: 31 additions & 277 deletions
Original file line numberDiff line numberDiff line change
@@ -396,12 +396,8 @@ char* cleanup_passwd(char* arg)
396396

397397
#ifdef WIN_NT
398398

399-
static bool validateProductSuite (LPCSTR lpszSuiteToValidate);
400-
401-
// hvlad: begins from Windows 2000 we can safely add 'Global\' prefix for
402-
// names of all kernel objects we use. For Win9x we must not add this prefix.
403-
// Win NT will accept such names only if Terminal Server is installed.
404-
// Check OS version carefully and add prefix if we can add it
399+
// With sufficient privileges, we can add 'Global\' prefix for
400+
// names of all kernel objects we use.
405401

406402
bool prefix_kernel_object_name(char* name, size_t bufsize)
407403
{
@@ -430,135 +426,51 @@ bool prefix_kernel_object_name(char* name, size_t bufsize)
430426

431427
memmove(name + move_prefix, name, len_name);
432428
memcpy(name, prefix, move_prefix);
433-
// CVC: Unfortunately, things like Glob instead of Global\\ do not achieve the objective
434-
// of telling the NT kernel the object is global and hence I consider them failures.
435-
//return move_prefix > 0; // Soft version of the check
436-
return move_prefix == len_prefix; // Strict version of the check.
429+
return move_prefix == len_prefix;
437430
}
438431
return true;
439432
}
440433

441-
442-
// Simply handle guardian.
443-
class DynLibHandle
444-
{
445-
public:
446-
explicit DynLibHandle(HMODULE mod)
447-
: m_handle(mod)
448-
{}
449-
~DynLibHandle()
450-
{
451-
if (m_handle)
452-
FreeLibrary(m_handle);
453-
}
454-
operator HMODULE() const
455-
{
456-
return m_handle;
457-
}
458-
/* The previous conversion is invoked with !object so this is enough.
459-
bool operator!() const
460-
{
461-
return !m_handle;
462-
}
463-
*/
464-
private:
465-
HMODULE m_handle;
466-
};
467-
468-
469-
// hvlad: two functions below got from
470-
// http://msdn2.microsoft.com/en-us/library/aa380797.aspx
471-
// and slightly adapted for our coding style
472-
473-
// -------------------------------------------------------------
474-
// Note that the validateProductSuite and isTerminalServices
475-
// functions use ANSI versions of the functions to maintain
476-
// compatibility with Windows Me/98/95.
477-
// -------------------------------------------------------------
478-
479434
bool isGlobalKernelPrefix()
480435
{
481436
// The strategy of this function is as follows: use Global\ kernel namespace
482-
// for engine objects if we can. This can be prevented by either lack of OS support
483-
// for the feature (Win9X) or lack of privileges (Vista, Windows 2000/XP restricted accounts)
437+
// for engine objects if we can.
484438

485-
const DWORD dwVersion = GetVersion();
439+
// Check if we have enough privileges to create global handles.
440+
// If not fall back to creating local ones.
486441

487-
// Is Windows NT running?
488-
if (!(dwVersion & 0x80000000))
442+
HANDLE hProcess = GetCurrentProcess();
443+
HANDLE hToken;
444+
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken) == 0)
489445
{
490-
if (LOBYTE(LOWORD(dwVersion)) <= 4) // This is Windows NT 4.0 or earlier.
491-
return validateProductSuite("Terminal Server");
492-
493-
// Is it Windows 2000 or greater? It is possible to use Global\ prefix on any
494-
// version of Windows from Windows 2000 and up
495-
// Check if we have enough privileges to create global handles.
496-
// If not fall back to creating local ones.
497-
// The API for that is the NT thing, so we have to get addresses of the
498-
// functions dynamically to avoid troubles on Windows 9X platforms
499-
500-
DynLibHandle hmodAdvApi(LoadLibrary("advapi32.dll"));
501-
502-
if (!hmodAdvApi)
503-
{
504-
gds__log("LoadLibrary failed for advapi32.dll. Error code: %lu", GetLastError());
505-
return false;
506-
}
507-
508-
typedef BOOL (WINAPI *PFnOpenProcessToken) (HANDLE, DWORD, PHANDLE);
509-
typedef BOOL (WINAPI *PFnLookupPrivilegeValue) (LPCSTR, LPCSTR, PLUID);
510-
typedef BOOL (WINAPI *PFnPrivilegeCheck) (HANDLE, PPRIVILEGE_SET, LPBOOL);
511-
512-
PFnOpenProcessToken pfnOpenProcessToken =
513-
(PFnOpenProcessToken) GetProcAddress(hmodAdvApi, "OpenProcessToken");
514-
PFnLookupPrivilegeValue pfnLookupPrivilegeValue =
515-
(PFnLookupPrivilegeValue) GetProcAddress(hmodAdvApi, "LookupPrivilegeValueA");
516-
PFnPrivilegeCheck pfnPrivilegeCheck =
517-
(PFnPrivilegeCheck) GetProcAddress(hmodAdvApi, "PrivilegeCheck");
518-
519-
if (!pfnOpenProcessToken || !pfnLookupPrivilegeValue || !pfnPrivilegeCheck)
520-
{
521-
// Should never happen, really
522-
gds__log("Cannot access privilege management API");
523-
return false;
524-
}
525-
526-
HANDLE hProcess = GetCurrentProcess();
527-
HANDLE hToken;
528-
if (pfnOpenProcessToken(hProcess, TOKEN_QUERY, &hToken) == 0)
529-
{
530-
gds__log("OpenProcessToken failed. Error code: %lu", GetLastError());
531-
return false;
532-
}
533-
534-
PRIVILEGE_SET ps;
535-
memset(&ps, 0, sizeof(ps));
536-
ps.Control = PRIVILEGE_SET_ALL_NECESSARY;
537-
ps.PrivilegeCount = 1;
538-
if (pfnLookupPrivilegeValue(NULL, TEXT("SeCreateGlobalPrivilege"), &ps.Privilege[0].Luid) == 0)
539-
{
540-
// Failure here means we're running on old version of Windows 2000 or XP
541-
// which always allow creating global handles
542-
CloseHandle(hToken);
543-
return true;
544-
}
545-
546-
BOOL checkResult;
547-
if (pfnPrivilegeCheck(hToken, &ps, &checkResult) == 0)
548-
{
549-
gds__log("PrivilegeCheck failed. Error code: %lu", GetLastError());
550-
CloseHandle(hToken);
551-
return false;
552-
}
446+
gds__log("OpenProcessToken failed. Error code: %lu", GetLastError());
447+
return false;
448+
}
553449

450+
PRIVILEGE_SET ps{};
451+
ps.Control = PRIVILEGE_SET_ALL_NECESSARY;
452+
ps.PrivilegeCount = 1;
453+
if (LookupPrivilegeValue(NULL, TEXT("SeCreateGlobalPrivilege"), &ps.Privilege[0].Luid) == 0)
454+
{
455+
// Failure here means we're running on old version of Windows 2000 or XP
456+
// which always allow creating global handles;
457+
// we don't run on those versions anymore, but leave this as is.
554458
CloseHandle(hToken);
459+
return true;
460+
}
555461

556-
return checkResult;
462+
BOOL checkResult;
463+
if (PrivilegeCheck(hToken, &ps, &checkResult) == 0)
464+
{
465+
gds__log("PrivilegeCheck failed. Error code: %lu", GetLastError());
466+
CloseHandle(hToken);
467+
return false;
557468
}
558469

559-
return false;
560-
}
470+
CloseHandle(hToken);
561471

472+
return checkResult;
473+
}
562474

563475
// Incapsulates Windows private namespace
564476
class PrivateNamespace
@@ -726,164 +638,6 @@ bool privateNameSpaceReady()
726638
return privateNamespace().isReady();
727639
}
728640

729-
730-
// This is a very basic registry querying class. Not much validation, but avoids
731-
// leaving the registry open by mistake.
732-
733-
class NTRegQuery
734-
{
735-
public:
736-
NTRegQuery();
737-
~NTRegQuery();
738-
bool openForRead(const char* key);
739-
bool readValueSize(const char* value);
740-
// Assumes previous call to readValueSize.
741-
bool readValueData(LPSTR data);
742-
void close();
743-
DWORD getDataType() const;
744-
DWORD getDataSize() const;
745-
private:
746-
HKEY m_hKey;
747-
DWORD m_dwType;
748-
DWORD m_dwSize;
749-
const char* m_value;
750-
};
751-
752-
inline NTRegQuery::NTRegQuery()
753-
: m_hKey(NULL), m_dwType(0), m_dwSize(0)
754-
{
755-
}
756-
757-
inline NTRegQuery::~NTRegQuery()
758-
{
759-
close();
760-
}
761-
762-
bool NTRegQuery::openForRead(const char* key)
763-
{
764-
return RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, &m_hKey) == ERROR_SUCCESS;
765-
}
766-
767-
bool NTRegQuery::readValueSize(const char* value)
768-
{
769-
m_value = value;
770-
return RegQueryValueExA(m_hKey, value, NULL, &m_dwType, NULL, &m_dwSize) == ERROR_SUCCESS;
771-
}
772-
773-
bool NTRegQuery::readValueData(LPSTR data)
774-
{
775-
return RegQueryValueExA(m_hKey, m_value, NULL, &m_dwType, (LPBYTE) data, &m_dwSize) == ERROR_SUCCESS;
776-
}
777-
778-
void NTRegQuery::close()
779-
{
780-
if (m_hKey)
781-
RegCloseKey(m_hKey);
782-
783-
m_hKey = NULL;
784-
}
785-
786-
inline DWORD NTRegQuery::getDataType() const
787-
{
788-
return m_dwType;
789-
}
790-
791-
inline DWORD NTRegQuery::getDataSize() const
792-
{
793-
return m_dwSize;
794-
}
795-
796-
797-
// This class represents the local allocation of dynamic memory in Windows.
798-
799-
class NTLocalString
800-
{
801-
public:
802-
explicit NTLocalString(DWORD dwSize);
803-
LPCSTR c_str() const;
804-
LPSTR getString();
805-
bool allocated() const;
806-
~NTLocalString();
807-
private:
808-
LPSTR m_string;
809-
};
810-
811-
NTLocalString::NTLocalString(DWORD dwSize)
812-
{
813-
m_string = (LPSTR) LocalAlloc(LPTR, dwSize);
814-
}
815-
816-
NTLocalString::~NTLocalString()
817-
{
818-
if (m_string)
819-
LocalFree(m_string);
820-
}
821-
822-
inline LPCSTR NTLocalString::c_str() const
823-
{
824-
return m_string;
825-
}
826-
827-
inline LPSTR NTLocalString::getString()
828-
{
829-
return m_string;
830-
}
831-
832-
inline bool NTLocalString::allocated() const
833-
{
834-
return m_string != 0;
835-
}
836-
837-
838-
////////////////////////////////////////////////////////////
839-
// validateProductSuite function
840-
//
841-
// Terminal Services detection code for systems running
842-
// Windows NT 4.0 and earlier.
843-
//
844-
////////////////////////////////////////////////////////////
845-
846-
bool validateProductSuite (LPCSTR lpszSuiteToValidate)
847-
{
848-
NTRegQuery query;
849-
850-
// Open the ProductOptions key.
851-
if (!query.openForRead("System\\CurrentControlSet\\Control\\ProductOptions"))
852-
return false;
853-
854-
// Determine required size of ProductSuite buffer.
855-
// If we get size == 1 it means multi string data with only a terminator.
856-
if (!query.readValueSize("ProductSuite") || query.getDataSize() < 2)
857-
return false;
858-
859-
// Allocate buffer.
860-
NTLocalString lpszProductSuites(query.getDataSize());
861-
if (!lpszProductSuites.allocated())
862-
return false;
863-
864-
// Retrieve array of product suite strings.
865-
if (!query.readValueData(lpszProductSuites.getString()) || query.getDataType() != REG_MULTI_SZ)
866-
return false;
867-
868-
query.close(); // explicit but redundant.
869-
870-
// Search for suite name in array of strings.
871-
bool fValidated = false;
872-
LPCSTR lpszSuite = lpszProductSuites.c_str();
873-
LPCSTR end = lpszSuite + query.getDataSize(); // paranoid check
874-
while (*lpszSuite && lpszSuite < end)
875-
{
876-
if (lstrcmpA(lpszSuite, lpszSuiteToValidate) == 0)
877-
{
878-
fValidated = true;
879-
break;
880-
}
881-
lpszSuite += (lstrlenA(lpszSuite) + 1);
882-
}
883-
884-
return fValidated;
885-
}
886-
887641
#endif // WIN_NT
888642

889643
// *******************************

0 commit comments

Comments
 (0)