Access permission and CIRA improvements.

Ylian Saint-Hilaire committed Mar 26, 2018 at 17:13 UTC ca94c192ace74b7d008ed6f6eab449103b7257d0
29 files changed +245 -65
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshagent_arm
Binary files a/agents/meshagent_arm and b/agents/meshagent_arm differ
agents/meshagent_pi
Binary files a/agents/meshagent_pi and b/agents/meshagent_pi differ
agents/meshagent_pogo
Binary files a/agents/meshagent_pogo and b/agents/meshagent_pogo differ
agents/meshagent_poky
Binary files a/agents/meshagent_poky and b/agents/meshagent_poky differ
agents/meshagent_poky64
Binary files a/agents/meshagent_poky64 and b/agents/meshagent_poky64 differ
agents/meshagent_x86
Binary files a/agents/meshagent_x86 and b/agents/meshagent_x86 differ
agents/meshagent_x86-64
Binary files a/agents/meshagent_x86-64 and b/agents/meshagent_x86-64 differ
agents/meshagent_x86-64_nokvm
Binary files a/agents/meshagent_x86-64_nokvm and b/agents/meshagent_x86-64_nokvm differ
agents/meshagent_x86_nokvm
Binary files a/agents/meshagent_x86_nokvm and b/agents/meshagent_x86_nokvm differ
agents/meshcmd.js
+31 -10
@@ -332,6 +332,7 @@ function run(argv) {
332 amtMei.getMACAddresses(function (result) { mestate.mac = result; });
333 amtMei.getLanInterfaceSettings(0, function (result) { mestate.net0 = result; });
334 amtMei.getLanInterfaceSettings(1, function (result) { mestate.net1 = result; });
335 + amtMei.getUuid(function (result) { if ((result != null) && (result.uuid != null)) { mestate.uuid = result.uuid; } });
336 amtMei.getDnsSuffix(function (result) {
337 mestate.dns = result;
338 var str = 'Intel AMT v' + mestate.ver;
@@ -341,7 +342,7 @@ function run(argv) {
342 if (mestate.ehbc.EHBC == true) { str += ', EHBC enabled'; }
343 str += '.';
344 if (mestate.net0 != null) { str += '\r\nWired ' + ((mestate.net0.enabled == 1) ? 'Enabled' : 'Disabled') + ((mestate.net0.dhcpEnabled == 1) ? ', DHCP' : ', Static') + ', ' + mestate.net0.mac + (mestate.net0.address == '0.0.0.0'?'':(', ' + mestate.net0.address)); }
344 - if (mestate.net1 != null) { str += '\r\nWireless ' + ((mestate.net0.enabled == 1) ? 'Enabled' : 'Disabled') + ((mestate.net0.dhcpEnabled == 1) ? ', DHCP' : ', Static') + ', ' + mestate.net0.mac + (mestate.net0.address == '0.0.0.0' ? '' : (', ' + mestate.net0.address)); }
345 + if (mestate.net1 != null) { str += '\r\nWireless ' + ((mestate.net1.enabled == 1) ? 'Enabled' : 'Disabled') + ((mestate.net1.dhcpEnabled == 1) ? ', DHCP' : ', Static') + ', ' + mestate.net1.mac + (mestate.net1.address == '0.0.0.0' ? '' : (', ' + mestate.net1.address)); }
346 console.log(str + '.');
347 exit(1);
348 });
@@ -369,9 +370,10 @@ function run(argv) {
370 startMeScript();
371 } else if (settings.action == 'amtuuid') {
372 // Start running
372 - if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
373 - if ((settings.hostname == null) || (typeof settings.hostname != 'string') || (settings.hostname == '')) { settings.hostname = '127.0.0.1'; }
374 - if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
373 + if (settings.hostname != null) {
374 + if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
375 + if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
376 + }
377 settings.protocol = 'http:';
378 settings.localport = 16992;
379 debug(1, "Settings: " + JSON.stringify(settings));
@@ -573,8 +575,14 @@ function activeToCCMEx3(stack, name, responses, status) {
575
576 // Called to get the UUID of Intel AMT, start by setting up MicroLMS if we are doing the operation on the local computer
577 function getAmtUuid() {
576 - // See if MicroLMS needs to be started
577 - if ((settings.hostname == '127.0.0.1') || (settings.hostname.toLowerCase() == 'localhost')) { settings.noconsole = true; startLms(getAmtUuidEx); } else { getAmtUuidEx() };
578 + if (settings.hostname == null) {
579 + var amtMeiModule = require('amt-mei');
580 + var amtMei = new amtMeiModule();
581 + amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
582 + amtMei.getUuid(function (result) { if ((result == null) || (result.uuid == null)) { console.log('Failed.'); } else { console.log(result.uuid); } exit(1); });
583 + } else {
584 + if ((settings.hostname == '127.0.0.1') || (settings.hostname.toLowerCase() == 'localhost')) { settings.noconsole = true; startLms(getAmtUuidEx); return; } else { getAmtUuidEx(); }
585 + }
586 }
587
588 // Fetch the computer's UUID by fetching the CIM_ComputerSystemPackage WSMAN object.
@@ -677,10 +685,22 @@ function saveEntireAmtStateDone() {
685
686 // Get Intel AMT information using MEI
687 // TODO: If this call is called many time at once, it's going to cause issues.
688 +var getAmtInfoFetching = null;
689 +var getAmtInfoFetchingTimer = null;
690 function getAmtInfo(func, tag) {
681 - //console.log('getAmtInfo1');
691 if (amtMei == null) { if (func != null) { func(null, tag); } return; }
692 + if (getAmtInfoFetching != null) { getAmtInfoFetching.push({ f: func, t: tag }); return; }
693 + getAmtInfoFetching = [{ f: func, t: tag }];
694 amtMeiTmpState = { Flags: 0, TrustedHashes: [] }; // Flags: 1=EHBC, 2=CCM, 4=ACM
695 + getAmtInfoFetchingTimer = setTimeout(function () {
696 + // MEI failed to respond, break out and reset everthing.
697 + for (var i in getAmtInfoFetching) { if (getAmtInfoFetching[i].f != null) { getAmtInfoFetching[i].f(amtMeiTmpState, getAmtInfoFetching[i].t); } }
698 + getAmtInfoFetching = null;
699 + getAmtInfoFetchingTimer = null;
700 + var amtMeiModule = require('amt-mei');
701 + amtMei = new amtMeiModule();
702 + amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
703 + }, 3000);
704 amtMei.getProtocolVersion(function (result) { if (result != null) { amtMeiTmpState.MeiVersion = result; } });
705 amtMei.getVersion(function (val) {
706 amtMeiTmpState.Versions = {};
@@ -699,9 +719,10 @@ function getAmtInfo(func, tag) {
719 amtMeiTmpState.TrustedHashes.push({ Active: result.isActive, Default: result.isDefault, HashAlgorithm: result.hashAlgorithm, Name: result.name, Hash: result.certificateHash });
720 if (--exitOnCount == 0) {
721 amtMeiTmpState.Notifications = lmsNotifications; amtMeiState = amtMeiTmpState;
702 - //console.log('getAmtInfo2', JSON.stringify(amtMeiState));
703 - if (func != null) { func(amtMeiTmpState, tag); }
704 - amtMeiTmpState = null;
722 + for (var i in getAmtInfoFetching) { if (getAmtInfoFetching[i].f != null) { getAmtInfoFetching[i].f(amtMeiTmpState, getAmtInfoFetching[i].t); } }
723 + getAmtInfoFetching = null;
724 + clearTimeout(getAmtInfoFetchingTimer);
725 + getAmtInfoFetchingTimer = null;
726 }
727 });
728 }
agents/meshcore.js
+2
@@ -1178,6 +1178,7 @@ function createMeshCore(agent) {
1178 if (meinfo.ProvisioningState) { intelamt.state = meinfo.ProvisioningState; p = true; }
1179 if (meinfo.flags) { intelamt.flags = meinfo.Flags; p = true; }
1180 if (meinfo.OsHostname) { intelamt.host = meinfo.OsHostname; p = true; }
1181 + if (meinfo.UUID) { intelamt.uuid = meinfo.UUID; p = true; }
1182 if (p == true) { r.intelamt = intelamt }
1183 }
1184 func(r);
@@ -1221,6 +1222,7 @@ function createMeshCore(agent) {
1222 amtMei.getProvisioningState(function (result) { amtMeiTmpState.ProvisioningState = result.state; });
1223 amtMei.getEHBCState(function (result) { if ((result != null) && (result.EHBC == true)) { amtMeiTmpState.Flags += 1; } });
1224 amtMei.getControlMode(function (result) { if (result.controlMode == 1) { amtMeiTmpState.Flags += 2; } if (result.controlMode == 2) { amtMeiTmpState.Flags += 4; } });
1225 + amtMei.getUuid(function (result) { if ((result != null) && (result.uuid != null)) { amtMeiTmpState.UUID = result.uuid; } });
1226 //amtMei.getMACAddresses(function (result) { amtMeiTmpState.mac = result; });
1227 amtMei.getDnsSuffix(function (result) { if (result != null) { amtMeiTmpState.dns = result; } if (func != null) { func(amtMeiTmpState); } });
1228 }
agents/modules_meshcmd/amt-mei.js
+28
@@ -105,6 +105,34 @@ function amt_heci() {
105 }, callback, optional);
106 };
107
108 + // Fill the left with zeros until the string is of a given length
109 + function zeroLeftPad(str, len) {
110 + if ((len == null) && (typeof (len) != 'number')) { return null; }
111 + if (str == null) str = ''; // If null, this is to generate zero leftpad string
112 + var zlp = '';
113 + for (var i = 0; i < len - str.length; i++) { zlp += '0'; }
114 + return zlp + str;
115 + }
116 +
117 + this.getUuid = function getUuid(callback) {
118 + var optional = [];
119 + for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
120 + this.sendCommand(0x5c, null, function (header, fn, opt) {
121 + if (header.Status == 0) {
122 + var result = {};
123 + result.uuid = [zeroLeftPad(header.Data.readUInt32LE(0).toString(16), 8),
124 + zeroLeftPad(header.Data.readUInt16LE(4).toString(16), 4),
125 + zeroLeftPad(header.Data.readUInt16LE(6).toString(16), 4),
126 + zeroLeftPad(header.Data.readUInt16BE(8).toString(16), 4),
127 + zeroLeftPad(header.Data.slice(10).toString('hex').toLowerCase(), 12)].join('-');
128 + opt.unshift(result);
129 + } else {
130 + opt.unshift(null);
131 + }
132 + fn.apply(this, opt);
133 + }, callback, optional);
134 + };
135 +
136 this.getProvisioningState = function getProvisioningState(callback) {
137 var optional = [];
138 for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
agents/modules_meshcore/amt-mei.js
+82 -8
@@ -23,15 +23,18 @@ function amt_heci() {
23
24 this._ObjectID = "pthi";
25 this._rq = new Q();
26 - this._setupPTHI = function _setupPTHI() {
26 + this._setupPTHI = function _setupPTHI()
27 + {
28 this._amt = heci.create();
29 this._amt.BiosVersionLen = 65;
30 this._amt.UnicodeStringLen = 20;
31
32 this._amt.Parent = this;
33 this._amt.on('error', function _amtOnError(e) { this.Parent.emit('error', e); });
33 - this._amt.on('connect', function _amtOnConnect() {
34 - this.on('data', function _amtOnData(chunk) {
34 + this._amt.on('connect', function _amtOnConnect()
35 + {
36 + this.on('data', function _amtOnData(chunk)
37 + {
38 //console.log("Received: " + chunk.length + " bytes");
39 var header = this.Parent.getCommand(chunk);
40 //console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse);
@@ -43,12 +46,14 @@ function amt_heci() {
46 params.unshift(header);
47 callback.apply(this.Parent, params);
48
46 - if (this.Parent._rq.isEmpty()) {
49 + if(this.Parent._rq.isEmpty())
50 + {
51 // No More Requests, we can close PTHI
52 this.Parent._amt.disconnect();
53 this.Parent._amt = null;
54 }
51 - else {
55 + else
56 + {
57 // Send the next request
58 this.write(this.Parent._rq.peekQueue().send);
59 }
@@ -73,9 +78,10 @@ function amt_heci() {
78 var header = Buffer.from('010100000000000000000000', 'hex');
79 header.writeUInt32LE(arguments[0] | 0x04000000, 4);
80 header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8);
76 - this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args, send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]])) });
81 + this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args , send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]]))});
82
78 - if (!this._amt) {
83 + if(!this._amt)
84 + {
85 this._setupPTHI();
86 this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 });
87 }
@@ -87,7 +93,7 @@ function amt_heci() {
93 this.sendCommand(26, null, function (header, fn, opt) {
94 if (header.Status == 0) {
95 var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4);
90 - for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen); ++i) {
96 + for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) {
97 val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() };
98 v = v.slice(4 + (2 * this._amt.UnicodeStringLen));
99 }
@@ -99,6 +105,34 @@ function amt_heci() {
105 }, callback, optional);
106 };
107
108 + // Fill the left with zeros until the string is of a given length
109 + function zeroLeftPad(str, len) {
110 + if ((len == null) && (typeof (len) != 'number')) { return null; }
111 + if (str == null) str = ''; // If null, this is to generate zero leftpad string
112 + var zlp = '';
113 + for (var i = 0; i < len - str.length; i++) { zlp += '0'; }
114 + return zlp + str;
115 + }
116 +
117 + this.getUuid = function getUuid(callback) {
118 + var optional = [];
119 + for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
120 + this.sendCommand(0x5c, null, function (header, fn, opt) {
121 + if (header.Status == 0) {
122 + var result = {};
123 + result.uuid = [zeroLeftPad(header.Data.readUInt32LE(0).toString(16), 8),
124 + zeroLeftPad(header.Data.readUInt16LE(4).toString(16), 4),
125 + zeroLeftPad(header.Data.readUInt16LE(6).toString(16), 4),
126 + zeroLeftPad(header.Data.readUInt16BE(8).toString(16), 4),
127 + zeroLeftPad(header.Data.slice(10).toString('hex').toLowerCase(), 12)].join('-');
128 + opt.unshift(result);
129 + } else {
130 + opt.unshift(null);
131 + }
132 + fn.apply(this, opt);
133 + }, callback, optional);
134 + };
135 +
136 this.getProvisioningState = function getProvisioningState(callback) {
137 var optional = [];
138 for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
@@ -248,6 +282,46 @@ function amt_heci() {
282 fn.apply(this, opt);
283 }, callback, optional);
284 }
285 + this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback)
286 + {
287 + var optional = [];
288 + for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
289 + var ifx = Buffer.alloc(4);
290 + ifx.writeUInt32LE(index);
291 + this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt)
292 + {
293 + if(header.Status == 0)
294 + {
295 + var info = {};
296 + info.enabled = header.Data.readUInt32LE(0);
297 + info.dhcpEnabled = header.Data.readUInt32LE(8);
298 + switch(header.Data[12])
299 + {
300 + case 1:
301 + info.dhcpMode = 'ACTIVE'
302 + break;
303 + case 2:
304 + info.dhcpMode = 'PASSIVE'
305 + break;
306 + default:
307 + info.dhcpMode = 'UNKNOWN';
308 + break;
309 + }
310 + info.mac = header.Data.slice(14).toString('hex:');
311 +
312 + var addr = header.Data.readUInt32LE(4);
313 + info.address = ((addr >> 24) & 255) + '.' + ((addr >> 16) & 255) + '.' + ((addr >> 8) & 255) + '.' + (addr & 255);
314 + opt.unshift(info);
315 + fn.apply(this, opt);
316 + }
317 + else
318 + {
319 + opt.unshift(null);
320 + fn.apply(this, opt);
321 + }
322 + }, callback, optional);
323 +
324 + };
325 this.unprovision = function unprovision(mode, callback) {
326 var optional = [];
327 for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
db.js
+1
@@ -107,6 +107,7 @@ module.exports.CreateDB = function (args, datapath) {
107 obj.clearOldEntries = function (type, days, domain) { var cutoff = Date.now() - (1000 * 60 * 60 * 24 * days); obj.file.remove({ type: type, time: { $lt: cutoff } }, { multi: true }); }
108 obj.getPowerTimeline = function (nodeid, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'power', node: { $in: ['*', nodeid] } }).sort({ time: 1 }).exec(func); } else { obj.file.find({ type: 'power', node: { $in: ['*', nodeid] } }).sort({ time: 1 }, func); } }
109 obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); }
110 + obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); }
111
112 // This is used to rate limit a number of operation per day. Returns a startValue each new days, but you can substract it and save the value in the db.
113 obj.getValueOfTheDay = function (id, startValue, func) { obj.Get(id, function (err, docs) { var date = new Date(), t = date.toLocaleDateString(); if (docs.length == 1) { var r = docs[0]; if (r.day == t) { func({ _id: id, value: r.value, day: t }); return; } } func({ _id: id, value: startValue, day: t }); }); }
meshagent.js
+1
@@ -549,6 +549,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
549 if (device.intelamt.state != command.intelamt.state) { device.intelamt.state = command.intelamt.state; change = 1; changes.push('AMT state'); }
550 if (device.intelamt.flags != command.intelamt.flags) { device.intelamt.flags = command.intelamt.flags; change = 1; changes.push('AMT flags'); }
551 if (device.intelamt.host != command.intelamt.host) { device.intelamt.host = command.intelamt.host; change = 1; changes.push('AMT host'); }
552 + if (device.intelamt.uuid != command.intelamt.uuid) { device.intelamt.uuid = command.intelamt.uuid; change = 1; changes.push('AMT uuid'); }
553 }
554 if (mesh.mtype == 2) {
555 if (device.host != obj.remoteaddr) { device.host = obj.remoteaddr; change = 1; changes.push('host'); }
meshcentral.js
+1
@@ -227,6 +227,7 @@ function CreateMeshCentralServer(config, args) {
227 //if (obj.servicelog != null) { var s = ''; for (var i in obj.args) { if (i != '_') { if (s.length > 0) { s += ', '; } s += i + "=" + obj.args[i]; } } logInfoEvent('MeshServer started with arguments: ' + s); }
228
229 // Look at passed in arguments
230 + if ((obj.args.user != null) && (typeof obj.args.user != 'string')) { delete obj.args.user; }
231 if ((obj.args.ciralocalfqdn != null) && ((obj.args.lanonly == true) || (obj.args.wanonly == true))) { console.log("WARNING: CIRA local FQDN's ignored when server in LAN-only or WAN-only mode."); }
232 if ((obj.args.ciralocalfqdn != null) && (obj.args.ciralocalfqdn.split(',').length > 4)) { console.log("WARNING: Can't have more than 4 CIRA local FQDN's. Ignoring value."); obj.args.ciralocalfqdn = null; }
233 if (obj.args.port == null || typeof obj.args.port != 'number') { if (obj.args.notls == null) { obj.args.port = 443; } else { obj.args.port = 80; } }
meshrelay.js
+1 -1
@@ -69,7 +69,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
69 obj.parent.authenticate(req.query.user, req.query.pass, obj.domain, function (err, userid, passhint) {
70 if (userid != null) {
71 obj.authenticated = true;
72 - // Check is we have agent routing instructions, process this here.
72 + // Check if we have agent routing instructions, process this here.
73 if ((req.query.nodeid != null) && (req.query.tcpport != null)) {
74 if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
75 var command = { nodeid: req.query.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: req.query.tcpport, tcpaddr: ((req.query.tcpaddr == null) ? '127.0.0.1' : req.query.tcpaddr) };
meshuser.js
+3 -3
@@ -167,7 +167,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
167 case 'files':
168 {
169 // Send the full list of server files to the browser app
170 - if ((user.siteadmin & 8) != 0) { updateUserFiles(user, ws, domain); }
170 + if ((user != null) && (user.siteadmin != null) && (user.siteadmin & 8) != 0) { updateUserFiles(user, ws, domain); }
171 break;
172 }
173 case 'fileoperation':
@@ -205,7 +205,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
205 if (agent != null) {
206 // Check if we have permission to send a message to that node
207 var rights = user.links[agent.dbMeshKey];
208 - if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
208 + if ((rights != null) && ((rights.rights & 8) != 0)) { // 8 is remote control permission
209 command.sessionid = ws.sessionId; // Set the session id, required for responses.
210 command.rights = rights.rights; // Add user rights flags to the message
211 delete command.nodeid; // Remove the nodeid since it's implyed.
@@ -217,7 +217,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
217 if (routing != null) {
218 // Check if we have permission to send a message to that node
219 var rights = user.links[routing.meshid];
220 - if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
220 + if ((rights != null) && ((rights.rights & 8) != 0)) { // 8 is remote control permission
221 command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
222 command.rights = rights.rights; // Add user rights flags to the message
223 obj.parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
mpsserver.js
+61 -30
@@ -227,44 +227,75 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
227 obj.db.GetAllType('mesh', function (err, docs) {
228 var mesh = null;
229 for (var i in docs) { if (docs[i]._id.indexOf(meshIdStart) > 0) { mesh = docs[i]; break; } }
230 - if (mesh == null) { Debug(1, 'MPS:Mesh not found', username, password);SendUserAuthFail(socket); return -1; }
231 -
232 - // Intel AMT GUID (socket.tag.SystemId) will be used at NodeID
233 - var systemid = socket.tag.SystemId.split('-').join('');
234 - var nodeid = new Buffer(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
235 - socket.tag.name = '';
236 - socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
237 - socket.tag.meshid = mesh._id;
238 -
239 - obj.db.Get(socket.tag.nodeid, function (err, nodes) {
240 - if (nodes.length == 0) {
241 - if (mesh.mtype == 1) {
242 - // Node is not in the database, add it. Credentials will be empty until added by the user.
243 - var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0 } };
244 - obj.db.Set(device);
245 -
246 - // Event the new node
247 - var device2 = common.Clone(device);
248 - if (device2.intelamt.pass != undefined) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
249 - var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
250 - obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain })
230 + if (mesh == null) { Debug(1, 'MPS:Mesh not found', username, password); SendUserAuthFail(socket); return -1; }
231 +
232 + // If this is a agent-less mesh, use the device guid 3 times as ID.
233 + if (mesh.mtype == 1) {
234 + // Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
235 + var systemid = socket.tag.SystemId.split('-').join('');
236 + var nodeid = new Buffer(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
237 + socket.tag.name = '';
238 + socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
239 + socket.tag.meshid = mesh._id;
240 + socket.tag.connectTime = Date.now();
241 +
242 + obj.db.Get(socket.tag.nodeid, function (err, nodes) {
243 + if (nodes.length == 0) {
244 + if (mesh.mtype == 1) {
245 + // Node is not in the database, add it. Credentials will be empty until added by the user.
246 + var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0 } };
247 + obj.db.Set(device);
248 +
249 + // Event the new node
250 + var device2 = common.Clone(device);
251 + if (device2.intelamt.pass != undefined) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
252 + var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
253 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain })
254 + } else {
255 + // New CIRA connection for unknown node, disconnect.
256 + console.log('CIRA connection for unknown node with incorrect mesh type. meshid: ' + socket.tag.meshid);
257 + socket.end();
258 + return;
259 + }
260 } else {
261 + // Node is already present
262 + var node = nodes[0];
263 + if (node.intelamt != undefined) { socket.tag.host = node.intelamt.host; }
264 + }
265 +
266 + // Add the connection to the MPS connection list
267 + obj.ciraConnections[socket.tag.nodeid] = socket;
268 + obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
269 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
270 + });
271 + } else if (mesh.mtype == 2) { // If this is a agent mesh, search the mesh for this device UUID
272 + // Intel AMT GUID (socket.tag.SystemId) will be used to search the node
273 + obj.db.getAmtUuidNode(mesh._id, socket.tag.SystemId, function (err, nodes) {
274 + if (nodes.length == 0) {
275 // New CIRA connection for unknown node, disconnect.
253 - console.log('CIRA connection for unknown node with incorrect mesh type. meshid: ' + socket.tag.meshid);
276 + console.log('CIRA connection for unknown node. meshid: ' + mesh._id + ', uuid: ' + systemid);
277 socket.end();
278 return;
279 }
257 - } else {
258 - // Node is already present
280 +
281 + // Node is present
282 var node = nodes[0];
283 if (node.intelamt != undefined) { socket.tag.host = node.intelamt.host; }
261 - }
284 + socket.tag.nodeid = node._id;
285 + socket.tag.meshid = mesh._id;
286 + socket.tag.connectTime = Date.now();
287
263 - // Add the connection to the MPS connection list
264 - obj.ciraConnections[socket.tag.nodeid] = socket;
265 - obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
266 - SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
267 - });
288 + // Add the connection to the MPS connection list
289 + obj.ciraConnections[socket.tag.nodeid] = socket;
290 + obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
291 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
292 + });
293 + } else { // Unknown mesh type
294 + // New CIRA connection for unknown node, disconnect.
295 + console.log('CIRA connection to a unknown mesh type. meshid: ' + socket.tag.meshid);
296 + socket.end();
297 + return;
298 + }
299 });
300 return 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen;
301 }
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.1.5-e",
3 + "version": "0.1.5-k",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/scripts/agent-desktop-0.0.2.js
+1 -1
@@ -159,7 +159,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
159 }
160
161 obj.ProcessScreenMsg = function (width, height) {
162 - //obj.Debug("ProcessScreenMsg: " + width + " x " + height);
162 + obj.Debug("ScreenSize: " + width + " x " + height);
163 obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
164 obj.rotation = 0;
165 obj.FirstDraw = true;
views/default.handlebars
+16 -11
@@ -1468,10 +1468,10 @@
1468 function getMeshActions(mesh, meshrights) {
1469 if ((meshrights & 4) == 0) return '';
1470 var r = '';
1471 + if ((features & 2) == 0) { // If not LAN-Only
1472 + r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer that is located on the internet." onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
1473 + }
1474 if (mesh.mtype == 1) {
1472 - if ((features & 2) == 0) { // If not LAN-Only
1473 - r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer that is located on the internet." onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
1474 - }
1475 if ((features & 1) == 0) { // If not WAN-Only
1476 r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer that is located on the local network." onclick=addDeviceToMesh(\"' + mesh._id + '\")>Add Local</a>';
1477 r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer by scanning the local network." onclick=addAmtScanToMesh(\"' + mesh._id + '\")>Scan Network</a>';
@@ -2580,7 +2580,7 @@
2580 if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showNodeNetInfoDialog("' + node._id + '") title="Show device network interface information">Interfaces</a>&nbsp;';
2581 if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '") title="Show device locations information">Location</a>&nbsp;';
2582
2583 - if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showMeshCmdDialog(1,"' + node._id + '") title="Traffic router used to connect to a device thru this server.">Router</a>&nbsp;';
2583 + if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += '<a style=cursor:pointer onclick=p10showMeshCmdDialog(1,"' + node._id + '") title="Traffic router used to connect to a device thru this server.">Router</a>&nbsp;';
2584
2585 // RDP link, show this link only of the remote machine is Windows.
2586 if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
@@ -2616,11 +2616,11 @@
2616 // Show or hide the tabs
2617 // mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
2618 // node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
2619 - QV('MainDevDesktop', (mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0));
2620 - QV('MainDevTerminal', (mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0));
2621 - QV('MainDevFiles', (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0)));
2622 - QV('MainDevAmt', node.intelamt != null);
2623 - QV('MainDevConsole', consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0)));
2619 + QV('MainDevDesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0)) && (meshrights & 8));
2620 + QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0)) && (meshrights & 8));
2621 + QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8));
2622 + QV('MainDevAmt', (node.intelamt != null) && (meshrights & 8));
2623 + QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
2624 QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0) && (userinfo.siteadmin == 0xFFFFFFFF));
2625 QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
2626
@@ -4041,8 +4041,12 @@
4041 c++;
4042 count++;
4043
4044 - // Mesh
4045 - var rights = 'Administrator'; // TODO
4044 + // Mesh rights
4045 + var meshrights = meshes[i].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
4046 + var rights = 'Partial Rights';
4047 + if (meshrights == 0xFFFFFFFF) rights = 'Full Administrator'; else if (meshrights == 0) rights = 'No Rights';
4048 +
4049 + // Print the mesh information
4050 r += '<div style=display:inline-block;width:431px;height:50px;padding-top:1px;padding-bottom:1px;float:left><div style=float:left;width:30px;height:100%></div><div style=height:100%;cursor:pointer onclick=gotoMesh(\'' + i + '\')><div class=mi style=float:left;width:50px;height:50px></div><div style=height:100%><div class=g1></div><div class=e2 style=width:300px><div class=e1>' + EscapeHtml(meshes[i].name) + '</div><div>' + rights + '</div></div><div class=g2 style=float:left></div></div></div></div>';
4051 }
4052
@@ -4247,6 +4251,7 @@
4251 if ((meshrights & 64) != 0) r += ', Wake Devices';
4252 }
4253 r = r.substring(2);
4254 + if (r == '') { r = 'No Rights'; }
4255 var x = addHtmlValue('User Name', userid.split('/')[2]);
4256 x += addHtmlValue('Permissions', r);
4257 var buttons = 1;
webserver.js
+16
@@ -537,6 +537,22 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
537 obj.authenticate(user.name, req.body.apassword1, domain, function (err, userid) {
538 var user = obj.users[userid];
539 if (user) {
540 + // Remove all the mesh links to this user
541 + if (user.links != null) {
542 + for (var meshid in user.links) {
543 + // Get the mesh
544 + var mesh = obj.meshes[meshid];
545 + if (mesh) {
546 + // Remove user from the mesh
547 + if (mesh.links[userid] != null) { delete mesh.links[userid]; obj.db.Set(mesh); }
548 + // Notify mesh change
549 + var change = 'Removed user ' + user.name + ' from mesh ' + mesh.name;
550 + obj.parent.DispatchEvent(['*', mesh._id, user._id, userid], obj, { etype: 'mesh', username: user.name, userid: userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id })
551 + }
552 + }
553 + }
554 +
555 + // Remove the user
556 obj.db.Remove(user._id);
557 delete obj.users[user._id];
558 req.session.destroy(function () { res.redirect(domain.url); });