Blob Blame History Raw
From 02772eb5f28b3c3a98f0d739b6210ca82d58f7ee Mon Sep 17 00:00:00 2001
From: Rich Megginson <rmeggins@redhat.com>
Date: Thu, 8 Feb 2018 18:13:13 -0700
Subject: [PATCH] omelasticsearch - add support for CA cert, client cert auth

This allows omelasticsearch to perform client cert based authentication
to Elasticsearch.
Add the following parameters:
`tls.cacert` - Full path and filename of the file containing the CA cert
               for the CA that issued the Elasticsearch server(s) cert(s)
`tls.mycert` - Full path and filename of the file containing the client
               cert used to authenticate to Elasticsearch
`tls.myprivkey` - Full path and filename of the file containing the client
                  key used to authenticate to Elasticsearch
---
 plugins/omelasticsearch/omelasticsearch.c | 79 ++++++++++++++++++++++++++++---
 1 file changed, 73 insertions(+), 6 deletions(-)

diff --git a/plugins/omelasticsearch/omelasticsearch.c b/plugins/omelasticsearch/omelasticsearch.c
index 97d8fb233..88bd5e16c 100644
--- a/plugins/omelasticsearch/omelasticsearch.c
+++ b/plugins/omelasticsearch/omelasticsearch.c
@@ -110,6 +110,9 @@ typedef struct _instanceData {
 	size_t maxbytes;
 	sbool useHttps;
 	sbool allowUnsignedCerts;
+	uchar *caCertFile;
+	uchar *myCertFile;
+	uchar *myPrivKeyFile;
 } instanceData;
 
 typedef struct wrkrInstanceData {
@@ -154,7 +157,10 @@ static struct cnfparamdescr actpdescr[] = {
 	{ "template", eCmdHdlrGetWord, 0 },
 	{ "dynbulkid", eCmdHdlrBinary, 0 },
 	{ "bulkid", eCmdHdlrGetWord, 0 },
-	{ "allowunsignedcerts", eCmdHdlrBinary, 0 }
+	{ "allowunsignedcerts", eCmdHdlrBinary, 0 },
+	{ "tls.cacert", eCmdHdlrString, 0 },
+	{ "tls.mycert", eCmdHdlrString, 0 },
+	{ "tls.myprivkey", eCmdHdlrString, 0 }
 };
 static struct cnfparamblk actpblk =
 	{ CNFPARAMBLK_VERSION,
@@ -168,6 +174,9 @@ BEGINcreateInstance
 CODESTARTcreateInstance
 	pData->fdErrFile = -1;
 	pthread_mutex_init(&pData->mutErrFile, NULL);
+	pData->caCertFile = NULL;
+	pData->myCertFile = NULL;
+	pData->myPrivKeyFile = NULL;
 ENDcreateInstance
 
 BEGINcreateWrkrInstance
@@ -216,6 +225,9 @@ CODESTARTfreeInstance
 	free(pData->timeout);
 	free(pData->errorFile);
 	free(pData->bulkId);
+	free(pData->caCertFile);
+	free(pData->myCertFile);
+	free(pData->myPrivKeyFile);
 ENDfreeInstance
 
 BEGINfreeWrkrInstance
@@ -270,6 +282,9 @@ CODESTARTdbgPrintInstInfo
 	dbgprintf("\tinterleaved=%d\n", pData->interleaved);
 	dbgprintf("\tdynbulkid=%d\n", pData->dynBulkId);
 	dbgprintf("\tbulkid='%s'\n", pData->bulkId);
+	dbgprintf("\ttls.cacert='%s'\n", pData->caCertFile);
+	dbgprintf("\ttls.mycert='%s'\n", pData->myCertFile);
+	dbgprintf("\ttls.myprivkey='%s'\n", pData->myPrivKeyFile);
 ENDdbgPrintInstInfo
 
 
@@ -311,7 +326,7 @@ computeBaseUrl(const char*const serverParam,
 		r = useHttps ? es_addBuf(&urlBuf, SCHEME_HTTPS, sizeof(SCHEME_HTTPS)-1) :
 			es_addBuf(&urlBuf, SCHEME_HTTP, sizeof(SCHEME_HTTP)-1);
 
-	if (r == 0) r = es_addBuf(&urlBuf, serverParam, strlen(serverParam));
+	if (r == 0) r = es_addBuf(&urlBuf, (char *)serverParam, strlen(serverParam));
 	if (r == 0 && !strchr(host, ':')) {
 		snprintf(portBuf, sizeof(portBuf), ":%d", defaultPort);
 		r = es_addBuf(&urlBuf, portBuf, strlen(portBuf));
@@ -1296,7 +1311,7 @@ finalize_it:
 }
 
 static void
-curlCheckConnSetup(CURL *handle, HEADER *header, long timeout, sbool allowUnsignedCerts)
+curlCheckConnSetup(CURL *handle, HEADER *header, long timeout, sbool allowUnsignedCerts, wrkrInstanceData_t *pWrkrData)
 {
 	curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header);
 	curl_easy_setopt(handle, CURLOPT_NOBODY, TRUE);
@@ -1305,13 +1320,21 @@ curlCheckConnSetup(CURL *handle, HEADER *header, long timeout, sbool allowUnsign
 
 	if(allowUnsignedCerts)
 		curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, FALSE);
+	if(pWrkrData->pData->caCertFile)
+		curl_easy_setopt(handle, CURLOPT_CAINFO, pWrkrData->pData->caCertFile);
+	if(pWrkrData->pData->myCertFile)
+		curl_easy_setopt(handle, CURLOPT_SSLCERT, pWrkrData->pData->myCertFile);
+	if(pWrkrData->pData->myPrivKeyFile)
+		curl_easy_setopt(handle, CURLOPT_SSLKEY, pWrkrData->pData->myPrivKeyFile);
+	/* uncomment for in-dept debuggung:
+	curl_easy_setopt(handle, CURLOPT_VERBOSE, TRUE); */
 
 	/* Only enable for debugging
 	curl_easy_setopt(curl, CURLOPT_VERBOSE, TRUE); */
 }
 
 static void
-curlPostSetup(CURL *handle, HEADER *header, uchar* authBuf)
+curlPostSetup(CURL *handle, HEADER *header, uchar* authBuf, wrkrInstanceData_t *pWrkrData)
 {
 	curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header);
 	curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curlResult);
@@ -1322,6 +1345,12 @@ curlPostSetup(CURL *handle, HEADER *header, uchar* authBuf)
 		curl_easy_setopt(handle, CURLOPT_USERPWD, authBuf);
 		curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
 	}
