| 1 | /* |
| 2 | Copyright 2018-2021 Intel Corporation |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | var Q = require('queue'); |
| 18 | var g_internal = null; |
| 19 | |
| 20 | function retry_pthi_later() |
| 21 | { |
| 22 | if (++g_internal.errorCount < 20) |
| 23 | { |
| 24 | g_internal.timeout = setTimeout(function (p) |
| 25 | { |
| 26 | p.connect(require('heci').GUIDS.AMT, { noPipeline: 1 }); |
| 27 | }, 250, this); |
| 28 | } |
| 29 | else |
| 30 | { |
| 31 | this.Parent.emit('error', 'PTHI Connection could not be established'); |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | function amt_heci() |
| 36 | { |
| 37 | var emitterUtils = require('events').inherits(this); |
| 38 | emitterUtils.createEvent('error'); |
| 39 | |
| 40 | var heci = require('heci'); |
| 41 | var sendConsole = function (msg) { try { require('MeshAgent').SendCommand({ "action": "msg", "type": "console", "value": msg }); } catch (ex) { } } |
| 42 | |
| 43 | this._ObjectID = "pthi"; |
| 44 | var that = this; |
| 45 | if (g_internal == null) |
| 46 | { |
| 47 | g_internal = { _rq: new Q(), _amt: null, errorCount: 0 }; |
| 48 | g_internal._setupPTHI = function _g_setupPTHI() |
| 49 | { |
| 50 | console.info1('setupPTHI()'); |
| 51 | this._amt = heci.create(); |
| 52 | this._amt.descriptorMetadata = "amt-pthi"; |
| 53 | this._amt.BiosVersionLen = 65; |
| 54 | this._amt.UnicodeStringLen = 20; |
| 55 | this._amt.Parent = that; |
| 56 | |
| 57 | this._amt.on('error', function _amtOnError(e) |
| 58 | { |
| 59 | console.info1('PTHIError: ' + e); |
| 60 | if (g_internal._rq.isEmpty()) |
| 61 | { |
| 62 | console.info1(' Queue is empty'); |
| 63 | this.Parent.emit('error', e); // No pending requests, so propagate the error up |
| 64 | } |
| 65 | else |
| 66 | { |
| 67 | console.info1(' Queue is NOT empty'); |
| 68 | |
| 69 | // Try again |
| 70 | retry_pthi_later.call(this); |
| 71 | } |
| 72 | }); |
| 73 | this._amt.on('connect', function _amtOnConnect() |
| 74 | { |
| 75 | g_internal.errorCount = 0; |
| 76 | this.on('data', function _amtOnData(chunk) |
| 77 | { |
| 78 | //console.log("Received: " + chunk.length + " bytes"); |
| 79 | var header = this.Parent.getCommand(chunk); |
| 80 | console.info1("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse); |
| 81 | |
| 82 | var user = g_internal._rq.deQueue(); |
| 83 | var params = user.optional; |
| 84 | var callback = user.func; |
| 85 | |
| 86 | params.unshift(header); |
| 87 | callback.apply(this.Parent, params); |
| 88 | |
| 89 | if (g_internal._rq.isEmpty()) |
| 90 | { |
| 91 | console.info1('No more requests, disconnecting'); |
| 92 | |
| 93 | // No More Requests, we can close PTHI |
| 94 | g_internal._amt.disconnect(); |
| 95 | g_internal._amt = null; |
| 96 | } |
| 97 | else |
| 98 | { |
| 99 | // Send the next request |
| 100 | console.info1('Sending Next Request'); |
| 101 | this.write(g_internal._rq.peekQueue().send); |
| 102 | } |
| 103 | }); |
| 104 | |
| 105 | // Start sending requests |
| 106 | this.write(g_internal._rq.peekQueue().send); |
| 107 | }); |
| 108 | |
| 109 | |
| 110 | |
| 111 | }; |
| 112 | } |
| 113 | |
| 114 | |
| 115 | function trim(x) { var y = x.indexOf('\0'); if (y >= 0) { return x.substring(0, y); } else { return x; } } |
| 116 | this.getCommand = function getCommand(chunk) { |
| 117 | var command = chunk.length == 0 ? (g_internal._rq.peekQueue().cmd | 0x800000) : chunk.readUInt32LE(4); |
| 118 | var ret = { IsResponse: (command & 0x800000) == 0x800000 ? true : false, Command: (command & 0x7FFFFF), Status: chunk.length != 0 ? chunk.readUInt32LE(12) : -1, Data: chunk.length != 0 ? chunk.slice(16) : null }; |
| 119 | return (ret); |
| 120 | }; |
| 121 | |
| 122 | this.sendCommand = function sendCommand() |
| 123 | { |
| 124 | if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); } |
| 125 | var args = []; |
| 126 | for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); } |
| 127 | |
| 128 | console.info1('sendCommand(' + arguments[0] + ')', this._hashCode()); |
| 129 | |
| 130 | var header = Buffer.from('010100000000000000000000', 'hex'); |
| 131 | header.writeUInt32LE(arguments[0] | 0x04000000, 4); |
| 132 | header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8); |
| 133 | |
| 134 | g_internal._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args, send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]])) }); |
| 135 | if (!g_internal._amt) |
| 136 | { |
| 137 | g_internal._setupPTHI(); |
| 138 | g_internal._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 }); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | this.getVersion = function getVersion(callback) { |
| 143 | var optional = []; |
| 144 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 145 | this.sendCommand(26, null, function (header, fn, opt) { |
| 146 | if (header.Status == 0) { |
| 147 | var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, g_internal._amt.BiosVersionLen).toString(), Versions: [] }, v = CodeVersion.slice(g_internal._amt.BiosVersionLen + 4); |
| 148 | for (i = 0; i < CodeVersion.readUInt32LE(g_internal._amt.BiosVersionLen) ; ++i) |
| 149 | { |
| 150 | val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + g_internal._amt.UnicodeStringLen, 4 + g_internal._amt.UnicodeStringLen + v.readUInt16LE(2 + g_internal._amt.UnicodeStringLen)).toString() }; |
| 151 | v = v.slice(4 + (2 * g_internal._amt.UnicodeStringLen)); |
| 152 | } |
| 153 | if (val.BiosVersion.indexOf('\0') > 0) { val.BiosVersion = val.BiosVersion.substring(0, val.BiosVersion.indexOf('\0')); } |
| 154 | opt.unshift(val); |
| 155 | } else { |
| 156 | opt.unshift(null); |
| 157 | } |
| 158 | fn.apply(this, opt); |
| 159 | }, callback, optional); |
| 160 | }; |
| 161 | |
| 162 | // Fill the left with zeros until the string is of a given length |
| 163 | function zeroLeftPad(str, len) { |
| 164 | if ((len == null) && (typeof (len) != 'number')) { return null; } |
| 165 | if (str == null) str = ''; // If null, this is to generate zero leftpad string |
| 166 | var zlp = ''; |
| 167 | for (var i = 0; i < len - str.length; i++) { zlp += '0'; } |
| 168 | return zlp + str; |
| 169 | } |
| 170 | |
| 171 | this.getUuid = function getUuid(callback) { |
| 172 | var optional = []; |
| 173 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 174 | this.sendCommand(0x5c, null, function (header, fn, opt) { |
| 175 | if (header.Status == 0) { |
| 176 | var result = {}; |
| 177 | result.uuid = [zeroLeftPad(header.Data.readUInt32LE(0).toString(16), 8), |
| 178 | zeroLeftPad(header.Data.readUInt16LE(4).toString(16), 4), |
| 179 | zeroLeftPad(header.Data.readUInt16LE(6).toString(16), 4), |
| 180 | zeroLeftPad(header.Data.readUInt16BE(8).toString(16), 4), |
| 181 | zeroLeftPad(header.Data.slice(10).toString('hex').toLowerCase(), 12)].join('-'); |
| 182 | opt.unshift(result); |
| 183 | } else { |
| 184 | opt.unshift(null); |
| 185 | } |
| 186 | fn.apply(this, opt); |
| 187 | }, callback, optional); |
| 188 | }; |
| 189 | |
| 190 | this.getProvisioningState = function getProvisioningState(callback) { |
| 191 | var optional = []; |
| 192 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 193 | this.sendCommand(17, null, function (header, fn, opt) { |
| 194 | if (header.Status == 0) { |
| 195 | var result = {}; |
| 196 | result.state = header.Data.readUInt32LE(0); |
| 197 | if (result.state < 3) { result.stateStr = ["PRE", "IN", "POST"][result.state]; } |
| 198 | opt.unshift(result); |
| 199 | } else { |
| 200 | opt.unshift(null); |
| 201 | } |
| 202 | fn.apply(this, opt); |
| 203 | }, callback, optional); |
| 204 | }; |
| 205 | this.getProvisioningMode = function getProvisioningMode(callback) { |
| 206 | var optional = []; |
| 207 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 208 | this.sendCommand(8, null, function (header, fn, opt) { |
| 209 | if (header.Status == 0) { |
| 210 | var result = {}; |
| 211 | result.mode = header.Data.readUInt32LE(0); |
| 212 | if (result.mode < 4) { result.modeStr = ["NONE", "ENTERPRISE", "SMALL_BUSINESS", "REMOTE_ASSISTANCE"][result.mode]; } |
| 213 | result.legacy = header.Data.readUInt32LE(4) == 0 ? false : true; |
| 214 | opt.unshift(result); |
| 215 | } else { |
| 216 | opt.unshift(null); |
| 217 | } |
| 218 | fn.apply(this, opt); |
| 219 | }, callback, optional); |
| 220 | }; |
| 221 | this.getEHBCState = function getEHBCState(callback) { |
| 222 | var optional = []; |
| 223 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 224 | this.sendCommand(132, null, function (header, fn, opt) { |
| 225 | if (header.Status == 0) { |
| 226 | opt.unshift({ EHBC: header.Data.readUInt32LE(0) != 0 }); |
| 227 | } else { |
| 228 | opt.unshift(null); |
| 229 | } |
| 230 | fn.apply(this, opt); |
| 231 | }, callback, optional); |
| 232 | }; |
| 233 | this.getControlMode = function getControlMode(callback) { |
| 234 | var optional = []; |
| 235 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 236 | this.sendCommand(107, null, function (header, fn, opt) { |
| 237 | if (header.Status == 0) { |
| 238 | var result = {}; |
| 239 | result.controlMode = header.Data.readUInt32LE(0); |
| 240 | if (result.controlMode < 3) { result.controlModeStr = ["NONE_RPAT", "CLIENT", "ADMIN", "REMOTE_ASSISTANCE"][result.controlMode]; } |
| 241 | opt.unshift(result); |
| 242 | } else { |
| 243 | opt.unshift(null); |
| 244 | } |
| 245 | fn.apply(this, opt); |
| 246 | }, callback, optional); |
| 247 | }; |
| 248 | this.getMACAddresses = function getMACAddresses(callback) { |
| 249 | var optional = []; |
| 250 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 251 | this.sendCommand(37, null, function (header, fn, opt) { |
| 252 | if (header.Status == 0) { |
| 253 | opt.unshift({ DedicatedMAC: header.Data.slice(0, 6).toString('hex:'), HostMAC: header.Data.slice(6, 12).toString('hex:') }); |
| 254 | } else { opt.unshift({ DedicatedMAC: null, HostMAC: null }); } |
| 255 | fn.apply(this, opt); |
| 256 | }, callback, optional); |
| 257 | }; |
| 258 | this.getDnsSuffix = function getDnsSuffix(callback) { |
| 259 | var optional = []; |
| 260 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 261 | this.sendCommand(54, null, function (header, fn, opt) { |
| 262 | if (header.Status == 0) { |
| 263 | var resultLen = header.Data.readUInt16LE(0); |
| 264 | if (resultLen > 0) { opt.unshift(header.Data.slice(2, 2 + resultLen).toString()); } else { opt.unshift(null); } |
| 265 | } else { |
| 266 | opt.unshift(null); |
| 267 | } |
| 268 | fn.apply(this, opt); |
| 269 | }, callback, optional); |
| 270 | }; |
| 271 | this.getHashHandles = function getHashHandles(callback) { |
| 272 | var optional = []; |
| 273 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 274 | this.sendCommand(0x2C, null, function (header, fn, opt) { |
| 275 | var result = []; |
| 276 | if (header.Status == 0) { |
| 277 | var resultLen = header.Data.readUInt32LE(0); |
| 278 | for (var i = 0; i < resultLen; ++i) { |
| 279 | result.push(header.Data.readUInt32LE(4 + (4 * i))); |
| 280 | } |
| 281 | } |
| 282 | opt.unshift(result); |
| 283 | fn.apply(this, opt); |
| 284 | }, callback, optional); |
| 285 | }; |
| 286 | this.getCertHashEntry = function getCertHashEntry(handle, callback) { |
| 287 | var optional = []; |
| 288 | for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 289 | |
| 290 | var data = Buffer.alloc(4); |
| 291 | data.writeUInt32LE(handle, 0); |
| 292 | |
| 293 | this.sendCommand(0x2D, data, function (header, fn, opt) { |
| 294 | if (header.Status == 0) { |
| 295 | var result = {}; |
| 296 | result.isDefault = header.Data.readUInt32LE(0); |
| 297 | result.isActive = header.Data.readUInt32LE(4); |
| 298 | result.hashAlgorithm = header.Data.readUInt8(72); |
| 299 | if (result.hashAlgorithm < 4) { |
| 300 | result.hashAlgorithmStr = ["MD5", "SHA1", "SHA256", "SHA512"][result.hashAlgorithm]; |
| 301 | result.hashAlgorithmSize = [16, 20, 32, 64][result.hashAlgorithm]; |
| 302 | result.certificateHash = header.Data.slice(8, 8 + result.hashAlgorithmSize).toString('hex'); |
| 303 | } |
| 304 | result.name = header.Data.slice(73 + 2, 73 + 2 + header.Data.readUInt16LE(73)).toString(); |
| 305 | opt.unshift(result); |
| 306 | } else { |
| 307 | opt.unshift(null); |
| 308 | } |
| 309 | fn.apply(this, opt); |
| 310 | }, callback, optional); |
| 311 | }; |
| 312 | this.getCertHashEntries = function getCertHashEntries(callback) { |
| 313 | var optional = []; |
| 314 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 315 | |
| 316 | this.getHashHandles(function (handles, fn, opt) { |
| 317 | var entries = []; |
| 318 | this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles); |
| 319 | }, callback, optional); |
| 320 | }; |
| 321 | |
| 322 | this._getHashEntrySink = function _getHashEntrySink(result, fn, opt, entries, handles) { |
| 323 | entries.push(result); |
| 324 | if (handles.length > 0) { |
| 325 | this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles); |
| 326 | } else { |
| 327 | opt.unshift(entries); |
| 328 | fn.apply(this, opt); |
| 329 | } |
| 330 | } |
| 331 | this.getLocalSystemAccount = function getLocalSystemAccount(callback) { |
| 332 | var optional = []; |
| 333 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 334 | this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) { |
| 335 | if (header.Status == 0 && header.Data.length == 68) { |
| 336 | opt.unshift({ user: trim(header.Data.slice(0, 33).toString()), pass: trim(header.Data.slice(33, 67).toString()), raw: header.Data }); |
| 337 | } |
| 338 | else { |
| 339 | opt.unshift(null); |
| 340 | } |
| 341 | fn.apply(this, opt); |
| 342 | }, callback, optional); |
| 343 | } |
| 344 | this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback) { |
| 345 | var optional = []; |
| 346 | for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 347 | var ifx = Buffer.alloc(4); |
| 348 | ifx.writeUInt32LE(index); |
| 349 | this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt) { |
| 350 | if (header.Status == 0) { |
| 351 | var info = {}; |
| 352 | info.enabled = header.Data.readUInt32LE(0); |
| 353 | info.dhcpEnabled = header.Data.readUInt32LE(8); |
| 354 | switch (header.Data[12]) { |
| 355 | case 1: |
| 356 | info.dhcpMode = 'ACTIVE' |
| 357 | break; |
| 358 | case 2: |
| 359 | info.dhcpMode = 'PASSIVE' |
| 360 | break; |
| 361 | default: |
| 362 | info.dhcpMode = 'UNKNOWN'; |
| 363 | break; |
| 364 | } |
| 365 | info.mac = header.Data.slice(14).toString('hex:'); |
| 366 | |
| 367 | var addr = header.Data.readUInt32LE(4); |
| 368 | info.address = ((addr >> 24) & 255) + '.' + ((addr >> 16) & 255) + '.' + ((addr >> 8) & 255) + '.' + (addr & 255); |
| 369 | opt.unshift(info); |
| 370 | fn.apply(this, opt); |
| 371 | } |
| 372 | else { |
| 373 | opt.unshift(null); |
| 374 | fn.apply(this, opt); |
| 375 | } |
| 376 | }, callback, optional); |
| 377 | |
| 378 | }; |
| 379 | this.unprovision = function unprovision(mode, callback) { |
| 380 | var optional = []; |
| 381 | for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 382 | var data = Buffer.alloc(4); |
| 383 | data.writeUInt32LE(mode, 0); |
| 384 | this.sendCommand(16, data, function (header, fn, opt) { |
| 385 | opt.unshift(header.Status); |
| 386 | fn.apply(this, opt); |
| 387 | }, callback, optional); |
| 388 | } |
| 389 | this.startConfiguration = function startConfiguration(callback) { |
| 390 | var optional = []; |
| 391 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 392 | this.sendCommand(0x29, null, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional); |
| 393 | } |
| 394 | this.stopConfiguration = function stopConfiguration(callback) { |
| 395 | var optional = []; |
| 396 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 397 | this.sendCommand(0x5E, null, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional); |
| 398 | } |
| 399 | this.openUserInitiatedConnection = function openUserInitiatedConnection(callback) { |
| 400 | var optional = []; |
| 401 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 402 | this.sendCommand(0x44, null, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional); |
| 403 | } |
| 404 | this.closeUserInitiatedConnection = function closeUnserInitiatedConnected(callback) { |
| 405 | var optional = []; |
| 406 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 407 | this.sendCommand(0x45, null, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional); |
| 408 | } |
| 409 | this.getRemoteAccessConnectionStatus = function getRemoteAccessConnectionStatus(callback) { |
| 410 | var optional = []; |
| 411 | for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 412 | this.sendCommand(0x46, null, function (header, fn, opt) { |
| 413 | if (header.Status == 0) { |
| 414 | var hostname = header.Data.slice(14, header.Data.readUInt16LE(12) + 14).toString() |
| 415 | opt.unshift({ status: header.Status, networkStatus: header.Data.readUInt32LE(0), remoteAccessStatus: header.Data.readUInt32LE(4), remoteAccessTrigger: header.Data.readUInt32LE(8), mpsHostname: hostname, raw: header.Data }); |
| 416 | } else { |
| 417 | opt.unshift({ status: header.Status }); |
| 418 | } |
| 419 | fn.apply(this, opt); |
| 420 | }, callback, optional); |
| 421 | } |
| 422 | this.getProtocolVersion = function getProtocolVersion(callback) { |
| 423 | var optional = []; |
| 424 | for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); } |
| 425 | |
| 426 | if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this; } |
| 427 | this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) { |
| 428 | if (status == 0) { |
| 429 | var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString(); |
| 430 | opt.unshift(result); |
| 431 | fn.apply(self, opt); |
| 432 | } |
| 433 | else { |
| 434 | opt.unshift(null); |
| 435 | fn.apply(self, opt); |
| 436 | } |
| 437 | |
| 438 | }, this, callback, optional); |
| 439 | } |
| 440 | this.startConfigurationHBased = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) { |
| 441 | if ((certHash == null) || ((certHash.length != 32) && (certHash.length != 48))) { func({ status: -101 }); } |
| 442 | this.stopConfiguration(function (status) { |
| 443 | if (status == 0) { |
| 444 | // We stopped the configuration, wait 20 seconds before starting up again. |
| 445 | var f = function tf() { delete tf.parent.xtimeout; tf.parent.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); } |
| 446 | f.parent = this; |
| 447 | this.xtimeout = setTimeout(f, 20000); |
| 448 | } else { |
| 449 | // We are not in the connect mode, this is good, start configuration right away. |
| 450 | this.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); |
| 451 | } |
| 452 | }) |
| 453 | } |
| 454 | this.startConfigurationHBasedEx = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) { |
| 455 | var optional = []; |
| 456 | for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); } |
| 457 | |
| 458 | // Format the command |
| 459 | var data = Buffer.alloc(1 + 64 + 4 + 4 + ((dnsSuffixList != null) ? 320 : 0)); |
| 460 | data[0] = (certHash.length == 48) ? 3 : 2 // Write certificate hash type: SHA256 = 2, SHA384 = 3 |
| 461 | certHash.copy(data, 1); // Write the hash |
| 462 | data.writeUInt32LE(hostVpn ? 1 : 0, 65); // Write is HostVPN is enabled |
| 463 | if (dnsSuffixList != null) { |
| 464 | data.writeUInt32LE(dnsSuffixList.length, 69); // Write the number of DNS Suffix, from 0 to 4 |
| 465 | var ptr = 73; |
| 466 | for (var i = 0; i < dnsSuffixList.length; i++) { ptr += data.write(dnsSuffixList[i], ptr) + 1; } // Write up to 4 DNS Suffix with null seperation. |
| 467 | } |
| 468 | |
| 469 | // Send the command |
| 470 | this.sendCommand(139, data, function (header, fn, opt) { |
| 471 | if (header.Status == 0) { |
| 472 | var amtHash = null; |
| 473 | if (header.Data[0] == 2) { amtHash = header.Data.slice(1, 33); } // SHA256 |
| 474 | if (header.Data[0] == 3) { amtHash = header.Data.slice(1, 49); } // SHA384 |
| 475 | opt.unshift({ status: header.Status, hash: amtHash.toString('hex') }); |
| 476 | } else { |
| 477 | opt.unshift({ status: header.Status }); |
| 478 | } |
| 479 | fn.apply(this, opt); |
| 480 | }, func, optional); |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | module.exports = amt_heci; |
| 485 | |
| 486 | |
| 487 | /* |
| 488 | AMT_STATUS_SUCCESS = 0, |
| 489 | AMT_STATUS_INTERNAL_ERROR = 1, |
| 490 | AMT_STATUS_INVALID_AMT_MODE = 3, |
| 491 | AMT_STATUS_INVALID_MESSAGE_LENGTH = 4, |
| 492 | AMT_STATUS_MAX_LIMIT_REACHED = 23, |
| 493 | AMT_STATUS_INVALID_PARAMETER = 36, |
| 494 | AMT_STATUS_RNG_GENERATION_IN_PROGRESS = 47, |
| 495 | AMT_STATUS_RNG_NOT_READY = 48, |
| 496 | AMT_STATUS_CERTIFICATE_NOT_READY = 49, |
| 497 | AMT_STATUS_INVALID_HANDLE = 2053 |
| 498 | AMT_STATUS_NOT_FOUND = 2068, |
| 499 | */ |