summaryrefslogtreecommitdiffstats
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
parent87c1125e74fd9ac40def2166d4c393afc5ae9a37 (diff)
downloadrsyslog-4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7.tar.gz
rsyslog-4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7.tar.xz
rsyslog-4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7.zip
applied gssapi patch from varmojfekoj - gss-api is now supported
-rw-r--r--Makefile.am6
-rw-r--r--cfsysline.c1
-rw-r--r--configure.ac22
-rw-r--r--omfwd.c370
-rw-r--r--syslogd.c71
-rw-r--r--tcpsyslog.c187
-rw-r--r--tcpsyslog.h19
7 files changed, 600 insertions, 76 deletions
diff --git a/Makefile.am b/Makefile.am
index e9373843..b8c19c1c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -58,10 +58,12 @@ rsyslogd_SOURCES = \
iminternal.c \
iminternal.h \
action.c \
- action.h
+ action.h \
+ gss-misc.c \
+ gss-misc.h
rsyslogd_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/\"
-rsyslogd_LDADD = $(zlib_libs) $(pthreads_libs) -ldl
+rsyslogd_LDADD = $(zlib_libs) $(pthreads_libs) $(gss_libs) -ldl
rsyslogd_LDFLAGS = -export-dynamic
man_MANS = rfc3195d.8 rklogd.8 rsyslogd.8 rsyslog.conf.5
diff --git a/cfsysline.c b/cfsysline.c
index 9b3c703d..8a61c7ef 100644
--- a/cfsysline.c
+++ b/cfsysline.c
@@ -376,6 +376,7 @@ static rsRetVal doGetWord(uchar **pp, rsRetVal (*pSetHdlr)(void*, uchar*), void
CHKiRet(rsCStrFinish(pStrB));
CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, &pNewVal, 0));
+ pStrB = NULL;
/* we got the word, now set it */
if(pSetHdlr == NULL) {
diff --git a/configure.ac b/configure.ac
index e542591a..f146259d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,6 +123,27 @@ if test "$enable_zlib" = "yes"; then
fi
fi
+#gssapi
+AC_ARG_ENABLE(gssapi_krb5,
+ [AS_HELP_STRING([--enable-gssapi-krb5],[Enable GSSAPI Kerberos 5 support @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) want_gssapi_krb5="yes" ;;
+ no) want_gssapi_krb5="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-gssapi-krb5) ;;
+ esac],
+ [want_gssapi_krb5=no]
+)
+if test $want_gssapi_krb5 = yes; then
+ AC_CHECK_LIB(gssapi_krb5, gss_acquire_cred, [
+ AC_CHECK_HEADER(gssapi/gssapi.h, [
+ AC_DEFINE(USE_GSSAPI,,
+ Define if you want to use GSSAPI)
+ gss_libs="-lgssapi_krb5"
+ AC_SUBST(gss_libs)
+ ])
+ ])
+fi
+
# multithreading via pthreads
AC_ARG_ENABLE(pthreads,
[AS_HELP_STRING([--enable-pthreads],[Enable multithreading via pthreads @<:@default=yes@:>@])],
@@ -292,5 +313,6 @@ echo "Zlib compression support enabled: $enable_zlib"
echo "MySql support enabled: $enable_mysql"
echo "Large file support enabled: $enable_largefile"
echo "Networking support enabled: $enable_inet"
+echo "Enable GSSAPI Kerberos 5 support: $want_gssapi_krb5"
echo "Debug mode enabled: $enable_debug"
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 */
diff --git a/syslogd.c b/syslogd.c
index a7ca44d1..144f11d8 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -655,6 +655,12 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
#ifdef USE_PTHREADS
iMainMsgQueueSize = 10000;
#endif
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+ if (gss_listen_service_name != NULL) {
+ free(gss_listen_service_name);
+ gss_listen_service_name = NULL;
+ }
+#endif
return RS_RET_OK;
}
@@ -4458,6 +4464,14 @@ static void init(void)
* need to do that, I recommend controlling that via a
* user-selectable option. rgerhards, 2007-06-21
*/
+# ifdef USE_GSSAPI
+ if(bEnableTCP == 2) {
+ if(TCPSessGSSInit()) {
+ logerror("GSS-API initialization failed\n");
+ bEnableTCP = -1;
+ }
+ }
+# endif
if((sockTCPLstn = create_tcp_socket()) != NULL) {
dbgprintf("Opened %d syslog TCP port(s).\n", *sockTCPLstn);
}
@@ -5693,7 +5707,12 @@ static rsRetVal processSelectAfter(int maxfds, int nfds, fd_set *pReadfds, fd_se
for (i = 0; i < *sockTCPLstn; i++) {
if (FD_ISSET(sockTCPLstn[i+1], pReadfds)) {
dbgprintf("New connect on TCP inetd socket: #%d\n", sockTCPLstn[i+1]);
- TCPSessAccept(sockTCPLstn[i+1]);
+# ifdef USE_GSSAPI
+ if(bEnableTCP == 2)
+ TCPSessGSSAccept(sockTCPLstn[i+1]);
+ else
+# endif
+ TCPSessAccept(sockTCPLstn[i+1]);
FDPROCESSED();
}
}
@@ -5709,16 +5728,34 @@ static rsRetVal processSelectAfter(int maxfds, int nfds, fd_set *pReadfds, fd_se
dbgprintf("tcp session socket with new data: #%d\n", fdSess);
/* Receive message */
- state = recv(fdSess, buf, sizeof(buf), 0);
+# ifdef USE_GSSAPI
+ if(bEnableTCP == 2)
+ state = TCPSessGSSRecv(iTCPSess, buf, sizeof(buf));
+ else
+# endif
+ state = recv(fdSess, buf, sizeof(buf), 0);
if(state == 0) {
- /* process any incomplete frames left over */
- TCPSessPrepareClose(iTCPSess);
- /* Session closed */
- TCPSessClose(iTCPSess);
+# ifdef USE_GSSAPI
+ if(bEnableTCP == 2)
+ TCPSessGSSClose(iTCPSess);
+ else {
+# endif
+ /* process any incomplete frames left over */
+ TCPSessPrepareClose(iTCPSess);
+ /* Session closed */
+ TCPSessClose(iTCPSess);
+# ifdef USE_GSSAPI
+ }
+# endif
} else if(state == -1) {
logerrorInt("TCP session %d will be closed, error ignored\n",
fdSess);
- TCPSessClose(iTCPSess);
+# ifdef USE_GSSAPI
+ if(bEnableTCP == 2)
+ TCPSessGSSClose(iTCPSess);
+ else
+# endif
+ TCPSessClose(iTCPSess);
} else {
/* valid data received, process it! */
if(TCPSessDataRcvd(iTCPSess, buf, state) == 0) {
@@ -5728,7 +5765,12 @@ static rsRetVal processSelectAfter(int maxfds, int nfds, fd_set *pReadfds, fd_se
logerrorInt("Tearing down TCP Session %d - see "
"previous messages for reason(s)\n",
iTCPSess);
- TCPSessClose(iTCPSess);
+# ifdef USE_GSSAPI
+ if(bEnableTCP == 2)
+ TCPSessGSSClose(iTCPSess);
+ else
+# endif
+ TCPSessClose(iTCPSess);
}
}
FDPROCESSED();
@@ -6010,6 +6052,9 @@ static rsRetVal loadBuildInModules(void)
NULL, &bDebugPrintCfSysLineHandlerList));
CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir));
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL));
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+ CHKiRet(regCfSysLineHdlr((uchar *)"gsslistenservicename", 0, eCmdHdlrGetWord, NULL, &gss_listen_service_name));
+#endif
finalize_it:
return iRet;
@@ -6156,7 +6201,7 @@ int main(int argc, char **argv)
/* END core initializations */
- while ((ch = getopt(argc, argv, "46Aa:dehi:f:l:m:nop:r::s:t:u:vwx")) != EOF) {
+ while ((ch = getopt(argc, argv, "46Aa:dehi:f:g:l:m:nop:r::s:t:u:vwx")) != EOF) {
switch((char)ch) {
case '4':
family = PF_INET;
@@ -6189,6 +6234,14 @@ int main(int argc, char **argv)
case 'f': /* configuration file */
ConfFile = (uchar*) optarg;
break;
+ case 'g': /* enable tcp gssapi logging */
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+ configureTCPListen(optarg);
+ bEnableTCP = 2;
+#else
+ fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support");
+#endif
+ break;
case 'h':
NoHops = 0;
break;
diff --git a/tcpsyslog.c b/tcpsyslog.c
index d2a4b724..c2591663 100644
--- a/tcpsyslog.c
+++ b/tcpsyslog.c
@@ -42,10 +42,15 @@
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
-
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+#include <gssapi.h>
+#endif
#include "syslogd.h"
#include "syslogd-types.h"
#include "net.h"
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+#include "gss-misc.h"
+#endif
#include "tcpsyslog.h"
/********************************************************************
* ### SYSLOG/TCP CODE ###
@@ -71,7 +76,10 @@ int bEnableTCP = 0; /* read-only after startup */
int *sockTCPLstn = NULL; /* read-only after startup, modified by restart */
struct TCPSession *pTCPSessions;
/* The thread-safeness of the sesion table is doubtful */
-
+#ifdef USE_GSSAPI
+static gss_cred_id_t gss_server_creds;
+char *gss_listen_service_name = NULL;
+#endif
/* configure TCP listener settings. This is called during command
* line parsing. The argument following -t is supplied as an argument.
@@ -155,6 +163,10 @@ static int TCPSessInit(void)
pTCPSessions[i].iMsg = 0; /* just make sure... */
pTCPSessions[i].bAtStrtOfFram = 1; /* indicate frame header expected */
pTCPSessions[i].eFraming = TCP_FRAMING_OCTET_STUFFING; /* just make sure... */
+#ifdef USE_GSSAPI
+ pTCPSessions[i].gss_flags = 0;
+ pTCPSessions[i].gss_context = GSS_C_NO_CONTEXT;
+#endif
}
return(0);
}
@@ -215,6 +227,15 @@ void deinit_tcp_listener(void)
fd = pTCPSessions[iTCPSess].sock;
dbgprintf("Closing TCP Session %d\n", fd);
close(fd);
+ free(pTCPSessions[iTCPSess].fromHost);
+#ifdef USE_GSSAPI
+ if(bEnableTCP == 2) {
+ OM_uint32 maj_stat, min_stat;
+ maj_stat = gss_delete_sec_context(&min_stat, &pTCPSessions[iTCPSess].gss_context, GSS_C_NO_BUFFER);
+ if (maj_stat != GSS_S_COMPLETE)
+ display_status("deleting context", maj_stat, min_stat);
+ }
+#endif
/* now get next... */
iTCPSess = TCPSessGetNxtSess(iTCPSess);
}
@@ -389,7 +410,7 @@ int *create_tcp_socket(void)
* is no more space left in the connection table, the new TCP
* connection is immediately dropped.
*/
-void TCPSessAccept(int fd)
+int TCPSessAccept(int fd)
{
int newConn;
int iSess;
@@ -403,7 +424,7 @@ void TCPSessAccept(int fd)
newConn = accept(fd, (struct sockaddr*) &addr, &addrlen);
if (newConn < 0) {
logerror("tcp accept, ignoring error and connection request");
- return;
+ return -1;
}
/* Add to session list */
@@ -412,7 +433,7 @@ void TCPSessAccept(int fd)
errno = 0;
logerror("too many tcp sessions - dropping incoming request");
close(newConn);
- return;
+ return -1;
}
/* OK, we have a "good" index... */
@@ -423,7 +444,7 @@ void TCPSessAccept(int fd)
* Error message has been generated by cvthname.
*/
close (newConn);
- return;
+ return -1;
}
/* Here we check if a host is permitted to send us
@@ -439,7 +460,7 @@ void TCPSessAccept(int fd)
(char*)fromHost);
}
close(newConn);
- return;
+ return -1;
}
/* OK, we have an allowed sender, so let's continue */
@@ -454,6 +475,7 @@ void TCPSessAccept(int fd)
pTCPSessions[iSess].sock = newConn;
pTCPSessions[iSess].iMsg = 0; /* init msg buffer! */
+ return iSess;
}
@@ -678,6 +700,157 @@ int TCPSessDataRcvd(int iTCPSess, char *pData, int iLen)
}
+#ifdef USE_GSSAPI
+int TCPSessGSSInit(void)
+{
+ gss_buffer_desc name_buf;
+ gss_name_t server_name;
+ OM_uint32 maj_stat, min_stat;
+
+ name_buf.value = (gss_listen_service_name == NULL) ? "host" : gss_listen_service_name;
+ name_buf.length = strlen(name_buf.value) + 1;
+ maj_stat = gss_import_name(&min_stat, &name_buf, GSS_C_NT_HOSTBASED_SERVICE, &server_name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("importing name", maj_stat, min_stat);
+ return -1;
+ }
+
+ maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
+ GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+ &gss_server_creds, NULL, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("acquiring credentials", maj_stat, min_stat);
+ return -1;
+ }
+
+ gss_release_name(&min_stat, &server_name);
+ dbgprintf("GSS-API initialized\n");
+ return 0;
+}
+
+
+int TCPSessGSSAccept(int fd)
+{
+ gss_buffer_desc send_tok, recv_tok;
+ gss_name_t client;
+ gss_OID doid;
+ OM_uint32 maj_stat, min_stat, acc_sec_min_stat;
+ int iSess;
+ gss_ctx_id_t *context;
+ OM_uint32 *sess_flags;
+ int fdSess;
+
+ if ((iSess = TCPSessAccept(fd)) == -1)
+ return -1;
+
+ context = &pTCPSessions[iSess].gss_context;
+ *context = GSS_C_NO_CONTEXT;
+ sess_flags = &pTCPSessions[iSess].gss_flags;
+ fdSess = pTCPSessions[iSess].sock;
+
+ do {
+ if (recv_token(fdSess, &recv_tok) <= 0)
+ return -1;
+
+ maj_stat = gss_accept_sec_context(&acc_sec_min_stat, context, gss_server_creds,
+ &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &client,
+ NULL, &send_tok, sess_flags, NULL, NULL);
+ if (recv_tok.value) {
+ free(recv_tok.value);
+ recv_tok.value = NULL;
+ }
+ if (send_tok.length != 0) {
+ if (send_token(fdSess, &send_tok) < 0) {
+ return -1;
+ }
+
+ gss_release_buffer(&min_stat, &send_tok);
+ }
+ if (maj_stat != GSS_S_COMPLETE
+ && maj_stat != GSS_S_CONTINUE_NEEDED) {
+ display_status("accepting context", maj_stat,
+ acc_sec_min_stat);
+ if (*context != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&min_stat, context,
+ GSS_C_NO_BUFFER);
+ return -1;
+ }
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+ maj_stat = gss_display_name(&min_stat, client, &recv_tok, NULL);
+ if (maj_stat != GSS_S_COMPLETE)
+ display_status("displaying name", maj_stat, min_stat);
+ gss_release_name(&min_stat, &client);
+
+ dbgprintf("GSS-API Accepted connection from: %s\n", recv_tok.value);
+ gss_release_buffer(&min_stat, &recv_tok);
+
+ dbgprintf("GSS-API Provided context flags:\n");
+ display_ctx_flags(*sess_flags);
+
+ return 0;
+}
+
+
+int TCPSessGSSRecv(int iSess, void *buf, size_t buf_len)
+{
+ gss_buffer_desc xmit_buf, msg_buf;
+ gss_ctx_id_t *context;
+ OM_uint32 maj_stat, min_stat;
+ int fdSess;
+ int conf_state;
+ int state, len;
+
+ fdSess = pTCPSessions[iSess].sock;
+ if ((state = recv_token(fdSess, &xmit_buf)) <= 0)
+ return state;
+
+ context = &pTCPSessions[iSess].gss_context;
+ maj_stat = gss_unwrap(&min_stat, *context, &xmit_buf, &msg_buf,
+ &conf_state, (gss_qop_t *) NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("unsealing message", maj_stat, min_stat);
+ if (xmit_buf.value) {
+ free(xmit_buf.value);
+ xmit_buf.value = 0;
+ }
+ return (-1);
+ }
+ if (xmit_buf.value) {
+ free(xmit_buf.value);
+ xmit_buf.value = 0;
+ }
+
+ len = msg_buf.length < buf_len ? msg_buf.length : buf_len;
+ memcpy(buf, msg_buf.value, len);
+ gss_release_buffer(&min_stat, &msg_buf);
+
+ return len;
+}
+
+
+void TCPSessGSSClose(int iSess) {
+ OM_uint32 maj_stat, min_stat;
+ gss_ctx_id_t *context;
+
+ if(iSess < 0 || iSess > iTCPSessMax) {
+ errno = 0;
+ logerror("internal error, trying to close an invalid TCP session!");
+ return;
+ }
+
+ context = &pTCPSessions[iSess].gss_context;
+ maj_stat = gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER);
+ if (maj_stat != GSS_S_COMPLETE)
+ display_status("deleting context", maj_stat, min_stat);
+ *context = GSS_C_NO_CONTEXT;
+ pTCPSessions[iSess].gss_flags = 0;
+
+ TCPSessClose(iSess);
+}
+#endif /* #ifdef USE_GSSAPI */
+
+
#endif
/********************************************************************
* ### END OF SYSLOG/TCP CODE ###
diff --git a/tcpsyslog.h b/tcpsyslog.h
index 1cead1aa..f8e2fa94 100644
--- a/tcpsyslog.h
+++ b/tcpsyslog.h
@@ -24,6 +24,10 @@
#ifndef TCPSYSLOG_H_INCLUDED
#define TCPSYSLOG_H_INCLUDED 1
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+#include <gssapi.h>
+#endif
+
struct TCPSession {
int sock;
int iMsg; /* index of next char to store in msg */
@@ -32,6 +36,10 @@ struct TCPSession {
TCPFRAMINGMODE eFraming;
char msg[MAXLINE+1];
char *fromHost;
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+ OM_uint32 gss_flags;
+ gss_ctx_id_t gss_context;
+#endif
};
/* static data */
@@ -39,16 +47,25 @@ extern int *sockTCPLstn;
extern char *TCPLstnPort;
extern int bEnableTCP;
extern struct TCPSession *pTCPSessions;
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+extern char *gss_listen_service_name;
+#endif
/* prototypes */
void deinit_tcp_listener(void);
int *create_tcp_socket(void);
int TCPSessGetNxtSess(int iCurr);
-void TCPSessAccept(int fd);
+int TCPSessAccept(int fd);
void TCPSessPrepareClose(int iTCPSess);
void TCPSessClose(int iSess);
int TCPSessDataRcvd(int iTCPSess, char *pData, int iLen);
void configureTCPListen(char *cOptarg);
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+int TCPSessGSSInit(void);
+int TCPSessGSSAccept(int fd);
+int TCPSessGSSRecv(int fd, void *buf, size_t buf_len);
+void TCPSessGSSClose(int sess);
+#endif
#endif /* #ifndef TCPSYSLOG_H_INCLUDED */
/*