+	if(pWrkrData->pData->caCertFile)
+		curl_easy_setopt(handle, CURLOPT_CAINFO, pWrkrData->pData->caCertFile);
+	if(pWrkrData->pData->myCertFile)
+		curl_easy_setopt(handle, CURLOPT_SSLCERT, pWrkrData->pData->myCertFile);
+	if(pWrkrData->pData->myPrivKeyFile)
+		curl_easy_setopt(handle, CURLOPT_SSLKEY, pWrkrData->pData->myPrivKeyFile);
 }
 
 static rsRetVal
@@ -1332,7 +1361,7 @@ curlSetup(wrkrInstanceData_t *pWrkrData, instanceData *pData)
 	if (pWrkrData->curlPostHandle == NULL) {
 		return RS_RET_OBJ_CREATION_FAILED;
 	}
-	curlPostSetup(pWrkrData->curlPostHandle, pWrkrData->curlHeader, pData->authBuf);
+	curlPostSetup(pWrkrData->curlPostHandle, pWrkrData->curlHeader, pData->authBuf, pWrkrData);
 
 	pWrkrData->curlCheckConnHandle = curl_easy_init();
 	if (pWrkrData->curlCheckConnHandle == NULL) {
@@ -1341,7 +1370,7 @@ curlSetup(wrkrInstanceData_t *pWrkrData, instanceData *pData)
 		return RS_RET_OBJ_CREATION_FAILED;
 	}
 	curlCheckConnSetup(pWrkrData->curlCheckConnHandle, pWrkrData->curlHeader,
-		pData->healthCheckTimeout, pData->allowUnsignedCerts);
+		pData->healthCheckTimeout, pData->allowUnsignedCerts, pWrkrData);
 
 	return RS_RET_OK;
 }
@@ -1372,6 +1401,9 @@ setInstParamDefaults(instanceData *pData)
 	pData->interleaved=0;
 	pData->dynBulkId= 0;
 	pData->bulkId = NULL;
+	pData->caCertFile = NULL;
+	pData->myCertFile = NULL;
+	pData->myPrivKeyFile = NULL;
 }
 
 BEGINnewActInst
@@ -1380,6 +1412,8 @@ BEGINnewActInst
 	struct cnfarray* servers = NULL;
 	int i;
 	int iNumTpls;
+	FILE *fp;
+	char errStr[1024];
 CODESTARTnewActInst
 	if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
 		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
@@ -1435,6 +1469,39 @@ CODESTARTnewActInst
 			pData->dynBulkId = pvals[i].val.d.n;
 		} else if(!strcmp(actpblk.descr[i].name, "bulkid")) {
 			pData->bulkId = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+		} else if(!strcmp(actpblk.descr[i].name, "tls.cacert")) {
+			pData->caCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+			fp = fopen((const char*)pData->caCertFile, "r");
+			if(fp == NULL) {
+				rs_strerror_r(errno, errStr, sizeof(errStr));
+				errmsg.LogError(0, RS_RET_NO_FILE_ACCESS,
+						"error: 'tls.cacert' file %s couldn't be accessed: %s\n",
+						pData->caCertFile, errStr);
+			} else {
+				fclose(fp);
+			}
+		} else if(!strcmp(actpblk.descr[i].name, "tls.mycert")) {
+			pData->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+			fp = fopen((const char*)pData->myCertFile, "r");
+			if(fp == NULL) {
+				rs_strerror_r(errno, errStr, sizeof(errStr));
+				errmsg.LogError(0, RS_RET_NO_FILE_ACCESS,
+						"error: 'tls.mycert' file %s couldn't be accessed: %s\n",
+						pData->myCertFile, errStr);
+			} else {
+				fclose(fp);
+			}
+		} else if(!strcmp(actpblk.descr[i].name, "tls.myprivkey")) {
+			pData->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+			fp = fopen((const char*)pData->myPrivKeyFile, "r");
+			if(fp == NULL) {
+				rs_strerror_r(errno, errStr, sizeof(errStr));
+				errmsg.LogError(0, RS_RET_NO_FILE_ACCESS,
+						"error: 'tls.myprivkey' file %s couldn't be accessed: %s\n",
+						pData->myPrivKeyFile, errStr);
+			} else {
+				fclose(fp);
+			}
 		} else {
 			dbgprintf("omelasticsearch: program error, non-handled "
 			  "param '%s'\n", actpblk.descr[i].name);
-- 
2.14.3