/*! \file syslogmessage.c * \brief Implementation of the syslog message object. * * \author Rainer Gerhards * \date 2003-09-01 * coding begun. * * Copyright 2002-2003 * Rainer Gerhards and Adiscon GmbH. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Adiscon GmbH or Rainer Gerhards * nor the names of its contributors may be used to * endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "liblogging-config.h" #include "liblogging.h" #include "srAPI.h" #include "syslogmessage.h" #include "namevaluetree.h" #include "stringbuf.h" #include "oscalls.h" /* ################################################################# * * private members * * ################################################################# */ /* ################################################################## * * # Now come methods that are only available if the full-blown # * * # message object should be included in the build. # * * ################################################################## */ # if FEATURE_MSGAPI == 1 # endif /* # if FEATURE_MSGAPI == 1 */ /* Next should be public members! */ /* ################################################################# * * public members * * ################################################################# */ srRetVal srSLMGConstruct(srSLMGObj **ppThis) { if(ppThis == NULL) return SR_RET_NULL_POINTER_PROVIDED; if((*ppThis = calloc(1, sizeof(srSLMGObj))) == NULL) return SR_RET_OUT_OF_MEMORY; (*ppThis)->OID = OIDsrSLMG; (*ppThis)->pszRawMsg = NULL; (*ppThis)->iSource = srSLMG_Source_OWNGenerated; # if FEATURE_MSGAPI == 1 (*ppThis)->bTimStampIncludesTZ = FALSE; (*ppThis)->cTimStampOffsetMode = srSLMG_TimStamp_INVALID; (*ppThis)->iFacility = 1; /* default as of RFC 3164 */ (*ppThis)->iSeverity = 5; /* default as of RFC 3164 */ /* The timestamp fields are not initilized because calloc() * already did this job. So DO NOT REMOVE CALLOC()! */ (*ppThis)->pszHostname = NULL; (*ppThis)->pszLanguage = NULL; (*ppThis)->pszRemoteHost = NULL; (*ppThis)->pszTag = NULL; (*ppThis)->pszMsg = NULL; (*ppThis)->bOwnMsg = TRUE; /* right now, we own it ;) */ (*ppThis)->pszTimeStamp = NULL; # endif return SR_RET_OK; } void srSLMGDestroy(srSLMGObj *pThis) { /* as the caller provides this information AND the caller * may not be part of this lib, we can't use assert() here! */ if(pThis == NULL) return; if(pThis->OID != OIDsrSLMG) return; if((pThis->bOwnRemoteHostBuf == TRUE) && (pThis->pszRemoteHost != NULL)) free(pThis->pszRemoteHost); if((pThis->bOwnRawMsgBuf == TRUE) && (pThis->pszRawMsg != NULL)) free(pThis->pszRawMsg); # if FEATURE_MSGAPI == 1 if(pThis->pszHostname != NULL) free(pThis->pszHostname ); if(pThis->pszLanguage != NULL) free(pThis->pszLanguage ); if(pThis->pszTag != NULL) free(pThis->pszTag); if((pThis->bOwnMsg == TRUE) && (pThis->pszMsg != NULL)) free(pThis->pszMsg); if(pThis->pszTimeStamp != NULL) free(pThis->pszTimeStamp); # endif SRFREEOBJ(pThis); } /* ################################################################## * * # Now come methods that are only available if the full-blown # * * # message object should be included in the build. # * * ################################################################## */ #if FEATURE_MSGAPI == 1 /** * Parse a 32 bit integer number from a string. * * \param ppsz Pointer to the Pointer to the string being parsed. It * must be positioned at the first digit. Will be updated * so that on return it points to the first character AFTER * the integer parsed. * \retval The number parsed. */ int srSLMGParseInt32(unsigned char** ppsz) { int i; i = 0; while(isdigit(**ppsz)) { i = i * 10 + **ppsz - '0'; ++(*ppsz); } return i; } /** * Parse the PRI out of the message. */ static int srSLMGParsePRI(srSLMGObj* pThis, unsigned char** ppszBuf) { int i; srSLMGCHECKVALIDOBJECT(pThis); assert(ppszBuf != NULL); assert((*ppszBuf >= pThis->pszRawMsg)); if(**ppszBuf != '<') return FALSE; ++(*ppszBuf); /* extract PRI */ i = srSLMGParseInt32(ppszBuf); if(**ppszBuf != '>') return FALSE; ++(*ppszBuf); pThis->iFacility = i >> 3; pThis->iSeverity = i % 8; return TRUE; } /** * Parse a TIMESTAMP-3339. */ static int srSLMGParseTIMESTAMP3339(srSLMGObj* pThis, unsigned char* pszTS) { srSLMGCHECKVALIDOBJECT(pThis); assert(pszTS != NULL); pThis->iTimStampYear = srSLMGParseInt32(&pszTS); if(pThis->iTimStampYear < 2003 || pThis->iTimStampYear > 9999) /* The lib was written in 2003, so any value below that year is suspicious. * Of course, this prevents replay of data, but if someone really intends * to do this, he is free to modify this portion of the lib ;) */ return FALSE; /* We take the liberty to accept slightly malformed timestamps e.g. in * the format of 2003-9-1T1:0:0. This doesn't hurt on receiving. Of course, * with the current state of affairs, we would never run into this code * here because at postion 11, there is no "T" in such cases ;) */ if(*pszTS++ != '-') return FALSE; pThis->iTimStampMonth = srSLMGParseInt32(&pszTS); if(pThis->iTimStampMonth < 1 || pThis->iTimStampMonth > 12) return FALSE; if(*pszTS++ != '-') return FALSE; pThis->iTimStampDay = srSLMGParseInt32(&pszTS); if(pThis->iTimStampDay < 1 || pThis->iTimStampDay > 31) return FALSE; if(*pszTS++ != 'T') return FALSE; pThis->iTimStampHour = srSLMGParseInt32(&pszTS); if(pThis->iTimStampHour < 0 || pThis->iTimStampHour > 23) return FALSE; if(*pszTS++ != ':') return FALSE; pThis->iTimStampMinute = srSLMGParseInt32(&pszTS); if(pThis->iTimStampMinute < 0 || pThis->iTimStampMinute > 59) return FALSE; if(*pszTS++ != ':') return FALSE; pThis->iTimStampSecond = srSLMGParseInt32(&pszTS); if(pThis->iTimStampSecond < 0 || pThis->iTimStampSecond > 60) return FALSE; /* Now let's see if we have secfrac */ if(*pszTS == '.') { unsigned char *pszStart = ++pszTS; pThis->iTimStampSecFrac = srSLMGParseInt32(&pszTS); pThis->iTimStampSecFracPrecision = (int) (pszTS - pszStart); } else { pThis->iTimStampSecFracPrecision= 0; pThis->iTimStampSecFrac = 0; } /* check the timezone */ if(*pszTS == 'Z') { pThis->bTimStampIncludesTZ= TRUE; pThis->iTimStampOffsetHour = 0; pThis->iTimStampOffsetMinute = 0; } else if((*pszTS == '+') || (*pszTS == '-')) { pThis->cTimStampOffsetMode = *pszTS; pszTS++; pThis->iTimStampOffsetHour = srSLMGParseInt32(&pszTS); if(pThis->iTimStampOffsetHour < 0 || pThis->iTimStampOffsetHour > 23) return FALSE; if(*pszTS++ != ':') return FALSE; pThis->iTimStampOffsetMinute = srSLMGParseInt32(&pszTS); if(pThis->iTimStampOffsetMinute < 0 || pThis->iTimStampOffsetMinute > 59) return FALSE; pThis->bTimStampIncludesTZ = TRUE; } else /* there MUST be TZ information */ return FALSE; /* OK, we actually have a 3339 timestamp, so let's indicated this */ pThis->iTimStampType = srSLMG_TimStamp_3339; return TRUE; } /** * Parse a TIMESTAMP-3164. */ static int srSLMGParseTIMESTAMP3164(srSLMGObj* pThis, unsigned char* pszTS) { srSLMGCHECKVALIDOBJECT(pThis); assert(pszTS != NULL); /* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec), * we may see the following character sequences occur: * * J(an/u(n/l)), Feb, Ma(r/y), A(pr/ug), Sep, Oct, Nov, Dec * * We will use this for parsing, as it probably is the * fastest way to parse it. */ switch(*pszTS++) { case 'J': if(*pszTS++ == 'a') if(*pszTS++ == 'n') pThis->iTimStampMonth = 1; else return FALSE; else if(*pszTS++ == 'u') if(*pszTS++ == 'n') pThis->iTimStampMonth = 6; else if(*pszTS++ == 'l') pThis->iTimStampMonth = 7; else return FALSE; else return FALSE; break; case 'F': if(*pszTS++ == 'e') if(*pszTS++ == 'b') pThis->iTimStampMonth = 2; else return FALSE; else return FALSE; break; case 'M': if(*pszTS++ == 'a') if(*pszTS++ == 'r') pThis->iTimStampMonth = 3; else if(*pszTS++ == 'y') pThis->iTimStampMonth = 5; else return FALSE; else return FALSE; break; case 'A': if(*pszTS++ == 'p') if(*pszTS++ == 'r') pThis->iTimStampMonth = 4; else return FALSE; else if(*pszTS++ == 'u') if(*pszTS++ == 'g') pThis->iTimStampMonth = 8; else return FALSE; else return FALSE; break; case 'S': if(*pszTS++ == 'e') if(*pszTS++ == 'p') pThis->iTimStampMonth = 9; else return FALSE; else return FALSE; break; case 'O': if(*pszTS++ == 'c') if(*pszTS++ == 't') pThis->iTimStampMonth = 10; else return FALSE; else return FALSE; break; case 'N': if(*pszTS++ == 'o') if(*pszTS++ == 'v') pThis->iTimStampMonth = 11; else return FALSE; else return FALSE; break; case 'D': if(*pszTS++ == 'e') if(*pszTS++ == 'c') pThis->iTimStampMonth = 12; else return FALSE; else return FALSE; break; default: return FALSE; } /* done month */ if(*pszTS++ != ' ') return FALSE; /* we accept a slightly malformed timestamp when receiving. This is * we accept one-digit days */ if(*pszTS == ' ') ++pszTS; pThis->iTimStampDay = srSLMGParseInt32(&pszTS); if(pThis->iTimStampDay < 1 || pThis->iTimStampDay > 31) return FALSE; if(*pszTS++ != ' ') return FALSE; pThis->iTimStampHour = srSLMGParseInt32(&pszTS); if(pThis->iTimStampHour < 0 || pThis->iTimStampHour > 23) return FALSE; if(*pszTS++ != ':') return FALSE; pThis->iTimStampMinute = srSLMGParseInt32(&pszTS); if(pThis->iTimStampMinute < 0 || pThis->iTimStampMinute > 59) return FALSE; if(*pszTS++ != ':') return FALSE; pThis->iTimStampSecond = srSLMGParseInt32(&pszTS); if(pThis->iTimStampSecond < 0 || pThis->iTimStampSecond > 60) return FALSE; /* OK, we actually have a 3164 timestamp, so let's indicate this */ pThis->iTimStampType = srSLMG_TimStamp_3164; return TRUE; } /** * Parse the TIMESTAMP part of the message. * Primarily based on http://www.ietf.org/internet-drafts/draft-ietf-syslog-sign-12.txt; */ static int srSLMGParseTIMESTAMP(srSLMGObj* pThis, unsigned char** ppszBuf) { sbStrBObj *pStrBuf; int iLenTS; srSLMGCHECKVALIDOBJECT(pThis); assert(ppszBuf != NULL); assert((*ppszBuf >= pThis->pszRawMsg)); /* first of all, extract timestamp. The timestamp * string is also used by other parts of liblogging, * so it must be stored within the SLMG obj. * * A timestamp must be at least 10 characters wide. * As such, we read at last 15 characters (if the * string is large enough. This is mainly because * TIMESTAMP-3164 contains spaces in it and this is * the only (relatively) elegant way to get around * them... */ iLenTS = 0; if((pStrBuf = sbStrBConstruct()) == NULL) return FALSE; sbStrBSetAllocIncrement(pStrBuf, 33); while((iLenTS < 32) && **ppszBuf) { if((**ppszBuf == ' ') && (iLenTS >= 10)) break; if(sbStrBAppendChar(pStrBuf, **ppszBuf) != SR_RET_OK) { sbStrBDestruct(pStrBuf); return FALSE; } ++(*ppszBuf); ++iLenTS; } if(pThis->pszTimeStamp != NULL) free(pThis->pszTimeStamp); if((pThis->pszTimeStamp = sbStrBFinish(pStrBuf)) == NULL) return FALSE; if(**ppszBuf != ' ') return FALSE; ++(*ppszBuf); /* ok, the message buffer is already updated. Now let's * see what timestamp we got. * * we first see if it looks like a TIMESTAMP-3339 */ if((iLenTS > 11) && (pThis->pszTimeStamp[10] == 'T')) { /* looks like it is TIMESTAMP-3339, so let's try to parse it */ return srSLMGParseTIMESTAMP3339(pThis, pThis->pszTimeStamp); } else { /* looks like TIMESTAMP-3164 */ return srSLMGParseTIMESTAMP3164(pThis, pThis->pszTimeStamp); } /*NOTREACHED*/ } /** * Parse a HOSTNAME. */ static int srSLMGParseHOSTNAME(srSLMGObj* pThis, unsigned char** ppszBuf) { sbStrBObj *pStr; srSLMGCHECKVALIDOBJECT(pThis); assert(ppszBuf != NULL); assert((*ppszBuf >= pThis->pszRawMsg)); if(pThis->pszRemoteHost == NULL) { /* the hostname is NOT present on /dev/log */ if(sbSock_gethostname((char**) &(pThis->pszHostname)) != SR_RET_OK) { return FALSE; } } else { /* remotely received - extract hostname from message */ if((pStr = sbStrBConstruct()) == NULL) return FALSE; /* we have no way to indicated this (unlikely) error - so this is better than nothing.. */ sbStrBSetAllocIncrement(pStr, 64); /* should match always */ while(**ppszBuf && **ppszBuf != ' ') { sbStrBAppendChar(pStr, **ppszBuf); ++(*ppszBuf); } if(**ppszBuf == ' ') ++(*ppszBuf); else /* something went wrong ;) */ return FALSE; pThis->pszHostname = sbStrBFinish(pStr); } return TRUE; } /** * Parse a TAG. * * We do not have a totally clear view of what the tag is. * As such, we do some guesswork. First, we assume it is * terminated by a colon. If it isn't, we retry by terminating * it with a non-alphanumeric char. If that again doesn't help, * we have a message that is not compliant to any RFCs, thus * we assume it is a "raw" message. */ static int srSLMGParseTAG(srSLMGObj* pThis, unsigned char** ppszBuf) { unsigned char *pBuf; unsigned char *pInBuf; int i; srSLMGCHECKVALIDOBJECT(pThis); assert(ppszBuf != NULL); assert((*ppszBuf >= pThis->pszRawMsg)); pInBuf = *ppszBuf; if((pBuf = malloc(33 * sizeof(unsigned char))) == NULL) return FALSE; /* we have no way to indicated this (unlikely) error - so this is better than nothing.. */ i = 0; while(**ppszBuf && **ppszBuf != ':' && i < 32) { *(pBuf+i) = **ppszBuf; ++i; ++(*ppszBuf); } if(**ppszBuf == ':') { /* ok, looks like a syslog-sign tag */ if(i >= 32) { /* oops... */ free(pBuf); return FALSE; } *(pBuf+i++) = ':'; *(pBuf+i) = '\0'; ++(*ppszBuf); /* eat it, the colon is not part of the message under -sign */ pThis->pszTag = pBuf; return TRUE; } /* control reaches this point if the tag was no good and we * need to retry. */ *ppszBuf = pInBuf; i = 0; while(**ppszBuf && isalnum(**ppszBuf) && i < 32) { *(pBuf+i) = **ppszBuf; ++i; ++(*ppszBuf); } if(isalnum(**ppszBuf)) { /* oversize tag --> invalid! */ free(pBuf); return FALSE; } *(pBuf+i) = '\0'; pThis->pszTag = pBuf; return TRUE; } /** * Copy the MSG to its own buffer. * * In the future, we may add coockie processing e.g. for -sign, -interntional * here. */ static srRetVal srSLMGProcessMSG(srSLMGObj* pThis, unsigned char** ppszBuf) { srRetVal iRet; sbStrBObj *pStr; srSLMGCHECKVALIDOBJECT(pThis); assert(ppszBuf != NULL); assert((*ppszBuf >= pThis->pszRawMsg)); if((pStr = sbStrBConstruct()) == NULL) return SR_RET_OUT_OF_MEMORY; /* we have no way to indicated this (unlikely) error - so this is better than nothing.. */ while(**ppszBuf) { if((iRet = sbStrBAppendChar(pStr, **ppszBuf)) != SR_RET_OK) return iRet; ++(*ppszBuf); } pThis->pszMsg = sbStrBFinish(pStr); return SR_RET_OK; } srRetVal srSLMGParseMesg(srSLMGObj *pThis) { srRetVal iRet; unsigned char* pszBuf; srSLMGCHECKVALIDOBJECT_API(pThis); /* This algo works as follows: It tries to parse each of the syslog * message. A parser is called for each part (e.g. PRI and TIMESTAMP). * The parser tries to find a suitable format for that part of the * message and - if it does - updates the syslog message's properties * and returns TRUE. If it does not find a match, it returns FALSE. * A failed parser does not necessarily mean the message is invalid - * we can always fall back to plain 3164. However, the caller for whom * the message is being parsed is advised to check which format we * found and eventually issue an error message (e.g. if we have a * syslog-sign message with a RFC 3164 message format - that does * not work (or does it...?). */ pszBuf = pThis->pszRawMsg; if(srSLMGParsePRI(pThis, &pszBuf) == FALSE) { pThis->iFormat = srSLMGFmt_3164RAW; return SR_RET_OK; } if(srSLMGParseTIMESTAMP(pThis, &pszBuf) == FALSE) { pThis->iFormat = srSLMGFmt_3164RAW; return SR_RET_OK; } if(srSLMGParseHOSTNAME(pThis, &pszBuf) == FALSE) { pThis->iFormat = srSLMGFmt_3164RAW; return SR_RET_OK; } if(srSLMGParseTAG(pThis, &pszBuf) == FALSE) { pThis->iFormat = srSLMGFmt_3164RAW; return SR_RET_OK; } /* OK, this must be wellformed format */ if(pThis->iTimStampType == srSLMG_TimStamp_3164) pThis->iFormat = srSLMGFmt_3164WELLFORMED; else pThis->iFormat = srSLMGFmt_SIGN_12; if((iRet = srSLMGProcessMSG(pThis, &pszBuf)) != SR_RET_OK) return iRet; return SR_RET_OK; } srRetVal srSLMGGetPriority(srSLMGObj *pThis, int *piPrio) { srSLMGCHECKVALIDOBJECT_API(pThis); if(piPrio == NULL) return SR_RET_NULL_POINTER_PROVIDED; *piPrio = pThis->iSeverity ; return SR_RET_OK; } srRetVal srSLMGGetFacility(srSLMGObj *pThis, int *piFac) { srSLMGCHECKVALIDOBJECT_API(pThis); if(piFac == NULL) return SR_RET_NULL_POINTER_PROVIDED; *piFac = pThis->iFacility; return SR_RET_OK; } srRetVal srSLMGGetRemoteHost(srSLMGObj *pThis, char**ppsz) { srSLMGCHECKVALIDOBJECT_API(pThis); if(ppsz== NULL) return SR_RET_NULL_POINTER_PROVIDED; *ppsz = pThis->pszRemoteHost; return SR_RET_OK; } srRetVal srSLMGGetHostname(srSLMGObj *pThis, char**ppsz) { srSLMGCHECKVALIDOBJECT_API(pThis); if(ppsz== NULL) return SR_RET_NULL_POINTER_PROVIDED; if(!((pThis->iFormat == srSLMGFmt_3164WELLFORMED) || (pThis->iFormat == srSLMGFmt_SIGN_12))) return SR_RET_PROPERTY_NOT_AVAILABLE; *ppsz = pThis->pszHostname; return SR_RET_OK; } srRetVal srSLMGGetTag(srSLMGObj *pThis, unsigned char**ppsz) { srSLMGCHECKVALIDOBJECT_API(pThis); if(ppsz== NULL) return SR_RET_NULL_POINTER_PROVIDED; if(!((pThis->iFormat == srSLMGFmt_3164WELLFORMED) || (pThis->iFormat == srSLMGFmt_SIGN_12))) return SR_RET_PROPERTY_NOT_AVAILABLE; *ppsz = pThis->pszTag; return SR_RET_OK; } srRetVal srSLMGGetMSG(srSLMGObj *pThis, unsigned char**ppsz) { srSLMGCHECKVALIDOBJECT_API(pThis); if(ppsz== NULL) return SR_RET_NULL_POINTER_PROVIDED; if(!((pThis->iFormat == srSLMGFmt_3164WELLFORMED) || (pThis->iFormat == srSLMGFmt_SIGN_12))) /* in this case, we have nothing but the raw message and thus we return it. * Well... 3164 says this is exactly what we should do, as in the absense * of a proper header the whole message is deemed to be MSG only. */ *ppsz = pThis->pszRawMsg; else *ppsz = pThis->pszMsg; return SR_RET_OK; } /** * Provide the caller back with the raw message. * * This is especially useful for syslog-sign, where the * raw message must be stored in order to keep the sig * intact! * * \note The returned string is read-only. It is valid * only until the srSLMGObj is destroyed. If the caller intends * to use it for a prolonged period of time, it needs to * copy it! * * \param ppsz Pointer to Pointer to unsigned char to * receive the return string. */ srRetVal srSLMGGetRawMSG(srSLMGObj *pThis, unsigned char**ppsz) { srSLMGCHECKVALIDOBJECT_API(pThis); if(ppsz== NULL) return SR_RET_NULL_POINTER_PROVIDED; *ppsz = pThis->pszRawMsg; return SR_RET_OK; } /** * Provide the caller back with the message timestamp. * * The timestamp is provided in separate fields. * * \param ppsz Pointer to Pointer to unsigned char to * receive the return string. */ srRetVal srSLMGGetTIMESTAMP(srSLMGObj *pThis, int *piYear, int *piMonth, int *piDay, int *piHour, int *piMinute, int *piSecond, int *piSecFrac, int *piSecFracPrecision, int *piOffsetHour, int *piOffsetMinute, char *pcOffsetMode, int *pbHasTZ) { srSLMGCHECKVALIDOBJECT_API(pThis); if(piYear == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piMonth == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piDay == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piHour == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piMinute == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piSecond == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piSecFrac == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piSecFracPrecision == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piOffsetHour == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(piOffsetMinute == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(pbHasTZ == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(pcOffsetMode == NULL) return SR_RET_NULL_POINTER_PROVIDED; if(!((pThis->iFormat == srSLMGFmt_3164WELLFORMED) || (pThis->iFormat == srSLMGFmt_SIGN_12))) return SR_RET_PROPERTY_NOT_AVAILABLE; *piYear = pThis->iTimStampYear; *piMonth = pThis->iTimStampMonth; *piDay = pThis->iTimStampDay; *piHour = pThis->iTimStampHour; *piMinute = pThis->iTimStampMinute; *piSecond = pThis->iTimStampSecond; *piSecFrac = pThis->iTimStampSecFrac; *piSecFracPrecision = pThis->iTimStampSecFracPrecision; *piOffsetHour = pThis->iTimStampOffsetHour; *piOffsetMinute = pThis->iTimStampOffsetMinute; *pbHasTZ = pThis->bTimStampIncludesTZ; *pcOffsetMode = pThis->cTimStampOffsetMode; return SR_RET_OK; } srRetVal srSLMGSetRemoteHostIP(srSLMGObj *pThis, char *pszRemHostIP, int bCopyRemHost) { srSLMGCHECKVALIDOBJECT_API(pThis); if(pThis->pszRemoteHost != NULL) if(pThis->bOwnRemoteHostBuf == TRUE) free(pThis->pszRemoteHost); if(bCopyRemHost == TRUE) { if((pThis->pszRemoteHost = sbNVTEUtilStrDup(pszRemHostIP)) == NULL) return SR_RET_OUT_OF_MEMORY; } else pThis->pszRemoteHost = pszRemHostIP; pThis->bOwnRemoteHostBuf = bCopyRemHost; return SR_RET_OK; } srRetVal srSLMGSetRawMsg(srSLMGObj *pThis, char *pszRawMsg, int bCopyRawMsg) { srSLMGCHECKVALIDOBJECT_API(pThis); if(pThis->pszRawMsg != NULL) if(pThis->bOwnRawMsgBuf == TRUE) free(pThis->pszRawMsg); if(bCopyRawMsg == TRUE) { if((pThis->pszRawMsg = sbNVTEUtilStrDup(pszRawMsg)) == NULL) return SR_RET_OUT_OF_MEMORY; } else pThis->pszRawMsg = pszRawMsg; pThis->bOwnRawMsgBuf = bCopyRawMsg; return SR_RET_OK; } srRetVal srSLMGSetMSG(srSLMGObj *pThis, char *pszMSG, int bCopyMSG) { srSLMGCHECKVALIDOBJECT_API(pThis); if(pThis->pszMsg != NULL) if(pThis->bOwnMsg == TRUE) free(pThis->pszMsg); if(bCopyMSG == TRUE) { if((pThis->pszMsg = sbNVTEUtilStrDup(pszMSG)) == NULL) return SR_RET_OUT_OF_MEMORY; } else pThis->pszMsg = pszMSG; pThis->bOwnMsg = bCopyMSG; return SR_RET_OK; } srRetVal srSLMGSetTIMESTAMPtoCurrent(srSLMGObj *pThis) { srRetVal iRet; srSLMGCHECKVALIDOBJECT_API(pThis); iRet = getCurrTime(&pThis->iTimStampYear, &pThis->iTimStampMonth, &pThis->iTimStampDay, &pThis->iTimStampHour, &pThis->iTimStampMinute, &pThis->iTimStampSecond, &pThis->iTimStampSecFrac, &pThis->iTimStampSecFracPrecision, &pThis->cTimStampOffsetMode, &pThis->iTimStampOffsetHour, &pThis->iTimStampOffsetMinute); return iRet; } /** * Set the HOSTNAME to the current hostname. */ srRetVal srSLMGSetHOSTNAMEtoCurrent(srSLMGObj* pThis) { srSLMGCHECKVALIDOBJECT_API(pThis); return sbSock_gethostname((char**) (&(pThis->pszHostname))); } /* The following table is a helper to srSLMGFormatRawMsg: */ static char* srSLMGMonthNames[13] = {"ERR", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; srRetVal srSLMGFormatRawMsg(srSLMGObj *pThis, srSLMGFormat iFmtToUse) { srRetVal iRet; sbStrBObj *pStr; char szBuf[128]; int i; srSLMGCHECKVALIDOBJECT_API(pThis); if((iFmtToUse != srSLMGFmt_3164WELLFORMED) && (iFmtToUse != srSLMGFmt_SIGN_12)) return SR_RET_UNSUPPORTED_FORMAT; if(pThis->pszRawMsg != NULL) if(pThis->bOwnRawMsgBuf == FALSE) return SR_RET_UNALLOCATABLE_BUFFER; else { free(pThis->pszRawMsg); pThis->pszRawMsg = NULL; } if((pStr = sbStrBConstruct()) == NULL) return SR_RET_OUT_OF_MEMORY; /* PRI */ i = (pThis->iFacility << 3) + pThis->iSeverity; SNPRINTF(szBuf, sizeof(szBuf), "<%d>", i); if((iRet = sbStrBAppendStr(pStr, szBuf)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; } /* TIMESTAMP * Please note: all SNPRINTFs allow 34 Bytes, because of * a) the '\0' byte * b) the extra space at the end of the TIMESTAMP * So the TIMESTAMP itself will by 32 bytes at most. */ if(pThis->pszTimeStamp != NULL) free(pThis->pszTimeStamp); if((pThis->pszTimeStamp = calloc(34, sizeof(char))) == NULL) return SR_RET_OUT_OF_MEMORY; if(iFmtToUse == srSLMGFmt_3164WELLFORMED) { SNPRINTF(pThis->pszTimeStamp, 34, "%s %2d %2.2d:%2.2d:%2.2d ", srSLMGMonthNames[pThis->iTimStampMonth], pThis->iTimStampDay, pThis->iTimStampHour, pThis->iTimStampMinute, pThis->iTimStampSecond); } else { /* SIGN_12! */ if(pThis->iTimStampSecFracPrecision > 0) { /* we now need to include fractional seconds. While doing so, we must look at * the precision specified. For example, if we have millisec precision (3 digits), a * secFrac value of 12 is not equivalent to ".12" but ".012". Obviously, this * is a huge difference ;). To avoid this, we first create a format string with * the specific precision and *then* use that format string to do the actual * formating (mmmmhhh... kind of self-modifying code... ;)). */ char szFmtStr[64]; /* be careful: there is ONE actual %d in the format string below ;) */ SNPRINTF(szFmtStr, sizeof(szFmtStr), "%%04d-%%02d-%%02dT%%02d:%%02d:%%02d.%%0%dd%%c%%02d:%%02d ", pThis->iTimStampSecFracPrecision); SNPRINTF(pThis->pszTimeStamp, 34, szFmtStr, pThis->iTimStampYear, pThis->iTimStampMonth, pThis->iTimStampDay, pThis->iTimStampHour, pThis->iTimStampMinute, pThis->iTimStampSecond, pThis->iTimStampSecFrac, pThis->cTimStampOffsetMode, pThis->iTimStampOffsetHour, pThis->iTimStampOffsetMinute); } else SNPRINTF(pThis->pszTimeStamp, 34, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d%c%2.2d:%2.2d ", pThis->iTimStampYear, pThis->iTimStampMonth, pThis->iTimStampDay, pThis->iTimStampHour, pThis->iTimStampMinute, pThis->iTimStampSecond, pThis->cTimStampOffsetMode, pThis->iTimStampOffsetHour, pThis->iTimStampOffsetMinute); } /* timestamp done, add it... */ if((iRet = sbStrBAppendStr(pStr, pThis->pszTimeStamp)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; } /* HOSTNAME */ if((iRet = sbStrBAppendStr(pStr, pThis->pszHostname)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; } if((iRet = sbStrBAppendChar(pStr, ' ')) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; } /* TAG */ if((iRet = sbStrBAppendStr(pStr, pThis->pszTag)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; } if(*(pThis->pszTag + strlen(pThis->pszTag) - 1) != ':') if((iFmtToUse == srSLMGFmt_SIGN_12) || isalnum(*(pThis->pszTag + strlen(pThis->pszTag) - 1))) { /* -sign MUST be terminated by a colon, in 3164 it is not allowed to be terminated by alnum */ if((iRet = sbStrBAppendChar(pStr, ':')) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; } } /* MSG */ if((iRet = sbStrBAppendStr(pStr, pThis->pszMsg)) != SR_RET_OK) { sbStrBDestruct(pStr); return iRet; } /* done, let's store the new string */ pThis->pszRawMsg = sbStrBFinish(pStr); pThis->bOwnRawMsgBuf = TRUE; return SR_RET_OK; } srRetVal srSLMGSetFacility(srSLMGObj* pThis, int iNewVal) { srSLMGCHECKVALIDOBJECT_API(pThis); if(iNewVal < 0 || iNewVal > 23) return SR_RET_FACIL_OUT_OF_RANGE; pThis->iFacility = iNewVal; return SR_RET_OK; } srRetVal srSLMGSetSeverity(srSLMGObj* pThis, int iNewVal) { srSLMGCHECKVALIDOBJECT_API(pThis); if(iNewVal < 0 || iNewVal > 7) return SR_RET_PRIO_OUT_OF_RANGE; pThis->iSeverity = iNewVal; return SR_RET_OK; } srRetVal srSLMGSetTAG(srSLMGObj* pThis, char* pszNewTag) { srRetVal iRet; sbStrBObj *pStr; int i; srSLMGCHECKVALIDOBJECT_API(pThis); if(pszNewTag == NULL) return SR_RET_NULL_POINTER_PROVIDED; if((pStr = sbStrBConstruct()) == NULL) return SR_RET_OUT_OF_MEMORY; sbStrBSetAllocIncrement(pStr, 16); /* copy tag value & check validity * (we assume all chars except ':' and SP to be valid) */ for(i = 0 ; *(pszNewTag+i) && i < 32 ; ++i) if((*(pszNewTag+i) == ':') || (*(pszNewTag+i) == ' ')) return SR_RET_INVALID_TAG; else if((iRet = sbStrBAppendChar(pStr, *(pszNewTag+i))) != SR_RET_OK) return iRet; if(*(pszNewTag+i) != '\0') /* more than 32 chars */ return SR_RET_INVALID_TAG; /* done, set property */ if(pThis->pszTag != NULL) free(pThis->pszTag); if((pThis->pszTag = sbStrBFinish(pStr)) == NULL) return SR_RET_OUT_OF_MEMORY; return SR_RET_OK; } #endif /* #if FEATURE_MSGAPI == 1 */