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