From f2bc7d5349871f40ef70f75f7541336a91f1de05 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Sat, 17 Feb 2024 17:51:15 -0800 Subject: [PATCH] More BitLocker improvements. --- agents/meshcore.js | 71 +++++++++++++++++++--------------------- meshagent.js | 17 ++-------- meshuser.js | 6 ++++ views/default.handlebars | 44 +++++++++---------------- 4 files changed, 58 insertions(+), 80 deletions(-) diff --git a/agents/meshcore.js b/agents/meshcore.js index 1aaadb36..96559aa2 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -654,22 +654,6 @@ var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ? // Get the operating system description string try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (ex) { } -// Get Volumes and BitLocker if Windows -try { - if (process.platform == 'win32') { - if (require('computer-identifiers').volumes_promise != null) { - var p = require('computer-identifiers').volumes_promise(); - p.then(function (res) { - meshCoreObj.volumes = res; - meshCoreObjChanged(); - }); - } else if (require('computer-identifiers').volumes != null) { - meshCoreObj.volumes = require('computer-identifiers').volumes(); - meshCoreObjChanged(); - } - } -} catch(e) { } - // Setup logged in user monitoring (THIS IS BROKEN IN WIN7) try { var userSession = require('user-sessions'); @@ -1959,28 +1943,24 @@ function getSystemInformation(func) { results.hardware.network = { dns: require('os').dns() }; replaceSpacesWithUnderscoresRec(results); var hasher = require('SHA384Stream').create(); - // results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); - // func(results); - // On Windows platforms, get volume information - Needs more testing. if (process.platform == 'win32') { results.pendingReboot = require('win-info').pendingReboot(); // Pending reboot - if (require('computer-identifiers').volumes_promise != null) { var p = require('computer-identifiers').volumes_promise(); p.then(function (res) { - results.hardware.windows.volumes = res; + results.hardware.windows.volumes = cleanGetBitLockerVolumeInfo(res); results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); }); } else if (require('computer-identifiers').volumes != null) { - results.hardware.windows.volumes = require('computer-identifiers').volumes(); + results.hardware.windows.volumes = cleanGetBitLockerVolumeInfo(require('computer-identifiers').volumes()); results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); } @@ -3801,7 +3781,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) { if (require('os').dns != null) { availcommands += ',dnsinfo'; } try { require('linux-dhcp'); availcommands += ',dhcp'; } catch (ex) { } if (process.platform == 'win32') { - availcommands += ',cs,wpfhwacceleration,uac,volumes,rdpport'; + availcommands += ',bitlocker,cs,wpfhwacceleration,uac,volumes,rdpport'; if (bcdOK()) { availcommands += ',safemode'; } if (require('notifybar-desktop').DefaultPinned != null) { availcommands += ',privacybar'; } try { require('win-utils'); availcommands += ',taskbar'; } catch (ex) { } @@ -3962,6 +3942,17 @@ function processConsoleCommand(cmd, args, rights, sessionid) { case 'volumes': response = JSON.stringify(require('win-volumes').getVolumes(), null, 1); break; + case 'bitlocker': + if (process.platform == 'win32') { + if (require('computer-identifiers').volumes_promise != null) { + var p = require('computer-identifiers').volumes_promise(); + p.then(function (res) { sendConsoleText(JSON.stringify(cleanGetBitLockerVolumeInfo(res), null, 1), this.session); }); + response = "Please wait..."; + } else if (require('computer-identifiers').volumes != null) { + sendConsoleText(JSON.stringify(cleanGetBitLockerVolumeInfo(require('computer-identifiers').volumes()), null, 1), this.session); + } + } + break; case 'dhcp': // This command is only supported on Linux, this is because Linux does not give us the DNS suffix for each network adapter independently so we have to ask the DHCP server. { try { require('linux-dhcp'); } catch (ex) { response = 'Unknown command "dhcp", type "help" for list of available commands.'; break; } @@ -5702,6 +5693,7 @@ function sendPeriodicServerUpdate(flags, force) { }); } catch (ex) { } } + // Get Defender for Windows Server try { var d = require('win-info').defender(); @@ -5709,20 +5701,7 @@ function sendPeriodicServerUpdate(flags, force) { meshCoreObj.defender = res; meshCoreObjChanged(); }); - } catch (ex){ } - // Get Volumes and BitLocker if Windows - try { - if (require('computer-identifiers').volumes_promise != null){ - var p = require('computer-identifiers').volumes_promise(); - p.then(function (res){ - meshCoreObj.volumes = res; - meshCoreObjChanged(); - }); - }else if (require('computer-identifiers').volumes != null){ - meshCoreObj.volumes = require('computer-identifiers').volumes(); - meshCoreObjChanged(); - } - } catch(e) { } + } catch (ex) { } } // Send available data right now @@ -5736,6 +5715,24 @@ function sendPeriodicServerUpdate(flags, force) { } } +// Sort the names in an object +function sortObject(obj) { return Object.keys(obj).sort().reduce(function(a, v) { a[v] = obj[v]; return a; }, {}); } + +// Fix the incoming data and cut down how much data we use +function cleanGetBitLockerVolumeInfo(volumes) { + for (var i in volumes) { + const v = volumes[i]; + if (typeof v.size == 'string') { v.size = parseInt(v.size); } + if (v.identifier == '') { delete v.identifier; } + if (v.name == '') { delete v.name; } + if (v.removable != true) { delete v.removable; } + if (v.protectionStatus == 'On') { v.protectionStatus = true; } else { delete v.protectionStatus; } + if (v.volumeStatus == 'FullyDecrypted') { delete v.volumeStatus; } + if (v.recoveryPassword == '') { delete v.recoveryPassword; } + } + return sortObject(volumes); +} + // Once we are done collecting all the data, send to server if needed var LastPeriodicServerUpdate = null; var PeriodicServerUpdateNagleTimer = null; diff --git a/meshagent.js b/meshagent.js index e86cac07..53a4ee03 100644 --- a/meshagent.js +++ b/meshagent.js @@ -1940,21 +1940,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { // TODO: Check that the agent has an interface that is the same as the one we got this websocket connection on. Only set if we have a match. } - // Volumes and BitLocker - if (command.volumes != null) { - for (var i in command.volumes) { - // Fix the incoming data and cut down how much data we use - const v = command.volumes[i]; - if (typeof v.size == 'string') { v.size = parseInt(v.size); } - if (v.recoveryPassword == '') { delete v.recoveryPassword; } - if (v.identifier == '') { delete v.identifier; } - if (v.name == '') { delete v.name; } - if (v.removable != true) { delete v.removable; } - if (v.protectionStatus == 'On') { v.protectionStatus = true; } else { delete v.protectionStatus; } - if (v.volumeStatus == "FullyDecrypted") { delete v.volumeStatus; } - } - if (JSON.stringify(device.volumes) != JSON.stringify(command.volumes)) { device.volumes = command.volumes; change = 1; } - } + // Remove old volumes and BitLocker data, this is part of sysinfo. + delete device.volumes; // If there are changes, event the new device if (change == 1) { diff --git a/meshuser.js b/meshuser.js index b06b5b63..184a441f 100644 --- a/meshuser.js +++ b/meshuser.js @@ -6273,6 +6273,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use delete doc.type; delete doc.domain; delete doc._id; + + // If this is not a device group admin users, don't send any BitLocker recovery passwords + if ((rights != MESHRIGHT_ADMIN) && (doc.hardware) && (doc.hardware.windows) && (doc.hardware.windows.volumes)) { + for (var i in doc.hardware.windows.volumes) { delete doc.hardware.windows.volumes[i].recoveryPassword; } + } + if (command.nodeinfo === true) { doc.node = node; doc.rights = rights; } obj.send(doc); } else { diff --git a/views/default.handlebars b/views/default.handlebars index a22ffaef..c9492a66 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -7451,21 +7451,6 @@ x += addDeviceAttribute("Antivirus", y.join('
')); } - /* - // Volumes and Bitlocker - if (node.volumes){ - var bitlocker = []; - for (var i in node.volumes) { - if (typeof node.volumes[i].protectionStatus !== 'undefined' && node.volumes[i].protectionStatus == 'On'){ - bitlocker.push('
' + addKeyLinkConditional(i + ' - ' + EscapeHtml(node.volumes[i].volumeStatus) + '', 'p10showBitlockerKey(\'' + i + '\')', (userinfo.siteadmin == 0xFFFFFFFF)) + '
'); - } else if (typeof node.volumes[i].protectionStatus !== 'undefined') { - bitlocker.push('
' + i + ' - ' + EscapeHtml(node.volumes[i].volumeStatus) + '' + '
'); - } - } - if (bitlocker.length > 0) { x += addDeviceAttribute("BitLocker", bitlocker.join(' ')); } - } - */ - // Active Users if (node.users && node.conn && (node.users.length > 0) && (node.conn & 1)) { x += addDeviceAttribute(((node.users.length > 1)?"Active Users":"Active User"), EscapeHtml(node.users.join(', '))); } @@ -7918,13 +7903,6 @@ } } - function p10showBitlockerKey(drive) { - if (xxdialogMode) return false; - var x = '

