1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-15 07:43:50 +00:00

MeshAgent for MeshCentral2 Beta2 with improved crypto.

This commit is contained in:
Ylian Saint-Hilaire
2017-10-25 21:08:41 -07:00
parent 0a7e84849d
commit 34e09c2304
53 changed files with 1778 additions and 551 deletions

View File

@@ -109,6 +109,66 @@ typedef struct ScriptContainerSettings
void *nUncaughtExceptionUser;
char ContextGuid[sizeof(JS_ENGINE_CONTEXT) + 1];
}ScriptContainerSettings;
#pragma pack(push, 1)
typedef struct MeshCommand_BinaryPacket_AuthRequest
{
unsigned short command;
char serverHash[UTIL_HASHSIZE];
char serverNonce[UTIL_HASHSIZE];
}MeshCommand_BinaryPacket_AuthRequest;
typedef struct MeshCommand_BinaryPacket_AuthVerify_Header
{
unsigned short command;
unsigned short certLen;
char data[];
}MeshCommand_BinaryPacket_AuthVerify_Header;
typedef struct MeshCommand_BinaryPacket_AuthVerify
{
char *cert;
unsigned short certLen;
char *signature;
unsigned short signatureLen;
}MeshCommand_BinaryPacket_AuthVerify;
typedef enum MeshCommand_AuthInfo_PlatformType
{
MeshCommand_AuthInfo_PlatformType_DESKTOP = 1,
MeshCommand_AuthInfo_PlatformType_LAPTOP = 2,
MeshCommand_AuthInfo_PlatformType_MOBILE = 3,
MeshCommand_AuthInfo_PlatformType_SERVER = 4,
MeshCommand_AuthInfo_PlatformType_DISK = 5,
MeshCommand_AuthInfo_PlatformType_ROUTER = 6
}MeshCommand_BinaryPacket_AuthInfo_PlatformType;
typedef enum MeshCommand_AuthInfo_CapabilitiesMask
{
MeshCommand_AuthInfo_CapabilitiesMask_DESKTOP = 0x01,
MeshCommand_AuthInfo_CapabilitiesMask_TERMINAL = 0x02,
MeshCommand_AuthInfo_CapabilitiesMask_FILES = 0x04,
MeshCommand_AuthInfo_CapabilitiesMask_CONSOLE = 0x08,
MeshCommand_AuthInfo_CapabilitiesMask_JAVASCRIPT= 0x10
}MeshCommand_AuthInfo_CapabilitiesMask;
typedef struct MeshCommand_BinaryPacket_AuthInfo
{
unsigned short command;
unsigned int infoVersion;
unsigned int agentId;
unsigned int agentVersion;
unsigned int platformType;
char MeshID[UTIL_HASHSIZE];
unsigned int capabilities;
unsigned short hostnameLen;
char hostname[];
}MeshCommand_BinaryPacket_AuthInfo;
typedef struct MeshCommand_BinaryPacket_CoreModule
{
unsigned short command;
unsigned short request;
char coreModuleHash[UTIL_HASHSIZE];
char coreModule[];
}MeshCommand_BinaryPacket_CoreModule;
#pragma pack(pop)
#define ScriptContainerSettingsKey "\xFF_ScriptContainerSettings"
ScriptContainerSettings* ScriptEngine_GetSettings(duk_context *ctx)
@@ -375,14 +435,14 @@ void UDPSocket_OnData(ILibAsyncUDPSocket_SocketModule socketModule, char* buffer
// Check if this is a Mesh Server discovery packet and it is for our server
// It will have this form: "MeshCentral2|f5a50091028fe2c122434cbcbd2709a7ec10369295e5a0e43db8853a413d89df|wss://~:443/agent.ashx"
if ((bufferLength > 78) && (memcmp(buffer, "MeshCentral2|", 13) == 0) && ((ILibSimpleDataStore_Get(agentHost->masterDb, "ServerID", ILibScratchPad, sizeof(ILibScratchPad))) == 65) && (memcmp(ILibScratchPad, buffer + 13, 64) == 0)) {
if ((bufferLength > 78) && (memcmp(buffer, "MeshCentral2|", 13) == 0) && ((ILibSimpleDataStore_Get(agentHost->masterDb, "ServerID", ILibScratchPad, sizeof(ILibScratchPad))) == 97) && (memcmp(ILibScratchPad, buffer + 13, 96) == 0)) {
// We have a match, set the server URL correctly.
if (agentHost->multicastServerUrl != NULL) { free(agentHost->multicastServerUrl); agentHost->multicastServerUrl = NULL; }
if ((agentHost->multicastServerUrl = (char*)malloc(bufferLength - 78 + 128)) == NULL) { ILIBCRITICALEXIT(254); }
buffer[bufferLength] = 0;
ILibInet_ntop2((struct sockaddr*)remoteInterface, (char*)ILibScratchPad2, sizeof(ILibScratchPad));
sprintf_s(agentHost->multicastServerUrl, bufferLength - 78 + 128, buffer + 78, ILibScratchPad2);
sprintf_s(agentHost->multicastServerUrl, bufferLength - 78 + 128, buffer + 78 + 32, ILibScratchPad2);
//printf("FoundServer: %s\r\n", agentHost->multicastServerUrl);
if (agentHost->serverConnectionState == 0) { MeshServer_ConnectEx(agentHost); }
@@ -562,7 +622,7 @@ duk_ret_t ILibDuktape_MeshAgent_GenerateCertificate(duk_context *ctx)
ILibRemoteLogging_printf(ILibChainGetLogger(agent->chain), ILibRemoteLogging_Modules_Agent_GuardPost, ILibRemoteLogging_Flags_VerbosityLevel_1, "...Generating JS TLS Certificate");
#endif
len = util_mkCert(NULL, &(cert), 2048, 10000, "localhost", CERTIFICATE_TLS_CLIENT, NULL);
len = util_mkCert(NULL, &(cert), 3072, 10000, "localhost", CERTIFICATE_TLS_CLIENT, NULL);
len = util_to_p12(cert, passphrase, &data);
duk_push_fixed_buffer(ctx, len);
@@ -1030,7 +1090,7 @@ int agent_GenerateCertificates(MeshAgentHostContainer *agent, char* certfile)
do
{
if (util_mkCert(NULL, &(agent->selfcert), 2048, 10000, "MeshNodeCertificate", CERTIFICATE_ROOT, NULL) == 0) return -1;
if (util_mkCert(NULL, &(agent->selfcert), 3072, 10000, "MeshNodeCertificate", CERTIFICATE_ROOT, NULL) == 0) return -1;
util_keyhash(agent->selfcert, agent->g_selfid);
} while (((int*)agent->g_selfid)[0] == 0); // This removes any chance that the self_id starts with 32 bits of zeros.
@@ -1060,14 +1120,14 @@ int agent_GenerateCertificates(MeshAgentHostContainer *agent, char* certfile)
// Generate a new TLS certificate
ILibRemoteLogging_printf(ILibChainGetLogger(agent->chain), ILibRemoteLogging_Modules_Agent_GuardPost, ILibRemoteLogging_Flags_VerbosityLevel_1, "...Generating TLS Certificate");
len = util_mkCert(&(agent->selfcert), &(agent->selftlscert), 2048, 10000, "localhost", CERTIFICATE_TLS_SERVER, NULL);
len = util_mkCert(&(agent->selfcert), &(agent->selftlscert), 3072, 10000, "localhost", CERTIFICATE_TLS_SERVER, NULL);
len = util_to_p12(agent->selftlscert, "hidden", &str);
ILibSimpleDataStore_PutEx(agent->masterDb, "SelfNodeTlsCert", 15, str, len);
util_free(str);
// Generate a new TLS client certificate
ILibRemoteLogging_printf(ILibChainGetLogger(agent->chain), ILibRemoteLogging_Modules_Agent_GuardPost, ILibRemoteLogging_Flags_VerbosityLevel_1, "...Generating TLS Client Certificate");
len = util_mkCert(&(agent->selfcert), &(agent->selftlsclientcert), 2048, 10000, "localhost", CERTIFICATE_TLS_CLIENT, NULL);
len = util_mkCert(&(agent->selfcert), &(agent->selftlsclientcert), 3072, 10000, "localhost", CERTIFICATE_TLS_CLIENT, NULL);
len = util_to_p12(agent->selftlsclientcert, "hidden", &str);
ILibSimpleDataStore_PutEx(agent->masterDb, "SelfNodeTlsClientCert", 21, str, len);
util_free(str);
@@ -1291,96 +1351,107 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
switch (command)
{
case MeshCommand_AuthRequest: // This is basic authentication information from the server, we need to sign this and return the signature.
if (cmdLen == 66) {
int signLen, certlen;
SHA256_CTX c;
if (cmdLen == sizeof(MeshCommand_BinaryPacket_AuthRequest))
{
MeshCommand_BinaryPacket_AuthRequest *AuthRequest = (MeshCommand_BinaryPacket_AuthRequest*)cmd;
int signLen;
SHA512_CTX c;
EVP_PKEY *evp_prikey;
RSA *rsa_prikey;
char *certDer = ILibScratchPad2 + 4;
// Hash the server's web certificate and check if it matches the one in the auth request
util_keyhash2(peer, ILibScratchPad2); // Hash the server certificate public key and place it
if (memcmp(ILibScratchPad2, cmd + 2, UTIL_HASHSIZE) != 0) { printf("Bad server certificate hash\r\n"); break; } // TODO: Disconnect
memcpy_s(agent->serverNonce, sizeof(agent->serverNonce), cmd + 34, UTIL_HASHSIZE);
if (memcmp(ILibScratchPad2, AuthRequest->serverHash, sizeof(AuthRequest->serverHash)) != 0) { printf("Bad server certificate hash\r\n"); break; } // TODO: Disconnect
memcpy_s(agent->serverNonce, sizeof(agent->serverNonce), AuthRequest->serverNonce, sizeof(AuthRequest->serverNonce));
// Place our certificate in the response
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_AuthVerify); // MeshCommand_AuthVerify (2), agent certificate in ASN1 format
certlen = i2d_X509(agent->selfcert.x509, (unsigned char **)&certDer); // Place the agent root certificate in DER form
((unsigned short*)ILibScratchPad2)[1] = htons(certlen); // Place the size of the certificate
MeshCommand_BinaryPacket_AuthVerify_Header *rav = (MeshCommand_BinaryPacket_AuthVerify_Header*)ILibScratchPad2;
rav->command = htons(MeshCommand_AuthVerify); // MeshCommand_AuthVerify (2), agent certificate in ASN1 format
char *certDer = (char*)rav->data;
rav->certLen = htons(i2d_X509(agent->selfcert.x509, (unsigned char **)&certDer)); // Place the agent root certificate in DER form
// Use our agent root private key to sign the ServerWebHash + ServerNonce + AgentNonce
SHA256_Init(&c);
SHA384_Init(&c);
util_keyhash2(peer, ILibScratchPad);
SHA256_Update(&c, cmd + 2, UTIL_HASHSIZE); // Server web hash
SHA256_Update(&c, agent->serverNonce, UTIL_HASHSIZE); // Server nonce
SHA256_Update(&c, agent->agentNonce, UTIL_HASHSIZE); // Agent nonce
SHA256_Final((unsigned char*)ILibScratchPad, &c);
SHA384_Update(&c, AuthRequest->serverHash, sizeof(AuthRequest->serverHash)); // Server web hash
SHA384_Update(&c, agent->serverNonce, UTIL_HASHSIZE); // Server nonce
SHA384_Update(&c, agent->agentNonce, UTIL_HASHSIZE); // Agent nonce
SHA384_Final((unsigned char*)ILibScratchPad, &c);
// Place the signature & send
evp_prikey = agent->selfcert.pkey;
rsa_prikey = EVP_PKEY_get1_RSA(evp_prikey);
signLen = 65535 - (4 + certlen);
if (RSA_sign(NID_sha256, (unsigned char*)ILibScratchPad, UTIL_HASHSIZE, (unsigned char*)(ILibScratchPad2 + 4 + certlen), (unsigned int*)&signLen, rsa_prikey) == 1)
signLen = sizeof(ILibScratchPad2) - sizeof(MeshCommand_BinaryPacket_AuthVerify_Header) - rav->certLen;
if (RSA_sign(NID_sha384, (unsigned char*)ILibScratchPad, UTIL_HASHSIZE, (unsigned char*)(rav->data + rav->certLen), (unsigned int*)&signLen, rsa_prikey) == 1)
{
// Signature succesful, send the result to the server
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, 4 + certlen + signLen, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)rav, sizeof(MeshCommand_BinaryPacket_AuthVerify_Header) + rav->certLen + signLen, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
}
RSA_free(rsa_prikey);
}
break;
case MeshCommand_AuthVerify: // This is the signature from the server. We need to check everything is ok.
if (cmdLen > 8)
{
unsigned short certlen = ntohs(((unsigned short*)cmd)[1]);
if (cmdLen > (4 + certlen)) {
int platformType = 1, hashlen = UTIL_HASHSIZE;
SHA256_CTX c;
MeshCommand_BinaryPacket_AuthVerify_Header *avh = (MeshCommand_BinaryPacket_AuthVerify_Header*)cmd;
#ifdef WIN32
MeshCommand_BinaryPacket_AuthVerify *AuthVerify = (MeshCommand_BinaryPacket_AuthVerify*)_alloca(sizeof(MeshCommand_BinaryPacket_AuthVerify));
#else
MeshCommand_BinaryPacket_AuthVerify *AuthVerify = (MeshCommand_BinaryPacket_AuthVerify*)alloca(sizeof(MeshCommand_BinaryPacket_AuthVerify));
#endif
AuthVerify->cert = avh->data;
AuthVerify->certLen = ntohs(avh->certLen);
AuthVerify->signature = avh->data + AuthVerify->certLen;
AuthVerify->signatureLen = (unsigned short)(cmdLen - (int)(sizeof(MeshCommand_BinaryPacket_AuthVerify_Header) + AuthVerify->certLen));
if (cmdLen > (int)(sizeof(MeshCommand_BinaryPacket_AuthVerify_Header) + AuthVerify->certLen))
{
int hashlen = UTIL_HASHSIZE;
SHA512_CTX c;
X509* serverCert = NULL;
EVP_PKEY *evp_pubkey;
RSA *rsa_pubkey;
char* ptr = cmd + 4;
// Get the server certificate
if (!d2i_X509(&serverCert, (const unsigned char**)&ptr, certlen)) { printf("Invalid server certificate\r\n"); break; } // TODO: Disconnect
if (!d2i_X509(&serverCert, (const unsigned char**)&AuthVerify->cert, AuthVerify->certLen)) { printf("Invalid server certificate\r\n"); break; } // TODO: Disconnect
// Check if this certificate public key hash matches what we want
// util_sha256((char*)(serverCert->cert_info->key->public_key->data), serverCert->cert_info->key->public_key->length, ILibScratchPad); // OpenSSL 1.0
X509_pubkey_digest(serverCert, EVP_sha256(), (unsigned char*)ILibScratchPad, (unsigned int*)&hashlen); // OpenSSL 1.1
X509_pubkey_digest(serverCert, EVP_sha384(), (unsigned char*)ILibScratchPad, (unsigned int*)&hashlen); // OpenSSL 1.1
if (memcmp(ILibScratchPad, agent->serverHash, UTIL_HASHSIZE) != 0) { printf("Server certificate mismatch\r\n"); break; } // TODO: Disconnect
// Compute the authentication hash
SHA256_Init(&c);
SHA384_Init(&c);
util_keyhash2(peer, ILibScratchPad);
SHA256_Update(&c, ILibScratchPad, UTIL_HASHSIZE);
SHA256_Update(&c, agent->agentNonce, UTIL_HASHSIZE);
SHA256_Update(&c, agent->serverNonce, UTIL_HASHSIZE);
SHA256_Final((unsigned char*)ILibScratchPad, &c);
SHA384_Update(&c, ILibScratchPad, UTIL_HASHSIZE);
SHA384_Update(&c, agent->agentNonce, UTIL_HASHSIZE);
SHA384_Update(&c, agent->serverNonce, UTIL_HASHSIZE);
SHA384_Final((unsigned char*)ILibScratchPad, &c);
// Verify the hash signature using the server certificate
evp_pubkey = X509_get_pubkey(serverCert);
rsa_pubkey = EVP_PKEY_get1_RSA(evp_pubkey);
if (RSA_verify(NID_sha256, (unsigned char*)ILibScratchPad, UTIL_HASHSIZE, (unsigned char*)(cmd + 4 + certlen), cmdLen - (4 + certlen), rsa_pubkey) == 1)
if (RSA_verify(NID_sha384, (unsigned char*)ILibScratchPad, UTIL_HASHSIZE, (unsigned char*)AuthVerify->signature, AuthVerify->signatureLen, rsa_pubkey) == 1)
{
int hostnamelen = (int)strnlen_s(agent->hostname, sizeof(agent->hostname));
// Server signature verified, we are good to go.
agent->serverAuthState += 1;
// Send to the server information about this agent (TODO: Replace this with a struct)
if ((agent->batteryState != MeshAgentHost_BatteryInfo_NONE) && (agent->batteryState != MeshAgentHost_BatteryInfo_UNKNOWN)) { platformType = 2; } // If a battery is present, select laptop icon
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_AuthInfo); // MeshCommand_AuthInfo (3), agent information
((unsigned int*)(ILibScratchPad2 + 2))[0] = htonl(1); // Agent information version
((unsigned int*)(ILibScratchPad2 + 6))[0] = htonl(MESH_AGENTID); // Agent Identifier
((unsigned int*)(ILibScratchPad2 + 10))[0] = htonl(agent->version); // Agent Version
((unsigned int*)(ILibScratchPad2 + 14))[0] = htonl(platformType); // Platfrom Type: This is the icon: 1 = Desktop, 2 = Laptop, 3 = Mobile, 4 = Server, 5 = Disk, 6 = Router
memcpy_s(ILibScratchPad2 + 18, sizeof(ILibScratchPad2) - 18, agent->meshId, UTIL_HASHSIZE); // MeshId, taken from the agent settings
((unsigned int*)(ILibScratchPad2 + 50))[0] = htonl(8 + 16); // Capabilities of the agent(bitmask) : 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
((unsigned short*)ILibScratchPad2 + 54)[0] = htons(hostnamelen); // Hostname length
memcpy_s(ILibScratchPad2 + 56, sizeof(ILibScratchPad2) - 56, agent->hostname, hostnamelen); // Hostname
MeshCommand_BinaryPacket_AuthInfo *info = (MeshCommand_BinaryPacket_AuthInfo*)ILibScratchPad2;
info->command = htons(MeshCommand_AuthInfo);
info->infoVersion = htonl(1);
info->agentId = htonl(MESH_AGENTID);
info->agentVersion = htonl(agent->version);
info->platformType = htonl(((agent->batteryState != MeshAgentHost_BatteryInfo_NONE) && (agent->batteryState != MeshAgentHost_BatteryInfo_UNKNOWN)) ? MeshCommand_AuthInfo_PlatformType_LAPTOP : MeshCommand_AuthInfo_PlatformType_DESKTOP);
memcpy_s(info->MeshID, sizeof(info->MeshID), agent->meshId, sizeof(agent->meshId));
info->capabilities = htonl(MeshCommand_AuthInfo_CapabilitiesMask_CONSOLE | MeshCommand_AuthInfo_CapabilitiesMask_JAVASCRIPT);
info->hostnameLen = htons(hostnamelen);
memcpy_s(info->hostname, sizeof(ILibScratchPad2) - sizeof(MeshCommand_BinaryPacket_AuthInfo), agent->hostname, hostnamelen);
// Send mesh agent information to the server
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, 56 + hostnamelen, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)info, sizeof(MeshCommand_BinaryPacket_AuthInfo) + hostnamelen, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
agent->retryTime = 0;
printf("Connected.\n");
if (agent->serverAuthState == 3) { MeshServer_ServerAuthenticated(WebStateObject, agent); }
@@ -1472,20 +1543,22 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
case MeshCommand_CoreModule: // New core modules to be used instead of the old one, if empty, remove the core module
{
char *coreException = NULL;
MeshCommand_BinaryPacket_CoreModule *cm = (MeshCommand_BinaryPacket_CoreModule*)cmd;
// If the agent is running with a local core, ignore this command
if (agent->localScript != 0) break;
if (cmdLen > 36) // Setup a new mesh core. Command is: cmdid + requestid + sha256hash + javascript
if (cmdLen > sizeof(MeshCommand_BinaryPacket_CoreModule)) // Setup a new mesh core.
{
char *hashref = ILibSimpleDataStore_GetHash(agent->masterDb, "CoreModule"); // Get the reference to the SHA256 hash for the currently running code
if (hashref == NULL || memcmp(hashref, cmd + 4, 32) != 0)
if (hashref == NULL || memcmp(hashref, cm->coreModuleHash, sizeof(cm->coreModuleHash)) != 0)
{
// If server sends us the same core, just do nothing.
// Server sent us a new core, start by storing it in the data store
ILibSimpleDataStore_PutEx(agent->masterDb, "CoreModule", 10, cmd + 36, cmdLen - 36); // Store the JavaScript in the data store
ILibSimpleDataStore_PutEx(agent->masterDb, "CoreModule", 10, cm->coreModule, cmdLen - sizeof(MeshCommand_BinaryPacket_CoreModule)); // Store the JavaScript in the data store
hashref = ILibSimpleDataStore_GetHash(agent->masterDb, "CoreModule"); // Get the reference to the SHA256 hash
if (memcmp(hashref, cmd + 4, 32) != 0) { // Check the hash for sanity
if (memcmp(hashref, cm->coreModuleHash, sizeof(cm->coreModuleHash)) != 0)
{ // Check the hash for sanity
// Something went wrong, clear the data store
ILibSimpleDataStore_Delete(agent->masterDb, "CoreModule");
@@ -1495,9 +1568,10 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
ScriptEngine_Stop(agent, MeshAgent_JavaCore_ContextGuid);
// Tell the server we are no longer running a core module
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_CoreModuleHash); // MeshCommand_CoreModuleHash (11), SHA256 hash of the code module
((unsigned short*)ILibScratchPad2)[1] = htons(requestid); // Request id
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, 4, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
MeshCommand_BinaryPacket_CoreModule *rcm = (MeshCommand_BinaryPacket_CoreModule*)ILibScratchPad2;
rcm->command = htons(MeshCommand_CoreModuleHash); // MeshCommand_CoreModuleHash (11), SHA256 hash of the code module
rcm->request = htons(requestid); // Request id
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)rcm, 4, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
break;
}
@@ -1506,7 +1580,7 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
//printf("CORE: Restart\r\n");
ILibRemoteLogging_printf(ILibChainGetLogger(agent->chain), ILibRemoteLogging_Modules_Microstack_Generic | ILibRemoteLogging_Modules_ConsolePrint,
ILibRemoteLogging_Flags_VerbosityLevel_1, "MeshCore: Restart");
if ((coreException = ScriptEngine_Restart(agent, MeshAgent_JavaCore_ContextGuid, cmd + 40, cmdLen - 40)) != NULL)
if ((coreException = ScriptEngine_Restart(agent, MeshAgent_JavaCore_ContextGuid, cm->coreModule + 4, cmdLen - sizeof(MeshCommand_BinaryPacket_CoreModule) - 4)) != NULL)
{
ILibRemoteLogging_printf(ILibChainGetLogger(agent->chain), ILibRemoteLogging_Modules_Microstack_Generic | ILibRemoteLogging_Modules_ConsolePrint,
ILibRemoteLogging_Flags_VerbosityLevel_1, "MeshCore: Error: %s", coreException);
@@ -1518,12 +1592,13 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
}
// Create the server confirmation message that we are running the new core
MeshCommand_BinaryPacket_CoreModule *rcm = (MeshCommand_BinaryPacket_CoreModule*)ILibScratchPad2;
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_CoreModuleHash); // MeshCommand_CoreModuleHash (11), SHA256 hash of the code module
((unsigned short*)ILibScratchPad2)[1] = htons(requestid); // Request id
memcpy_s(ILibScratchPad2 + 4, sizeof(ILibScratchPad2) - 4, hashref, UTIL_HASHSIZE); // SHA256 hash
// Send the confirmation to the server
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, 36, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)rcm, sizeof(MeshCommand_BinaryPacket_CoreModule), ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
}
else if (cmdLen == 4)
{
@@ -1536,9 +1611,10 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
ScriptEngine_Stop(agent, MeshAgent_JavaCore_ContextGuid);
// Confirm to the server that we are not running any core
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_CoreModuleHash); // MeshCommand_CoreModuleHash (11), SHA256 hash of the code module
((unsigned short*)ILibScratchPad2)[1] = htons(requestid); // Request id
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, 4, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
MeshCommand_BinaryPacket_CoreModule *rcm = (MeshCommand_BinaryPacket_CoreModule*)ILibScratchPad2;
rcm->command = htons(MeshCommand_CoreModuleHash); // MeshCommand_CoreModuleHash (11), SHA256 hash of the code module
rcm->request = htons(requestid); // Request id
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)rcm, 4, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
}
break;
}
@@ -1552,12 +1628,13 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
if (agent->localScript != 0) break;
// Confirm to the server what core we are running
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_CoreModuleHash); // MeshCommand_CoreModuleHash (11), SHA256 hash of the code module
((unsigned short*)ILibScratchPad2)[1] = htons(requestid); // Request id
if (hashref != NULL) { memcpy_s(ILibScratchPad2 + 4, sizeof(ILibScratchPad2) - 4, hashref, UTIL_HASHSIZE); len += 32; }
MeshCommand_BinaryPacket_CoreModule *rcm = (MeshCommand_BinaryPacket_CoreModule*)ILibScratchPad2;
rcm->command = htons(MeshCommand_CoreModuleHash); // MeshCommand_CoreModuleHash (11), SHA256 hash of the code module
rcm->request = htons(requestid); // Request id
if (hashref != NULL) { memcpy_s(rcm->coreModuleHash, sizeof(rcm->coreModuleHash), hashref, UTIL_HASHSIZE); len = sizeof(MeshCommand_BinaryPacket_CoreModule); }
// Send the confirmation to the server
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, len, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)rcm, len, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
break;
}
@@ -1567,12 +1644,13 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
// This is a request for the hash of the agent binary
// Built the response that includes our self hash
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_AgentHash); // MeshCommand_AgentHash (12), SHA256 hash of the agent executable
((unsigned short*)ILibScratchPad2)[1] = htons(requestid); // Request id
memcpy_s(ILibScratchPad2 + 4, sizeof(ILibScratchPad2) - 4, agent->agentHash, UTIL_HASHSIZE);// SHA256 hash of the agent executable
MeshCommand_BinaryPacket_CoreModule *rcm = (MeshCommand_BinaryPacket_CoreModule*)ILibScratchPad2;
rcm->command = htons(MeshCommand_AgentHash); // MeshCommand_AgentHash (12), SHA256 hash of the agent executable
rcm->request = htons(requestid); // Request id
memcpy_s(rcm->coreModuleHash, sizeof(rcm->coreModuleHash), agent->agentHash, UTIL_HASHSIZE);// SHA256 hash of the agent executable
// Send the self hash back to the server
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, 36, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)rcm, sizeof(MeshCommand_BinaryPacket_CoreModule), ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
break;
}
@@ -1583,15 +1661,18 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
#else
char* updateFilePath = MeshAgent_MakeAbsolutePath(agent->exePath, ".update");
#endif
char updateFileHash[32];
char updateFileHash[UTIL_HASHSIZE];
MeshCommand_BinaryPacket_CoreModule *cm = (MeshCommand_BinaryPacket_CoreModule*)cmd;
if (cmdLen == 4) {
// Indicates the start of the agent update transfer
util_deletefile(updateFilePath);
} else if (cmdLen == 36) {
} else if (cmdLen == sizeof(MeshCommand_BinaryPacket_CoreModule))
{
// Indicates the end of the agent update transfer
// Check the SHA256 hash of the received file against the file we got.
if ((util_sha256file(updateFilePath, updateFileHash) == 0) && (memcmp(updateFileHash, cmd + 4, 32) == 0)) {
// Check the SHA384 hash of the received file against the file we got.
if ((util_sha384file(updateFilePath, updateFileHash) == 0) && (memcmp(updateFileHash, cm->coreModuleHash, sizeof(cm->coreModuleHash)) == 0))
{
printf("UPDATE: End OK\r\n");
// Check the file signature & version number
//if (signcheck_verifysign(updateFilePath, 1))
@@ -1697,13 +1778,15 @@ void MeshServer_OnResponse(ILibWebClient_StateObject WebStateObject, int Interru
agent->serverConnectionState = 2;
// Start authentication by sending a auth nonce & server TLS cert hash.
// Send 256 bits SHA256 hash of TLS cert public key + 256 bits nonce
util_random(32, agent->agentNonce); // Generate a new mesh agent connection nonce
((unsigned short*)ILibScratchPad2)[0] = htons(MeshCommand_AuthRequest); // MeshCommand_AuthRequest (1), server hash + nonce
util_keyhash2(peer, ILibScratchPad2 + 2); // Hash the server certificate public key and place it
// Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce
util_random(sizeof(agent->agentNonce), agent->agentNonce); // Generate a new mesh agent connection nonce
MeshCommand_BinaryPacket_AuthRequest *ar = (MeshCommand_BinaryPacket_AuthRequest*)ILibScratchPad2;
ar->command = htons(MeshCommand_AuthRequest); // MeshCommand_AuthRequest (1), server hash + nonce
util_keyhash2(peer, ar->serverHash); // Hash the server certificate public key and place it
if (peer != NULL) { X509_free(peer); }
memcpy_s(ILibScratchPad2 + 34, sizeof(ILibScratchPad2) - 34, agent->agentNonce, UTIL_HASHSIZE); // Place our mesh agent nonce
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, ILibScratchPad2, 66, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
memcpy_s(ar->serverNonce, sizeof(ar->serverNonce), agent->agentNonce, sizeof(agent->agentNonce)); // Place our mesh agent nonce
ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)ar, sizeof(MeshCommand_BinaryPacket_AuthRequest), ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete);
#endif
break;
}
@@ -1812,10 +1895,10 @@ void MeshServer_ConnectEx(MeshAgentHostContainer *agent)
{
if (agent->multicastServerUrl != NULL) {
serverUrl = agent->multicastServerUrl;
serverUrlLen = strlen(serverUrl);
serverUrlLen = (int)strlen(serverUrl);
} else {
// Multicast discovery packet to try to find our server
if ((agent->multicastDiscovery != NULL) && (ILibSimpleDataStore_Get(agent->masterDb, "ServerID", ILibScratchPad2, sizeof(ILibScratchPad2)) == 65)) { ILibMulticastSocket_Broadcast(agent->multicastDiscovery, ILibScratchPad2, 64, 1); }
if ((agent->multicastDiscovery != NULL) && (ILibSimpleDataStore_Get(agent->masterDb, "ServerID", ILibScratchPad2, sizeof(ILibScratchPad2)) == 97)) { ILibMulticastSocket_Broadcast(agent->multicastDiscovery, ILibScratchPad2, 96, 1); }
ILibDestructParserResults(rs);
MeshServer_Connect(agent);
return;
@@ -2100,12 +2183,13 @@ void MeshAgent_Slave(MeshAgentHostContainer *agentHost)
void MeshAgent_ChainEnd(void *chain, void *user)
{
MeshAgentHostContainer *agent = (MeshAgentHostContainer*)user;
duk_destroy_heap(agent->meshCoreCtx);
if (agent->meshCoreCtx != NULL) { duk_destroy_heap(agent->meshCoreCtx); }
}
void MeshAgent_RunScriptOnly_Finalizer(duk_context *ctx, void *user)
{
MeshAgentHostContainer *agentHost = (MeshAgentHostContainer*)user;
agentHost->meshCoreCtx = NULL;
if (ILibIsChainBeingDestroyed(agentHost->chain) == 0)
{
MeshAgent_Stop(agentHost);
@@ -2557,77 +2641,93 @@ void MeshAgent_ScriptMode(MeshAgentHostContainer *agentHost, int argc, char **ar
int connectAgent = 0;
int pathLen = 0;
// Get the full path name of the JavaScript file
#ifdef WIN32
pathLen = GetFullPathName(argv[1], sizeof(ILibScratchPad2), ILibScratchPad2, NULL);
#else
if (realpath(argv[1], ILibScratchPad2) != NULL) { pathLen = strnlen_s(ILibScratchPad2, PATH_MAX); }
#endif
// Try to load the JavaScript file from disk, if fail, return
jsFileLen = ILibReadFileFromDiskEx(&jsFile, ILibScratchPad2);
if (jsFileLen == 0) { printf("ERROR loading %s\n", ILibScratchPad2); return; }
// We need to pass the JavaScript full path to the JavaScript runtime as the first argument. Set the up here.
scriptArgs = (char**)ILibMemory_Allocate((1 + argc) * sizeof(char*), 1 + pathLen, NULL, (void**)&jsPath); // KLOCWORK is being dumb, becuase ILibScratchpad2 is gauranteed to be NULL terminated
strncpy_s(jsPath, ILibMemory_GetExtraMemorySize(jsPath), ILibScratchPad2, ILibMemory_GetExtraMemorySize(jsPath));
scriptArgs[0] = jsPath;
#ifdef WIN32
i = ILibString_LastIndexOf(ILibScratchPad2, pathLen, "\\", 1);
#else
i = ILibString_LastIndexOf(ILibScratchPad2, pathLen, "/", 1);
#endif
ILibScratchPad2[i] = 0;
#ifdef WIN32
SetCurrentDirectory(ILibScratchPad2);
#else
ignore_result(chdir(ILibScratchPad2));
#endif
// Parse arguments. Handle the ones we can, others will be passed to the JavaScript engine.
for (i = 2; i < argc; ++i)
if (agentHost->meshCoreCtx_embeddedScript == NULL)
{
if(agentHost->masterDb == NULL && strncmp(argv[i], "--script-db", 11) == 0 && ((i + 1) < argc))
// Get the full path name of the JavaScript file
#ifdef WIN32
pathLen = GetFullPathName(argv[1], sizeof(ILibScratchPad2), ILibScratchPad2, NULL);
#else
if (realpath(argv[1], ILibScratchPad2) != NULL) { pathLen = strnlen_s(ILibScratchPad2, PATH_MAX); }
#endif
// Try to load the JavaScript file from disk, if fail, return
jsFileLen = ILibReadFileFromDiskEx(&jsFile, ILibScratchPad2);
if (jsFileLen == 0) { printf("ERROR loading %s\n", ILibScratchPad2); return; }
// We need to pass the JavaScript full path to the JavaScript runtime as the first argument. Set the up here.
scriptArgs = (char**)ILibMemory_Allocate((1 + argc) * sizeof(char*), 1 + pathLen, NULL, (void**)&jsPath); // KLOCWORK is being dumb, becuase ILibScratchpad2 is gauranteed to be NULL terminated
strncpy_s(jsPath, ILibMemory_GetExtraMemorySize(jsPath), ILibScratchPad2, ILibMemory_GetExtraMemorySize(jsPath));
scriptArgs[0] = jsPath;
#ifdef WIN32
i = ILibString_LastIndexOf(ILibScratchPad2, pathLen, "\\", 1);
#else
i = ILibString_LastIndexOf(ILibScratchPad2, pathLen, "/", 1);
#endif
ILibScratchPad2[i] = 0;
#ifdef WIN32
SetCurrentDirectory(ILibScratchPad2);
#else
ignore_result(chdir(ILibScratchPad2));
#endif
// Parse arguments. Handle the ones we can, others will be passed to the JavaScript engine.
for (i = 2; i < argc; ++i)
{
// Specify DB file path
agentHost->masterDb = ILibSimpleDataStore_Create(MeshAgent_MakeAbsolutePath(agentHost->exePath, argv[i + 1]));
++i;
}
else if (strncmp(argv[i], "--script-flags", 14) == 0 && ((i + 1) < argc))
{
// JS Permissions (see .h for values)
if (ntohs(((unsigned short*)argv[i + 1])[0]) == HEX_IDENTIFIER)
if (agentHost->masterDb == NULL && strncmp(argv[i], "--script-db", 11) == 0 && ((i + 1) < argc))
{
int xlen = (int)strnlen_s(argv[i + 1], 32);
if (xlen <= 10)
{
util_hexToBuf(argv[i + 1] + 2, xlen - 2, (char*)&secFlags);
secFlags = ntohl(secFlags);
}
// Specify DB file path
agentHost->masterDb = ILibSimpleDataStore_Create(MeshAgent_MakeAbsolutePath(agentHost->exePath, argv[i + 1]));
++i;
}
}
else if (strncmp(argv[i], "--script-timeout", 16) == 0 && ((i + 1) < argc))
{
// Seconds before watchdog termination, 0 for unlimited
execTimeout = (unsigned int)atoi(argv[i + 1]);
++i;
}
else if (strncmp(argv[i], "--script-connect", 16) == 0)
{
// Connect to MeshCentral
connectAgent = 1;
if (agentHost->masterDb == NULL)
else if (strncmp(argv[i], "--script-flags", 14) == 0 && ((i + 1) < argc))
{
agentHost->masterDb = ILibSimpleDataStore_Create(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".db"));
// JS Permissions (see .h for values)
if (ntohs(((unsigned short*)argv[i + 1])[0]) == HEX_IDENTIFIER)
{
int xlen = (int)strnlen_s(argv[i + 1], 32);
if (xlen <= 10)
{
util_hexToBuf(argv[i + 1] + 2, xlen - 2, (char*)&secFlags);
secFlags = ntohl(secFlags);
}
++i;
}
}
else if (strncmp(argv[i], "--script-timeout", 16) == 0 && ((i + 1) < argc))
{
// Seconds before watchdog termination, 0 for unlimited
execTimeout = (unsigned int)atoi(argv[i + 1]);
++i;
}
else if (strncmp(argv[i], "--script-connect", 16) == 0)
{
// Connect to MeshCentral
connectAgent = 1;
if (agentHost->masterDb == NULL)
{
agentHost->masterDb = ILibSimpleDataStore_Create(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".db"));
}
}
else
{
// Unhandled arguments, passed to JavaScript
scriptArgs[sx++] = argv[i];
}
}
else
}
else
{
// Embedded JavaScript
jsFile = agentHost->meshCoreCtx_embeddedScript;
jsFileLen = agentHost->meshCoreCtx_embeddedScriptLen;
scriptArgs = (char**)ILibMemory_Allocate((1 + argc) * sizeof(char*), 0, NULL, NULL);
for (i = 1; i < argc; ++i)
{
// Unhandled arguments, passed to JavaScript
scriptArgs[sx++] = argv[i];
scriptArgs[i] = argv[i];
}
scriptArgs[i] = NULL;
scriptArgs[0] = agentHost->exePath;
}
// Start the JavaScript engine, run the loaded .js file
@@ -2639,8 +2739,11 @@ void MeshAgent_ScriptMode(MeshAgentHostContainer *agentHost, int argc, char **ar
if (ILibDuktape_ScriptContainer_CompileJavaScript(agentHost->meshCoreCtx, jsFile, jsFileLen) != 0 || ILibDuktape_ScriptContainer_ExecuteByteCode(agentHost->meshCoreCtx) != 0)
{
// Error
ILibRemoteLogging_printf(ILibChainGetLogger(agentHost->chain), ILibRemoteLogging_Modules_Microstack_Generic | ILibRemoteLogging_Modules_ConsolePrint, ILibRemoteLogging_Flags_VerbosityLevel_1, "Script Error: %s", duk_safe_to_string(agentHost->meshCoreCtx, -1));
if (strcmp(duk_safe_to_string(agentHost->meshCoreCtx, -1), "Process.exit() forced script termination") != 0)
{
// Error
ILibRemoteLogging_printf(ILibChainGetLogger(agentHost->chain), ILibRemoteLogging_Modules_Microstack_Generic | ILibRemoteLogging_Modules_ConsolePrint, ILibRemoteLogging_Flags_VerbosityLevel_1, "Script Error: %s", duk_safe_to_string(agentHost->meshCoreCtx, -1));
}
duk_pop(agentHost->meshCoreCtx);
}
@@ -2701,22 +2804,25 @@ int MeshAgent_Start(MeshAgentHostContainer *agentHost, int paramLen, char **para
exePath[x] = 0;
#endif
// Perform a self SHA256 Hash
util_sha256file(agentHost->exePath, agentHost->agentHash);
// Perform a self SHA384 Hash
util_sha384file(agentHost->exePath, agentHost->agentHash);
#ifdef _REMOTELOGGINGSERVER
{
int len;
if (agentHost->masterDb == NULL) { agentHost->masterDb = ILibSimpleDataStore_Create(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".db")); }
if (agentHost->masterDb != NULL)
if (agentHost->masterDb == NULL && ILibSimpleDataStore_Exists(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".db")) != 0)
{
if ((len = ILibSimpleDataStore_Get(agentHost->masterDb, "enableILibRemoteLogging", ILibScratchPad, sizeof(ILibScratchPad))) != 0)
agentHost->masterDb = ILibSimpleDataStore_Create(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".db"));
if (agentHost->masterDb != NULL)
{
ILibScratchPad[len] = 0;
ILibStartDefaultLoggerEx(agentHost->chain, (unsigned short)atoi(ILibScratchPad), MeshAgent_MakeAbsolutePath(agentHost->exePath, ".wlg"));
if ((len = ILibSimpleDataStore_Get(agentHost->masterDb, "enableILibRemoteLogging", ILibScratchPad, sizeof(ILibScratchPad))) != 0)
{
ILibScratchPad[len] = 0;
ILibStartDefaultLoggerEx(agentHost->chain, (unsigned short)atoi(ILibScratchPad), MeshAgent_MakeAbsolutePath(agentHost->exePath, ".wlg"));
}
ILibSimpleDataStore_Close(agentHost->masterDb);
agentHost->masterDb = NULL;
}
ILibSimpleDataStore_Close(agentHost->masterDb);
agentHost->masterDb = NULL;
}
}
#endif
@@ -2740,7 +2846,7 @@ int MeshAgent_Start(MeshAgentHostContainer *agentHost, int paramLen, char **para
void *reserved[] = { agentHost, &paramLen, param };
// Check to see if we are running as just a JavaScript Engine
if (paramLen >= 2 && ILibString_EndsWith(param[1], -1, ".js", 3) != 0)
if (agentHost->meshCoreCtx_embeddedScript != NULL || (paramLen >= 2 && ILibString_EndsWith(param[1], -1, ".js", 3) != 0))
{
// We are acting as a scripting engine
ILibChain_RunOnMicrostackThreadEx(agentHost->chain, MeshAgent_ScriptMode_Dispatched, reserved);