1 /* msg.c
2  * The msg object. Implementation of all msg-related functions
3  *
4  * File begun on 2007-07-13 by RGerhards (extracted from syslogd.c)
5  * This file is under development and has not yet arrived at being fully
6  * self-contained and a real object. So far, it is mostly an excerpt
7  * of the "old" message code without any modifications. However, it
8  * helps to have things at the right place one we go to the meat of it.
9  *
10  * Copyright 2007-2020 Rainer Gerhards and Adiscon GmbH.
11  *
12  * This file is part of the rsyslog runtime library.
13  *
14  * The rsyslog runtime library is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * The rsyslog runtime library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with the rsyslog runtime library.  If not, see <http://www.gnu.org/licenses/>.
26  *
27  * A copy of the GPL can be found in the file "COPYING" in this distribution.
28  * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
29  */
30 #include "config.h"
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #define SYSLOG_NAMES
35 #include <string.h>
36 #include <assert.h>
37 #include <ctype.h>
38 #include <sys/socket.h>
39 #ifdef HAVE_SYSINFO_UPTIME
40 #include <sys/sysinfo.h>
41 #endif
42 #include <netdb.h>
43 #include <libestr.h>
44 #include <json.h>
45 #ifdef HAVE_MALLOC_H
46 #  include <malloc.h>
47 #endif
48 #ifdef USE_LIBUUID
49 #  include <uuid/uuid.h>
50 #endif
51 #include <errno.h>
52 #include "rsyslog.h"
53 #include "srUtils.h"
54 #include "stringbuf.h"
55 #include "template.h"
56 #include "msg.h"
57 #include "datetime.h"
58 #include "glbl.h"
59 #include "regexp.h"
60 #include "atomic.h"
61 #include "unicode-helper.h"
62 #include "ruleset.h"
63 #include "prop.h"
64 #include "net.h"
65 #include "var.h"
66 #include "rsconf.h"
67 #include "parserif.h"
68 #include "errmsg.h"
69 
70 #define DEV_DEBUG 0	/* set to 1 to enable very verbose developer debugging messages */
71 
72 /* inlines */
73 extern void msgSetPRI(smsg_t *const __restrict__ pMsg, syslog_pri_t pri);
74 
75 /* TODO: move the global variable root to the config object - had no time to to it
76  * right now before vacation -- rgerhards, 2013-07-22
77  */
78 static pthread_mutex_t glblVars_lock;
79 struct json_object *global_var_root = NULL;
80 
81 /* static data */
82 DEFobjStaticHelpers
83 DEFobjCurrIf(datetime)
84 DEFobjCurrIf(glbl)
85 DEFobjCurrIf(regexp)
86 DEFobjCurrIf(prop)
87 DEFobjCurrIf(net)
88 DEFobjCurrIf(var)
89 
90 static const char *one_digit[10] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
91 
92 static const char *two_digits[100] = {
93 	"00", "01", "02", "03", "04", "05", "06", "07", "08", "09",
94 	"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
95 	"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
96 	"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
97 	"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
98 	"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
99 	"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
100 	"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
101 	"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
102 	"90", "91", "92", "93", "94", "95", "96", "97", "98", "99"};
103 
104 static const char *wdayNames[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
105 
106 /* Table of days in a year, needed for getYearDay */
107 static const char *daysInYear[366] = {
108 	       "001", "002", "003", "004", "005", "006", "007", "008", "009",
109 	"010", "011", "012", "013", "014", "015", "016", "017", "018", "019",
110 	"020", "021", "022", "023", "024", "025", "026", "027", "028", "029",
111 	"030", "031", "032", "033", "034", "035", "036", "037", "038", "039",
112 	"040", "041", "042", "043", "044", "045", "046", "047", "048", "049",
113 	"050", "051", "052", "053", "054", "055", "056", "057", "058", "059",
114 	"060", "061", "062", "063", "064", "065", "066", "067", "068", "069",
115 	"070", "071", "072", "073", "074", "075", "076", "077", "078", "079",
116 	"080", "081", "082", "083", "084", "085", "086", "087", "088", "089",
117 	"090", "091", "092", "093", "094", "095", "096", "097", "098", "099",
118 	"100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
119 	"110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
120 	"120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
121 	"130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
122 	"140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
123 	"150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
124 	"160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
125 	"170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
126 	"180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
127 	"190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
128 	"200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
129 	"210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
130 	"220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
131 	"230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
132 	"240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
133 	"250", "251", "252", "253", "254", "255", "256", "257", "258", "259",
134 	"260", "261", "262", "263", "264", "265", "266", "267", "268", "269",
135 	"270", "271", "272", "273", "274", "275", "276", "277", "278", "279",
136 	"280", "281", "282", "283", "284", "285", "286", "287", "288", "289",
137 	"290", "291", "292", "293", "294", "295", "296", "297", "298", "299",
138 	"300", "301", "302", "303", "304", "305", "306", "307", "308", "309",
139 	"310", "311", "312", "313", "314", "315", "316", "317", "318", "319",
140 	"320", "321", "322", "323", "324", "325", "326", "327", "328", "329",
141 	"330", "331", "332", "333", "334", "335", "336", "337", "338", "339",
142 	"340", "341", "342", "343", "344", "345", "346", "347", "348", "349",
143 	"350", "351", "352", "353", "354", "355", "356", "357", "358", "359",
144 	"360", "361", "362", "363", "364", "365", "366"};
145 
146 /* The following is a table of supported years. This permits us
147  * to avoid dynamic memory allocation. Note that the time-based
148  * algos need to be upgraded after the year 2099 in any case.
149  * Quite honestly, I don't expect that this is a real problem ;)
150  */
151 static const char *years[] = {
152 	"1967", "1968", "1969", "1970", "1971", "1972", "1973", "1974",
153 	"1975", "1976", "1977", "1978", "1979", "1980", "1981", "1982",
154 	"1983", "1984", "1985", "1986", "1987", "1988", "1989", "1990",
155 	"1991", "1992", "1993", "1994", "1995", "1996", "1997", "1998",
156 	"1999", "2000", "2001", "2002", "2003", "2004", "2005", "2006",
157 	"2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014",
158 	"2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022",
159 	"2023", "2024", "2025", "2026", "2027", "2028", "2029", "2030",
160 	"2031", "2032", "2033", "2034", "2035", "2036", "2037", "2038",
161 	"2039", "2040", "2041", "2042", "2043", "2044", "2045", "2046",
162 	"2047", "2048", "2049", "2050", "2051", "2052", "2053", "2054",
163 	"2055", "2056", "2057", "2058", "2059", "2060", "2061", "2062",
164 	"2063", "2064", "2065", "2066", "2067", "2068", "2069", "2070",
165 	"2071", "2072", "2073", "2074", "2075", "2076", "2077", "2078",
166 	"2079", "2080", "2081", "2082", "2083", "2084", "2085", "2086",
167 	"2087", "2088", "2089", "2090", "2091", "2092", "2093", "2094",
168 	"2095", "2096", "2097", "2098", "2099" };
169 
170 static struct {
171 	uchar *pszName;
172 } syslog_pri_names[200] = {
173 	{ UCHAR_CONSTANT("0") },
174 	{ UCHAR_CONSTANT("1") },
175 	{ UCHAR_CONSTANT("2") },
176 	{ UCHAR_CONSTANT("3") },
177 	{ UCHAR_CONSTANT("4") },
178 	{ UCHAR_CONSTANT("5") },
179 	{ UCHAR_CONSTANT("6") },
180 	{ UCHAR_CONSTANT("7") },
181 	{ UCHAR_CONSTANT("8") },
182 	{ UCHAR_CONSTANT("9") },
183 	{ UCHAR_CONSTANT("10") },
184 	{ UCHAR_CONSTANT("11") },
185 	{ UCHAR_CONSTANT("12") },
186 	{ UCHAR_CONSTANT("13") },
187 	{ UCHAR_CONSTANT("14") },
188 	{ UCHAR_CONSTANT("15") },
189 	{ UCHAR_CONSTANT("16") },
190 	{ UCHAR_CONSTANT("17") },
191 	{ UCHAR_CONSTANT("18") },
192 	{ UCHAR_CONSTANT("19") },
193 	{ UCHAR_CONSTANT("20") },
194 	{ UCHAR_CONSTANT("21") },
195 	{ UCHAR_CONSTANT("22") },
196 	{ UCHAR_CONSTANT("23") },
197 	{ UCHAR_CONSTANT("24") },
198 	{ UCHAR_CONSTANT("25") },
199 	{ UCHAR_CONSTANT("26") },
200 	{ UCHAR_CONSTANT("27") },
201 	{ UCHAR_CONSTANT("28") },
202 	{ UCHAR_CONSTANT("29") },
203 	{ UCHAR_CONSTANT("30") },
204 	{ UCHAR_CONSTANT("31") },
205 	{ UCHAR_CONSTANT("32") },
206 	{ UCHAR_CONSTANT("33") },
207 	{ UCHAR_CONSTANT("34") },
208 	{ UCHAR_CONSTANT("35") },
209 	{ UCHAR_CONSTANT("36") },
210 	{ UCHAR_CONSTANT("37") },
211 	{ UCHAR_CONSTANT("38") },
212 	{ UCHAR_CONSTANT("39") },
213 	{ UCHAR_CONSTANT("40") },
214 	{ UCHAR_CONSTANT("41") },
215 	{ UCHAR_CONSTANT("42") },
216 	{ UCHAR_CONSTANT("43") },
217 	{ UCHAR_CONSTANT("44") },
218 	{ UCHAR_CONSTANT("45") },
219 	{ UCHAR_CONSTANT("46") },
220 	{ UCHAR_CONSTANT("47") },
221 	{ UCHAR_CONSTANT("48") },
222 	{ UCHAR_CONSTANT("49") },
223 	{ UCHAR_CONSTANT("50") },
224 	{ UCHAR_CONSTANT("51") },
225 	{ UCHAR_CONSTANT("52") },
226 	{ UCHAR_CONSTANT("53") },
227 	{ UCHAR_CONSTANT("54") },
228 	{ UCHAR_CONSTANT("55") },
229 	{ UCHAR_CONSTANT("56") },
230 	{ UCHAR_CONSTANT("57") },
231 	{ UCHAR_CONSTANT("58") },
232 	{ UCHAR_CONSTANT("59") },
233 	{ UCHAR_CONSTANT("60") },
234 	{ UCHAR_CONSTANT("61") },
235 	{ UCHAR_CONSTANT("62") },
236 	{ UCHAR_CONSTANT("63") },
237 	{ UCHAR_CONSTANT("64") },
238 	{ UCHAR_CONSTANT("65") },
239 	{ UCHAR_CONSTANT("66") },
240 	{ UCHAR_CONSTANT("67") },
241 	{ UCHAR_CONSTANT("68") },
242 	{ UCHAR_CONSTANT("69") },
243 	{ UCHAR_CONSTANT("70") },
244 	{ UCHAR_CONSTANT("71") },
245 	{ UCHAR_CONSTANT("72") },
246 	{ UCHAR_CONSTANT("73") },
247 	{ UCHAR_CONSTANT("74") },
248 	{ UCHAR_CONSTANT("75") },
249 	{ UCHAR_CONSTANT("76") },
250 	{ UCHAR_CONSTANT("77") },
251 	{ UCHAR_CONSTANT("78") },
252 	{ UCHAR_CONSTANT("79") },
253 	{ UCHAR_CONSTANT("80") },
254 	{ UCHAR_CONSTANT("81") },
255 	{ UCHAR_CONSTANT("82") },
256 	{ UCHAR_CONSTANT("83") },
257 	{ UCHAR_CONSTANT("84") },
258 	{ UCHAR_CONSTANT("85") },
259 	{ UCHAR_CONSTANT("86") },
260 	{ UCHAR_CONSTANT("87") },
261 	{ UCHAR_CONSTANT("88") },
262 	{ UCHAR_CONSTANT("89") },
263 	{ UCHAR_CONSTANT("90") },
264 	{ UCHAR_CONSTANT("91") },
265 	{ UCHAR_CONSTANT("92") },
266 	{ UCHAR_CONSTANT("93") },
267 	{ UCHAR_CONSTANT("94") },
268 	{ UCHAR_CONSTANT("95") },
269 	{ UCHAR_CONSTANT("96") },
270 	{ UCHAR_CONSTANT("97") },
271 	{ UCHAR_CONSTANT("98") },
272 	{ UCHAR_CONSTANT("99") },
273 	{ UCHAR_CONSTANT("100") },
274 	{ UCHAR_CONSTANT("101") },
275 	{ UCHAR_CONSTANT("102") },
276 	{ UCHAR_CONSTANT("103") },
277 	{ UCHAR_CONSTANT("104") },
278 	{ UCHAR_CONSTANT("105") },
279 	{ UCHAR_CONSTANT("106") },
280 	{ UCHAR_CONSTANT("107") },
281 	{ UCHAR_CONSTANT("108") },
282 	{ UCHAR_CONSTANT("109") },
283 	{ UCHAR_CONSTANT("110") },
284 	{ UCHAR_CONSTANT("111") },
285 	{ UCHAR_CONSTANT("112") },
286 	{ UCHAR_CONSTANT("113") },
287 	{ UCHAR_CONSTANT("114") },
288 	{ UCHAR_CONSTANT("115") },
289 	{ UCHAR_CONSTANT("116") },
290 	{ UCHAR_CONSTANT("117") },
291 	{ UCHAR_CONSTANT("118") },
292 	{ UCHAR_CONSTANT("119") },
293 	{ UCHAR_CONSTANT("120") },
294 	{ UCHAR_CONSTANT("121") },
295 	{ UCHAR_CONSTANT("122") },
296 	{ UCHAR_CONSTANT("123") },
297 	{ UCHAR_CONSTANT("124") },
298 	{ UCHAR_CONSTANT("125") },
299 	{ UCHAR_CONSTANT("126") },
300 	{ UCHAR_CONSTANT("127") },
301 	{ UCHAR_CONSTANT("128") },
302 	{ UCHAR_CONSTANT("129") },
303 	{ UCHAR_CONSTANT("130") },
304 	{ UCHAR_CONSTANT("131") },
305 	{ UCHAR_CONSTANT("132") },
306 	{ UCHAR_CONSTANT("133") },
307 	{ UCHAR_CONSTANT("134") },
308 	{ UCHAR_CONSTANT("135") },
309 	{ UCHAR_CONSTANT("136") },
310 	{ UCHAR_CONSTANT("137") },
311 	{ UCHAR_CONSTANT("138") },
312 	{ UCHAR_CONSTANT("139") },
313 	{ UCHAR_CONSTANT("140") },
314 	{ UCHAR_CONSTANT("141") },
315 	{ UCHAR_CONSTANT("142") },
316 	{ UCHAR_CONSTANT("143") },
317 	{ UCHAR_CONSTANT("144") },
318 	{ UCHAR_CONSTANT("145") },
319 	{ UCHAR_CONSTANT("146") },
320 	{ UCHAR_CONSTANT("147") },
321 	{ UCHAR_CONSTANT("148") },
322 	{ UCHAR_CONSTANT("149") },
323 	{ UCHAR_CONSTANT("150") },
324 	{ UCHAR_CONSTANT("151") },
325 	{ UCHAR_CONSTANT("152") },
326 	{ UCHAR_CONSTANT("153") },
327 	{ UCHAR_CONSTANT("154") },
328 	{ UCHAR_CONSTANT("155") },
329 	{ UCHAR_CONSTANT("156") },
330 	{ UCHAR_CONSTANT("157") },
331 	{ UCHAR_CONSTANT("158") },
332 	{ UCHAR_CONSTANT("159") },
333 	{ UCHAR_CONSTANT("160") },
334 	{ UCHAR_CONSTANT("161") },
335 	{ UCHAR_CONSTANT("162") },
336 	{ UCHAR_CONSTANT("163") },
337 	{ UCHAR_CONSTANT("164") },
338 	{ UCHAR_CONSTANT("165") },
339 	{ UCHAR_CONSTANT("166") },
340 	{ UCHAR_CONSTANT("167") },
341 	{ UCHAR_CONSTANT("168") },
342 	{ UCHAR_CONSTANT("169") },
343 	{ UCHAR_CONSTANT("170") },
344 	{ UCHAR_CONSTANT("171") },
345 	{ UCHAR_CONSTANT("172") },
346 	{ UCHAR_CONSTANT("173") },
347 	{ UCHAR_CONSTANT("174") },
348 	{ UCHAR_CONSTANT("175") },
349 	{ UCHAR_CONSTANT("176") },
350 	{ UCHAR_CONSTANT("177") },
351 	{ UCHAR_CONSTANT("178") },
352 	{ UCHAR_CONSTANT("179") },
353 	{ UCHAR_CONSTANT("180") },
354 	{ UCHAR_CONSTANT("181") },
355 	{ UCHAR_CONSTANT("182") },
356 	{ UCHAR_CONSTANT("183") },
357 	{ UCHAR_CONSTANT("184") },
358 	{ UCHAR_CONSTANT("185") },
359 	{ UCHAR_CONSTANT("186") },
360 	{ UCHAR_CONSTANT("187") },
361 	{ UCHAR_CONSTANT("188") },
362 	{ UCHAR_CONSTANT("189") },
363 	{ UCHAR_CONSTANT("190") },
364 	{ UCHAR_CONSTANT("191") },
365 	{ UCHAR_CONSTANT("192") },
366 	{ UCHAR_CONSTANT("193") },
367 	{ UCHAR_CONSTANT("194") },
368 	{ UCHAR_CONSTANT("195") },
369 	{ UCHAR_CONSTANT("196") },
370 	{ UCHAR_CONSTANT("197") },
371 	{ UCHAR_CONSTANT("198") },
372 	{ UCHAR_CONSTANT("199") }
373 	};
374 static char hexdigit[16] =
375 	{'0', '1', '2', '3', '4', '5', '6', '7', '8',
376 	 '9', 'A', 'B', 'C', 'D', 'E', 'F' };
377 
378 #if defined(_AIX)
379 /* AIXPORT : replace facility names with aso and caa only for AIX */
380 static const char *syslog_fac_names[LOG_NFACILITIES] = { "kern", "user", "mail", "daemon", "auth", "syslog", "lpr",
381 							"news", "uucp", "cron", "authpriv", "ftp", "aso", "audit",
382 							"alert", "caa", "local0", "local1", "local2", "local3",
383 							"local4", "local5", "local6", "local7", "invld"    };
384 /* length of the facility names string (for optimizatiions) */
385 static short len_syslog_fac_names[LOG_NFACILITIES] = { 4, 4, 4, 6, 4, 6, 3,
386 							4, 4, 4, 8, 3, 3, 5,
387 							5, 3, 6, 6, 6, 6,
388 							6, 6, 6, 6, 5 };
389 
390 #else
391 /*syslog facility names (as of RFC5424) */
392 static const char *syslog_fac_names[LOG_NFACILITIES] = { "kern", "user", "mail", "daemon", "auth", "syslog", "lpr",
393 							"news", "uucp", "cron", "authpriv", "ftp", "ntp", "audit",
394 							"alert", "clock", "local0", "local1", "local2", "local3",
395 							"local4", "local5", "local6", "local7", "invld" };
396 /* length of the facility names string (for optimizatiions) */
397 static short len_syslog_fac_names[LOG_NFACILITIES] = { 4, 4, 4, 6, 4, 6, 3,
398 							4, 4, 4, 8, 3, 3, 5,
399 							5, 5, 6, 6, 6, 6,
400 							6, 6, 6, 6, 5 };
401 #endif
402 
403 /* table of severity names (in numerical order)*/
404 static const char *syslog_severity_names[8] = { "emerg", "alert", "crit", "err", "warning", "notice", "info",
405 	"debug" };
406 static short len_syslog_severity_names[8] = { 5, 5, 4, 3, 7, 6, 4, 5 };
407 
408 /* numerical values as string - this is the most efficient approach to convert severity
409  * and facility values to a numerical string... -- rgerhars, 2009-06-17
410  */
411 
412 static const char *syslog_number_names[LOG_NFACILITIES] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
413 	"10", "11", "12", "13", "14",
414 	"15", "16", "17", "18", "19", "20", "21", "22", "23", "24" };
415 
416 /* global variables */
417 #if defined(HAVE_MALLOC_TRIM) && !defined(HAVE_ATOMIC_BUILTINS)
418 static pthread_mutex_t mutTrimCtr;	 /* mutex to handle malloc trim */
419 #endif
420 
421 /* some forward declarations */
422 static int getAPPNAMELen(smsg_t * const pM, sbool bLockMutex);
423 static rsRetVal jsonPathFindParent(struct json_object *jroot, uchar *name, uchar *leaf,
424 	struct json_object **parent, int bCreate);
425 static uchar * jsonPathGetLeaf(uchar *name, int lenName);
426 struct json_object *jsonDeepCopy(struct json_object *src);
427 static json_bool jsonVarExtract(struct json_object* root, const char *key, struct json_object **value);
428 void getRawMsgAfterPRI(smsg_t * const pM, uchar **pBuf, int *piLen);
429 
430 
431 /* the locking and unlocking implementations: */
432 static inline void
MsgLock(smsg_t * pThis)433 MsgLock(smsg_t *pThis)
434 {
435 	#if DEV_DEBUG == 1
436 	dbgprintf("MsgLock(0x%lx)\n", (unsigned long) pThis);
437 	#endif
438 	pthread_mutex_lock(&pThis->mut);
439 }
440 static inline void
MsgUnlock(smsg_t * pThis)441 MsgUnlock(smsg_t *pThis)
442 {
443 	#if DEV_DEBUG == 1
444 	dbgprintf("MsgUnlock(0x%lx)\n", (unsigned long) pThis);
445 	#endif
446 	pthread_mutex_unlock(&pThis->mut);
447 }
448 
449 
450 /* set RcvFromIP name in msg object WITHOUT calling AddRef.
451  * rgerhards, 2013-01-22
452  */
453 static inline void
MsgSetRcvFromIPWithoutAddRef(smsg_t * pThis,prop_t * new)454 MsgSetRcvFromIPWithoutAddRef(smsg_t *pThis, prop_t *new)
455 {
456 	if(pThis->pRcvFromIP != NULL)
457 		prop.Destruct(&pThis->pRcvFromIP);
458 	pThis->pRcvFromIP = new;
459 }
460 
461 
462 /* set RcvFrom name in msg object WITHOUT calling AddRef.
463  * rgerhards, 2013-01-22
464  */
MsgSetRcvFromWithoutAddRef(smsg_t * pThis,prop_t * new)465 static void MsgSetRcvFromWithoutAddRef(smsg_t *pThis, prop_t *new)
466 {
467 	assert(pThis != NULL);
468 
469 	if(pThis->msgFlags & NEEDS_DNSRESOL) {
470 		if(pThis->rcvFrom.pfrominet != NULL)
471 			free(pThis->rcvFrom.pfrominet);
472 		pThis->msgFlags &= ~NEEDS_DNSRESOL;
473 	} else {
474 		if(pThis->rcvFrom.pRcvFrom != NULL)
475 			prop.Destruct(&pThis->rcvFrom.pRcvFrom);
476 	}
477 	pThis->rcvFrom.pRcvFrom = new;
478 }
479 
480 
481 /* rgerhards 2012-04-18: set associated ruleset (by ruleset name)
482  * pRuleset pointer inside msg is updated. If ruleset cannot be found,
483  * no update is done and an error message emitted.
484  */
ATTR_NONNULL()485 static void ATTR_NONNULL()
486 MsgSetRulesetByName(smsg_t * const pMsg, cstr_t *const rulesetName)
487 {
488 	uchar *const rs_name = rsCStrGetSzStrNoNULL(rulesetName);
489 	const rsRetVal localRet =
490 		 rulesetGetRuleset(runConf, &(pMsg->pRuleset), rs_name);
491 
492 	if(localRet != RS_RET_OK) {
493 		LogError(0, localRet, "msg: ruleset '%s' could not be found and could not "
494 			"be assgined to message object. This possibly leads to the message "
495 			"being processed incorrectly. We cannot do anything against this, but "
496 			"wanted to let you know.", rs_name);
497 	}
498 }
499 
500 /* do a DNS reverse resolution, if not already done, reflect status
501  * rgerhards, 2009-11-16
502  */
503 static rsRetVal
resolveDNS(smsg_t * const pMsg)504 resolveDNS(smsg_t * const pMsg) {
505 	rsRetVal localRet;
506 	prop_t *propFromHost = NULL;
507 	prop_t *ip;
508 	prop_t *localName;
509 	DEFiRet;
510 
511 	MsgLock(pMsg);
512 	CHKiRet(objUse(net, CORE_COMPONENT));
513 	if(pMsg->msgFlags & NEEDS_DNSRESOL) {
514 		if (pMsg->msgFlags & PRESERVE_CASE) {
515 			localRet = net.cvthname(pMsg->rcvFrom.pfrominet, NULL, &localName, &ip);
516 		} else {
517 			localRet = net.cvthname(pMsg->rcvFrom.pfrominet, &localName, NULL, &ip);
518 		}
519 		if(localRet == RS_RET_OK) {
520 			/* we pass down the props, so no need for AddRef */
521 			MsgSetRcvFromWithoutAddRef(pMsg, localName);
522 			MsgSetRcvFromIPWithoutAddRef(pMsg, ip);
523 		}
524 	}
525 finalize_it:
526 	if(iRet != RS_RET_OK) {
527 		/* best we can do: remove property */
528 		MsgSetRcvFromStr(pMsg, UCHAR_CONSTANT(""), 0, &propFromHost);
529 		prop.Destruct(&propFromHost);
530 	}
531 	MsgUnlock(pMsg);
532 	if(propFromHost != NULL)
533 		prop.Destruct(&propFromHost);
534 	RETiRet;
535 }
536 
537 
538 void
getInputName(const smsg_t * const pM,uchar ** ppsz,int * const plen)539 getInputName(const smsg_t * const pM, uchar **ppsz, int *const plen)
540 {
541 	if(pM == NULL || pM->pInputName == NULL) {
542 		*ppsz = UCHAR_CONSTANT("");
543 		*plen = 0;
544 	} else {
545 		prop.GetString(pM->pInputName, ppsz, plen);
546 	}
547 }
548 
549 
550 static uchar*
getRcvFromIP(smsg_t * const pM)551 getRcvFromIP(smsg_t * const pM)
552 {
553 	uchar *psz;
554 	int len;
555 	if(pM == NULL) {
556 		psz = UCHAR_CONSTANT("");
557 	} else {
558 		resolveDNS(pM); /* make sure we have a resolved entry */
559 		if(pM->pRcvFromIP == NULL)
560 			psz = UCHAR_CONSTANT("");
561 		else
562 			prop.GetString(pM->pRcvFromIP, &psz, &len);
563 	}
564 	return psz;
565 }
566 
567 
568 /* map a property name (string) to a property ID */
569 rsRetVal
propNameToID(const uchar * const pName,propid_t * const pPropID)570 propNameToID(const uchar *const pName, propid_t *const pPropID)
571 {
572 	DEFiRet;
573 
574 	/* sometimes there are aliases to the original MonitoWare
575 	 * property names. These come after || in the ifs below. */
576 	if(!strcasecmp((char*) pName, "msg")) {
577 		*pPropID = PROP_MSG;
578 	} else if(!strcasecmp((char*) pName, "timestamp")
579 		  || !strcasecmp((char*) pName, "timereported")) {
580 		*pPropID = PROP_TIMESTAMP;
581 	} else if(!strcasecmp((char*) pName, "hostname") || !strcasecmp((char*) pName, "source")) {
582 		*pPropID = PROP_HOSTNAME;
583 	} else if(!strcasecmp((char*) pName, "syslogtag")) {
584 		*pPropID = PROP_SYSLOGTAG;
585 	} else if(!strcasecmp((char*) pName, "rawmsg")) {
586 		*pPropID = PROP_RAWMSG;
587 	} else if(!strcasecmp((char*) pName, "rawmsg-after-pri")) {
588 		*pPropID = PROP_RAWMSG_AFTER_PRI;
589 	} else if(!strcasecmp((char*) pName, "inputname")) {
590 		*pPropID = PROP_INPUTNAME;
591 	} else if(!strcasecmp((char*) pName, "fromhost")) {
592 		*pPropID = PROP_FROMHOST;
593 	} else if(!strcasecmp((char*) pName, "fromhost-ip")) {
594 		*pPropID = PROP_FROMHOST_IP;
595 	} else if(!strcasecmp((char*) pName, "pri")) {
596 		*pPropID = PROP_PRI;
597 	} else if(!strcasecmp((char*) pName, "pri-text")) {
598 		*pPropID = PROP_PRI_TEXT;
599 	} else if(!strcasecmp((char*) pName, "iut")) {
600 		*pPropID = PROP_IUT;
601 	} else if(!strcasecmp((char*) pName, "syslogfacility")) {
602 		*pPropID = PROP_SYSLOGFACILITY;
603 	} else if(!strcasecmp((char*) pName, "syslogfacility-text")) {
604 		*pPropID = PROP_SYSLOGFACILITY_TEXT;
605 	} else if(!strcasecmp((char*) pName, "syslogseverity") || !strcasecmp((char*) pName, "syslogpriority")) {
606 		*pPropID = PROP_SYSLOGSEVERITY;
607 	} else if(!strcasecmp((char*) pName, "syslogseverity-text") ||
608 	!strcasecmp((char*) pName, "syslogpriority-text")) {
609 		*pPropID = PROP_SYSLOGSEVERITY_TEXT;
610 	} else if(!strcasecmp((char*) pName, "timegenerated")) {
611 		*pPropID = PROP_TIMEGENERATED;
612 	} else if(!strcasecmp((char*) pName, "programname")) {
613 		*pPropID = PROP_PROGRAMNAME;
614 	} else if(!strcasecmp((char*) pName, "protocol-version")) {
615 		*pPropID = PROP_PROTOCOL_VERSION;
616 	} else if(!strcasecmp((char*) pName, "structured-data")) {
617 		*pPropID = PROP_STRUCTURED_DATA;
618 	} else if(!strcasecmp((char*) pName, "app-name")) {
619 		*pPropID = PROP_APP_NAME;
620 	} else if(!strcasecmp((char*) pName, "procid")) {
621 		*pPropID = PROP_PROCID;
622 	} else if(!strcasecmp((char*) pName, "msgid")) {
623 		*pPropID = PROP_MSGID;
624 	} else if(!strcasecmp((char*) pName, "jsonmesg")) {
625 		*pPropID = PROP_JSONMESG;
626 	} else if(!strcasecmp((char*) pName, "parsesuccess")) {
627 		*pPropID = PROP_PARSESUCCESS;
628 #ifdef USE_LIBUUID
629 	} else if(!strcasecmp((char*) pName, "uuid")) {
630 		*pPropID = PROP_UUID;
631 #endif
632 	/* here start system properties (those, that do not relate to the message itself */
633 	} else if(!strcasecmp((char*) pName, "$NOW")) {
634 		*pPropID = PROP_SYS_NOW;
635 	} else if(!strcasecmp((char*) pName, "$YEAR")) {
636 		*pPropID = PROP_SYS_YEAR;
637 	} else if(!strcasecmp((char*) pName, "$MONTH")) {
638 		*pPropID = PROP_SYS_MONTH;
639 	} else if(!strcasecmp((char*) pName, "$DAY")) {
640 		*pPropID = PROP_SYS_DAY;
641 	} else if(!strcasecmp((char*) pName, "$HOUR")) {
642 		*pPropID = PROP_SYS_HOUR;
643 	} else if(!strcasecmp((char*) pName, "$HHOUR")) {
644 		*pPropID = PROP_SYS_HHOUR;
645 	} else if(!strcasecmp((char*) pName, "$QHOUR")) {
646 		*pPropID = PROP_SYS_QHOUR;
647 	} else if(!strcasecmp((char*) pName, "$MINUTE")) {
648 		*pPropID = PROP_SYS_MINUTE;
649 	} else if(!strcasecmp((char*) pName, "$WDAY")) {
650 		*pPropID = PROP_SYS_WDAY;
651 	} else if(!strcasecmp((char*) pName, "$now-utc")) {
652 		*pPropID = PROP_SYS_NOW_UTC;
653 	} else if(!strcasecmp((char*) pName, "$year-utc")) {
654 		*pPropID = PROP_SYS_YEAR_UTC;
655 	} else if(!strcasecmp((char*) pName, "$month-utc")) {
656 		*pPropID = PROP_SYS_MONTH_UTC;
657 	} else if(!strcasecmp((char*) pName, "$day-utc")) {
658 		*pPropID = PROP_SYS_DAY_UTC;
659 	} else if(!strcasecmp((char*) pName, "$hour-utc")) {
660 		*pPropID = PROP_SYS_HOUR_UTC;
661 	} else if(!strcasecmp((char*) pName, "$hhour-utc")) {
662 		*pPropID = PROP_SYS_HHOUR_UTC;
663 	} else if(!strcasecmp((char*) pName, "$qhour-utc")) {
664 		*pPropID = PROP_SYS_QHOUR_UTC;
665 	} else if(!strcasecmp((char*) pName, "$minute-utc")) {
666 		*pPropID = PROP_SYS_MINUTE_UTC;
667 	} else if(!strcasecmp((char*) pName, "$wday-utc")) {
668 		*pPropID = PROP_SYS_WDAY_UTC;
669 	} else if(!strcasecmp((char*) pName, "$now-unixtimestamp")) {
670 		*pPropID = PROP_SYS_NOW_UXTIMESTAMP;
671 	} else if(!strcasecmp((char*) pName, "$MYHOSTNAME")) {
672 		*pPropID = PROP_SYS_MYHOSTNAME;
673 	} else if(!strcasecmp((char*) pName, "$!all-json")) {
674 		*pPropID = PROP_CEE_ALL_JSON;
675 	} else if(!strcasecmp((char*) pName, "$!all-json-plain")) {
676 		*pPropID = PROP_CEE_ALL_JSON_PLAIN;
677 	} else if(!strcasecmp((char*) pName, "$BOM")) {
678 		*pPropID = PROP_SYS_BOM;
679 	} else if(!strcasecmp((char*) pName, "$UPTIME")) {
680 		*pPropID = PROP_SYS_UPTIME;
681 	} else if(!strncmp((char*) pName, "$!", 2) || pName[0] == '!') {
682 		*pPropID = PROP_CEE;
683 	} else if(!strncmp((char*) pName, "$.", 2) || pName[0] == '.') {
684 		*pPropID = PROP_LOCAL_VAR;
685 	} else if(!strncmp((char*) pName, "$/", 2) || pName[0] == '/') {
686 		*pPropID = PROP_GLOBAL_VAR;
687 	} else {
688 		DBGPRINTF("PROP_INVALID for name '%s'\n", pName);
689 		*pPropID = PROP_INVALID;
690 		iRet = RS_RET_VAR_NOT_FOUND;
691 	}
692 
693 	RETiRet;
694 }
695 
696 
697 /* map a property ID to a name string (useful for displaying) */
propIDToName(propid_t propID)698 uchar *propIDToName(propid_t propID)
699 {
700 	switch(propID) {
701 		case PROP_MSG:
702 			return UCHAR_CONSTANT("msg");
703 		case PROP_TIMESTAMP:
704 			return UCHAR_CONSTANT("timestamp");
705 		case PROP_HOSTNAME:
706 			return UCHAR_CONSTANT("hostname");
707 		case PROP_SYSLOGTAG:
708 			return UCHAR_CONSTANT("syslogtag");
709 		case PROP_RAWMSG:
710 			return UCHAR_CONSTANT("rawmsg");
711 		case PROP_RAWMSG_AFTER_PRI:
712 			return UCHAR_CONSTANT("rawmsg-after-pri");
713 		case PROP_INPUTNAME:
714 			return UCHAR_CONSTANT("inputname");
715 		case PROP_FROMHOST:
716 			return UCHAR_CONSTANT("fromhost");
717 		case PROP_FROMHOST_IP:
718 			return UCHAR_CONSTANT("fromhost-ip");
719 		case PROP_PRI:
720 			return UCHAR_CONSTANT("pri");
721 		case PROP_PRI_TEXT:
722 			return UCHAR_CONSTANT("pri-text");
723 		case PROP_IUT:
724 			return UCHAR_CONSTANT("iut");
725 		case PROP_SYSLOGFACILITY:
726 			return UCHAR_CONSTANT("syslogfacility");
727 		case PROP_SYSLOGFACILITY_TEXT:
728 			return UCHAR_CONSTANT("syslogfacility-text");
729 		case PROP_SYSLOGSEVERITY:
730 			return UCHAR_CONSTANT("syslogseverity");
731 		case PROP_SYSLOGSEVERITY_TEXT:
732 			return UCHAR_CONSTANT("syslogseverity-text");
733 		case PROP_TIMEGENERATED:
734 			return UCHAR_CONSTANT("timegenerated");
735 		case PROP_PROGRAMNAME:
736 			return UCHAR_CONSTANT("programname");
737 		case PROP_PROTOCOL_VERSION:
738 			return UCHAR_CONSTANT("protocol-version");
739 		case PROP_STRUCTURED_DATA:
740 			return UCHAR_CONSTANT("structured-data");
741 		case PROP_APP_NAME:
742 			return UCHAR_CONSTANT("app-name");
743 		case PROP_PROCID:
744 			return UCHAR_CONSTANT("procid");
745 		case PROP_MSGID:
746 			return UCHAR_CONSTANT("msgid");
747 		case PROP_JSONMESG:
748 			return UCHAR_CONSTANT("jsonmesg");
749 		case PROP_PARSESUCCESS:
750 			return UCHAR_CONSTANT("parsesuccess");
751 #ifdef USE_LIBUUID
752 		case PROP_UUID:
753 			return UCHAR_CONSTANT("uuid");
754 #endif
755 		case PROP_SYS_NOW:
756 			return UCHAR_CONSTANT("$NOW");
757 		case PROP_SYS_YEAR:
758 			return UCHAR_CONSTANT("$YEAR");
759 		case PROP_SYS_MONTH:
760 			return UCHAR_CONSTANT("$MONTH");
761 		case PROP_SYS_DAY:
762 			return UCHAR_CONSTANT("$DAY");
763 		case PROP_SYS_HOUR:
764 			return UCHAR_CONSTANT("$HOUR");
765 		case PROP_SYS_HHOUR:
766 			return UCHAR_CONSTANT("$HHOUR");
767 		case PROP_SYS_QHOUR:
768 			return UCHAR_CONSTANT("$QHOUR");
769 		case PROP_SYS_MINUTE:
770 			return UCHAR_CONSTANT("$MINUTE");
771 		case PROP_SYS_NOW_UTC:
772 			return UCHAR_CONSTANT("$NOW-UTC");
773 		case PROP_SYS_YEAR_UTC:
774 			return UCHAR_CONSTANT("$YEAR-UTC");
775 		case PROP_SYS_MONTH_UTC:
776 			return UCHAR_CONSTANT("$MONTH-UTC");
777 		case PROP_SYS_DAY_UTC:
778 			return UCHAR_CONSTANT("$DAY-UTC");
779 		case PROP_SYS_HOUR_UTC:
780 			return UCHAR_CONSTANT("$HOUR-UTC");
781 		case PROP_SYS_HHOUR_UTC:
782 			return UCHAR_CONSTANT("$HHOUR-UTC");
783 		case PROP_SYS_QHOUR_UTC:
784 			return UCHAR_CONSTANT("$QHOUR-UTC");
785 		case PROP_SYS_MINUTE_UTC:
786 			return UCHAR_CONSTANT("$MINUTE-UTC");
787 		case PROP_SYS_WDAY:
788 			return UCHAR_CONSTANT("$WDAY");
789 		case PROP_SYS_WDAY_UTC:
790 			return UCHAR_CONSTANT("$WDAY-UTC");
791 		case PROP_SYS_NOW_UXTIMESTAMP:
792 			return UCHAR_CONSTANT("$NOW-UNIXTIMESTAMP");
793 		case PROP_SYS_MYHOSTNAME:
794 			return UCHAR_CONSTANT("$MYHOSTNAME");
795 		case PROP_CEE_ALL_JSON:
796 			return UCHAR_CONSTANT("$!all-json");
797 		case PROP_CEE_ALL_JSON_PLAIN:
798 			return UCHAR_CONSTANT("$!all-json-plain");
799 		case PROP_SYS_BOM:
800 			return UCHAR_CONSTANT("$BOM");
801 		case PROP_SYS_UPTIME:
802 			return UCHAR_CONSTANT("$UPTIME");
803 		case PROP_CEE:
804 			return UCHAR_CONSTANT("*CEE-based property*");
805 		case PROP_LOCAL_VAR:
806 			return UCHAR_CONSTANT("*LOCAL_VARIABLE*");
807 		case PROP_GLOBAL_VAR:
808 			return UCHAR_CONSTANT("*GLOBAL_VARIABLE*");
809 		default:
810 			return UCHAR_CONSTANT("*invalid property id*");
811 	}
812 }
813 
814 
815 /* This is common code for all Constructors. It is defined in an
816  * inline'able function so that we can save a function call in the
817  * actual constructors (otherwise, the msgConstruct would need
818  * to call msgConstructWithTime(), which would require a
819  * function call). Now, both can use this inline function. This
820  * enables us to be optimal, but still have the code just once.
821  * the new object or NULL if no such object could be allocated.
822  * An object constructed via this function should only be destroyed
823  * via "msgDestruct()". This constructor does not query system time
824  * itself but rather uses a user-supplied value. This enables the caller
825  * to do some tricks to save processing time (done, for example, in the
826  * udp input).
827  * NOTE: this constructor does NOT call calloc(), as we have many bytes
828  * inside the structure which do not need to be cleared. bzero() will
829  * heavily thrash the cache, so we do the init manually (which also
830  * is the right thing to do with pointers, as they are not neccessarily
831  * a binary 0 on all machines [but today almost always...]).
832  * rgerhards, 2008-10-06
833  */
834 static rsRetVal
msgBaseConstruct(smsg_t ** ppThis)835 msgBaseConstruct(smsg_t **ppThis)
836 {
837 	DEFiRet;
838 	smsg_t *pM;
839 
840 	assert(ppThis != NULL);
841 	CHKmalloc(pM = malloc(sizeof(smsg_t)));
842 	objConstructSetObjInfo(pM); /* intialize object helper entities */
843 
844 	/* initialize members in ORDER they appear in structure (think "cache line"!) */
845 	pM->flowCtlType = 0;
846 	pM->bParseSuccess = 0;
847 	pM->iRefCount = 1;
848 	pM->iSeverity = LOG_DEBUG;
849 	pM->iFacility = LOG_INVLD;
850 	pM->iLenPROGNAME = -1;
851 	pM->offAfterPRI = 0;
852 	pM->offMSG = -1;
853 	pM->iProtocolVersion = 0;
854 	pM->msgFlags = 0;
855 	pM->iLenRawMsg = 0;
856 	pM->iLenMSG = 0;
857 	pM->iLenTAG = 0;
858 	pM->iLenHOSTNAME = 0;
859 	pM->pszRawMsg = NULL;
860 	pM->pszHOSTNAME = NULL;
861 	pM->pszRcvdAt3164 = NULL;
862 	pM->pszRcvdAt3339 = NULL;
863 	pM->pszRcvdAt_MySQL = NULL;
864 	pM->pszRcvdAt_PgSQL = NULL;
865 	pM->pszTIMESTAMP3164 = NULL;
866 	pM->pszTIMESTAMP3339 = NULL;
867 	pM->pszTIMESTAMP_MySQL = NULL;
868 	pM->pszTIMESTAMP_PgSQL = NULL;
869 	pM->pszStrucData = NULL;
870 	pM->lenStrucData = 0;
871 	pM->pCSAPPNAME = NULL;
872 	pM->pCSPROCID = NULL;
873 	pM->pCSMSGID = NULL;
874 	pM->pInputName = NULL;
875 	pM->pRcvFromIP = NULL;
876 	pM->rcvFrom.pRcvFrom = NULL;
877 	pM->pRuleset = NULL;
878 	pM->json = NULL;
879 	pM->localvars = NULL;
880 	pM->dfltTZ[0] = '\0';
881 	memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt));
882 	memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP));
883 	pM->TAG.pszTAG = NULL;
884 	pM->pszTimestamp3164[0] = '\0';
885 	pM->pszTimestamp3339[0] = '\0';
886 	pM->pszTIMESTAMP_SecFrac[0] = '\0';
887 	pM->pszRcvdAt_SecFrac[0] = '\0';
888 	pM->pszTIMESTAMP_Unix[0] = '\0';
889 	pM->pszRcvdAt_Unix[0] = '\0';
890 	pM->pszUUID = NULL;
891 	pthread_mutex_init(&pM->mut, NULL);
892 
893 	#if DEV_DEBUG == 1
894 	dbgprintf("msgConstruct\t0x%x, ref 1\n", (int)pM);
895 	#endif
896 
897 	*ppThis = pM;
898 
899 finalize_it:
900 	RETiRet;
901 }
902 
903 
904 /* "Constructor" for a msg "object". Returns a pointer to
905  * the new object or NULL if no such object could be allocated.
906  * An object constructed via this function should only be destroyed
907  * via "msgDestruct()". This constructor does not query system time
908  * itself but rather uses a user-supplied value. This enables the caller
909  * to do some tricks to save processing time (done, for example, in the
910  * udp input).
911  * rgerhards, 2008-10-06
912  */
msgConstructWithTime(smsg_t ** ppThis,const struct syslogTime * stTime,const time_t ttGenTime)913 rsRetVal msgConstructWithTime(smsg_t **ppThis, const struct syslogTime *stTime, const time_t ttGenTime)
914 {
915 	DEFiRet;
916 
917 	CHKiRet(msgBaseConstruct(ppThis));
918 	(*ppThis)->ttGenTime = ttGenTime;
919 	memcpy(&(*ppThis)->tRcvdAt, stTime, sizeof(struct syslogTime));
920 	memcpy(&(*ppThis)->tTIMESTAMP, stTime, sizeof(struct syslogTime));
921 
922 finalize_it:
923 	RETiRet;
924 }
925 
926 
927 /* "Constructor" for a msg "object". Returns a pointer to
928  * the new object or NULL if no such object could be allocated.
929  * An object constructed via this function should only be destroyed
930  * via "msgDestruct()". This constructor, for historical reasons,
931  * also sets the two timestamps to the current time.
932  */
msgConstruct(smsg_t ** ppThis)933 rsRetVal msgConstruct(smsg_t **ppThis)
934 {
935 	DEFiRet;
936 
937 	CHKiRet(msgBaseConstruct(ppThis));
938 	/* we initialize both timestamps to contain the current time, so that they
939 	 * are consistent. Also, this saves us from doing any further time calls just
940 	 * to obtain a timestamp. The memcpy() should not really make a difference,
941 	 * especially as I think there is no codepath currently where it would not be
942 	 * required (after I have cleaned up the pathes ;)). -- rgerhards, 2008-10-02
943 	 */
944 	datetime.getCurrTime(&((*ppThis)->tRcvdAt), &((*ppThis)->ttGenTime), TIME_IN_LOCALTIME);
945 	memcpy(&(*ppThis)->tTIMESTAMP, &(*ppThis)->tRcvdAt, sizeof(struct syslogTime));
946 
947 finalize_it:
948 	RETiRet;
949 }
950 
951 
952 /* Special msg constructor, to be used when an object is deserialized.
953  * we do only the base init as we know the properties will be set in
954  * any case by the deserializer. We still do the "inexpensive" inits
955  * just to be on the safe side. The whole process needs to be
956  * refactored together with the msg serialization subsystem.
957  */
958 rsRetVal
msgConstructForDeserializer(smsg_t ** ppThis)959 msgConstructForDeserializer(smsg_t **ppThis)
960 {
961 	return msgBaseConstruct(ppThis);
962 }
963 
964 
965 /* some free handlers for (slightly) complicated cases... All of them may be called
966  * with an empty element.
967  */
freeTAG(smsg_t * pThis)968 static inline void freeTAG(smsg_t *pThis)
969 {
970 	if(pThis->iLenTAG >= CONF_TAG_BUFSIZE)
971 		free(pThis->TAG.pszTAG);
972 }
freeHOSTNAME(smsg_t * pThis)973 static inline void freeHOSTNAME(smsg_t *pThis)
974 {
975 	if(pThis->iLenHOSTNAME >= CONF_HOSTNAME_BUFSIZE)
976 		free(pThis->pszHOSTNAME);
977 }
978 
979 
msgDestruct(smsg_t ** ppThis)980 rsRetVal msgDestruct(smsg_t **ppThis)
981 {
982 	DEFiRet;
983 	smsg_t *pThis;
984 	int currRefCount;
985 #	ifdef HAVE_MALLOC_TRIM
986 	int currCnt;
987 #	endif
988 CODESTARTobjDestruct(msg)
989 	#if DEV_DEBUG == 1
990 	dbgprintf("msgDestruct\t0x%lx, "
991 		"Ref now: %d\n", (unsigned long)pThis, pThis->iRefCount - 1);
992 	#endif
993 #	ifdef HAVE_ATOMIC_BUILTINS
994 		currRefCount = ATOMIC_DEC_AND_FETCH(&pThis->iRefCount, NULL);
995 #	else
996 		MsgLock(pThis);
997 		currRefCount = --pThis->iRefCount;
998 # 	endif
999 	if(currRefCount == 0)
1000 	{
1001 		#if DEV_DEBUG == 1
1002 		dbgprintf("msgDestruct\t0x%lx, RefCount now 0, doing DESTROY\n",
1003 			(unsigned long)pThis);
1004 		#endif
1005 		if(pThis->pszRawMsg != pThis->szRawMsg)
1006 			free(pThis->pszRawMsg);
1007 		freeTAG(pThis);
1008 		freeHOSTNAME(pThis);
1009 		if(pThis->pInputName != NULL)
1010 			prop.Destruct(&pThis->pInputName);
1011 		if((pThis->msgFlags & NEEDS_DNSRESOL) == 0) {
1012 			if(pThis->rcvFrom.pRcvFrom != NULL)
1013 				prop.Destruct(&pThis->rcvFrom.pRcvFrom);
1014 		} else {
1015 			free(pThis->rcvFrom.pfrominet);
1016 		}
1017 		if(pThis->pRcvFromIP != NULL)
1018 			prop.Destruct(&pThis->pRcvFromIP);
1019 		free(pThis->pszRcvdAt3164);
1020 		free(pThis->pszRcvdAt3339);
1021 		free(pThis->pszRcvdAt_MySQL);
1022 		free(pThis->pszRcvdAt_PgSQL);
1023 		free(pThis->pszTIMESTAMP_MySQL);
1024 		free(pThis->pszTIMESTAMP_PgSQL);
1025 		free(pThis->pszStrucData);
1026 		if(pThis->iLenPROGNAME >= CONF_PROGNAME_BUFSIZE)
1027 			free(pThis->PROGNAME.ptr);
1028 		if(pThis->pCSAPPNAME != NULL)
1029 			rsCStrDestruct(&pThis->pCSAPPNAME);
1030 		if(pThis->pCSPROCID != NULL)
1031 			rsCStrDestruct(&pThis->pCSPROCID);
1032 		if(pThis->pCSMSGID != NULL)
1033 			rsCStrDestruct(&pThis->pCSMSGID);
1034 		if(pThis->json != NULL)
1035 			json_object_put(pThis->json);
1036 		if(pThis->localvars != NULL)
1037 			json_object_put(pThis->localvars);
1038 		if(pThis->pszUUID != NULL)
1039 			free(pThis->pszUUID);
1040 #	ifndef HAVE_ATOMIC_BUILTINS
1041 		MsgUnlock(pThis);
1042 # 	endif
1043 		pthread_mutex_destroy(&pThis->mut);
1044 		/* now we need to do our own optimization. Testing has shown that at least the glibc
1045 		 * malloc() subsystem returns memory to the OS far too late in our case. So we need
1046 		 * to help it a bit, by calling malloc_trim(), which will tell the alloc subsystem
1047 		 * to consolidate and return to the OS. We keep 128K for our use, as a safeguard
1048 		 * to too-frequent reallocs. But more importantly, we call this hook only every
1049 		 * 100,000 messages (which is an approximation, as we do not work with atomic
1050 		 * operations on the counter. --- rgerhards, 2009-06-22.
1051 		 */
1052 #		ifdef HAVE_MALLOC_TRIM
1053 		{	/* standard C requires a new block for a new variable definition!
1054 			 * To simplify matters, we use modulo arithmetic and live with the fact
1055 			 * that we trim too often when the counter wraps.
1056 			 */
1057 			static unsigned iTrimCtr = 1;
1058 			currCnt = ATOMIC_INC_AND_FETCH_unsigned(&iTrimCtr, &mutTrimCtr);
1059 			if(currCnt % 100000 == 0) {
1060 				malloc_trim(128*1024);
1061 			}
1062 		}
1063 #		endif
1064 	} else {
1065 #	ifndef HAVE_ATOMIC_BUILTINS
1066 		MsgUnlock(pThis);
1067 # 	endif
1068 		pThis = NULL; /* tell framework not to destructing the object! */
1069 	}
1070 ENDobjDestruct(msg)
1071 
1072 /* The macros below are used in MsgDup(). I use macros
1073  * to keep the fuction code somewhat more readyble. It is my
1074  * replacement for inline functions in CPP
1075  */
1076 #define tmpCOPYSZ(name) \
1077 	if(pOld->psz##name != NULL) { \
1078 		if((pNew->psz##name = srUtilStrDup(pOld->psz##name, pOld->iLen##name)) == NULL) {\
1079 			msgDestruct(&pNew);\
1080 			return NULL;\
1081 		}\
1082 		pNew->iLen##name = pOld->iLen##name;\
1083 	}
1084 
1085 /* copy the CStr objects.
1086  * if the old value is NULL, we do not need to do anything because we
1087  * initialized the new value to NULL via calloc().
1088  */
1089 #define tmpCOPYCSTR(name) \
1090 	if(pOld->pCS##name != NULL) {\
1091 		if(rsCStrConstructFromCStr(&(pNew->pCS##name), pOld->pCS##name) != RS_RET_OK) {\
1092 			msgDestruct(&pNew);\
1093 			return NULL;\
1094 		}\
1095 		cstrFinalize(pNew->pCS##name); \
1096 	}
1097 /* Constructs a message object by duplicating another one.
1098  * Returns NULL if duplication failed. We do not need to lock the
1099  * message object here, because a fully-created msg object is never
1100  * allowed to be manipulated. For this, MsgDup() must be used, so MsgDup()
1101  * can never run into a situation where the message object is being
1102  * modified while its content is copied - it's forbidden by definition.
1103  * rgerhards, 2007-07-10
1104  */
1105 smsg_t* MsgDup(smsg_t* pOld)
1106 {
1107 	smsg_t* pNew;
1108 	rsRetVal localRet;
1109 
1110 	assert(pOld != NULL);
1111 
1112 	if(msgConstructWithTime(&pNew, &pOld->tTIMESTAMP, pOld->ttGenTime) != RS_RET_OK) {
1113 		return NULL;
1114 	}
1115 
1116 	/* now copy the message properties */
1117 	pNew->iRefCount = 1;
1118 	pNew->iSeverity = pOld->iSeverity;
1119 	pNew->iFacility = pOld->iFacility;
1120 	pNew->msgFlags = pOld->msgFlags;
1121 	pNew->iProtocolVersion = pOld->iProtocolVersion;
1122 	pNew->tRcvdAt = pOld->tRcvdAt;
1123 	pNew->offMSG = pOld->offMSG;
1124 	pNew->iLenRawMsg = pOld->iLenRawMsg;
1125 	pNew->iLenMSG = pOld->iLenMSG;
1126 	pNew->iLenTAG = pOld->iLenTAG;
1127 	pNew->iLenHOSTNAME = pOld->iLenHOSTNAME;
1128 	if((pOld->msgFlags & NEEDS_DNSRESOL)) {
1129 			localRet = msgSetFromSockinfo(pNew, pOld->rcvFrom.pfrominet);
1130 			if(localRet != RS_RET_OK) {
1131 				/* if something fails, we accept loss of this property, it is
1132 				 * better than losing the whole message.
1133 				 */
1134 				pNew->msgFlags &= ~NEEDS_DNSRESOL;
1135 				pNew->rcvFrom.pRcvFrom = NULL; /* make sure no dangling values */
1136 			}
1137 	} else {
1138 		if(pOld->rcvFrom.pRcvFrom != NULL) {
1139 			pNew->rcvFrom.pRcvFrom = pOld->rcvFrom.pRcvFrom;
1140 			prop.AddRef(pNew->rcvFrom.pRcvFrom);
1141 		}
1142 	}
1143 	if(pOld->pRcvFromIP != NULL) {
1144 		pNew->pRcvFromIP = pOld->pRcvFromIP;
1145 		prop.AddRef(pNew->pRcvFromIP);
1146 	}
1147 	if(pOld->pInputName != NULL) {
1148 		pNew->pInputName = pOld->pInputName;
1149 		prop.AddRef(pNew->pInputName);
1150 	}
1151 	if(pOld->iLenTAG > 0) {
1152 		if(pOld->iLenTAG < CONF_TAG_BUFSIZE) {
1153 			memcpy(pNew->TAG.szBuf, pOld->TAG.szBuf, pOld->iLenTAG + 1);
1154 		} else {
1155 			if((pNew->TAG.pszTAG = srUtilStrDup(pOld->TAG.pszTAG, pOld->iLenTAG)) == NULL) {
1156 				msgDestruct(&pNew);
1157 				return NULL;
1158 			}
1159 			pNew->iLenTAG = pOld->iLenTAG;
1160 		}
1161 	}
1162 	if(pOld->pszRawMsg == pOld->szRawMsg) {
1163 		memcpy(pNew->szRawMsg, pOld->szRawMsg, pOld->iLenRawMsg + 1);
1164 		pNew->pszRawMsg = pNew->szRawMsg;
1165 	} else {
1166 		tmpCOPYSZ(RawMsg);
1167 	}
1168 	if(pOld->pszHOSTNAME == NULL) {
1169 		pNew->pszHOSTNAME = NULL;
1170 	} else {
1171 		if(pOld->iLenHOSTNAME < CONF_HOSTNAME_BUFSIZE) {
1172 			memcpy(pNew->szHOSTNAME, pOld->szHOSTNAME, pOld->iLenHOSTNAME + 1);
1173 			pNew->pszHOSTNAME = pNew->szHOSTNAME;
1174 		} else {
1175 			tmpCOPYSZ(HOSTNAME);
1176 		}
1177 	}
1178 	if(pOld->pszStrucData == NULL) {
1179 		pNew->pszStrucData = NULL;
1180 	} else {
1181 		pNew->pszStrucData = (uchar*)strdup((char*)pOld->pszStrucData);
1182 		pNew->lenStrucData = pOld->lenStrucData;
1183 	}
1184 
1185 	tmpCOPYCSTR(APPNAME);
1186 	tmpCOPYCSTR(PROCID);
1187 	tmpCOPYCSTR(MSGID);
1188 
1189 	if(pOld->json != NULL)
1190 		pNew->json = jsonDeepCopy(pOld->json);
1191 	if(pOld->localvars != NULL)
1192 		pNew->localvars = jsonDeepCopy(pOld->localvars);
1193 
1194 	/* we do not copy all other cache properties, as we do not even know
1195 	 * if they are needed once again. So we let them re-create if needed.
1196 	 */
1197 
1198 	return pNew;
1199 }
1200 #undef tmpCOPYSZ
1201 #undef tmpCOPYCSTR
1202 
1203 
1204 /* This method serializes a message object. That means the whole
1205  * object is modified into text form. That text form is suitable for
1206  * later reconstruction of the object by calling MsgDeSerialize().
1207  * The most common use case for this method is the creation of an
1208  * on-disk representation of the message object.
1209  * We do not serialize the cache properties. We re-create them when needed.
1210  * This saves us a lot of memory. Performance is no concern, as serializing
1211  * is a so slow operation that recration of the caches does not count. Also,
1212  * we do not serialize --currently none--, as this is only a helper variable
1213  * during msg construction - and never again used later.
1214  * rgerhards, 2008-01-03
1215  */
1216 static rsRetVal MsgSerialize(smsg_t *pThis, strm_t *pStrm)
1217 {
1218 	uchar *psz;
1219 	int len;
1220 	DEFiRet;
1221 
1222 	assert(pThis != NULL);
1223 	assert(pStrm != NULL);
1224 
1225 	/* then serialize elements */
1226 	CHKiRet(obj.BeginSerialize(pStrm, (obj_t*) pThis));
1227 	objSerializeSCALAR(pStrm, iProtocolVersion, SHORT);
1228 	objSerializeSCALAR(pStrm, iSeverity, SHORT);
1229 	objSerializeSCALAR(pStrm, iFacility, SHORT);
1230 	objSerializeSCALAR(pStrm, msgFlags, INT);
1231 	objSerializeSCALAR(pStrm, ttGenTime, INT);
1232 	objSerializeSCALAR(pStrm, tRcvdAt, SYSLOGTIME);
1233 	objSerializeSCALAR(pStrm, tTIMESTAMP, SYSLOGTIME);
1234 
1235 	CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszTAG"), PROPTYPE_PSZ, (void*)
1236 		((pThis->iLenTAG < CONF_TAG_BUFSIZE) ? pThis->TAG.szBuf : pThis->TAG.pszTAG)));
1237 
1238 	objSerializePTR(pStrm, pszRawMsg, PSZ);
1239 	objSerializePTR(pStrm, pszHOSTNAME, PSZ);
1240 	getInputName(pThis, &psz, &len);
1241 	CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszInputName"), PROPTYPE_PSZ, (void*) psz));
1242 	psz = getRcvFrom(pThis);
1243 	CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFrom"), PROPTYPE_PSZ, (void*) psz));
1244 	psz = getRcvFromIP(pThis);
1245 	CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFromIP"), PROPTYPE_PSZ, (void*) psz));
1246 	psz = pThis->pszStrucData;
1247 	CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszStrucData"), PROPTYPE_PSZ, (void*) psz));
1248 	if(pThis->json != NULL) {
1249 		MsgLock(pThis);
1250 		psz = (uchar*) json_object_get_string(pThis->json);
1251 		MsgUnlock(pThis);
1252 		CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("json"), PROPTYPE_PSZ, (void*) psz));
1253 	}
1254 	if(pThis->localvars != NULL) {
1255 		MsgLock(pThis);
1256 		psz = (uchar*) json_object_get_string(pThis->localvars);
1257 		MsgUnlock(pThis);
1258 		CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("localvars"), PROPTYPE_PSZ, (void*) psz));
1259 	}
1260 
1261 	objSerializePTR(pStrm, pCSAPPNAME, CSTR);
1262 	objSerializePTR(pStrm, pCSPROCID, CSTR);
1263 	objSerializePTR(pStrm, pCSMSGID, CSTR);
1264 
1265 	objSerializePTR(pStrm, pszUUID, PSZ);
1266 
1267 	if(pThis->pRuleset != NULL) {
1268 		CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRuleset"), PROPTYPE_PSZ,
1269 			rulesetGetName(pThis->pRuleset)));
1270 	}
1271 
1272 	/* offset must be serialized after pszRawMsg, because we need that to obtain the correct
1273 	 * MSG size.
1274 	 */
1275 	objSerializeSCALAR(pStrm, offMSG, INT);
1276 
1277 	CHKiRet(obj.EndSerialize(pStrm));
1278 
1279 finalize_it:
1280 	RETiRet;
1281 }
1282 
1283 
1284 /* This is a helper for MsgDeserialize that re-inits the var object. This
1285  * whole construct should be replaced, var is really ready to be retired.
1286  * But as an interim help during refactoring let's introduce this function
1287  * here (and thus NOT as method of var object!). -- rgerhads, 2012-11-06
1288  */
1289 static void
1290 reinitVar(var_t *pVar)
1291 {
1292 	rsCStrDestruct(&pVar->pcsName); /* no longer needed */
1293 	if(pVar->varType == VARTYPE_STR) {
1294 		if(pVar->val.pStr != NULL)
1295 			rsCStrDestruct(&pVar->val.pStr);
1296 	}
1297 }
1298 /* deserialize the message again
1299  * we deserialize the properties in the same order that we serialized them. Except
1300  * for some checks to cover downlevel version, we do not need to do all these
1301  * CPU intense name checkings.
1302  */
1303 #define isProp(name) !rsCStrSzStrCmp(pVar->pcsName, (uchar*) name, sizeof(name) - 1)
1304 rsRetVal
1305 MsgDeserialize(smsg_t * const pMsg, strm_t *pStrm)
1306 {
1307 	prop_t *myProp;
1308 	prop_t *propRcvFrom = NULL;
1309 	prop_t *propRcvFromIP = NULL;
1310 	struct json_tokener *tokener;
1311 	var_t *pVar = NULL;
1312 	DEFiRet;
1313 
1314 	ISOBJ_TYPE_assert(pStrm, strm);
1315 
1316 	CHKiRet(var.Construct(&pVar));
1317 	CHKiRet(var.ConstructFinalize(pVar));
1318 
1319 	CHKiRet(objDeserializeProperty(pVar, pStrm));
1320 	if(isProp("iProtocolVersion")) {
1321 		setProtocolVersion(pMsg, pVar->val.num);
1322 		reinitVar(pVar);
1323 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1324 	}
1325 	if(isProp("iSeverity")) {
1326 		pMsg->iSeverity = pVar->val.num;
1327 		reinitVar(pVar);
1328 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1329 	}
1330 	if(isProp("iFacility")) {
1331 		pMsg->iFacility = pVar->val.num;
1332 		reinitVar(pVar);
1333 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1334 	}
1335 	if(isProp("msgFlags")) {
1336 		pMsg->msgFlags = pVar->val.num;
1337 		reinitVar(pVar);
1338 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1339 	}
1340 	if(isProp("ttGenTime")) {
1341 		pMsg->ttGenTime = pVar->val.num;
1342 		reinitVar(pVar);
1343 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1344 	}
1345 	if(isProp("tRcvdAt")) {
1346 		memcpy(&pMsg->tRcvdAt, &pVar->val.vSyslogTime, sizeof(struct syslogTime));
1347 		reinitVar(pVar);
1348 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1349 	}
1350 	if(isProp("tTIMESTAMP")) {
1351 		memcpy(&pMsg->tTIMESTAMP, &pVar->val.vSyslogTime, sizeof(struct syslogTime));
1352 		reinitVar(pVar);
1353 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1354 	}
1355 	if(isProp("pszTAG")) {
1356 		MsgSetTAG(pMsg, rsCStrGetSzStrNoNULL(pVar->val.pStr), cstrLen(pVar->val.pStr));
1357 		reinitVar(pVar);
1358 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1359 	}
1360 	if(isProp("pszRawMsg")) {
1361 		MsgSetRawMsg(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr), cstrLen(pVar->val.pStr));
1362 		reinitVar(pVar);
1363 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1364 	}
1365 	if(isProp("pszHOSTNAME")) {
1366 		MsgSetHOSTNAME(pMsg, rsCStrGetSzStrNoNULL(pVar->val.pStr), rsCStrLen(pVar->val.pStr));
1367 		reinitVar(pVar);
1368 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1369 	}
1370 	if(isProp("pszInputName")) {
1371 		/* we need to create a property */
1372 		CHKiRet(prop.Construct(&myProp));
1373 		CHKiRet(prop.SetString(myProp, rsCStrGetSzStrNoNULL(pVar->val.pStr), rsCStrLen(pVar->val.pStr)));
1374 		CHKiRet(prop.ConstructFinalize(myProp));
1375 		MsgSetInputName(pMsg, myProp);
1376 		prop.Destruct(&myProp);
1377 		reinitVar(pVar);
1378 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1379 	}
1380 	if(isProp("pszRcvFrom")) {
1381 		MsgSetRcvFromStr(pMsg, rsCStrGetSzStrNoNULL(pVar->val.pStr), rsCStrLen(pVar->val.pStr), &propRcvFrom);
1382 		prop.Destruct(&propRcvFrom);
1383 		reinitVar(pVar);
1384 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1385 	}
1386 	if(isProp("pszRcvFromIP")) {
1387 		MsgSetRcvFromIPStr(pMsg, rsCStrGetSzStrNoNULL(pVar->val.pStr), rsCStrLen(pVar->val.pStr),
1388 			&propRcvFromIP);
1389 		prop.Destruct(&propRcvFromIP);
1390 		reinitVar(pVar);
1391 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1392 	}
1393 	if(isProp("pszStrucData")) {
1394 		MsgSetStructuredData(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr));
1395 		reinitVar(pVar);
1396 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1397 	}
1398 	if(isProp("json")) {
1399 		tokener = json_tokener_new();
1400 		pMsg->json = json_tokener_parse_ex(tokener, (char*)rsCStrGetSzStrNoNULL(pVar->val.pStr),
1401 					     cstrLen(pVar->val.pStr));
1402 		json_tokener_free(tokener);
1403 		reinitVar(pVar);
1404 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1405 	}
1406 	if(isProp("localvars")) {
1407 		tokener = json_tokener_new();
1408 		pMsg->localvars = json_tokener_parse_ex(tokener, (char*)rsCStrGetSzStrNoNULL(pVar->val.pStr),
1409 						        cstrLen(pVar->val.pStr));
1410 		json_tokener_free(tokener);
1411 		reinitVar(pVar);
1412 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1413 	}
1414 	if(isProp("pCSAPPNAME")) {
1415 		MsgSetAPPNAME(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr));
1416 		reinitVar(pVar);
1417 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1418 	}
1419 	if(isProp("pCSPROCID")) {
1420 		MsgSetPROCID(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr));
1421 		reinitVar(pVar);
1422 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1423 	}
1424 	if(isProp("pCSMSGID")) {
1425 		MsgSetMSGID(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr));
1426 		reinitVar(pVar);
1427 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1428 	}
1429 	if(isProp("pszUUID")) {
1430 		pMsg->pszUUID = ustrdup(rsCStrGetSzStrNoNULL(pVar->val.pStr));
1431 		reinitVar(pVar);
1432 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1433 	}
1434 	if(isProp("pszRuleset")) {
1435 		MsgSetRulesetByName(pMsg, pVar->val.pStr);
1436 		reinitVar(pVar);
1437 		CHKiRet(objDeserializeProperty(pVar, pStrm));
1438 	}
1439 	/* "offMSG" must always be our last field, so we use this as an
1440 	 * indicator if the sequence is correct. This is a bit questionable,
1441 	 * but on the other hand it works decently AND we will probably replace
1442 	 * the whole persisted format soon in any case. -- rgerhards, 2012-11-06
1443 	 */
1444 	if(!isProp("offMSG")) {
1445 		DBGPRINTF("error property: %s\n", rsCStrGetSzStrNoNULL(pVar->pcsName));
1446 		ABORT_FINALIZE(RS_RET_DS_PROP_SEQ_ERR);
1447 	}
1448 	MsgSetMSGoffs(pMsg, pVar->val.num);
1449 finalize_it:
1450 	if(pVar != NULL)
1451 		var.Destruct(&pVar);
1452 	if(Debug && iRet != RS_RET_OK) {
1453 		dbgprintf("MsgDeserialize error %d\n", iRet);
1454 	}
1455 	RETiRet;
1456 }
1457 #undef isProp
1458 
1459 
1460 /* Increment reference count - see description of the "msg"
1461  * structure for details. As a convenience to developers,
1462  * this method returns the msg pointer that is passed to it.
1463  * It is recommended that it is called as follows:
1464  *
1465  * pSecondMsgPointer = MsgAddRef(pOrgMsgPointer);
1466  */
1467 smsg_t *MsgAddRef(smsg_t * const pM)
1468 {
1469 	assert(pM != NULL);
1470 #	ifdef HAVE_ATOMIC_BUILTINS
1471 		ATOMIC_INC(&pM->iRefCount, NULL);
1472 #	else
1473 		MsgLock(pM);
1474 		pM->iRefCount++;
1475 		MsgUnlock(pM);
1476 #	endif
1477 	#if DEV_DEBUG == 1
1478 	dbgprintf("MsgAddRef\t0x%x done, Ref now: %d\n", (int)pM, pM->iRefCount);
1479 	#endif
1480 	return(pM);
1481 }
1482 
1483 
1484 /* This functions tries to aquire the PROCID from TAG. Its primary use is
1485  * when a legacy syslog message has been received and should be forwarded as
1486  * syslog-protocol (or the PROCID is requested for any other reason).
1487  * In legacy syslog, the PROCID is considered to be the character sequence
1488  * between the first [ and the first ]. This usually are digits only, but we
1489  * do not check that. However, if there is no closing ], we do not assume we
1490  * can obtain a PROCID. Take in mind that not every legacy syslog message
1491  * actually has a PROCID.
1492  * rgerhards, 2005-11-24
1493  * THIS MUST be called with the message lock locked.
1494  */
1495 static rsRetVal aquirePROCIDFromTAG(smsg_t * const pM)
1496 {
1497 	register int i;
1498 	uchar *pszTag;
1499 	DEFiRet;
1500 
1501 	assert(pM != NULL);
1502 
1503 	if(pM->pCSPROCID != NULL)
1504 		return RS_RET_OK; /* we are already done ;) */
1505 
1506 	if(msgGetProtocolVersion(pM) != 0)
1507 		return RS_RET_OK; /* we can only emulate if we have legacy format */
1508 
1509 	pszTag = (uchar*) ((pM->iLenTAG < CONF_TAG_BUFSIZE) ? pM->TAG.szBuf : pM->TAG.pszTAG);
1510 
1511 	/* find first '['... */
1512 	i = 0;
1513 	while((i < pM->iLenTAG) && (pszTag[i] != '['))
1514 		++i;
1515 	if(!(i < pM->iLenTAG))
1516 		return RS_RET_OK;	/* no [, so can not emulate... */
1517 
1518 	++i; /* skip '[' */
1519 
1520 	/* now obtain the PROCID string... */
1521 	CHKiRet(cstrConstruct(&pM->pCSPROCID));
1522 	while((i < pM->iLenTAG) && (pszTag[i] != ']')) {
1523 		CHKiRet(cstrAppendChar(pM->pCSPROCID, pszTag[i]));
1524 		++i;
1525 	}
1526 
1527 	if(!(i < pM->iLenTAG)) {
1528 		/* oops... it looked like we had a PROCID, but now it has
1529 		 * turned out this is not true. In this case, we need to free
1530 		 * the buffer and simply return. Note that this is NOT an error
1531 		 * case!
1532 		 */
1533 		cstrDestruct(&pM->pCSPROCID);
1534 		FINALIZE;
1535 	}
1536 
1537 	/* OK, finally we could obtain a PROCID. So let's use it ;) */
1538 	cstrFinalize(pM->pCSPROCID);
1539 
1540 finalize_it:
1541 	RETiRet;
1542 }
1543 
1544 
1545 /* Parse and set the "programname" for a given MSG object. Programname
1546  * is a BSD concept, it is the tag without any instance-specific information.
1547  * Precisely, the programname is terminated by either (whichever occurs first):
1548  * - end of tag
1549  * - nonprintable character
1550  * - ':'
1551  * - '['
1552  * - '/'
1553  * The above definition has been taken from the FreeBSD syslogd sources.
1554  *
1555  * The program name is not parsed by default, because it is infrequently-used.
1556  * IMPORTANT: A locked message object must be provided, else a crash will occur.
1557  * rgerhards, 2005-10-19
1558  */
1559 static rsRetVal
1560 aquireProgramName(smsg_t * const pM)
1561 {
1562 	int i;
1563 	uchar *pszTag, *pszProgName;
1564 	DEFiRet;
1565 
1566 	assert(pM != NULL);
1567 	pszTag = (uchar*) ((pM->iLenTAG < CONF_TAG_BUFSIZE) ? pM->TAG.szBuf : pM->TAG.pszTAG);
1568 	for(  i = 0
1569 	    ; (i < pM->iLenTAG) && isprint((int) pszTag[i])
1570 	      && (pszTag[i] != '\0') && (pszTag[i] != ':')
1571 	      && (pszTag[i] != '[')
1572 	      && (bPermitSlashInProgramname || (pszTag[i] != '/'))
1573 	    ; ++i)
1574 		; /* just search end of PROGNAME */
1575 	if(i < CONF_PROGNAME_BUFSIZE) {
1576 		pszProgName = pM->PROGNAME.szBuf;
1577 	} else {
1578 		CHKmalloc(pM->PROGNAME.ptr = malloc(i+1));
1579 		pszProgName = pM->PROGNAME.ptr;
1580 	}
1581 	memcpy((char*)pszProgName, (char*)pszTag, i);
1582 	pszProgName[i] = '\0';
1583 	pM->iLenPROGNAME = i;
1584 finalize_it:
1585 	RETiRet;
1586 }
1587 
1588 
1589 /* Access methods - dumb & easy, not a comment for each ;)
1590  */
1591 void setProtocolVersion(smsg_t * const pM, int iNewVersion)
1592 {
1593 	assert(pM != NULL);
1594 	if(iNewVersion != 0 && iNewVersion != 1) {
1595 		dbgprintf("Tried to set unsupported protocol version %d - changed to 0.\n", iNewVersion);
1596 		iNewVersion = 0;
1597 	}
1598 	pM->iProtocolVersion = iNewVersion;
1599 }
1600 
1601 /* note: string is taken from constant pool, do NOT free */
1602 static const char *getProtocolVersionString(smsg_t * const pM)
1603 {
1604 	assert(pM != NULL);
1605 	return(pM->iProtocolVersion ? "1" : "0");
1606 }
1607 
1608 void
1609 msgSetPRI(smsg_t *const __restrict__ pMsg, syslog_pri_t pri)
1610 {
1611 	if(pri > LOG_MAXPRI)
1612 		pri = LOG_PRI_INVLD;
1613 	pMsg->iFacility = pri2fac(pri),
1614 	pMsg->iSeverity = pri2sev(pri);
1615 }
1616 
1617 #ifdef USE_LIBUUID
1618 /* note: libuuid seems not to be thread-safe, so we need
1619  * to get some safeguards in place.
1620  */
1621 static void msgSetUUID(smsg_t * const pM)
1622 {
1623 	size_t lenRes = sizeof(uuid_t) * 2 + 1;
1624 	char hex_char [] = "0123456789ABCDEF";
1625 	unsigned int byte_nbr;
1626 	uuid_t uuid;
1627 	static pthread_mutex_t mutUUID = PTHREAD_MUTEX_INITIALIZER;
1628 
1629 	dbgprintf("[MsgSetUUID] START, lenRes %llu\n", (long long unsigned) lenRes);
1630 	assert(pM != NULL);
1631 
1632 	if((pM->pszUUID = (uchar*) malloc(lenRes)) == NULL) {
1633 		pM->pszUUID = (uchar *)"";
1634 	} else {
1635 		pthread_mutex_lock(&mutUUID);
1636 		uuid_generate(uuid);
1637 		pthread_mutex_unlock(&mutUUID);
1638 		for (byte_nbr = 0; byte_nbr < sizeof (uuid_t); byte_nbr++) {
1639 			pM->pszUUID[byte_nbr * 2 + 0] = hex_char[uuid [byte_nbr] >> 4];
1640 			pM->pszUUID[byte_nbr * 2 + 1] = hex_char[uuid [byte_nbr] & 15];
1641 		}
1642 
1643 		pM->pszUUID[lenRes-1] = '\0';
1644 		dbgprintf("[MsgSetUUID] UUID : %s LEN: %d \n", pM->pszUUID, (int)lenRes);
1645 	}
1646 	dbgprintf("[MsgSetUUID] END\n");
1647 }
1648 
1649 static void getUUID(smsg_t * const pM, uchar **pBuf, int *piLen)
1650 {
1651 	dbgprintf("[getUUID] START\n");
1652 	if(pM == NULL) {
1653 		dbgprintf("[getUUID] pM is NULL\n");
1654 		*pBuf=	UCHAR_CONSTANT("");
1655 		*piLen = 0;
1656 	} else {
1657 		if(pM->pszUUID == NULL) {
1658 			dbgprintf("[getUUID] pM->pszUUID is NULL\n");
1659 			MsgLock(pM);
1660 			/* re-query, things may have changed in the mean time... */
1661 			if(pM->pszUUID == NULL)
1662 				msgSetUUID(pM);
1663 			MsgUnlock(pM);
1664 		} else { /* UUID already there we reuse it */
1665 			dbgprintf("[getUUID] pM->pszUUID already exists\n");
1666 		}
1667 		*pBuf = pM->pszUUID;
1668 		*piLen = sizeof(uuid_t) * 2;
1669 	}
1670 	dbgprintf("[getUUID] END\n");
1671 }
1672 #endif
1673 
1674 int ATTR_NONNULL()
1675 getRawMsgLen(const smsg_t *const pMsg)
1676 {
1677 	return (pMsg->pszRawMsg == NULL) ?  0 : pMsg->iLenRawMsg;
1678 }
1679 
1680 void
1681 getRawMsg(const smsg_t * const pM, uchar **pBuf, int *piLen)
1682 {
1683 	if(pM == NULL) {
1684 		*pBuf=  UCHAR_CONSTANT("");
1685 		*piLen = 0;
1686 	} else {
1687 		if(pM->pszRawMsg == NULL) {
1688 			*pBuf=  UCHAR_CONSTANT("");
1689 			*piLen = 0;
1690 		} else {
1691 			*pBuf = pM->pszRawMsg;
1692 			*piLen = pM->iLenRawMsg;
1693 		}
1694 	}
1695 }
1696 
1697 void
1698 getRawMsgAfterPRI(smsg_t * const pM, uchar **pBuf, int *piLen)
1699 {
1700 	if(pM == NULL) {
1701 		*pBuf=  UCHAR_CONSTANT("");
1702 		*piLen = 0;
1703 	} else {
1704 		if(pM->pszRawMsg == NULL) {
1705 			*pBuf=  UCHAR_CONSTANT("");
1706 			*piLen = 0;
1707 		} else {
1708 			/* unfortunately, pM->offAfterPRI seems NOT to be
1709 			 * correct/consistent in all cases. imuxsock and imudp
1710 			 * seem to have other values than imptcp. Testbench
1711 			 * covers some of that. As a work-around, we caluculate
1712 			 * the value ourselfes here. -- rgerhards, 2015-10-09
1713 			 */
1714 			size_t offAfterPRI = 0;
1715 			if(pM->pszRawMsg[0] == '<') { /* do we have a PRI? */
1716 				if(pM->pszRawMsg[2] == '>')
1717 					offAfterPRI = 3;
1718 				else if(pM->pszRawMsg[3] == '>')
1719 					offAfterPRI = 4;
1720 				else if(pM->pszRawMsg[4] == '>')
1721 					offAfterPRI = 5;
1722 			}
1723 			*pBuf = pM->pszRawMsg + offAfterPRI;
1724 			*piLen = pM->iLenRawMsg - offAfterPRI;
1725 		}
1726 	}
1727 }
1728 
1729 
1730 /* note: setMSGLen() is only for friends who really know what they
1731  * do. Setting an invalid length can be desasterous!
1732  */
1733 void setMSGLen(smsg_t * const pM, int lenMsg)
1734 {
1735 	pM->iLenMSG = lenMsg;
1736 }
1737 
1738 int getMSGLen(smsg_t * const pM)
1739 {
1740 	return((pM == NULL) ? 0 : pM->iLenMSG);
1741 }
1742 
1743 uchar *getMSG(smsg_t * const pM)
1744 {
1745 	uchar *ret;
1746 	if(pM == NULL)
1747 		ret = UCHAR_CONSTANT("");
1748 	else {
1749 		if(pM->iLenMSG == 0)
1750 			ret = UCHAR_CONSTANT("");
1751 		else
1752 			ret = pM->pszRawMsg + pM->offMSG;
1753 	}
1754 	return ret;
1755 }
1756 
1757 
1758 /* Get PRI value as integer */
1759 int
1760 getPRIi(const smsg_t * const pM)
1761 {
1762 	syslog_pri_t pri = (pM->iFacility << 3) + (pM->iSeverity);
1763 	if(pri > 191)
1764 		pri = LOG_PRI_INVLD;
1765 	return pri;
1766 }
1767 
1768 
1769 /* Get PRI value in text form
1770  */
1771 const char *
1772 getPRI(smsg_t * const pM)
1773 {
1774 	/* PRI is a number in the range 0..191. Thus, we use a simple lookup table to obtain the
1775 	 * string value. It looks a bit clumpsy here in code ;)
1776 	 */
1777 	int iPRI;
1778 
1779 	if(pM == NULL)
1780 		return "";
1781 
1782 	iPRI = getPRIi(pM);
1783 	return (iPRI > 191) ? "invld" : (char*)syslog_pri_names[iPRI].pszName;
1784 }
1785 
1786 
1787 const char *
1788 getTimeReported(smsg_t * const pM, enum tplFormatTypes eFmt)
1789 {
1790 	if(pM == NULL)
1791 		return "";
1792 
1793 	switch(eFmt) {
1794 	case tplFmtDefault:
1795 	case tplFmtRFC3164Date:
1796 	case tplFmtRFC3164BuggyDate:
1797 		MsgLock(pM);
1798 		if(pM->pszTIMESTAMP3164 == NULL) {
1799 			pM->pszTIMESTAMP3164 = pM->pszTimestamp3164;
1800 			datetime.formatTimestamp3164(&pM->tTIMESTAMP, pM->pszTIMESTAMP3164,
1801 						     (eFmt == tplFmtRFC3164BuggyDate));
1802 		}
1803 		MsgUnlock(pM);
1804 		return(pM->pszTIMESTAMP3164);
1805 	case tplFmtMySQLDate:
1806 		MsgLock(pM);
1807 		if(pM->pszTIMESTAMP_MySQL == NULL) {
1808 			if((pM->pszTIMESTAMP_MySQL = malloc(15)) == NULL) {
1809 				MsgUnlock(pM);
1810 				return "";
1811 			}
1812 			datetime.formatTimestampToMySQL(&pM->tTIMESTAMP, pM->pszTIMESTAMP_MySQL);
1813 		}
1814 		MsgUnlock(pM);
1815 		return(pM->pszTIMESTAMP_MySQL);
1816 	case tplFmtPgSQLDate:
1817 		MsgLock(pM);
1818 		if(pM->pszTIMESTAMP_PgSQL == NULL) {
1819 			if((pM->pszTIMESTAMP_PgSQL = malloc(21)) == NULL) {
1820 				MsgUnlock(pM);
1821 				return "";
1822 			}
1823 			datetime.formatTimestampToPgSQL(&pM->tTIMESTAMP, pM->pszTIMESTAMP_PgSQL);
1824 		}
1825 		MsgUnlock(pM);
1826 		return(pM->pszTIMESTAMP_PgSQL);
1827 	case tplFmtRFC3339Date:
1828 		MsgLock(pM);
1829 		if(pM->pszTIMESTAMP3339 == NULL) {
1830 			pM->pszTIMESTAMP3339 = pM->pszTimestamp3339;
1831 			datetime.formatTimestamp3339(&pM->tTIMESTAMP, pM->pszTIMESTAMP3339);
1832 		}
1833 		MsgUnlock(pM);
1834 		return(pM->pszTIMESTAMP3339);
1835 	case tplFmtUnixDate:
1836 		MsgLock(pM);
1837 		if(pM->pszTIMESTAMP_Unix[0] == '\0') {
1838 			datetime.formatTimestampUnix(&pM->tTIMESTAMP, pM->pszTIMESTAMP_Unix);
1839 		}
1840 		MsgUnlock(pM);
1841 		return(pM->pszTIMESTAMP_Unix);
1842 	case tplFmtSecFrac:
1843 		if(pM->pszTIMESTAMP_SecFrac[0] == '\0') {
1844 			MsgLock(pM);
1845 			/* re-check, may have changed while we did not hold lock */
1846 			if(pM->pszTIMESTAMP_SecFrac[0] == '\0') {
1847 				datetime.formatTimestampSecFrac(&pM->tTIMESTAMP, pM->pszTIMESTAMP_SecFrac);
1848 			}
1849 			MsgUnlock(pM);
1850 		}
1851 		return(pM->pszTIMESTAMP_SecFrac);
1852 	case tplFmtWDayName:
1853 		return wdayNames[getWeekdayNbr(&pM->tTIMESTAMP)];
1854 	case tplFmtWDay:
1855 		return one_digit[getWeekdayNbr(&pM->tTIMESTAMP)];
1856 	case tplFmtMonth:
1857 		return two_digits[(int)pM->tTIMESTAMP.month];
1858 	case tplFmtYear:
1859 		if(pM->tTIMESTAMP.year >= 1967 && pM->tTIMESTAMP.year <= 2099)
1860 			return years[pM->tTIMESTAMP.year - 1967];
1861 		else
1862 			return "YEAR OUT OF RANGE(1967-2099)";
1863 	case tplFmtDay:
1864 		return two_digits[(int)pM->tTIMESTAMP.day];
1865 	case tplFmtHour:
1866 		return two_digits[(int)pM->tTIMESTAMP.hour];
1867 	case tplFmtMinute:
1868 		return two_digits[(int)pM->tTIMESTAMP.minute];
1869 	case tplFmtSecond:
1870 		return two_digits[(int)pM->tTIMESTAMP.second];
1871 	case tplFmtTZOffsHour:
1872 		return two_digits[(int)pM->tTIMESTAMP.OffsetHour];
1873 	case tplFmtTZOffsMin:
1874 		return two_digits[(int)pM->tTIMESTAMP.OffsetMinute];
1875 	case tplFmtTZOffsDirection:
1876 		return (pM->tTIMESTAMP.OffsetMode == '+')? "+" : "-";
1877 	case tplFmtOrdinal:
1878 		return daysInYear[getOrdinal(&pM->tTIMESTAMP)];
1879 	case tplFmtWeek:
1880 		return two_digits[getWeek(&pM->tTIMESTAMP)];
1881 	}
1882 	return "INVALID eFmt OPTION!";
1883 }
1884 
1885 
1886 
1887 static const char *getTimeUTC(struct syslogTime *const __restrict__ pTmIn,
1888 	const enum tplFormatTypes eFmt,
1889 	unsigned short *const __restrict__ pbMustBeFreed)
1890 {
1891 	struct syslogTime tUTC;
1892 	char *retbuf = NULL;
1893 
1894 	timeConvertToUTC(pTmIn, &tUTC);
1895 	struct syslogTime *const pTm = &tUTC;
1896 
1897 	switch(eFmt) {
1898 	case tplFmtDefault:
1899 		if((retbuf = malloc(16)) != NULL) {
1900 			datetime.formatTimestamp3164(pTm, retbuf, 0);
1901 		}
1902 		break;
1903 	case tplFmtMySQLDate:
1904 		if((retbuf = malloc(15)) != NULL) {
1905 			datetime.formatTimestampToMySQL(pTm, retbuf);
1906 		}
1907 		break;
1908 	case tplFmtPgSQLDate:
1909 		if((retbuf = malloc(21)) != NULL) {
1910 			datetime.formatTimestampToPgSQL(pTm, retbuf);
1911 		}
1912 		break;
1913 	case tplFmtRFC3164Date:
1914 	case tplFmtRFC3164BuggyDate:
1915 		if((retbuf = malloc(16)) != NULL) {
1916 			datetime.formatTimestamp3164(pTm, retbuf, (eFmt == tplFmtRFC3164BuggyDate));
1917 		}
1918 		break;
1919 	case tplFmtRFC3339Date:
1920 		if((retbuf = malloc(33)) != NULL) {
1921 			datetime.formatTimestamp3339(pTm, retbuf);
1922 		}
1923 		break;
1924 	case tplFmtUnixDate:
1925 		if((retbuf = malloc(12)) != NULL) {
1926 			datetime.formatTimestampUnix(pTm, retbuf);
1927 		}
1928 		break;
1929 	case tplFmtSecFrac:
1930 		if((retbuf = malloc(7)) != NULL) {
1931 			datetime.formatTimestampSecFrac(pTm, retbuf);
1932 		}
1933 		break;
1934 	case tplFmtWDayName:
1935 		retbuf = strdup(wdayNames[getWeekdayNbr(pTm)]);
1936 		break;
1937 	case tplFmtWDay:
1938 		retbuf = strdup(one_digit[getWeekdayNbr(pTm)]);
1939 		break;
1940 	case tplFmtMonth:
1941 		retbuf = strdup(two_digits[(int)pTm->month]);
1942 		break;
1943 	case tplFmtYear:
1944 		if(pTm->year >= 1967 && pTm->year <= 2099)
1945 			retbuf = strdup(years[pTm->year - 1967]);
1946 		else
1947 			retbuf = strdup("YEAR OUT OF RANGE(1967-2099)");
1948 		break;
1949 	case tplFmtDay:
1950 		retbuf = strdup(two_digits[(int)pTm->day]);
1951 		break;
1952 	case tplFmtHour:
1953 		retbuf = strdup(two_digits[(int)pTm->hour]);
1954 		break;
1955 	case tplFmtMinute:
1956 		retbuf = strdup(two_digits[(int)pTm->minute]);
1957 		break;
1958 	case tplFmtSecond:
1959 		retbuf = strdup(two_digits[(int)pTm->second]);
1960 		break;
1961 	case tplFmtTZOffsHour:
1962 		retbuf = strdup(two_digits[(int)pTm->OffsetHour]);
1963 		break;
1964 	case tplFmtTZOffsMin:
1965 		retbuf = strdup(two_digits[(int)pTm->OffsetMinute]);
1966 		break;
1967 	case tplFmtTZOffsDirection:
1968 		retbuf = strdup((pTm->OffsetMode == '+')? "+" : "-");
1969 		break;
1970 	case tplFmtOrdinal:
1971 		retbuf = strdup(daysInYear[getOrdinal(pTm)]);
1972 		break;
1973 	case tplFmtWeek:
1974 		retbuf = strdup(two_digits[getWeek(pTm)]);
1975 		break;
1976 	}
1977 
1978 	if(retbuf == NULL) {
1979 		retbuf = (char*)"internal error: invalid eFmt option or malloc problem";
1980 		*pbMustBeFreed = 0;
1981 	} else {
1982 		*pbMustBeFreed = 1;
1983 	}
1984 	return retbuf;
1985 }
1986 
1987 static const char *
1988 getTimeGenerated(smsg_t *const __restrict__ pM,
1989 	const enum tplFormatTypes eFmt)
1990 {
1991 	struct syslogTime *const pTm = &pM->tRcvdAt;
1992 	if(pM == NULL)
1993 		return "";
1994 
1995 	switch(eFmt) {
1996 	case tplFmtDefault:
1997 		MsgLock(pM);
1998 		if(pM->pszRcvdAt3164 == NULL) {
1999 			if((pM->pszRcvdAt3164 = malloc(16)) == NULL) {
2000 				MsgUnlock(pM);
2001 				return "";
2002 			}
2003 			datetime.formatTimestamp3164(pTm, pM->pszRcvdAt3164, 0);
2004 		}
2005 		MsgUnlock(pM);
2006 		return(pM->pszRcvdAt3164);
2007 	case tplFmtMySQLDate:
2008 		MsgLock(pM);
2009 		if(pM->pszRcvdAt_MySQL == NULL) {
2010 			if((pM->pszRcvdAt_MySQL = malloc(15)) == NULL) {
2011 				MsgUnlock(pM);
2012 				return "";
2013 			}
2014 			datetime.formatTimestampToMySQL(pTm, pM->pszRcvdAt_MySQL);
2015 		}
2016 		MsgUnlock(pM);
2017 		return(pM->pszRcvdAt_MySQL);
2018 	case tplFmtPgSQLDate:
2019 		MsgLock(pM);
2020 		if(pM->pszRcvdAt_PgSQL == NULL) {
2021 			if((pM->pszRcvdAt_PgSQL = malloc(21)) == NULL) {
2022 				MsgUnlock(pM);
2023 				return "";
2024 			}
2025 			datetime.formatTimestampToPgSQL(pTm, pM->pszRcvdAt_PgSQL);
2026 		}
2027 		MsgUnlock(pM);
2028 		return(pM->pszRcvdAt_PgSQL);
2029 	case tplFmtRFC3164Date:
2030 	case tplFmtRFC3164BuggyDate:
2031 		MsgLock(pM);
2032 		if(pM->pszRcvdAt3164 == NULL) {
2033 			if((pM->pszRcvdAt3164 = malloc(16)) == NULL) {
2034 					MsgUnlock(pM);
2035 					return "";
2036 				}
2037 			datetime.formatTimestamp3164(pTm, pM->pszRcvdAt3164,
2038 						     (eFmt == tplFmtRFC3164BuggyDate));
2039 		}
2040 		MsgUnlock(pM);
2041 		return(pM->pszRcvdAt3164);
2042 	case tplFmtRFC3339Date:
2043 		MsgLock(pM);
2044 		if(pM->pszRcvdAt3339 == NULL) {
2045 			if((pM->pszRcvdAt3339 = malloc(33)) == NULL) {
2046 				MsgUnlock(pM);
2047 				return "";
2048 			}
2049 			datetime.formatTimestamp3339(pTm, pM->pszRcvdAt3339);
2050 		}
2051 		MsgUnlock(pM);
2052 		return(pM->pszRcvdAt3339);
2053 	case tplFmtUnixDate:
2054 		MsgLock(pM);
2055 		if(pM->pszRcvdAt_Unix[0] == '\0') {
2056 			datetime.formatTimestampUnix(pTm, pM->pszRcvdAt_Unix);
2057 		}
2058 		MsgUnlock(pM);
2059 		return(pM->pszRcvdAt_Unix);
2060 	case tplFmtSecFrac:
2061 		if(pM->pszRcvdAt_SecFrac[0] == '\0') {
2062 			MsgLock(pM);
2063 			/* re-check, may have changed while we did not hold lock */
2064 			if(pM->pszRcvdAt_SecFrac[0] == '\0') {
2065 				datetime.formatTimestampSecFrac(pTm, pM->pszRcvdAt_SecFrac);
2066 			}
2067 			MsgUnlock(pM);
2068 		}
2069 		return(pM->pszRcvdAt_SecFrac);
2070 	case tplFmtWDayName:
2071 		return wdayNames[getWeekdayNbr(pTm)];
2072 	case tplFmtWDay:
2073 		return one_digit[getWeekdayNbr(pTm)];
2074 	case tplFmtMonth:
2075 		return two_digits[(int)pTm->month];
2076 	case tplFmtYear:
2077 		if(pTm->year >= 1967 && pTm->year <= 2099)
2078 			return years[pTm->year - 1967];
2079 		else
2080 			return "YEAR OUT OF RANGE(1967-2099)";
2081 	case tplFmtDay:
2082 		return two_digits[(int)pTm->day];
2083 	case tplFmtHour:
2084 		return two_digits[(int)pTm->hour];
2085 	case tplFmtMinute:
2086 		return two_digits[(int)pTm->minute];
2087 	case tplFmtSecond:
2088 		return two_digits[(int)pTm->second];
2089 	case tplFmtTZOffsHour:
2090 		return two_digits[(int)pTm->OffsetHour];
2091 	case tplFmtTZOffsMin:
2092 		return two_digits[(int)pTm->OffsetMinute];
2093 	case tplFmtTZOffsDirection:
2094 		return (pTm->OffsetMode == '+')? "+" : "-";
2095 	case tplFmtOrdinal:
2096 		return daysInYear[getOrdinal(pTm)];
2097 	case tplFmtWeek:
2098 		return two_digits[getWeek(pTm)];
2099 	}
2100 	return "INVALID eFmt OPTION!";
2101 }
2102 
2103 
2104 static const char *getSeverity(smsg_t * const pM)
2105 {
2106 	const char *name = NULL;
2107 
2108 	if(pM == NULL)
2109 		return "";
2110 
2111 	if(pM->iSeverity > 7) {
2112 		name = "invld";
2113 	} else {
2114 		name = syslog_number_names[pM->iSeverity];
2115 	}
2116 
2117 	return name;
2118 }
2119 
2120 
2121 static const char *getSeverityStr(smsg_t * const pM)
2122 {
2123 	const char *name = NULL;
2124 
2125 	if(pM == NULL)
2126 		return "";
2127 
2128 	if(pM->iSeverity > 7) {
2129 		name = "invld";
2130 	} else {
2131 		name = syslog_severity_names[pM->iSeverity];
2132 	}
2133 
2134 	return name;
2135 }
2136 
2137 static const char *getFacility(smsg_t * const pM)
2138 {
2139 	const char *name = NULL;
2140 
2141 	if(pM == NULL)
2142 		return "";
2143 
2144 	if(pM->iFacility > 23) {
2145 		name = "invld";
2146 	} else {
2147 		name = syslog_number_names[pM->iFacility];
2148 	}
2149 
2150 	return name;
2151 }
2152 
2153 static const char *getFacilityStr(smsg_t * const pM)
2154 {
2155 	const char *name = NULL;
2156 
2157 	if(pM == NULL)
2158 		return "";
2159 
2160 	if(pM->iFacility > 23) {
2161 		name = "invld";
2162 	} else {
2163 		name = syslog_fac_names[pM->iFacility];
2164 	}
2165 
2166 	return name;
2167 }
2168 
2169 
2170 /* set flow control state (if not called, the default - NO_DELAY - is used)
2171  * This needs no locking because it is only done while the object is
2172  * not fully constructed (which also means you must not call this
2173  * method after the msg has been handed over to a queue).
2174  * rgerhards, 2008-03-14
2175  */
2176 rsRetVal
2177 MsgSetFlowControlType(smsg_t * const pMsg, flowControl_t eFlowCtl)
2178 {
2179 	DEFiRet;
2180 	assert(pMsg != NULL);
2181 	assert(eFlowCtl == eFLOWCTL_NO_DELAY || eFlowCtl == eFLOWCTL_LIGHT_DELAY || eFlowCtl == eFLOWCTL_FULL_DELAY);
2182 
2183 	pMsg->flowCtlType = eFlowCtl;
2184 
2185 	RETiRet;
2186 }
2187 
2188 /* set offset after which PRI in raw msg starts
2189  * rgerhards, 2009-06-16
2190  */
2191 rsRetVal
2192 MsgSetAfterPRIOffs(smsg_t * const pMsg, int offs)
2193 {
2194 	assert(pMsg != NULL);
2195 	pMsg->offAfterPRI = offs;
2196 	return RS_RET_OK;
2197 }
2198 
2199 
2200 /* rgerhards 2004-11-24: set APP-NAME in msg object
2201  * This is not locked, because it either is called during message
2202  * construction (where we need no locking) or later as part of a function
2203  * which already obtained the lock. So in general, this function here must
2204  * only be called when it it safe to do so without it aquiring a lock.
2205  */
2206 rsRetVal ATTR_NONNULL(1,2)
2207 MsgSetAPPNAME(smsg_t *__restrict__ const pMsg, const char *pszAPPNAME)
2208 {
2209 	DEFiRet;
2210 	assert(pMsg != NULL);
2211 	if(pszAPPNAME[0] == '\0') {
2212 		pszAPPNAME = "-"; /* RFC5424 NIL value */
2213 	}
2214 	if(pMsg->pCSAPPNAME == NULL) {
2215 		/* we need to obtain the object first */
2216 		CHKiRet(rsCStrConstruct(&pMsg->pCSAPPNAME));
2217 	}
2218 	/* if we reach this point, we have the object */
2219 	CHKiRet(rsCStrSetSzStr(pMsg->pCSAPPNAME, (uchar*) pszAPPNAME));
2220 	cstrFinalize(pMsg->pCSAPPNAME);
2221 
2222 finalize_it:
2223 	RETiRet;
2224 }
2225 
2226 
2227 /* rgerhards 2004-11-24: set PROCID in msg object
2228  */
2229 rsRetVal MsgSetPROCID(smsg_t *__restrict__ const pMsg, const char* pszPROCID)
2230 {
2231 	DEFiRet;
2232 	ISOBJ_TYPE_assert(pMsg, msg);
2233 	if(pMsg->pCSPROCID == NULL) {
2234 		/* we need to obtain the object first */
2235 		CHKiRet(cstrConstruct(&pMsg->pCSPROCID));
2236 	}
2237 	/* if we reach this point, we have the object */
2238 	CHKiRet(rsCStrSetSzStr(pMsg->pCSPROCID, (uchar*) pszPROCID));
2239 	cstrFinalize(pMsg->pCSPROCID);
2240 
2241 finalize_it:
2242 	RETiRet;
2243 }
2244 
2245 
2246 /* check if we have a procid, and, if not, try to aquire/emulate it.
2247  * This must be called WITHOUT the message lock being held.
2248  * rgerhards, 2009-06-26
2249  */
2250 static void preparePROCID(smsg_t * const pM, sbool bLockMutex)
2251 {
2252 	if(pM->pCSPROCID == NULL) {
2253 		if(bLockMutex == LOCK_MUTEX)
2254 			MsgLock(pM);
2255 		/* re-query, things may have changed in the mean time... */
2256 		if(pM->pCSPROCID == NULL)
2257 			aquirePROCIDFromTAG(pM);
2258 		if(bLockMutex == LOCK_MUTEX)
2259 			MsgUnlock(pM);
2260 	}
2261 }
2262 
2263 
2264 #if 0
2265 /* rgerhards, 2005-11-24
2266  */
2267 static int getPROCIDLen(smsg_t *pM, sbool bLockMutex)
2268 {
2269 	assert(pM != NULL);
2270 	preparePROCID(pM, bLockMutex);
2271 	return (pM->pCSPROCID == NULL) ? 1 : rsCStrLen(pM->pCSPROCID);
2272 }
2273 #endif
2274 
2275 
2276 /* rgerhards, 2005-11-24
2277  */
2278 char *getPROCID(smsg_t * const pM, sbool bLockMutex)
2279 {
2280 	uchar *pszRet;
2281 
2282 	ISOBJ_TYPE_assert(pM, msg);
2283 	if(bLockMutex == LOCK_MUTEX)
2284 		MsgLock(pM);
2285 	preparePROCID(pM, MUTEX_ALREADY_LOCKED);
2286 	if(pM->pCSPROCID == NULL)
2287 		pszRet = UCHAR_CONSTANT("-");
2288 	else
2289 		pszRet = rsCStrGetSzStrNoNULL(pM->pCSPROCID);
2290 	if(bLockMutex == LOCK_MUTEX)
2291 		MsgUnlock(pM);
2292 	return (char*) pszRet;
2293 }
2294 
2295 
2296 /* rgerhards 2004-11-24: set MSGID in msg object
2297  */
2298 rsRetVal MsgSetMSGID(smsg_t * const pMsg, const char* pszMSGID)
2299 {
2300 	DEFiRet;
2301 	ISOBJ_TYPE_assert(pMsg, msg);
2302 	if(pMsg->pCSMSGID == NULL) {
2303 		/* we need to obtain the object first */
2304 		CHKiRet(rsCStrConstruct(&pMsg->pCSMSGID));
2305 	}
2306 	/* if we reach this point, we have the object */
2307 	CHKiRet(rsCStrSetSzStr(pMsg->pCSMSGID, (uchar*) pszMSGID));
2308 	cstrFinalize(pMsg->pCSMSGID);
2309 
2310 finalize_it:
2311 	RETiRet;
2312 }
2313 
2314 
2315 /* Return state of last parser. If it had success, "OK" is returned, else
2316  * "FAIL". All from the constant pool.
2317  */
2318 static const char *getParseSuccess(smsg_t * const pM)
2319 {
2320 	return (pM->bParseSuccess) ? "OK" : "FAIL";
2321 }
2322 
2323 
2324 /* al, 2011-07-26: LockMsg to avoid race conditions
2325  */
2326 static const char *getMSGID(smsg_t * const pM)
2327 {
2328 	if (pM->pCSMSGID == NULL) {
2329 		return "-";
2330 	}
2331 	else {
2332 		MsgLock(pM);
2333 		char* pszreturn = (char*) rsCStrGetSzStrNoNULL(pM->pCSMSGID);
2334 		MsgUnlock(pM);
2335 		return pszreturn;
2336 	}
2337 }
2338 
2339 /* rgerhards 2012-03-15: set parser success (an integer, acutally bool)
2340  */
2341 void MsgSetParseSuccess(smsg_t * const pMsg, int bSuccess)
2342 {
2343 	assert(pMsg != NULL);
2344 	pMsg->bParseSuccess = bSuccess;
2345 }
2346 
2347 
2348 /* return full message as a json string */
2349 const uchar*
2350 msgGetJSONMESG(smsg_t *__restrict__ const pMsg)
2351 {
2352 	struct json_object *json;
2353 	struct json_object *jval;
2354 	uchar *pRes; /* result pointer */
2355 	rs_size_t bufLen = -1; /* length of string or -1, if not known */
2356 
2357 	json = json_object_new_object();
2358 
2359 	jval = json_object_new_string((char*)getMSG(pMsg));
2360 	json_object_object_add(json, "msg", jval);
2361 
2362 	getRawMsg(pMsg, &pRes, &bufLen);
2363 	jval = json_object_new_string((char*)pRes);
2364 	json_object_object_add(json, "rawmsg", jval);
2365 
2366 	pRes = (uchar*)getTimeReported(pMsg, tplFmtRFC3339Date);
2367 	jval = json_object_new_string((char*)pRes);
2368 	json_object_object_add(json, "timereported", jval);
2369 
2370 	jval = json_object_new_string(getHOSTNAME(pMsg));
2371 	json_object_object_add(json, "hostname", jval);
2372 
2373 	getTAG(pMsg, &pRes, &bufLen, LOCK_MUTEX);
2374 	jval = json_object_new_string((char*)pRes);
2375 	json_object_object_add(json, "syslogtag", jval);
2376 
2377 	getInputName(pMsg, &pRes, &bufLen);
2378 	jval = json_object_new_string((char*)pRes);
2379 	json_object_object_add(json, "inputname", jval);
2380 
2381 	jval = json_object_new_string((char*)getRcvFrom(pMsg));
2382 	json_object_object_add(json, "fromhost", jval);
2383 
2384 	jval = json_object_new_string((char*)getRcvFromIP(pMsg));
2385 	json_object_object_add(json, "fromhost-ip", jval);
2386 
2387 	jval = json_object_new_string(getPRI(pMsg));
2388 	json_object_object_add(json, "pri", jval);
2389 
2390 	jval = json_object_new_string(getFacility(pMsg));
2391 	json_object_object_add(json, "syslogfacility", jval);
2392 
2393 	jval = json_object_new_string(getSeverity(pMsg));
2394 	json_object_object_add(json, "syslogseverity", jval);
2395 
2396 	pRes = (uchar*)getTimeGenerated(pMsg, tplFmtRFC3339Date);
2397 	jval = json_object_new_string((char*)pRes);
2398 	json_object_object_add(json, "timegenerated", jval);
2399 
2400 	jval = json_object_new_string((char*)getProgramName(pMsg, LOCK_MUTEX));
2401 	json_object_object_add(json, "programname", jval);
2402 
2403 	jval = json_object_new_string(getProtocolVersionString(pMsg));
2404 	json_object_object_add(json, "protocol-version", jval);
2405 
2406 	MsgGetStructuredData(pMsg, &pRes, &bufLen);
2407 	jval = json_object_new_string((char*)pRes);
2408 	json_object_object_add(json, "structured-data", jval);
2409 
2410 	jval = json_object_new_string(getAPPNAME(pMsg, LOCK_MUTEX));
2411 	json_object_object_add(json, "app-name", jval);
2412 
2413 	jval = json_object_new_string(getPROCID(pMsg, LOCK_MUTEX));
2414 	json_object_object_add(json, "procid", jval);
2415 
2416 	jval = json_object_new_string(getMSGID(pMsg));
2417 	json_object_object_add(json, "msgid", jval);
2418 
2419 #ifdef USE_LIBUUID
2420 	if(pMsg->pszUUID == NULL) {
2421 		jval = NULL;
2422 	} else {
2423 		getUUID(pMsg, &pRes, &bufLen);
2424 		jval = json_object_new_string((char*)pRes);
2425 	}
2426 	json_object_object_add(json, "uuid", jval);
2427 #endif
2428 
2429 	json_object_object_add(json, "$!", json_object_get(pMsg->json));
2430 
2431 	pRes = (uchar*) strdup(json_object_get_string(json));
2432 	json_object_put(json);
2433 	return pRes;
2434 }
2435 
2436 /* rgerhards 2009-06-12: set associated ruleset
2437  */
2438 void MsgSetRuleset(smsg_t * const pMsg, ruleset_t *pRuleset)
2439 {
2440 	assert(pMsg != NULL);
2441 	pMsg->pRuleset = pRuleset;
2442 }
2443 
2444 
2445 /* set TAG in msg object
2446  * (rewritten 2009-06-18 rgerhards)
2447  */
2448 void MsgSetTAG(smsg_t *__restrict__ const pMsg, const uchar* pszBuf, const size_t lenBuf)
2449 {
2450 	uchar *pBuf;
2451 	assert(pMsg != NULL);
2452 
2453 	freeTAG(pMsg);
2454 
2455 	pMsg->iLenTAG = lenBuf;
2456 	if(pMsg->iLenTAG < CONF_TAG_BUFSIZE) {
2457 		/* small enough: use fixed buffer (faster!) */
2458 		pBuf = pMsg->TAG.szBuf;
2459 	} else {
2460 		if((pBuf = (uchar*) malloc(pMsg->iLenTAG + 1)) == NULL) {
2461 			/* truncate message, better than completely loosing it... */
2462 			pBuf = pMsg->TAG.szBuf;
2463 			pMsg->iLenTAG = CONF_TAG_BUFSIZE - 1;
2464 		} else {
2465 			pMsg->TAG.pszTAG = pBuf;
2466 		}
2467 	}
2468 
2469 	memcpy(pBuf, pszBuf, pMsg->iLenTAG);
2470 	pBuf[pMsg->iLenTAG] = '\0'; /* this also works with truncation! */
2471 }
2472 
2473 
2474 /* This function tries to emulate the TAG if none is
2475  * set. Its primary purpose is to provide an old-style TAG
2476  * when a syslog-protocol message has been received. Then,
2477  * the tag is APP-NAME "[" PROCID "]". The function first checks
2478  * if there is a TAG and, if not, if it can emulate it.
2479  * rgerhards, 2005-11-24
2480  */
2481 static void ATTR_NONNULL(1)
2482 tryEmulateTAG(smsg_t *const pM, const sbool bLockMutex)
2483 {
2484 	size_t lenTAG;
2485 	uchar bufTAG[CONF_TAG_MAXSIZE];
2486 	assert(pM != NULL);
2487 
2488 	if(bLockMutex == LOCK_MUTEX)
2489 		MsgLock(pM);
2490 	if(pM->iLenTAG > 0) {
2491 		if(bLockMutex == LOCK_MUTEX)
2492 			MsgUnlock(pM);
2493 		return; /* done, no need to emulate */
2494 	}
2495 
2496 	if(msgGetProtocolVersion(pM) == 1) {
2497 		if(!strcmp(getPROCID(pM, MUTEX_ALREADY_LOCKED), "-")) {
2498 			/* no process ID, use APP-NAME only */
2499 			MsgSetTAG(pM, (uchar*) getAPPNAME(pM, MUTEX_ALREADY_LOCKED),
2500 					getAPPNAMELen(pM, MUTEX_ALREADY_LOCKED));
2501 		} else {
2502 			/* now we can try to emulate */
2503 			lenTAG = snprintf((char*)bufTAG, CONF_TAG_MAXSIZE, "%s[%s]",
2504 					  getAPPNAME(pM, MUTEX_ALREADY_LOCKED), getPROCID(pM, MUTEX_ALREADY_LOCKED));
2505 			bufTAG[sizeof(bufTAG)-1] = '\0'; /* just to make sure... */
2506 			MsgSetTAG(pM, bufTAG, lenTAG);
2507 		}
2508 		/* Signal change in TAG for aquireProgramName */
2509 		pM->iLenPROGNAME = -1;
2510 	}
2511 	if(bLockMutex == LOCK_MUTEX)
2512 		MsgUnlock(pM);
2513 }
2514 
2515 
2516 void ATTR_NONNULL(2,3)
2517 getTAG(smsg_t * const pM, uchar **const ppBuf, int *const piLen, const sbool bLockMutex)
2518 {
2519 	if(pM == NULL) {
2520 		*ppBuf = UCHAR_CONSTANT("");
2521 		*piLen = 0;
2522 	} else {
2523 		if(pM->iLenTAG == 0)
2524 			tryEmulateTAG(pM, bLockMutex);
2525 		if(pM->iLenTAG == 0) {
2526 			*ppBuf = UCHAR_CONSTANT("");
2527 			*piLen = 0;
2528 		} else {
2529 			*ppBuf = (pM->iLenTAG < CONF_TAG_BUFSIZE) ? pM->TAG.szBuf : pM->TAG.pszTAG;
2530 			*piLen = pM->iLenTAG;
2531 		}
2532 	}
2533 }
2534 
2535 
2536 int getHOSTNAMELen(smsg_t * const pM)
2537 {
2538 	if(pM == NULL)
2539 		return 0;
2540 	else
2541 		if(pM->pszHOSTNAME == NULL) {
2542 			resolveDNS(pM);
2543 			if(pM->rcvFrom.pRcvFrom == NULL)
2544 				return 0;
2545 			else
2546 				return prop.GetStringLen(pM->rcvFrom.pRcvFrom);
2547 		} else
2548 			return pM->iLenHOSTNAME;
2549 }
2550 
2551 
2552 const char *getHOSTNAME(smsg_t * const pM)
2553 {
2554 	if(pM == NULL)
2555 		return "";
2556 	else
2557 		if(pM->pszHOSTNAME == NULL) {
2558 			resolveDNS(pM);
2559 			if(pM->rcvFrom.pRcvFrom == NULL) {
2560 				return "";
2561 			} else {
2562 				uchar *psz;
2563 				int len;
2564 				prop.GetString(pM->rcvFrom.pRcvFrom, &psz, &len);
2565 				return (char*) psz;
2566 			}
2567 		} else {
2568 			return (char*) pM->pszHOSTNAME;
2569 		}
2570 }
2571 
2572 
2573 uchar *getRcvFrom(smsg_t * const pM)
2574 {
2575 	uchar *psz;
2576 	int len;
2577 
2578 	if(pM == NULL) {
2579 		psz = UCHAR_CONSTANT("");
2580 	} else {
2581 		resolveDNS(pM);
2582 		if(pM->rcvFrom.pRcvFrom == NULL)
2583 			psz = UCHAR_CONSTANT("");
2584 		else
2585 			prop.GetString(pM->rcvFrom.pRcvFrom, &psz, &len);
2586 	}
2587 	return psz;
2588 }
2589 
2590 
2591 /* rgerhards 2004-11-24: set STRUCTURED DATA in msg object
2592  */
2593 rsRetVal MsgSetStructuredData(smsg_t * const pMsg, const char* pszStrucData)
2594 {
2595 	DEFiRet;
2596 	ISOBJ_TYPE_assert(pMsg, msg);
2597 	free(pMsg->pszStrucData);
2598 	CHKmalloc(pMsg->pszStrucData = (uchar*)strdup(pszStrucData));
2599 	pMsg->lenStrucData = strlen(pszStrucData);
2600 finalize_it:
2601 	RETiRet;
2602 }
2603 
2604 
2605 /* get the "STRUCTURED-DATA" as sz string, including length */
2606 void
2607 MsgGetStructuredData(smsg_t * const pM, uchar **pBuf, rs_size_t *len)
2608 {
2609 	MsgLock(pM);
2610 	if(pM->pszStrucData == NULL) {
2611 		*pBuf = UCHAR_CONSTANT("-"),
2612 		*len = 1;
2613 	} else  {
2614 		*pBuf = pM->pszStrucData,
2615 		*len = pM->lenStrucData;
2616 	}
2617 	MsgUnlock(pM);
2618 }
2619 
2620 /* get the "programname" as sz string
2621  * rgerhards, 2005-10-19
2622  */
2623 uchar * ATTR_NONNULL(1)
2624 getProgramName(smsg_t *const pM, const sbool bLockMutex)
2625 {
2626 	if(bLockMutex == LOCK_MUTEX) {
2627 		MsgLock(pM);
2628 	}
2629 
2630 	if(pM->iLenPROGNAME == -1) {
2631 		if(pM->iLenTAG == 0) {
2632 			uchar *pRes;
2633 			rs_size_t bufLen = -1;
2634 			getTAG(pM, &pRes, &bufLen, MUTEX_ALREADY_LOCKED);
2635 		}
2636 		aquireProgramName(pM);
2637 	}
2638 
2639 	if(bLockMutex == LOCK_MUTEX) {
2640 		MsgUnlock(pM);
2641 	}
2642 	return (pM->iLenPROGNAME < CONF_PROGNAME_BUFSIZE) ? pM->PROGNAME.szBuf
2643 						       : pM->PROGNAME.ptr;
2644 }
2645 
2646 
2647 
2648 /* check if we have a APPNAME, and, if not, try to aquire/emulate it.
2649  * rgerhards, 2009-06-26
2650  */
2651 static void ATTR_NONNULL(1)
2652 prepareAPPNAME(smsg_t *const pM, const sbool bLockMutex)
2653 {
2654 	if(pM->pCSAPPNAME == NULL) {
2655 		if(bLockMutex == LOCK_MUTEX)
2656 			MsgLock(pM);
2657 
2658 		/* re-query as things might have changed during locking */
2659 		if(pM->pCSAPPNAME == NULL) {
2660 			if(msgGetProtocolVersion(pM) == 0) {
2661 				/* only then it makes sense to emulate */
2662 				MsgSetAPPNAME(pM, (char*)getProgramName(pM, MUTEX_ALREADY_LOCKED));
2663 			}
2664 		}
2665 
2666 		if(bLockMutex == LOCK_MUTEX)
2667 			MsgUnlock(pM);
2668 	}
2669 }
2670 
2671 /* rgerhards, 2005-11-24
2672  */
2673 char *getAPPNAME(smsg_t * const pM, const sbool bLockMutex)
2674 {
2675 	uchar *pszRet;
2676 
2677 	assert(pM != NULL);
2678 	if(bLockMutex == LOCK_MUTEX)
2679 		MsgLock(pM);
2680 	prepareAPPNAME(pM, MUTEX_ALREADY_LOCKED);
2681 	if(pM->pCSAPPNAME == NULL)
2682 		pszRet = UCHAR_CONSTANT("");
2683 	else
2684 		pszRet = rsCStrGetSzStrNoNULL(pM->pCSAPPNAME);
2685 	if(bLockMutex == LOCK_MUTEX)
2686 		MsgUnlock(pM);
2687 	return (char*)pszRet;
2688 }
2689 
2690 /* rgerhards, 2005-11-24
2691  */
2692 static int getAPPNAMELen(smsg_t * const pM, const sbool bLockMutex)
2693 {
2694 	assert(pM != NULL);
2695 	prepareAPPNAME(pM, bLockMutex);
2696 	return (pM->pCSAPPNAME == NULL) ? 0 : rsCStrLen(pM->pCSAPPNAME);
2697 }
2698 
2699 /* rgerhards 2008-09-10: set pszInputName in msg object. This calls AddRef()
2700  * on the property, because this must be done in all current cases and there
2701  * is no case expected where this may not be necessary.
2702  * rgerhards, 2009-06-16
2703  */
2704 void MsgSetInputName(smsg_t *pThis, prop_t *inputName)
2705 {
2706 	assert(pThis != NULL);
2707 
2708 	prop.AddRef(inputName);
2709 	if(pThis->pInputName != NULL)
2710 		prop.Destruct(&pThis->pInputName);
2711 	pThis->pInputName = inputName;
2712 }
2713 
2714 /* Set default TZ. Note that at most 7 chars are set, as we would
2715  * otherwise overrun our buffer!
2716  */
2717 void MsgSetDfltTZ(smsg_t *pThis, char *tz)
2718 {
2719 	strncpy(pThis->dfltTZ, tz, 7);
2720 	pThis->dfltTZ[7] = '\0'; /* ensure 0-Term in case of overflow! */
2721 }
2722 
2723 
2724 /* Set the pfrominet socket store, so that we can obtain the peer at some
2725  * later time. Note that we do not check if pRcvFrom is already set, so this
2726  * function must only be called during message creation.
2727  * NOTE: msgFlags is NOT set. While this is somewhat a violation of layers,
2728  * it is done because it gains us some performance. So the caller must make
2729  * sure the message flags are properly maintained. For all current callers,
2730  * this is always the case and without extra effort required.
2731  * rgerhards, 2009-11-17
2732  */
2733 rsRetVal
2734 msgSetFromSockinfo(smsg_t *pThis, struct sockaddr_storage *sa){
2735 	DEFiRet;
2736 	assert(pThis->rcvFrom.pRcvFrom == NULL);
2737 
2738 	CHKmalloc(pThis->rcvFrom.pfrominet = malloc(sizeof(struct sockaddr_storage)));
2739 	memcpy(pThis->rcvFrom.pfrominet, sa, sizeof(struct sockaddr_storage));
2740 
2741 finalize_it:
2742 	RETiRet;
2743 }
2744 
2745 /* rgerhards 2008-09-10: set RcvFrom name in msg object. This calls AddRef()
2746  * on the property, because this must be done in all current cases and there
2747  * is no case expected where this may not be necessary.
2748  * rgerhards, 2009-06-30
2749  */
2750 void MsgSetRcvFrom(smsg_t *pThis, prop_t *new)
2751 {
2752 	prop.AddRef(new);
2753 	MsgSetRcvFromWithoutAddRef(pThis, new);
2754 }
2755 
2756 
2757 /* This is used to set the property via a string. This function should not be
2758  * called if there is a reliable way for a caller to make sure that the
2759  * same name can be used across multiple messages. However, if it can not
2760  * ensure that, calling this function is the second best thing, because it
2761  * will re-use the previously created property if it contained the same
2762  * name (but it works only for the immediate previous).
2763  * rgerhards, 2009-06-31
2764  */
2765 void MsgSetRcvFromStr(smsg_t * const pThis, const uchar *psz, const int len, prop_t **ppProp)
2766 {
2767 	assert(pThis != NULL);
2768 	assert(ppProp != NULL);
2769 
2770 	prop.CreateOrReuseStringProp(ppProp, psz, len);
2771 	MsgSetRcvFrom(pThis, *ppProp);
2772 }
2773 
2774 
2775 /* set RcvFromIP name in msg object. This calls AddRef()
2776  * on the property, because this must be done in all current cases and there
2777  * is no case expected where this may not be necessary.
2778  * rgerhards, 2009-06-30
2779  */
2780 rsRetVal MsgSetRcvFromIP(smsg_t *pThis, prop_t *new)
2781 {
2782 	assert(pThis != NULL);
2783 
2784 	prop.AddRef(new);
2785 	MsgSetRcvFromIPWithoutAddRef(pThis, new);
2786 	return RS_RET_OK;
2787 }
2788 
2789 
2790 /* This is used to set the property via a string. This function should not be
2791  * called if there is a reliable way for a caller to make sure that the
2792  * same name can be used across multiple messages. However, if it can not
2793  * ensure that, calling this function is the second best thing, because it
2794  * will re-use the previously created property if it contained the same
2795  * name (but it works only for the immediate previous).
2796  * rgerhards, 2009-06-31
2797  */
2798 rsRetVal MsgSetRcvFromIPStr(smsg_t *const pThis, const uchar *psz, const int len, prop_t **ppProp)
2799 {
2800 	DEFiRet;
2801 	assert(pThis != NULL);
2802 
2803 	CHKiRet(prop.CreateOrReuseStringProp(ppProp, psz, len));
2804 	MsgSetRcvFromIP(pThis, *ppProp);
2805 
2806 finalize_it:
2807 	RETiRet;
2808 }
2809 
2810 
2811 /* rgerhards 2004-11-09: set HOSTNAME in msg object
2812  * rgerhards, 2007-06-21:
2813  * Does not return anything. If an error occurs, the hostname is
2814  * simply not set. I have changed this behaviour. The only problem
2815  * we can run into is memory shortage. If we have such, it is better
2816  * to loose the hostname than the full message. So we silently ignore
2817  * that problem and hope that memory will be available the next time
2818  * we need it. The rest of the code already knows how to handle an
2819  * unset HOSTNAME.
2820  */
2821 void MsgSetHOSTNAME(smsg_t *pThis, const uchar* pszHOSTNAME, const int lenHOSTNAME)
2822 {
2823 	assert(pThis != NULL);
2824 
2825 	freeHOSTNAME(pThis);
2826 
2827 	pThis->iLenHOSTNAME = lenHOSTNAME;
2828 	if(pThis->iLenHOSTNAME < CONF_HOSTNAME_BUFSIZE) {
2829 		/* small enough: use fixed buffer (faster!) */
2830 		pThis->pszHOSTNAME = pThis->szHOSTNAME;
2831 	} else if((pThis->pszHOSTNAME = (uchar*) malloc(pThis->iLenHOSTNAME + 1)) == NULL) {
2832 		/* truncate message, better than completely loosing it... */
2833 		pThis->pszHOSTNAME = pThis->szHOSTNAME;
2834 		pThis->iLenHOSTNAME = CONF_HOSTNAME_BUFSIZE - 1;
2835 	}
2836 
2837 	memcpy(pThis->pszHOSTNAME, pszHOSTNAME, pThis->iLenHOSTNAME);
2838 	pThis->pszHOSTNAME[pThis->iLenHOSTNAME] = '\0'; /* this also works with truncation! */
2839 }
2840 
2841 
2842 /* set the offset of the MSG part into the raw msg buffer
2843  * Note that the offset may be higher than the length of the raw message
2844  * (exactly by one). This can happen if we have a message that does not
2845  * contain any MSG part.
2846  */
2847 void MsgSetMSGoffs(smsg_t * const pMsg, int offs)
2848 {
2849 	ISOBJ_TYPE_assert(pMsg, msg);
2850 	pMsg->offMSG = offs;
2851 	if(offs > pMsg->iLenRawMsg) {
2852 		assert((int)offs - 1 == pMsg->iLenRawMsg);
2853 		pMsg->iLenMSG = 0;
2854 	} else {
2855 		pMsg->iLenMSG = pMsg->iLenRawMsg - offs;
2856 	}
2857 }
2858 
2859 
2860 /* replace the MSG part of a message. The update actually takes place inside
2861  * rawmsg.
2862  * There are two cases: either the new message will be larger than the new msg
2863  * or it will be less than or equal. If it is less than or equal, we can utilize
2864  * the previous message buffer. If it is larger, we can utilize the smsg_t-included
2865  * message buffer if it fits in there. If this is not the case, we need to alloc
2866  * a new, larger, chunk and copy over the data to it. Note that this function is
2867  * (hopefully) relatively seldom being called, so some performance impact is
2868  * uncritical. In any case, pszMSG is copied, so if it was dynamically allocated,
2869  * the caller is responsible for freeing it.
2870  * rgerhards, 2009-06-23
2871  */
2872 rsRetVal MsgReplaceMSG(smsg_t *pThis, const uchar* pszMSG, int lenMSG)
2873 {
2874 	int lenNew;
2875 	uchar *bufNew;
2876 	DEFiRet;
2877 	ISOBJ_TYPE_assert(pThis, msg);
2878 	assert(pszMSG != NULL);
2879 
2880 	lenNew = pThis->iLenRawMsg + lenMSG - pThis->iLenMSG;
2881 	if(lenMSG > pThis->iLenMSG && lenNew >= CONF_RAWMSG_BUFSIZE) {
2882 		/*  we have lost our "bet" and need to alloc a new buffer ;) */
2883 		CHKmalloc(bufNew = malloc(lenNew + 1));
2884 		memcpy(bufNew, pThis->pszRawMsg, pThis->offMSG);
2885 		if(pThis->pszRawMsg != pThis->szRawMsg)
2886 			free(pThis->pszRawMsg);
2887 		pThis->pszRawMsg = bufNew;
2888 	}
2889 
2890 	if(lenMSG > 0)
2891 		memcpy(pThis->pszRawMsg + pThis->offMSG, pszMSG, lenMSG);
2892 	pThis->pszRawMsg[lenNew] = '\0'; /* this also works with truncation! */
2893 	pThis->iLenRawMsg = lenNew;
2894 	pThis->iLenMSG = lenMSG;
2895 
2896 finalize_it:
2897 	RETiRet;
2898 }
2899 
2900 /* truncate the (raw) message to configured max size.
2901  * The function makes sure that the stored rawmsg remains
2902  * properly terminated by '\0'.
2903  */
2904 void ATTR_NONNULL()
2905 MsgTruncateToMaxSize(smsg_t *const pThis)
2906 {
2907 	ISOBJ_TYPE_assert(pThis, msg);
2908 	const int maxMsgSize = glblGetMaxLine();
2909 	assert(pThis->iLenRawMsg > maxMsgSize);
2910 
2911 	const int deltaSize = pThis->iLenRawMsg - maxMsgSize;
2912 	pThis->pszRawMsg[maxMsgSize] = '\0';
2913 	pThis->iLenRawMsg = maxMsgSize;
2914 	if(pThis->iLenMSG < deltaSize) {
2915 		pThis->iLenMSG = 0;
2916 	} else {
2917 		pThis->iLenMSG -= deltaSize;
2918 	}
2919 }
2920 
2921 /* set raw message in message object. Size of message is provided.
2922  * The function makes sure that the stored rawmsg is properly
2923  * terminated by '\0'.
2924  * rgerhards, 2009-06-16
2925  */
2926 void ATTR_NONNULL()
2927 MsgSetRawMsg(smsg_t *const pThis, const char*const pszRawMsg, const size_t lenMsg)
2928 {
2929 	ISOBJ_TYPE_assert(pThis, msg);
2930 	int deltaSize;
2931 	if(pThis->pszRawMsg != pThis->szRawMsg)
2932 		free(pThis->pszRawMsg);
2933 
2934 	deltaSize = (int) lenMsg - pThis->iLenRawMsg; /* value < 0 in truncation case! */
2935 	pThis->iLenRawMsg = lenMsg;
2936 	if(pThis->iLenRawMsg < CONF_RAWMSG_BUFSIZE) {
2937 		/* small enough: use fixed buffer (faster!) */
2938 		pThis->pszRawMsg = pThis->szRawMsg;
2939 	} else if((pThis->pszRawMsg = (uchar*) malloc(pThis->iLenRawMsg + 1)) == NULL) {
2940 		/* truncate message, better than completely loosing it... */
2941 		pThis->pszRawMsg = pThis->szRawMsg;
2942 		pThis->iLenRawMsg = CONF_RAWMSG_BUFSIZE - 1;
2943 	}
2944 
2945 	memcpy(pThis->pszRawMsg, pszRawMsg, pThis->iLenRawMsg);
2946 	pThis->pszRawMsg[pThis->iLenRawMsg] = '\0'; /* this also works with truncation! */
2947 	/* correct other information */
2948 	if(pThis->iLenRawMsg > pThis->offMSG)
2949 		pThis->iLenMSG += deltaSize;
2950 	else
2951 		pThis->iLenMSG = 0;
2952 }
2953 
2954 
2955 /* set raw message in message object. Size of message is not provided. This
2956  * function should only be used when it is unavoidable (and over time we should
2957  * try to remove it altogether).
2958  * rgerhards, 2009-06-16
2959  */
2960 void MsgSetRawMsgWOSize(smsg_t * const pMsg, char* pszRawMsg)
2961 {
2962 	MsgSetRawMsg(pMsg, pszRawMsg, strlen(pszRawMsg));
2963 }
2964 
2965 
2966 /* create textual representation of facility and severity.
2967  * The variable pRes must point to a user-supplied buffer of
2968  * at least 20 characters.
2969  */
2970 static uchar *
2971 textpri(const smsg_t *const __restrict__ pMsg)
2972 {
2973 	int lenfac = len_syslog_fac_names[pMsg->iFacility];
2974 	int lensev = len_syslog_severity_names[pMsg->iSeverity];
2975 	int totlen = lenfac + 1 + lensev + 1;
2976 	char *pRes = malloc(totlen);
2977 	if(pRes != NULL) {
2978 		memcpy(pRes, syslog_fac_names[pMsg->iFacility], lenfac);
2979 		pRes[lenfac] = '.';
2980 		memcpy(pRes+lenfac+1, syslog_severity_names[pMsg->iSeverity], lensev+1 /* for \0! */);
2981 	}
2982 	return (uchar*)pRes;
2983 }
2984 
2985 
2986 /* This function returns the current date in different
2987  * variants. It is used to construct the $NOW series of
2988  * system properties. The returned buffer must be freed
2989  * by the caller when no longer needed. If the function
2990  * can not allocate memory, it returns a NULL pointer.
2991  * Added 2007-07-10 rgerhards
2992  */
2993 typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR,
2994 		NOW_HHOUR, NOW_QHOUR, NOW_MINUTE, NOW_WDAY } eNOWType;
2995 #define tmpBUFSIZE 16	/* size of formatting buffer */
2996 static uchar *getNOW(eNOWType eNow, struct syslogTime *t, const int inUTC)
2997 {
2998 	uchar *pBuf;
2999 	struct syslogTime tt;
3000 
3001 	if((pBuf = (uchar*) malloc(tmpBUFSIZE)) == NULL) {
3002 		return NULL;
3003 	}
3004 
3005 	if(t == NULL) { /* can happen if called via script engine */
3006 		datetime.getCurrTime(&tt, NULL, inUTC);
3007 		t = &tt;
3008 	}
3009 
3010 	if(t->year == 0 || t->inUTC != inUTC) { /* not yet set! */
3011 		datetime.getCurrTime(t, NULL, inUTC);
3012 	}
3013 
3014 	switch(eNow) {
3015 	case NOW_NOW:
3016 		memcpy(pBuf, two_digits[t->year/100], 2);
3017 		memcpy(pBuf+2, two_digits[t->year%100], 2);
3018 		pBuf[4] = '-';
3019 		memcpy(pBuf+5, two_digits[(int)t->month], 2);
3020 		pBuf[7] = '-';
3021 		memcpy(pBuf+8, two_digits[(int)t->day], 3);
3022 		break;
3023 	case NOW_YEAR:
3024 		memcpy(pBuf, two_digits[t->year/100], 2);
3025 		memcpy(pBuf+2, two_digits[t->year%100], 3);
3026 		break;
3027 	case NOW_MONTH:
3028 		memcpy(pBuf, two_digits[(int)t->month], 3);
3029 		break;
3030 	case NOW_DAY:
3031 		memcpy(pBuf, two_digits[(int)t->day], 3);
3032 		break;
3033 	case NOW_HOUR:
3034 		memcpy(pBuf, two_digits[(int)t->hour], 3);
3035 		break;
3036 	case NOW_HHOUR:
3037 		memcpy(pBuf, two_digits[t->minute/30], 3);
3038 		break;
3039 	case NOW_QHOUR:
3040 		memcpy(pBuf, two_digits[t->minute/15], 3);
3041 		break;
3042 	case NOW_MINUTE:
3043 		memcpy(pBuf, two_digits[(int)t->minute], 3);
3044 		break;
3045 	case NOW_WDAY:
3046 		memcpy(pBuf, one_digit[(int)t->wday], 2);
3047 		break;
3048 	}
3049 
3050 	return(pBuf);
3051 }
3052 #undef tmpBUFSIZE /* clean up */
3053 
3054 
3055 /* helper function to obtain correct JSON root and mutex depending on
3056  * property type (essentially based on the property id. If a non-json
3057  * property id is given the function errors out.
3058  * Note well: jroot points to a pointer to a (ptr to a) json object.
3059  * This is necessary because the caller needs a pointer to where the
3060  * json object pointer is stored, that in turn is necessary because
3061  * while the address of the actual pointer stays stable, the actual
3062  * content is volatile until the caller has locked the variable tree,
3063  * which we DO NOT do to keep calling semantics simple.
3064  */
3065 static rsRetVal ATTR_NONNULL()
3066 getJSONRootAndMutex(smsg_t *const pMsg, const propid_t id,
3067 	struct json_object ***const jroot, pthread_mutex_t **const mut)
3068 {
3069 	DEFiRet;
3070 	assert(jroot != NULL); /* asserts also help static analyzer! */
3071 	assert(mut != NULL);
3072 	assert(*mut == NULL); /* caller shall have initialized this one! */
3073 	assert(id == PROP_CEE || id == PROP_LOCAL_VAR || id == PROP_GLOBAL_VAR);
3074 
3075 	if(id == PROP_CEE) {
3076 		*mut = &pMsg->mut;
3077 		*jroot = &pMsg->json;
3078 	} else if(id == PROP_LOCAL_VAR) {
3079 		*mut = &pMsg->mut;
3080 		*jroot = &pMsg->localvars;
3081 	} else if(id == PROP_GLOBAL_VAR) {
3082 		*mut = &glblVars_lock;
3083 		*jroot = &global_var_root;
3084 	} else {
3085 		LogError(0, RS_RET_NON_JSON_PROP, "internal error:  "
3086 			"getJSONRootAndMutex; invalid property id %d", id);
3087 		iRet = RS_RET_NON_JSON_PROP;
3088 	}
3089 
3090 	RETiRet;
3091 }
3092 
3093 /* basically same function, but does not use property id, but the the
3094  * variable name type indicator (char after starting $, e.g. $!myvar --> CEE)
3095  */
3096 static rsRetVal ATTR_NONNULL()
3097 getJSONRootAndMutexByVarChar(smsg_t *const pMsg, const char c,
3098 	struct json_object ***const jroot, pthread_mutex_t **const mut)
3099 {
3100 	DEFiRet;
3101 	propid_t id;
3102 	assert(c == '!' || c == '.' || c == '/');
3103 
3104 	switch(c) {
3105 		case '!':
3106 			id = PROP_CEE;
3107 			break;
3108 		case '.':
3109 			id = PROP_LOCAL_VAR;
3110 			break;
3111 		case '/':
3112 			id = PROP_GLOBAL_VAR;
3113 			break;
3114 		default:
3115 			LogError(0, RS_RET_NON_JSON_PROP, "internal error:  "
3116 				"getJSONRootAndMutex; invalid indicator char %c(%2.2x)", c, c);
3117 			ABORT_FINALIZE(RS_RET_NON_JSON_PROP);
3118 			break;
3119 	}
3120 	iRet = getJSONRootAndMutex(pMsg, id, jroot, mut);
3121 
3122 finalize_it:
3123 	RETiRet;
3124 }
3125 
3126 
3127 /* Get a JSON-Property as string value  (used for various types of JSON-based vars) */
3128 rsRetVal
3129 getJSONPropVal(smsg_t * const pMsg, msgPropDescr_t *pProp, uchar **pRes, rs_size_t *buflen,
3130 	unsigned short *pbMustBeFreed)
3131 {
3132 	uchar *leaf;
3133 	struct json_object **jroot;
3134 	struct json_object *parent;
3135 	struct json_object *field;
3136 	pthread_mutex_t *mut = NULL;
3137 	DEFiRet;
3138 
3139 	*pRes = NULL;
3140 	CHKiRet(getJSONRootAndMutex(pMsg, pProp->id, &jroot, &mut));
3141 	pthread_mutex_lock(mut);
3142 
3143 	if(*jroot == NULL) FINALIZE;
3144 
3145 	if(!strcmp((char*)pProp->name, "!")) {
3146 		field = *jroot;
3147 	} else {
3148 		leaf = jsonPathGetLeaf(pProp->name, pProp->nameLen);
3149 		CHKiRet(jsonPathFindParent(*jroot, pProp->name, leaf, &parent, 0));
3150 		if(jsonVarExtract(parent, (char*)leaf, &field) == FALSE)
3151 			field = NULL;
3152 	}
3153 	if(field != NULL) {
3154 		*pRes = (uchar*) strdup(json_object_get_string(field));
3155 		*buflen = (int) ustrlen(*pRes);
3156 		*pbMustBeFreed = 1;
3157 	}
3158 
3159 finalize_it:
3160 	if(mut != NULL)
3161 		pthread_mutex_unlock(mut);
3162 	if(*pRes == NULL) {
3163 		/* could not find any value, so set it to empty */
3164 		*pRes = (unsigned char*)"";
3165 		*pbMustBeFreed = 0;
3166 	}
3167 	RETiRet;
3168 }
3169 
3170 
3171 /* Get a JSON-based-variable as native json object, except
3172  * when it is string type, in which case a string is returned.
3173  * This is an optimization to not use JSON when not strictly
3174  * necessary. This in turn is helpful, as calling json-c is
3175  * *very* expensive due to our need for locking and deep
3176  * copies.
3177  * The caller needs to check pjson and pcstr: one of them
3178  * is non-NULL and contains the return value. Note that
3179  * the caller is responsible for freeing the string pointer
3180  * it if is being returned.
3181  */
3182 rsRetVal
3183 msgGetJSONPropJSONorString(smsg_t * const pMsg, msgPropDescr_t *pProp, struct json_object **pjson,
3184 	uchar **pcstr)
3185 {
3186 	struct json_object **jroot;
3187 	uchar *leaf;
3188 	struct json_object *parent;
3189 	pthread_mutex_t *mut = NULL;
3190 	DEFiRet;
3191 
3192 	*pjson = NULL, *pcstr = NULL;
3193 
3194 	CHKiRet(getJSONRootAndMutex(pMsg, pProp->id, &jroot, &mut));
3195 	pthread_mutex_lock(mut);
3196 	if(!strcmp((char*)pProp->name, "!")) {
3197 		*pjson = *jroot;
3198 		FINALIZE;
3199 	}
3200 	if(*jroot == NULL) {
3201 		ABORT_FINALIZE(RS_RET_NOT_FOUND);
3202 	}
3203 	leaf = jsonPathGetLeaf(pProp->name, pProp->nameLen);
3204 	CHKiRet(jsonPathFindParent(*jroot, pProp->name, leaf, &parent, 0));
3205 	if(jsonVarExtract(parent, (char*)leaf, pjson) == FALSE) {
3206 		ABORT_FINALIZE(RS_RET_NOT_FOUND);
3207 	}
3208 	if(*pjson == NULL) {
3209 		/* we had a NULL json object and represent this as empty string */
3210 		*pcstr = (uchar*) strdup("");
3211 	} else {
3212 		if(json_object_get_type(*pjson) == json_type_string) {
3213 			*pcstr = (uchar*) strdup(json_object_get_string(*pjson));
3214 			*pjson = NULL;
3215 		}
3216 	}
3217 
3218 finalize_it:
3219 	/* we need a deep copy, as another thread may modify the object */
3220 	if(*pjson != NULL)
3221 		*pjson = jsonDeepCopy(*pjson);
3222 	if(mut != NULL)
3223 		pthread_mutex_unlock(mut);
3224 	RETiRet;
3225 }
3226 
3227 
3228 
3229 /* Get a JSON-based-variable as native json object */
3230 rsRetVal
3231 msgGetJSONPropJSON(smsg_t * const pMsg, msgPropDescr_t *pProp, struct json_object **pjson)
3232 {
3233 	struct json_object **jroot;
3234 	uchar *leaf;
3235 	struct json_object *parent;
3236 	pthread_mutex_t *mut = NULL;
3237 	DEFiRet;
3238 
3239 	*pjson = NULL;
3240 
3241 	CHKiRet(getJSONRootAndMutex(pMsg, pProp->id, &jroot, &mut));
3242 	pthread_mutex_lock(mut);
3243 
3244 	if(!strcmp((char*)pProp->name, "!")) {
3245 		*pjson = *jroot;
3246 		FINALIZE;
3247 	}
3248 	leaf = jsonPathGetLeaf(pProp->name, pProp->nameLen);
3249 	CHKiRet(jsonPathFindParent(*jroot, pProp->name, leaf, &parent, 0));
3250 	if(jsonVarExtract(parent, (char*)leaf, pjson) == FALSE) {
3251 		ABORT_FINALIZE(RS_RET_NOT_FOUND);
3252 	}
3253 
3254 finalize_it:
3255 	/* we need a deep copy, as another thread may modify the object */
3256 	if(*pjson != NULL)
3257 		*pjson = jsonDeepCopy(*pjson);
3258 	if(mut != NULL)
3259 		pthread_mutex_unlock(mut);
3260 	RETiRet;
3261 }
3262 
3263 
3264 /* Encode a JSON value and add it to provided string. Note that
3265  * the string object may be NULL. In this case, it is created
3266  * if and only if escaping is needed. if escapeAll is false, previously
3267  * escaped strings are left as is
3268  */
3269 static rsRetVal
3270 jsonAddVal(uchar *pSrc, unsigned buflen, es_str_t **dst, int escapeAll)
3271 {
3272 	unsigned char c;
3273 	es_size_t i;
3274 	char numbuf[4];
3275 	unsigned ni;
3276 	unsigned char nc;
3277 	int j;
3278 	DEFiRet;
3279 
3280 	for(i = 0 ; i < buflen ; ++i) {
3281 		c = pSrc[i];
3282 		if(   (c >= 0x23 && c <= 0x2e)
3283 		   || (c >= 0x30 && c <= 0x5b)
3284 		   || (c >= 0x5d /* && c <= 0x10FFFF*/)
3285 		   || c == 0x20 || c == 0x21) {
3286 			/* no need to escape */
3287 			if(*dst != NULL)
3288 				es_addChar(dst, c);
3289 		} else {
3290 			if(*dst == NULL) {
3291 				if(i == 0) {
3292 					/* we hope we have only few escapes... */
3293 					*dst = es_newStr(buflen+10);
3294 				} else {
3295 					*dst = es_newStrFromBuf((char*)pSrc, i);
3296 				}
3297 				if(*dst == NULL) {
3298 					ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
3299 				}
3300 			}
3301 			/* we must escape, try RFC4627-defined special sequences first */
3302 			switch(c) {
3303 			case '\0':
3304 				es_addBuf(dst, "\\u0000", 6);
3305 				break;
3306 			case '\"':
3307 				es_addBuf(dst, "\\\"", 2);
3308 				break;
3309 			case '/':
3310 				es_addBuf(dst, "\\/", 2);
3311 				break;
3312 			case '\\':
3313 				if (escapeAll == RSFALSE) {
3314 					ni = i + 1;
3315 					if (ni <= buflen) {
3316 						nc = pSrc[ni];
3317 
3318 						/* Attempt to not double encode */
3319 						if (   nc == '"' || nc == '/' || nc == '\\' || nc == 'b' || nc == 'f'
3320 							|| nc == 'n' || nc == 'r' || nc == 't' || nc == 'u') {
3321 
3322 							es_addChar(dst, c);
3323 							es_addChar(dst, nc);
3324 							i = ni;
3325 							break;
3326 						}
3327 					}
3328 				}
3329 
3330 				es_addBuf(dst, "\\\\", 2);
3331 				break;
3332 			case '\010':
3333 				es_addBuf(dst, "\\b", 2);
3334 				break;
3335 			case '\014':
3336 				es_addBuf(dst, "\\f", 2);
3337 				break;
3338 			case '\n':
3339 				es_addBuf(dst, "\\n", 2);
3340 				break;
3341 			case '\r':
3342 				es_addBuf(dst, "\\r", 2);
3343 				break;
3344 			case '\t':
3345 				es_addBuf(dst, "\\t", 2);
3346 				break;
3347 			default:
3348 				/* TODO : proper Unicode encoding (see header comment) */
3349 				for(j = 0 ; j < 4 ; ++j) {
3350 					numbuf[3-j] = hexdigit[c % 16];
3351 					c = c / 16;
3352 				}
3353 				es_addBuf(dst, "\\u", 2);
3354 				es_addBuf(dst, numbuf, 4);
3355 				break;
3356 			}
3357 		}
3358 	}
3359 finalize_it:
3360 	RETiRet;
3361 }
3362 
3363 
3364 /* encode a property in JSON escaped format. This is a helper
3365  * to MsgGetProp. It needs to update all provided parameters.
3366  * For performance reasons, we begin to copy the string only
3367  * when we recognice that we actually need to do some escaping.
3368  * rgerhards, 2012-03-16
3369  */
3370 static rsRetVal
3371 jsonEncode(uchar **ppRes, unsigned short *pbMustBeFreed, int *pBufLen, int escapeAll)
3372 {
3373 	unsigned buflen;
3374 	uchar *pSrc;
3375 	es_str_t *dst = NULL;
3376 	DEFiRet;
3377 
3378 	pSrc = *ppRes;
3379 	buflen = (*pBufLen == -1) ? (int) ustrlen(pSrc) : *pBufLen;
3380 	CHKiRet(jsonAddVal(pSrc, buflen, &dst, escapeAll));
3381 
3382 	if(dst != NULL) {
3383 		/* we updated the string and need to replace the
3384 		 * previous data.
3385 		 */
3386 		if(*pbMustBeFreed)
3387 			free(*ppRes);
3388 		*ppRes = (uchar*)es_str2cstr(dst, NULL);
3389 		*pbMustBeFreed = 1;
3390 		*pBufLen = -1;
3391 		es_deleteStr(dst);
3392 	}
3393 
3394 finalize_it:
3395 	RETiRet;
3396 }
3397 
3398 
3399 /* Format a property as JSON field, that means
3400  * "name"="value"
3401  * where value is JSON-escaped (here we assume that the name
3402  * only contains characters from the valid character set).
3403  * Note: this function duplicates code from jsonEncode().
3404  * TODO: these two functions should be combined, at least if
3405  * that makes any sense from a performance PoV - definitely
3406  * something to consider at a later stage. rgerhards, 2012-04-19
3407  */
3408 static rsRetVal ATTR_NONNULL()
3409 jsonField(const struct templateEntry *const pTpe,
3410 	uchar **const ppRes,
3411 	unsigned short *const pbMustBeFreed,
3412 	int *const pBufLen,
3413 	int escapeAll)
3414 {
3415 	unsigned buflen;
3416 	uchar *pSrc;
3417 	es_str_t *dst = NULL;
3418 	int is_numeric = 1;
3419 	DEFiRet;
3420 
3421 	pSrc = *ppRes;
3422 	buflen = (*pBufLen == -1) ? (int) ustrlen(pSrc) : *pBufLen;
3423 dbgprintf("jsonEncode: datatype: %u, onEmpty: %u val %*s\n", (unsigned) pTpe->data.field.options.dataType,
3424 (unsigned) pTpe->data.field.options.onEmpty, buflen, pSrc);
3425 	if(buflen == 0) {
3426 		if(pTpe->data.field.options.onEmpty == TPE_DATAEMPTY_SKIP) {
3427 			FINALIZE;
3428 		}
3429 		is_numeric = 0;
3430 	}
3431 	/* we hope we have only few escapes... */
3432 	dst = es_newStr(buflen+pTpe->lenFieldName+15);
3433 	es_addChar(&dst, '"');
3434 	es_addBuf(&dst, (char*)pTpe->fieldName, pTpe->lenFieldName);
3435 	es_addBufConstcstr(&dst, "\":");
3436 	if(buflen == 0 && pTpe->data.field.options.onEmpty == TPE_DATAEMPTY_NULL) {
3437 		es_addBufConstcstr(&dst, "null");
3438 	} else {
3439 		if(pTpe->data.field.options.dataType == TPE_DATATYPE_AUTO) {
3440 			for(unsigned i = 0 ; i < buflen ; ++i) {
3441 				if(pSrc[i] < '0' || pSrc[i] > '9') {
3442 					is_numeric = 0;
3443 					break;
3444 				}
3445 			}
3446 			if(!is_numeric) {
3447 				es_addChar(&dst, '"');
3448 			}
3449 			CHKiRet(jsonAddVal(pSrc, buflen, &dst, escapeAll));
3450 			if(!is_numeric) {
3451 				es_addChar(&dst, '"');
3452 			}
3453 		} else if(pTpe->data.field.options.dataType == TPE_DATATYPE_STRING) {
3454 			es_addChar(&dst, '"');
3455 			CHKiRet(jsonAddVal(pSrc, buflen, &dst, escapeAll));
3456 			es_addChar(&dst, '"');
3457 		} else if(pTpe->data.field.options.dataType == TPE_DATATYPE_NUMBER) {
3458 			if(buflen == 0) {
3459 				es_addChar(&dst, '0');
3460 			} else {
3461 				CHKiRet(jsonAddVal(pSrc, buflen, &dst, escapeAll));
3462 			}
3463 		} else if(pTpe->data.field.options.dataType == TPE_DATATYPE_BOOL) {
3464 			if(buflen == 1 && *pSrc == '0') {
3465 				es_addBufConstcstr(&dst, "false");
3466 			} else {
3467 				es_addBufConstcstr(&dst, "true");
3468 			}
3469 		}
3470 	}
3471 
3472 	if(*pbMustBeFreed)
3473 		free(*ppRes);
3474 	/* we know we do not have \0 chars - so the size does not change */
3475 	*pBufLen = es_strlen(dst);
3476 	*ppRes = (uchar*)es_str2cstr(dst, NULL);
3477 	*pbMustBeFreed = 1;
3478 	es_deleteStr(dst);
3479 
3480 finalize_it:
3481 	RETiRet;
3482 }
3483 
3484 
3485 /* This function returns a string-representation of the
3486  * requested message property. This is a generic function used
3487  * to abstract properties so that these can be easier
3488  * queried. Returns NULL if property could not be found.
3489  * Actually, this function is a big if..elseif. What it does
3490  * is simply to map property names (from MonitorWare) to the
3491  * message object data fields.
3492  *
3493  * In case we need string forms of propertis we do not
3494  * yet have in string form, we do a memory allocation that
3495  * is sufficiently large (in all cases). Once the string
3496  * form has been obtained, it is saved until the Msg object
3497  * is finally destroyed. This is so that we save the processing
3498  * time in the (likely) case that this property is requested
3499  * again. It also saves us a lot of dynamic memory management
3500  * issues in the upper layers, because we so can guarantee that
3501  * the buffer will remain static AND available during the lifetime
3502  * of the object. Please note that both the max size allocation as
3503  * well as keeping things in memory might like look like a
3504  * waste of memory (some might say it actually is...) - we
3505  * deliberately accept this because performance is more important
3506  * to us ;)
3507  * rgerhards 2004-11-18
3508  * Parameter "bMustBeFreed" is set by this function. It tells the
3509  * caller whether or not the string returned must be freed by the
3510  * caller itself. It is is 0, the caller MUST NOT free it. If it is
3511  * 1, the caller MUST free it. Handling this wrongly leads to either
3512  * a memory leak of a program abort (do to double-frees or frees on
3513  * the constant memory pool). So be careful to do it right.
3514  * rgerhards 2004-11-23
3515  * regular expression support contributed by Andres Riancho merged
3516  * on 2005-09-13
3517  * changed so that it now an be called without a template entry (NULL).
3518  * In this case, only the (unmodified) property is returned. This will
3519  * be used in selector line processing.
3520  * rgerhards 2005-09-15
3521  */
3522 /* a quick helper to save some writing: */
3523 #define RET_OUT_OF_MEMORY { *pbMustBeFreed = 0;\
3524 	*pPropLen = sizeof("**OUT OF MEMORY**") - 1; \
3525 	return(UCHAR_CONSTANT("**OUT OF MEMORY**"));}
3526 uchar *MsgGetProp(smsg_t *__restrict__ const pMsg, struct templateEntry *__restrict__ const pTpe,
3527 			msgPropDescr_t *pProp, rs_size_t *__restrict__ const pPropLen,
3528 			unsigned short *__restrict__ const pbMustBeFreed, struct syslogTime * const ttNow)
3529 {
3530 	uchar *pRes; /* result pointer */
3531 	rs_size_t bufLen = -1; /* length of string or -1, if not known */
3532 	uchar *pBufStart;
3533 	uchar *pBuf;
3534 	int iLen;
3535 	short iOffs;
3536 	enum tplFormatTypes datefmt;
3537 	int bDateInUTC;
3538 
3539 	assert(pMsg != NULL);
3540 	assert(pbMustBeFreed != NULL);
3541 
3542 #ifdef	FEATURE_REGEXP
3543 	/* Variables necessary for regular expression matching */
3544 	size_t nmatch = 10;
3545 	regmatch_t pmatch[10];
3546 #endif
3547 
3548 	*pbMustBeFreed = 0;
3549 
3550 	switch(pProp->id) {
3551 		case PROP_MSG:
3552 			pRes = getMSG(pMsg);
3553 			bufLen = getMSGLen(pMsg);
3554 			break;
3555 		case PROP_TIMESTAMP:
3556 			if(pTpe != NULL) {
3557 				datefmt = pTpe->data.field.eDateFormat;
3558 				bDateInUTC = pTpe->data.field.options.bDateInUTC;
3559 			} else {
3560 				datefmt = tplFmtDefault;
3561 				bDateInUTC = 0;
3562 			}
3563 			if(bDateInUTC) {
3564 				pRes = (uchar*)getTimeUTC(&pMsg->tTIMESTAMP, datefmt, pbMustBeFreed);
3565 			} else {
3566 				pRes = (uchar*)getTimeReported(pMsg, datefmt);
3567 			}
3568 			break;
3569 		case PROP_HOSTNAME:
3570 			pRes = (uchar*)getHOSTNAME(pMsg);
3571 			bufLen = getHOSTNAMELen(pMsg);
3572 			break;
3573 		case PROP_SYSLOGTAG:
3574 			getTAG(pMsg, &pRes, &bufLen, LOCK_MUTEX);
3575 			break;
3576 		case PROP_RAWMSG:
3577 			getRawMsg(pMsg, &pRes, &bufLen);
3578 			break;
3579 		case PROP_RAWMSG_AFTER_PRI:
3580 			getRawMsgAfterPRI(pMsg, &pRes, &bufLen);
3581 			break;
3582 		case PROP_INPUTNAME:
3583 			getInputName(pMsg, &pRes, &bufLen);
3584 			break;
3585 		case PROP_FROMHOST:
3586 			pRes = getRcvFrom(pMsg);
3587 			break;
3588 		case PROP_FROMHOST_IP:
3589 			pRes = getRcvFromIP(pMsg);
3590 			break;
3591 		case PROP_PRI:
3592 			pRes = (uchar*)getPRI(pMsg);
3593 			break;
3594 		case PROP_PRI_TEXT:
3595 			pRes = textpri(pMsg);
3596 			if(pRes == NULL)
3597 				RET_OUT_OF_MEMORY;
3598 			*pbMustBeFreed = 1;
3599 			break;
3600 		case PROP_IUT:
3601 			pRes = UCHAR_CONSTANT("1"); /* always 1 for syslog messages (a MonitorWare thing;)) */
3602 			bufLen = 1;
3603 			break;
3604 		case PROP_SYSLOGFACILITY:
3605 			pRes = (uchar*)getFacility(pMsg);
3606 			break;
3607 		case PROP_SYSLOGFACILITY_TEXT:
3608 			pRes = (uchar*)getFacilityStr(pMsg);
3609 			break;
3610 		case PROP_SYSLOGSEVERITY:
3611 			pRes = (uchar*)getSeverity(pMsg);
3612 			break;
3613 		case PROP_SYSLOGSEVERITY_TEXT:
3614 			pRes = (uchar*)getSeverityStr(pMsg);
3615 			break;
3616 		case PROP_TIMEGENERATED:
3617 			if(pTpe != NULL) {
3618 				datefmt = pTpe->data.field.eDateFormat;
3619 				bDateInUTC = pTpe->data.field.options.bDateInUTC;
3620 			} else {
3621 				datefmt = tplFmtDefault;
3622 				bDateInUTC = 0;
3623 			}
3624 			if(bDateInUTC) {
3625 				pRes = (uchar*)getTimeUTC(&pMsg->tRcvdAt, datefmt, pbMustBeFreed);
3626 			} else {
3627 				pRes = (uchar*)getTimeGenerated(pMsg, datefmt);
3628 			}
3629 			break;
3630 		case PROP_PROGRAMNAME:
3631 			pRes = getProgramName(pMsg, LOCK_MUTEX);
3632 			break;
3633 		case PROP_PROTOCOL_VERSION:
3634 			pRes = (uchar*)getProtocolVersionString(pMsg);
3635 			break;
3636 		case PROP_STRUCTURED_DATA:
3637 			MsgGetStructuredData(pMsg, &pRes, &bufLen);
3638 			break;
3639 		case PROP_APP_NAME:
3640 			pRes = (uchar*)getAPPNAME(pMsg, LOCK_MUTEX);
3641 			break;
3642 		case PROP_PROCID:
3643 			pRes = (uchar*)getPROCID(pMsg, LOCK_MUTEX);
3644 			break;
3645 		case PROP_MSGID:
3646 			pRes = (uchar*)getMSGID(pMsg);
3647 			break;
3648 		case PROP_JSONMESG:
3649 			pRes = (uchar*)msgGetJSONMESG(pMsg);
3650 			*pbMustBeFreed = 1;
3651 			break;
3652 #ifdef USE_LIBUUID
3653 		case PROP_UUID:
3654 			getUUID(pMsg, &pRes, &bufLen);
3655 			break;
3656 #endif
3657 		case PROP_PARSESUCCESS:
3658 			pRes = (uchar*)getParseSuccess(pMsg);
3659 			break;
3660 		case PROP_SYS_NOW:
3661 			if((pRes = getNOW(NOW_NOW, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3662 				RET_OUT_OF_MEMORY;
3663 			} else {
3664 				*pbMustBeFreed = 1;
3665 				bufLen = 10;
3666 			}
3667 			break;
3668 		case PROP_SYS_YEAR:
3669 			if((pRes = getNOW(NOW_YEAR, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3670 				RET_OUT_OF_MEMORY;
3671 			} else {
3672 				*pbMustBeFreed = 1;
3673 				bufLen = 4;
3674 			}
3675 			break;
3676 		case PROP_SYS_MONTH:
3677 			if((pRes = getNOW(NOW_MONTH, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3678 				RET_OUT_OF_MEMORY;
3679 			} else {
3680 				*pbMustBeFreed = 1;
3681 				bufLen = 2;
3682 			}
3683 			break;
3684 		case PROP_SYS_DAY:
3685 			if((pRes = getNOW(NOW_DAY, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3686 				RET_OUT_OF_MEMORY;
3687 			} else {
3688 				*pbMustBeFreed = 1;
3689 				bufLen = 2;
3690 			}
3691 			break;
3692 		case PROP_SYS_HOUR:
3693 			if((pRes = getNOW(NOW_HOUR, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3694 				RET_OUT_OF_MEMORY;
3695 			} else {
3696 				*pbMustBeFreed = 1;
3697 				bufLen = 2;
3698 			}
3699 			break;
3700 		case PROP_SYS_HHOUR:
3701 			if((pRes = getNOW(NOW_HHOUR, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3702 				RET_OUT_OF_MEMORY;
3703 			} else {
3704 				*pbMustBeFreed = 1;
3705 				bufLen = 2;
3706 			}
3707 			break;
3708 		case PROP_SYS_QHOUR:
3709 			if((pRes = getNOW(NOW_QHOUR, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3710 				RET_OUT_OF_MEMORY;
3711 			} else {
3712 				*pbMustBeFreed = 1;
3713 				bufLen = 2;
3714 			}
3715 			break;
3716 		case PROP_SYS_MINUTE:
3717 			if((pRes = getNOW(NOW_MINUTE, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3718 				RET_OUT_OF_MEMORY;
3719 			} else {
3720 				*pbMustBeFreed = 1;
3721 				bufLen = 2;
3722 			}
3723 			break;
3724 		case PROP_SYS_NOW_UTC:
3725 			if((pRes = getNOW(NOW_NOW, ttNow, TIME_IN_UTC)) == NULL) {
3726 				RET_OUT_OF_MEMORY;
3727 			} else {
3728 				*pbMustBeFreed = 1;
3729 				bufLen = 10;
3730 			}
3731 			break;
3732 		case PROP_SYS_YEAR_UTC:
3733 			if((pRes = getNOW(NOW_YEAR, ttNow, TIME_IN_UTC)) == NULL) {
3734 				RET_OUT_OF_MEMORY;
3735 			} else {
3736 				*pbMustBeFreed = 1;
3737 				bufLen = 4;
3738 			}
3739 			break;
3740 		case PROP_SYS_MONTH_UTC:
3741 			if((pRes = getNOW(NOW_MONTH, ttNow, TIME_IN_UTC)) == NULL) {
3742 				RET_OUT_OF_MEMORY;
3743 			} else {
3744 				*pbMustBeFreed = 1;
3745 				bufLen = 2;
3746 			}
3747 			break;
3748 		case PROP_SYS_DAY_UTC:
3749 			if((pRes = getNOW(NOW_DAY, ttNow, TIME_IN_UTC)) == NULL) {
3750 				RET_OUT_OF_MEMORY;
3751 			} else {
3752 				*pbMustBeFreed = 1;
3753 				bufLen = 2;
3754 			}
3755 			break;
3756 		case PROP_SYS_HOUR_UTC:
3757 			if((pRes = getNOW(NOW_HOUR, ttNow, TIME_IN_UTC)) == NULL) {
3758 				RET_OUT_OF_MEMORY;
3759 			} else {
3760 				*pbMustBeFreed = 1;
3761 				bufLen = 2;
3762 			}
3763 			break;
3764 		case PROP_SYS_HHOUR_UTC:
3765 			if((pRes = getNOW(NOW_HHOUR, ttNow, TIME_IN_UTC)) == NULL) {
3766 				RET_OUT_OF_MEMORY;
3767 			} else {
3768 				*pbMustBeFreed = 1;
3769 				bufLen = 2;
3770 			}
3771 			break;
3772 		case PROP_SYS_QHOUR_UTC:
3773 			if((pRes = getNOW(NOW_QHOUR, ttNow, TIME_IN_UTC)) == NULL) {
3774 				RET_OUT_OF_MEMORY;
3775 			} else {
3776 				*pbMustBeFreed = 1;
3777 				bufLen = 2;
3778 			}
3779 			break;
3780 		case PROP_SYS_MINUTE_UTC:
3781 			if((pRes = getNOW(NOW_MINUTE, ttNow, TIME_IN_UTC)) == NULL) {
3782 				RET_OUT_OF_MEMORY;
3783 			} else {
3784 				*pbMustBeFreed = 1;
3785 				bufLen = 2;
3786 			}
3787 			break;
3788 		case PROP_SYS_WDAY:
3789 			if((pRes = getNOW(NOW_WDAY, ttNow, TIME_IN_LOCALTIME)) == NULL) {
3790 				RET_OUT_OF_MEMORY;
3791 			} else {
3792 				*pbMustBeFreed = 1;
3793 				bufLen = 1;
3794 			}
3795 			break;
3796 		case PROP_SYS_WDAY_UTC:
3797 			if((pRes = getNOW(NOW_WDAY, ttNow, TIME_IN_UTC)) == NULL) {
3798 				RET_OUT_OF_MEMORY;
3799 			} else {
3800 				*pbMustBeFreed = 1;
3801 				bufLen = 1;
3802 			}
3803 			break;
3804 		case PROP_SYS_NOW_UXTIMESTAMP:
3805 			if((pRes = malloc(16)) == NULL) {
3806 				RET_OUT_OF_MEMORY;
3807 			} else {
3808 				snprintf((char*) pRes, 16-1, "%lld", (long long) getTime(NULL));
3809 				pRes[16-1] = '\0';
3810 				*pbMustBeFreed = 1;
3811 				bufLen = -1;
3812 			}
3813 			break;
3814 		case PROP_SYS_MYHOSTNAME:
3815 			pRes = glbl.GetLocalHostName();
3816 			break;
3817 		case PROP_CEE_ALL_JSON:
3818 		case PROP_CEE_ALL_JSON_PLAIN:
3819 			if(pMsg->json == NULL) {
3820 				pRes = (uchar*) "{}";
3821 				bufLen = 2;
3822 				*pbMustBeFreed = 0;
3823 			} else {
3824 				const char *jstr;
3825 				MsgLock(pMsg);
3826 				int jflag = 0;
3827 				if(pProp->id == PROP_CEE_ALL_JSON) {
3828 					jflag = JSON_C_TO_STRING_SPACED;
3829 				} else if(pProp->id == PROP_CEE_ALL_JSON_PLAIN) {
3830 					jflag = JSON_C_TO_STRING_PLAIN;
3831 				}
3832 				jstr = json_object_to_json_string_ext(pMsg->json, jflag);
3833 				MsgUnlock(pMsg);
3834 				if(jstr == NULL) {
3835 					RET_OUT_OF_MEMORY;
3836 				}
3837 				pRes = (uchar*)strdup(jstr);
3838 				if(pRes == NULL) {
3839 					RET_OUT_OF_MEMORY;
3840 				}
3841 				*pbMustBeFreed = 1;
3842 			}
3843 			break;
3844 		case PROP_CEE:
3845 		case PROP_LOCAL_VAR:
3846 		case PROP_GLOBAL_VAR:
3847 			getJSONPropVal(pMsg, pProp, &pRes, &bufLen, pbMustBeFreed);
3848 			break;
3849 		case PROP_SYS_BOM:
3850 			pRes = (uchar*) "\xEF\xBB\xBF";
3851 			*pbMustBeFreed = 0;
3852 			break;
3853 		case PROP_SYS_UPTIME:
3854 #			ifndef HAVE_SYSINFO_UPTIME
3855 			/* An alternative on some systems (eg Solaris) is to scan
3856 			* /var/adm/utmpx for last boot time.
3857 			*/
3858 			pRes = (uchar*) "UPTIME NOT available on this system";
3859 			*pbMustBeFreed = 0;
3860 
3861 #			elif defined(__FreeBSD__)
3862 
3863 			{
3864 			struct timespec tp;
3865 
3866 			if((pRes = (uchar*) malloc(32)) == NULL) {
3867 				RET_OUT_OF_MEMORY;
3868 			}
3869 
3870 			if(clock_gettime(CLOCK_UPTIME, &tp) == -1) {
3871 				free(pRes);
3872 				*pPropLen = sizeof("**SYSCALL FAILED**") - 1;
3873 				return(UCHAR_CONSTANT("**SYSCALL FAILED**"));
3874 			}
3875 
3876 			*pbMustBeFreed = 1;
3877 
3878 			snprintf((char*) pRes, 32, "%ld", tp.tv_sec);
3879 			}
3880 
3881 #			else
3882 
3883 			{
3884 			struct sysinfo s_info;
3885 
3886 			if((pRes = (uchar*) malloc(32)) == NULL) {
3887 				RET_OUT_OF_MEMORY;
3888 			}
3889 
3890 			if(sysinfo(&s_info) < 0) {
3891 				free(pRes);
3892 				*pPropLen = sizeof("**SYSCALL FAILED**") - 1;
3893 				return(UCHAR_CONSTANT("**SYSCALL FAILED**"));
3894 			}
3895 
3896 			*pbMustBeFreed = 1;
3897 
3898 			snprintf((char*) pRes, 32, "%ld", s_info.uptime);
3899 			}
3900 #			endif
3901 		break;
3902 		default:
3903 			/* there is no point in continuing, we may even otherwise render the
3904 			 * error message unreadable. rgerhards, 2007-07-10
3905 			 */
3906 			dbgprintf("invalid property id: '%d'\n", pProp->id);
3907 			*pbMustBeFreed = 0;
3908 			*pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1;
3909 			return UCHAR_CONSTANT("**INVALID PROPERTY NAME**");
3910 	}
3911 
3912 	/* If we did not receive a template pointer, we are already done... */
3913 	if(pTpe == NULL || !pTpe->bComplexProcessing) {
3914 		*pPropLen = (bufLen == -1) ? (int) ustrlen(pRes) : bufLen;
3915 		return pRes;
3916 	}
3917 
3918 	/* Now check if we need to make "temporary" transformations (these
3919 	 * are transformations that do not go back into the message -
3920 	 * memory must be allocated for them!).
3921 	 */
3922 
3923 	/* substring extraction */
3924 	/* first we check if we need to extract by field number
3925 	 * rgerhards, 2005-12-22
3926 	 */
3927 	if(pTpe->data.field.has_fields == 1) {
3928 		size_t iCurrFld;
3929 		uchar *pFld;
3930 		uchar *pFldEnd;
3931 		/* first, skip to the field in question. The field separator
3932 		 * is always one character and is stored in the template entry.
3933 		 */
3934 		iCurrFld = 1;
3935 		pFld = pRes;
3936 		while(*pFld && iCurrFld < pTpe->data.field.iFieldNr) {
3937 			/* skip fields until the requested field or end of string is found */
3938 			while(*pFld && (uchar) *pFld != pTpe->data.field.field_delim)
3939 				++pFld; /* skip to field terminator */
3940 			if(*pFld == pTpe->data.field.field_delim) {
3941 				++pFld; /* eat it */
3942 #ifdef STRICT_GPLV3
3943 				if (pTpe->data.field.field_expand != 0) {
3944 					while (*pFld == pTpe->data.field.field_delim) {
3945 						++pFld;
3946 					}
3947 				}
3948 #endif
3949 				++iCurrFld;
3950 			}
3951 		}
3952 		dbgprintf("field requested %d, field found %d\n", pTpe->data.field.iFieldNr, (int) iCurrFld);
3953 
3954 		if(iCurrFld == pTpe->data.field.iFieldNr) {
3955 			/* field found, now extract it */
3956 			/* first of all, we need to find the end */
3957 			pFldEnd = pFld;
3958 			while(*pFldEnd && *pFldEnd != pTpe->data.field.field_delim)
3959 				++pFldEnd;
3960 			--pFldEnd; /* we are already at the delimiter - so we need to
3961 			            * step back a little not to copy it as part of the field. */
3962 			/* we got our end pointer, now do the copy */
3963 			/* TODO: code copied from below, this is a candidate for a separate function */
3964 			iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */
3965 			pBufStart = pBuf = malloc(iLen + 1);
3966 			if(pBuf == NULL) {
3967 				if(*pbMustBeFreed == 1)
3968 					free(pRes);
3969 				RET_OUT_OF_MEMORY;
3970 			}
3971 			/* now copy */
3972 			memcpy(pBuf, pFld, iLen);
3973 			bufLen = iLen;
3974 			pBuf[iLen] = '\0'; /* terminate it */
3975 			if(*pbMustBeFreed == 1)
3976 				free(pRes);
3977 			pRes = pBufStart;
3978 			*pbMustBeFreed = 1;
3979 		} else {
3980 			/* field not found, return error */
3981 			if(*pbMustBeFreed == 1)
3982 				free(pRes);
3983 			*pbMustBeFreed = 0;
3984 			*pPropLen = sizeof("**FIELD NOT FOUND**") - 1;
3985 			return UCHAR_CONSTANT("**FIELD NOT FOUND**");
3986 		}
3987 #ifdef FEATURE_REGEXP
3988 	} else {
3989 		/* Check for regular expressions */
3990 		if (pTpe->data.field.has_regex != 0) {
3991 			if (pTpe->data.field.has_regex == 2) {
3992 				/* Could not compile regex before! */
3993 				if (*pbMustBeFreed == 1) {
3994 					free(pRes);
3995 					*pbMustBeFreed = 0;
3996 				}
3997 				*pPropLen = sizeof("**NO MATCH** **BAD REGULAR EXPRESSION**") - 1;
3998 				return UCHAR_CONSTANT("**NO MATCH** **BAD REGULAR EXPRESSION**");
3999 			}
4000 
4001 			dbgprintf("string to match for regex is: %s\n", pRes);
4002 
4003 			if(objUse(regexp, LM_REGEXP_FILENAME) == RS_RET_OK) {
4004 				short iTry = 0;
4005 				uchar bFound = 0;
4006 				iOffs = 0;
4007 				/* first see if we find a match, iterating through the series of
4008 				 * potential matches over the string.
4009 				 */
4010 				while(!bFound) {
4011 					int iREstat;
4012 					iREstat = regexp.regexec(&pTpe->data.field.re, (char*)(pRes + iOffs),
4013 								nmatch, pmatch, 0);
4014 					dbgprintf("regexec return is %d\n", iREstat);
4015 					if(iREstat == 0) {
4016 						if(pmatch[0].rm_so == -1) {
4017 							dbgprintf("oops ... start offset of successful "
4018 								"regexec is -1\n");
4019 							break;
4020 						}
4021 						if(iTry == pTpe->data.field.iMatchToUse) {
4022 							bFound = 1;
4023 						} else {
4024 							dbgprintf("regex found at offset %d, new offset %d, "
4025 								"tries %d\n", iOffs,
4026 								(int) (iOffs + pmatch[0].rm_eo), iTry);
4027 							iOffs += pmatch[0].rm_eo;
4028 							++iTry;
4029 						}
4030 					} else {
4031 						break;
4032 					}
4033 				}
4034 				dbgprintf("regex: end search, found %d\n", bFound);
4035 				if(!bFound) {
4036 					/* we got no match! */
4037 					if(pTpe->data.field.nomatchAction != TPL_REGEX_NOMATCH_USE_WHOLE_FIELD) {
4038 						if (*pbMustBeFreed == 1) {
4039 							free(pRes);
4040 							*pbMustBeFreed = 0;
4041 						}
4042 						if(pTpe->data.field.nomatchAction == TPL_REGEX_NOMATCH_USE_DFLTSTR) {
4043 							bufLen = sizeof("**NO MATCH**") - 1;
4044 							pRes = UCHAR_CONSTANT("**NO MATCH**");
4045 						} else if(pTpe->data.field.nomatchAction ==
4046 						TPL_REGEX_NOMATCH_USE_ZERO) {
4047 							bufLen = 1;
4048 							pRes = UCHAR_CONSTANT("0");
4049 						} else {
4050 							bufLen = 0;
4051 							pRes = UCHAR_CONSTANT("");
4052 						}
4053 					}
4054 				} else {
4055 					/* Match- but did it match the one we wanted? */
4056 					/* we got no match! */
4057 					if(pmatch[pTpe->data.field.iSubMatchToUse].rm_so == -1) {
4058 						if(pTpe->data.field.nomatchAction !=
4059 						TPL_REGEX_NOMATCH_USE_WHOLE_FIELD) {
4060 							if (*pbMustBeFreed == 1) {
4061 								free(pRes);
4062 								*pbMustBeFreed = 0;
4063 							}
4064 							if(pTpe->data.field.nomatchAction ==
4065 							TPL_REGEX_NOMATCH_USE_DFLTSTR) {
4066 								bufLen = sizeof("**NO MATCH**") - 1;
4067 								pRes = UCHAR_CONSTANT("**NO MATCH**");
4068 							} else if(pTpe->data.field.nomatchAction ==
4069 								TPL_REGEX_NOMATCH_USE_ZERO) {
4070 								bufLen = 1;
4071 								pRes = UCHAR_CONSTANT("0");
4072 							} else {
4073 								bufLen = 0;
4074 								pRes = UCHAR_CONSTANT("");
4075 							}
4076 						}
4077 					}
4078 					/* OK, we have a usable match - we now need to malloc pB */
4079 					int iLenBuf;
4080 					uchar *pB;
4081 
4082 					iLenBuf = pmatch[pTpe->data.field.iSubMatchToUse].rm_eo
4083 						  - pmatch[pTpe->data.field.iSubMatchToUse].rm_so;
4084 					pB = malloc(iLenBuf + 1);
4085 
4086 					if (pB == NULL) {
4087 						if (*pbMustBeFreed == 1)
4088 							free(pRes);
4089 						RET_OUT_OF_MEMORY;
4090 					}
4091 
4092 					/* Lets copy the matched substring to the buffer */
4093 					memcpy(pB, pRes + iOffs +  pmatch[pTpe->data.field.iSubMatchToUse].rm_so,
4094 						iLenBuf);
4095 					bufLen = iLenBuf;
4096 					pB[iLenBuf] = '\0';/* terminate string, did not happen before */
4097 
4098 					if (*pbMustBeFreed == 1)
4099 						free(pRes);
4100 					pRes = pB;
4101 					*pbMustBeFreed = 1;
4102 				}
4103 			} else {
4104 				/* we could not load regular expression support. This is quite unexpected at
4105 				 * this stage of processing (after all, the config parser found it), but so
4106 				 * it is. We return an error in that case. -- rgerhards, 2008-03-07
4107 				 */
4108 				dbgprintf("could not get regexp object pointer, so regexp can not be evaluated\n");
4109 				if (*pbMustBeFreed == 1) {
4110 					free(pRes);
4111 					*pbMustBeFreed = 0;
4112 				}
4113 				*pPropLen = sizeof("***REGEXP NOT AVAILABLE***") - 1;
4114 				return UCHAR_CONSTANT("***REGEXP NOT AVAILABLE***");
4115 			}
4116 		}
4117 #endif /* #ifdef FEATURE_REGEXP */
4118 	}
4119 
4120 	if(pTpe->data.field.iFromPos != 0 || pTpe->data.field.iToPos != 0) {
4121 		/* we need to obtain a private copy */
4122 		int iFrom, iTo;
4123 		uchar *pSb;
4124 		iFrom = pTpe->data.field.iFromPos;
4125 		iTo = pTpe->data.field.iToPos;
4126 		if(bufLen == -1)
4127 			bufLen = ustrlen(pRes);
4128 		if(pTpe->data.field.options.bFromPosEndRelative) {
4129 			iFrom = (bufLen < iFrom) ? 0 : bufLen - iFrom;
4130 			iTo = (bufLen < iTo)? 0 : bufLen - iTo;
4131 		} else {
4132 			/* need to zero-base to and from (they are 1-based!) */
4133 			if(iFrom > 0)
4134 				--iFrom;
4135 			if(iTo > 0)
4136 				--iTo;
4137 		}
4138 		if(iFrom >= bufLen) {
4139 			DBGPRINTF("msgGetProp: iFrom %d >= buflen %d, returning empty string\n",
4140 				iFrom, bufLen);
4141 			if(*pbMustBeFreed == 1)
4142 				free(pRes);
4143 			pRes = (uchar*) "";
4144 			*pbMustBeFreed = 0;
4145 			bufLen = 0;
4146 		} else if(iFrom == 0 && iTo >= bufLen && pTpe->data.field.options.bFixedWidth == 0) {
4147 			/* in this case, the requested string is a superset of what we already have,
4148 			 * so there is no need to do any processing. This is a frequent case for size-limited
4149 			 * fields like TAG in the default forwarding template (so it is a useful optimization
4150 			 * to check for this condition ;)). -- rgerhards, 2009-07-09
4151 			 */
4152 			; /*DO NOTHING*/
4153 		} else {
4154 			if(iTo >= bufLen)  /* iTo is very large, if no to-position is set in the template! */
4155 				if (pTpe->data.field.options.bFixedWidth == 0)
4156 					iTo = bufLen - 1;
4157 
4158 			iLen = iTo - iFrom + 1; /* the +1 is for an actual char, NOT \0! */
4159 			pBufStart = pBuf = malloc(iLen + 1);
4160 			if(pBuf == NULL) {
4161 				if(*pbMustBeFreed == 1)
4162 					free(pRes);
4163 				RET_OUT_OF_MEMORY;
4164 			}
4165 			pSb = pRes;
4166 			if(iFrom) {
4167 			/* skip to the start of the substring (can't do pointer arithmetic
4168 			 * because the whole string might be smaller!!)
4169 			 */
4170 				while(*pSb && iFrom) {
4171 					--iFrom;
4172 					++pSb;
4173 				}
4174 			}
4175 			/* OK, we are at the begin - now let's copy... */
4176 			bufLen = iLen;
4177 			while(iLen) {
4178 				if (*pSb) {
4179 					*pBuf++ = *pSb;
4180 					++pSb;
4181 				} else {
4182 					*pBuf++ = ' ';
4183 				}
4184 				--iLen;
4185 			}
4186 			*pBuf = '\0';
4187 			bufLen -= iLen; /* subtract remaining length if the string was smaller! */
4188 			if(*pbMustBeFreed == 1)
4189 				free(pRes);
4190 			pRes = pBufStart;
4191 			*pbMustBeFreed = 1;
4192 		}
4193 	}
4194 
4195 	/* now check if we need to do our "SP if first char is non-space" hack logic */
4196 	if(*pRes && pTpe->data.field.options.bSPIffNo1stSP) {
4197 		/* here, we always destruct the buffer and return a new one */
4198 		uchar cFirst = *pRes; /* save first char */
4199 		if(*pbMustBeFreed == 1)
4200 			free(pRes);
4201 		pRes = (cFirst == ' ') ? UCHAR_CONSTANT("") : UCHAR_CONSTANT(" ");
4202 		bufLen = (cFirst == ' ') ? 0 : 1;
4203 		*pbMustBeFreed = 0;
4204 	}
4205 
4206 	if(*pRes) {
4207 		/* case conversations (should go after substring, because so we are able to
4208 		 * work on the smallest possible buffer).
4209 		 */
4210 		if(pTpe->data.field.eCaseConv != tplCaseConvNo) {
4211 			/* we need to obtain a private copy */
4212 			if(bufLen == -1)
4213 				bufLen = ustrlen(pRes);
4214 			uchar *pBStart;
4215 			uchar *pB;
4216 			uchar *pSrc;
4217 			pBStart = pB = malloc(bufLen + 1);
4218 			if(pB == NULL) {
4219 				if(*pbMustBeFreed == 1)
4220 					free(pRes);
4221 				RET_OUT_OF_MEMORY;
4222 			}
4223 			pSrc = pRes;
4224 			while(*pSrc) {
4225 				*pB++ = (pTpe->data.field.eCaseConv == tplCaseConvUpper) ?
4226 					(uchar)toupper((int)*pSrc) : (uchar)tolower((int)*pSrc);
4227 				/* currently only these two exist */
4228 				++pSrc;
4229 			}
4230 			*pB = '\0';
4231 			if(*pbMustBeFreed == 1)
4232 				free(pRes);
4233 			pRes = pBStart;
4234 			*pbMustBeFreed = 1;
4235 		}
4236 
4237 		/* now do control character dropping/escaping/replacement
4238 		 * Only one of these can be used. If multiple options are given, the
4239 		 * result is random (though currently there obviously is an order of
4240 		 * preferrence, see code below. But this is NOT guaranteed.
4241 		 * RGerhards, 2006-11-17
4242 		 * We must copy the strings if we modify them, because they may either
4243 		 * point to static memory or may point into the message object, in which
4244 		 * case we would actually modify the original property (which of course
4245 		 * is wrong).
4246 		 * This was found and fixed by varmojefkoj on 2007-09-11
4247 		 */
4248 		if(pTpe->data.field.options.bDropCC) {
4249 			int iLenBuf = 0;
4250 			uchar *pSrc = pRes;
4251 			uchar *pDstStart;
4252 			uchar *pDst;
4253 			uchar bDropped = 0;
4254 
4255 			while(*pSrc) {
4256 				if(!iscntrl((int) *pSrc++))
4257 					iLenBuf++;
4258 				else
4259 					bDropped = 1;
4260 			}
4261 
4262 			if(bDropped) {
4263 				pDst = pDstStart = malloc(iLenBuf + 1);
4264 				if(pDst == NULL) {
4265 					if(*pbMustBeFreed == 1)
4266 						free(pRes);
4267 					RET_OUT_OF_MEMORY;
4268 				}
4269 				for(pSrc = pRes; *pSrc; pSrc++) {
4270 					if(!iscntrl((int) *pSrc))
4271 						*pDst++ = *pSrc;
4272 				}
4273 				*pDst = '\0';
4274 				if(*pbMustBeFreed == 1)
4275 					free(pRes);
4276 				pRes = pDstStart;
4277 				bufLen = iLenBuf;
4278 				*pbMustBeFreed = 1;
4279 			}
4280 		} else if(pTpe->data.field.options.bSpaceCC) {
4281 			uchar *pSrc;
4282 			uchar *pDstStart;
4283 			uchar *pDst;
4284 
4285 			if(*pbMustBeFreed == 1) {
4286 				/* in this case, we already work on dynamic
4287 				 * memory, so there is no need to copy it - we can
4288 				 * modify it in-place without any harm. This is a
4289 				 * performance optiomization.
4290 				 */
4291 				for(pDst = pRes; *pDst; pDst++) {
4292 					if(iscntrl((int) *pDst))
4293 						*pDst = ' ';
4294 				}
4295 			} else {
4296 				if(bufLen == -1)
4297 					bufLen = ustrlen(pRes);
4298 				pDst = pDstStart = malloc(bufLen + 1);
4299 				if(pDst == NULL) {
4300 					if(*pbMustBeFreed == 1)
4301 						free(pRes);
4302 					RET_OUT_OF_MEMORY;
4303 				}
4304 				for(pSrc = pRes; *pSrc; pSrc++) {
4305 					if(iscntrl((int) *pSrc))
4306 						*pDst++ = ' ';
4307 					else
4308 						*pDst++ = *pSrc;
4309 				}
4310 				*pDst = '\0';
4311 				pRes = pDstStart;
4312 				*pbMustBeFreed = 1;
4313 			}
4314 		} else if(pTpe->data.field.options.bEscapeCC) {
4315 			/* we must first count how many control charactes are
4316 			 * present, because we need this to compute the new string
4317 			 * buffer length. While doing so, we also compute the string
4318 			 * length.
4319 			 */
4320 			int iNumCC = 0;
4321 			int iLenBuf = 0;
4322 			uchar *pSrc;
4323 			uchar *pB;
4324 
4325 			for(pB = pRes ; *pB ; ++pB) {
4326 				++iLenBuf;
4327 				if(iscntrl((int) *pB))
4328 					++iNumCC;
4329 			}
4330 
4331 			if(iNumCC > 0) { /* if 0, there is nothing to escape, so we are done */
4332 				/* OK, let's do the escaping... */
4333 				uchar *pBStart;
4334 				uchar szCCEsc[8]; /* buffer for escape sequence */
4335 				int i;
4336 
4337 				iLenBuf += iNumCC * 4;
4338 				pBStart = pB = malloc(iLenBuf + 1);
4339 				if(pB == NULL) {
4340 					if(*pbMustBeFreed == 1)
4341 						free(pRes);
4342 					RET_OUT_OF_MEMORY;
4343 				}
4344 				for(pSrc = pRes; *pSrc; pSrc++) {
4345 					if(iscntrl((int) *pSrc)) {
4346 						snprintf((char*)szCCEsc, sizeof(szCCEsc), "#%3.3d", *pSrc);
4347 						for(i = 0 ; i < 4 ; ++i)
4348 							*pB++ = szCCEsc[i];
4349 					} else {
4350 						*pB++ = *pSrc;
4351 					}
4352 				}
4353 				*pB = '\0';
4354 				if(*pbMustBeFreed == 1)
4355 					free(pRes);
4356 				pRes = pBStart;
4357 				bufLen = -1;
4358 				*pbMustBeFreed = 1;
4359 			}
4360 		}
4361 	}
4362 
4363 	/* Take care of spurious characters to make the property safe
4364 	 * for a path definition
4365 	 */
4366 	if(pTpe->data.field.options.bSecPathDrop || pTpe->data.field.options.bSecPathReplace) {
4367 		if(pTpe->data.field.options.bSecPathDrop) {
4368 			int iLenBuf = 0;
4369 			uchar *pSrc = pRes;
4370 			uchar *pDstStart;
4371 			uchar *pDst;
4372 			uchar bDropped = 0;
4373 
4374 			while(*pSrc) {
4375 				if(*pSrc++ != '/')
4376 					iLenBuf++;
4377 				else
4378 					bDropped = 1;
4379 			}
4380 
4381 			if(bDropped) {
4382 				pDst = pDstStart = malloc(iLenBuf + 1);
4383 				if(pDst == NULL) {
4384 					if(*pbMustBeFreed == 1)
4385 						free(pRes);
4386 					RET_OUT_OF_MEMORY;
4387 				}
4388 				for(pSrc = pRes; *pSrc; pSrc++) {
4389 					if(*pSrc != '/')
4390 						*pDst++ = *pSrc;
4391 				}
4392 				*pDst = '\0';
4393 				if(*pbMustBeFreed == 1)
4394 					free(pRes);
4395 				pRes = pDstStart;
4396 				bufLen = -1; /* TODO: can we do better? */
4397 				*pbMustBeFreed = 1;
4398 			}
4399 		} else {
4400 			uchar *pSrc;
4401 			uchar *pDstStart;
4402 			uchar *pDst;
4403 
4404 			if(*pbMustBeFreed == 1) {
4405 				/* here, again, we can modify the string as we already obtained
4406 				 * a private buffer. As we do not change the size of that buffer,
4407 				 * in-place modification is possible. This is a performance
4408 				 * enhancement.
4409 				 */
4410 				for(pDst = pRes; *pDst; pDst++) {
4411 					if(*pDst == '/')
4412 						*pDst++ = '_';
4413 				}
4414 			} else {
4415 				if(bufLen == -1)
4416 					bufLen = ustrlen(pRes);
4417 				pDst = pDstStart = malloc(bufLen + 1);
4418 				if(pDst == NULL) {
4419 					if(*pbMustBeFreed == 1)
4420 						free(pRes);
4421 					RET_OUT_OF_MEMORY;
4422 				}
4423 				for(pSrc = pRes; *pSrc; pSrc++) {
4424 					if(*pSrc == '/')
4425 						*pDst++ = '_';
4426 					else
4427 						*pDst++ = *pSrc;
4428 				}
4429 				*pDst = '\0';
4430 				/* we must NOT check if it needs to be freed, because we have done
4431 				 * this in the if above. So if we come to hear, the pSrc string needs
4432 				 * not to be freed (and we do not need to care about it).
4433 				 */
4434 				pRes = pDstStart;
4435 				*pbMustBeFreed = 1;
4436 			}
4437 		}
4438 
4439 		/* check for "." and ".." (note the parenthesis in the if condition!) */
4440 		if(*pRes == '\0') {
4441 			if(*pbMustBeFreed == 1)
4442 				free(pRes);
4443 			pRes = UCHAR_CONSTANT("_");
4444 			bufLen = 1;
4445 			*pbMustBeFreed = 0;
4446 		} else if((*pRes == '.') && (*(pRes + 1) == '\0' || (*(pRes + 1) == '.' && *(pRes + 2) == '\0'))) {
4447 			uchar *pTmp = pRes;
4448 
4449 			if(*(pRes + 1) == '\0')
4450 				pRes = UCHAR_CONSTANT("_");
4451 			else
4452 				pRes = UCHAR_CONSTANT("_.");;
4453 			if(*pbMustBeFreed == 1)
4454 				free(pTmp);
4455 			*pbMustBeFreed = 0;
4456 		}
4457 	}
4458 
4459 	/* Now drop last LF if present (pls note that this must not be done
4460 	 * if bEscapeCC was set)!
4461 	 */
4462 	if(pTpe->data.field.options.bDropLastLF && !pTpe->data.field.options.bEscapeCC) {
4463 		int iLn;
4464 		uchar *pB;
4465 		if(bufLen == -1)
4466 			bufLen = ustrlen(pRes);
4467 		iLn = bufLen;
4468 		if(iLn > 0 && *(pRes + iLn - 1) == '\n') {
4469 			/* we have a LF! */
4470 			/* check if we need to obtain a private copy */
4471 			if(*pbMustBeFreed == 0) {
4472 				/* ok, original copy, need a private one */
4473 				pB = malloc(iLn + 1);
4474 				if(pB == NULL) {
4475 					RET_OUT_OF_MEMORY;
4476 				}
4477 				memcpy(pB, pRes, iLn - 1);
4478 				pRes = pB;
4479 				*pbMustBeFreed = 1;
4480 			}
4481 			*(pRes + iLn - 1) = '\0'; /* drop LF ;) */
4482 			--bufLen;
4483 		}
4484 	}
4485 
4486 	/* Now everything is squased as much as possible and more or less ready to
4487 	 * go. This is the perfect place to compress any remaining spaces, if so
4488 	 * instructed by the user/config.
4489 	 */
4490 	if(pTpe->data.field.options.bCompressSP) {
4491 		int needCompress = 0;
4492 		int hadSP = 0;
4493 		uchar *pB;
4494 		if(*pbMustBeFreed == 0) {
4495 			for(pB = pRes ; *pB && needCompress == 0 ; ++pB) {
4496 				if(*pB == ' ') {
4497 					if(hadSP) {
4498 						uchar *const tmp = ustrdup(pRes);
4499 						if(tmp == NULL)
4500 							/* better not compress than
4501 							 * loose message. */
4502 							break;
4503 						*pbMustBeFreed = 1;
4504 						pRes = tmp;
4505 						needCompress = 1;
4506 					} else {
4507 						hadSP = 1;
4508 					}
4509 				}
4510 			}
4511 		} else {
4512 			/* If we can modify the buffer in any case, we
4513 			 * do NOT check if we actually need to compress,
4514 			 * but "just do it" - that's the quickest way
4515 			 * to get it done.
4516 			 */
4517 			needCompress = 1;
4518 		}
4519 		if(needCompress) {
4520 			hadSP = 0;
4521 			uchar *pDst = pRes;
4522 			int needCopy = 0;
4523 			for(pB = pRes ; *pB ; ++pB) {
4524 				if(*pB == ' ') {
4525 					if(hadSP) {
4526 						needCopy = 1;
4527 					}  else {
4528 						hadSP = 1;
4529 						if(needCopy)
4530 							*pDst = *pB;
4531 						++pDst;
4532 					}
4533 				} else {
4534 					hadSP = 0;
4535 					if(needCopy)
4536 						*pDst = *pB;
4537 					++pDst;
4538 				}
4539 			}
4540 			*pDst = '\0';
4541 			bufLen = pDst - pRes;
4542 		}
4543 	}
4544 
4545 	/* finally, we need to check if the property should be formatted in CSV or JSON.
4546 	 * For CSV we use RFC 4180, and always use double quotes. As of this writing,
4547 	 * this should be the last action carried out on the property, but in the
4548 	 * future there may be reasons to change that. -- rgerhards, 2009-04-02
4549 	 */
4550 	if(pTpe->data.field.options.bCSV) {
4551 		/* we need to obtain a private copy, as we need to at least add the double quotes */
4552 		int iBufLen;
4553 		uchar *pBStart;
4554 		uchar *pDst;
4555 		uchar *pSrc;
4556 		if(bufLen == -1)
4557 			bufLen = ustrlen(pRes);
4558 		iBufLen = bufLen;
4559 		/* the malloc may be optimized, we currently use the worst case... */
4560 		pBStart = pDst = malloc(2 * iBufLen + 3);
4561 		if(pDst == NULL) {
4562 			if(*pbMustBeFreed == 1)
4563 				free(pRes);
4564 			RET_OUT_OF_MEMORY;
4565 		}
4566 		pSrc = pRes;
4567 		*pDst++ = '"'; /* starting quote */
4568 		while(*pSrc) {
4569 			if(*pSrc == '"')
4570 				*pDst++ = '"'; /* need to add double double quote (see RFC4180) */
4571 			*pDst++ = *pSrc++;
4572 		}
4573 		*pDst++ = '"';	/* ending quote */
4574 		*pDst = '\0';
4575 		if(*pbMustBeFreed == 1)
4576 			free(pRes);
4577 		pRes = pBStart;
4578 		bufLen = -1;
4579 		*pbMustBeFreed = 1;
4580 	} else if(pTpe->data.field.options.bJSON) {
4581 		jsonEncode(&pRes, pbMustBeFreed, &bufLen, RSTRUE);
4582 	} else if(pTpe->data.field.options.bJSONf) {
4583 		jsonField(pTpe, &pRes, pbMustBeFreed, &bufLen, RSTRUE);
4584 	} else if(pTpe->data.field.options.bJSONr) {
4585 		jsonEncode(&pRes, pbMustBeFreed, &bufLen, RSFALSE);
4586 	} else if(pTpe->data.field.options.bJSONfr) {
4587 		jsonField(pTpe, &pRes, pbMustBeFreed, &bufLen, RSFALSE);
4588 	}
4589 
4590 	*pPropLen = (bufLen == -1) ? (int) ustrlen(pRes) : bufLen;
4591 
4592 	return(pRes);
4593 }
4594 
4595 /* Set a single property based on the JSON object provided. The
4596  * property name is extracted from the JSON object.
4597  */
4598 static rsRetVal
4599 msgSetPropViaJSON(smsg_t *__restrict__ const pMsg, const char *name, struct json_object *json, int sharedReference)
4600 {
4601 	const char *psz;
4602 	int val;
4603 	prop_t *propFromHost = NULL;
4604 	prop_t *propRcvFromIP = NULL;
4605 	int bNeedFree = 1;
4606 	DEFiRet;
4607 
4608 	/* note: json_object_get_string() manages the memory of the returned
4609 	 *       string. So we MUST NOT free it!
4610 	 */
4611 	dbgprintf("DDDD: msgSetPropViaJSON key: '%s'\n", name);
4612 	if(!strcmp(name, "rawmsg")) {
4613 		psz = json_object_get_string(json);
4614 		MsgSetRawMsg(pMsg, psz, strlen(psz));
4615 	} else if(!strcmp(name, "msg")) {
4616 		psz = json_object_get_string(json);
4617 		MsgReplaceMSG(pMsg, (const uchar*)psz, strlen(psz));
4618 	} else if(!strcmp(name, "syslogtag")) {
4619 		psz = json_object_get_string(json);
4620 		MsgSetTAG(pMsg, (const uchar*)psz, strlen(psz));
4621 	} else if(!strcmp(name, "pri")) {
4622 		val = json_object_get_int(json);
4623 		msgSetPRI(pMsg, val);
4624 	} else if(!strcmp(name, "syslogfacility")) {
4625 		val = json_object_get_int(json);
4626 		if(val >= 0 && val <= 24)
4627 			pMsg->iFacility = val;
4628 		else
4629 			DBGPRINTF("mmexternal: invalid fac %d requested -- ignored\n", val);
4630 	} else if(!strcmp(name, "syslogseverity")) {
4631 		val = json_object_get_int(json);
4632 		if(val >= 0 && val <= 7)
4633 			pMsg->iSeverity = val;
4634 		else
4635 			DBGPRINTF("mmexternal: invalid fac %d requested -- ignored\n", val);
4636 	} else if(!strcmp(name, "procid")) {
4637 		psz = json_object_get_string(json);
4638 		MsgSetPROCID(pMsg, psz);
4639 	} else if(!strcmp(name, "msgid")) {
4640 		psz = json_object_get_string(json);
4641 		MsgSetMSGID(pMsg, psz);
4642 	} else if(!strcmp(name, "structured-data")) {
4643 		psz = json_object_get_string(json);
4644 		MsgSetStructuredData(pMsg, psz);
4645 	} else if(!strcmp(name, "hostname") || !strcmp(name, "source")) {
4646 		psz = json_object_get_string(json);
4647 		MsgSetHOSTNAME(pMsg, (const uchar*)psz, strlen(psz));
4648 	} else if(!strcmp(name, "fromhost")) {
4649 		psz = json_object_get_string(json);
4650 		MsgSetRcvFromStr(pMsg, (const uchar*) psz, strlen(psz), &propFromHost);
4651 		prop.Destruct(&propFromHost);
4652 	} else if(!strcmp(name, "fromhost-ip")) {
4653 		psz = json_object_get_string(json);
4654 		MsgSetRcvFromIPStr(pMsg, (const uchar*)psz, strlen(psz), &propRcvFromIP);
4655 		prop.Destruct(&propRcvFromIP);
4656 	} else if(!strcmp(name, "$!")) {
4657 		/* msgAddJSON expects that it can keep the object without incremeting
4658 		 * the json reference count. So we MUST NOT free (_put) the object in
4659 		 * this case. -- rgerhards, 2018-09-14
4660 		 */
4661 		bNeedFree = 0;
4662 		msgAddJSON(pMsg, (uchar*)"!", json, 0, sharedReference);
4663 	} else {
4664 		/* we ignore unknown properties */
4665 		DBGPRINTF("msgSetPropViaJSON: unkonwn property ignored: %s\n",
4666 			  name);
4667 	}
4668 
4669 	if(bNeedFree) {
4670 		json_object_put(json);
4671 	}
4672 
4673 	RETiRet;
4674 }
4675 
4676 
4677 /* set message properties based on JSON string. This function does it all,
4678  * including parsing the JSON string. If an error is detected, the operation
4679  * is aborted at the time of error. Any modifications made before the
4680  * error ocurs are still PERSISTED.
4681  * This function is meant to support the external message modifiction module
4682  * interface. As such, replacing properties is expressively permited. Note that
4683  * properties which were derived from the message during parsing are NOT
4684  * updated if the underlying (raw)msg property is changed.
4685  */
4686 rsRetVal
4687 MsgSetPropsViaJSON(smsg_t *__restrict__ const pMsg, const uchar *__restrict__ const jsonstr)
4688 {
4689 	struct json_tokener *tokener = NULL;
4690 	struct json_object *json;
4691 	const char *errMsg;
4692 	DEFiRet;
4693 
4694 	DBGPRINTF("DDDDDD: JSON string for message mod: '%s'\n", jsonstr);
4695 	if(!strcmp((char*)jsonstr, "{}")) /* shortcut for a common case */
4696 		FINALIZE;
4697 
4698 	tokener = json_tokener_new();
4699 
4700 	json = json_tokener_parse_ex(tokener, (char*)jsonstr, ustrlen(jsonstr));
4701 	if(Debug) {
4702 		errMsg = NULL;
4703 		if(json == NULL) {
4704 			enum json_tokener_error err;
4705 
4706 			err = tokener->err;
4707 			if(err != json_tokener_continue)
4708 				errMsg = json_tokener_error_desc(err);
4709 			else
4710 				errMsg = "Unterminated input";
4711 		} else if(!json_object_is_type(json, json_type_object))
4712 			errMsg = "JSON value is not an object";
4713 		if(errMsg != NULL) {
4714 			DBGPRINTF("MsgSetPropsViaJSON: Error parsing JSON '%s': %s\n",
4715 					jsonstr, errMsg);
4716 		}
4717 	}
4718 	if(json == NULL || !json_object_is_type(json, json_type_object)) {
4719 		ABORT_FINALIZE(RS_RET_JSON_UNUSABLE);
4720 	}
4721 	MsgSetPropsViaJSON_Object(pMsg, json);
4722 
4723 finalize_it:
4724 	if(tokener != NULL)
4725 		json_tokener_free(tokener);
4726 	RETiRet;
4727 }
4728 
4729 
4730 /* Used by MsgSetPropsViaJSON to set properties.
4731  * The same as MsgSetPropsViaJSON only that a json object is given and not a string
4732  */
4733 rsRetVal
4734 MsgSetPropsViaJSON_Object(smsg_t *__restrict__ const pMsg, struct json_object *json)
4735 {
4736 	DEFiRet;
4737 	if(json == NULL || !json_object_is_type(json, json_type_object)) {
4738 		DBGPRINTF("MsgSetPropsViaJSON_Object: json NULL or not object type\n");
4739 		ABORT_FINALIZE(RS_RET_JSON_UNUSABLE);
4740 	}
4741 	struct json_object_iterator it = json_object_iter_begin(json);
4742 	struct json_object_iterator itEnd = json_object_iter_end(json);
4743 	while (!json_object_iter_equal(&it, &itEnd)) {
4744 		struct json_object *child = json_object_iter_peek_value(&it);
4745 		json_object_get(child);
4746 		msgSetPropViaJSON(pMsg, json_object_iter_peek_name(&it),
4747 			child, 0);
4748 		json_object_iter_next(&it);
4749 	}
4750 	json_object_put(json);
4751 
4752 finalize_it:
4753 	RETiRet;
4754 }
4755 
4756 
4757 /* get the severity - this is an entry point that
4758  * satisfies the base object class getSeverity semantics.
4759  * rgerhards, 2008-01-14
4760  */
4761 rsRetVal
4762 MsgGetSeverity(smsg_t * const pMsg, int *piSeverity)
4763 {
4764 	*piSeverity = pMsg->iSeverity;
4765 	return RS_RET_OK;
4766 }
4767 
4768 
4769 static uchar *
4770 jsonPathGetLeaf(uchar *name, int lenName)
4771 {
4772 	int i;
4773 	for(i = lenName ; i >= 0 ; --i)
4774 		if(i == 0) {
4775 			if(name[0] == '!'  || name[0] == '.' || name[0] == '/')
4776 				break;
4777 		} else {
4778 			if(name[i] == '!')
4779 				break;
4780 		}
4781 	if(name[i] == '!' || name[i] == '.' || name[i] == '/')
4782 		++i;
4783 	return name + i;
4784 }
4785 
4786 static json_bool jsonVarExtract(struct json_object* root, const char *key, struct json_object **value) {
4787 	char namebuf[MAX_VARIABLE_NAME_LEN];
4788 	int key_len = strlen(key);
4789 	char *array_idx_start = strstr(key, "[");
4790 	char *array_idx_end = NULL;
4791 	char *array_idx_num_end_discovered = NULL;
4792 	struct json_object *arr = NULL;
4793 	if (array_idx_start != NULL) {
4794 		array_idx_end = strstr(array_idx_start, "]");
4795 	}
4796 	if (array_idx_end != NULL && (array_idx_end - key + 1) == key_len) {
4797 		errno = 0;
4798 		int idx = (int) strtol(array_idx_start + 1, &array_idx_num_end_discovered, 10);
4799 		if (errno == 0 && array_idx_num_end_discovered == array_idx_end) {
4800 			memcpy(namebuf, key, array_idx_start - key);
4801 			namebuf[array_idx_start - key] = '\0';
4802 			json_bool found_obj = json_object_object_get_ex(root, namebuf, &arr);
4803 			if (found_obj && json_object_is_type(arr, json_type_array)) {
4804 				int len = json_object_array_length(arr);
4805 				if (len > idx) {
4806 					*value = json_object_array_get_idx(arr, idx);
4807 					if (*value != NULL) return TRUE;
4808 				}
4809 				return FALSE;
4810 			}
4811 		}
4812 	}
4813 	return json_object_object_get_ex(root, key, value);
4814 }
4815 
4816 
4817 static rsRetVal
4818 jsonPathFindNext(struct json_object *root, uchar *namestart, uchar **name, uchar *leaf,
4819 		 struct json_object **found, int bCreate)
4820 {
4821 	uchar namebuf[MAX_VARIABLE_NAME_LEN];
4822 	struct json_object *json;
4823 	size_t i;
4824 	uchar *p = *name;
4825 	DEFiRet;
4826 
4827 	if(*p == '!' || (*name == namestart && (*p == '.' || *p == '/')))
4828 		++p;
4829 	for(i = 0 ; *p && !(p == namestart && (*p == '.' || *p == '/')) && *p != '!'
4830 		&& p != leaf && i < sizeof(namebuf)-1 ; ++i, ++p)
4831 		namebuf[i] = *p;
4832 	if(i > 0) {
4833 		namebuf[i] = '\0';
4834 		if(jsonVarExtract(root, (char*)namebuf, &json) == FALSE) {
4835 			json = NULL;
4836 		}
4837 	} else
4838 		json = root;
4839 	if(json == NULL) {
4840 		if(!bCreate) {
4841 			ABORT_FINALIZE(RS_RET_JNAME_INVALID);
4842 		} else {
4843 			if (json_object_get_type(root) != json_type_object) {
4844 				DBGPRINTF("jsonPathFindNext with bCreate: not a container in json path, "
4845 					"name is '%s'\n", namestart);
4846 				ABORT_FINALIZE(RS_RET_INVLD_SETOP);
4847 			}
4848 			json = json_object_new_object();
4849 			json_object_object_add(root, (char*)namebuf, json);
4850 		}
4851 	}
4852 
4853 	*name = p;
4854 	*found = json;
4855 finalize_it:
4856 	RETiRet;
4857 }
4858 
4859 static rsRetVal
4860 jsonPathFindParent(struct json_object *jroot, uchar *name, uchar *leaf, struct json_object **parent,
4861 	const int bCreate)
4862 {
4863 	uchar *namestart;
4864 	DEFiRet;
4865 	namestart = name;
4866 	*parent = jroot;
4867 	while(name < leaf-1) {
4868 		CHKiRet(jsonPathFindNext(*parent, namestart, &name, leaf, parent, bCreate));
4869 	}
4870 	if(*parent == NULL)
4871 		ABORT_FINALIZE(RS_RET_NOT_FOUND);
4872 finalize_it:
4873 	RETiRet;
4874 }
4875 
4876 static rsRetVal
4877 jsonMerge(struct json_object *existing, struct json_object *json)
4878 {
4879 	/* TODO: check & handle duplicate names */
4880 	DEFiRet;
4881 
4882 	struct json_object_iterator it = json_object_iter_begin(json);
4883 	struct json_object_iterator itEnd = json_object_iter_end(json);
4884 	while (!json_object_iter_equal(&it, &itEnd)) {
4885 		json_object_object_add(existing, json_object_iter_peek_name(&it),
4886 			json_object_get(json_object_iter_peek_value(&it)));
4887 		json_object_iter_next(&it);
4888 	}
4889 	/* note: json-c does ref counting. We added all descandants refcounts
4890 	 * in the loop above. So when we now free(_put) the root object, only
4891 	 * root gets freed().
4892 	 */
4893 	json_object_put(json);
4894 	RETiRet;
4895 }
4896 
4897 /* find a JSON structure element (field or container doesn't matter).  */
4898 rsRetVal
4899 jsonFind(smsg_t *const pMsg, msgPropDescr_t *pProp, struct json_object **jsonres)
4900 {
4901 	uchar *leaf;
4902 	struct json_object *parent;
4903 	struct json_object *field;
4904 	struct json_object **jroot = NULL;
4905 	pthread_mutex_t *mut = NULL;
4906 	DEFiRet;
4907 
4908 	CHKiRet(getJSONRootAndMutex(pMsg, pProp->id, &jroot, &mut));
4909 	pthread_mutex_lock(mut);
4910 
4911 	if(*jroot == NULL) {
4912 		field = NULL;
4913 		goto finalize_it;
4914 	}
4915 
4916 	if(!strcmp((char*)pProp->name, "!")) {
4917 		field = *jroot;
4918 	} else if(!strcmp((char*)pProp->name, ".")) {
4919 		field = *jroot;
4920 	} else {
4921 		leaf = jsonPathGetLeaf(pProp->name, pProp->nameLen);
4922 		CHKiRet(jsonPathFindParent(*jroot, pProp->name, leaf, &parent, 0));
4923 		if(jsonVarExtract(parent, (char*)leaf, &field) == FALSE)
4924 			field = NULL;
4925 	}
4926 	*jsonres = field;
4927 
4928 finalize_it:
4929 	if(mut != NULL)
4930 		pthread_mutex_unlock(mut);
4931 	RETiRet;
4932 }
4933 
4934 /* check if JSON variable exists (works on terminal var and container) */
4935 rsRetVal ATTR_NONNULL()
4936 msgCheckVarExists(smsg_t *const pMsg, msgPropDescr_t *pProp)
4937 {
4938 	struct json_object *jsonres = NULL;
4939 	DEFiRet;
4940 
4941 	CHKiRet(jsonFind(pMsg, pProp, &jsonres));
4942 	if(jsonres == NULL) {
4943 		iRet = RS_RET_NOT_FOUND;
4944 	}
4945 
4946 finalize_it:
4947 	RETiRet;
4948 }
4949 
4950 rsRetVal
4951 msgAddJSON(smsg_t * const pM, uchar *name, struct json_object *json, int force_reset, int sharedReference)
4952 {
4953 	/* TODO: error checks! This is a quick&dirty PoC! */
4954 	struct json_object **jroot;
4955 	struct json_object *parent, *leafnode;
4956 	struct json_object *given = NULL;
4957 	uchar *leaf;
4958 	pthread_mutex_t *mut = NULL;
4959 	DEFiRet;
4960 
4961 	CHKiRet(getJSONRootAndMutexByVarChar(pM, name[0], &jroot, &mut));
4962 	pthread_mutex_lock(mut);
4963 
4964 	if(name[0] == '/') { /* globl var special handling */
4965 		if (sharedReference) {
4966 			given = json;
4967 			json = jsonDeepCopy(json);
4968 			json_object_put(given);
4969 		}
4970 	}
4971 
4972 	if(name[1] == '\0') { /* full tree? */
4973 		if(*jroot == NULL)
4974 			*jroot = json;
4975 		else
4976 			CHKiRet(jsonMerge(*jroot, json));
4977 	} else {
4978 		if(*jroot == NULL) {
4979 			/* now we need a root obj */
4980 			*jroot = json_object_new_object();
4981 		}
4982 		leaf = jsonPathGetLeaf(name, ustrlen(name));
4983 		iRet = jsonPathFindParent(*jroot, name, leaf, &parent, 1);
4984 		if (unlikely(iRet != RS_RET_OK)) {
4985 			json_object_put(json);
4986 			FINALIZE;
4987 		}
4988 		if (json_object_get_type(parent) != json_type_object) {
4989 			DBGPRINTF("msgAddJSON: not a container in json path,"
4990 				"name is '%s'\n", name);
4991 			json_object_put(json);
4992 			ABORT_FINALIZE(RS_RET_INVLD_SETOP);
4993 		}
4994 		if(jsonVarExtract(parent, (char*)leaf, &leafnode) == FALSE)
4995 			leafnode = NULL;
4996 		/* json-c code indicates we can simply replace a
4997 		 * json type. Unfortunaltely, this is not documented
4998 		 * as part of the interface spec. We still use it,
4999 		 * because it speeds up processing. If it does not work
5000 		 * at some point, use
5001 		 * json_object_object_del(parent, (char*)leaf);
5002 		 * before adding. rgerhards, 2012-09-17
5003 		 */
5004 		if (force_reset || (leafnode == NULL)) {
5005 			json_object_object_add(parent, (char*)leaf, json);
5006 		} else {
5007 			if(json_object_get_type(json) == json_type_object) {
5008 				CHKiRet(jsonMerge(*jroot, json));
5009 			} else {
5010 				/* TODO: improve the code below, however, the current
5011 				 *       state is not really bad */
5012 				if(json_object_get_type(leafnode) == json_type_object) {
5013 					DBGPRINTF("msgAddJSON: trying to update a container "
5014 							  "node with a leaf, name is %s - "
5015 							  "forbidden", name);
5016 					json_object_put(json);
5017 					ABORT_FINALIZE(RS_RET_INVLD_SETOP);
5018 				}
5019 				json_object_object_add(parent, (char*)leaf, json);
5020 			}
5021 		}
5022 	}
5023 
5024 finalize_it:
5025 	if(mut != NULL)
5026 		pthread_mutex_unlock(mut);
5027 	RETiRet;
5028 }
5029 
5030 
5031 rsRetVal
5032 msgDelJSON(smsg_t * const pM, uchar *name)
5033 {
5034 	struct json_object **jroot;
5035 	struct json_object *parent, *leafnode;
5036 	uchar *leaf;
5037 	pthread_mutex_t *mut = NULL;
5038 	DEFiRet;
5039 
5040 	CHKiRet(getJSONRootAndMutexByVarChar(pM, name[0], &jroot, &mut));
5041 	pthread_mutex_lock(mut);
5042 
5043 	if(*jroot == NULL) {
5044 		DBGPRINTF("msgDelJSONVar; jroot empty in unset for property %s\n",
5045 			  name);
5046 		FINALIZE;
5047 	}
5048 
5049 	if(name[1] == '\0') {
5050 		/* full tree! Strange, but I think we should permit this. After all,
5051 		 * we trust rsyslog.conf to be written by the admin.
5052 		 */
5053 		DBGPRINTF("unsetting JSON root object\n");
5054 		json_object_put(*jroot);
5055 		*jroot = NULL;
5056 	} else {
5057 		leaf = jsonPathGetLeaf(name, ustrlen(name));
5058 		CHKiRet(jsonPathFindParent(*jroot, name, leaf, &parent, 0));
5059 		if(jsonVarExtract(parent, (char*)leaf, &leafnode) == FALSE)
5060 			leafnode = NULL;
5061 		if(leafnode == NULL) {
5062 			DBGPRINTF("unset JSON: could not find '%s'\n", name);
5063 			ABORT_FINALIZE(RS_RET_JNAME_NOTFOUND);
5064 		} else {
5065 			DBGPRINTF("deleting JSON value path '%s', "
5066 				  "leaf '%s', type %d\n",
5067 				  name, leaf, json_object_get_type(leafnode));
5068 			json_object_object_del(parent, (char*)leaf);
5069 		}
5070 	}
5071 
5072 finalize_it:
5073 	if(mut != NULL)
5074 		pthread_mutex_unlock(mut);
5075 	RETiRet;
5076 }
5077 
5078 /* add Metadata to the message. This is stored in a special JSON
5079  * container. Note that only string types are currently supported,
5080  * what should pose absolutely no problem with the string-ish nature
5081  * of rsyslog metadata.
5082  * added 2015-01-09 rgerhards
5083  */
5084 rsRetVal
5085 msgAddMetadata(smsg_t *const __restrict__ pMsg,
5086 	       uchar *const __restrict__ metaname,
5087 	       uchar *const __restrict__ metaval)
5088 {
5089 	DEFiRet;
5090 	struct json_object *const json = json_object_new_object();
5091 	CHKmalloc(json);
5092 	struct json_object *const jval = json_object_new_string((char*)metaval);
5093 	if(jval == NULL) {
5094 		json_object_put(json);
5095 		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
5096 	}
5097 	json_object_object_add(json, (const char *const)metaname, jval);
5098 	iRet = msgAddJSON(pMsg, (uchar*)"!metadata", json, 0, 0);
5099 finalize_it:
5100 	RETiRet;
5101 }
5102 
5103 rsRetVal
5104 msgAddMultiMetadata(smsg_t *const __restrict__ pMsg,
5105 	       const uchar ** __restrict__ metaname,
5106 	       const uchar ** __restrict__ metaval,
5107 	       const int count)
5108 {
5109 	DEFiRet;
5110 	int i = 0 ;
5111 	struct json_object *const json = json_object_new_object();
5112 	CHKmalloc(json);
5113 	for ( i = 0 ; i < count ; i++ ) {
5114 		struct json_object *const jval = json_object_new_string((char*)metaval[i]);
5115 		if(jval == NULL) {
5116 			json_object_put(json);
5117 			ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
5118 		}
5119 		json_object_object_add(json, (const char *const)metaname[i], jval);
5120 	}
5121 	iRet = msgAddJSON(pMsg, (uchar*)"!metadata", json, 0, 0);
5122 finalize_it:
5123 	RETiRet;
5124 }
5125 
5126 struct json_object *
5127 jsonDeepCopy(struct json_object *src)
5128 {
5129 	struct json_object *dst = NULL, *json;
5130 	int arrayLen, i;
5131 
5132 	if(src == NULL) goto done;
5133 
5134 	switch(json_object_get_type(src)) {
5135 	case json_type_boolean:
5136 		dst = json_object_new_boolean(json_object_get_boolean(src));
5137 		break;
5138 	case json_type_double:
5139 		dst = json_object_new_double(json_object_get_double(src));
5140 		break;
5141 	case json_type_int:
5142 		dst = json_object_new_int64(json_object_get_int64(src));
5143 		break;
5144 	case json_type_string:
5145 		dst = json_object_new_string(json_object_get_string(src));
5146 		break;
5147 	case json_type_object:
5148 		dst = json_object_new_object();
5149 		struct json_object_iterator it = json_object_iter_begin(src);
5150 		struct json_object_iterator itEnd = json_object_iter_end(src);
5151 		while (!json_object_iter_equal(&it, &itEnd)) {
5152 			json = jsonDeepCopy(json_object_iter_peek_value(&it));
5153 			json_object_object_add(dst, json_object_iter_peek_name(&it), json);
5154 			json_object_iter_next(&it);
5155 		}
5156 		break;
5157 	case json_type_array:
5158 		arrayLen = json_object_array_length(src);
5159 		dst = json_object_new_array();
5160 		for(i = 0 ; i < arrayLen ; ++i) {
5161 			json = json_object_array_get_idx(src, i);
5162 			json = jsonDeepCopy(json);
5163 			json_object_array_add(dst, json);
5164 		}
5165 		break;
5166 	case json_type_null:
5167 	default:DBGPRINTF("jsonDeepCopy(): error unknown type %d\n",
5168 			 json_object_get_type(src));
5169 		dst = NULL;
5170 		break;
5171 	}
5172 done:	return dst;
5173 }
5174 
5175 
5176 rsRetVal
5177 msgSetJSONFromVar(smsg_t * const pMsg, uchar *varname, struct svar *v, int force_reset)
5178 {
5179 	struct json_object *json = NULL;
5180 	char *cstr;
5181 	DEFiRet;
5182 	switch(v->datatype) {
5183 	case 'S':/* string */
5184 		cstr = es_str2cstr(v->d.estr, NULL);
5185 		json = json_object_new_string(cstr);
5186 		free(cstr);
5187 		break;
5188 	case 'N':/* number (integer) */
5189 		json = json_object_new_int64(v->d.n);
5190 		break;
5191 	case 'J':/* native JSON */
5192 		json = jsonDeepCopy(v->d.json);
5193 		break;
5194 	default:DBGPRINTF("msgSetJSONFromVar: unsupported datatype %c\n",
5195 		v->datatype);
5196 		ABORT_FINALIZE(RS_RET_ERR);
5197 	}
5198 
5199 	msgAddJSON(pMsg, varname, json, force_reset, 0);
5200 finalize_it:
5201 	RETiRet;
5202 }
5203 
5204 rsRetVal
5205 MsgAddToStructuredData(smsg_t * const pMsg, uchar *toadd, rs_size_t len)
5206 {
5207 	uchar *newptr;
5208 	rs_size_t newlen;
5209 	int empty;
5210 	DEFiRet;
5211 	empty = pMsg->pszStrucData == NULL || pMsg->pszStrucData[0] == '-';
5212 	newlen = (empty) ? len : pMsg->lenStrucData + len;
5213 	CHKmalloc(newptr = (uchar*) realloc(pMsg->pszStrucData, newlen+1));
5214 	if(empty) {
5215 		memcpy(newptr, toadd, len);
5216 	} else {
5217 		memcpy(newptr+pMsg->lenStrucData, toadd, len);
5218 	}
5219 	pMsg->pszStrucData = newptr;
5220 	pMsg->pszStrucData[newlen] = '\0';
5221 	pMsg->lenStrucData = newlen;
5222 finalize_it:
5223 	RETiRet;
5224 }
5225 
5226 
5227 /* Fill a message propert description. Space must already be alloced
5228  * by the caller. This is for efficiency, as we expect this to happen
5229  * as part of a larger structure alloc.
5230  * Note that CEE/LOCAL_VAR properties can come in either as
5231  * "$!xx"/"$.xx" or "!xx"/".xx" - we will unify them here.
5232  */
5233 rsRetVal
5234 msgPropDescrFill(msgPropDescr_t *pProp, uchar *name, int nameLen)
5235 {
5236 	propid_t id;
5237 	int offs;
5238 	DEFiRet;
5239 	if(propNameToID(name, &id) != RS_RET_OK) {
5240 		parser_errmsg("invalid property '%s'", name);
5241 		/* now try to find some common error causes */
5242 		if(!strcasecmp((char*)name, "myhostname"))
5243 			parser_errmsg("did you mean '$myhostname' instead of '%s'? "
5244 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5245 		else if(!strcasecmp((char*)name, "bom"))
5246 			parser_errmsg("did you mean '$bom' instead of '%s'?"
5247 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5248 		else if(!strcasecmp((char*)name, "now"))
5249 			parser_errmsg("did you mean '$now' instead of '%s'?"
5250 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5251 		else if(!strcasecmp((char*)name, "year"))
5252 			parser_errmsg("did you mean '$year' instead of '%s'?"
5253 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5254 		else if(!strcasecmp((char*)name, "month"))
5255 			parser_errmsg("did you mean '$month' instead of '%s'?"
5256 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5257 		else if(!strcasecmp((char*)name, "day"))
5258 			parser_errmsg("did you mean '$day' instead of '%s'?"
5259 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5260 		else if(!strcasecmp((char*)name, "hour"))
5261 			parser_errmsg("did you mean '$hour' instead of '%s'?"
5262 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5263 		else if(!strcasecmp((char*)name, "hhour"))
5264 			parser_errmsg("did you mean '$hhour' instead of '%s'?"
5265 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5266 		else if(!strcasecmp((char*)name, "qhour"))
5267 			parser_errmsg("did you mean '$qhour' instead of '%s'?"
5268 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5269 		else if(!strcasecmp((char*)name, "minute"))
5270 			parser_errmsg("did you mean '$minute' instead of '%s'?"
5271 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5272 		else if(!strcasecmp((char*)name, "now-utc"))
5273 			parser_errmsg("did you mean '$now-utc' instead of '%s'?"
5274 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5275 		else if(!strcasecmp((char*)name, "year-utc"))
5276 			parser_errmsg("did you mean '$year-utc' instead of '%s'?"
5277 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5278 		else if(!strcasecmp((char*)name, "month-utc"))
5279 			parser_errmsg("did you mean '$month-utc' instead of '%s'?"
5280 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5281 		else if(!strcasecmp((char*)name, "day-utc"))
5282 			parser_errmsg("did you mean '$day-utc' instead of '%s'?"
5283 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5284 		else if(!strcasecmp((char*)name, "hour-utc"))
5285 			parser_errmsg("did you mean '$hour-utc' instead of '%s'?"
5286 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5287 		else if(!strcasecmp((char*)name, "hhour-utc"))
5288 			parser_errmsg("did you mean '$hhour-utc' instead of '%s'?"
5289 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5290 		else if(!strcasecmp((char*)name, "qhour-utc"))
5291 			parser_errmsg("did you mean '$qhour-utc' instead of '%s'?"
5292 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5293 		else if(!strcasecmp((char*)name, "minute-utc"))
5294 			parser_errmsg("did you mean '$minute-utc' instead of '%s'?"
5295 				"See also: https://www.rsyslog.com/rsyslog-info-1/", name);
5296 		ABORT_FINALIZE(RS_RET_INVLD_PROP);
5297 	}
5298 	if(id == PROP_CEE || id == PROP_LOCAL_VAR || id == PROP_GLOBAL_VAR) {
5299 	  	/* in these cases, we need the field name for later processing */
5300 		/* normalize name: remove $ if present */
5301 		offs = (name[0] == '$') ? 1 : 0;
5302 		pProp->name = ustrdup(name + offs);
5303 		pProp->nameLen = nameLen - offs;
5304 		/* we patch the root name, so that support functions do not need to
5305 		 * check for different root chars. */
5306 		pProp->name[0] = '!';
5307 	}
5308 	pProp->id = id;
5309 finalize_it:
5310 	RETiRet;
5311 }
5312 
5313 void
5314 msgPropDescrDestruct(msgPropDescr_t *pProp)
5315 {
5316 	if(pProp != NULL) {
5317 		if(pProp->id == PROP_CEE ||
5318 		   pProp->id == PROP_LOCAL_VAR ||
5319 		   pProp->id == PROP_GLOBAL_VAR)
5320 			free(pProp->name);
5321 	}
5322 }
5323 
5324 
5325 /* dummy */
5326 static rsRetVal msgQueryInterface(interface_t __attribute__((unused)) *i) { return RS_RET_NOT_IMPLEMENTED; }
5327 
5328 /* Initialize the message class. Must be called as the very first method
5329  * before anything else is called inside this class.
5330  * rgerhards, 2008-01-04
5331  */
5332 BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE)
5333 	pthread_mutex_init(&glblVars_lock, NULL);
5334 
5335 	/* request objects we use */
5336 	CHKiRet(objUse(datetime, CORE_COMPONENT));
5337 	CHKiRet(objUse(glbl, CORE_COMPONENT));
5338 	CHKiRet(objUse(prop, CORE_COMPONENT));
5339 	CHKiRet(objUse(var, CORE_COMPONENT));
5340 
5341 	/* set our own handlers */
5342 	OBJSetMethodHandler(objMethod_SERIALIZE, MsgSerialize);
5343 	/* some more inits */
5344 #	ifdef HAVE_MALLOC_TRIM
5345 	INIT_ATOMIC_HELPER_MUT(mutTrimCtr);
5346 #	endif
5347 ENDObjClassInit(msg)
5348 /* vim:set ai:
5349  */
5350