summaryrefslogtreecommitdiffstats
path: root/omfwd.c
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2007-11-19 10:03:32 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2007-11-19 10:03:32 +0000
commit4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7 (patch)
tree6f72296a5330b10a7bde56ba7af4943355b827e2 /omfwd.c
parent87c1125e74fd9ac40def2166d4c393afc5ae9a37 (diff)
downloadrsyslog-4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7.tar.gz
rsyslog-4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7.tar.xz
rsyslog-4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7.zip
applied gssapi patch from varmojfekoj - gss-api is now supported
Diffstat (limited to 'omfwd.c')
-rw-r--r--omfwd.c370
1 files changed, 313 insertions, 57 deletions
diff --git a/omfwd.c b/omfwd.c
index 07ff7ac2..49c59fa3 100644
--- a/omfwd.c
+++ b/omfwd.c
@@ -48,6 +48,9 @@
#else
#include <fcntl.h>
#endif
+#ifdef USE_GSSAPI
+#include <gssapi.h>
+#endif
#include "syslogd.h"
#include "syslogd-types.h"
#include "srUtils.h"
@@ -56,7 +59,11 @@
#include "template.h"
#include "msg.h"
#include "tcpsyslog.h"
+#include "cfsysline.h"
#include "module-template.h"
+#ifdef USE_GSSAPI
+#include "gss-misc.h"
+#endif
#ifdef SYSLOG_INET
//#define INET_SUSPEND_TIME 60 /* equal to 1 minute
@@ -108,8 +115,21 @@ typedef struct _instanceData {
# ifdef USE_PTHREADS
pthread_mutex_t mtxTCPSend;
# endif
+# ifdef USE_GSSAPI
+ gss_ctx_id_t gss_context;
+ OM_uint32 gss_flags;
+# endif
} instanceData;
+#ifdef USE_GSSAPI
+static char *gss_base_service_name = NULL;
+static enum gss_mode_t {
+ GSSMODE_NONE,
+ GSSMODE_MIC,
+ GSSMODE_ENC
+} gss_mode;
+#endif
+
BEGINcreateInstance
CODESTARTcreateInstance
@@ -141,6 +161,24 @@ CODESTARTfreeInstance
pthread_mutex_destroy(&pData->mtxTCPSend);
}
# endif
+# ifdef USE_GSSAPI
+ if (gss_mode != GSSMODE_NONE) {
+ OM_uint32 maj_stat, min_stat;
+
+ if (pData->gss_context != GSS_C_NO_CONTEXT) {
+ maj_stat = gss_delete_sec_context(&min_stat, pData->gss_context, GSS_C_NO_BUFFER);
+ if (maj_stat != GSS_S_COMPLETE)
+ display_status("deleting context", maj_stat, min_stat);
+ }
+ }
+ /* this is meant to be done when module is unloaded,
+ but since this module is static...
+ */
+ if (gss_base_service_name != NULL) {
+ free(gss_base_service_name);
+ gss_base_service_name = NULL;
+ }
+# endif
ENDfreeInstance
@@ -256,6 +294,153 @@ static int TCPSendCreateSocket(instanceData *pData, struct addrinfo *addrDest)
return -1;
}
+
+#ifdef USE_GSSAPI
+static int TCPSendGSSInit(instanceData *pData)
+{
+ int s = -1;
+ char *base;
+ OM_uint32 maj_stat, min_stat, init_sec_min_stat, *sess_flags, ret_flags;
+ gss_buffer_desc out_tok, in_tok;
+ gss_buffer_t tok_ptr;
+ gss_name_t target_name;
+ gss_ctx_id_t *context;
+
+ assert(pData != NULL);
+
+ base = (gss_base_service_name == NULL) ? "host" : gss_base_service_name;
+ out_tok.length = strlen(pData->f_hname) + strlen(base) + 2;
+ if ((out_tok.value = malloc(out_tok.length)) == NULL)
+ return -1;
+ strcpy(out_tok.value, base);
+ strcat(out_tok.value, "@");
+ strcat(out_tok.value, pData->f_hname);
+ dbgprintf("GSS-API service name: %s\n", out_tok.value);
+
+ tok_ptr = GSS_C_NO_BUFFER;
+ context = &pData->gss_context;
+ *context = GSS_C_NO_CONTEXT;
+
+ maj_stat = gss_import_name(&min_stat, &out_tok, GSS_C_NT_HOSTBASED_SERVICE, &target_name);
+ free(out_tok.value);
+ out_tok.value = NULL;
+ out_tok.length = 0;
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("parsing name", maj_stat, min_stat);
+ goto fail;
+ }
+
+ sess_flags = &pData->gss_flags;
+ *sess_flags = GSS_C_MUTUAL_FLAG;
+ if (gss_mode == GSSMODE_MIC) {
+ *sess_flags |= GSS_C_INTEG_FLAG;
+ }
+ if (gss_mode == GSSMODE_ENC) {
+ *sess_flags |= GSS_C_CONF_FLAG;
+ }
+ dbgprintf("GSS-API requested context flags:\n");
+ display_ctx_flags(*sess_flags);
+
+ do {
+ maj_stat = gss_init_sec_context(&init_sec_min_stat, GSS_C_NO_CREDENTIAL, context,
+ target_name, GSS_C_NO_OID, *sess_flags, 0, NULL,
+ tok_ptr, NULL, &out_tok, &ret_flags, NULL);
+ if (tok_ptr != GSS_C_NO_BUFFER)
+ free(in_tok.value);
+
+ if (maj_stat != GSS_S_COMPLETE
+ && maj_stat != GSS_S_CONTINUE_NEEDED) {
+ display_status("initializing context", maj_stat, init_sec_min_stat);
+ goto fail;
+ }
+
+ if (s == -1)
+ if ((s = pData->sock = TCPSendCreateSocket(pData, pData->f_addr)) == -1)
+ goto fail;
+
+ if (out_tok.length != 0) {
+ dbgprintf("GSS-API Sending init_sec_context token (length: %d)\n", out_tok.length);
+ if (send_token(s, &out_tok) < 0) {
+ goto fail;
+ }
+ }
+ gss_release_buffer(&min_stat, &out_tok);
+
+ if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+ dbgprintf("GSS-API Continue needed...\n");
+ if (recv_token(s, &in_tok) <= 0) {
+ goto fail;
+ }
+ tok_ptr = &in_tok;
+ }
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+ dbgprintf("GSS-API Provided context flags:\n");
+ *sess_flags = ret_flags;
+ display_ctx_flags(*sess_flags);
+
+ dbgprintf("GSS-API Context initialized\n");
+ gss_release_name(&min_stat, &target_name);
+
+ return 0;
+
+ fail:
+ logerror("GSS-API Context initialization failed\n");
+ gss_release_name(&min_stat, &target_name);
+ gss_release_buffer(&min_stat, &out_tok);
+ if (*context != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER);
+ *context = GSS_C_NO_CONTEXT;
+ }
+ if (s != -1)
+ close(s);
+ pData->sock = -1;
+ return -1;
+}
+
+
+static int TCPSendGSSSend(instanceData *pData, char *msg, size_t len)
+{
+ int s;
+ gss_ctx_id_t *context;
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc in_buf, out_buf;
+
+ assert(pData != NULL);
+ assert(msg != NULL);
+ assert(len > 0);
+
+ s = pData->sock;
+ context = &pData->gss_context;
+ in_buf.value = msg;
+ in_buf.length = len;
+ maj_stat = gss_wrap(&min_stat, *context, (gss_mode == GSSMODE_ENC) ? 1 : 0, GSS_C_QOP_DEFAULT,
+ &in_buf, NULL, &out_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("wrapping message", maj_stat, min_stat);
+ goto fail;
+ }
+
+ if (send_token(s, &out_buf) < 0) {
+ goto fail;
+ }
+ gss_release_buffer(&min_stat, &out_buf);
+
+ return 0;
+
+ fail:
+ close(s);
+ pData->sock = -1;
+ TCPSendSetStatus(pData, TCP_SEND_NOTCONNECTED);
+ gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER);
+ *context = GSS_C_NO_CONTEXT;
+ gss_release_buffer(&min_stat, &out_buf);
+ return -1;
+}
+#endif /* #ifdef USE_GSSAPI */
+
+
/* Sends a TCP message. It is first checked if the
* session is open and, if not, it is opened. Then the send
* is tried. If it fails, one silent re-try is made. If the send
@@ -314,9 +499,14 @@ static int TCPSend(instanceData *pData, char *msg, size_t len)
do { /* try to send message */
if(pData->sock <= 0) {
/* we need to open the socket first */
- if((pData->sock = TCPSendCreateSocket(pData, pData->f_addr)) <= 0) {
- return -1;
- }
+# ifdef USE_GSSAPI
+ if(gss_mode != GSSMODE_NONE) {
+ if(TCPSendGSSInit(pData) != 0)
+ return -1;
+ } else
+# endif
+ if((pData->sock = TCPSendCreateSocket(pData, pData->f_addr)) <= 0)
+ return -1;
}
eState = TCPSendGetStatus(pData); /* cache info */
@@ -447,68 +637,91 @@ static int TCPSend(instanceData *pData, char *msg, size_t len)
}
/* frame building complete, on to actual sending */
-
- lenSend = send(pData->sock, msg, len, 0);
- dbgprintf("TCP sent %d bytes, requested %d, msg: '%s'\n", lenSend, len,
- bIsCompressed ? "***compressed***" : msg);
- if((unsigned)lenSend == len) {
- /* all well */
- if(buf != NULL) {
- free(buf);
+# ifdef USE_GSSAPI
+ if(gss_mode != GSSMODE_NONE) {
+ if(TCPSendGSSSend(pData, msg, len) == 0) {
+ if(buf != NULL) {
+ free(buf);
+ }
+ return 0;
+ } else {
+ if(retry == 0) {
+ ++retry;
+ /* try to recover */
+ continue;
+ } else {
+ if(buf != NULL)
+ free(buf);
+ dbgprintf("message not (tcp)send");
+ return -1;
+ }
}
- return 0;
- } else if(lenSend != -1) {
- /* no real error, could "just" not send everything...
- * For the time being, we ignore this...
- * rgerhards, 2005-10-25
- */
- dbgprintf("message not completely (tcp)send, ignoring %d\n", lenSend);
+ } else {
+# endif
+ lenSend = send(pData->sock, msg, len, 0);
+ dbgprintf("TCP sent %d bytes, requested %d, msg: '%s'\n", lenSend, len,
+ bIsCompressed ? "***compressed***" : msg);
+ if((unsigned)lenSend == len) {
+ /* all well */
+ if(buf != NULL) {
+ free(buf);
+ }
+ return 0;
+ } else if(lenSend != -1) {
+ /* no real error, could "just" not send everything...
+ * For the time being, we ignore this...
+ * rgerhards, 2005-10-25
+ */
+ dbgprintf("message not completely (tcp)send, ignoring %d\n", lenSend);
# if USE_PTHREADS
- usleep(1000); /* experimental - might be benefitial in this situation */
+ usleep(1000); /* experimental - might be benefitial in this situation */
# endif
- if(buf != NULL)
- free(buf);
- return 0;
- }
+ if(buf != NULL)
+ free(buf);
+ return 0;
+ }
- switch(errno) {
- case EMSGSIZE:
- dbgprintf("message not (tcp)send, too large\n");
- /* This is not a real error, so it is not flagged as one */
- if(buf != NULL)
- free(buf);
- return 0;
- break;
- case EINPROGRESS:
- case EAGAIN:
- dbgprintf("message not (tcp)send, would block\n");
+ switch(errno) {
+ case EMSGSIZE:
+ dbgprintf("message not (tcp)send, too large\n");
+ /* This is not a real error, so it is not flagged as one */
+ if(buf != NULL)
+ free(buf);
+ return 0;
+ break;
+ case EINPROGRESS:
+ case EAGAIN:
+ dbgprintf("message not (tcp)send, would block\n");
# if USE_PTHREADS
- usleep(1000); /* experimental - might be benefitial in this situation */
+ usleep(1000); /* experimental - might be benefitial in this situation */
# endif
- /* we loose this message, but that's better than loosing
- * all ;)
- */
- /* This is not a real error, so it is not flagged as one */
- if(buf != NULL)
- free(buf);
- return 0;
- break;
- default:
- dbgprintf("message not (tcp)send");
- break;
- }
+ /* we loose this message, but that's better than loosing
+ * all ;)
+ */
+ /* This is not a real error, so it is not flagged as one */
+ if(buf != NULL)
+ free(buf);
+ return 0;
+ break;
+ default:
+ dbgprintf("message not (tcp)send");
+ break;
+ }
- if(retry == 0) {
- ++retry;
- /* try to recover */
- close(pData->sock);
- TCPSendSetStatus(pData, TCP_SEND_NOTCONNECTED);
- pData->sock = -1;
- } else {
- if(buf != NULL)
- free(buf);
- return -1;
+ if(retry == 0) {
+ ++retry;
+ /* try to recover */
+ close(pData->sock);
+ TCPSendSetStatus(pData, TCP_SEND_NOTCONNECTED);
+ pData->sock = -1;
+ } else {
+ if(buf != NULL)
+ free(buf);
+ return -1;
+ }
+# ifdef USE_GSSAPI
}
+# endif
} while(!done); /* warning: do ... while() */
/*NOT REACHED*/
@@ -703,6 +916,7 @@ CODESTARTdoAction
if(TCPSend(pData, psz, l) != 0) {
/* error! */
dbgprintf("error forwarding via tcp, suspending\n");
+ pData->eDestState = eDestFORW_SUSP;
iRet = RS_RET_SUSPENDED;
}
}
@@ -921,10 +1135,52 @@ CODEqueryEtryPt_STD_OMOD_QUERIES
ENDqueryEtryPt
+#ifdef USE_GSSAPI
+static rsRetVal setGSSMode(void *pVal, uchar *mode)
+{
+ if (!strcmp((char *) mode, "none")) {
+ gss_mode = GSSMODE_NONE;
+ free(mode);
+ dbgprintf("GSS-API gssmode set to GSSMODE_NONE\n");
+ } else if (!strcmp((char *) mode, "integrity")) {
+ gss_mode = GSSMODE_MIC;
+ free(mode);
+ dbgprintf("GSS-API gssmode set to GSSMODE_MIC\n");
+ } else if (!strcmp((char *) mode, "encryption")) {
+ gss_mode = GSSMODE_ENC;
+ free(mode);
+ dbgprintf("GSS-API gssmode set to GSSMODE_ENC\n");
+ } else {
+ logerrorSz("unknown gssmode parameter: %s", (char *) mode);
+ free(mode);
+ return RS_RET_ERR;
+ }
+
+ return RS_RET_OK;
+}
+
+
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ gss_mode = GSSMODE_NONE;
+ if (gss_base_service_name != NULL) {
+ free(gss_base_service_name);
+ gss_base_service_name = NULL;
+ }
+ return RS_RET_OK;
+}
+#endif /* #ifdef USE_GSSAPI */
+
+
BEGINmodInit(Fwd)
CODESTARTmodInit
*ipIFVersProvided = 1; /* so far, we only support the initial definition */
CODEmodInit_QueryRegCFSLineHdlr
+# ifdef USE_GSSAPI
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"gssforwardservicename", 0, eCmdHdlrGetWord, NULL, &gss_base_service_name));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"gssmode", 0, eCmdHdlrGetWord, setGSSMode, &gss_mode));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL));
+# endif
ENDmodInit
#endif /* #ifdef SYSLOG_INET */