1 /*! \file syslogmessage.c
2  *  \brief Implementation of the syslog message object.
3  *
4  * \author  Rainer Gerhards <rgerhards@adiscon.com>
5  * \date    2003-09-01
6  *          coding begun.
7  *
8  * Copyright 2002-2014
9  *     Rainer Gerhards and Adiscon GmbH. All Rights Reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are
13  * met:
14  *
15  *     * Redistributions of source code must retain the above copyright
16  *       notice, this list of conditions and the following disclaimer.
17  *
18  *     * Redistributions in binary form must reproduce the above copyright
19  *       notice, this list of conditions and the following disclaimer in
20  *       the documentation and/or other materials provided with the
21  *       distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
27  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <ctype.h>
37 #include <assert.h>
38 #include "settings.h"
39 #include "liblogging.h"
40 #include "srAPI.h"
41 #include "syslogmessage.h"
42 #include "namevaluetree.h"
43 #include "stringbuf.h"
44 #include "oscalls.h"
45 
46 /* ################################################################# *
47  * private members                                                   *
48  * ################################################################# */
49 
50 /* ################################################################## *
51  * # Now come methods that are only available if the full-blown     # *
52  * # message object should be included in the build.                # *
53  * ################################################################## */
54 #	if FEATURE_MSGAPI == 1
55 
56 
57 #	endif /* #	if FEATURE_MSGAPI == 1 */
58 /* Next should be public members! */
59 
60 
61 /* ################################################################# *
62  * public members                                                    *
63  * ################################################################# */
64 
srSLMGConstruct(srSLMGObj ** ppThis)65 srRetVal srSLMGConstruct(srSLMGObj **ppThis)
66 {
67 	if(ppThis == NULL)
68 		return SR_RET_NULL_POINTER_PROVIDED;
69 
70 	if((*ppThis = calloc(1, sizeof(srSLMGObj))) == NULL)
71 		return SR_RET_OUT_OF_MEMORY;
72 
73 	(*ppThis)->OID = OIDsrSLMG;
74 	(*ppThis)->pszRawMsg = NULL;
75 	(*ppThis)->iSource = srSLMG_Source_OWNGenerated;
76 #	if FEATURE_MSGAPI == 1
77 	(*ppThis)->bTimStampIncludesTZ = FALSE;
78 	(*ppThis)->cTimStampOffsetMode = srSLMG_TimStamp_INVALID;
79 	(*ppThis)->iFacility = 1; /* default as of RFC 3164 */
80 	(*ppThis)->iSeverity = 5; /* default as of RFC 3164 */
81 	/* The timestamp fields are not initilized because calloc()
82 	 * already did this job. So DO NOT REMOVE CALLOC()! */
83 	(*ppThis)->pszHostname = NULL;
84 	(*ppThis)->pszLanguage = NULL;
85 	(*ppThis)->pszRemoteHost = NULL;
86 	(*ppThis)->pszTag = NULL;
87 	(*ppThis)->pszMsg = NULL;
88 	(*ppThis)->bOwnMsg = TRUE;	/* right now, we own it ;) */
89 	(*ppThis)->pszTimeStamp = NULL;
90 #	endif
91 	return SR_RET_OK;
92 }
93 
94 
srSLMGDestroy(srSLMGObj * pThis)95 void srSLMGDestroy(srSLMGObj *pThis)
96 {
97 	/* as the caller provides this information AND the caller
98 	 * may not be part of this lib, we can't use assert() here!
99 	 */
100 	if(pThis == NULL)
101 		return;
102 
103 	if(pThis->OID != OIDsrSLMG)
104 		return;
105 
106 	if((pThis->bOwnRemoteHostBuf == TRUE) && (pThis->pszRemoteHost != NULL))
107 		free(pThis->pszRemoteHost);
108 	if((pThis->bOwnRawMsgBuf == TRUE) && (pThis->pszRawMsg != NULL))
109 		free(pThis->pszRawMsg);
110 #	if FEATURE_MSGAPI == 1
111 	if(pThis->pszHostname != NULL)
112 		free(pThis->pszHostname );
113 	if(pThis->pszLanguage != NULL)
114 		free(pThis->pszLanguage );
115 	if(pThis->pszTag != NULL)
116 		free(pThis->pszTag);
117 	if((pThis->bOwnMsg == TRUE) && (pThis->pszMsg != NULL))
118 		free(pThis->pszMsg);
119 	if(pThis->pszTimeStamp != NULL)
120 		free(pThis->pszTimeStamp);
121 #	endif
122 
123 	SRFREEOBJ(pThis);
124 }
125 
126 /* ################################################################## *
127  * # Now come methods that are only available if the full-blown     # *
128  * # message object should be included in the build.                # *
129  * ################################################################## */
130 #if FEATURE_MSGAPI == 1
131 
132 
133 /**
134  * Parse a 32 bit integer number from a string.
135  *
136  * \param ppsz Pointer to the Pointer to the string being parsed. It
137  *             must be positioned at the first digit. Will be updated
138  *             so that on return it points to the first character AFTER
139  *             the integer parsed.
140  * \retval The number parsed.
141  */
_srSLMGParseInt32(unsigned char ** ppsz)142 static int _srSLMGParseInt32(unsigned char** ppsz)
143 {
144 	int i;
145 
146 	i = 0;
147 	while(isdigit(**ppsz))
148 	{
149 		i = i * 10 + **ppsz - '0';
150 		++(*ppsz);
151 	}
152 
153 	return i;
154 }
155 
156 
157 /**
158  * Parse the PRI out of the message.
159  */
srSLMGParsePRI(srSLMGObj * pThis,unsigned char ** ppszBuf)160 static int srSLMGParsePRI(srSLMGObj* pThis, unsigned char** ppszBuf)
161 {
162 	int i;
163 
164 	srSLMGCHECKVALIDOBJECT(pThis);
165 	assert(ppszBuf != NULL);
166 	assert((*ppszBuf >= pThis->pszRawMsg));
167 
168 	if(**ppszBuf != '<')
169 		return FALSE;
170 	++(*ppszBuf);
171 
172 	/* extract PRI */
173 	i = _srSLMGParseInt32(ppszBuf);
174 
175 	if(**ppszBuf != '>')
176 		return FALSE;
177 	++(*ppszBuf);
178 
179 	pThis->iFacility = i >> 3;
180 	pThis->iSeverity = i % 8;
181 
182 	return TRUE;
183 }
184 
185 
186 /**
187  * Parse a TIMESTAMP-3339.
188  */
srSLMGParseTIMESTAMP3339(srSLMGObj * pThis,unsigned char * pszTS)189 static int srSLMGParseTIMESTAMP3339(srSLMGObj* pThis, unsigned char* pszTS)
190 {
191 	srSLMGCHECKVALIDOBJECT(pThis);
192 	assert(pszTS != NULL);
193 
194 	pThis->iTimStampYear = _srSLMGParseInt32(&pszTS);
195 	if(pThis->iTimStampYear < 2003 || pThis->iTimStampYear > 9999)
196 		/* The lib was written in 2003, so any value below that year is suspicious.
197 		 * Of course, this prevents replay of data, but if someone really intends
198 		 * to do this, he is free to modify this portion of the lib ;)
199 		 */
200 		return FALSE;
201 
202 	/* We take the liberty to accept slightly malformed timestamps e.g. in
203 	 * the format of 2003-9-1T1:0:0. This doesn't hurt on receiving. Of course,
204 	 * with the current state of affairs, we would never run into this code
205 	 * here because at postion 11, there is no "T" in such cases ;)
206 	 */
207 	if(*pszTS++ != '-')
208 		return FALSE;
209 	pThis->iTimStampMonth = _srSLMGParseInt32(&pszTS);
210 	if(pThis->iTimStampMonth < 1 || pThis->iTimStampMonth > 12)
211 		return FALSE;
212 
213 	if(*pszTS++ != '-')
214 		return FALSE;
215 	pThis->iTimStampDay = _srSLMGParseInt32(&pszTS);
216 	if(pThis->iTimStampDay < 1 || pThis->iTimStampDay > 31)
217 		return FALSE;
218 
219 	if(*pszTS++ != 'T')
220 		return FALSE;
221 	pThis->iTimStampHour = _srSLMGParseInt32(&pszTS);
222 	if(pThis->iTimStampHour < 0 || pThis->iTimStampHour > 23)
223 		return FALSE;
224 
225 	if(*pszTS++ != ':')
226 		return FALSE;
227 	pThis->iTimStampMinute = _srSLMGParseInt32(&pszTS);
228 	if(pThis->iTimStampMinute < 0 || pThis->iTimStampMinute > 59)
229 		return FALSE;
230 
231 	if(*pszTS++ != ':')
232 		return FALSE;
233 	pThis->iTimStampSecond = _srSLMGParseInt32(&pszTS);
234 	if(pThis->iTimStampSecond < 0 || pThis->iTimStampSecond > 60)
235 		return FALSE;
236 
237 	/* Now let's see if we have secfrac */
238 	if(*pszTS == '.')
239 	{
240 		unsigned char *pszStart = ++pszTS;
241 		pThis->iTimStampSecFrac = _srSLMGParseInt32(&pszTS);
242 		pThis->iTimStampSecFracPrecision = (int) (pszTS - pszStart);
243 	}
244 	else
245 	{
246 		pThis->iTimStampSecFracPrecision= 0;
247 		pThis->iTimStampSecFrac = 0;
248 	}
249 
250 	/* check the timezone */
251 	if(*pszTS == 'Z')
252 	{
253 		pThis->bTimStampIncludesTZ= TRUE;
254 		pThis->iTimStampOffsetHour = 0;
255 		pThis->iTimStampOffsetMinute = 0;
256 	}
257 	else if((*pszTS == '+') || (*pszTS == '-'))
258 	{
259 		pThis->cTimStampOffsetMode = *pszTS;
260 		pszTS++;
261 
262 		pThis->iTimStampOffsetHour = _srSLMGParseInt32(&pszTS);
263 		if(pThis->iTimStampOffsetHour < 0 || pThis->iTimStampOffsetHour > 23)
264 			return FALSE;
265 
266 		if(*pszTS++ != ':')
267 			return FALSE;
268 		pThis->iTimStampOffsetMinute = _srSLMGParseInt32(&pszTS);
269 		if(pThis->iTimStampOffsetMinute < 0 || pThis->iTimStampOffsetMinute > 59)
270 			return FALSE;
271 
272 		pThis->bTimStampIncludesTZ = TRUE;
273 	}
274 	else
275 		/* there MUST be TZ information */
276 		return FALSE;
277 
278 	/* OK, we actually have a 3339 timestamp, so let's indicated this */
279 	pThis->iTimStampType = srSLMG_TimStamp_3339;
280 
281 	return TRUE;
282 }
283 
284 
285 /**
286  * Parse a TIMESTAMP-3164.
287  */
srSLMGParseTIMESTAMP3164(srSLMGObj * pThis,unsigned char * pszTS)288 static int srSLMGParseTIMESTAMP3164(srSLMGObj* pThis, unsigned char* pszTS)
289 {
290 	srSLMGCHECKVALIDOBJECT(pThis);
291 	assert(pszTS != NULL);
292 
293 	/* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec),
294 	 * we may see the following character sequences occur:
295 	 *
296 	 * J(an/u(n/l)), Feb, Ma(r/y), A(pr/ug), Sep, Oct, Nov, Dec
297 	 *
298 	 * We will use this for parsing, as it probably is the
299 	 * fastest way to parse it.
300 	 */
301 	switch(*pszTS++)
302 	{
303 	case 'J':
304 		if(*pszTS++ == 'a')
305 			if(*pszTS++ == 'n')
306 				pThis->iTimStampMonth = 1;
307 			else
308 				return FALSE;
309 		else if(*pszTS++ == 'u')
310 			if(*pszTS++ == 'n')
311 				pThis->iTimStampMonth = 6;
312 			else if(*pszTS++ == 'l')
313 				pThis->iTimStampMonth = 7;
314 			else
315 				return FALSE;
316 		else
317 			return FALSE;
318 		break;
319 	case 'F':
320 		if(*pszTS++ == 'e')
321 			if(*pszTS++ == 'b')
322 				pThis->iTimStampMonth = 2;
323 			else
324 				return FALSE;
325 		else
326 			return FALSE;
327 		break;
328 	case 'M':
329 		if(*pszTS++ == 'a')
330 			if(*pszTS++ == 'r')
331 				pThis->iTimStampMonth = 3;
332 			else if(*pszTS++ == 'y')
333 				pThis->iTimStampMonth = 5;
334 			else
335 				return FALSE;
336 		else
337 			return FALSE;
338 		break;
339 	case 'A':
340 		if(*pszTS++ == 'p')
341 			if(*pszTS++ == 'r')
342 				pThis->iTimStampMonth = 4;
343 			else
344 				return FALSE;
345 		else if(*pszTS++ == 'u')
346 			if(*pszTS++ == 'g')
347 				pThis->iTimStampMonth = 8;
348 			else
349 				return FALSE;
350 		else
351 			return FALSE;
352 		break;
353 	case 'S':
354 		if(*pszTS++ == 'e')
355 			if(*pszTS++ == 'p')
356 				pThis->iTimStampMonth = 9;
357 			else
358 				return FALSE;
359 		else
360 			return FALSE;
361 		break;
362 	case 'O':
363 		if(*pszTS++ == 'c')
364 			if(*pszTS++ == 't')
365 				pThis->iTimStampMonth = 10;
366 			else
367 				return FALSE;
368 		else
369 			return FALSE;
370 		break;
371 	case 'N':
372 		if(*pszTS++ == 'o')
373 			if(*pszTS++ == 'v')
374 				pThis->iTimStampMonth = 11;
375 			else
376 				return FALSE;
377 		else
378 			return FALSE;
379 		break;
380 	case 'D':
381 		if(*pszTS++ == 'e')
382 			if(*pszTS++ == 'c')
383 				pThis->iTimStampMonth = 12;
384 			else
385 				return FALSE;
386 		else
387 			return FALSE;
388 		break;
389 	default:
390 		return FALSE;
391 	}
392 
393 	/* done month */
394 
395 	if(*pszTS++ != ' ')
396 		return FALSE;
397 
398 	/* we accept a slightly malformed timestamp when receiving. This is
399 	 * we accept one-digit days
400 	 */
401 	if(*pszTS == ' ')
402 		++pszTS;
403 
404 	pThis->iTimStampDay = _srSLMGParseInt32(&pszTS);
405 	if(pThis->iTimStampDay < 1 || pThis->iTimStampDay > 31)
406 		return FALSE;
407 
408 	if(*pszTS++ != ' ')
409 		return FALSE;
410 	pThis->iTimStampHour = _srSLMGParseInt32(&pszTS);
411 	if(pThis->iTimStampHour < 0 || pThis->iTimStampHour > 23)
412 		return FALSE;
413 
414 	if(*pszTS++ != ':')
415 		return FALSE;
416 	pThis->iTimStampMinute = _srSLMGParseInt32(&pszTS);
417 	if(pThis->iTimStampMinute < 0 || pThis->iTimStampMinute > 59)
418 		return FALSE;
419 
420 	if(*pszTS++ != ':')
421 		return FALSE;
422 	pThis->iTimStampSecond = _srSLMGParseInt32(&pszTS);
423 	if(pThis->iTimStampSecond < 0 || pThis->iTimStampSecond > 60)
424 		return FALSE;
425 
426 	/* OK, we actually have a 3164 timestamp, so let's indicate this */
427 	pThis->iTimStampType = srSLMG_TimStamp_3164;
428 
429 	return TRUE;
430 }
431 
432 
433 /**
434  * Parse the TIMESTAMP part of the message.
435  * Primarily based on http://www.ietf.org/internet-drafts/draft-ietf-syslog-sign-12.txt;
436  */
srSLMGParseTIMESTAMP(srSLMGObj * pThis,unsigned char ** ppszBuf)437 static int srSLMGParseTIMESTAMP(srSLMGObj* pThis, unsigned char** ppszBuf)
438 {
439 	sbStrBObj *pStrBuf;
440 	int iLenTS;
441 
442 	srSLMGCHECKVALIDOBJECT(pThis);
443 	assert(ppszBuf != NULL);
444 	assert((*ppszBuf >= pThis->pszRawMsg));
445 
446 	/* first of all, extract timestamp. The timestamp
447 	 * string is also used by other parts of liblogging,
448 	 * so it must be stored within the SLMG obj.
449 	 *
450 	 * A timestamp must be at least 10 characters wide.
451 	 * As such, we read at last 15 characters (if the
452 	 * string is large enough. This is mainly because
453 	 * TIMESTAMP-3164 contains spaces in it and this is
454 	 * the only (relatively) elegant way to get around
455 	 * them...
456 	 */
457 	iLenTS = 0;
458 	if((pStrBuf = sbStrBConstruct()) == NULL)	return FALSE;
459 	sbStrBSetAllocIncrement(pStrBuf, 33);
460 	while((iLenTS < 32) && **ppszBuf)
461 	{
462 		if((**ppszBuf == ' ') && (iLenTS >= 10))
463 			break;
464 		if(sbStrBAppendChar(pStrBuf, **ppszBuf) != SR_RET_OK)	{ sbStrBDestruct(pStrBuf); return FALSE; }
465 		++(*ppszBuf);
466 		++iLenTS;
467 	}
468 	if(pThis->pszTimeStamp != NULL)
469 		free(pThis->pszTimeStamp);
470 	if((pThis->pszTimeStamp = sbStrBFinish(pStrBuf)) == NULL) return FALSE;
471 
472 	if(**ppszBuf != ' ')
473 		return FALSE;
474 	++(*ppszBuf);
475 	/* ok, the message buffer is already updated. Now let's
476 	 * see what timestamp we got.
477 	 *
478      * we first see if it looks like a TIMESTAMP-3339
479 	 */
480 	if((iLenTS > 11) && (pThis->pszTimeStamp[10] == 'T'))
481 	{	/* looks like it is TIMESTAMP-3339, so let's try to parse it */
482 		return srSLMGParseTIMESTAMP3339(pThis, pThis->pszTimeStamp);
483 	}
484 	else
485 	{	/* looks like TIMESTAMP-3164 */
486 		return srSLMGParseTIMESTAMP3164(pThis, pThis->pszTimeStamp);
487 	}
488 	/*NOTREACHED*/
489 }
490 
491 
492 /**
493  * Parse a HOSTNAME.
494  */
srSLMGParseHOSTNAME(srSLMGObj * pThis,unsigned char ** ppszBuf)495 static int srSLMGParseHOSTNAME(srSLMGObj* pThis, unsigned char** ppszBuf)
496 {
497 	sbStrBObj *pStr;
498 
499 	srSLMGCHECKVALIDOBJECT(pThis);
500 	assert(ppszBuf != NULL);
501 	assert((*ppszBuf >= pThis->pszRawMsg));
502 
503 	if(pThis->pszRemoteHost == NULL)
504 	{ /* the hostname is NOT present on /dev/log */
505 		if(sbSock_gethostname((char**) &(pThis->pszHostname)) != SR_RET_OK)
506 		{
507 			return FALSE;
508 		}
509 	}
510 	else
511 	{ /* remotely received - extract hostname from message */
512 		if((pStr = sbStrBConstruct()) == NULL)
513 			return FALSE; /* we have no way to indicated this (unlikely) error - so this is better than nothing.. */
514 
515 		sbStrBSetAllocIncrement(pStr, 64); /* should match always */
516 
517 		while(**ppszBuf && **ppszBuf != ' ')
518 		{
519 			sbStrBAppendChar(pStr, **ppszBuf);
520 			++(*ppszBuf);
521 		}
522 
523 		if(**ppszBuf == ' ')
524 			++(*ppszBuf);
525 		else
526 			/* something went wrong ;) */
527 			return FALSE;
528 
529 		pThis->pszHostname = sbStrBFinish(pStr);
530 	}
531 
532 	return TRUE;
533 }
534 
535 
536 /**
537  * Parse a TAG.
538  *
539  * We do not have a totally clear view of what the tag is.
540  * As such, we do some guesswork. First, we assume it is
541  * terminated by a colon. If it isn't, we retry by terminating
542  * it with a non-alphanumeric char. If that again doesn't help,
543  * we have a message that is not compliant to any RFCs, thus
544  * we assume it is a "raw" message.
545  */
srSLMGParseTAG(srSLMGObj * pThis,unsigned char ** ppszBuf)546 static int srSLMGParseTAG(srSLMGObj* pThis, unsigned char** ppszBuf)
547 {
548 	unsigned char *pBuf;
549 	unsigned char *pInBuf;
550 	int i;
551 
552 	srSLMGCHECKVALIDOBJECT(pThis);
553 	assert(ppszBuf != NULL);
554 	assert((*ppszBuf >= pThis->pszRawMsg));
555 
556 	pInBuf = *ppszBuf;
557 	if((pBuf = malloc(33 * sizeof(unsigned char))) == NULL)
558 		return FALSE; /* we have no way to indicated this (unlikely) error - so this is better than nothing.. */
559 
560 	i = 0;
561 	while(**ppszBuf && **ppszBuf != ':' && i < 32)
562 	{
563 		*(pBuf+i) = **ppszBuf;
564 		++i;
565 		++(*ppszBuf);
566 	}
567 
568 	if(**ppszBuf == ':')
569 	{	/* ok, looks like a syslog-sign tag */
570 		if(i >= 32)
571 		{	/* oops... */
572 			free(pBuf);
573 			return FALSE;
574 		}
575 		*(pBuf+i++) = ':';
576 		*(pBuf+i) = '\0';
577 		++(*ppszBuf);	/* eat it, the colon is not part of the message under -sign */
578 		pThis->pszTag = pBuf;
579 		return TRUE;
580 	}
581 
582 	/* control reaches this point if the tag was no good and we
583 	 * need to retry.
584 	 */
585 	*ppszBuf = pInBuf;
586 	i = 0;
587 	while(**ppszBuf && isalnum(**ppszBuf) && i < 32)
588 	{
589 		*(pBuf+i) = **ppszBuf;
590 		++i;
591 		++(*ppszBuf);
592 	}
593 
594 	if(isalnum(**ppszBuf))
595 	{	/* oversize tag --> invalid! */
596 		free(pBuf);
597 		return FALSE;
598 	}
599 
600 	*(pBuf+i) = '\0';
601 	pThis->pszTag = pBuf;
602 
603 	return TRUE;
604 }
605 
606 
607 /**
608  * Copy the MSG to its own buffer.
609  *
610  * In the future, we may add coockie processing e.g. for -sign, -interntional
611  * here.
612  */
srSLMGProcessMSG(srSLMGObj * pThis,unsigned char ** ppszBuf)613 static srRetVal srSLMGProcessMSG(srSLMGObj* pThis, unsigned char** ppszBuf)
614 {
615 	srRetVal iRet;
616 	sbStrBObj *pStr;
617 
618 	srSLMGCHECKVALIDOBJECT(pThis);
619 	assert(ppszBuf != NULL);
620 	assert((*ppszBuf >= pThis->pszRawMsg));
621 
622 	if((pStr = sbStrBConstruct()) == NULL)
623 		return SR_RET_OUT_OF_MEMORY; /* we have no way to indicated this (unlikely) error - so this is better than nothing.. */
624 
625 	while(**ppszBuf)
626 	{
627 		if((iRet = sbStrBAppendChar(pStr, **ppszBuf)) != SR_RET_OK)
628 			return iRet;
629 		++(*ppszBuf);
630 	}
631 
632 	pThis->pszMsg = sbStrBFinish(pStr);
633 
634 	return SR_RET_OK;
635 }
636 
637 
srSLMGParseMesg(srSLMGObj * pThis)638 srRetVal srSLMGParseMesg(srSLMGObj *pThis)
639 {
640 	srRetVal iRet;
641 	unsigned char* pszBuf;
642 	srSLMGCHECKVALIDOBJECT_API(pThis);
643 
644 	/* This algo works as follows: It tries to parse each of the syslog
645 	 * message. A parser is called for each part (e.g. PRI and TIMESTAMP).
646 	 * The parser tries to find a suitable format for that part of the
647 	 * message and - if it does - updates the syslog message's properties
648 	 * and returns TRUE. If it does not find a match, it returns FALSE.
649 	 * A failed parser does not necessarily mean the message is invalid -
650 	 * we can always fall back to plain 3164. However, the caller for whom
651 	 * the message is being parsed is advised to check which format we
652      * found and eventually issue an error message (e.g. if we have a
653 	 * syslog-sign message with a RFC 3164 message format - that does
654 	 * not work (or does it...?).
655 	 */
656 	pszBuf = pThis->pszRawMsg;
657 	if(srSLMGParsePRI(pThis, &pszBuf) == FALSE)
658 	{
659 		pThis->iFormat = srSLMGFmt_3164RAW;
660 		return SR_RET_OK;
661 	}
662 
663 	if(srSLMGParseTIMESTAMP(pThis, &pszBuf) == FALSE)
664 	{
665 		pThis->iFormat = srSLMGFmt_3164RAW;
666 		return SR_RET_OK;
667 	}
668 
669 	if(srSLMGParseHOSTNAME(pThis, &pszBuf) == FALSE)
670 	{
671 		pThis->iFormat = srSLMGFmt_3164RAW;
672 		return SR_RET_OK;
673 	}
674 
675 	if(srSLMGParseTAG(pThis, &pszBuf) == FALSE)
676 	{
677 		pThis->iFormat = srSLMGFmt_3164RAW;
678 		return SR_RET_OK;
679 	}
680 
681 	/* OK, this must be wellformed format */
682 	if(pThis->iTimStampType == srSLMG_TimStamp_3164)
683 		pThis->iFormat = srSLMGFmt_3164WELLFORMED;
684 	else
685 		pThis->iFormat = srSLMGFmt_SIGN_12;
686 
687 	if((iRet = srSLMGProcessMSG(pThis, &pszBuf)) != SR_RET_OK)
688 		return iRet;
689 
690 	return SR_RET_OK;
691 }
692 
693 
srSLMGGetPriority(srSLMGObj * pThis,int * piPrio)694 srRetVal srSLMGGetPriority(srSLMGObj *pThis, int *piPrio)
695 {
696 	srSLMGCHECKVALIDOBJECT_API(pThis);
697 	if(piPrio == NULL)
698 		return SR_RET_NULL_POINTER_PROVIDED;
699 	*piPrio = pThis->iSeverity ;
700 	return SR_RET_OK;
701 }
702 
703 
srSLMGGetFacility(srSLMGObj * pThis,int * piFac)704 srRetVal srSLMGGetFacility(srSLMGObj *pThis, int *piFac)
705 {
706 	srSLMGCHECKVALIDOBJECT_API(pThis);
707 	if(piFac == NULL)
708 		return SR_RET_NULL_POINTER_PROVIDED;
709 	*piFac = pThis->iFacility;
710 	return SR_RET_OK;
711 }
712 
713 
srSLMGGetRemoteHost(srSLMGObj * pThis,char ** ppsz)714 srRetVal srSLMGGetRemoteHost(srSLMGObj *pThis, char**ppsz)
715 {
716 	srSLMGCHECKVALIDOBJECT_API(pThis);
717 	if(ppsz== NULL)
718 		return SR_RET_NULL_POINTER_PROVIDED;
719 	*ppsz = pThis->pszRemoteHost;
720 	return SR_RET_OK;
721 }
722 
723 
srSLMGGetHostname(srSLMGObj * pThis,char ** ppsz)724 srRetVal srSLMGGetHostname(srSLMGObj *pThis, char**ppsz)
725 {
726 	srSLMGCHECKVALIDOBJECT_API(pThis);
727 	if(ppsz== NULL)
728 		return SR_RET_NULL_POINTER_PROVIDED;
729 	if(!((pThis->iFormat == srSLMGFmt_3164WELLFORMED) || (pThis->iFormat == srSLMGFmt_SIGN_12)))
730 		return SR_RET_PROPERTY_NOT_AVAILABLE;
731 	*ppsz = pThis->pszHostname;
732 	return SR_RET_OK;
733 }
734 
735 
srSLMGGetTag(srSLMGObj * pThis,unsigned char ** ppsz)736 srRetVal srSLMGGetTag(srSLMGObj *pThis, unsigned char**ppsz)
737 {
738 	srSLMGCHECKVALIDOBJECT_API(pThis);
739 	if(ppsz== NULL)
740 		return SR_RET_NULL_POINTER_PROVIDED;
741 	if(!((pThis->iFormat == srSLMGFmt_3164WELLFORMED) || (pThis->iFormat == srSLMGFmt_SIGN_12)))
742 		return SR_RET_PROPERTY_NOT_AVAILABLE;
743 	*ppsz = pThis->pszTag;
744 	return SR_RET_OK;
745 }
746 
747 
srSLMGGetMSG(srSLMGObj * pThis,unsigned char ** ppsz)748 srRetVal srSLMGGetMSG(srSLMGObj *pThis, unsigned char**ppsz)
749 {
750 	srSLMGCHECKVALIDOBJECT_API(pThis);
751 	if(ppsz== NULL)
752 		return SR_RET_NULL_POINTER_PROVIDED;
753 	if(!((pThis->iFormat == srSLMGFmt_3164WELLFORMED) || (pThis->iFormat == srSLMGFmt_SIGN_12)))
754 		/* in this case, we have nothing  but the raw message and thus we return it.
755 		 * Well... 3164 says this is exactly what we should do, as in the absense
756 		 * of a proper header the whole message is deemed to be MSG only.
757 		 */
758 		*ppsz = pThis->pszRawMsg;
759 	else
760 		*ppsz = pThis->pszMsg;
761 	return SR_RET_OK;
762 }
763 
764 
765 /**
766  * Provide the caller back with the raw message.
767  *
768  * This is especially useful for syslog-sign, where the
769  * raw message must be stored in order to keep the sig
770  * intact!
771  *
772  * \note The returned string is read-only. It is valid
773  * only until the srSLMGObj is destroyed. If the caller intends
774  * to use it for a prolonged period of time, it needs to
775  * copy it!
776  *
777  * \param ppsz Pointer to Pointer to unsigned char to
778  *             receive the return string.
779  */
srSLMGGetRawMSG(srSLMGObj * pThis,unsigned char ** ppsz)780 srRetVal srSLMGGetRawMSG(srSLMGObj *pThis, unsigned char**ppsz)
781 {
782 	srSLMGCHECKVALIDOBJECT_API(pThis);
783 	if(ppsz== NULL)
784 		return SR_RET_NULL_POINTER_PROVIDED;
785 	*ppsz = pThis->pszRawMsg;
786 	return SR_RET_OK;
787 }
788 
srSLMGSetRemoteHostIP(srSLMGObj * pThis,char * pszRemHostIP,int bCopyRemHost)789 srRetVal srSLMGSetRemoteHostIP(srSLMGObj *pThis, char *pszRemHostIP, int bCopyRemHost)
790 {
791 	srSLMGCHECKVALIDOBJECT_API(pThis);
792 
793 	if(pThis->pszRemoteHost != NULL)
794 		if(pThis->bOwnRemoteHostBuf == TRUE)
795 			free(pThis->pszRemoteHost);
796 
797 	if(bCopyRemHost == TRUE)
798 	{
799 		if((pThis->pszRemoteHost = sbNVTEUtilStrDup(pszRemHostIP)) == NULL)
800 			return SR_RET_OUT_OF_MEMORY;
801 	}
802 	else
803 		pThis->pszRemoteHost = pszRemHostIP;
804 
805 	pThis->bOwnRemoteHostBuf = bCopyRemHost;
806 
807 	return SR_RET_OK;
808 }
809 
810 
srSLMGSetRawMsg(srSLMGObj * pThis,char * pszRawMsg,int bCopyRawMsg)811 srRetVal srSLMGSetRawMsg(srSLMGObj *pThis, char *pszRawMsg, int bCopyRawMsg)
812 {
813 	srSLMGCHECKVALIDOBJECT_API(pThis);
814 	if(pThis->pszRawMsg != NULL)
815 		if(pThis->bOwnRawMsgBuf == TRUE)
816 			free(pThis->pszRawMsg);
817 
818 	if(bCopyRawMsg == TRUE)
819 	{
820 		if((pThis->pszRawMsg = sbNVTEUtilStrDup(pszRawMsg)) == NULL)
821 			return SR_RET_OUT_OF_MEMORY;
822 	}
823 	else
824 		pThis->pszRawMsg = pszRawMsg;
825 
826 	pThis->bOwnRawMsgBuf = bCopyRawMsg;
827 
828 	return SR_RET_OK;
829 }
830 
831 
srSLMGSetMSG(srSLMGObj * pThis,char * pszMSG,int bCopyMSG)832 srRetVal srSLMGSetMSG(srSLMGObj *pThis, char *pszMSG, int bCopyMSG)
833 {
834 	srSLMGCHECKVALIDOBJECT_API(pThis);
835 	if(pThis->pszMsg != NULL)
836 		if(pThis->bOwnMsg == TRUE)
837 			free(pThis->pszMsg);
838 
839 	if(bCopyMSG == TRUE)
840 	{
841 		if((pThis->pszMsg = sbNVTEUtilStrDup(pszMSG)) == NULL)
842 			return SR_RET_OUT_OF_MEMORY;
843 	}
844 	else
845 		pThis->pszMsg = pszMSG;
846 
847 	pThis->bOwnMsg = bCopyMSG;
848 
849 	return SR_RET_OK;
850 }
851 
852 
853 
srSLMGSetTIMESTAMPtoCurrent(srSLMGObj * pThis)854 srRetVal srSLMGSetTIMESTAMPtoCurrent(srSLMGObj *pThis)
855 {
856 	srRetVal iRet;
857 	srSLMGCHECKVALIDOBJECT_API(pThis);
858 
859 	iRet = getCurrTime(&pThis->iTimStampYear, &pThis->iTimStampMonth, &pThis->iTimStampDay,
860 					   &pThis->iTimStampHour, &pThis->iTimStampMinute, &pThis->iTimStampSecond,
861 					   &pThis->iTimStampSecFrac, &pThis->iTimStampSecFracPrecision, &pThis->cTimStampOffsetMode,
862 					   &pThis->iTimStampOffsetHour, &pThis->iTimStampOffsetMinute);
863 
864 	return iRet;
865 }
866 
867 
868 /**
869  * Set the HOSTNAME to the current hostname.
870  */
srSLMGSetHOSTNAMEtoCurrent(srSLMGObj * pThis)871 srRetVal srSLMGSetHOSTNAMEtoCurrent(srSLMGObj* pThis)
872 {
873 	srSLMGCHECKVALIDOBJECT_API(pThis);
874 	return sbSock_gethostname((char**) (&(pThis->pszHostname)));
875 }
876 
877 
878 /* The following table is a helper to srSLMGFormatRawMsg:
879  */
880 static char* srSLMGMonthNames[13] = {"ERR", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
881 
srSLMGFormatRawMsg(srSLMGObj * pThis,srSLMGFormat iFmtToUse)882 srRetVal srSLMGFormatRawMsg(srSLMGObj *pThis, srSLMGFormat iFmtToUse)
883 {
884 	srRetVal iRet;
885 	sbStrBObj *pStr;
886 	char szBuf[128];
887 	int i;
888 
889 	srSLMGCHECKVALIDOBJECT_API(pThis);
890 	if((iFmtToUse != srSLMGFmt_3164WELLFORMED) && (iFmtToUse != srSLMGFmt_SIGN_12))
891 		return SR_RET_UNSUPPORTED_FORMAT;
892 
893 	if(pThis->pszRawMsg != NULL)
894 		if(pThis->bOwnRawMsgBuf == FALSE)
895 			return SR_RET_UNALLOCATABLE_BUFFER;
896 		else
897 		{
898 			free(pThis->pszRawMsg);
899 			pThis->pszRawMsg = NULL;
900 		}
901 
902 	if((pStr = sbStrBConstruct()) == NULL)
903 		return SR_RET_OUT_OF_MEMORY;
904 
905 	/* PRI */
906 	i = (pThis->iFacility << 3) + pThis->iSeverity;
907 	SNPRINTF(szBuf, sizeof(szBuf), "<%d>", i);
908 	if((iRet = sbStrBAppendStr(pStr, szBuf)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; }
909 
910 	/* TIMESTAMP
911 	 * Please note: all SNPRINTFs allow 34 Bytes, because of
912 	 * a) the '\0' byte
913 	 * b) the extra space at the end of the TIMESTAMP
914 	 * So the TIMESTAMP itself will by 32 bytes at most.
915 	 */
916 	if(pThis->pszTimeStamp != NULL)
917 		free(pThis->pszTimeStamp);
918 	if((pThis->pszTimeStamp = calloc(34, sizeof(char))) == NULL)
919 		return SR_RET_OUT_OF_MEMORY;
920 	if(iFmtToUse == srSLMGFmt_3164WELLFORMED)
921 	{
922 		SNPRINTF(pThis->pszTimeStamp,
923 			     34, "%s %2d %2.2d:%2.2d:%2.2d ",
924 				 srSLMGMonthNames[pThis->iTimStampMonth], pThis->iTimStampDay,
925 				 pThis->iTimStampHour, pThis->iTimStampMinute, pThis->iTimStampSecond);
926 	}
927 	else
928 	{ /* SIGN_12! */
929 		if(pThis->iTimStampSecFracPrecision > 0)
930 		{	/* we now need to include fractional seconds. While doing so, we must look at
931 			 * the precision specified. For example, if we have millisec precision (3 digits), a
932 			 * secFrac value of 12 is not equivalent to ".12" but ".012". Obviously, this
933 			 * is a huge difference ;). To avoid this, we first create a format string with
934 			 * the specific precision and *then* use that format string to do the actual
935 			 * formating (mmmmhhh... kind of self-modifying code... ;)).
936 			 */
937 			char szFmtStr[64];
938 			/* be careful: there is ONE actual %d in the format string below ;) */
939 			SNPRINTF(szFmtStr, sizeof(szFmtStr), "%%04d-%%02d-%%02dT%%02d:%%02d:%%02d.%%0%dd%%c%%02d:%%02d ",
940 								pThis->iTimStampSecFracPrecision);
941 
942 			SNPRINTF(pThis->pszTimeStamp, 34, szFmtStr,
943 								pThis->iTimStampYear, pThis->iTimStampMonth, pThis->iTimStampDay,
944 								pThis->iTimStampHour, pThis->iTimStampMinute, pThis->iTimStampSecond, pThis->iTimStampSecFrac,
945 								pThis->cTimStampOffsetMode, pThis->iTimStampOffsetHour, pThis->iTimStampOffsetMinute);
946 		}
947 		else
948 			SNPRINTF(pThis->pszTimeStamp, 34, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d%c%2.2d:%2.2d ",
949 								pThis->iTimStampYear, pThis->iTimStampMonth, pThis->iTimStampDay,
950 								pThis->iTimStampHour, pThis->iTimStampMinute, pThis->iTimStampSecond,
951 								pThis->cTimStampOffsetMode, pThis->iTimStampOffsetHour, pThis->iTimStampOffsetMinute);
952 	}
953 	/* timestamp done, add it... */
954 	if((iRet = sbStrBAppendStr(pStr, pThis->pszTimeStamp)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; }
955 
956 	/* HOSTNAME */
957 	if((iRet = sbStrBAppendStr(pStr, pThis->pszHostname)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; }
958 	if((iRet = sbStrBAppendChar(pStr, ' ')) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; }
959 
960 	/* TAG */
961 	if((iRet = sbStrBAppendStr(pStr, pThis->pszTag)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; }
962 	if(*(pThis->pszTag + strlen(pThis->pszTag) - 1) != ':')
963 		if((iFmtToUse == srSLMGFmt_SIGN_12) || isalnum(*(pThis->pszTag + strlen(pThis->pszTag) - 1)))
964 		{	/* -sign MUST be terminated by a colon, in 3164 it is not allowed to be terminated by alnum */
965 			if((iRet = sbStrBAppendChar(pStr, ':')) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; }
966 		}
967 
968 
969 
970 	/* MSG */
971 	if((iRet = sbStrBAppendStr(pStr, pThis->pszMsg)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; }
972 
973 	/* done, let's store the new string */
974 	pThis->pszRawMsg = sbStrBFinish(pStr);
975 	pThis->bOwnRawMsgBuf = TRUE;
976 	return SR_RET_OK;
977 }
978 
979 
srSLMGSetFacility(srSLMGObj * pThis,int iNewVal)980 srRetVal srSLMGSetFacility(srSLMGObj* pThis, int iNewVal)
981 {
982 	srSLMGCHECKVALIDOBJECT_API(pThis);
983 
984 	if(iNewVal < 0 || iNewVal > 23)
985 		return SR_RET_FACIL_OUT_OF_RANGE;
986 
987 	pThis->iFacility = iNewVal;
988 
989 	return SR_RET_OK;
990 }
991 
992 
srSLMGSetSeverity(srSLMGObj * pThis,int iNewVal)993 srRetVal srSLMGSetSeverity(srSLMGObj* pThis, int iNewVal)
994 {
995 	srSLMGCHECKVALIDOBJECT_API(pThis);
996 
997 	if(iNewVal < 0 || iNewVal > 7)
998 		return SR_RET_PRIO_OUT_OF_RANGE;
999 
1000 	pThis->iSeverity = iNewVal;
1001 
1002 	return SR_RET_OK;
1003 }
1004 
1005 
srSLMGSetTAG(srSLMGObj * pThis,char * pszNewTag)1006 srRetVal srSLMGSetTAG(srSLMGObj* pThis, char* pszNewTag)
1007 {
1008 	srRetVal iRet;
1009 	sbStrBObj *pStr;
1010 	int i;
1011 
1012 	srSLMGCHECKVALIDOBJECT_API(pThis);
1013 	if(pszNewTag == NULL)
1014 		return SR_RET_NULL_POINTER_PROVIDED;
1015 
1016     if((pStr = sbStrBConstruct()) == NULL) return SR_RET_OUT_OF_MEMORY;
1017 
1018 	sbStrBSetAllocIncrement(pStr, 16);
1019 
1020 	/* copy tag value & check validity
1021 	 * (we assume all chars except ':' and SP to be valid)
1022 	 */
1023 	for(i = 0 ; *(pszNewTag+i) && i < 32 ; ++i)
1024 		if((*(pszNewTag+i) == ':') || (*(pszNewTag+i) == ' '))
1025 			return SR_RET_INVALID_TAG;
1026 		else
1027 			if((iRet = sbStrBAppendChar(pStr, *(pszNewTag+i))) != SR_RET_OK)
1028 				return iRet;
1029 
1030 	if(*(pszNewTag+i) != '\0')
1031 		/* more than 32 chars */
1032 		return SR_RET_INVALID_TAG;
1033 
1034 	/* done, set property */
1035 	if(pThis->pszTag != NULL)
1036 		free(pThis->pszTag);
1037 	if((pThis->pszTag = sbStrBFinish(pStr)) == NULL) return SR_RET_OUT_OF_MEMORY;
1038 
1039 	return SR_RET_OK;
1040 }
1041 
1042 #endif /* #if FEATURE_MSGAPI == 1 */
1043