mirror of
https://github.com/rsyslog/rsyslog.git
synced 2025-12-17 05:50:41 +01:00
first working TLS-enabled plain TCP sender
implemented a first working version of a TLS-enabled plain TCP sender (but, of course, the implementation is insecure as it is)
This commit is contained in:
parent
032b9c1f64
commit
2069ab114e
14
ca.pem
Normal file
14
ca.pem
Normal file
@ -0,0 +1,14 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICPDCCAaegAwIBAgIBADALBgkqhkiG9w0BAQUwRTELMAkGA1UEBhMCR1IxDDAK
|
||||
BgNVBAoTA0ZTRjEPMA0GA1UECxMGR05VVExTMRcwFQYDVQQDEw5HTlVUTFMgVEVT
|
||||
VCBDQTAeFw0wNDA2MjgyMjQ0MDBaFw0wNzAzMjQyMjQ0MDBaMEUxCzAJBgNVBAYT
|
||||
AkdSMQwwCgYDVQQKEwNGU0YxDzANBgNVBAsTBkdOVVRMUzEXMBUGA1UEAxMOR05V
|
||||
VExTIFRFU1QgQ0EwgZwwCwYJKoZIhvcNAQEBA4GMADCBiAKBgMK0cY9Tap5F7DXX
|
||||
tu7HpHlZtu+zqfofyLJSIBpUdbiwFIGzB486stbog0mpiy32mGIG5hNlpcRMJMVm
|
||||
MmZ1RueqQWR+vdDroBoV199zAZQVww1NmmHi/Wtxa6x9SsXdya+SnoC8KI/V3EKx
|
||||
gYG0hYAuYWNA9JnntTU0xCwWOBaPAgMBAAGjQzBBMA8GA1UdEwEB/wQFMAMBAf8w
|
||||
DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUeesbb6Nm5nnh0eK129onBkUpCkgw
|
||||
CwYJKoZIhvcNAQEFA4GBAGCCzUSCVZOXffm/KFxbyT2Lrltyzqlr0Oknp55eNAIk
|
||||
fy+m/viSOmoTCaK9Gmtk3eMAxIeZ8U7TDKrbrxx/NSsggbypqa3EMMwr2JH9kzAZ
|
||||
eluQ0vEVqfvRq5jzjuORYYhl7VgqpU0/ctvI3b+9tCZAOCcUX0HPvNweAzYjnkDi
|
||||
-----END CERTIFICATE-----
|
||||
@ -488,16 +488,16 @@ if test "x$enable_gnutls" = "xyes"; then
|
||||
AC_CHECK_LIB(
|
||||
[gnutls],
|
||||
[gnutls_check_version],
|
||||
[tls_cflags=`libgnutls-config --cflags`
|
||||
tls_libs=`libgnutls-config --libs`
|
||||
[gnutls_cflags=`libgnutls-config --cflags`
|
||||
gnutls_libs=`libgnutls-config --libs`
|
||||
],
|
||||
[AC_MSG_FAILURE([GNU TLS library is missing])],
|
||||
[`libgnutls-config --libs`]
|
||||
)
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_GNUTLS, test x$enable_gnutls = xyes)
|
||||
AC_SUBST(tls_cflags)
|
||||
AC_SUBST(tls_libs)
|
||||
AC_SUBST(gnutls_cflags)
|
||||
AC_SUBST(gnutls_libs)
|
||||
|
||||
|
||||
# support for building the rsyslogd runtime
|
||||
|
||||
@ -110,8 +110,8 @@ 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_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
|
||||
lmnsd_gtls_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) $(gnutls_cflags)
|
||||
lmnsd_gtls_la_LDFLAGS = -module -avoid-version
|
||||
lmnsd_gtls_la_LIBADD =
|
||||
lmnsd_gtls_la_LIBADD = $(gnutls_libs)
|
||||
endif
|
||||
|
||||
|
||||
@ -84,18 +84,22 @@ loadDrvr(netstrm_t *pThis)
|
||||
uchar *pDrvrName;
|
||||
DEFiRet;
|
||||
|
||||
pDrvrName = pThis->pDrvrName;
|
||||
if(pDrvrName == NULL) /* if no drvr name is set, use system default */
|
||||
pDrvrName = glbl.GetDfltNetstrmDrvr();
|
||||
if(pThis->Drvr.ifIsLoaded == 0) {
|
||||
pDrvrName = pThis->pDrvrName;
|
||||
if(pDrvrName == NULL) { /* if no drvr name is set, use system default */
|
||||
pDrvrName = glbl.GetDfltNetstrmDrvr();
|
||||
pThis->pDrvrName = (uchar*)strdup((char*)pDrvrName); // TODO: use set method once it exists
|
||||
}
|
||||
|
||||
pThis->Drvr.ifVersion = nsdCURR_IF_VERSION;
|
||||
/* The pDrvrName+2 below is a hack to obtain the object name. It
|
||||
* safes us to have yet another variable with the name without "lm" in
|
||||
* front of it. If we change the module load interface, we may re-think
|
||||
* 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));
|
||||
pThis->Drvr.ifVersion = nsdCURR_IF_VERSION;
|
||||
/* The pDrvrName+2 below is a hack to obtain the object name. It
|
||||
* safes us to have yet another variable with the name without "lm" in
|
||||
* front of it. If we change the module load interface, we may re-think
|
||||
* 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));
|
||||
}
|
||||
finalize_it:
|
||||
RETiRet;
|
||||
}
|
||||
@ -111,6 +115,13 @@ BEGINobjDestruct(netstrm) /* be sure to specify the object type also in END and
|
||||
CODESTARTobjDestruct(netstrm)
|
||||
if(pThis->pDrvrData != NULL)
|
||||
iRet = pThis->Drvr.Destruct(&pThis->pDrvrData);
|
||||
|
||||
/* driver can only be released after all data has been destructed */
|
||||
if(pThis->Drvr.ifIsLoaded == 1) {
|
||||
obj.ReleaseObj(__FILE__, pThis->pDrvrName+2, pThis->pDrvrName, (void*) &pThis->Drvr);
|
||||
}
|
||||
if(pThis->pDrvrName != NULL)
|
||||
free(pThis->pDrvrName);
|
||||
ENDobjDestruct(netstrm)
|
||||
|
||||
|
||||
|
||||
@ -41,6 +41,11 @@ BEGINinterface(nsd) /* name must also be changed in ENDinterface macro! */
|
||||
rsRetVal (*Rcv)(nsd_t *pThis, uchar *pRcvBuf, ssize_t *pLenBuf);
|
||||
rsRetVal (*Send)(nsd_t *pThis, uchar *pBuf, ssize_t *pLenBuf);
|
||||
rsRetVal (*Connect)(nsd_t *pThis, int family, unsigned char *port, unsigned char *host);
|
||||
rsRetVal (*GetSock)(nsd_t *pThis, int *pSock);
|
||||
/* GetSock() returns an error if the driver does not use plain
|
||||
* OS sockets. This interface is primarily meant as an internal aid for
|
||||
* those drivers that utilize the nsd_ptcp to do some of their work.
|
||||
*/
|
||||
ENDinterface(nsd)
|
||||
#define nsdCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#include <fnmatch.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
#include "rsyslog.h"
|
||||
#include "syslogd-types.h"
|
||||
@ -57,15 +58,72 @@ DEFobjCurrIf(glbl)
|
||||
DEFobjCurrIf(nsd_ptcp)
|
||||
|
||||
|
||||
/* 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? */ \
|
||||
ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \
|
||||
}
|
||||
|
||||
#define CAFILE "ca.pem" // TODO: allow to specify
|
||||
|
||||
/* ------------------------------ GnuTLS specifics ------------------------------ */
|
||||
static gnutls_certificate_credentials xcred;
|
||||
|
||||
/* globally initialize GnuTLS */
|
||||
static rsRetVal
|
||||
gtlsGlblInit(void)
|
||||
{
|
||||
int gnuRet;
|
||||
DEFiRet;
|
||||
|
||||
CHKgnutls(gnutls_global_init());
|
||||
|
||||
/* X509 stuff */
|
||||
CHKgnutls(gnutls_certificate_allocate_credentials(&xcred));
|
||||
|
||||
/* sets the trusted cas file */
|
||||
gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM);
|
||||
|
||||
finalize_it:
|
||||
RETiRet;
|
||||
}
|
||||
|
||||
|
||||
/* globally de-initialize GnuTLS */
|
||||
static rsRetVal
|
||||
gtlsGlblExit(void)
|
||||
{
|
||||
DEFiRet;
|
||||
/* X509 stuff */
|
||||
gnutls_certificate_free_credentials(xcred);
|
||||
gnutls_global_deinit(); /* we are done... */
|
||||
RETiRet;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------- end GnuTLS specifics ---------------------------- */
|
||||
|
||||
|
||||
/* 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 */
|
||||
ENDobjConstruct(nsd_gtls)
|
||||
|
||||
|
||||
/* destructor for the nsd_gtls object */
|
||||
BEGINobjDestruct(nsd_gtls) /* be sure to specify the object type also in END and CODESTART macros! */
|
||||
CODESTARTobjDestruct(nsd_gtls)
|
||||
if(pThis->iMode == 1) {
|
||||
if(pThis->bHaveSess) {
|
||||
// TODO: Check for EAGAIN et al
|
||||
gnutls_bye(pThis->sess, GNUTLS_SHUT_RDWR);
|
||||
gnutls_deinit(pThis->sess);
|
||||
}
|
||||
}
|
||||
|
||||
if(pThis->pTcp != NULL)
|
||||
nsd_ptcp.Destruct(&pThis->pTcp);
|
||||
ENDobjDestruct(nsd_gtls)
|
||||
@ -150,36 +208,82 @@ finalize_it:
|
||||
static rsRetVal
|
||||
Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
|
||||
{
|
||||
int iSent;
|
||||
nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
|
||||
DEFiRet;
|
||||
ISOBJ_TYPE_assert(pThis, nsd_gtls);
|
||||
|
||||
if(pThis->iMode == 0) {
|
||||
CHKiRet(nsd_ptcp.Send(pThis->pTcp, pBuf, pLenBuf));
|
||||
FINALIZE;
|
||||
}
|
||||
|
||||
/* in TLS mode now */
|
||||
while(1) { /* loop broken inside */
|
||||
iSent = gnutls_record_send(pThis->sess, pBuf, *pLenBuf);
|
||||
RUNLOG_VAR("%d", iSent);
|
||||
if(iSent >= 0) {
|
||||
*pLenBuf = iSent;
|
||||
break;
|
||||
}
|
||||
if(iSent != GNUTLS_E_INTERRUPTED && iSent != GNUTLS_E_AGAIN)
|
||||
ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
|
||||
}
|
||||
|
||||
finalize_it:
|
||||
RETiRet;
|
||||
}
|
||||
|
||||
|
||||
/* open a connection to a remote host (server).
|
||||
/* open a connection to a remote host (server). With GnuTLS, we always
|
||||
* open a plain tcp socket and then, if in TLS mode, do a handshake on it.
|
||||
* rgerhards, 2008-03-19
|
||||
*/
|
||||
static rsRetVal
|
||||
Connect(nsd_t *pNsd, int family, uchar *port, uchar *host)
|
||||
{
|
||||
nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
|
||||
int sock;
|
||||
int gnuRet;
|
||||
static const int cert_type_priority[3] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
|
||||
DEFiRet;
|
||||
|
||||
ISOBJ_TYPE_assert(pThis, nsd_gtls);
|
||||
assert(port != NULL);
|
||||
assert(host != NULL);
|
||||
if(pThis->iMode == 0) {
|
||||
CHKiRet(nsd_ptcp.Connect(pThis->pTcp, family, port, host));
|
||||
}
|
||||
|
||||
CHKiRet(nsd_ptcp.Connect(pThis->pTcp, family, port, host));
|
||||
|
||||
if(pThis->iMode == 0)
|
||||
FINALIZE;
|
||||
|
||||
/* we reach this point if in TLS mode */
|
||||
CHKgnutls(gnutls_init(&pThis->sess, GNUTLS_CLIENT));
|
||||
pThis->bHaveSess = 1;
|
||||
|
||||
/* Use default priorities */
|
||||
CHKgnutls(gnutls_set_default_priority(pThis->sess));
|
||||
CHKgnutls(gnutls_certificate_type_set_priority(pThis->sess, cert_type_priority));
|
||||
|
||||
/* put the x509 credentials to the current session */
|
||||
CHKgnutls(gnutls_credentials_set(pThis->sess, GNUTLS_CRD_CERTIFICATE, xcred));
|
||||
|
||||
/* assign the socket to GnuTls */
|
||||
CHKiRet(nsd_ptcp.GetSock(pThis->pTcp, &sock));
|
||||
gnutls_transport_set_ptr(pThis->sess, (gnutls_transport_ptr)sock);
|
||||
|
||||
/* and perform the handshake */
|
||||
CHKgnutls(gnutls_handshake(pThis->sess));
|
||||
dbgprintf("GnuTLS handshake succeeded\n");
|
||||
|
||||
finalize_it:
|
||||
if(iRet != RS_RET_OK) {
|
||||
if(pThis->bHaveSess) {
|
||||
gnutls_deinit(pThis->sess);
|
||||
pThis->bHaveSess = 0;
|
||||
}
|
||||
}
|
||||
|
||||
RETiRet;
|
||||
}
|
||||
|
||||
@ -212,6 +316,8 @@ ENDobjQueryInterface(nsd_gtls)
|
||||
*/
|
||||
BEGINObjClassExit(nsd_gtls, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
|
||||
CODESTARTObjClassExit(nsd_gtls)
|
||||
gtlsGlblExit(); /* shut down GnuTLS */
|
||||
|
||||
/* release objects we no longer need */
|
||||
objRelease(nsd_ptcp, LM_NSD_PTCP_FILENAME);
|
||||
objRelease(glbl, CORE_COMPONENT);
|
||||
@ -229,7 +335,8 @@ BEGINObjClassInit(nsd_gtls, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */
|
||||
CHKiRet(objUse(glbl, CORE_COMPONENT));
|
||||
CHKiRet(objUse(nsd_ptcp, LM_NSD_PTCP_FILENAME));
|
||||
|
||||
/* set our own handlers */
|
||||
/* now do global TLS init stuff */
|
||||
CHKiRet(gtlsGlblInit());
|
||||
ENDObjClassInit(nsd_gtls)
|
||||
|
||||
|
||||
|
||||
@ -33,6 +33,8 @@ 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 */
|
||||
gnutls_session sess;
|
||||
int bHaveSess;
|
||||
};
|
||||
|
||||
/* interface is defined in nsd.h, we just implement it! */
|
||||
|
||||
@ -87,6 +87,26 @@ CODESTARTobjDestruct(nsd_ptcp)
|
||||
ENDobjDestruct(nsd_ptcp)
|
||||
|
||||
|
||||
/* 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
|
||||
* TODO: what about the server socket structure?
|
||||
*/
|
||||
static rsRetVal
|
||||
GetSock(nsd_t *pNsd, int *pSock)
|
||||
{
|
||||
nsd_ptcp_t *pThis = (nsd_ptcp_t*) pNsd;
|
||||
DEFiRet;
|
||||
|
||||
ISOBJ_TYPE_assert((pThis), nsd_ptcp);
|
||||
assert(pSock != NULL);
|
||||
|
||||
*pSock = pThis->sock;
|
||||
|
||||
RETiRet;
|
||||
}
|
||||
|
||||
|
||||
/* abort a connection. This is meant to be called immediately
|
||||
* before the Destruct call. -- rgerhards, 2008-03-24
|
||||
*/
|
||||
@ -519,6 +539,7 @@ CODESTARTobjQueryInterface(nsd_ptcp)
|
||||
pIf->Construct = (rsRetVal(*)(nsd_t**)) nsd_ptcpConstruct;
|
||||
pIf->Destruct = (rsRetVal(*)(nsd_t**)) nsd_ptcpDestruct;
|
||||
pIf->Abort = Abort;
|
||||
pIf->GetSock = GetSock;
|
||||
pIf->LstnInit = LstnInit;
|
||||
pIf->AcceptConnReq = AcceptConnReq;
|
||||
pIf->Rcv = Rcv;
|
||||
|
||||
@ -209,6 +209,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
|
||||
RS_RET_INVALID_HNAME = -2075, /**< remote peer's hostname invalid or unobtainable */
|
||||
RS_RET_INVALID_PORT = -2076, /**< invalid port value */
|
||||
RS_RET_COULD_NOT_BIND = -2077, /**< could not bind socket, defunct */
|
||||
RS_RET_GNUTLS_ERR = -2078, /**< (unexpected) error in GnuTLS call */
|
||||
|
||||
/* RainerScript error messages (range 1000.. 1999) */
|
||||
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user