diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Makefile.am | 34 | ||||
-rw-r--r-- | runtime/debug.c | 2 | ||||
-rw-r--r-- | runtime/glbl.c | 70 | ||||
-rw-r--r-- | runtime/glbl.h | 3 | ||||
-rw-r--r-- | runtime/modules.c | 13 | ||||
-rw-r--r-- | runtime/netstrm.c | 62 | ||||
-rw-r--r-- | runtime/netstrm.h | 13 | ||||
-rw-r--r-- | runtime/netstrms.c | 101 | ||||
-rw-r--r-- | runtime/netstrms.h | 7 | ||||
-rw-r--r-- | runtime/nsd.h | 1 | ||||
-rw-r--r-- | runtime/nsd_gtls.c | 190 | ||||
-rw-r--r-- | runtime/nsd_gtls.h | 10 | ||||
-rw-r--r-- | runtime/nsd_ptcp.c | 28 | ||||
-rw-r--r-- | runtime/nsdsel_gtls.c | 107 | ||||
-rw-r--r-- | runtime/nsdsel_gtls.h | 3 | ||||
-rw-r--r-- | runtime/nsdsel_ptcp.c | 30 | ||||
-rw-r--r-- | runtime/nsdsel_ptcp.h | 3 | ||||
-rw-r--r-- | runtime/nssel.c | 66 | ||||
-rw-r--r-- | runtime/nssel.h | 7 | ||||
-rw-r--r-- | runtime/obj.c | 6 | ||||
-rw-r--r-- | runtime/rsyslog.h | 3 |
21 files changed, 550 insertions, 209 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am index dcb475d8..a7a2b91e 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -81,7 +81,7 @@ lmregexp_la_LIBADD = endif if ENABLE_INET -pkglib_LTLIBRARIES += lmnet.la lmnetstrms.la lmnetstrm.la lmnssel.la +pkglib_LTLIBRARIES += lmnet.la lmnetstrms.la # # network support # @@ -91,38 +91,19 @@ lmnet_la_LDFLAGS = -module -avoid-version lmnet_la_LIBADD = # network stream master class and stream factory -lmnetstrms_la_SOURCES = netstrms.c netstrms.h +lmnetstrms_la_SOURCES = netstrms.c netstrms.h netstrm.c netstrm.h nssel.c nssel.h lmnetstrms_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) lmnetstrms_la_LDFLAGS = -module -avoid-version lmnetstrms_la_LIBADD = -# individual network streams -lmnetstrm_la_SOURCES = netstrm.c netstrm.h -lmnetstrm_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) -lmnetstrm_la_LDFLAGS = -module -avoid-version -lmnetstrm_la_LIBADD = - -# network stream select support (a helper class) -lmnssel_la_SOURCES = nssel.c nssel.h -lmnssel_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) -lmnssel_la_LDFLAGS = -module -avoid-version -lmnssel_la_LIBADD = - # netstream drivers # plain tcp driver - main driver pkglib_LTLIBRARIES += lmnsd_ptcp.la -lmnsd_ptcp_la_SOURCES = nsd_ptcp.c nsd_ptcp.h +lmnsd_ptcp_la_SOURCES = nsd_ptcp.c nsd_ptcp.h nsdsel_ptcp.c nsdsel_ptcp.h lmnsd_ptcp_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) lmnsd_ptcp_la_LDFLAGS = -module -avoid-version lmnsd_ptcp_la_LIBADD = - -# select interface for ptcp driver -pkglib_LTLIBRARIES += lmnsdsel_ptcp.la -lmnsdsel_ptcp_la_SOURCES = nsdsel_ptcp.c nsdsel_ptcp.h -lmnsdsel_ptcp_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) -lmnsdsel_ptcp_la_LDFLAGS = -module -avoid-version -lmnsdsel_ptcp_la_LIBADD = endif # if ENABLE_INET # @@ -130,16 +111,9 @@ endif # if ENABLE_INET # if ENABLE_GNUTLS pkglib_LTLIBRARIES += lmnsd_gtls.la -lmnsd_gtls_la_SOURCES = nsd_gtls.c nsd_gtls.h +lmnsd_gtls_la_SOURCES = nsd_gtls.c nsd_gtls.h nsdsel_gtls.c nsdsel_gtls.h lmnsd_gtls_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) $(gnutls_cflags) lmnsd_gtls_la_LDFLAGS = -module -avoid-version lmnsd_gtls_la_LIBADD = $(gnutls_libs) -# -# select interface for gtls driver -pkglib_LTLIBRARIES += lmnsdsel_gtls.la -lmnsdsel_gtls_la_SOURCES = nsdsel_gtls.c nsdsel_gtls.h -lmnsdsel_gtls_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) -lmnsdsel_gtls_la_LDFLAGS = -module -avoid-version -lmnsdsel_gtls_la_LIBADD = endif diff --git a/runtime/debug.c b/runtime/debug.c index 53624e38..f543efd8 100644 --- a/runtime/debug.c +++ b/runtime/debug.c @@ -1145,8 +1145,6 @@ dbgPrintNameAdd(uchar *pName, dbgPrintName_t **ppRoot) pEntry->pNext = *ppRoot; /* we enqueue at the front */ } *ppRoot = pEntry; - -printf("Name %s added to %p\n", pName, *ppRoot); } diff --git a/runtime/glbl.c b/runtime/glbl.c index 787b6ab7..20840318 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -40,9 +40,16 @@ /* some defaults */ #ifndef DFLT_NETSTRM_DRVR -// TESTING ONLY# define DFLT_NETSTRM_DRVR ((uchar*)"lmnsd_ptcp") -#warning "define must be restored for non-testing!" -# define DFLT_NETSTRM_DRVR ((uchar*)"lmnsd_gtls") +# define DFLT_NETSTRM_DRVR ((uchar*)"ptcp") +#endif +#ifndef DFLT_NETSTRM_DRVR_CAF +# define DFLT_NETSTRM_DRVR_CAF ((uchar*)"ca.pem") +#endif +#ifndef DFLT_NETSTRM_DRVR_KEYFILE +# define DFLT_NETSTRM_DRVR_KEYFILE ((uchar*)"key.pem") +#endif +#ifndef DFLT_NETSTRM_DRVR_CERTFILE +# define DFLT_NETSTRM_DRVR_CERTFILE ((uchar*)"cert.pem") #endif /* static data */ @@ -62,6 +69,9 @@ static uchar *LocalDomain; /* our local domain name - read-only after startup * static char **StripDomains = NULL;/* these domains may be stripped before writing logs - r/o after s.u., never touched by init */ static char **LocalHosts = NULL;/* these hosts are logged with their hostname - read-only after startup, never touched by init */ static uchar *pszDfltNetstrmDrvr = NULL; /* module name of default netstream driver */ +static uchar *pszDfltNetstrmDrvrCAF = NULL; /* default CA file for the netstrm driver */ +static uchar *pszDfltNetstrmDrvrKeyFile = NULL; /* default key file for the netstrm driver (server) */ +static uchar *pszDfltNetstrmDrvrCertFile = NULL; /* default cert file for the netstrm driver (server) */ /* define a macro for the simple properties' set and get functions @@ -93,6 +103,9 @@ SIMP_PROP(LocalHosts, LocalHosts, char**) SIMP_PROP_SET(LocalHostName, LocalHostName, uchar*) SIMP_PROP_SET(DfltNetstrmDrvr, pszDfltNetstrmDrvr, uchar*) // TODO: use custom function which frees existing value +SIMP_PROP_SET(DfltNetstrmDrvrCAF, pszDfltNetstrmDrvrCAF, uchar*) // TODO: use custom function which frees existing value +SIMP_PROP_SET(DfltNetstrmDrvrKeyFile, pszDfltNetstrmDrvrKeyFile, uchar*) // TODO: use custom function which frees existing value +SIMP_PROP_SET(DfltNetstrmDrvrCertFile, pszDfltNetstrmDrvrCertFile, uchar*) // TODO: use custom function which frees existing value #undef SIMP_PROP #undef SIMP_PROP_SET @@ -120,7 +133,31 @@ GetWorkDir(void) static uchar* GetDfltNetstrmDrvr(void) { - return(pszDfltNetstrmDrvr == NULL ? DFLT_NETSTRM_DRVR : pszWorkDir); + return(pszDfltNetstrmDrvr == NULL ? DFLT_NETSTRM_DRVR : pszDfltNetstrmDrvr); +} + + +/* return the current default netstream driver CA File */ +static uchar* +GetDfltNetstrmDrvrCAF(void) +{ + return(pszDfltNetstrmDrvrCAF == NULL ? DFLT_NETSTRM_DRVR_CAF : pszDfltNetstrmDrvrCAF); +} + + +/* return the current default netstream driver key File */ +static uchar* +GetDfltNetstrmDrvrKeyFile(void) +{ + return(pszDfltNetstrmDrvrKeyFile == NULL ? DFLT_NETSTRM_DRVR_KEYFILE : pszDfltNetstrmDrvrKeyFile); +} + + +/* return the current default netstream driver certificate File */ +static uchar* +GetDfltNetstrmDrvrCertFile(void) +{ + return(pszDfltNetstrmDrvrCertFile == NULL ? DFLT_NETSTRM_DRVR_CERTFILE : pszDfltNetstrmDrvrCertFile); } @@ -151,6 +188,9 @@ CODESTARTobjQueryInterface(glbl) SIMP_PROP(StripDomains) SIMP_PROP(LocalHosts) SIMP_PROP(DfltNetstrmDrvr) + SIMP_PROP(DfltNetstrmDrvrCAF) + SIMP_PROP(DfltNetstrmDrvrKeyFile) + SIMP_PROP(DfltNetstrmDrvrCertFile) #undef SIMP_PROP finalize_it: ENDobjQueryInterface(glbl) @@ -165,6 +205,18 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a free(pszDfltNetstrmDrvr); pszDfltNetstrmDrvr = NULL; } + if(pszDfltNetstrmDrvrCAF != NULL) { + free(pszDfltNetstrmDrvrCAF); + pszDfltNetstrmDrvrCAF = NULL; + } + if(pszDfltNetstrmDrvrKeyFile != NULL) { + free(pszDfltNetstrmDrvrKeyFile); + pszDfltNetstrmDrvrKeyFile = NULL; + } + if(pszDfltNetstrmDrvrCertFile != NULL) { + free(pszDfltNetstrmDrvrCertFile); + pszDfltNetstrmDrvrCertFile = NULL; + } if(pszWorkDir != NULL) { free(pszWorkDir); pszWorkDir = NULL; @@ -185,6 +237,10 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* register config handlers (TODO: we need to implement a way to unregister them) */ CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, NULL, &pszWorkDir, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, NULL, &bDropMalPTRMsgs, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvr, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL)); ENDObjClassInit(glbl) @@ -195,6 +251,12 @@ ENDObjClassInit(glbl) BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */ if(pszDfltNetstrmDrvr != NULL) free(pszDfltNetstrmDrvr); + if(pszDfltNetstrmDrvrCAF != NULL) + free(pszDfltNetstrmDrvrCAF); + if(pszDfltNetstrmDrvrKeyFile != NULL) + free(pszDfltNetstrmDrvrKeyFile); + if(pszDfltNetstrmDrvrCertFile != NULL) + free(pszDfltNetstrmDrvrCertFile); if(pszWorkDir != NULL) free(pszWorkDir); if(LocalHostName != NULL) diff --git a/runtime/glbl.h b/runtime/glbl.h index b6864f3d..adfae27e 100644 --- a/runtime/glbl.h +++ b/runtime/glbl.h @@ -49,6 +49,9 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */ SIMP_PROP(StripDomains, char**) SIMP_PROP(LocalHosts, char**) SIMP_PROP(DfltNetstrmDrvr, uchar*) + SIMP_PROP(DfltNetstrmDrvrCAF, uchar*) + SIMP_PROP(DfltNetstrmDrvrKeyFile, uchar*) + SIMP_PROP(DfltNetstrmDrvrCertFile, uchar*) #undef SIMP_PROP ENDinterface(glbl) #define glblCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ diff --git a/runtime/modules.c b/runtime/modules.c index c156fef2..1e59a5fc 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -522,11 +522,16 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) if(modLinkTypesToUnload == eMOD_LINK_ALL || pModCurr->eLinkType == modLinkTypesToUnload) { if(modUnlinkAndDestroy(&pModCurr) == RS_RET_MODULE_STILL_REFERENCED) { pModCurr = GetNxt(pModCurr); + } else { + /* Note: if the module was successfully unloaded, it has updated the + * pModCurr pointer to the next module. However, the unload process may + * still have indirectly referenced the pointer list in a way that the + * unloaded module is not aware of. So we restart the unload process + * to make sure we do not fall into a trap (what we did ;)). The + * performance toll is minimal. -- rgerhards, 2008-04-28 + */ + pModCurr = GetNxt(NULL); } - /* Note: if the module was successfully unloaded, it has updated the - * pModCurr pointer to the next module. So we do NOT need to advance - * to the next module on successful unload. - */ } else { pModCurr = GetNxt(pModCurr); } diff --git a/runtime/netstrm.c b/runtime/netstrm.c index be754aae..a1384a28 100644 --- a/runtime/netstrm.c +++ b/runtime/netstrm.c @@ -46,12 +46,9 @@ #include "module-template.h" #include "obj.h" #include "errmsg.h" -//#include "nsd.h" #include "netstrms.h" #include "netstrm.h" -MODULE_TYPE_LIB - /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) @@ -119,6 +116,7 @@ AcceptConnReq(netstrm_t *pThis, netstrm_t **ppNew) /* accept the new connection */ CHKiRet(pThis->Drvr.AcceptConnReq(pThis->pDrvrData, &pNewNsd)); /* construct our object so that we can use it... */ + CHKiRet(objUse(netstrms, DONT_LOAD_LIB)); /* use netstrms obj if not already done so */ CHKiRet(netstrms.CreateStrm(pThis->pNS, ppNew)); (*ppNew)->pDrvrData = pNewNsd; @@ -175,6 +173,19 @@ Rcv(netstrm_t *pThis, uchar *pBuf, ssize_t *pLenBuf) } +/* set the driver mode + * rgerhards, 2008-04-28 + */ +static rsRetVal +SetDrvrMode(netstrm_t *pThis, int iMode) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, netstrm); + iRet = pThis->Drvr.SetMode(pThis->pDrvrData, iMode); + RETiRet; +} + + /* send a buffer. On entry, pLenBuf contains the number of octets to * write. On exit, it contains the number of octets actually written. * If this number is lower than on entry, only a partial buffer has @@ -228,6 +239,22 @@ Connect(netstrm_t *pThis, int family, uchar *port, uchar *host) } +/* Provide access to the underlying OS socket. This is dirty + * and scheduled to be removed. Does not work with all nsd drivers. + * See comment in netstrm interface for details. + * rgerhards, 2008-05-05 + */ +static rsRetVal +GetSock(netstrm_t *pThis, int *pSock) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, netstrm); + assert(pSock != NULL); + iRet = pThis->Drvr.GetSock(pThis->pDrvrData, pSock); + RETiRet; +} + + /* queryInterface function */ BEGINobjQueryInterface(netstrm) @@ -252,6 +279,8 @@ CODESTARTobjQueryInterface(netstrm) pIf->AcceptConnReq = AcceptConnReq; pIf->GetRemoteHName = GetRemoteHName; pIf->GetRemoteIP = GetRemoteIP; + pIf->SetDrvrMode = SetDrvrMode; + pIf->GetSock = GetSock; finalize_it: ENDobjQueryInterface(netstrm) @@ -262,7 +291,7 @@ BEGINObjClassExit(netstrm, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END M CODESTARTObjClassExit(netstrm) /* release objects we no longer need */ objRelease(errmsg, CORE_COMPONENT); - objRelease(netstrms, LM_NETSTRMS_FILENAME); + objRelease(netstrms, DONT_LOAD_LIB); ENDObjClassExit(netstrm) @@ -273,33 +302,8 @@ ENDObjClassExit(netstrm) BEGINAbstractObjClassInit(netstrm, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(netstrms, LM_NETSTRMS_FILENAME)); /* set our own handlers */ ENDObjClassInit(netstrm) - - -/* --------------- here now comes the plumbing that makes as a library module --------------- */ - - -BEGINmodExit -CODESTARTmodExit - netstrmClassExit(); -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_LIB_QUERIES -ENDqueryEtryPt - - -BEGINmodInit() -CODESTARTmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ - - /* Initialize all classes that are in our module - this includes ourselfs */ - CHKiRet(netstrmClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ -ENDmodInit /* vi:set ai: */ diff --git a/runtime/netstrm.h b/runtime/netstrm.h index 160bbb0b..a15c1d9b 100644 --- a/runtime/netstrm.h +++ b/runtime/netstrm.h @@ -24,7 +24,7 @@ #ifndef INCLUDED_NETSTRM_H #define INCLUDED_NETSTRM_H -#include "nsd.h" /* we need our driver interface to be defined */ +#include "netstrms.h" /* the netstrm object */ struct netstrm_s { @@ -49,6 +49,15 @@ BEGINinterface(netstrm) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Connect)(netstrm_t *pThis, int family, unsigned char *port, unsigned char *host); rsRetVal (*GetRemoteHName)(netstrm_t *pThis, uchar **pszName); rsRetVal (*GetRemoteIP)(netstrm_t *pThis, uchar **pszIP); + rsRetVal (*SetDrvrMode)(netstrm_t *pThis, int iMode); + /* the GetSock() below is a hack to make imgssapi work. In the long term, + * we should migrate imgssapi to a stream driver, which will relieve us of + * this problem. Please note that nobody else should use GetSock(). Using it + * will also tie the caller to nsd_ptcp, because other drivers may not support + * it at all. Once the imgssapi problem is solved, GetSock should be removed from + * this interface. -- rgerhards, 2008-05-05 + */ + rsRetVal (*GetSock)(netstrm_t *pThis, int *pSock); ENDinterface(netstrm) #define netstrmCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ @@ -56,6 +65,6 @@ ENDinterface(netstrm) PROTOTYPEObj(netstrm); /* the name of our library binary */ -#define LM_NETSTRM_FILENAME "lmnetstrm" +#define LM_NETSTRM_FILENAME LM_NETSTRMS_FILENAME #endif /* #ifndef INCLUDED_NETSTRM_H */ diff --git a/runtime/netstrms.c b/runtime/netstrms.c index 661234e4..fde0788d 100644 --- a/runtime/netstrms.c +++ b/runtime/netstrms.c @@ -23,6 +23,7 @@ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. */ #include "config.h" +#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <errno.h> @@ -31,9 +32,9 @@ #include "module-template.h" #include "obj.h" //#include "errmsg.h" -//#include "net.h" #include "nsd.h" #include "netstrm.h" +#include "nssel.h" #include "netstrms.h" MODULE_TYPE_LIB @@ -43,24 +44,29 @@ DEFobjStaticHelpers //DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(netstrm) -//DEFobjCurrIf(net) /* load our low-level driver. This must be done before any * driver-specific functions (allmost all...) can be carried * out. Note that the driver's .ifIsLoaded is correctly * initialized by calloc() and we depend on that. + * WARNING: this code is mostly identical to similar code in + * nssel.c - TODO: abstract it and move it to some common place. * rgerhards, 2008-04-18 */ static rsRetVal loadDrvr(netstrms_t *pThis) { - uchar *pDrvrName; DEFiRet; + uchar *pBaseDrvrName; + uchar szDrvrName[48]; /* 48 shall be large enough */ - pDrvrName = pThis->pDrvrName; - if(pDrvrName == NULL) /* if no drvr name is set, use system default */ - pDrvrName = glbl.GetDfltNetstrmDrvr(); + pBaseDrvrName = pThis->pBaseDrvrName; + if(pBaseDrvrName == NULL) /* if no drvr name is set, use system default */ + pBaseDrvrName = glbl.GetDfltNetstrmDrvr(); + if(snprintf((char*)szDrvrName, sizeof(szDrvrName), "lmnsd_%s", pBaseDrvrName) == sizeof(szDrvrName)) + ABORT_FINALIZE(RS_RET_DRVRNAME_TOO_LONG); + CHKmalloc(pThis->pDrvrName = (uchar*) strdup((char*)szDrvrName)); pThis->Drvr.ifVersion = nsdCURR_IF_VERSION; /* The pDrvrName+2 below is a hack to obtain the object name. It @@ -69,8 +75,14 @@ loadDrvr(netstrms_t *pThis) * about this hack, but for the time being it is efficient and clean * enough. -- rgerhards, 2008-04-18 */ - CHKiRet(obj.UseObj(__FILE__, pDrvrName+2, pDrvrName, (void*) &pThis->Drvr)); + CHKiRet(obj.UseObj(__FILE__, szDrvrName+2, szDrvrName, (void*) &pThis->Drvr)); + finalize_it: + if(iRet != RS_RET_OK) { + if(pThis->pDrvrName != NULL) + free(pThis->pDrvrName); + pThis->pDrvrName = NULL; + } RETiRet; } @@ -83,8 +95,18 @@ ENDobjConstruct(netstrms) /* destructor for the netstrms object */ BEGINobjDestruct(netstrms) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(netstrms) - if(pThis->pDrvrName != NULL) + /* and now we must release our driver, if we got one. We use the presence of + * a driver name string as load indicator (because we also need that string + * to release the driver + */ + if(pThis->pDrvrName != NULL) { + obj.ReleaseObj(__FILE__, pThis->pDrvrName+2, pThis->pDrvrName, (void*) &pThis->Drvr); free(pThis->pDrvrName); + } + if(pThis->pBaseDrvrName != NULL) { + free(pThis->pBaseDrvrName); + pThis->pBaseDrvrName = NULL; + } ENDobjDestruct(netstrms) @@ -100,6 +122,54 @@ finalize_it: } +/* set the base driver name. If the driver name + * is set to NULL, the previously set name is deleted but + * no name set again (which results in the system default being + * used)-- rgerhards, 2008-05-05 + */ +static rsRetVal +SetDrvrName(netstrms_t *pThis, uchar *pszName) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, netstrms); + if(pThis->pBaseDrvrName != NULL) { + free(pThis->pBaseDrvrName); + pThis->pBaseDrvrName = NULL; + } + + if(pszName != NULL) { + CHKmalloc(pThis->pBaseDrvrName = (uchar*) strdup((char*) pszName)); + } +finalize_it: + RETiRet; +} + + +/* set the driver mode -- rgerhards, 2008-04-30 + */ +static rsRetVal +SetDrvrMode(netstrms_t *pThis, int iMode) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, netstrms); + pThis->iDrvrMode = iMode; + RETiRet; +} + + +/* return the driver mode + * We use non-standard calling conventions because it makes an awful lot + * of sense here. + * rgerhards, 2008-04-30 + */ +static int +GetDrvrMode(netstrms_t *pThis) +{ + ISOBJ_TYPE_assert(pThis, netstrms); + return pThis->iDrvrMode; +} + + /* create an instance of a netstrm object. It is initialized with default * values. The current driver is used. The caller may set netstrm properties * and must call ConstructFinalize(). @@ -110,7 +180,7 @@ CreateStrm(netstrms_t *pThis, netstrm_t **ppStrm) netstrm_t *pStrm = NULL; DEFiRet; - CHKiRet(objUse(netstrm, LM_NETSTRM_FILENAME)); + CHKiRet(objUse(netstrm, DONT_LOAD_LIB)); CHKiRet(netstrm.Construct(&pStrm)); /* we copy over our driver structure. We could provide a pointer to * ourselves, but that costs some performance on each driver invocation. @@ -147,6 +217,9 @@ CODESTARTobjQueryInterface(netstrms) pIf->ConstructFinalize = netstrmsConstructFinalize; pIf->Destruct = netstrmsDestruct; pIf->CreateStrm = CreateStrm; + pIf->SetDrvrName = SetDrvrName; + pIf->SetDrvrMode = SetDrvrMode; + pIf->GetDrvrMode = GetDrvrMode; finalize_it: ENDobjQueryInterface(netstrms) @@ -155,9 +228,8 @@ ENDobjQueryInterface(netstrms) BEGINObjClassExit(netstrms, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */ CODESTARTObjClassExit(netstrms) /* release objects we no longer need */ - //objRelease(net, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); - objRelease(netstrm, LM_NETSTRM_FILENAME); + objRelease(netstrm, DONT_LOAD_LIB); ENDObjClassExit(netstrms) @@ -168,7 +240,6 @@ ENDObjClassExit(netstrms) BEGINAbstractObjClassInit(netstrms, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(glbl, CORE_COMPONENT)); - //CHKiRet(objUse(net, CORE_COMPONENT)); /* set our own handlers */ ENDObjClassInit(netstrms) @@ -179,7 +250,9 @@ ENDObjClassInit(netstrms) BEGINmodExit CODESTARTmodExit + nsselClassExit(); netstrmsClassExit(); + netstrmClassExit(); /* we use this object, so we must exit it after we are finished */ ENDmodExit @@ -194,7 +267,9 @@ CODESTARTmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ /* Initialize all classes that are in our module - this includes ourselfs */ - CHKiRet(netstrmsClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ + CHKiRet(netstrmClassInit(pModInfo)); + CHKiRet(nsselClassInit(pModInfo)); + CHKiRet(netstrmsClassInit(pModInfo)); ENDmodInit /* vi:set ai: */ diff --git a/runtime/netstrms.h b/runtime/netstrms.h index 1e920304..1d1cc892 100644 --- a/runtime/netstrms.h +++ b/runtime/netstrms.h @@ -29,7 +29,9 @@ /* the netstrms object */ struct netstrms_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - uchar *pDrvrName; /**< nsd driver name to use, or NULL if system default */ + uchar *pBaseDrvrName; /**< nsd base driver name to use, or NULL if system default */ + uchar *pDrvrName; /**< full base driver name (set when driver is loaded) */ + int iDrvrMode; /**< current default driver mode */ nsd_if_t Drvr; /**< our stream driver */ }; @@ -40,6 +42,9 @@ BEGINinterface(netstrms) /* name must also be changed in ENDinterface macro! */ rsRetVal (*ConstructFinalize)(netstrms_t *pThis); rsRetVal (*Destruct)(netstrms_t **ppThis); rsRetVal (*CreateStrm)(netstrms_t *pThis, netstrm_t **ppStrm); + rsRetVal (*SetDrvrName)(netstrms_t *pThis, uchar *pszName); + rsRetVal (*SetDrvrMode)(netstrms_t *pThis, int iMode); + int (*GetDrvrMode)(netstrms_t *pThis); ENDinterface(netstrms) #define netstrmsCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ diff --git a/runtime/nsd.h b/runtime/nsd.h index 1b3702a0..cc06c877 100644 --- a/runtime/nsd.h +++ b/runtime/nsd.h @@ -50,6 +50,7 @@ BEGINinterface(nsd) /* name must also be changed in ENDinterface macro! */ rsRetVal (*AcceptConnReq)(nsd_t *pThis, nsd_t **ppThis); rsRetVal (*GetRemoteHName)(nsd_t *pThis, uchar **pszName); rsRetVal (*GetRemoteIP)(nsd_t *pThis, uchar **pszIP); + rsRetVal (*SetMode)(nsd_t *pThis, int mode); /* sets a driver specific mode - see driver doc for details */ rsRetVal (*GetSock)(nsd_t *pThis, int *pSock); rsRetVal (*SetSock)(nsd_t *pThis, int sock); /* GetSock() and SetSock() return an error if the driver does not use plain diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c index d59043f2..20de772a 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -30,11 +30,18 @@ #include "rsyslog.h" #include "syslogd-types.h" #include "module-template.h" +#include "cfsysline.h" #include "obj.h" #include "errmsg.h" #include "nsd_ptcp.h" +#include "nsdsel_gtls.h" #include "nsd_gtls.h" +/* things to move to some better place/functionality - TODO */ +#define DH_BITS 1024 +#define CRLFILE "crl.pem" + + MODULE_TYPE_LIB /* static data */ @@ -43,25 +50,43 @@ DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(nsd_ptcp) +static int bGlblSrvrInitDone = 0; /**< 0 - server global init not yet done, 1 - already done */ /* a macro to check GnuTLS calls against unexpected errors */ #define CHKgnutls(x) \ if((gnuRet = (x)) != 0) { \ - dbgprintf("unexpected GnuTLS error %d in %s:%d\n", gnuRet, __FILE__, __LINE__); \ - gnutls_perror(gnuRet); /* TODO: can we do better? */ \ + uchar *pErr = gtlsStrerror(gnuRet); \ + dbgprintf("unexpected GnuTLS error %d in %s:%d: %s\n", gnuRet, __FILE__, __LINE__, pErr); \ + free(pErr); \ ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \ } -#define CAFILE "ca.pem" // TODO: allow to specify /* ------------------------------ GnuTLS specifics ------------------------------ */ static gnutls_certificate_credentials xcred; +static gnutls_dh_params dh_params; + +/* a thread-safe variant of gnutls_strerror - TODO: implement it! + * The caller must free the returned string. + * rgerhards, 2008-04-30 + */ +uchar *gtlsStrerror(int error) +{ + uchar *pErr; + + // TODO: guard by mutex! + pErr = (uchar*) strdup(gnutls_strerror(error)); + + return pErr; +} + /* globally initialize GnuTLS */ static rsRetVal gtlsGlblInit(void) { int gnuRet; + uchar *cafile; DEFiRet; CHKgnutls(gnutls_global_init()); @@ -70,7 +95,90 @@ gtlsGlblInit(void) CHKgnutls(gnutls_certificate_allocate_credentials(&xcred)); /* sets the trusted cas file */ - gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); + cafile = glbl.GetDfltNetstrmDrvrCAF(); + dbgprintf("GTLS CA file: '%s'\n", cafile); + gnuRet = gnutls_certificate_set_x509_trust_file(xcred, (char*)cafile, GNUTLS_X509_FMT_PEM); + if(gnuRet < 0) { + /* TODO; a more generic error-tracking function (this one based on CHKgnutls()) */ + uchar *pErr = gtlsStrerror(gnuRet); + dbgprintf("unexpected GnuTLS error %d in %s:%d: %s\n", gnuRet, __FILE__, __LINE__, pErr); + free(pErr); + ABORT_FINALIZE(RS_RET_GNUTLS_ERR); + } + +finalize_it: + RETiRet; +} + +static rsRetVal +gtlsInitSession(nsd_gtls_t *pThis) +{ + DEFiRet; + int gnuRet; + gnutls_session session; + + gnutls_init(&session, GNUTLS_SERVER); + pThis->bHaveSess = 1; + pThis->bIsInitiator = 0; + + /* avoid calling all the priority functions, since the defaults are adequate. */ + CHKgnutls(gnutls_set_default_priority(session)); + CHKgnutls(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred)); + + /* request client certificate if any. */ + gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUEST); + gnutls_dh_set_prime_bits(session, DH_BITS); + + pThis->sess = session; + +finalize_it: + RETiRet; +} + + + +static rsRetVal +generate_dh_params(void) +{ + int gnuRet; + DEFiRet; + /* Generate Diffie Hellman parameters - for use with DHE + * kx algorithms. These should be discarded and regenerated + * once a day, once a week or once a month. Depending on the + * security requirements. + */ + CHKgnutls(gnutls_dh_params_init( &dh_params)); + CHKgnutls(gnutls_dh_params_generate2( dh_params, DH_BITS)); +finalize_it: + RETiRet; +} + + +/* set up all global things that are needed for server operations + * rgerhards, 2008-04-30 + */ +static rsRetVal +gtlsGlblInitLstn(void) +{ + int gnuRet; + uchar *keyFile; + uchar *certFile; + DEFiRet; + + if(bGlblSrvrInitDone == 0) { + /* we do not use CRLs right now, and I doubt we'll ever do. This functionality is + * considered legacy. -- rgerhards, 2008-05-05 + */ + /*CHKgnutls(gnutls_certificate_set_x509_crl_file(xcred, CRLFILE, GNUTLS_X509_FMT_PEM));*/ + certFile = glbl.GetDfltNetstrmDrvrCertFile(); + keyFile = glbl.GetDfltNetstrmDrvrKeyFile(); + dbgprintf("GTLS certificate file: '%s'\n", certFile); + dbgprintf("GTLS key file: '%s'\n", keyFile); + CHKgnutls(gnutls_certificate_set_x509_key_file(xcred, (char*)certFile, (char*)keyFile, GNUTLS_X509_FMT_PEM)); + CHKiRet(generate_dh_params()); + gnutls_certificate_set_dh_params(xcred, dh_params); /* this is void */ + bGlblSrvrInitDone = 1; /* we are all set now */ + } finalize_it: RETiRet; @@ -100,9 +208,11 @@ gtlsEndSess(nsd_gtls_t *pThis) DEFiRet; if(pThis->bHaveSess) { - gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_RDWR); - while(gnuRet == GNUTLS_E_INTERRUPTED || gnuRet == GNUTLS_E_AGAIN) { + if(pThis->bIsInitiator) { gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_RDWR); + while(gnuRet == GNUTLS_E_INTERRUPTED || gnuRet == GNUTLS_E_AGAIN) { + gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_RDWR); + } } gnutls_deinit(pThis->sess); } @@ -116,8 +226,6 @@ gtlsEndSess(nsd_gtls_t *pThis) /* Standard-Constructor */ BEGINobjConstruct(nsd_gtls) /* be sure to specify the object type also in END macro! */ iRet = nsd_ptcp.Construct(&pThis->pTcp); - pThis->iMode = 1; /* TODO: must be made configurable */ - pThis->iMode = 0; /* TODO: must be made configurable */ ENDobjConstruct(nsd_gtls) @@ -134,6 +242,29 @@ CODESTARTobjDestruct(nsd_gtls) ENDobjDestruct(nsd_gtls) +/* Set the driver mode. For us, this has the following meaning: + * 0 - work in plain tcp mode, without tls (e.g. before a STARTTLS) + * 1 - work in TLS mode + * rgerhards, 2008-04-28 + */ +static rsRetVal +SetMode(nsd_t *pNsd, int mode) +{ + DEFiRet; + nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; + +dbgprintf("SetMOde tries to set mode %d\n", mode); + ISOBJ_TYPE_assert((pThis), nsd_gtls); + if(mode != 0 && mode != 1) + ABORT_FINALIZE(RS_RET_INVAID_DRVR_MODE); + + pThis->iMode = mode; + +finalize_it: + RETiRet; +} + + /* Provide access to the underlying OS socket. This is primarily * useful for other drivers (like nsd_gtls) who utilize ourselfs * for some of their functionality. -- rgerhards, 2008-04-18 @@ -184,7 +315,9 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), uchar *pLstnPort, uchar *pLstnIP, int iSessMax) { DEFiRet; + CHKiRet(gtlsGlblInitLstn()); iRet = nsd_ptcp.LstnInit(pNS, pUsr, fAddLstn, pLstnPort, pLstnIP, iSessMax); +finalize_it: RETiRet; } @@ -227,15 +360,38 @@ static rsRetVal AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew) { DEFiRet; + int gnuRet; nsd_gtls_t *pNew = NULL; nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; ISOBJ_TYPE_assert((pThis), nsd_gtls); - // TODO: method to construct without pTcp CHKiRet(nsd_gtlsConstruct(&pNew)); CHKiRet(nsd_ptcp.Destruct(&pNew->pTcp)); CHKiRet(nsd_ptcp.AcceptConnReq(pThis->pTcp, &pNew->pTcp)); + if(pThis->iMode == 0) { + /* we are in non-TLS mode, so we are done */ + *ppNew = (nsd_t*) pNew; + FINALIZE; + } + + /* if we reach this point, we are in TLS mode */ + CHKiRet(gtlsInitSession(pNew)); + gnutls_transport_set_ptr(pNew->sess, (gnutls_transport_ptr_t)((nsd_ptcp_t*) (pNew->pTcp))->sock); + + /* we now do the handshake. This is a bit complicated, because we are + * on non-blocking sockets. Usually, the handshake will not complete + * immediately, so that we need to retry it some time later. + */ + gnuRet = gnutls_handshake(pNew->sess); + if(gnuRet == GNUTLS_E_AGAIN || gnuRet == GNUTLS_E_INTERRUPTED) { + pNew->rtryCall = gtlsRtry_handshake; + dbgprintf("GnuTLS handshake does not complete immediately - setting to retry (this is OK and normal)\n"); + } else if(gnuRet != 0) { + ABORT_FINALIZE(RS_RET_TLS_HANDSHAKE_ERR); + } + pNew->iMode = 1; /* this session is now in TLS mode! */ + *ppNew = (nsd_t*) pNew; finalize_it: @@ -260,6 +416,8 @@ static rsRetVal Rcv(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf) { DEFiRet; + int gnuRet; + ssize_t lenRcvd; nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; ISOBJ_TYPE_assert(pThis, nsd_gtls); @@ -269,6 +427,8 @@ Rcv(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf) } /* in TLS mode now */ + lenRcvd = gnutls_record_recv(pThis->sess, pBuf, *pLenBuf); + *pLenBuf = lenRcvd; finalize_it: RETiRet; @@ -301,8 +461,11 @@ Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf) *pLenBuf = iSent; break; } - if(iSent != GNUTLS_E_INTERRUPTED && iSent != GNUTLS_E_AGAIN) + if(iSent != GNUTLS_E_INTERRUPTED && iSent != GNUTLS_E_AGAIN) { + dbgprintf("unexpected GnuTLS error %d in %s:%d\n", iSent, __FILE__, __LINE__); + gnutls_perror(iSent); /* TODO: can we do better? */ ABORT_FINALIZE(RS_RET_GNUTLS_ERR); + } } finalize_it: @@ -335,6 +498,7 @@ Connect(nsd_t *pNsd, int family, uchar *port, uchar *host) /* we reach this point if in TLS mode */ CHKgnutls(gnutls_init(&pThis->sess, GNUTLS_CLIENT)); pThis->bHaveSess = 1; + pThis->bIsInitiator = 1; /* Use default priorities */ CHKgnutls(gnutls_set_default_priority(pThis->sess)); @@ -345,7 +509,7 @@ Connect(nsd_t *pNsd, int family, uchar *port, uchar *host) /* assign the socket to GnuTls */ CHKiRet(nsd_ptcp.GetSock(pThis->pTcp, &sock)); - gnutls_transport_set_ptr(pThis->sess, (gnutls_transport_ptr)sock); + gnutls_transport_set_ptr(pThis->sess, (gnutls_transport_ptr_t)sock); /* and perform the handshake */ CHKgnutls(gnutls_handshake(pThis->sess)); @@ -384,6 +548,7 @@ CODESTARTobjQueryInterface(nsd_gtls) pIf->Send = Send; pIf->Connect = Connect; pIf->SetSock = SetSock; + pIf->SetMode = SetMode; pIf->GetRemoteHName = GetRemoteHName; pIf->GetRemoteIP = GetRemoteIP; finalize_it: @@ -423,6 +588,7 @@ ENDObjClassInit(nsd_gtls) BEGINmodExit CODESTARTmodExit + nsdsel_gtlsClassExit(); nsd_gtlsClassExit(); ENDmodExit @@ -439,6 +605,8 @@ CODESTARTmodInit /* Initialize all classes that are in our module - this includes ourselfs */ CHKiRet(nsd_gtlsClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ + CHKiRet(nsdsel_gtlsClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ + ENDmodInit /* vi:set ai: */ diff --git a/runtime/nsd_gtls.h b/runtime/nsd_gtls.h index c193f57c..83e15f29 100644 --- a/runtime/nsd_gtls.h +++ b/runtime/nsd_gtls.h @@ -26,6 +26,11 @@ #include "nsd.h" +typedef enum { + gtlsRtry_None = 0, /**< no call needs to be retried */ + gtlsRtry_handshake = 1 +} gtlsRtryCall_t; /**< IDs of calls that needs to be retried */ + typedef nsd_if_t nsd_gtls_if_t; /* we just *implement* this interface */ /* the nsd_gtls object */ @@ -33,8 +38,11 @@ struct nsd_gtls_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ nsd_t *pTcp; /**< our aggregated nsd_ptcp data */ int iMode; /* 0 - plain tcp, 1 - TLS */ + gtlsRtryCall_t rtryCall;/**< what must we retry? */ + int bIsInitiator; /**< 0 if socket is the server end (listener), 1 if it is the initiator */ gnutls_session sess; - int bHaveSess; + int bHaveSess; /* as we don't know exactly which gnutls_session values are invalid, we use this one + to flag whether or not we are in a session (same as -1 for a socket meaning no sess) */ }; /* interface is defined in nsd.h, we just implement it! */ diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index 2a74e061..c5480a05 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -47,6 +47,7 @@ #include "net.h" #include "netstrms.h" #include "netstrm.h" +#include "nsdsel_ptcp.h" #include "nsd_ptcp.h" MODULE_TYPE_LIB @@ -109,6 +110,22 @@ GetSock(nsd_t *pNsd, int *pSock) } +/* Set the driver mode. We support no different modes, but allow mode + * 0 to be set to be compatible with config file defaults and the other + * drivers. + * rgerhards, 2008-04-28 + */ +static rsRetVal +SetMode(nsd_t __attribute__((unused)) *pNsd, int mode) +{ + DEFiRet; + if(mode != 0) + ABORT_FINALIZE(RS_RET_INVAID_DRVR_MODE); +finalize_it: + RETiRet; +} + + /* Provide access to the underlying OS socket. This is primarily * useful for other drivers (like nsd_gtls) who utilize ourselfs * for some of their functionality. @@ -415,13 +432,11 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), * construct a new netstrm obj and hand it over to the upper layers for inclusion * into their socket array. -- rgerhards, 2008-04-23 */ -RUNLOG_VAR("%d", sock); CHKiRet(pNS->Drvr.Construct(&pNewNsd)); CHKiRet(pNS->Drvr.SetSock(pNewNsd, sock)); -RUNLOG; + CHKiRet(pNS->Drvr.SetMode(pNewNsd, netstrms.GetDrvrMode(pNS))); CHKiRet(netstrms.CreateStrm(pNS, &pNewStrm)); pNewStrm->pDrvrData = (nsd_t*) pNewNsd; -RUNLOG; CHKiRet(fAddLstn(pUsr, pNewStrm)); pNewNsd = NULL; pNewStrm = NULL; @@ -609,6 +624,7 @@ CODESTARTobjQueryInterface(nsd_ptcp) pIf->Abort = Abort; pIf->GetSock = GetSock; pIf->SetSock = SetSock; + pIf->SetMode = SetMode; pIf->Rcv = Rcv; pIf->Send = Send; pIf->LstnInit = LstnInit; @@ -628,7 +644,7 @@ CODESTARTObjClassExit(nsd_ptcp) objRelease(net, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); - objRelease(netstrm, LM_NETSTRM_FILENAME); + objRelease(netstrm, DONT_LOAD_LIB); objRelease(netstrms, LM_NETSTRMS_FILENAME); ENDObjClassExit(nsd_ptcp) @@ -642,8 +658,8 @@ BEGINObjClassInit(nsd_ptcp, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(net, CORE_COMPONENT)); - CHKiRet(objUse(netstrm, LM_NETSTRM_FILENAME)); CHKiRet(objUse(netstrms, LM_NETSTRMS_FILENAME)); + CHKiRet(objUse(netstrm, DONT_LOAD_LIB)); /* set our own handlers */ ENDObjClassInit(nsd_ptcp) @@ -654,6 +670,7 @@ ENDObjClassInit(nsd_ptcp) BEGINmodExit CODESTARTmodExit + nsdsel_ptcpClassExit(); nsd_ptcpClassExit(); ENDmodExit @@ -670,6 +687,7 @@ CODESTARTmodInit /* Initialize all classes that are in our module - this includes ourselfs */ CHKiRet(nsd_ptcpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ + CHKiRet(nsdsel_ptcpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ ENDmodInit /* vi:set ai: */ diff --git a/runtime/nsdsel_gtls.c b/runtime/nsdsel_gtls.c index 7cafec49..8c1e705b 100644 --- a/runtime/nsdsel_gtls.c +++ b/runtime/nsdsel_gtls.c @@ -37,11 +37,10 @@ #include "errmsg.h" #include "nsd.h" #include "nsd_gtls.h" +#include "nsd_ptcp.h" #include "nsdsel_ptcp.h" #include "nsdsel_gtls.h" -MODULE_TYPE_LIB - /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) @@ -74,7 +73,21 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp) ISOBJ_TYPE_assert(pThis, nsdsel_gtls); ISOBJ_TYPE_assert(pNsdGTLS, nsd_gtls); - iRet = nsdsel_ptcp.Add(pThis->pTcp, pNsdGTLS->pTcp, waitOp); + if(pNsdGTLS->iMode == 1) { + if(pNsdGTLS->rtryCall != gtlsRtry_None) { + if(gnutls_record_get_direction(pNsdGTLS->sess) == 0) { + CHKiRet(nsdsel_ptcp.Add(pThis->pTcp, pNsdGTLS->pTcp, NSDSEL_RD)); + } else { + CHKiRet(nsdsel_ptcp.Add(pThis->pTcp, pNsdGTLS->pTcp, NSDSEL_WR)); + } + FINALIZE; + } + } + + /* if we reach this point, we need no special handling */ + CHKiRet(nsdsel_ptcp.Add(pThis->pTcp, pNsdGTLS->pTcp, waitOp)); + +finalize_it: RETiRet; } @@ -94,6 +107,47 @@ Select(nsdsel_t *pNsdsel, int *piNumReady) } +/* retry an interrupted GTLS operation + * rgerhards, 2008-04-30 + */ +static rsRetVal +doRetry(nsd_gtls_t *pNsd) +{ + DEFiRet; + int gnuRet; + + dbgprintf("GnuTLS requested retry of %d operation - executing\n", pNsd->rtryCall); + + /* We follow a common scheme here: first, we do the systen call and + * then we check the result. So far, the result is checked after the + * switch, because the result check is the same for all calls. Note that + * this may change once we deal with the read and write calls (but + * probably this becomes an issue only when we begin to work on TLS + * for relp). -- rgerhards, 2008-04-30 + */ + switch(pNsd->rtryCall) { + case gtlsRtry_handshake: + gnuRet = gnutls_handshake(pNsd->sess); + break; + default: + assert(0); /* this shall not happen! */ + break; + } + + if(gnuRet == 0) { + pNsd->rtryCall = gtlsRtry_None; /* we are done */ + } else if(gnuRet != GNUTLS_E_AGAIN && gnuRet != GNUTLS_E_INTERRUPTED) { + ABORT_FINALIZE(RS_RET_GNUTLS_ERR); + } + /* if we are interrupted once again (else case), we do not need to + * change our status because we are already setup for retries. + */ + +finalize_it: + RETiRet; +} + + /* check if a socket is ready for IO */ static rsRetVal IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady) @@ -104,7 +158,20 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady) ISOBJ_TYPE_assert(pThis, nsdsel_gtls); ISOBJ_TYPE_assert(pNsdGTLS, nsd_gtls); - iRet = nsdsel_ptcp.IsReady(pThis->pTcp, pNsdGTLS->pTcp, waitOp, pbIsReady); + if(pNsdGTLS->iMode == 1) { + if(pNsdGTLS->rtryCall != gtlsRtry_None) { + CHKiRet(doRetry(pNsdGTLS)); + /* we used this up for our own internal processing, so the socket + * is not ready from the upper layer point of view. + */ + *pbIsReady = 0; + FINALIZE; + } + } + + CHKiRet(nsdsel_ptcp.IsReady(pThis->pTcp, pNsdGTLS->pTcp, waitOp, pbIsReady)); + +finalize_it: RETiRet; } @@ -135,12 +202,12 @@ ENDobjQueryInterface(nsdsel_gtls) /* exit our class */ -BEGINObjClassExit(nsdsel_gtls, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */ +BEGINObjClassExit(nsdsel_gtls, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */ CODESTARTObjClassExit(nsdsel_gtls) /* release objects we no longer need */ objRelease(glbl, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); - objRelease(nsdsel_ptcp, LM_NSDSEL_PTCP_FILENAME); + objRelease(nsdsel_ptcp, LM_NSD_PTCP_FILENAME); ENDObjClassExit(nsdsel_gtls) @@ -148,37 +215,13 @@ ENDObjClassExit(nsdsel_gtls) * before anything else is called inside this class. * rgerhards, 2008-02-19 */ -BEGINObjClassInit(nsdsel_gtls, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */ +BEGINObjClassInit(nsdsel_gtls, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); - CHKiRet(objUse(nsdsel_ptcp, LM_NSDSEL_PTCP_FILENAME)); + CHKiRet(objUse(nsdsel_ptcp, LM_NSD_PTCP_FILENAME)); /* set our own handlers */ ENDObjClassInit(nsdsel_gtls) - - -/* --------------- here now comes the plumbing that makes as a library module --------------- */ - - -BEGINmodExit -CODESTARTmodExit - nsdsel_gtlsClassExit(); -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_LIB_QUERIES -ENDqueryEtryPt - - -BEGINmodInit() -CODESTARTmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ - - /* Initialize all classes that are in our module - this includes ourselfs */ - CHKiRet(nsdsel_gtlsClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ -ENDmodInit /* vi:set ai: */ diff --git a/runtime/nsdsel_gtls.h b/runtime/nsdsel_gtls.h index a309d302..7c2df684 100644 --- a/runtime/nsdsel_gtls.h +++ b/runtime/nsdsel_gtls.h @@ -39,7 +39,4 @@ struct nsdsel_gtls_s { /* prototypes */ PROTOTYPEObj(nsdsel_gtls); -/* the name of our library binary */ -#define LM_NSDSEL_GTLS_FILENAME "lmnsdsel_gtls" - #endif /* #ifndef INCLUDED_NSDSEL_GTLS_H */ diff --git a/runtime/nsdsel_ptcp.c b/runtime/nsdsel_ptcp.c index b439063a..41b85e0c 100644 --- a/runtime/nsdsel_ptcp.c +++ b/runtime/nsdsel_ptcp.c @@ -37,8 +37,6 @@ #include "nsd_ptcp.h" #include "nsdsel_ptcp.h" -MODULE_TYPE_LIB - /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) @@ -175,7 +173,7 @@ ENDobjQueryInterface(nsdsel_ptcp) /* exit our class */ -BEGINObjClassExit(nsdsel_ptcp, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */ +BEGINObjClassExit(nsdsel_ptcp, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */ CODESTARTObjClassExit(nsdsel_ptcp) /* release objects we no longer need */ objRelease(glbl, CORE_COMPONENT); @@ -187,36 +185,12 @@ ENDObjClassExit(nsdsel_ptcp) * before anything else is called inside this class. * rgerhards, 2008-02-19 */ -BEGINObjClassInit(nsdsel_ptcp, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */ +BEGINObjClassInit(nsdsel_ptcp, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); /* set our own handlers */ ENDObjClassInit(nsdsel_ptcp) - - -/* --------------- here now comes the plumbing that makes as a library module --------------- */ - - -BEGINmodExit -CODESTARTmodExit - nsdsel_ptcpClassExit(); -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_LIB_QUERIES -ENDqueryEtryPt - - -BEGINmodInit() -CODESTARTmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ - - /* Initialize all classes that are in our module - this includes ourselfs */ - CHKiRet(nsdsel_ptcpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ -ENDmodInit /* vi:set ai: */ diff --git a/runtime/nsdsel_ptcp.h b/runtime/nsdsel_ptcp.h index 93874e55..6c0c7fa7 100644 --- a/runtime/nsdsel_ptcp.h +++ b/runtime/nsdsel_ptcp.h @@ -41,7 +41,4 @@ struct nsdsel_ptcp_s { /* prototypes */ PROTOTYPEObj(nsdsel_ptcp); -/* the name of our library binary */ -#define LM_NSDSEL_PTCP_FILENAME "lmnsdsel_ptcp" - #endif /* #ifndef INCLUDED_NSDSEL_PTCP_H */ diff --git a/runtime/nssel.c b/runtime/nssel.c index 5333fc75..d11d5fe1 100644 --- a/runtime/nssel.c +++ b/runtime/nssel.c @@ -44,8 +44,6 @@ #include "netstrm.h" #include "nssel.h" -MODULE_TYPE_LIB - /* static data */ DEFobjStaticHelpers DEFobjCurrIf(glbl) @@ -54,18 +52,28 @@ DEFobjCurrIf(glbl) /* load our low-level driver. This must be done before any * driver-specific functions (allmost all...) can be carried * out. Note that the driver's .ifIsLoaded is correctly - * initialized by calloc() and we depend on that. - * rgerhards, 2008-04-18 + * initialized by calloc() and we depend on that. Please note that + * we do some name-mangeling. We know that each nsd driver also needs + * a nssel driver. So we simply append "sel" to the nsd driver name: This, + * of course, means that the driver name must match these rules, but that + * shouldn't be a real problem. + * WARNING: this code is mostly identical to similar code in + * netstrms.c - TODO: abstract it and move it to some common place. + * rgerhards, 2008-04-28 */ static rsRetVal loadDrvr(nssel_t *pThis) { - uchar *pDrvrName; DEFiRet; + uchar *pBaseDrvrName; + uchar szDrvrName[48]; /* 48 shall be large enough */ - pDrvrName = pThis->pDrvrName; - if(pDrvrName == NULL) /* if no drvr name is set, use system default */ - pDrvrName = glbl.GetDfltNetstrmDrvr(); + pBaseDrvrName = pThis->pBaseDrvrName; + if(pBaseDrvrName == NULL) /* if no drvr name is set, use system default */ + pBaseDrvrName = glbl.GetDfltNetstrmDrvr(); + if(snprintf((char*)szDrvrName, sizeof(szDrvrName), "lmnsdsel_%s", pBaseDrvrName) == sizeof(szDrvrName)) + ABORT_FINALIZE(RS_RET_DRVRNAME_TOO_LONG); + CHKmalloc(pThis->pDrvrName = (uchar*) strdup((char*)szDrvrName)); pThis->Drvr.ifVersion = nsdCURR_IF_VERSION; /* The pDrvrName+2 below is a hack to obtain the object name. It @@ -74,9 +82,14 @@ loadDrvr(nssel_t *pThis) * about this hack, but for the time being it is efficient and clean * enough. -- rgerhards, 2008-04-18 */ - //CHKiRet(obj.UseObj(__FILE__, pDrvrName+2, pDrvrName, (void*) &pThis->Drvr)); - CHKiRet(obj.UseObj(__FILE__, "nsdsel_gtls", "lmnsdsel_gtls", (void*) &pThis->Drvr)); + CHKiRet(obj.UseObj(__FILE__, szDrvrName+2, DONT_LOAD_LIB, (void*) &pThis->Drvr)); + finalize_it: + if(iRet != RS_RET_OK) { + if(pThis->pDrvrName != NULL) + free(pThis->pDrvrName); + pThis->pDrvrName = NULL; + } RETiRet; } @@ -91,6 +104,15 @@ BEGINobjDestruct(nssel) /* be sure to specify the object type also in END and CO CODESTARTobjDestruct(nssel) if(pThis->pDrvrData != NULL) pThis->Drvr.Destruct(&pThis->pDrvrData); + + /* and now we must release our driver, if we got one. We use the presence of + * a driver name string as load indicator (because we also need that string + * to release the driver + */ + if(pThis->pDrvrName != NULL) { + obj.ReleaseObj(__FILE__, pThis->pDrvrName+2, DONT_LOAD_LIB, (void*) &pThis->Drvr); + free(pThis->pDrvrName); + } ENDobjDestruct(nssel) @@ -201,29 +223,5 @@ BEGINObjClassInit(nssel, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* set our own handlers */ ENDObjClassInit(nssel) - - -/* --------------- here now comes the plumbing that makes us a library module --------------- */ - - -BEGINmodExit -CODESTARTmodExit - nsselClassExit(); -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_LIB_QUERIES -ENDqueryEtryPt - - -BEGINmodInit() -CODESTARTmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ - - /* Initialize all classes that are in our module - this includes ourselfs */ - CHKiRet(nsselClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */ -ENDmodInit /* vi:set ai: */ diff --git a/runtime/nssel.h b/runtime/nssel.h index 2f907caa..8cb34f5a 100644 --- a/runtime/nssel.h +++ b/runtime/nssel.h @@ -24,13 +24,14 @@ #ifndef INCLUDED_NSSEL_H #define INCLUDED_NSSEL_H -#include "nsd.h" +#include "netstrms.h" /* the nssel object */ struct nssel_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ nsd_t *pDrvrData; /**< the driver's data elements */ - uchar *pDrvrName; /**< nsd driver name to use, or NULL if system default */ + uchar *pBaseDrvrName; /**< nsd base driver name to use, or NULL if system default */ + uchar *pDrvrName; /**< full base driver name (set when driver is loaded) */ nsdsel_if_t Drvr; /**< our stream driver */ }; @@ -50,6 +51,6 @@ ENDinterface(nssel) PROTOTYPEObj(nssel); /* the name of our library binary */ -#define LM_NSSEL_FILENAME "lmnssel" +#define LM_NSSEL_FILENAME LM_NETSTRMS_FILENAME #endif /* #ifndef INCLUDED_NSSEL_H */ diff --git a/runtime/obj.c b/runtime/obj.c index 18a4a726..312ed223 100644 --- a/runtime/obj.c +++ b/runtime/obj.c @@ -1192,15 +1192,14 @@ ReleaseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf) objInfo_t *pObjInfo; - dbgprintf("source file %s requests object '%s', ifIsLoaded %d\n", srcFile, pObjName, pIf->ifIsLoaded); + dbgprintf("source file %s releasing object '%s', ifIsLoaded %d\n", srcFile, pObjName, pIf->ifIsLoaded); if(pObjFile == NULL) FINALIZE; /* if it is not a lodable module, we do not need to do anything... */ if(pIf->ifIsLoaded == 0) { ABORT_FINALIZE(RS_RET_OK); /* we are not loaded - this is perfectly OK... */ - } - if(pIf->ifIsLoaded == 2) { + } else if(pIf->ifIsLoaded == 2) { pIf->ifIsLoaded = 0; /* clean up */ ABORT_FINALIZE(RS_RET_OK); /* we had a load error and can not continue */ } @@ -1209,7 +1208,6 @@ ReleaseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf) CHKiRet(FindObjInfo(pStr, &pObjInfo)); /* if we reach this point, we have a valid pObjInfo */ - //if(pObjInfo->pModInfo != NULL) { /* NULL means core module */ module.Release(srcFile, &pObjInfo->pModInfo); /* decrease refcount */ pIf->ifIsLoaded = 0; /* indicated "no longer valid" */ diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 19fda468..c32e190c 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -219,6 +219,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_GNUTLS_ERR = -2078, /**< (unexpected) error in GnuTLS call */ RS_RET_MAX_SESS_REACHED = -2079, /**< max nbr of sessions reached, can not create more */ RS_RET_MAX_LSTN_REACHED = -2080, /**< max nbr of listeners reached, can not create more */ + RS_RET_INVAID_DRVR_MODE = -2081, /**< tried to set mode not supported by driver */ + RS_RET_DRVRNAME_TOO_LONG = -2082, /**< driver name too long - should never happen */ + RS_RET_TLS_HANDSHAKE_ERR = -2083, /**< TLS handshake failed */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ |