From 85b587f93d7f1294fae78317c0841a30aaa03583 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 May 2008 18:52:44 +0200 Subject: first implementation of TLS server client authentication check The TLS server now checks the client fingerprint. This works, but is highly experimental. Needs to be refined for practice. Also: - implemented permittedPeers helper construct to store names - changed omfwd implementation to use new permittedPeers --- plugins/imtcp/imtcp.c | 48 ++++++++++++++++++++++++++++++++++++++ runtime/net.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/net.h | 19 ++++++++++++++- runtime/netstrm.c | 12 ++++++---- runtime/netstrm.h | 2 +- runtime/netstrms.c | 51 +++++++++++++++++++++++++++++++++++++++- runtime/netstrms.h | 9 +++++++- runtime/nsd.h | 2 +- runtime/nsd_gtls.c | 55 ++++++++++++++++++++++++++++--------------- runtime/nsd_gtls.h | 3 ++- runtime/nsd_ptcp.c | 20 +++++++++++----- runtime/nsdsel_gtls.c | 9 ++++---- runtime/rsyslog.h | 2 ++ tcpsrv.c | 53 +++++++++++++++++++++++++++++++++++++++--- tcpsrv.h | 6 ++++- tools/omfwd.c | 50 ++++++++++++++++++++++++++++------------ 16 files changed, 347 insertions(+), 58 deletions(-) diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 971d3aec..d8363151 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -23,6 +23,20 @@ * A copy of the GPL can be found in the file "COPYING" in this distribution. */ +/* This note shall explain the calling sequence while we do not have + * have full RainerScript support for (TLS) sender authentication: + * + * imtcp --> tcpsrv --> netstrms (this sequence stored pPermPeers in netstrms class) + * then a callback (doOpenLstnSocks) into imtcp happens, which in turn calls + * into tcpsrv.create_tcp_socket(), + * which calls into netstrm.LstnInit(), which receives a pointer to netstrms obj + * which calls into the driver function LstnInit (again, netstrms obj passed) + * which finally calls back into netstrms obj's get functions to obtain the auth + * parameters and then applies them to the driver object instance + * + * rgerhards, 2008-05-19 + */ + #include "config.h" #include #include @@ -46,6 +60,7 @@ #include "netstrm.h" #include "errmsg.h" #include "tcpsrv.h" +#include "net.h" /* for permittedPeers, may be removed when this is removed */ MODULE_TYPE_INPUT @@ -59,10 +74,13 @@ DEFobjCurrIf(errmsg) /* Module static data */ static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */ +static permittedPeers_t *pPermPeersRoot = NULL; + /* config settings */ static int iTCPSessMax = 200; /* max number of sessions */ static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ +static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */ /* callbacks */ @@ -122,9 +140,22 @@ onErrClose(tcps_sess_t *pSess) /* ------------------------------ end callbacks ------------------------------ */ +/* set permitted peer -- rgerhards, 2008-05-19 + */ +static rsRetVal +setPermittedPeer(void __attribute__((unused)) *pVal, uchar *pszID) +{ + DEFiRet; + CHKiRet(net.AddPermittedPeer(&pPermPeersRoot, pszID)); +finalize_it: + RETiRet; +} + + static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal) { DEFiRet; + if(pOurTcpsrv == NULL) { CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); @@ -133,6 +164,15 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose)); CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose)); CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode)); + /* now set optional params, but only if they were actually configured */ + if(pszStrmDrvrAuthMode != NULL) { +RUNLOG_VAR("%s", pszStrmDrvrAuthMode); + CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, pszStrmDrvrAuthMode)); + } + if(pPermPeersRoot != NULL) { + CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot)); + } + /* most params set, now start listener */ tcpsrv.configureTCPListen(pOurTcpsrv, (char *) pNewVal); CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv)); } @@ -183,6 +223,10 @@ CODESTARTmodExit if(pOurTcpsrv != NULL) iRet = tcpsrv.Destruct(&pOurTcpsrv); + if(pPermPeersRoot != NULL) { + net.DestructPermittedPeers(&pPermPeersRoot); + } + /* release objects we used */ objRelease(net, LM_NET_FILENAME); objRelease(netstrm, LM_NETSTRMS_FILENAME); @@ -227,6 +271,10 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdrivermode", 0, eCmdHdlrInt, NULL, &iStrmDrvrMode, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverauthmode", 0, + eCmdHdlrGetWord, NULL, &pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverpermittedpeer", 0, + eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit diff --git a/runtime/net.c b/runtime/net.c index 7663b1b3..cbff1003 100644 --- a/runtime/net.c +++ b/runtime/net.c @@ -88,6 +88,68 @@ static struct AllowedSenders *pLastAllowedSenders_GSS = NULL; int ACLAddHostnameOnFail = 0; /* add hostname to acl when DNS resolving has failed */ int ACLDontResolve = 0; /* add hostname to acl instead of resolving it to IP(s) */ + +/* ------------------------------ begin permitted peers code ------------------------------ */ + + +/* add a permitted peer. PermittedPeers is an interim solution until we can provide + * access control via enhanced RainerScript methods. + * Note: the provided string is handed over to this function, caller must + * no longer access it. -- rgerhards, 2008-05-19 + */ +static rsRetVal +AddPermittedPeer(permittedPeers_t **ppRootPeer, uchar* pszID) +{ + permittedPeers_t *pNew = NULL; + DEFiRet; + + assert(ppRootPeer != NULL); + assert(pszID != NULL); + + CHKmalloc(pNew = malloc(sizeof(permittedPeers_t))); + CHKmalloc(pNew->pszID = (uchar*)strdup((char*)pszID)); + pNew->pNext = NULL; + + if(*ppRootPeer != NULL) { + pNew->pNext = *ppRootPeer; + } + *ppRootPeer = pNew; + +finalize_it: + if(iRet != RS_RET_OK) { + if(pNew != NULL) + free(pNew); + } + RETiRet; +} + + +/* Destruct a permitted peers list -- rgerhards, 2008-05-19 */ +static rsRetVal +DestructPermittedPeers(permittedPeers_t **ppRootPeer) +{ + permittedPeers_t *pCurr; + permittedPeers_t *pDel; + DEFiRet; + + assert(ppRootPeer != NULL); + + for(pCurr = *ppRootPeer ; pCurr != NULL ; /*EMPTY*/) { + pDel = pCurr; + pCurr = pCurr->pNext; + free(pDel->pszID); + free(pDel); + } + + *ppRootPeer = NULL; + + RETiRet; +} + + +/* ------------------------------ end permitted peers code ------------------------------ */ + + /* Code for handling allowed/disallowed senders */ static inline void MaskIP6 (struct in6_addr *addr, uint8_t bits) { @@ -1095,6 +1157,8 @@ CODESTARTobjQueryInterface(net) pIf->isAllowedSender = isAllowedSender; pIf->should_use_so_bsdcompat = should_use_so_bsdcompat; pIf->getLocalHostname = getLocalHostname; + pIf->AddPermittedPeer = AddPermittedPeer; + pIf->DestructPermittedPeers = DestructPermittedPeers; finalize_it: ENDobjQueryInterface(net) diff --git a/runtime/net.h b/runtime/net.h index 9e471bf9..673f45a9 100644 --- a/runtime/net.h +++ b/runtime/net.h @@ -91,6 +91,20 @@ struct AllowedSenders { }; +/* for fingerprints and hostnames, we need to have a temporary linked list of + * permitted values. Unforutnately, we must also duplicate this in the netstream + * drivers. However, this is the best interim solution (with the least effort). + * A clean implementation requires that we have more capable variables and the + * full-fledged scripting engine available. So we have opted to do the interim + * solution so that our users can begin to enjoy authenticated TLS. The next step + * (hopefully) is to enhance RainerScript. -- rgerhards, 2008-05-19 + */ +struct permittedPeers_s { + uchar *pszID; + permittedPeers_t *pNext; +}; + + /* interfaces */ BEGINinterface(net) /* name must also be changed in ENDinterface macro! */ rsRetVal (*cvthname)(struct sockaddr_storage *f, uchar *pszHost, uchar *pszHostFQDN, uchar *pszIP); @@ -104,7 +118,10 @@ BEGINinterface(net) /* name must also be changed in ENDinterface macro! */ int (*isAllowedSender)(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost); rsRetVal (*getLocalHostname)(uchar**); int (*should_use_so_bsdcompat)(void); - /* data memebers - these should go away over time... TODO */ + /* permitted peer handling should be replaced by something better (see comments above) */ + rsRetVal (*AddPermittedPeer)(permittedPeers_t **ppRootPeer, uchar *pszID); + rsRetVal (*DestructPermittedPeers)(permittedPeers_t **ppRootPeer); + /* data members - these should go away over time... TODO */ int *pACLAddHostnameOnFail; /* add hostname to acl when DNS resolving has failed */ int *pACLDontResolve; /* add hostname to acl instead of resolving it to IP(s) */ struct AllowedSenders *pAllowedSenders_UDP; diff --git a/runtime/netstrm.c b/runtime/netstrm.c index 899cb3bf..786ba7f8 100644 --- a/runtime/netstrm.c +++ b/runtime/netstrm.c @@ -43,6 +43,7 @@ #include #include "rsyslog.h" +#include "net.h" #include "module-template.h" #include "obj.h" #include "errmsg.h" @@ -202,20 +203,21 @@ SetDrvrAuthMode(netstrm_t *pThis, uchar *mode) } -/* add an accepted fingerprint -- rgerhards, 2008-05-16 - */ +/* set the driver's permitted peers -- rgerhards, 2008-05-19 */ static rsRetVal -AddDrvrPermittedFingerprint(netstrm_t *pThis, uchar *fingerprint) +SetDrvrPermPeers(netstrm_t *pThis, permittedPeers_t *pPermPeers) { DEFiRet; ISOBJ_TYPE_assert(pThis, netstrm); - iRet = pThis->Drvr.AddPermFingerprint(pThis->pDrvrData, fingerprint); + iRet = pThis->Drvr.SetPermPeers(pThis->pDrvrData, pPermPeers); RETiRet; } + /* End of methods to shuffle autentication settings to the driver. * -------------------------------------------------------------------------- */ + /* 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 @@ -311,7 +313,7 @@ CODESTARTobjQueryInterface(netstrm) pIf->GetRemoteIP = GetRemoteIP; pIf->SetDrvrMode = SetDrvrMode; pIf->SetDrvrAuthMode = SetDrvrAuthMode; - pIf->AddDrvrPermittedFingerprint = AddDrvrPermittedFingerprint; + pIf->SetDrvrPermPeers = SetDrvrPermPeers; pIf->GetSock = GetSock; finalize_it: ENDobjQueryInterface(netstrm) diff --git a/runtime/netstrm.h b/runtime/netstrm.h index ffdb392e..ae135beb 100644 --- a/runtime/netstrm.h +++ b/runtime/netstrm.h @@ -51,7 +51,7 @@ BEGINinterface(netstrm) /* name must also be changed in ENDinterface macro! */ rsRetVal (*GetRemoteIP)(netstrm_t *pThis, uchar **pszIP); rsRetVal (*SetDrvrMode)(netstrm_t *pThis, int iMode); rsRetVal (*SetDrvrAuthMode)(netstrm_t *pThis, uchar*); - rsRetVal (*AddDrvrPermittedFingerprint)(netstrm_t *pThis, uchar*); + rsRetVal (*SetDrvrPermPeers)(netstrm_t *pThis, permittedPeers_t*); /* 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 diff --git a/runtime/netstrms.c b/runtime/netstrms.c index 03a46329..3e5b7819 100644 --- a/runtime/netstrms.c +++ b/runtime/netstrms.c @@ -146,8 +146,53 @@ finalize_it: } -/* set the driver mode -- rgerhards, 2008-04-30 +/* set the driver's permitted peers -- rgerhards, 2008-05-19 */ +static rsRetVal +SetDrvrPermPeers(netstrms_t *pThis, permittedPeers_t *pPermPeers) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, netstrms); + pThis->pPermPeers = pPermPeers; + RETiRet; +} +/* return the driver's permitted peers + * We use non-standard calling conventions because it makes an awful lot + * of sense here. + * rgerhards, 2008-05-19 + */ +static uchar* +GetDrvrPermPeers(netstrms_t *pThis) +{ + ISOBJ_TYPE_assert(pThis, netstrms); + return pThis->pPermPeers; +} + + +/* set the driver auth mode -- rgerhards, 2008-05-19 */ +static rsRetVal +SetDrvrAuthMode(netstrms_t *pThis, uchar *mode) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, netstrms); +RUNLOG_VAR("%s", mode); + CHKmalloc(pThis->pszDrvrAuthMode = (uchar*)strdup((char*)mode)); +finalize_it: + RETiRet; +} +/* return the driver auth mode + * We use non-standard calling conventions because it makes an awful lot + * of sense here. + * rgerhards, 2008-05-19 */ +static uchar* +GetDrvrAuthMode(netstrms_t *pThis) +{ + ISOBJ_TYPE_assert(pThis, netstrms); + return pThis->pszDrvrAuthMode; +} + + +/* set the driver mode -- rgerhards, 2008-04-30 */ static rsRetVal SetDrvrMode(netstrms_t *pThis, int iMode) { @@ -221,6 +266,10 @@ CODESTARTobjQueryInterface(netstrms) pIf->SetDrvrName = SetDrvrName; pIf->SetDrvrMode = SetDrvrMode; pIf->GetDrvrMode = GetDrvrMode; + pIf->SetDrvrAuthMode = SetDrvrAuthMode; + pIf->GetDrvrAuthMode = GetDrvrAuthMode; + pIf->SetDrvrPermPeers = SetDrvrPermPeers; + pIf->GetDrvrPermPeers = GetDrvrPermPeers; finalize_it: ENDobjQueryInterface(netstrms) diff --git a/runtime/netstrms.h b/runtime/netstrms.h index 1d1cc892..3f686af6 100644 --- a/runtime/netstrms.h +++ b/runtime/netstrms.h @@ -32,6 +32,9 @@ struct netstrms_s { 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 */ + uchar *pszDrvrAuthMode; /**< current driver authentication mode */ + permittedPeers_t *pPermPeers;/**< current driver's permitted peers */ + nsd_if_t Drvr; /**< our stream driver */ }; @@ -44,7 +47,11 @@ BEGINinterface(netstrms) /* name must also be changed in ENDinterface macro! */ 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); + rsRetVal (*SetDrvrAuthMode)(netstrms_t *pThis, uchar*); + rsRetVal (*SetDrvrPermPeers)(netstrms_t *pThis, permittedPeers_t*); + int (*GetDrvrMode)(netstrms_t *pThis); + uchar* (*GetDrvrAuthMode)(netstrms_t *pThis); + permittedPeers_t* (*GetDrvrPermPeers)(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 1dc9efe9..53693b59 100644 --- a/runtime/nsd.h +++ b/runtime/nsd.h @@ -52,7 +52,7 @@ BEGINinterface(nsd) /* name must also be changed in ENDinterface macro! */ 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 (*SetAuthMode)(nsd_t *pThis, uchar*); /* sets a driver specific mode - see driver doc for details */ - rsRetVal (*AddPermFingerprint)(nsd_t *pThis, uchar*); /* sets a driver specific mode - see driver doc for details */ + rsRetVal (*SetPermPeers)(nsd_t *pThis, permittedPeers_t*); /* sets driver permitted peers for auth needs */ 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 4e7fa3b6..ff162754 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -39,6 +39,7 @@ #include "obj.h" #include "stringbuf.h" #include "errmsg.h" +#include "net.h" #include "nsd_ptcp.h" #include "nsdsel_gtls.h" #include "nsd_gtls.h" @@ -252,7 +253,6 @@ finalize_it: /* check the fingerprint of the remote peer's certificate. * rgerhards, 2008-05-08 */ -//static rsRetVal rsRetVal gtlsChkFingerprint(nsd_gtls_t *pThis) { @@ -264,6 +264,8 @@ gtlsChkFingerprint(nsd_gtls_t *pThis) gnutls_x509_crt cert; int bMustDeinitCert = 0; int gnuRet; + int bFoundPositiveMatch; + permittedPeers_t *pPeer; DEFiRet; ISOBJ_TYPE_assert(pThis, nsd_gtls); @@ -296,11 +298,23 @@ gtlsChkFingerprint(nsd_gtls_t *pThis) if(pThis->authMode != GTLS_AUTH_CERTFINGERPRINT) FINALIZE; - if(pThis->authIDs == NULL || rsCStrSzStrCmp(pstrFingerprint, pThis->authIDs, strlen((char*) pThis->authIDs))) { - dbgprintf("invalid server fingerprint, not permitted to talk to us\n"); + /* now search through the permitted peers to see if we can find a permitted one */ + bFoundPositiveMatch = 0; + pPeer = pThis->pPermPeers; + while(pPeer != NULL && !bFoundPositiveMatch) { + if(!rsCStrSzStrCmp(pstrFingerprint, pPeer->pszID, strlen((char*) pPeer->pszID))) { + bFoundPositiveMatch = 1; + } else { + pPeer = pPeer->pNext; + } + } + + if(!bFoundPositiveMatch) { + dbgprintf("invalid peer fingerprint, not permitted to talk to it\n"); if(pThis->bReportAuthErr == 1) { - errmsg.LogError(NO_ERRCODE, "error: server fingerprint '%s' unknown - we are " - "not permitted to talk to this server", rsCStrGetSzStr(pstrFingerprint)); + errno = 0; + errmsg.LogError(NO_ERRCODE, "error: peer fingerprint '%s' unknown - we are " + "not permitted to talk to it", rsCStrGetSzStr(pstrFingerprint)); pThis->bReportAuthErr = 0; } ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT); @@ -401,7 +415,6 @@ 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) { errmsg.LogError(NO_ERRCODE, "error: driver mode %d not supported by " @@ -450,28 +463,26 @@ dbgprintf("gtls auth mode %d set\n", pThis->authMode); } -/* Add a permitted fingerprint. Only useful to call if we are using - * fingerprint authentication. Results in error if we are not in this mode. - * rgerhards, 2008-05-16 +/* Set permitted peers. It is depending on the auth mode if this are + * fingerprints or names. -- rgerhards, 2008-05-19 */ static rsRetVal -AddPermFingerprint(nsd_t *pNsd, uchar *pszFingerprint) +SetPermPeers(nsd_t *pNsd, permittedPeers_t *pPermPeers) { DEFiRet; nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; ISOBJ_TYPE_assert((pThis), nsd_gtls); - if(pThis->authMode != GTLS_AUTH_CERTFINGERPRINT) { - errmsg.LogError(NO_ERRCODE, "fingerprint authentication not supported by " + if(pPermPeers == NULL) + FINALIZE; + + if(pThis->authMode != GTLS_AUTH_CERTFINGERPRINT && pThis->authMode != GTLS_AUTH_CERTNAME) { + errmsg.LogError(NO_ERRCODE, "authentication not supported by " "gtls netstream driver in the configured authentication mode - ignored"); ABORT_FINALIZE(RS_RET_VALUE_NOT_IN_THIS_MODE); } - // TODO: proper handling - but we need to redo this when we do the - // linked list. So for now, this is good enough (but MUST BE CHANGED!). - - pThis->authIDs = pszFingerprint; -dbgprintf("gtls fingerprint '%s' set\n", pThis->authIDs); + pThis->pPermPeers = pPermPeers; finalize_it: RETiRet; @@ -590,6 +601,8 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew) /* if we reach this point, we are in TLS mode */ CHKiRet(gtlsInitSession(pNew)); gtlsSetTransportPtr(pNew, ((nsd_ptcp_t*) (pNew->pTcp))->sock); + pNew->authMode = pThis->authMode; + pNew->pPermPeers = pThis->pPermPeers; /* we now do the handshake. This is a bit complicated, because we are * on non-blocking sockets. Usually, the handshake will not complete @@ -633,6 +646,9 @@ Rcv(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf) nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; ISOBJ_TYPE_assert(pThis, nsd_gtls); + if(pThis->bAbortConn) + ABORT_FINALIZE(RS_RET_CONNECTION_ABORTREQ); + if(pThis->iMode == 0) { CHKiRet(nsd_ptcp.Rcv(pThis->pTcp, pBuf, pLenBuf)); FINALIZE; @@ -667,6 +683,9 @@ Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf) DEFiRet; ISOBJ_TYPE_assert(pThis, nsd_gtls); + if(pThis->bAbortConn) + ABORT_FINALIZE(RS_RET_CONNECTION_ABORTREQ); + if(pThis->iMode == 0) { CHKiRet(nsd_ptcp.Send(pThis->pTcp, pBuf, pLenBuf)); FINALIZE; @@ -771,7 +790,7 @@ CODESTARTobjQueryInterface(nsd_gtls) pIf->SetSock = SetSock; pIf->SetMode = SetMode; pIf->SetAuthMode = SetAuthMode; - pIf->AddPermFingerprint = AddPermFingerprint; + pIf->SetPermPeers =SetPermPeers; pIf->GetRemoteHName = GetRemoteHName; pIf->GetRemoteIP = GetRemoteIP; finalize_it: diff --git a/runtime/nsd_gtls.h b/runtime/nsd_gtls.h index 0576a993..1f3eb6b1 100644 --- a/runtime/nsd_gtls.h +++ b/runtime/nsd_gtls.h @@ -38,6 +38,7 @@ 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 */ + int bAbortConn; /* if set, abort conncection (fatal error had happened) */ enum { GTLS_AUTH_CERTNAME = 0, GTLS_AUTH_CERTFINGERPRINT = 1, @@ -51,7 +52,7 @@ struct nsd_gtls_s { int bReportAuthErr; /* only the first auth error is to be reported, this var triggers it. Initially, it is * set to 1 and changed to 0 after the first report. It is changed back to 1 after * one successful authentication. */ - uchar *authIDs; /* TODO: make linked list, currently just a single fingerprint, must also support names */ + permittedPeers_t *pPermPeers; /* permitted senders */ }; /* interface is defined in nsd.h, we just implement it! */ diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index 6702e118..14c564a3 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -153,16 +153,22 @@ finalize_it: } -/* Add a permitted fingerprint. This is a dummy, always returning an +/* Set the permitted peers. This is a dummy, always returning an * error because we do not support fingerprint authentication. * rgerhards, 2008-05-17 */ static rsRetVal -AddPermFingerprint(nsd_t __attribute__((unused)) *pNsd, uchar __attribute__((unused)) *pszFingerprint) +SetPermPeers(nsd_t __attribute__((unused)) *pNsd, permittedPeers_t __attribute__((unused)) *pPermPeers) { - errmsg.LogError(NO_ERRCODE, "fingerprint authentication not supported by " - "ptcp netstream driver"); - return RS_RET_VALUE_NOT_IN_THIS_MODE; + DEFiRet; + + if(pPermPeers != NULL) { + errmsg.LogError(NO_ERRCODE, "authentication not supported by ptcp netstream driver"); + ABORT_FINALIZE(RS_RET_VALUE_NOT_IN_THIS_MODE); + } + +finalize_it: + RETiRet; } @@ -477,6 +483,8 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), CHKiRet(pNS->Drvr.Construct(&pNewNsd)); CHKiRet(pNS->Drvr.SetSock(pNewNsd, sock)); CHKiRet(pNS->Drvr.SetMode(pNewNsd, netstrms.GetDrvrMode(pNS))); + CHKiRet(pNS->Drvr.SetAuthMode(pNewNsd, netstrms.GetDrvrAuthMode(pNS))); + CHKiRet(pNS->Drvr.SetPermPeers(pNewNsd, netstrms.GetDrvrPermPeers(pNS))); CHKiRet(netstrms.CreateStrm(pNS, &pNewStrm)); pNewStrm->pDrvrData = (nsd_t*) pNewNsd; CHKiRet(fAddLstn(pUsr, pNewStrm)); @@ -668,7 +676,7 @@ CODESTARTobjQueryInterface(nsd_ptcp) pIf->SetSock = SetSock; pIf->SetMode = SetMode; pIf->SetAuthMode = SetAuthMode; - pIf->AddPermFingerprint = AddPermFingerprint; + pIf->SetPermPeers = SetPermPeers; pIf->Rcv = Rcv; pIf->Send = Send; pIf->LstnInit = LstnInit; diff --git a/runtime/nsdsel_gtls.c b/runtime/nsdsel_gtls.c index e54693dc..082a044b 100644 --- a/runtime/nsdsel_gtls.c +++ b/runtime/nsdsel_gtls.c @@ -128,12 +128,10 @@ doRetry(nsd_gtls_t *pNsd) switch(pNsd->rtryCall) { case gtlsRtry_handshake: gnuRet = gnutls_handshake(pNsd->sess); - dbgprintf("handshake ret %d\n", gnuRet); if(gnuRet == 0) { + pNsd->rtryCall = gtlsRtry_None; /* we are done */ /* we got a handshake, now check authorization */ - // TODO: do it! - dbgprintf("handshake done\n"); - gtlsChkFingerprint(pNsd); + CHKiRet(gtlsChkFingerprint(pNsd)); } break; default: @@ -157,6 +155,9 @@ doRetry(nsd_gtls_t *pNsd) */ finalize_it: + if(iRet != RS_RET_OK) + pNsd->bAbortConn = 1; /* request abort */ +RUNLOG_VAR("%d", pNsd->bAbortConn); RETiRet; } diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index fe26bb44..c06b01c3 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -81,6 +81,7 @@ typedef struct interface_s interface_t; typedef struct objInfo_s objInfo_t; typedef enum rsRetVal_ rsRetVal; /**< friendly type for global return value */ typedef rsRetVal (*errLogFunc_t)(uchar*); /* this is a trick to store a function ptr to a function returning a function ptr... */ +typedef struct permittedPeers_s permittedPeers_t; /* this should go away in the long term -- rgerhards, 2008-05-19 */ typedef struct tcpsrv_s tcpsrv_t; /* some universal 64 bit define... */ @@ -227,6 +228,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_VALUE_NOT_SUPPORTED = -2086, /**< a provided value is not supported */ RS_RET_VALUE_NOT_IN_THIS_MODE = -2087, /**< a provided value is invalid for the curret mode */ RS_RET_INVALID_FINGERPRINT = -2088, /**< a fingerprint is not valid for this use case */ + RS_RET_CONNECTION_ABORTREQ = -2089, /**< connection was abort requested due to previous error */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tcpsrv.c b/tcpsrv.c index 6db2fee7..9b3553f1 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -457,6 +457,7 @@ Run(tcpsrv_t *pThis) pThis->pOnRegularClose(pThis->pSessions[iTCPSess]); tcps_sess.Destruct(&pThis->pSessions[iTCPSess]); } else if(state == -1) { + errno = 0; errmsg.LogError(NO_ERRCODE, "netstream session %p will be closed, error ignored\n", pThis->pSessions[iTCPSess]->pStrm); pThis->pOnErrClose(pThis->pSessions[iTCPSess]); @@ -478,12 +479,18 @@ Run(tcpsrv_t *pThis) iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess); } CHKiRet(nssel.Destruct(&pSel)); +finalize_it: /* this is a very special case - this time only we do not exit the function, + * because that would not help us either. So we simply retry it. Let's see + * if that actually is a better idea. Exiting the loop wasn't we always + * crashed, which made sense (the rest of the engine was not prepared for + * that) -- rgerhards, 2008-05-19 + */ + /*EMPTY*/; } /* note that this point is usually not reached */ pthread_cleanup_pop(0); /* remove cleanup handler */ -finalize_it: // TODO: think: is it really good to exit the loop? RETiRet; } @@ -504,6 +511,10 @@ tcpsrvConstructFinalize(tcpsrv_t *pThis) /* prepare network stream subsystem */ CHKiRet(netstrms.Construct(&pThis->pNS)); CHKiRet(netstrms.SetDrvrMode(pThis->pNS, pThis->iDrvrMode)); + if(pThis->pszDrvrAuthMode != NULL) + CHKiRet(netstrms.SetDrvrAuthMode(pThis->pNS, pThis->pszDrvrAuthMode)); + if(pThis->pPermPeers != NULL) + CHKiRet(netstrms.SetDrvrPermPeers(pThis->pNS, pThis->pPermPeers)); // TODO: set driver! CHKiRet(netstrms.ConstructFinalize(pThis->pNS)); @@ -530,6 +541,8 @@ CODESTARTobjDestruct(tcpsrv) if(pThis->pNS != NULL) netstrms.Destruct(&pThis->pNS); + if(pThis->pszDrvrAuthMode != NULL) + free(pThis->pszDrvrAuthMode); if(pThis->ppLstn != NULL) free(pThis->ppLstn); ENDobjDestruct(tcpsrv) @@ -628,8 +641,14 @@ SetUsrP(tcpsrv_t *pThis, void *pUsr) pThis->pUsr = pUsr; RETiRet; } -/* set the driver mode -- rgerhards, 2008-04-30 - */ + + +/* here follows a number of methods that shuffle authentication settings down + * to the drivers. Drivers not supporting these settings may return an error + * state. + * -------------------------------------------------------------------------- */ + +/* set the driver mode -- rgerhards, 2008-04-30 */ static rsRetVal SetDrvrMode(tcpsrv_t *pThis, int iMode) { @@ -640,6 +659,32 @@ SetDrvrMode(tcpsrv_t *pThis, int iMode) } +/* set the driver authentication mode -- rgerhards, 2008-05-19 */ +static rsRetVal +SetDrvrAuthMode(tcpsrv_t *pThis, uchar *mode) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, tcpsrv); + CHKmalloc(pThis->pszDrvrAuthMode = (uchar*)strdup((char*)mode)); +finalize_it: + RETiRet; +} + + +/* set the driver's permitted peers -- rgerhards, 2008-05-19 */ +static rsRetVal +SetDrvrPermPeers(tcpsrv_t *pThis, permittedPeers_t *pPermPeers) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, tcpsrv); + pThis->pPermPeers = pPermPeers; + RETiRet; +} + + +/* End of methods to shuffle autentication settings to the driver.; + + * -------------------------------------------------------------------------- */ /* queryInterface function @@ -668,6 +713,8 @@ CODESTARTobjQueryInterface(tcpsrv) pIf->SetUsrP = SetUsrP; pIf->SetDrvrMode = SetDrvrMode; + pIf->SetDrvrAuthMode = SetDrvrAuthMode; + pIf->SetDrvrPermPeers = SetDrvrPermPeers; pIf->SetCBIsPermittedHost = SetCBIsPermittedHost; pIf->SetCBOpenLstnSocks = SetCBOpenLstnSocks; pIf->SetCBRcvData = SetCBRcvData; diff --git a/tcpsrv.h b/tcpsrv.h index 07826125..0feb62f3 100644 --- a/tcpsrv.h +++ b/tcpsrv.h @@ -30,6 +30,8 @@ struct tcpsrv_s { BEGINobjInstance; /**< Data to implement generic object - MUST be the first data element! */ netstrms_t *pNS; /**< pointer to network stream subsystem */ int iDrvrMode; /**< mode of the stream driver to use */ + uchar *pszDrvrAuthMode; /**< auth mode of the stream driver to use */ + permittedPeers_t *pPermPeers;/**< driver's permitted peers */ int iLstnMax; /**< max nbr of listeners currently supported */ netstrm_t **ppLstn; /**< our netstream listners */ int iSessMax; /**< max number of sessions supported */ @@ -71,12 +73,14 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */ rsRetVal (*SetCBOnRegularClose)(tcpsrv_t*, rsRetVal (*) (tcps_sess_t*)); rsRetVal (*SetCBOnErrClose)(tcpsrv_t*, rsRetVal (*) (tcps_sess_t*)); rsRetVal (*SetDrvrMode)(tcpsrv_t *pThis, int iMode); + rsRetVal (*SetDrvrAuthMode)(tcpsrv_t *pThis, uchar *pszMode); + rsRetVal (*SetDrvrPermPeers)(tcpsrv_t *pThis, permittedPeers_t*); /* session specifics */ rsRetVal (*SetCBOnSessAccept)(tcpsrv_t*, rsRetVal (*) (tcpsrv_t*, tcps_sess_t*)); rsRetVal (*SetCBOnSessDestruct)(tcpsrv_t*, rsRetVal (*) (void*)); rsRetVal (*SetCBOnSessConstructFinalize)(tcpsrv_t*, rsRetVal (*) (void*)); ENDinterface(tcpsrv) -#define tcpsrvCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ +#define tcpsrvCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */ /* prototypes */ diff --git a/tools/omfwd.c b/tools/omfwd.c index 43f601e3..a902fe3b 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -79,7 +79,8 @@ typedef struct _instanceData { netstrm_t *pNetstrm; /* our output netstream */ uchar *pszStrmDrvr; uchar *pszStrmDrvrAuthMode; - uchar *pszStrmDrvrFingerprint; + permittedPeers_t *pPermPeersRootFingerprint; + permittedPeers_t *pPermPeersRootNames; int iStrmDrvrMode; char *f_hname; int *pSockArray; /* sockets to use for UDP */ @@ -98,9 +99,10 @@ typedef struct _instanceData { static uchar *pszTplName = NULL; /* name of the default template to use */ static uchar *pszStrmDrvr = NULL; /* name of the stream driver to use */ static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ -static uchar *pszStrmDrvrAuthMode = NULL; /* name of the default template to use */ -static uchar *pszStrmDrvrFingerprint = NULL; /* name of the default template to use */ +static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */ +static permittedPeers_t *pPermPeersRootFingerprint = NULL; +static permittedPeers_t *pPermPeersRootNames = NULL; /* get the syslog forward port from selector_t. The passed in * struct must be one that is setup for forwarding. @@ -154,8 +156,10 @@ CODESTARTfreeInstance free(pData->pszStrmDrvr); if(pData->pszStrmDrvrAuthMode != NULL) free(pData->pszStrmDrvrAuthMode); - if(pData->pszStrmDrvrFingerprint != NULL) - free(pData->pszStrmDrvrFingerprint); + if(pData->pPermPeersRootFingerprint != NULL) + net.DestructPermittedPeers(&pData->pPermPeersRootFingerprint); + if(pData->pPermPeersRootNames != NULL) + net.DestructPermittedPeers(&pData->pPermPeersRootNames); ENDfreeInstance @@ -212,6 +216,19 @@ static rsRetVal UDPSend(instanceData *pData, char *msg, size_t len) } +/* set the cert fingerprint -- rgerhards, 2008-05-19 + */ +static rsRetVal +setFingerprint(void __attribute__((unused)) *pVal, uchar *pszID) +{ + DEFiRet; + CHKiRet(net.AddPermittedPeer(&pPermPeersRootFingerprint, pszID)); +finalize_it: + RETiRet; +} + + + /* CODE FOR SENDING TCP MESSAGES */ @@ -281,9 +298,8 @@ static rsRetVal TCPSendInit(void *pvData) if(pData->pszStrmDrvrAuthMode != NULL) { CHKiRet(netstrm.SetDrvrAuthMode(pData->pNetstrm, pData->pszStrmDrvrAuthMode)); } - if(pData->pszStrmDrvrFingerprint != NULL) { - CHKiRet(netstrm.AddDrvrPermittedFingerprint(pData->pNetstrm, - pData->pszStrmDrvrFingerprint)); + if(pData->pPermPeersRootFingerprint != NULL) { + CHKiRet(netstrm.SetDrvrPermPeers(pData->pNetstrm, pData->pPermPeersRootFingerprint)); } /* params set, now connect */ CHKiRet(netstrm.Connect(pData->pNetstrm, glbl.GetDefPFFamily(), @@ -590,9 +606,14 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) if(pszStrmDrvrAuthMode != NULL) CHKmalloc(pData->pszStrmDrvrAuthMode = (uchar*)strdup((char*)pszStrmDrvrAuthMode)); - if(pszStrmDrvrFingerprint != NULL) - CHKmalloc(pData->pszStrmDrvrFingerprint = - (uchar*)strdup((char*)pszStrmDrvrFingerprint)); + if(pPermPeersRootFingerprint != NULL) { + pData->pPermPeersRootFingerprint = pPermPeersRootFingerprint; + pPermPeersRootFingerprint = NULL; + } + if(pPermPeersRootNames != NULL) { + pData->pPermPeersRootNames = pPermPeersRootNames; + pPermPeersRootNames = NULL; + } } CODE_STD_FINALIZERparseSelectorAct @@ -617,9 +638,8 @@ freeConfigVars(void) free(pszStrmDrvrAuthMode); pszStrmDrvrAuthMode = NULL; } - if(pszStrmDrvrFingerprint != NULL) { - free(pszStrmDrvrFingerprint); - pszStrmDrvrFingerprint = NULL; + if(pPermPeersRootFingerprint != NULL) { + free(pPermPeersRootFingerprint); } } @@ -670,7 +690,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszStrmDrvr, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdrivermode", 0, eCmdHdlrInt, NULL, &iStrmDrvrMode, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriverauthmode", 0, eCmdHdlrGetWord, NULL, &pszStrmDrvrAuthMode, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdrivercertfingerprint", 0, eCmdHdlrGetWord, NULL, &pszStrmDrvrFingerprint, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdrivercertfingerprint", 0, eCmdHdlrGetWord, setFingerprint, NULL, NULL)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit -- cgit