OXYGENHUB
◆ main openmsx / src / security / SspiNegotiateServer.cc
3.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#ifdef _WIN32
2
3
#include "SspiNegotiateServer.hh"
4
#include "MSXException.hh"
5
6
#include "one_of.hh"
7
8
#include <cstdint>
9
10
namespace openmsx {
11
12
using namespace sspiutils;
13
14
SspiNegotiateServer::SspiNegotiateServer(StreamWrapper& serverStream)
15
	: SspiPackageBase(serverStream, NEGOSSP_NAME_W)
16
{
17
	// We should probably cache the security descriptor, but this
18
	// isn't exactly a performance-sensitive part of the code
19
	psd = CreateCurrentUserSecurityDescriptor();
20
	if (!psd) {
21
		throw MSXException("CreateCurrentUserSecurityDescriptor failed");
22
	}
23
}
24
25
SspiNegotiateServer::~SspiNegotiateServer()
26
{
27
	LocalFree(psd);
28
}
29
30
bool SspiNegotiateServer::Authenticate()
31
{
32
	TimeStamp tsCredsExpiry;
33
	SECURITY_STATUS ss = AcquireCredentialsHandleW(
34
		nullptr,
35
		const_cast<SEC_WCHAR*>(NEGOSSP_NAME_W),
36
		SECPKG_CRED_INBOUND,
37
		nullptr,
38
		nullptr,
39
		nullptr,
40
		nullptr,
41
		&hCreds,
42
		&tsCredsExpiry);
43
44
	DebugPrintSecurityStatus("AcquireCredentialsHandleW", ss);
45
	if (ss != SEC_E_OK) {
46
		return false;
47
	}
48
49
	SecBufferDesc secClientBufferDesc, secServerBufferDesc;
50
	SecBuffer secClientBuffer, secServerBuffer;
51
	InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer);
52
	InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer);
53
54
	std::vector<char> buffer;
55
	PCtxtHandle phContext = nullptr;
56
	while (true) {
57
		// Receive another buffer from the client
58
		bool ret = RecvChunk(stream, buffer, cbMaxTokenSize);
59
		if (!ret) return false;
60
61
		secClientBuffer.cbBuffer = static_cast<unsigned long>(buffer.size());
62
		secClientBuffer.pvBuffer = &buffer[0];
63
64
		ULONG fContextAttr;
65
		TimeStamp tsContextExpiry;
66
		ss = AcceptSecurityContext(
67
			&hCreds,
68
			phContext,
69
			&secClientBufferDesc,
70
			ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
71
			SECURITY_NETWORK_DREP,
72
			&hContext,
73
			&secServerBufferDesc,
74
			&fContextAttr,
75
			&tsContextExpiry);
76
77
		DebugPrintSecurityStatus("AcceptSecurityContext", ss);
78
		if (ss != one_of(SEC_E_OK, SEC_I_CONTINUE_NEEDED)) {
79
			return false;
80
		}
81
82
		// If we have something for the client, send it
83
		if (secServerBuffer.cbBuffer) {
84
			ret = SendChunk(stream, secServerBuffer.pvBuffer, secServerBuffer.cbBuffer);
85
			ClearContextBuffers(&secServerBufferDesc);
86
			if (!ret) return false;
87
		}
88
89
		// SEC_E_OK means that we're done
90
		if (ss == SEC_E_OK) {
91
			DebugPrintSecurityPackageName(&hContext);
92
			DebugPrintSecurityPrincipalName(&hContext);
93
			return true;
94
		}
95
96
		// Another time around the loop
97
		phContext = &hContext;
98
	}
99
}
100
101
bool SspiNegotiateServer::Authorize()
102
{
103
#ifdef __GNUC__
104
	// MinGW32's headers do not define QuerySecurityContextToken,
105
	// nor does its import library provide an export for it.
106
	// So when building with MinGW32, we load the export by hand.
107
	HMODULE secur32 = GetModuleHandleW(L"secur32.dll");
108
	if (!secur32) {
109
		return false;
110
	}
111
	auto QuerySecurityContextToken = reinterpret_cast<QUERY_SECURITY_CONTEXT_TOKEN_FN>(
112
		GetProcAddress(secur32, "QuerySecurityContextToken"));
113
	if (!QuerySecurityContextToken) {
114
		return false;
115
	}
116
#endif
117
118
	HANDLE hClientToken;
119
	SECURITY_STATUS ss = QuerySecurityContextToken(&hContext, &hClientToken);
120
	DebugPrintSecurityStatus("QuerySecurityContextToken", ss);
121
	if (ss != SEC_E_OK) {
122
		return false;
123
	}
124
125
	PRIVILEGE_SET privilegeSet;
126
	DWORD dwPrivSetSize = sizeof(privilegeSet);
127
	DWORD dwGranted;
128
	BOOL fAccess;
129
	BOOL ret = AccessCheck(
130
		psd,
131
		hClientToken,
132
		ACCESS_ALL,
133
		const_cast<PGENERIC_MAPPING>(&mapping),
134
		&privilegeSet,
135
		&dwPrivSetSize,
136
		&dwGranted,
137
		&fAccess);
138
139
	DebugPrintSecurityBool("AccessCheck", ret);
140
	DebugPrintSecurityPrincipalName(&hContext);
141
142
	CloseHandle(hClientToken);
143
144
	return ret && fAccess;
145
}
146
147
} // namespace openmsx
148
149
#endif