Rainer Gerhards wrote:
> Hi Tomas,
>
> it's probably the simplest if you post your code so that I can give you the
> relevant hints.
>
> Rainer
>
>
>> -----Original Message-----
>> From: [email protected] [mailto:rsyslog-
>> [email protected]] On Behalf Of Tomas Kubina
>> Sent: Wednesday, January 13, 2010 12:16 PM
>> To: rsyslog-users
>> Subject: [rsyslog] How to add new configuration option
>>
>> Hi,
>>
>> I would appreciate any help with adding support for a new configuration
>> directive. I have done some
>> code and I need now something like:
>> $AddClientCN [on/off].
>> I have read the sources to find out how rsyslog processes conf file.
>> There is some linked list with
>> known commands. I think that it is enough to add new item to this list
>> but I don't know how.
>> Is this my idea right?
>>
>> Thanks for any help.
>>
>> Regards,
>>
>> Tomas
>>
>
Hi Rainer,
the modified files are attached. The alternative code is marked by #if
statement. I had to try to do this modification because the project,
I am interested in, needs to verify client's authentication. I realize
that the patch is something like a hack, because the rsyslog's
architecture doesn't provide this feature (adding client CN to
syslog message) and it is not proper solution, but for our needs it is
enough.
BTW I use this templete:
template ILS_template,"%timegenerated% %fromhost-ip% %HOSTNAME%
%syslogtag%%msg%\n";
I have done a similar code for adding client principal for imgssapi.
Thanks for help.
Regards,
Tomas
FILES:
nsd_gtls.c
static rsRetVal
AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
{
DEFiRet;
int gnuRet;
nsd_gtls_t *pNew = NULL;
nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
ISOBJ_TYPE_assert((pThis), nsd_gtls);
CHKiRet(nsd_gtlsConstruct(&pNew)); // TODO: prevent construct/destruct!
CHKiRet(nsd_ptcp.Destruct(&pNew->pTcp));
CHKiRet(nsd_ptcp.AcceptConnReq(pThis->pTcp, &pNew->pTcp));
if(pThis->iMode == 0) {
/* we are in non-TLS mode, so we are done */
*ppNew = (nsd_t*) pNew;
FINALIZE;
}
/* if we reach this point, we are in TLS mode */
CHKiRet(gtlsInitSession(pNew));
gtlsSetTransportPtr(pNew, ((nsd_ptcp_t*) (pNew->pTcp))->sock);
pNew->authMode = pThis->authMode;
pNew->pPermPeers = pThis->pPermPeers;
/* we now do the handshake. This is a bit complicated, because we are
* on non-blocking sockets. Usually, the handshake will not complete
* immediately, so that we need to retry it some time later.
*/
gnuRet = gnutls_handshake(pNew->sess);
if(gnuRet == GNUTLS_E_AGAIN || gnuRet == GNUTLS_E_INTERRUPTED) {
pNew->rtryCall = gtlsRtry_handshake;
dbgprintf("GnuTLS handshake does not complete immediately -
setting to
retry (this is OK and normal)\n");
} else if(gnuRet == 0) {
/* we got a handshake, now check authorization */
CHKiRet(gtlsChkPeerAuth(pNew));
} else {
ABORT_FINALIZE(RS_RET_TLS_HANDSHAKE_ERR);
}
pNew->iMode = 1; /* this session is now in TLS mode! */
#if 1
pNew->clientCNValid = 0;
#endif
*ppNew = (nsd_t*) pNew;
finalize_it:
if(iRet != RS_RET_OK) {
if(pNew != NULL)
nsd_gtlsDestruct(&pNew);
}
RETiRet;
}
static rsRetVal
Rcv(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
{
DEFiRet;
ssize_t iBytesCopy; /* how many bytes are to be copied to the client
buffer? */
nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
ISOBJ_TYPE_assert(pThis, nsd_gtls);
#if 1
cstr_t *pstrCN = NULL;
const gnutls_datum *cert_list;
unsigned int cert_list_size = 0;
gnutls_x509_crt cert;
int len = 0;
char *buf_temp;
#endif
if(pThis->bAbortConn)
ABORT_FINALIZE(RS_RET_CONNECTION_ABORTREQ);
if(pThis->iMode == 0) {
CHKiRet(nsd_ptcp.Rcv(pThis->pTcp, pBuf, pLenBuf));
FINALIZE;
}
/* --- in TLS mode now --- */
/* Buffer logic applies only if we are in TLS mode. Here we
* assume that we will switch from plain to TLS, but never back. This
* assumption may be unsafe, but it is the model for the time being and
I
* do not see any valid reason why we should switch back to plain TCP
after
* we were in TLS mode. However, in that case we may lose something that
* is already in the receive buffer ... risk accepted. -- rgerhards,
2008-06-23
*/
if(pThis->pszRcvBuf == NULL) {
/* we have no buffer, so we need to malloc one */
CHKmalloc(pThis->pszRcvBuf = MALLOC(NSD_GTLS_MAX_RCVBUF));
pThis->lenRcvBuf = -1;
}
/* now check if we have something in our buffer. If so, we satisfy
* the request from buffer contents.
*/
if(pThis->lenRcvBuf == -1) { /* no data present, must read */
CHKiRet(gtlsRecordRecv(pThis));
}
if(pThis->lenRcvBuf == 0) { /* EOS */
*pLenBuf = 0;
/* in this case, we also need to free the receive buffer, if we
* allocated one. -- rgerhards, 2008-12-03
*/
if(pThis->pszRcvBuf != NULL) {
free(pThis->pszRcvBuf);
pThis->pszRcvBuf = NULL;
}
ABORT_FINALIZE(RS_RET_CLOSED);
}
/* if we reach this point, data is present in the buffer and must be
copied */
iBytesCopy = pThis->lenRcvBuf - pThis->ptrRcvBuf;
if(iBytesCopy > *pLenBuf) {
iBytesCopy = *pLenBuf;
} else {
pThis->lenRcvBuf = -1; /* buffer will be emptied below */
}
#if 1
if (pThis->clientCNValid != 1)
{
cert_list = gnutls_certificate_get_peers(pThis->sess,
&cert_list_size);
if(cert_list_size > 0)
{
// we only print information about the first certificate
gnutls_x509_crt_init(&cert);
gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
CHKiRet(gtlsGetCN(pThis, &cert, &pstrCN));
len = snprintf(NULL, 0, "CN:%s ", (char*)cstrGetSzStr(pstrCN));
if ( !(pThis->clientCN = malloc((len + 1)*sizeof(char))) )
return -1;
snprintf(pThis->clientCN, len + 1, "CN:%s ",
(char*)cstrGetSzStr(pstrCN));
pThis->clientCN[len] = '\0';
pThis->clientCNLen = len + 1;
pThis->clientCNValid = 1;
}
}
iBytesCopy = iBytesCopy + pThis->clientCNLen - 1 < *pLenBuf ?
iBytesCopy + pThis->clientCNLen - 1 : *pLenBuf;
buf_temp = (char*)malloc(iBytesCopy);
if (buf_temp)
{
memset(buf_temp, 0, iBytesCopy);
strncpy(buf_temp, pThis->clientCN, pThis->clientCNLen);
strncat(buf_temp, pThis->pszRcvBuf, pThis->lenRcvBuf);
buf_temp[iBytesCopy] ='\0';
}
memset(pBuf, 0, *pLenBuf);
memcpy(pBuf, buf_temp, iBytesCopy);
if (buf_temp)
free(buf_temp);
#else
memcpy(pBuf, pThis->pszRcvBuf + pThis->ptrRcvBuf, iBytesCopy);
#endif
pThis->ptrRcvBuf += iBytesCopy;
*pLenBuf = iBytesCopy;
finalize_it:
dbgprintf("gtlsRcv return. nsd %p, iRet %d, lenRcvBuf %d, ptrRcvBuf
%d\n", pThis, iRet, pThis->lenRcvBuf, pThis->ptrRcvBuf);
RETiRet;
}
tcps_sess.c
static rsRetVal
Close(tcps_sess_t *pThis)
{
DEFiRet;
ISOBJ_TYPE_assert(pThis, tcps_sess);
netstrm.Destruct(&pThis->pStrm);
if(pThis->fromHost != NULL) {
prop.Destruct(&pThis->fromHost);
}
if(pThis->fromHostIP != NULL)
prop.Destruct(&pThis->fromHostIP);
#if 1
if(pThis->clientPrincipal != NULL)
free(pThis->clientPrincipal);
#endif
RETiRet;
}
tcps_sess.h
/* the tcps_sess object */
struct tcps_sess_s {
BEGINobjInstance; /* Data to implement generic object - MUST be
the
first data element! */
tcpsrv_t *pSrv; /* pointer back to my server (e.g. for callbacks) */
tcpLstnPortList_t *pLstnInfo; /* pointer back to listener info */
netstrm_t *pStrm;
int iMsg; /* index of next char to store in msg */
int bAtStrtOfFram; /* are we at the very beginning of a new frame?
*/
enum {
eAtStrtFram,
eInOctetCnt,
eInMsg
} inputState; /* our current state */
int iOctetsRemain; /* Number of Octets remaining in message */
TCPFRAMINGMODE eFraming;
uchar *pMsg; /* message (fragment) received */
prop_t *fromHost; /* host name we received messages from */
prop_t *fromHostIP;
void *pUsr; /* a user-pointer */
#if 1
char *clientPrincipal; /* client principal */
int clientPrincipalLen;
#endif
rsRetVal (*DoSubmitMessage)(tcps_sess_t*, uchar*, int); /* submit
message callback */
};
_______________________________________________
rsyslog mailing list
http://lists.adiscon.net/mailman/listinfo/rsyslog
http://www.rsyslog.com