amtevents.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /**
  2. * @description MeshCentral Intel(R) AMT Event Parser
  3. * @author Ylian Saint-Hilaire & Bryan Roe
  4. * @copyright Intel Corporation 2018-2022
  5. * @license Apache-2.0
  6. * @version v0.0.1
  7. */
  8. /*jslint node: true */
  9. /*jshint node: true */
  10. /*jshint strict:false */
  11. /*jshint -W097 */
  12. /*jshint esversion: 6 */
  13. "use strict";
  14. // Construct a MeshAgent object, called upon connection
  15. module.exports.CreateAmtEventsHandler = function (parent) {
  16. var obj = {};
  17. obj.parent = parent;
  18. // Private method
  19. function ParseWsman(xml) {
  20. try {
  21. if (!xml.childNodes) xml = _turnToXml(xml);
  22. var r = { Header: {} }, header = xml.getElementsByTagName("Header")[0], t;
  23. if (!header) header = xml.getElementsByTagName("a:Header")[0];
  24. if (!header) return null;
  25. for (var i = 0; i < header.childNodes.length; i++) {
  26. var child = header.childNodes[i];
  27. r.Header[child.localName] = child.textContent;
  28. }
  29. var body = xml.getElementsByTagName("Body")[0];
  30. if (!body) body = xml.getElementsByTagName("a:Body")[0];
  31. if (!body) return null;
  32. if (body.childNodes.length > 0) {
  33. t = body.childNodes[0].localName;
  34. var x = t.indexOf('_OUTPUT');
  35. if ((x != -1) && (x == (t.length - 7))) { t = t.substring(0, t.length - 7); }
  36. r.Header.Method = t;
  37. r.Body = _ParseWsmanRec(body.childNodes[0]);
  38. }
  39. return r;
  40. } catch (e) {
  41. console.log("Unable to parse XML: " + xml);
  42. return null;
  43. }
  44. }
  45. // Private method
  46. function _ParseWsmanRec(node) {
  47. var data, r = {};
  48. for (var i = 0; i < node.childNodes.length; i++) {
  49. var child = node.childNodes[i];
  50. if (child.childNodes == null) { data = child.textContent; } else { data = _ParseWsmanRec(child); }
  51. if (data == 'true') data = true; // Convert 'true' into true
  52. if (data == 'false') data = false; // Convert 'false' into false
  53. var childObj = data;
  54. if (child.attributes != null) {
  55. childObj = { 'Value': data };
  56. for (var j = 0; j < child.attributes.length; j++) {
  57. childObj['@' + child.attributes[j].name] = child.attributes[j].value;
  58. }
  59. }
  60. if (r[child.localName] instanceof Array) { r[child.localName].push(childObj); }
  61. else if (r[child.localName] == undefined) { r[child.localName] = childObj; }
  62. else { r[child.localName] = [r[child.localName], childObj]; }
  63. }
  64. return r;
  65. }
  66. // Parse and handle an event coming from Intel AMT
  67. obj.handleAmtEvent = function (data, nodeid, amthost) {
  68. var x = ParseWsman(data);
  69. if (x != null) {
  70. // TODO: Dispatch this event, we need to keep a running Intel AMT log for each machine.
  71. console.log('Got Intel AMT event from ' + amthost + ', nodeid: ' + nodeid.substring(0, 8));
  72. //console.log(x);
  73. }
  74. return x;
  75. };
  76. // DEBUG: This is an example event, to test parsing and dispatching
  77. //obj.handleAmtEvent('<?xml version="1.0" encoding="UTF-8"?><a:Envelope xmlns:a="http://www.w3.org/2003/05/soap-envelope" xmlns:b="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:c="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:d="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:e="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:f="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd" xmlns:g="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_AlertIndication" xmlns:h="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><a:Header><b:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</b:To><b:ReplyTo><b:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</b:Address></b:ReplyTo><c:AckRequested></c:AckRequested><b:Action a:mustUnderstand="true">http://schemas.dmtf.org/wbem/wsman/1/wsman/Event</b:Action><b:MessageID>uuid:00000000-8086-8086-8086-000000128538</b:MessageID><c:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_AlertIndication</c:ResourceURI></a:Header><a:Body><g:CIM_AlertIndication><g:AlertType>8</g:AlertType><g:AlertingElementFormat>2</g:AlertingElementFormat><g:AlertingManagedElement>Interop:CIM_ComputerSystem.CreationClassName=&quot;CIM_ComputerSystem&quot;,Name=&quot;Intel(r) AMT&quot;</g:AlertingManagedElement><g:IndicationFilterName>Intel(r) AMT:AllEvents</g:IndicationFilterName><g:IndicationIdentifier>Intel(r):2950234687</g:IndicationIdentifier><g:IndicationTime><h:Datetime>2017-01-31T15:40:09.000Z</h:Datetime></g:IndicationTime><g:Message></g:Message><g:MessageArguments>0</g:MessageArguments><g:MessageArguments>Interop:CIM_ComputerSystem.CreationClassName=CIM_ComputerSystem,Name=Intel(r) AMT</g:MessageArguments><g:MessageID>iAMT0005</g:MessageID><g:OtherAlertingElementFormat></g:OtherAlertingElementFormat><g:OtherSeverity></g:OtherSeverity><g:OwningEntity>Intel(r) AMT</g:OwningEntity><g:PerceivedSeverity>2</g:PerceivedSeverity><g:ProbableCause>0</g:ProbableCause><g:SystemName>Intel(r) AMT</g:SystemName></g:CIM_AlertIndication></a:Body></a:Envelope>', 'aabbccdd', '1.2.3.4');
  78. // This is a drop-in replacement to _turnToXml() that works without xml parser dependency.
  79. try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : null); } }); } catch (ex) { }
  80. function _treeBuilder() {
  81. this.tree = [];
  82. this.push = function (element) { this.tree.push(element); };
  83. this.pop = function () { var element = this.tree.pop(); if (this.tree.length > 0) { var x = this.tree.peek(); x.childNodes.push(element); x.childElementCount = x.childNodes.length; } return (element); };
  84. this.peek = function () { return (this.tree.peek()); }
  85. this.addNamespace = function (prefix, namespace) { this.tree.peek().nsTable[prefix] = namespace; if (this.tree.peek().attributes.length > 0) { for (var i = 0; i < this.tree.peek().attributes; ++i) { var a = this.tree.peek().attributes[i]; if (prefix == '*' && a.name == a.localName) { a.namespace = namespace; } else if (prefix != '*' && a.name != a.localName) { var pfx = a.name.split(':')[0]; if (pfx == prefix) { a.namespace = namespace; } } } } }
  86. this.getNamespace = function (prefix) { for (var i = this.tree.length - 1; i >= 0; --i) { if (this.tree[i].nsTable[prefix] != null) { return (this.tree[i].nsTable[prefix]); } } return null; }
  87. }
  88. function _turnToXml(text) { if (text == null) return null; return ({ childNodes: [_turnToXmlRec(text)], getElementsByTagName: _getElementsByTagName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS }); }
  89. function _getElementsByTagNameNS(ns, name) { var ret = []; _xmlTraverseAllRec(this.childNodes, function (node) { if (node.localName == name && (node.namespace == ns || ns == '*')) { ret.push(node); } }); return ret; }
  90. function _getElementsByTagName(name) { var ret = []; _xmlTraverseAllRec(this.childNodes, function (node) { if (node.localName == name) { ret.push(node); } }); return ret; }
  91. function _getChildElementsByTagName(name) { var ret = []; if (this.childNodes != null) { for (var node in this.childNodes) { if (this.childNodes[node].localName == name) { ret.push(this.childNodes[node]); } } } return (ret); }
  92. function _getChildElementsByTagNameNS(ns, name) { var ret = []; if (this.childNodes != null) { for (var node in this.childNodes) { if (this.childNodes[node].localName == name && (ns == '*' || this.childNodes[node].namespace == ns)) { ret.push(this.childNodes[node]); } } } return (ret); }
  93. function _xmlTraverseAllRec(nodes, func) { for (var i in nodes) { func(nodes[i]); if (nodes[i].childNodes) { _xmlTraverseAllRec(nodes[i].childNodes, func); } } }
  94. function _turnToXmlRec(text) {
  95. var elementStack = new _treeBuilder(), lastElement = null, x1 = text.split('<'), ret = [], element = null, currentElementName = null;
  96. for (var i in x1) {
  97. var x2 = x1[i].split('>'), x3 = x2[0].split(' '), elementName = x3[0];
  98. if ((elementName.length > 0) && (elementName[0] != '?')) {
  99. if (elementName[0] != '/') {
  100. var attributes = [], localName, localname2 = elementName.split(' ')[0].split(':'), localName = (localname2.length > 1) ? localname2[1] : localname2[0];
  101. Object.defineProperty(attributes, "get",
  102. {
  103. value: function () {
  104. if (arguments.length == 1) {
  105. for (var a in this) { if (this[a].name == arguments[0]) { return (this[a]); } }
  106. }
  107. else if (arguments.length == 2) {
  108. for (var a in this) { if (this[a].name == arguments[1] && (arguments[0] == '*' || this[a].namespace == arguments[0])) { return (this[a]); } }
  109. }
  110. else {
  111. throw ('attributes.get(): Invalid number of parameters');
  112. }
  113. }
  114. });
  115. elementStack.push({ name: elementName, localName: localName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS, getChildElementsByTagNameNS: _getChildElementsByTagNameNS, attributes: attributes, childNodes: [], nsTable: {} });
  116. // Parse Attributes
  117. if (x3.length > 0) {
  118. var skip = false;
  119. for (var j in x3) {
  120. if (x3[j] == '/') {
  121. // This is an empty Element
  122. elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':')));
  123. elementStack.peek().textContent = '';
  124. lastElement = elementStack.pop();
  125. skip = true;
  126. break;
  127. }
  128. var k = x3[j].indexOf('=');
  129. if (k > 0) {
  130. var attrName = x3[j].substring(0, k);
  131. var attrValue = x3[j].substring(k + 2, x3[j].length - 1);
  132. var attrNS = elementStack.getNamespace('*');
  133. if (attrName == 'xmlns') {
  134. elementStack.addNamespace('*', attrValue);
  135. attrNS = attrValue;
  136. } else if (attrName.startsWith('xmlns:')) {
  137. elementStack.addNamespace(attrName.substring(6), attrValue);
  138. } else {
  139. var ax = attrName.split(':');
  140. if (ax.length == 2) { attrName = ax[1]; attrNS = elementStack.getNamespace(ax[0]); }
  141. }
  142. var x = { name: attrName, value: attrValue }
  143. if (attrNS != null) x.namespace = attrNS;
  144. elementStack.peek().attributes.push(x);
  145. }
  146. }
  147. if (skip) { continue; }
  148. }
  149. elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':')));
  150. if (x2[1]) { elementStack.peek().textContent = x2[1]; }
  151. } else { lastElement = elementStack.pop(); }
  152. }
  153. }
  154. return lastElement;
  155. }
  156. return obj;
  157. };