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