1 /*
  2  * Copyright © [2008-2009] Novell, Inc.  All Rights Reserved.
  3  * 
  4  * USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE DEVELOPER LICENSE AGREEMENT
  5  * OR OTHER AGREEMENT THROUGH WHICH NOVELL, INC. MAKES THE WORK AVAILABLE.  THIS WORK 
  6  * MAY NOT BE ADAPTED WITHOUT NOVELL'S PRIOR WRITTEN CONSENT.
  7  * 
  8  * NOVELL PROVIDES THE WORK "AS IS," WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, 
  9  * INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR 
 10  * A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  NOVELL, THE AUTHORS OF THE WORK, AND THE 
 11  * OWNERS OF COPYRIGHT IN THE WORK ARE NOT LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER 
 12  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, 
 13  * OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS IN THE WORK.
 14  */
 15 
 16 /**
 17  * @fileoverview
 18  * This file defines the Event class, which represents the output event that will be
 19  * sent to Sentinel.
 20  * @name Event Class
 21  */
 22 
 23 /**
 24  * Constructs a new instance of an Event object, which can be sent to Sentinel.
 25  * The constructor can take an object or JSON string as input to set pre-defined
 26  * fields, e.g. constants for initialization of the new Event object.
 27  * @class
 28  * Represents a Sentinel event that can be sent up to the Collector Manager.
 29  * In general, Event objects are not manipulated directly as the field values
 30  * need to be protected, but are manipulated via methods. 
 31  * @param {Event} proto  The prototype or template event that should be cloned to create this new Event
 32  */
 33 function Event(proto) {
 34 	for (var src in proto) {
 35 		if ( proto.hasOwnProperty(src) ) {
 36 			this[src] = proto[src];
 37 		} 
 38 	}
 39 }
 40 
 41 /**
 42  * Sets the DeviceEventTime and DeviceEventTimeString to the time according to the event source.
 43  * The Sentinel event schema includes two fields:
 44  * <dl>
 45  * <dt>DeviceEventTimeString</dt><dd>A string which represents the time according to the event source; 
 46  * this is always expressed in local time according to the Collector Manager, since that's where the time is processed.</dd>
 47  * <dt>DeviceEventTime</dt><dd>A field of Date type which represents the time according to the event source</dd>
 48  * </dl>
 49  * Both fields will be set by this method.
 50  * <p>Note that you must pass a Date object to this method; you must therefore first convert whatever
 51  * textual representation of the date and time is embedded in the input record into a Date object.
 52  * We have included the <a href="http://www.datejs.com/">date.js library</a> to make this easier. You
 53  * should be able to pass it almost any datetime representation and have it correctly create a Date,
 54  * but note that in some cases you may need to add missing year and/or timezone information.
 55  * @example
 56  * Record.prototype.parse = function(e) {
 57  *  this.devtime = Date.parse(this.s_RXBufferString.substr(0,30));
 58  *  e.setDeviceEventTime(this.devtime);
 59  *  
 60  * @param {Date} time  The date/time according to the event source. This MUST be a Date object.
 61  * @return {Boolean} A Boolean to indicate successful completion
 62  */
 63 Event.prototype.setDeviceEventTime = function(time){
 64 
 65   if ( !(time instanceof Date) ) { return false; }	
 66 	this.DeviceEventTime = time;
 67 	return true;
 68 };
 69 
 70 /**
 71  * Sets the BeginTime field to the time the event(s) began according to the event source.
 72  * <p>Note that you must pass a Date object to this method; you must therefore first convert whatever
 73  * textual representation of the date and time is embedded in the input record into a Date object.
 74  * We have included the <a href="http://www.datejs.com/">date.js library</a> to make this easier. You
 75  * should be able to pass it almost any datetime representation and have it correctly create a Date,
 76  * but note that in some cases you may need to add missing year and/or timezone information.
 77  * @example
 78  * Record.prototype.parse = function(e) {
 79  *  this.begintime = Date.parse(this.s_RXBufferString.substr(0,30));
 80  *  e.setBeginTime(this.begintime);
 81  *  
 82  * @param {Date} time  The date/time the event(s) began according to the event source. This MUST be a Date object.
 83  * @return {Boolean} A Boolean to indicate successful completion
 84  */
 85 Event.prototype.setBeginTime = function(time){
 86 
 87   if ( !(time instanceof Date) ) { return false; }	
 88 		this.BeginTime = time;
 89 		return true;
 90 };
 91 
 92 /**
 93  * Sets the EndTime field to the time the event(s) ended according to the event source.
 94  * <p>Note that you must pass a Date object to this method; you must therefore first convert whatever
 95  * textual representation of the date and time is embedded in the input record into a Date object.
 96  * We have included the <a href="http://www.datejs.com/">date.js library</a> to make this easier. You
 97  * should be able to pass it almost any datetime representation and have it correctly create a Date,
 98  * but note that in some cases you may need to add missing year and/or timezone information.
 99  * @example
100  * Record.prototype.parse = function(e) {
101  *  this.endtime = Date.parse(this.s_RXBufferString.substr(0,30));
102  *  e.setEndTime(this.endtime);
103  *  
104  * @param {Date} time  The date/time the event(s) ended according to the event source. This MUST be a Date object.
105  * @return {Boolean} A Boolean to indicate successful completion
106  */
107 Event.prototype.setEndTime = function(time){
108 
109   if ( !(time instanceof Date) ) { return false; }	
110 		this.EndTime = time;
111 		return true;
112 };
113 
114 /**
115  * Adds the arguments to the Sentinel ExtendedInformation field.
116  * Sentinel's ExtendedInformation field has a pre-defined internal format as name-value pair.
117  * To enforce this format, use this method to add data to this field.
118  * <p>Example:
119  * <pre>
120  * curEvt.add2EI( "CustomData", rec.s_RXBufferString.substr(20,30);
121  * </pre>
122 	* @param {String} name  The attribute name that will be set
123  * @param {String} val  The value for that attribute
124  * @return {Boolean} A Boolean to indicate successful completion
125  */
126 Event.prototype.add2EI = function(name, val){
127 	if (typeof name == "undefined" || typeof val == "undefined" || name === "" || val === "") { 
128 	 return false;
129 	}
130 	this.ExtendedInformation = this.ExtendedInformation ? (this.ExtendedInformation + " " + name + "=" + val + ";") : (name + "=" + val + ";");
131 	return true;
132 };
133 
134 /**
135  * Sets the taxonomy key to be used when constructing the output Event.
136  * The taxonomy key is used to determine the taxonomy classification for the event. It
137  * should include enough information to determine the type of action taken as well as the
138  * outcome of the event (status or result). The key needs to match one of the entries in
139  * the taxonomy {@link KeyMap}, which is loaded from the taxonomy.map file.
140  * <p>The taxonomy key is used to set the following Event fields:
141  * <ul>
142  * <li>Event.TaxonomyLevel1
143 	* <li>Event.TaxonomyLevel2
144 	* <li>Event.TaxonomyLevel3
145 	* <li>Event.TaxonomyLevel4
146 	* <li>Event.XDASEventName
147  * <li>Event.XDASEventOutcome
148  * <li>Event.XDASRegistry
149  * <li>Event.XDASProvider
150  * <li>Event.XDASClass
151  * <li>Event.XDASIdentifier
152  * <li>Event.XDASOutcome
153  * <li>Event.XDASDetail
154  * </ul>
155  * @param {String} key  The string to use as the taxonomy key
156  * @return {Boolean} Result
157  */
158 Event.prototype.setTaxKey = function(key){
159 	// Use key to look up taxonomy
160 	if (typeof key == "undefined") { return false; }
161 	var taxonomy = instance.MAPS.tax.lookup(key);
162 	if (typeof taxonomy == "undefined") { return false; }
163 	this.TaxonomyLevel1 = taxonomy[0];
164 	this.TaxonomyLevel2 = taxonomy[1];
165 	this.TaxonomyLevel3 = taxonomy[2];
166 	this.TaxonomyLevel4 = taxonomy[3];
167 	this.XDASTaxonomyName = taxonomy[4];
168 	this.XDASOutcomeName = taxonomy[5];
169 	var taxcode = instance.MAPS.taxcode.lookup(this.XDASTaxonomyName);
170 	var taxout = instance.MAPS.taxout.lookup(this.XDASOutcomeName);
171 	this.XDASRegistry = taxcode[0];
172 	this.XDASProvider = taxcode[1];
173 	this.XDASClass = taxcode[2];
174 	this.XDASIdentifier = taxcode[3];
175 	this.XDASOutcome = taxout[0];
176 	this.XDASDetail = taxout[1];
177 	return true;
178 };
179 
180 /**
181  * Sends an event to the Collector Manager.
182  * This method consumes the input record object to set fields in the output event,
183  * as well as performing some additional processing.
184  * @param {DataMap} datamap  The map to use (optional) when converting the 'rec' object into the Event. Will default to Rec2Evt.
185  * @return {Boolean} Result
186  */
187 Event.prototype.send = function(datamap) {
188 	
189 	if (typeof datamap == "undefined") {
190 		datamap = instance.MAPS.Rec2Evt;
191 	}
192 
193 	// Convert record to output event (if this is not an internal event)
194 	if (typeof rec != "undefined") {
195 		rec.convert(this, datamap);
196 	}
197 	else { // probably a debug event with no input record; need a blank one
198 		rec = new Record();
199 		var hashMap = new HashMap();
200 		rec.connectorData = new ConnectorData(hashMap);
201 	}
202 	
203 	// Produce debug output
204 	if (instance.CONFIG.params.ExecutionMode == "debug") {
205 		instance.CONFIG.debugFile.writeLine(JSON.stringify(this) + "\n");
206 	}
207 	
208 	// Mark replay events
209 	if (rec.CONNECTION_MODE == "Replay") {
210 		this.SensorType = "T";
211 	}
212 	
213 	// resolve hostnames if asked
214 	if (instance.CONFIG.params.Resolve_IP_and_Hostname == "yes") {
215 		var assets = {"Init":null,"Target":null,"Observer":null,"Reporter":null};
216 		
217 		var unknownIPs = [];
218 		var unknownHosts = [];
219 		var fqdn;
220 		
221 		for (var asset in assets) {
222 			if (typeof this[asset + "HostName"] == 'undefined') { // Need the hostname
223 				if (typeof this[asset + "IP"] != 'undefined') {
224 					if (typeof instance.MAPS.ip2n[this[asset + "IP"]] != 'undefined') {
225 						fqdn = instance.MAPS.ip2n[this[asset + "IP"]][0];
226 						if (fqdn.search(/\./) != -1) {
227 							this[asset + "HostName"] = fqdn.substr(0, fqdn.indexOf("."));
228 							this[asset + "HostDomain"] = fqdn.substr(fqdn.indexOf(".") + 1);
229 						}	else {
230 							this[asset + "HostName"] = fqdn;
231 						}
232 					}	else {
233 						unknownIPs.push(this[asset + "IP"]);
234 					}
235 				}
236 			}	else { // Need the IP
237 				if (typeof this[asset + "IP"] == 'undefined') {
238 					if (typeof this[asset + "HostName"] != 'undefined' && typeof this[asset + "HostDomain"] != 'undefined') {
239 						fqdn = this[asset + "HostName"] + "." + this[asset + "HostDomain"];
240 					} else if (typeof this[asset + "HostName"] != 'undefined' && typeof this[asset + "HostDomain"] == 'undefined') {
241 						fqdn = this[asset + "HostName"];
242 					} 
243 					if (typeof fqdn != 'undefined') {
244 						if (typeof instance.MAPS.n2ip[fqdn] != 'undefined') {
245 							this[asset + "IP"] = instance.MAPS.n2ip[fqdn][0];
246 						}	else {
247 							unknownHosts.push(fqdn);
248 						}
249 					}
250 				}
251 			}
252 		}
253 	
254 		if (unknownIPs.length > 0) {
255 			var needIPsFile = new File(instance.CONFIG.commonDir + instance.UUID + ".needIPs.tmp", "w");
256 			for (var i = unknownIPs.length - 1; i > -1; i--) {
257 				needIPsFile.writeLine(unknownIPs[i]);
258 			}
259 			needIPsFile.close();
260 		}
261 		if (unknownHosts.length > 0) {
262 			var needHostsFile = new File(instance.CONFIG.commonDir + instance.UUID + ".needHosts.tmp", "w");
263 			for (i = unknownHosts.length - 1; i > -1; i--) {
264 				needHostsFile.writeLine(unknownHosts[i]);
265 			}
266 			needHostsFile.close();
267 		}
268 	} // end name resolution
269 	
270 	if (instance.CONFIG.params.Resolve_IP_To_User == "yes") {
271 		// Store a user if they log in
272 		if (this.XDASClass == "2" && this.XDASIdentifier == "0" && this.XDASOutcome == "0" &&
273 				(typeof this.TargetUserName != "undefined" || this.TargetUserName != "") &&
274 				(typeof this.TargetUserID != "undefined" || this.TargetUserID != "") && 
275 				typeof this.TargetIP != "undefined" && this.TargetIP != "") {
276 			var ip2uFile = new File(instance.CONFIG.commonDir + instance.UUID + ".ip2u.tmp", "w");
277 			ip2uFile.writeLine(this.TargetIP + "," + this.TargetUserName + 
278 													"," + this.TargetUserDomain + "," + this.TargetUserID);
279 			ip2uFile.close();		
280 		}
281 		// If InitUserName is unset, try to find it
282 		if (typeof this.InitUserName == "undefined" && typeof this.InitUserID == "undefined" &&
283 				typeof this.InitIP != undefined && this.InitIP != "") {
284 			var userinfo = instance.MAPS.ip2u.lookup[this.InitIP];
285 			if (typeof userinfo[0] != "undefined" && userinfo[0] != "") {
286 				this.InitUserName = userinfo[0];
287 			}
288 			if (typeof userinfo[1] != "undefined" && userinfo[1] != "") {
289 				this.InitUserDomain = userinfo[1];
290 			}
291 			if (typeof userinfo[2] != "undefined" && userinfo[2] != "") {
292 				this.InitUserID = userinfo[2];
293 			}
294 		}
295   } // end user resolution
296 	
297 	// Construct the Java event from the JS event
298 	var JEvent = new EventData();
299 	for (var field in this) {
300 		if (this.hasOwnProperty(field)) {
301 				var value = this[field];
302 				if (value != "" && instance.MAPS.Evt2EvtData[field] && typeof value != "undefined" && value != "undefined" 
303 							&& field != "DeviceEventTime" && field != "BeginTime" && field != "EndTime") {
304 					 JEvent.setString(instance.MAPS.Evt2EvtData[field], String(value));
305 				}
306 	  }
307 	}
308 	
309 	// Set DeviceEventTime and DeviceEventTimeString 
310 		if (this.DeviceEventTime instanceof Date) {
311 			this.DeviceEventTime.adjustTimezone();
312 			JEvent.setDeviceEventTime(String(this.DeviceEventTime.getTime()));
313 			JEvent.setString( "et", this.DeviceEventTime.toString());
314 		}
315 	
316 		// Set BeginTime and EndTime
317 		if (this.BeginTime instanceof Date) {
318 			this.BeginTime.adjustTimezone();
319 			JEvent.setString("bgnt", String(this.BeginTime.getTime()));
320 		}
321 		if (this.EndTime instanceof Date) {
322 			this.EndTime.adjustTimezone();
323 			JEvent.setString("endt", String(this.EndTime.getTime()));
324 		}
325 		// Send event
326 	instance.CONFIG.scriptContext.fireEvent(JEvent, rec.connectorData);
327 	return true;
328 };
329