diff -up rsyslog/omfwd.c.orig rsyslog/omfwd.c --- rsyslog/omfwd.c.orig 2007-10-23 09:31:00.000000000 +0200 +++ rsyslog/omfwd.c 2007-11-14 16:03:31.000000000 +0100 @@ -48,6 +48,9 @@ #else #include #endif +#ifdef USE_GSSAPI +#include +#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(instanceD 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, 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, } /* 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 -up rsyslog/Makefile.am.orig rsyslog/Makefile.am --- rsyslog/Makefile.am.orig 2007-10-25 11:10:52.000000000 +0200 +++ rsyslog/Makefile.am 2007-11-01 12:13:03.000000000 +0100 @@ -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 -up rsyslog/configure.ac.orig rsyslog/configure.ac --- rsyslog/configure.ac.orig 2007-10-25 11:16:57.000000000 +0200 +++ rsyslog/configure.ac 2007-10-25 11:20:48.000000000 +0200 @@ -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: 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 -up rsyslog/tcpsyslog.c.orig rsyslog/tcpsyslog.c --- rsyslog/tcpsyslog.c.orig 2007-10-30 09:21:06.000000000 +0100 +++ rsyslog/tcpsyslog.c 2007-11-14 16:03:46.000000000 +0100 @@ -42,10 +42,15 @@ #if HAVE_FCNTL_H #include #endif - +#if defined(SYSLOG_INET) && defined(USE_GSSAPI) +#include +#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 s 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 * } +#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 -up rsyslog/tcpsyslog.h.orig rsyslog/tcpsyslog.h --- rsyslog/tcpsyslog.h.orig 2007-10-30 14:51:47.000000000 +0100 +++ rsyslog/tcpsyslog.h 2007-11-08 12:05:05.000000000 +0100 @@ -24,6 +24,10 @@ #ifndef TCPSYSLOG_H_INCLUDED #define TCPSYSLOG_H_INCLUDED 1 +#if defined(SYSLOG_INET) && defined(USE_GSSAPI) +#include +#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 */ /* diff -up rsyslog/gss-misc.h.orig rsyslog/gss-misc.h --- rsyslog/gss-misc.h.orig 2007-10-30 19:11:20.000000000 +0100 +++ rsyslog/gss-misc.h 2007-11-08 12:08:51.000000000 +0100 @@ -0,0 +1,11 @@ +#ifndef GSS_MISC_H_INCLUDED +#define GSS_MISC_H_INCLUDED 1 + +#include + +int recv_token(int s, gss_buffer_t tok); +int send_token(int s, gss_buffer_t tok); +void display_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat); +void display_ctx_flags(OM_uint32 flags); + +#endif /* #ifndef GSS_MISC_H_INCLUDED */ diff -up rsyslog/syslogd.c.orig rsyslog/syslogd.c --- rsyslog/syslogd.c.orig 2007-11-01 10:56:37.000000000 +0100 +++ rsyslog/syslogd.c 2007-11-08 13:17:12.000000000 +0100 @@ -655,6 +655,12 @@ static rsRetVal resetConfigVariables(uch #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 m 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 m 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 m 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 -up rsyslog/omfwd.h.orig rsyslog/omfwd.h diff -up rsyslog/gss-misc.c.orig rsyslog/gss-misc.c --- rsyslog/gss-misc.c.orig 2007-10-30 19:11:16.000000000 +0100 +++ rsyslog/gss-misc.c 2007-11-14 16:50:42.000000000 +0100 @@ -0,0 +1,210 @@ +#include "config.h" +#if defined(SYSLOG_INET) && defined(USE_GSSAPI) +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_PTHREADS +#include +#else +#include +#endif +#include +#include "syslogd.h" +#include "syslogd-types.h" +#include "srUtils.h" +#include "net.h" +#include "omfwd.h" +#include "template.h" +#include "msg.h" +#include "tcpsyslog.h" +#include "module-template.h" +#include "gss-misc.h" + + +static void display_status_(char *m, OM_uint32 code, int type) +{ + OM_uint32 maj_stat, min_stat, msg_ctx = 0; + gss_buffer_desc msg; + + do { + maj_stat = gss_display_status(&min_stat, code, type, GSS_C_NO_OID, &msg_ctx, &msg); + if (maj_stat != GSS_S_COMPLETE) { + logerrorSz("GSS-API error in gss_display_status called from <%s>\n", m); + break; + } else { + char buf[1024]; + snprintf(buf, sizeof(buf), "GSS-API error %s: %s\n", m, (char *) msg.value); + buf[sizeof(buf)/sizeof(char) - 1] = '\0'; + logerror(buf); + } + if (msg.length != 0) + gss_release_buffer(&min_stat, &msg); + } while (msg_ctx); +} + + +void display_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat) +{ + display_status_(m, maj_stat, GSS_C_GSS_CODE); + display_status_(m, min_stat, GSS_C_MECH_CODE); +} + + +void display_ctx_flags(OM_uint32 flags) +{ + if (flags & GSS_C_DELEG_FLAG) + dbgprintf("GSS_C_DELEG_FLAG\n"); + if (flags & GSS_C_MUTUAL_FLAG) + dbgprintf("GSS_C_MUTUAL_FLAG\n"); + if (flags & GSS_C_REPLAY_FLAG) + dbgprintf("GSS_C_REPLAY_FLAG\n"); + if (flags & GSS_C_SEQUENCE_FLAG) + dbgprintf("GSS_C_SEQUENCE_FLAG\n"); + if (flags & GSS_C_CONF_FLAG) + dbgprintf("GSS_C_CONF_FLAG\n"); + if (flags & GSS_C_INTEG_FLAG) + dbgprintf("GSS_C_INTEG_FLAG\n"); +} + + +static int read_all(int fd, char *buf, unsigned int nbyte) +{ + int ret; + char *ptr; + fd_set rfds; + struct timeval tv; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = 1; + tv.tv_usec = 0; + + for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { + if ((ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) <= 0 + || !FD_ISSET(fd, &rfds)) + return ret; + ret = recv(fd, ptr, nbyte, 0); + if (ret < 0) { + if (errno == EINTR) + continue; + return (ret); + } else if (ret == 0) { + return (ptr - buf); + } + } + + return (ptr - buf); +} + + +static int write_all(int fd, char *buf, unsigned int nbyte) +{ + int ret; + char *ptr; + + for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { + ret = send(fd, ptr, nbyte, 0); + if (ret < 0) { + if (errno == EINTR) + continue; + return (ret); + } else if (ret == 0) { + return (ptr - buf); + } + } + + return (ptr - buf); +} + + +int recv_token(int s, gss_buffer_t tok) +{ + int ret; + unsigned char lenbuf[4]; + unsigned int len; + + ret = read_all(s, (char *) lenbuf, 4); + if (ret < 0) { + logerror("GSS-API error reading token length"); + return -1; + } else if (!ret) { + return 0; + } else if (ret != 4) { + logerror("GSS-API error reading token length"); + return -1; + } + + len = ((lenbuf[0] << 24) + | (lenbuf[1] << 16) + | (lenbuf[2] << 8) + | lenbuf[3]); + tok->length = ntohl(len); + + tok->value = (char *) malloc(tok->length ? tok->length : 1); + if (tok->length && tok->value == NULL) { + logerror("Out of memory allocating token data\n"); + return -1; + } + + ret = read_all(s, (char *) tok->value, tok->length); + if (ret < 0) { + logerror("GSS-API error reading token data"); + free(tok->value); + return -1; + } else if (ret != (int) tok->length) { + logerror("GSS-API error reading token data"); + free(tok->value); + return -1; + } + + return 1; +} + + +int send_token(int s, gss_buffer_t tok) +{ + int ret; + unsigned char lenbuf[4]; + unsigned int len; + + if (tok->length > 0xffffffffUL) + abort(); + len = htonl(tok->length); + lenbuf[0] = (len >> 24) & 0xff; + lenbuf[1] = (len >> 16) & 0xff; + lenbuf[2] = (len >> 8) & 0xff; + lenbuf[3] = len & 0xff; + + ret = write_all(s, (char *) lenbuf, 4); + if (ret < 0) { + logerror("GSS-API error sending token length"); + return -1; + } else if (ret != 4) { + logerror("GSS-API error sending token length"); + return -1; + } + + ret = write_all(s, tok->value, tok->length); + if (ret < 0) { + logerror("GSS-API error sending token data"); + return -1; + } else if (ret != (int) tok->length) { + logerror("GSS-API error sending token data"); + return -1; + } + + return 0; +} + +#endif /* #if defined(SYSLOG_INET) && defined(USE_GSSAPI) */ diff -up rsyslog/cfsysline.c.orig rsyslog/cfsysline.c --- rsyslog/cfsysline.c.orig 2007-11-07 15:41:40.000000000 +0100 +++ rsyslog/cfsysline.c 2007-11-07 15:42:39.000000000 +0100 @@ -376,6 +376,7 @@ static rsRetVal doGetWord(uchar **pp, rs CHKiRet(rsCStrFinish(pStrB)); CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, &pNewVal, 0)); + pStrB = NULL; /* we got the word, now set it */ if(pSetHdlr == NULL) {