[rsyslog] How to add new configuration option

Tomas Kubina xkubina at fi.muni.cz
Wed Jan 13 14:48:33 CET 2010


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: rsyslog-bounces at lists.adiscon.com [mailto:rsyslog-
>> bounces at lists.adiscon.com] 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 */
};





More information about the rsyslog mailing list