diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2008-04-04 16:57:25 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2008-04-04 16:57:25 +0000 |
commit | 0d5d42c52228964d76996c0e58fdf69258436716 (patch) | |
tree | 0505b84f979f9e369eebce188046fd6c7ed5902c | |
parent | ee629c4f742ac904c4a5055e85ef86d6decfb344 (diff) | |
download | rsyslog-0d5d42c52228964d76996c0e58fdf69258436716.tar.gz rsyslog-0d5d42c52228964d76996c0e58fdf69258436716.tar.xz rsyslog-0d5d42c52228964d76996c0e58fdf69258436716.zip |
an initial, somewhat working, tester for the mail functionality
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | plugins/ommail/ommail.c | 215 | ||||
-rw-r--r-- | rsyslog.h | 1 |
3 files changed, 232 insertions, 4 deletions
@@ -44,12 +44,30 @@ Version 3.15.0 (rgerhards), 2008-04-01 only installed if corresponding option is selected. Thanks to Michael Biebl for pointing these problems out. --------------------------------------------------------------------------- -Version 3.14.0 (rgerhards), 2008-04-02 +Version 3.14.1 (rgerhards), 2008-04-04 +- bugfix: some messages were emited without hostname - bugfix: rsyslogd was no longer build by default; man pages are only installed if corresponding option is selected. Thanks to Michael Biebl for pointing these problems out. +- bugfix: zero-length strings were not supported in object + deserializer - disabled atomic operations for this stable build as it caused platform problems +- bugfix: memory leaks in script engine +- bugfix: $hostname and $fromhost in RainerScript did not work +- bugfix: some memory leak when queue is runing in disk mode +- man pages improved thanks to varmofekoj and Peter Vrabec +- We have removed the 32 character size limit (from RFC3164) on the + tag. This had bad effects on existing envrionments, as sysklogd didn't + obey it either (probably another bug in RFC3164...). We now receive + the full size, but will modify the outputs so that only 32 characters + max are used by default. If you need large tags in the output, you need + to provide custom templates. +--------------------------------------------------------------------------- +Version 3.14.0 (rgerhards), 2008-04-02 +An interim version was accidently released to the web. It was named 3.14.0. +To avoid confusion, we have not assigned this version number to any +official release. If you happen to use 3.14.0, please update to 3.14.1. --------------------------------------------------------------------------- Version 3.13.0-dev0 (rgerhards), 2008-03-31 - bugfix: accidently set debug option in 3.12.5 reset to production diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c index 57de7fc0..4da4f58c 100644 --- a/plugins/ommail/ommail.c +++ b/plugins/ommail/ommail.c @@ -33,9 +33,10 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include <unistd.h> #include <errno.h> -#include <ctype.h> -#include <librelp.h> +#include <netdb.h> +#include <sys/socket.h> #include "syslogd.h" #include "syslogd-types.h" #include "srUtils.h" @@ -63,6 +64,9 @@ typedef struct _instanceData { uchar *pszFrom; uchar *pszTo; uchar *pszSubject; + char RcvBuf[1024]; /* buffer for receiving server responses */ + size_t lenRcvBuf; + size_t iRcvBuf; /* current index into the rcvBuf (buf empty if iRcvBuf == lenRcvBuf) */ int sock; /* socket to this server (most important when we do multiple msgs per mail) */ } smtp; } md; /* mode-specific data */ @@ -104,6 +108,197 @@ CODESTARTdbgPrintInstInfo ENDdbgPrintInstInfo +/* TCP support code, should probably be moved to net.c or some place else... -- rgerhards, 2008-04-04 */ + +/* "receive" a character from the remote server. A single character + * is returned. Returns RS_RET_NO_MORE_DATA if the server has closed + * the connection and RS_RET_IO_ERROR if something goes wrong. This + * is a blocking read. + * rgerhards, 2008-04-04 + */ +static rsRetVal +getRcvChar(instanceData *pData, char *pC) +{ + DEFiRet; + ssize_t lenBuf; + assert(pData != NULL); + + if(pData->md.smtp.iRcvBuf == pData->md.smtp.lenRcvBuf) { /* buffer empty? */ + /* yes, we need to read the next server response */ + do { + lenBuf = recv(pData->md.smtp.sock, pData->md.smtp.RcvBuf, sizeof(pData->md.smtp.RcvBuf), 0); + if(lenBuf == 0) { + ABORT_FINALIZE(RS_RET_NO_MORE_DATA); + } else if(lenBuf < 0) { + if(errno != EAGAIN) { + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + } else { + /* good read */ + pData->md.smtp.iRcvBuf = 0; + pData->md.smtp.lenRcvBuf = lenBuf; + } + + } while(lenBuf < 1); + } + + /* when we reach this point, we have a non-empty buffer */ + *pC = pData->md.smtp.RcvBuf[pData->md.smtp.iRcvBuf++]; + +finalize_it: + RETiRet; +} + + +#if 0 +/* Initialize TCP socket (for sender), new socket is returned in + * pSock if all goes well. + */ +static rsRetVal +CreateSocket(struct addrinfo *addrDest, int *pSock) +{ + DEFiRet; + int fd; + struct addrinfo *r; + char errStr[1024]; + + r = addrDest; + + while(r != NULL) { + fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); + if(fd != -1) { + if(connect(fd, r->ai_addr, r->ai_addrlen) != 0) { + dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + } else { + *pSock = fd; + FINALIZE; + } + close(fd); + } else { + dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + } + r = r->ai_next; + } + + dbgprintf("no working socket could be obtained"); + iRet = RS_RET_NO_SOCKET; + +finalize_it: + RETiRet; +} +#endif + + +/* open a connection to the mail server + * rgerhards, 2008-04-04 + */ +static rsRetVal +serverConnect(instanceData *pData) +{ + struct addrinfo *res = NULL; + struct addrinfo hints; + char errStr[1024]; + + DEFiRet; + assert(pData != NULL); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* TODO: make configurable! */ + hints.ai_socktype = SOCK_STREAM; + if(getaddrinfo((char*)pData->md.smtp.pszSrv, (char*)pData->md.smtp.pszSrvPort, &hints, &res) != 0) { + dbgprintf("error %d in getaddrinfo\n", errno); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + + if((pData->md.smtp.sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { + dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + + if(connect(pData->md.smtp.sock, res->ai_addr, res->ai_addrlen) != 0) { + dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + +finalize_it: + if(res != NULL) + freeaddrinfo(res); + + if(iRet != RS_RET_OK) { + if(pData->md.smtp.sock != -1) { + close(pData->md.smtp.sock); + pData->md.smtp.sock = -1; + } + } + + RETiRet; +} + + + +/* send text to the server, blocking send */ +static rsRetVal +Send(int sock, char *msg, size_t len) +{ + DEFiRet; + size_t offsBuf = 0; + ssize_t lenSend; + + assert(msg != NULL); + + if(len == 0) /* it's valid, but does not make much sense ;) */ + FINALIZE; + + do { + lenSend = send(sock, msg + offsBuf, len - offsBuf, 0); + dbgprintf("TCP sent %ld bytes, requested %ld\n", (long) lenSend, (long) len); + + if(lenSend == -1) { + if(errno != EAGAIN) { + dbgprintf("message not (tcp)send, errno %d", errno); + ABORT_FINALIZE(RS_RET_TCP_SEND_ERROR); + } + } else if(lenSend != (ssize_t) len) { + offsBuf += len; /* on to next round... */ + } else { + FINALIZE; + } + } while(1); + +finalize_it: + RETiRet; +} + + +/* send a message via SMTP + * TODO: care about the result codes, we can't do it that blindly ;) + * rgerhards, 2008-04-04 + */ +static rsRetVal +sendSMTP(instanceData *pData, uchar *body) +{ + DEFiRet; + + assert(pData != NULL); + + CHKiRet(serverConnect(pData)); + CHKiRet(Send(pData->md.smtp.sock, "HELO\r\n", 6)); + CHKiRet(Send(pData->md.smtp.sock, "MAIL FROM: <rgerhards@adiscon.com>\r\n", sizeof("MAIL FROM: <rgerhards@adiscon.com>\r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, "RCPT TO: <rgerhards@adiscon.com>\r\n", sizeof("RCPT TO: <rgerhards@adiscon.com>\r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, "DATA\r\n", sizeof("DATA\r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, body, strlen((char*) body))); + CHKiRet(Send(pData->md.smtp.sock, "\r\n.\r\n", sizeof("\r\n.\r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, "QUIT\r\n", sizeof("QUIT\r\n") - 1)); + + close(pData->md.smtp.sock); + pData->md.smtp.sock = -1; + +finalize_it: + RETiRet; +} + + + /* connect to server * rgerhards, 2008-04-04 */ @@ -111,6 +306,10 @@ static rsRetVal doConnect(instanceData *pData) { DEFiRet; + iRet = serverConnect(pData); + if(iRet == RS_RET_IO_ERROR) + iRet = RS_RET_SUSPENDED; + RETiRet; } @@ -131,7 +330,7 @@ CODESTARTdoAction /* forward */ iRet = sendSMTP(pData, ppString[0]); - if(iRet != RELP_RET_OK) { + if(iRet != RS_RET_OK) { /* error! */ dbgprintf("error sending mail, suspending\n"); iRet = RS_RET_SUSPENDED; @@ -154,6 +353,16 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) if((iRet = createInstance(&pData)) != RS_RET_OK) FINALIZE; + //pData->md.smtp.pszSrv = "172.19.2.10"; + pData->md.smtp.pszSrv = "172.19.0.6"; + pData->md.smtp.pszSrvPort = "25"; + pData->md.smtp.pszFrom = "rgerhards@adiscon.com"; + pData->md.smtp.pszTo = "rgerhards@adiscon.com"; + pData->md.smtp.pszSubject = "rsyslog test message"; + + /* process template */ + CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_TraditionalForwardFormat")); + /* TODO: do we need to call freeInstance if we failed - this is a general question for * all output modules. I'll address it later as the interface evolves. rgerhards, 2007-07-25 */ @@ -167,6 +167,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_MODULE_LOAD_ERR_DLOPEN = -2066, /**< module could not be loaded - problem in dlopen() */ RS_RET_MODULE_LOAD_ERR_NO_INIT = -2067, /**< module could not be loaded - init() missing */ RS_RET_MODULE_LOAD_ERR_INIT_FAILED = -2068, /**< module could not be loaded - init() failed */ + RS_RET_NO_SOCKET = -2069, /**< socket could not be obtained or was not provided */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ |