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 Record class, which represents the input record from the data source
 19  * (typically an event, but could be a record defining an Identity or other object).
 20  * @name Record Class
 21  */
 22 
 23 /**
 24  * Constructs a new instance of a Record object.
 25  * @class
 26  * The Record class represents the next record (or partial record) in the inbound data 
 27  * stream from some event source. There are a number of attributes and methods defined for
 28  * this class, but for the most part it is used as a general storage container for the data
 29  * in the input record plus all strings parsed out of that data.
 30  * <p>
 31  * This constructor only sets pre-defined default attributes; in most cases you will use
 32  * the Connector.read() method to fetch an actual populated record. In fact, the template
 33  * will usually do this for you at the beginning of each loop.
 34  * <p>
 35  * The Connector will set various attributes in the Record object according to the input.
 36  * Note that if there are multiple Connectors sending data to the Collector, they will all 
 37  * feed the same queue; you can determine which Connector sent you the data by the UUID or
 38  * the connection mode.
 39  * <p>
 40  * Connectors in general operate in one of two modes which will affect what the received
 41  * record looks like:
 42  * <ul>
 43  * <li>Buffer string mode: In this mode, the input from the event source is presented as a
 44  * single string, which will be in <code>rec.s_RXBufferString</code>. If the event source produces complex
 45  * data output, it may be pre-processed into NVP format.
 46  * <li>Map mode: The input from the event source is placed into several variables, with names
 47  * determined by the Connector. The DB Connector, for example, will return a variable for each 
 48  * column returned by the query.
 49  * </ul>
 50  * In addition to the <code>s_RXBufferString</code> and data map variables, there are also a number of additional
 51  * defaults that most Connectors will set in the input map:
 52  * <ul>
 53  * <li><code>rec.CONNECTION_METHOD</code>: The type of Connector that delivered the data
 54  * <li><code>rec.CONNECTION_MODE</code>: The connection mode in use by that Connector - this may affect the format
 55  * of the data.
 56  * <li><code>rec.i_RXBufferLength</code>: If s_RXBufferString is set, this is the length of that string. Can be used
 57  * to determine if an empty record was retrieved.
 58  * <li><code>rec.s_raw_message</code>: A copy of the raw message recieved. This is used by the signing feature.
 59  * <li><code>rec.o</code>: Used as a status variable to indicate the state of the Connector.
 60  * <li><code>rec.s_RV21</code>: The UUID of the Collector Manager that this Collector is running on.
 61  * <li><code>rec.s_RV22</code>: The UUID of this Collector instance.
 62  * <li><code>rec.s_RV23</code>: The UUID of the Connector delivering this data.
 63  * <li><code>rec.s_RV24</code>: The UUID of the Event Source from which this data was captured.
 64  * <li><code>rec.s_RV25</code>: A UUID assigned to this data record.
 65  * </ul>
 66  * For most of these variables, the template will handle processing them. You can use
 67  * <code>rec.CONNECTION_METHOD</code> and <code>rec.CONNECTION_MODE</code> to select the appropriate parsing 
 68  * methods, and <code>rec.i_RXBufferLength</code> to check for error conditions.
 69  * <p>
 70  * @author   Novell Engineering
 71  * @version  6.1
 72  * @constructor
 73  */
 74 function Record() {
 75 	// Initial blank objects
 76 	var hashMap = new HashMap();
 77 	/**
 78 	 * Dummy connector data object to pass to fireEvent(); will be replaced when data is read in most cases
 79 	 * @type ConnectorData
 80 	 */
 81 	this.connectorData = new ConnectorData(hashMap);
 82 	
 83 	/**
 84 	 * Empty object to hold field-based structured input
 85 	 */
 86 	this.RXMap={};
 87 	
 88 	/**
 89 	 * Converts a Record object into another object.
 90 	 * This method defaults to converting to an output Event, but can be used to convert
 91 	 * input into other objects like Identities, Assets, Vulnerabilities, etc.
 92 	 * <p>Example:
 93 	 * <pre>
 94 	 * // Usually the template will take care of conversion of your completely parsed record into
 95 	 * // the output event. But in case you need to convert to some other type of object:
 96 	 * rec.convert(outputID, instance.MAPS.Rec2ID);
 97 	 * </pre>
 98 	 * @param {Object} output  The object that the Record will be converted into.
 99 	 * @param {DataMap} map  The map to be used for the conversion.
100 	 * @return {Boolean} Result of conversion attempt
101 	 * @see DataMap
102 	 */
103 	this.convert = function(output, map){
104 		if ( typeof map == 'undefined' || !(map instanceof DataMap)) { return false; }
105 		if (map.preconvert) {
106 			map.preconvert(this, output);
107 		}	else {
108 			for (var src in map) {
109 				if (typeof map[src] != "function") {
110 					try {
111 						eval("output[src] = this" + map[src]); // Need to handle multilevel attrs
112 						if (output[src]) {
113 							output[src] = String(output[src]); // coerce to String
114 							}	else {
115 								delete output[src]; // Not sure why, but otherwise undefined is retained?
116 						}
117 					} catch (err) { /* do nothing */ }
118 				}
119 				
120 			}
121 		}
122 		return true;
123 	};	
124 
125 	/**
126 	 * This method sends a generic unparsed event where minimal processing is performed.
127 	 * In general this method is used to report unrecognized or unsupported records received from the
128 	 * event source. Collectors are typically written to support the most common events received from a
129 	 * particular source; in many cases infrequent events or events caused by add-on modules are not
130 	 * parsed by the default Collector code.
131 	 * <p>Note that there are two template parameters which control unparsed events:
132 	 * <ul>
133 	 * <li>Report Unparsed Events: This turns on/off the reporting of unparsed (unsupported) events.
134 	 * <li>Unparsed Events Severity: The reported severity of unparsed events.
135 	 * </ul>
136 	 * <p>When developing a Collector, you will usually want to attempt to parse the input records,
137 	 * and then call this method of the attempt is unsuccessful. In fact, the original template code
138 	 * has an example of this: see the parse() method which calls this method and then returns false
139 	 * to halt processing of this record.
140 	 * @param {Event} e  An Event object (optional) to use as the basis for the unparsed event. Will default to the global 'curEvt' object.
141 	 * @return {Boolean} Whether an event was set or not.
142 	 */
143 	this.sendUnsupported = function(e) {
144 		var appid;
145 		if (typeof e == "undefined" || !(e instanceof Event)) {
146 			e = curEvt;
147 		}
148 		if (typeof instance.CONFIG.params.Report_Unsupp != 'undefined' && instance.CONFIG.params.Report_Unsupp == "yes" ) {
149 			if (typeof instance.CONFIG.params.Unsupp_Severity != "undefined") {
150 				e.Severity = instance.CONFIG.params.Unsupp_Severity;
151 			} else {
152 				e.Severity = 0;
153 			}
154 			if (typeof this.s_AppId != "undefined" && this.s_AppId != "") { // If we know the appid, inject it into the event name
155 				appid = " " + this.s_AppId;
156 			} else {
157 				appid = "";
158 			}
159 			if (instance.CONFIG.params.UseConnectorName) { // This is the Generic Collector, so use the Connector name
160 				e.EventName = this.CONNECTION_METHOD + appid + " Event";
161 			} else {
162 				e.EventName = instance.CONFIG.collectorScript + appid + " Event";
163 			}
164 			if (this.CONNECTION_MODE == "map") {
165 				if ( typeof this.s_Body != "undefined" && this.s_Body != "") {
166 					e.Message = this.s_Body;
167 				} else {
168 				e.Message = String(rec.connectorData);
169 				}	
170 			} else {
171 				e.Message = this.s_RXBufferString;
172 			}
173 			e.send(instance.MAPS.UnsupEvt);
174 			return true;
175 		} 
176 		return false;
177 	};
178 }
179 
180