diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2007-11-19 10:03:32 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2007-11-19 10:03:32 +0000 |
commit | 4ddd2037c8b4f963fa6c32e9e569c449fd0c4bb7 (patch) | |
tree | 6f72296a5330b10a7bde56ba7af4943355b827e2 /omfwd.c | |
parent | 87c1125e74fd9ac40def2166d4c393afc5ae9a37 (diff) | |
download | rsyslog-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.c | 370 |
1 files changed, 313 insertions, 57 deletions
@@ -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 */ |