#include "stdio.h" // KPKDBG
#include "ccs_request.h"
#include "ccapi.h"
#include "util.h"
extern "C" {
#include "cci_debugging.h"
#include "tls.h" // KPKDBG
}
#include "client.h"
#include "init.hxx"
#include "name.h"
#include "secure.hxx"
#define SECONDS_TO_WAIT 10
#define STARTUP "CLIENT STARTUP: "
#define DISCONNECT "CLIENT DISCONNECT: "
bool Client::s_init = false;
CcOsLock Client::sLock;
static DWORD bind_client(char* ep OPTIONAL, Init::InitInfo& info, LPSTR* endpoint) {
DWORD status = 0;
unsigned char * pszStringBinding = NULL;
if (!ep) {
status = alloc_name(endpoint, "ep", isNT());
}
else {
*endpoint = ep;
}
if (!status) {
status = RpcStringBindingCompose(0, (unsigned char*)"ncalrpc", 0, (unsigned char*)(*endpoint), 0, &pszStringBinding);
cci_check_error(status);
}
if (!status) {
status = RpcBindingFromStringBinding(pszStringBinding, &ccs_request_IfHandle);
cci_check_error(status);
}
if (!status) {
if (isNT()) {
RPC_SECURITY_QOS qos;
qos.Version = RPC_C_SECURITY_QOS_VERSION;
qos.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT;
qos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
qos.ImpersonationType = RPC_C_IMP_LEVEL_IDENTIFY;
status = info.fRpcBindingSetAuthInfoEx(ccs_request_IfHandle,
0, RPC_C_AUTHN_LEVEL_CONNECT,
RPC_C_AUTHN_WINNT,
0, RPC_C_AUTHZ_NAME,
&qos);
cci_check_error(status);
}
}
if (pszStringBinding) {
DWORD status = RpcStringFree(&pszStringBinding);
cci_check_error(status);
}
return cci_check_error(status);
}
DWORD find_server(Init::InitInfo& info, LPSTR endpoint) {
DWORD status = 0;
LPSTR event_name = 0;
HANDLE hEvent = 0;
SECURITY_ATTRIBUTES sa = { 0 };
PSECURITY_ATTRIBUTES psa = 0;
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
char* szExe = 0;
char* szDir = 0;
BOOL bRes = FALSE;
char* cmdline = NULL;
#if 0
HANDLE hToken = 0;
#endif
psa = isNT() ? &sa : 0;
cci_debug_printf("%s Looking for server; ccs_request_IfHandle:0x%X", __FUNCTION__, ccs_request_IfHandle);
status = cci_check_error(RpcMgmtIsServerListening(ccs_request_IfHandle));
if (status == RPC_S_NOT_LISTENING) {
cci_debug_printf(" Server *NOT* found!");
si.cb = sizeof(si);
status = alloc_module_dir_name(CCAPI_DLL, &szDir);
if (!status) {
status = alloc_module_dir_name_with_file(CCAPI_DLL, CCAPI_EXE, &szExe);
}
if (!status) {
status = alloc_name(&event_name, "startup", isNT());
cci_check_error(status);
}
if (!status) {
if (isNT()) {
sa.nLength = sizeof(sa);
status = alloc_own_security_descriptor_NT(&sa.lpSecurityDescriptor);
cci_check_error(status);
}
}
if (!status) {
hEvent = CreateEvent(psa, FALSE, FALSE, event_name);
cci_debug_printf(" CreateEvent(... %s) returned hEvent 0x%X", event_name, hEvent);
if (!hEvent) status = GetLastError();
}
if (!status) {
#if 0
if (SecureClient::IsImp()) {
cci_debug_printf(STARTUP "Token is impersonation token"));
SecureClient::DuplicateImpAsPrimary(hToken);
}
else {
cci_debug_printf(STARTUP "Token is NOT impersonation token"));
}
#endif
#if 0
if (hToken)
bRes = CreateProcessAsUser(hToken,
szExe, NULL, psa, psa, FALSE,
CREATE_NEW_PROCESS_GROUP |
NORMAL_PRIORITY_CLASS |
DETACHED_PROCESS |
0
,
NULL, szDir, &si,
&pi);
else
#endif
alloc_cmdline_2_args(szExe, endpoint, "-D", &cmdline);
bRes = CreateProcess( szExe, NULL, psa, psa, FALSE,
CREATE_NEW_PROCESS_GROUP |
CREATE_NEW_CONSOLE |
NORMAL_PRIORITY_CLASS |
0
,
NULL, szDir, &si,
&pi);
if (!bRes) {
status = GetLastError();
cci_debug_printf(" CreateProcess returned %d; LastError: %d", bRes, status);
}
cci_debug_printf(" Waiting...");
}
cci_check_error(status);
if (!status) {
status = WaitForSingleObject(hEvent, (SECONDS_TO_WAIT)*1000);
status = RpcMgmtIsServerListening(ccs_request_IfHandle);
}
}
else if (status) {
cci_debug_printf(" unexpected error while looking for server: 0D%d / 0U%u / 0X%X", status, status, status);
}
#if 0
if (hToken)
CloseHandle(hToken);
#endif
if (szDir) free_alloc_p(&szDir);
if (szExe) free_alloc_p(&szExe);
if (hEvent) CloseHandle(hEvent);
if (pi.hThread) CloseHandle(pi.hThread);
if (pi.hProcess) CloseHandle(pi.hProcess);
if (sa.lpSecurityDescriptor) free_alloc_p(&sa.lpSecurityDescriptor);
return cci_check_error(status);
}
static
DWORD
authenticate_server(Init::InitInfo& info) {
DWORD challenge = 17; DWORD desired_response= challenge + 1;
HANDLE hMap = 0;
LPSTR mem_name = 0;
PDWORD pvalue = 0;
CC_UINT32 response = 0;
SECURITY_ATTRIBUTES sa = { 0 };
DWORD status = 0;
cci_debug_printf("%s entry", __FUNCTION__);
status = alloc_name(&mem_name, "auth", isNT());
cci_check_error(status);
if (!status) {
if (isNT()) {
sa.nLength = sizeof(sa);
status = alloc_own_security_descriptor_NT(&sa.lpSecurityDescriptor);
}
}
cci_check_error(status);
if (!status) {
hMap = CreateFileMapping(INVALID_HANDLE_VALUE, isNT() ? &sa : 0,
PAGE_READWRITE, 0, sizeof(DWORD), mem_name);
if (!hMap)
status = GetLastError();
}
cci_check_error(status);
if (!status) {
pvalue = (PDWORD)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (!pvalue) status = GetLastError();
}
cci_check_error(status);
if (!status) {
*pvalue = challenge;
RpcTryExcept {
response = ccs_authenticate( (CC_CHAR*)mem_name );
}
RpcExcept(1) {
status = RpcExceptionCode();
cci_check_error(status);
}
RpcEndExcept;
}
cci_check_error(status);
if (!status) {
if ((response != desired_response) && (*pvalue != desired_response)) {
cci_debug_printf(" Could not authenticate server.");
status = ERROR_ACCESS_DENIED; }
else {
cci_debug_printf(" Server authenticated!");
}
cci_check_error(status);
}
free_alloc_p(&mem_name);
free_alloc_p(&sa.lpSecurityDescriptor);
if (pvalue) {
BOOL ok = UnmapViewOfFile(pvalue);
}
if (hMap) CloseHandle(hMap);
return status;
}
DWORD
Client::Disconnect() {
DWORD status = 0;
if (ccs_request_IfHandle) {
status = RpcBindingFree(&ccs_request_IfHandle);
}
s_init = false;
return status;
}
DWORD
Client::Connect(char* ep OPTIONAL) {
LPSTR endpoint = 0;
DWORD status = 0;
if (!ccs_request_IfHandle) {
Init::InitInfo info;
status = Init::Info(info);
cci_check_error(status);
if (!status) {
status = bind_client(ep, info, &endpoint);
cci_check_error(status);
}
if (!status) {
status = find_server(info, endpoint);
cci_check_error(status);
}
if (!status) {
status = authenticate_server(info);
cci_check_error(status);
}
}
if (endpoint && (endpoint != ep)) free_alloc_p(&endpoint);
if (status) Client::Disconnect();
return status;
}
DWORD Client::Initialize(char* ep OPTIONAL) {
CcAutoLock AL(Client::sLock);
SecureClient s;
ccs_request_IfHandle = NULL;
if (s_init) return 0;
DWORD status = Client::Connect(ep);
if (!status) s_init = true;
return status;
}
DWORD Client::Cleanup() {
CcAutoLock AL(Client::sLock);
SecureClient s;
return Client::Disconnect();
}
DWORD Client::Reconnect(char* ep OPTIONAL) {
CcAutoLock AL(Client::sLock);
SecureClient s;
DWORD status = 0;
if (Initialized()) {
DWORD status = Client::Cleanup();
}
if ( (!status) ) {
status = Client::Initialize(ep);
}
return status;
}