/
githubmirror
/
rsyslog
Обзор
Документация
Войти
/
githubmirror
/
rsyslog
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
plugins/imgssapi/imgssapi.c
850 строк
28 KB
Rainer Gerhards
gssapi: fix token timeout handling
17 апр 2026, 13:29
Не верифицирован
17 апр 2026, 13:29
2334dab
Код
Авторство
О чём код?
/* imgssapi.c * This is the implementation of the GSSAPI input module. * * Note: the root gssapi code was contributed by varmojfekoj and is most often * maintened by him. I am just doing the plumbing around it (I event don't have a * test lab for gssapi yet... ). I am very grateful for this useful code * contribution -- rgerhards, 2008-03-05 * * NOTE: read comments in module-template.h to understand how this file * works! * * Copyright 2007, 2017 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * * Rsyslog is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Rsyslog is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>. * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ #include "config.h" #include <stdlib.h> #include <assert.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <stdarg.h> #include <ctype.h> #include <netinet/in.h> #include <netdb.h> #include <stdint.h> #include <sys/types.h> #include <sys/socket.h> #if HAVE_FCNTL_H #include <fcntl.h> #endif #include <gssapi/gssapi.h> #include "rsyslog.h" #include "dirty.h" #include "cfsysline.h" #include "module-template.h" #include "unicode-helper.h" #include "net.h" #include "srUtils.h" #include "gss-misc.h" #include "gss-token-util.h" #include "tcpsrv.h" #include "tcps_sess.h" #include "errmsg.h" #include "netstrm.h" #include "glbl.h" #include "debug.h" #include "unlimited_select.h" #include "rsconf.h" MODULE_TYPE_INPUT; MODULE_TYPE_NOKEEP; /* defines */ #define ALLOWEDMETHOD_GSS 2 #define ALLOWEDMETHOD_TCP 1 /* some forward definitions - they may go away when we no longer include imtcp.c */ static rsRetVal addGSSListener(void __attribute__((unused)) * pVal, uchar *pNewVal); static rsRetVal actGSSListener(uchar *port); static int TCPSessGSSInit(void); static void TCPSessGSSClose(tcps_sess_t *pSess); static rsRetVal TCPSessGSSRecv(tcps_sess_t *pSess, void *buf, size_t buf_len, ssize_t *); static rsRetVal onSessAccept(tcpsrv_t *pThis, tcps_sess_t *pSess, ATTR_UNUSED char *connInfo); static rsRetVal OnSessAcceptGSS(tcpsrv_t *pThis, tcps_sess_t *ppSess); static rsRetVal setInputGSSTokenIOTimeout(void *pVal, int timeout_secs); /* static data */ DEF_IMOD_STATIC_DATA; DEFobjCurrIf(tcpsrv) DEFobjCurrIf(tcps_sess) DEFobjCurrIf(gssutil) DEFobjCurrIf(netstrm) DEFobjCurrIf(net) DEFobjCurrIf(glbl) DEFobjCurrIf(prop) static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */ static gss_cred_id_t gss_server_creds = GSS_C_NO_CREDENTIAL; static uchar *srvPort; /* our usr structure for the tcpsrv object */ typedef struct gsssrv_s { char allowedMethods; } gsssrv_t; /* our usr structure for the session object */ typedef struct gss_sess_s { OM_uint32 gss_flags; gss_ctx_id_t gss_context; char allowedMethods; } gss_sess_t; /* config variables */ struct modConfData_s { EMPTY_STRUCT; }; static uchar *pszLstnPortFileName = NULL; /* file for dynamic port */ static int iTCPSessMax = 200; /* max number of sessions */ static char *gss_listen_service_name = NULL; static int bPermitPlainTcp = 0; /* plain tcp syslog allowed on GSSAPI port? */ static int bKeepAlive = 0; /* use SO_KEEPALIVE? */ static int gss_token_io_timeout_secs = GSS_TOKEN_IO_TIMEOUT_SECS; /* methods */ /* callbacks */ static rsRetVal OnSessConstructFinalize(void *ppUsr) { DEFiRet; gss_sess_t **ppGSess = (gss_sess_t **)ppUsr; gss_sess_t *pGSess; assert(ppGSess != NULL); if ((pGSess = calloc(1, sizeof(gss_sess_t))) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); pGSess->gss_flags = 0; pGSess->gss_context = GSS_C_NO_CONTEXT; pGSess->allowedMethods = 0; *ppGSess = pGSess; finalize_it: RETiRet; } /* Destruct the user session pointer for a GSSAPI session. Please note * that it *is* valid to receive a NULL user pointer. In this case, the * sessions is to be torn down before it was fully initialized. This * happens in error cases, e.g. when the host ACL did not match. * rgerhards, 2008-03-03 */ static rsRetVal OnSessDestruct(void *ppUsr) { DEFiRet; gss_sess_t **ppGSess = (gss_sess_t **)ppUsr; assert(ppGSess != NULL); if (*ppGSess == NULL) FINALIZE; if ((*ppGSess)->allowedMethods & ALLOWEDMETHOD_GSS) { OM_uint32 maj_stat, min_stat; maj_stat = gss_delete_sec_context(&min_stat, &(*ppGSess)->gss_context, GSS_C_NO_BUFFER); if (maj_stat != GSS_S_COMPLETE) gssutil.display_status((char *)"deleting context", maj_stat, min_stat); } free(*ppGSess); *ppGSess = NULL; finalize_it: RETiRet; } /* Check if the host is permitted to send us messages. * Note: the pUsrSess may be zero if the server is running in tcp-only mode! */ static char getAllowedMethodsForPeer(struct sockaddr *addr, const char *fromHostFQDN, const gsssrv_t *pGSrv) { char allowedMethods = 0; assert(addr != NULL); assert(pGSrv != NULL); if ((pGSrv->allowedMethods & ALLOWEDMETHOD_TCP) && net.isAllowedSender2((uchar *)"TCP", addr, (char *)fromHostFQDN, 1)) allowedMethods |= ALLOWEDMETHOD_TCP; if ((pGSrv->allowedMethods & ALLOWEDMETHOD_GSS) && net.isAllowedSender2((uchar *)"GSS", addr, (char *)fromHostFQDN, 1)) allowedMethods |= ALLOWEDMETHOD_GSS; return allowedMethods; } static int isPermittedHost(struct sockaddr *addr, char *fromHostFQDN, void *pUsrSrv, void *pUsrSess) { gsssrv_t *pGSrv; gss_sess_t *pGSess; char allowedMethods; assert(pUsrSrv != NULL); pGSrv = (gsssrv_t *)pUsrSrv; pGSess = (gss_sess_t *)pUsrSess; allowedMethods = getAllowedMethodsForPeer(addr, fromHostFQDN, pGSrv); if (allowedMethods && pGSess != NULL) pGSess->allowedMethods = allowedMethods; return allowedMethods; } static rsRetVal getAllowedMethodsForSess(tcps_sess_t *pSess, gsssrv_t *pGSrv, char *pAllowedMethods) { DEFiRet; int fdSess; struct sockaddr_storage peerAddr; socklen_t peerAddrLen; uchar *pszPeer = NULL; int lenPeer = 0; assert(pSess != NULL); assert(pGSrv != NULL); assert(pAllowedMethods != NULL); peerAddrLen = sizeof(peerAddr); CHKiRet(netstrm.GetSock(pSess->pStrm, &fdSess)); if (getpeername(fdSess, (struct sockaddr *)&peerAddr, &peerAddrLen) != 0) { LogError(errno, RS_RET_ERR, "imgssapi: could not determine peer address during session accept"); ABORT_FINALIZE(RS_RET_ERR); } prop.GetString(pSess->fromHost, &pszPeer, &lenPeer); *pAllowedMethods = getAllowedMethodsForPeer((struct sockaddr *)&peerAddr, (char *)pszPeer, pGSrv); finalize_it: RETiRet; } static rsRetVal onSessAccept(tcpsrv_t *pThis, tcps_sess_t *pSess, ATTR_UNUSED char *connInfo) { DEFiRet; char allowedMethods; gsssrv_t *pGSrv; gss_sess_t *pGSess; pGSrv = (gsssrv_t *)pThis->pUsr; pGSess = (gss_sess_t *)pSess->pUsr; assert(pGSess != NULL); CHKiRet(getAllowedMethodsForSess(pSess, pGSrv, &allowedMethods)); if (allowedMethods == 0) ABORT_FINALIZE(RS_RET_HOST_NOT_PERMITTED); pGSess->allowedMethods = allowedMethods; if (allowedMethods & ALLOWEDMETHOD_GSS) { iRet = OnSessAcceptGSS(pThis, pSess); } finalize_it: RETiRet; } static rsRetVal onRegularClose(tcps_sess_t *pSess) { DEFiRet; gss_sess_t *pGSess; assert(pSess != NULL); assert(pSess->pUsr != NULL); pGSess = (gss_sess_t *)pSess->pUsr; if (pGSess->allowedMethods & ALLOWEDMETHOD_GSS) TCPSessGSSClose(pSess); else { /* process any incomplete frames left over */ tcps_sess.PrepareClose(pSess); /* Session closed */ tcps_sess.Close(pSess); } RETiRet; } static rsRetVal onErrClose(tcps_sess_t *pSess) { DEFiRet; gss_sess_t *pGSess; assert(pSess != NULL); assert(pSess->pUsr != NULL); pGSess = (gss_sess_t *)pSess->pUsr; if (pGSess->allowedMethods & ALLOWEDMETHOD_GSS) TCPSessGSSClose(pSess); else tcps_sess.Close(pSess); RETiRet; } /* open the listen sockets */ static rsRetVal doOpenLstnSocks(tcpsrv_t *pSrv) { gsssrv_t *pGSrv; DEFiRet; ISOBJ_TYPE_assert(pSrv, tcpsrv); pGSrv = pSrv->pUsr; assert(pGSrv != NULL); /* first apply some config settings */ if (pGSrv->allowedMethods) { if (pGSrv->allowedMethods & ALLOWEDMETHOD_GSS) { if (TCPSessGSSInit()) { LogError(0, NO_ERRCODE, "GSS-API initialization failed\n"); pGSrv->allowedMethods &= ~(ALLOWEDMETHOD_GSS); } } if (pGSrv->allowedMethods) { /* fallback to plain TCP */ CHKiRet(tcpsrv.create_tcp_socket(pSrv)); } else { ABORT_FINALIZE(RS_RET_GSS_ERR); } } finalize_it: RETiRet; } static rsRetVal doRcvData(tcps_sess_t *pSess, char *buf, size_t lenBuf, ssize_t *piLenRcvd, int *const oserr, unsigned *const nextIODirection) { DEFiRet; int allowedMethods; gss_sess_t *pGSess; assert(pSess != NULL); assert(pSess->pUsr != NULL); pGSess = (gss_sess_t *)pSess->pUsr; assert(piLenRcvd != NULL); allowedMethods = pGSess->allowedMethods; if (allowedMethods & ALLOWEDMETHOD_GSS) { CHKiRet(TCPSessGSSRecv(pSess, buf, lenBuf, piLenRcvd)); } else { *piLenRcvd = lenBuf; CHKiRet(netstrm.Rcv(pSess->pStrm, (uchar *)buf, piLenRcvd, oserr, nextIODirection)); } finalize_it: RETiRet; } /* end callbacks */ static rsRetVal addGSSListener(void __attribute__((unused)) * pVal, uchar *pNewVal) { DEFiRet; if ((ustrcmp(pNewVal, UCHAR_CONSTANT("0")) == 0 && pszLstnPortFileName == NULL) || ustrcmp(pNewVal, UCHAR_CONSTANT("0")) < 0) { CHKmalloc(srvPort = (uchar *)strdup("514")); } else { srvPort = pNewVal; } finalize_it: RETiRet; } static rsRetVal actGSSListener(uchar *port) { DEFiRet; tcpLstnParams_t *cnf_params = NULL; gsssrv_t *pGSrv = NULL; assert(pOurTcpsrv == NULL); CHKmalloc(cnf_params = (tcpLstnParams_t *)calloc(1, sizeof(tcpLstnParams_t))); /* first create/init the gsssrv "object" */ if ((pGSrv = calloc(1, sizeof(gsssrv_t))) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); pGSrv->allowedMethods = ALLOWEDMETHOD_GSS; if (bPermitPlainTcp) pGSrv->allowedMethods |= ALLOWEDMETHOD_TCP; /* gsssrv initialized */ CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); CHKiRet(tcpsrv.SetUsrP(pOurTcpsrv, pGSrv)); CHKiRet(tcpsrv.SetCBOnSessConstructFinalize(pOurTcpsrv, OnSessConstructFinalize)); CHKiRet(tcpsrv.SetCBOnSessDestruct(pOurTcpsrv, OnSessDestruct)); CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); CHKiRet(tcpsrv.SetCBRcvData(pOurTcpsrv, doRcvData)); CHKiRet(tcpsrv.SetCBOpenLstnSocks(pOurTcpsrv, doOpenLstnSocks)); CHKiRet(tcpsrv.SetCBOnSessAccept(pOurTcpsrv, onSessAccept)); CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose)); CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose)); CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, cnf_params, UCHAR_CONSTANT("imgssapi"))); CHKiRet(tcpsrv.SetNumWrkr(pOurTcpsrv, 1)); CHKiRet(tcpsrv.SetKeepAlive(pOurTcpsrv, bKeepAlive)); CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, iTCPSessMax)); CHKiRet(tcpsrv.SetOrigin(pOurTcpsrv, UCHAR_CONSTANT("imgssapi"))); cnf_params->pszPort = port; cnf_params->bSuppOctetFram = 1; if (pszLstnPortFileName != NULL) { CHKmalloc(cnf_params->pszLstnPortFileName = ustrdup(pszLstnPortFileName)); } tcpsrv.configureTCPListen(pOurTcpsrv, cnf_params); CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv)); cnf_params = NULL; finalize_it: if (iRet != RS_RET_OK) { LogError(0, NO_ERRCODE, "error %d trying to add listener", iRet); if (pOurTcpsrv != NULL) tcpsrv.Destruct(&pOurTcpsrv); free(pGSrv); } free(cnf_params); RETiRet; } /* returns 0 if all went OK, -1 if it failed */ static int TCPSessGSSInit(void) { gss_buffer_desc name_buf; gss_name_t server_name; OM_uint32 maj_stat, min_stat; if (gss_server_creds != GSS_C_NO_CREDENTIAL) return 0; name_buf.value = (gss_listen_service_name == NULL) ? (char *)"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) { gssutil.display_status((char *)"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) { gssutil.display_status((char *)"acquiring credentials", maj_stat, min_stat); return -1; } gss_release_name(&min_stat, &server_name); dbgprintf("GSS-API initialized\n"); return 0; } /* returns 0 if all went OK, -1 if it failed * tries to guess if the connection uses gssapi. */ static rsRetVal OnSessAcceptGSS(ATTR_UNUSED tcpsrv_t *pThis, tcps_sess_t *pSess) { DEFiRet; gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; gss_name_t client; OM_uint32 maj_stat, min_stat, acc_sec_min_stat; gss_ctx_id_t *context; OM_uint32 *sess_flags; int fdSess; char allowedMethods; gss_sess_t *pGSess; uchar *pszPeer = NULL; int lenPeer = 0; char *buf = NULL; assert(pSess != NULL); pGSess = (gss_sess_t *)pSess->pUsr; allowedMethods = pGSess->allowedMethods; if (allowedMethods & ALLOWEDMETHOD_GSS) { int ret = 0; const size_t bufsize = glbl.GetMaxLine(runConf); CHKmalloc(buf = (char *)malloc(bufsize + 1)); prop.GetString(pSess->fromHostIP, &pszPeer, &lenPeer); dbgprintf("GSS-API Trying to accept TCP session %p from %s\n", pSess, (char *)pszPeer); CHKiRet(netstrm.GetSock(pSess->pStrm, &fdSess)); // TODO: method access! if (allowedMethods & ALLOWEDMETHOD_TCP) { size_t hinted_len = 0; struct timeval tv; #ifdef USE_UNLIMITED_SELECT fd_set *pFds = malloc(glbl.GetFdSetSize()); #else fd_set fds; fd_set *pFds = &fds; #endif do { FD_ZERO(pFds); FD_SET(fdSess, pFds); tv.tv_sec = 1; tv.tv_usec = 0; ret = select(fdSess + 1, pFds, NULL, NULL, &tv); } while (ret < 0 && errno == EINTR); if (ret < 0) { LogError(0, RS_RET_ERR, "TCP session %p from %s will be " "closed, error ignored\n", pSess, (char *)pszPeer); ABORT_FINALIZE(RS_RET_ERR); // TODO: define good error codes } else if (ret == 0) { dbgprintf("GSS-API Reverting to plain TCP\n"); pGSess->allowedMethods = ALLOWEDMETHOD_TCP; ABORT_FINALIZE(RS_RET_OK); // TODO: define good error codes } do { ret = recv(fdSess, buf, bufsize, MSG_PEEK); } while (ret < 0 && errno == EINTR); if (ret <= 0) { if (ret == 0) { dbgprintf("GSS-API Connection closed by peer %s\n", (char *)pszPeer); } else { LogError(0, RS_RET_ERR, "TCP(GSS) session %p from %s will be closed, " "error ignored\n", pSess, (char *)pszPeer); } ABORT_FINALIZE(RS_RET_ERR); // TODO: define good error codes } if (ret < 4) { dbgprintf("GSS-API Reverting to plain TCP from %s\n", (char *)pszPeer); pGSess->allowedMethods = ALLOWEDMETHOD_TCP; ABORT_FINALIZE(RS_RET_OK); // TODO: define good error codes } else if (ret == 4) { /* The client might has been interupted after sending * the data length (4B), give him another chance. */ srSleep(1, 0); do { ret = recv(fdSess, buf, bufsize, MSG_PEEK); } while (ret < 0 && errno == EINTR); if (ret <= 0) { if (ret == 0) { dbgprintf("GSS-API Connection closed by peer %s\n", (char *)pszPeer); } else { LogError(0, NO_ERRCODE, "TCP session %p from %s will be " "closed, error ignored\n", pSess, (char *)pszPeer); } ABORT_FINALIZE(RS_RET_ERR); // TODO: define good error codes } } /* TODO: how does this work together with IPv6? Does it? */ if (gssTokenDecodeLength((unsigned char *)buf, SIZE_MAX, &hinted_len) != RS_RET_OK || (size_t)(ret - 4) < hinted_len || hinted_len == 0) { dbgprintf("GSS-API Reverting to plain TCP from %s\n", (char *)pszPeer); pGSess->allowedMethods = ALLOWEDMETHOD_TCP; ABORT_FINALIZE(RS_RET_OK); // TODO: define good error codes } freeFdSet(pFds); } context = &pGSess->gss_context; *context = GSS_C_NO_CONTEXT; sess_flags = &pGSess->gss_flags; do { if (gssutil.recv_token(fdSess, &recv_tok, GSS_TOKEN_MAX_HANDSHAKE_BYTES, (unsigned int)gss_token_io_timeout_secs) <= 0) { LogError(0, NO_ERRCODE, "TCP session %p from %s will be " "closed, error ignored\n", pSess, (char *)pszPeer); ABORT_FINALIZE(RS_RET_ERR); // TODO: define good error codes } 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 (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) { gss_release_buffer(&min_stat, &send_tok); if (*context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER); gssutil.display_status((char *)"accepting context", maj_stat, acc_sec_min_stat); ABORT_FINALIZE(RS_RET_ERR); // TODO: define good error codes } if (send_tok.length != 0) { if (gssutil.send_token(fdSess, &send_tok) < 0) { gss_release_buffer(&min_stat, &send_tok); LogError(0, NO_ERRCODE, "TCP session %p from %s will be " "closed, error ignored\n", pSess, (char *)pszPeer); if (*context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER); ABORT_FINALIZE(RS_RET_ERR); // TODO: define good error codes } gss_release_buffer(&min_stat, &send_tok); } } while (maj_stat == GSS_S_CONTINUE_NEEDED); maj_stat = gss_display_name(&min_stat, client, &recv_tok, NULL); if (maj_stat != GSS_S_COMPLETE) { gssutil.display_status((char *)"displaying name", maj_stat, min_stat); } else { dbgprintf("GSS-API Accepted connection from peer %s: %s\n", (char *)pszPeer, (char *)recv_tok.value); } gss_release_name(&min_stat, &client); gss_release_buffer(&min_stat, &recv_tok); dbgprintf("GSS-API Provided context flags:\n"); gssutil.display_ctx_flags(*sess_flags); pGSess->allowedMethods = ALLOWEDMETHOD_GSS; } finalize_it: free(buf); RETiRet; } /* Replaces recv() for gssapi connections. */ rsRetVal TCPSessGSSRecv(tcps_sess_t *pSess, void *buf, size_t buf_len, ssize_t *piLenRcvd) { DEFiRet; gss_buffer_desc xmit_buf = GSS_C_EMPTY_BUFFER; gss_buffer_desc msg_buf = GSS_C_EMPTY_BUFFER; gss_ctx_id_t *context; OM_uint32 maj_stat, min_stat; int fdSess; int conf_state; gss_sess_t *pGSess; assert(pSess->pUsr != NULL); assert(piLenRcvd != NULL); pGSess = (gss_sess_t *)pSess->pUsr; netstrm.GetSock(pSess->pStrm, &fdSess); // TODO: method access, CHKiRet! if (gssutil.recv_token(fdSess, &xmit_buf, gssTokenGetMessageLimit(buf_len), (unsigned int)gss_token_io_timeout_secs) <= 0) ABORT_FINALIZE(RS_RET_GSS_ERR); context = &pGSess->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) { gssutil.display_status((char *)"unsealing message", maj_stat, min_stat); if (xmit_buf.value) { free(xmit_buf.value); xmit_buf.value = 0; } ABORT_FINALIZE(RS_RET_GSS_ERR); } if (xmit_buf.value) { free(xmit_buf.value); xmit_buf.value = 0; } if (msg_buf.length > buf_len) { LogError(0, NO_ERRCODE, "GSS-API message length %zu exceeds configured max message size %zu; closing session", (size_t)msg_buf.length, buf_len); gss_release_buffer(&min_stat, &msg_buf); ABORT_FINALIZE(RS_RET_GSS_ERR); } *piLenRcvd = msg_buf.length; memcpy(buf, msg_buf.value, *piLenRcvd); gss_release_buffer(&min_stat, &msg_buf); finalize_it: RETiRet; } /* Takes care of cleaning up gssapi stuff and then calls * TCPSessClose(). */ void TCPSessGSSClose(tcps_sess_t *pSess) { OM_uint32 maj_stat, min_stat; gss_ctx_id_t *context; gss_sess_t *pGSess; assert(pSess->pUsr != NULL); pGSess = (gss_sess_t *)pSess->pUsr; context = &pGSess->gss_context; maj_stat = gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER); if (maj_stat != GSS_S_COMPLETE) gssutil.display_status((char *)"deleting context", maj_stat, min_stat); *context = GSS_C_NO_CONTEXT; pGSess->gss_flags = 0; pGSess->allowedMethods = 0; tcps_sess.Close(pSess); } /* Counterpart of TCPSessGSSInit(). This is called to exit the GSS system * at all. It is a server-based session exit. */ static rsRetVal TCPSessGSSDeinit(void) { DEFiRet; OM_uint32 maj_stat, min_stat; if (gss_server_creds != GSS_C_NO_CREDENTIAL) { maj_stat = gss_release_cred(&min_stat, &gss_server_creds); if (maj_stat != GSS_S_COMPLETE) gssutil.display_status((char *)"releasing credentials", maj_stat, min_stat); } RETiRet; } #if 0 /* can be used to integrate into new config system */ BEGINbeginCnfLoad CODESTARTbeginCnfLoad; ENDbeginCnfLoad BEGINendCnfLoad CODESTARTendCnfLoad; ENDendCnfLoad BEGINcheckCnf CODESTARTcheckCnf; ENDcheckCnf BEGINactivateCnf CODESTARTactivateCnf; ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf; ENDfreeCnf #endif /* This function is called to gather input. */ BEGINrunInput CODESTARTrunInput; /* This will fail if the priviledges are dropped. Should be * moved to the '*activateCnfPrePrivDrop' section eventually. */ actGSSListener(srvPort); iRet = tcpsrv.Run(pOurTcpsrv); ENDrunInput /* initialize and return if will run or not */ BEGINwillRun CODESTARTwillRun; if (srvPort == NULL) ABORT_FINALIZE(RS_RET_NO_RUN); net.PrintAllowedSenders(2); /* TCP */ net.PrintAllowedSenders(3); /* GSS */ finalize_it: ENDwillRun BEGINmodExit CODESTARTmodExit; if (pOurTcpsrv != NULL) iRet = tcpsrv.Destruct(&pOurTcpsrv); TCPSessGSSDeinit(); /* release objects we used */ objRelease(tcps_sess, LM_TCPSRV_FILENAME); objRelease(tcpsrv, LM_TCPSRV_FILENAME); objRelease(gssutil, LM_GSSUTIL_FILENAME); objRelease(glbl, CORE_COMPONENT); objRelease(netstrm, LM_NETSTRM_FILENAME); objRelease(net, LM_NET_FILENAME); objRelease(prop, CORE_COMPONENT); ENDmodExit BEGINafterRun CODESTARTafterRun; /* do cleanup here */ net.clearAllowedSenders((uchar *)"TCP"); net.clearAllowedSenders((uchar *)"GSS"); ENDafterRun BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature; if (eFeat == sFEATURENonCancelInputTermination) iRet = RS_RET_OK; ENDisCompatibleWithFeature BEGINqueryEtryPt CODESTARTqueryEtryPt; CODEqueryEtryPt_STD_IMOD_QUERIES; CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES; ENDqueryEtryPt static rsRetVal resetConfigVariables(uchar __attribute__((unused)) * pp, void __attribute__((unused)) * pVal) { if (gss_listen_service_name != NULL) { free(gss_listen_service_name); gss_listen_service_name = NULL; } if (pszLstnPortFileName != NULL) { free(pszLstnPortFileName); pszLstnPortFileName = NULL; } bPermitPlainTcp = 0; iTCPSessMax = 200; bKeepAlive = 0; gss_token_io_timeout_secs = GSS_TOKEN_IO_TIMEOUT_SECS; return RS_RET_OK; } static rsRetVal setInputGSSTokenIOTimeout(void __attribute__((unused)) * pVal, int timeout_secs) { if (timeout_secs < 0) { LogError(0, RS_RET_PARAM_ERROR, "imgssapi: $InputGSSServerTokenIOTimeout must be greater than or equal to 0"); return RS_RET_PARAM_ERROR; } gss_token_io_timeout_secs = timeout_secs; return RS_RET_OK; } BEGINmodInit() CODESTARTmodInit; *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current definition */ CODEmodInit_QueryRegCFSLineHdlr pOurTcpsrv = NULL; /* request objects we use */ CHKiRet(objUse(tcps_sess, LM_TCPSRV_FILENAME)); CHKiRet(objUse(tcpsrv, LM_TCPSRV_FILENAME)); CHKiRet(objUse(gssutil, LM_GSSUTIL_FILENAME)); CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(netstrm, LM_NETSTRM_FILENAME)); CHKiRet(objUse(net, LM_NET_FILENAME)); CHKiRet(objUse(prop, CORE_COMPONENT)); /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputgssserverpermitplaintcp", 0, eCmdHdlrBinary, NULL, &bPermitPlainTcp, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputgssserverrun", 0, eCmdHdlrGetWord, addGSSListener, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputgssserverservicename", 0, eCmdHdlrGetWord, NULL, &gss_listen_service_name, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputgsslistenportfilename", 0, eCmdHdlrGetWord, NULL, &pszLstnPortFileName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputgssservermaxsessions", 0, eCmdHdlrInt, NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputgssservertokeniotimeout", 0, eCmdHdlrInt, setInputGSSTokenIOTimeout, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputgssserverkeepalive", 0, eCmdHdlrBinary, NULL, &bKeepAlive, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit /* vim:set ai: */