extern "C" {
#include "k5-thread.h"
#include "ccapi_os_ipc.h"
#include "cci_debugging.h"
#include "ccs_reply.h"
#include "ccs_request.h"
#include "ccutils.h"
#include "tls.h"
#include "util.h"
#include "win-utils.h"
}
#include "autolock.hxx"
#include "CredentialsCache.h"
#include "secure.hxx"
#include "opts.hxx"
#include "client.h"
extern "C" DWORD GetTlsIndex();
#define SECONDS_TO_WAIT 10
#define CLIENT_REQUEST_RPC_HANDLE ccs_request_IfHandle
extern HANDLE hCCAPIv2Mutex;
ParseOpts::Opts opts = { 0 };
PSECURITY_ATTRIBUTES psa = 0;
SECURITY_ATTRIBUTES sa = { 0 };
cc_int32 ccapi_connect(const struct tspdata* tsp);
static DWORD handle_exception(DWORD code, struct tspdata* ptspdata);
extern "C" {
cc_int32 cci_os_ipc_msg( cc_int32 in_launch_server,
k5_ipc_stream in_request_stream,
cc_int32 in_msg,
k5_ipc_stream* out_reply_stream);
}
extern "C" cc_int32 cci_os_ipc_process_init (void) {
RPC_STATUS status;
if (!isNT()) {
status = RpcServerRegisterIf(ccs_reply_ServerIfHandle,
NULL,
NULL);
}
else {
status = RpcServerRegisterIfEx(ccs_reply_ServerIfHandle,
NULL,
NULL,
RPC_IF_ALLOW_SECURE_ONLY,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
NULL);
}
cci_check_error(status);
if (!status) {
status = RpcServerRegisterAuthInfo(0,
RPC_C_AUTHN_WINNT,
0,
0 );
cci_check_error(status);
}
return status;
}
extern "C" cc_int32 cci_os_ipc_thread_init (void) {
cc_int32 err = ccNoError;
struct tspdata* ptspdata;
HANDLE replyEvent = NULL;
UUID __RPC_FAR uuid;
RPC_CSTR __RPC_FAR uuidString = NULL;
char* endpoint = NULL;
if (!GetTspData(GetTlsIndex(), &ptspdata)) return ccErrNoMem;
err = cci_check_error(UuidCreate(&uuid));
if (err == RPC_S_OK) {
err = UuidToString(&uuid, &uuidString);
cci_check_error(err);
}
if (!err) {
tspdata_setUUID(ptspdata, uuidString);
endpoint = clientEndpoint((const char *)uuidString);
err = RpcServerUseProtseqEp((RPC_CSTR)"ncalrpc",
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
(RPC_CSTR)endpoint,
sa.lpSecurityDescriptor);
free(endpoint);
cci_check_error(err);
}
if (!err) if (!Init:: Initialized()) err = Init:: Initialize( );
if (!err) if (!Client::Initialized()) err = Client::Initialize(0);
if (!err) {
replyEvent = createThreadEvent((char*)uuidString, REPLY_SUFFIX);
}
if (!err) {
static bool bListening = false;
if (!bListening) {
err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
cci_check_error(err);
}
bListening = err == 0;
}
if (replyEvent) tspdata_setReplyEvent(ptspdata, replyEvent);
else err = cci_check_error(GetLastError());
if (uuidString) RpcStringFree(&uuidString);
return cci_check_error(err);
}
cc_int32 cci_os_ipc (cc_int32 in_launch_server,
k5_ipc_stream in_request_stream,
k5_ipc_stream* out_reply_stream) {
return cci_os_ipc_msg( in_launch_server,
in_request_stream,
CCMSG_REQUEST,
out_reply_stream);
}
extern "C" cc_int32 cci_os_ipc_msg( cc_int32 in_launch_server,
k5_ipc_stream in_request_stream,
cc_int32 in_msg,
k5_ipc_stream* out_reply_stream) {
cc_int32 err = ccNoError;
cc_int32 done = FALSE;
cc_int32 try_count = 0;
cc_int32 server_died = FALSE;
TCHAR* pszStringBinding= NULL;
struct tspdata* ptspdata = NULL;
char* uuid = NULL;
int lenUUID = 0;
unsigned int trycount = 0;
time_t sst = 0;
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
HANDLE replyEvent = 0;
BOOL bCCAPI_Connected= FALSE;
BOOL bListening = FALSE;
unsigned char tspdata_handle[8] = { 0 };
if (!in_request_stream) { err = cci_check_error (ccErrBadParam); }
if (!out_reply_stream ) { err = cci_check_error (ccErrBadParam); }
if (!GetTspData(GetTlsIndex(), &ptspdata)) {return ccErrBadParam;}
bListening = tspdata_getListening(ptspdata);
if (!bListening) {
err = cci_check_error(cci_os_ipc_thread_init());
bListening = !err;
tspdata_setListening(ptspdata, bListening);
}
bCCAPI_Connected = tspdata_getConnected (ptspdata);
replyEvent = tspdata_getReplyEvent (ptspdata);
sst = tspdata_getSST (ptspdata);
uuid = tspdata_getUUID(ptspdata);
if (!err && !bCCAPI_Connected) {
err = cci_check_error(ccapi_connect(ptspdata));
bCCAPI_Connected = !err;
tspdata_setConnected(ptspdata, bCCAPI_Connected);
}
ResetEvent(replyEvent);
WaitForSingleObject( hCCAPIv2Mutex, INFINITE );
SecureClient* s = 0;
SecureClient::Start(s);
CcAutoLock* a = 0;
CcAutoLock::Start(a, Client::sLock);
if (!err) {
RpcTryExcept {
if (!GetTspData(GetTlsIndex(), &ptspdata)) {return ccErrBadParam;}
uuid = tspdata_getUUID(ptspdata);
lenUUID = 1 + strlen(uuid);
memcpy(tspdata_handle, &ptspdata, sizeof(ptspdata));
ccs_rpc_request(
in_msg,
tspdata_handle,
(unsigned char*)uuid,
krb5int_ipc_stream_size(in_request_stream),
(unsigned char*)krb5int_ipc_stream_data(in_request_stream),
sst,
(long*)(&err) );
}
RpcExcept(1) {
err = handle_exception(RpcExceptionCode(), ptspdata);
}
RpcEndExcept;
}
cci_check_error(err);
CcAutoLock::Stop(a);
SecureClient::Stop(s);
ReleaseMutex(hCCAPIv2Mutex);
if (!err) {
err = cci_check_error(WaitForSingleObject(replyEvent, INFINITE));
}
if (!err) {
err = cci_check_error(RpcMgmtIsServerListening(CLIENT_REQUEST_RPC_HANDLE));
}
if (!err && server_died) {
err = cci_check_error (ccErrServerUnavailable);
}
if (!err) {
*out_reply_stream = tspdata_getStream(ptspdata);
}
return cci_check_error (err);
}
static DWORD handle_exception(DWORD code, struct tspdata* ptspdata) {
cci_debug_printf("%s code %u; ccs_request_IfHandle:0x%X", __FUNCTION__, code, ccs_request_IfHandle);
if ( (code == RPC_S_SERVER_UNAVAILABLE) || (code == RPC_S_INVALID_BINDING) ) {
Client::Cleanup();
tspdata_setConnected(ptspdata, FALSE);
}
return code;
}
cc_int32 ccapi_connect(const struct tspdata* tsp) {
BOOL bListen = TRUE;
HANDLE replyEvent = 0;
RPC_STATUS status = FALSE;
char* uuid = NULL;
unsigned char tspdata_handle[8] = {0};
replyEvent = tspdata_getReplyEvent(tsp);
uuid = tspdata_getUUID(tsp);
cci_debug_printf("%s is listening ...", __FUNCTION__);
ResetEvent(replyEvent);
WaitForSingleObject( hCCAPIv2Mutex, INFINITE );
SecureClient* s = 0;
SecureClient::Start(s);
CcAutoLock* a = 0;
CcAutoLock::Start(a, Client::sLock);
if (!status) if (!Init:: Initialized()) status = Init:: Initialize( );
if (!status) if (!Client::Initialized()) status = Client::Initialize(0);
if (!status) {
memcpy(tspdata_handle, &tsp, sizeof(tsp));
RpcTryExcept {
ccs_rpc_connect(
CCMSG_CONNECT,
tspdata_handle,
(unsigned char*)uuid,
(long*)(&status) );
}
RpcExcept(1) {
cci_check_error(RpcExceptionCode());
status = ccErrBadInternalMessage;
}
RpcEndExcept;
}
CcAutoLock::Stop(a);
SecureClient::Stop(s);
ReleaseMutex(hCCAPIv2Mutex);
if (!status) {
status = WaitForSingleObject(replyEvent, INFINITE);
status = cci_check_error(RpcMgmtIsServerListening(CLIENT_REQUEST_RPC_HANDLE));
cci_debug_printf(" Server %sFOUND!", (status) ? "NOT " : "");
}
if (status) {
cci_debug_printf(" unexpected error while looking for server... (%u)", status);
}
return status;
}