' + "Identifier" + '

' + EscapeHtml(currentNode.volumes[drive].identifier ? currentNode.volumes[drive].identifier : "Unknown") + '

'; - x += '

' + "Recovery Password" + '

' + EscapeHtml(currentNode.volumes[drive].recoveryPassword ? currentNode.volumes[drive].recoveryPassword : "Unknown") + '

'; - setDialogMode(2, EscapeHtml(drive) + ': ' + "BitLocker Information", 1, null, x, ''); - } - function p20editDeviceNotify() { if (xxdialogMode) return false; var devNotify = 0, fx = ((features2 & 0x00004000) && (userinfo.emailVerified))?1:0; @@ -12123,24 +12101,27 @@ } // Volumes and Bitlocker - if (node.volumes) { + if (hardware.windows && hardware.windows.volumes) { var x = ''; - for (var i in node.volumes) { - var m = node.volumes[i]; + for (var i in hardware.windows.volumes) { + var m = hardware.windows.volumes[i]; x += '
'; x += '
' + i + ':' + (((m.name == null) || (m.name == '')) ? '' : (' - ' + EscapeHtml(m.name))) + '
'; if (m.size) { var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - var i = parseInt(Math.floor(Math.log(Math.abs(m.size)) / Math.log(1024)), 10); - var fsize = (i === 0 ? `${m.size} ${sizes[i]}` : `${(m.size / (1024 ** i)).toFixed(2)} ${sizes[i]}`); + var j = parseInt(Math.floor(Math.log(Math.abs(m.size)) / Math.log(1024)), 10); + var fsize = (j === 0 ? `${m.size} ${sizes[j]}` : `${(m.size / (1024 ** j)).toFixed(2)} ${sizes[j]}`); x += addDetailItem("Capacity", EscapeHtml(fsize), s); } if (m.type) { x += addDetailItem("File System", (m.removable == true ? ("Removable" + ' / ') : '') + EscapeHtml(m.type), s); } + if (m.protectionStatus || m.volumeStatus) { var bitlockerState = []; if (m.protectionStatus) bitlockerState.push("Enabled"); if (m.volumeStatus) bitlockerState.push(EscapeHtml(m.volumeStatus)); - x += addDetailItem("BitLocker", bitlockerState.join(' - '), s); + bitlockerState = bitlockerState.join(' - '); + if (m.recoveryPassword) { bitlockerState += addKeyLink('', 'deviceDetailsShowBitlockerInfo(\"' + encodeURIComponentEx(i) + '\",\"' + encodeURIComponentEx(m.identifier) + '\",\"' + encodeURIComponentEx(m.recoveryPassword) + '\")'); } + x += addDetailItem("BitLocker", bitlockerState, s); } x += '
'; } @@ -12167,6 +12148,13 @@ } } + function deviceDetailsShowBitlockerInfo(drive, identifier, password) { + if (xxdialogMode) return false; + var x = '

' + "Identifier" + '

' + (identifier ? decodeURIComponent(identifier) : "Unknown") + '

'; + x += '

' + "Recovery Password" + '

' + (password ? decodeURIComponent(password) : "Unknown") + '

'; + setDialogMode(2, decodeURIComponent(drive) + ': ' + "BitLocker Information", 1, null, x, ''); + } + // // CONSOLE //