Blob Blame History Raw
From 85f48d11900ade931cc667750b8dd69e7fa656ef Mon Sep 17 00:00:00 2001
From: Tomas Heinrich <theinric@redhat.com>
Date: Thu, 23 Jul 2015 17:28:50 +0200
Subject: [PATCH] imuxsock: handle unlimited number of listeners

---
 plugins/imuxsock/imuxsock.c | 258 ++++++++++++++++++++++----------------------
 1 file changed, 130 insertions(+), 128 deletions(-)

diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 8fda133..eca9a34 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -62,7 +62,6 @@ MODULE_TYPE_NOKEEP
 MODULE_CNFNAME("imuxsock")
 
 /* defines */
-#define MAXFUNIX	50
 #ifndef _PATH_LOG
 #ifdef BSD
 #define _PATH_LOG	"/var/run/log"
@@ -148,7 +147,7 @@ typedef struct lstn_s {
 	sbool bUseSysTimeStamp;	/* use timestamp from system (instead of from message) */
 	sbool bUnlink;		/* unlink&re-create socket at start and end of processing */
 } lstn_t;
-static lstn_t listeners[MAXFUNIX];
+static lstn_t *listeners;
 
 static prop_t *pLocalHostIP = NULL;	/* there is only one global IP for all internally-generated messages */
 static prop_t *pInputName = NULL;	/* our inputName currently is always "imudp", and this will hold it */
@@ -360,12 +359,7 @@ finalize_it:
 }
 
 
-/* add an additional listen socket. Socket names are added
- * until the array is filled up. It is never reset, only at
- * module unload.
- * TODO: we should change the array to a list so that we
- * can support any number of listen socket names.
- * rgerhards, 2007-12-20
+/* add an additional listen socket. 
  * added capability to specify hostname for socket -- rgerhards, 2008-08-01
  */
 static rsRetVal
@@ -373,66 +367,70 @@ addListner(instanceConf_t *inst)
 {
 	DEFiRet;
 
-	if(nfd < MAXFUNIX) {
-		if(*inst->sockName == ':') {
-			listeners[nfd].bParseHost = 1;
-		} else {
-			listeners[nfd].bParseHost = 0;
-		}
-		if(inst->pLogHostName == NULL) {
-			listeners[nfd].hostName = NULL;
-		} else {
-			CHKiRet(prop.Construct(&(listeners[nfd].hostName)));
-			CHKiRet(prop.SetString(listeners[nfd].hostName, inst->pLogHostName, ustrlen(inst->pLogHostName)));
-			CHKiRet(prop.ConstructFinalize(listeners[nfd].hostName));
-		}
-		if(inst->ratelimitInterval > 0) {
-			if((listeners[nfd].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn,
-				(void(*)(void*))ratelimitDestruct)) == NULL) {
-				/* in this case, we simply turn off rate-limiting */
-				DBGPRINTF("imuxsock: turning off rate limiting because we could not "
-					  "create hash table\n");
-				inst->ratelimitInterval = 0;
-			}
+	if(*inst->sockName == ':') {
+		listeners[nfd].bParseHost = 1;
+	} else {
+		listeners[nfd].bParseHost = 0;
+	}
+	if(inst->pLogHostName == NULL) {
+		listeners[nfd].hostName = NULL;
+	} else {
+		CHKiRet(prop.Construct(&(listeners[nfd].hostName)));
+		CHKiRet(prop.SetString(listeners[nfd].hostName, inst->pLogHostName, ustrlen(inst->pLogHostName)));
+		CHKiRet(prop.ConstructFinalize(listeners[nfd].hostName));
+	}
+	if(inst->ratelimitInterval > 0) {
+		if((listeners[nfd].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn,
+			(void(*)(void*))ratelimitDestruct)) == NULL) {
+			/* in this case, we simply turn off rate-limiting */
+			DBGPRINTF("imuxsock: turning off rate limiting because we could not "
+				  "create hash table\n");
+			inst->ratelimitInterval = 0;
 		}
-		listeners[nfd].ratelimitInterval = inst->ratelimitInterval;
-		listeners[nfd].ratelimitBurst = inst->ratelimitBurst;
-		listeners[nfd].ratelimitSev = inst->ratelimitSeverity;
-		listeners[nfd].flowCtl = inst->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
-		listeners[nfd].flags = inst->bIgnoreTimestamp ? IGNDATE : NOFLAG;
-		listeners[nfd].bCreatePath = inst->bCreatePath;
-		listeners[nfd].sockName = ustrdup(inst->sockName);
-		listeners[nfd].bUseCreds = (inst->bDiscardOwnMsgs || inst->bWritePid || inst->ratelimitInterval || inst->bAnnotate || inst->bUseSysTimeStamp) ? 1 : 0;
-		listeners[nfd].bAnnotate = inst->bAnnotate;
-		listeners[nfd].bParseTrusted = inst->bParseTrusted;
-		listeners[nfd].bDiscardOwnMsgs = inst->bDiscardOwnMsgs;
-		listeners[nfd].bUnlink = inst->bUnlink;
-		listeners[nfd].bWritePid = inst->bWritePid;
-		listeners[nfd].bUseSysTimeStamp = inst->bUseSysTimeStamp;
-		CHKiRet(ratelimitNew(&listeners[nfd].dflt_ratelimiter, "imuxsock", NULL));
-		ratelimitSetLinuxLike(listeners[nfd].dflt_ratelimiter,
-				      listeners[nfd].ratelimitInterval,
-				      listeners[nfd].ratelimitBurst);
-		ratelimitSetSeverity(listeners[nfd].dflt_ratelimiter,
-				     listeners[nfd].ratelimitSev);
-		nfd++;
 	} else {
-		errmsg.LogError(0, NO_ERRCODE, "Out of unix socket name descriptors, ignoring %s\n",
-			 inst->sockName);
+		listeners[nfd].ht = NULL;
 	}
+	listeners[nfd].ratelimitInterval = inst->ratelimitInterval;
+	listeners[nfd].ratelimitBurst = inst->ratelimitBurst;
+	listeners[nfd].ratelimitSev = inst->ratelimitSeverity;
+	listeners[nfd].flowCtl = inst->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
+	listeners[nfd].flags = inst->bIgnoreTimestamp ? IGNDATE : NOFLAG;
+	listeners[nfd].bCreatePath = inst->bCreatePath;
+	listeners[nfd].sockName = ustrdup(inst->sockName);
+	listeners[nfd].bUseCreds = (inst->bDiscardOwnMsgs || inst->bWritePid || inst->ratelimitInterval || inst->bAnnotate || runModConf->bUseSysTimeStamp) ? 1 : 0;
+	listeners[nfd].bAnnotate = inst->bAnnotate;
+	listeners[nfd].bParseTrusted = inst->bParseTrusted;
+	listeners[nfd].bDiscardOwnMsgs = inst->bDiscardOwnMsgs;
+	listeners[nfd].bUnlink = inst->bUnlink;
+	listeners[nfd].bWritePid = inst->bWritePid;
+	listeners[nfd].bUseSysTimeStamp = inst->bUseSysTimeStamp;
+	CHKiRet(ratelimitNew(&listeners[nfd].dflt_ratelimiter, "imuxsock", NULL));
+	ratelimitSetLinuxLike(listeners[nfd].dflt_ratelimiter,
+			      listeners[nfd].ratelimitInterval,
+			      listeners[nfd].ratelimitBurst);
+	ratelimitSetSeverity(listeners[nfd].dflt_ratelimiter,
+			     listeners[nfd].ratelimitSev);
+	nfd++;
 
 finalize_it:
 	RETiRet;
 }
 
 
-/* discard/Destruct all log sockets except for "socket" 0. Data for it comes from
- * the constant memory pool - and if not, it is freeed via some other pointer.
- */
 static rsRetVal discardLogSockets(void)
 {
 	int i;
 
+	/* Check whether the system socket is in use */
+	if(startIndexUxLocalSockets == 0) {
+		/* Clean up rate limiting data for the system socket */
+		if(listeners[0].ht != NULL) {
+			hashtable_destroy(listeners[0].ht, 1); /* 1 => free all values automatically */
+		}
+		ratelimitDestruct(listeners[0].dflt_ratelimiter);
+	}
+
+	/* Clean up all other sockets */
         for (i = 1; i < nfd; i++) {
 		if(listeners[i].sockName != NULL) {
 			free(listeners[i].sockName);
@@ -1033,50 +1031,51 @@ activateListeners()
 	int actSocks;
 	DEFiRet;
 
-	/* first apply some config settings */
-#	ifdef OS_SOLARIS
-		/* under solaris, we must NEVER process the local log socket, because
-		 * it is implemented there differently. If we used it, we would actually
-		 * delete it and render the system partly unusable. So don't do that.
-		 * rgerhards, 2010-03-26
-		 */
-		startIndexUxLocalSockets = 1;
-#	else
-		startIndexUxLocalSockets = runModConf->bOmitLocalLogging ? 1 : 0;
-#	endif
-	if(runModConf->pLogSockName != NULL)
-		listeners[0].sockName = runModConf->pLogSockName;
-	else if(sd_booted()) {
-		struct stat st;
-		if(stat(SYSTEMD_PATH_LOG, &st) != -1 && S_ISSOCK(st.st_mode)) {
-			listeners[0].sockName = (uchar*) SYSTEMD_PATH_LOG;
+	/* Initialize the system socket only if it's in use */
+	if(startIndexUxLocalSockets == 0) {
+		/* first apply some config settings */
+		listeners[0].sockName = UCHAR_CONSTANT(_PATH_LOG);
+		if(runModConf->pLogSockName != NULL)
+			listeners[0].sockName = runModConf->pLogSockName;
+		else if(sd_booted()) {
+			struct stat st;
+			if(stat(SYSTEMD_PATH_LOG, &st) != -1 && S_ISSOCK(st.st_mode)) {
+				listeners[0].sockName = (uchar*) SYSTEMD_PATH_LOG;
+			}
 		}
-	}
-	if(runModConf->ratelimitIntervalSysSock > 0) {
-		if((listeners[0].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) {
-			/* in this case, we simply turn of rate-limiting */
-			errmsg.LogError(0, NO_ERRCODE, "imuxsock: turning off rate limiting because we could not "
-				  "create hash table\n");
-			runModConf->ratelimitIntervalSysSock = 0;
+		if(runModConf->ratelimitIntervalSysSock > 0) {
+			if((listeners[0].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) {
+				/* in this case, we simply turn of rate-limiting */
+				errmsg.LogError(0, NO_ERRCODE, "imuxsock: turning off rate limiting because we could not "
+						"create hash table\n");
+				runModConf->ratelimitIntervalSysSock = 0;
+			}
+		} else {
+			listeners[0].ht = NULL;
 		}
-	}
-	listeners[0].ratelimitInterval = runModConf->ratelimitIntervalSysSock;
-	listeners[0].ratelimitBurst = runModConf->ratelimitBurstSysSock;
-	listeners[0].ratelimitSev = runModConf->ratelimitSeveritySysSock;
-	listeners[0].bUseCreds = (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock || runModConf->bAnnotateSysSock || runModConf->bDiscardOwnMsgs || runModConf->bUseSysTimeStamp) ? 1 : 0;
-	listeners[0].bWritePid = runModConf->bWritePidSysSock;
-	listeners[0].bAnnotate = runModConf->bAnnotateSysSock;
-	listeners[0].bParseTrusted = runModConf->bParseTrusted;
-	listeners[0].bDiscardOwnMsgs = runModConf->bDiscardOwnMsgs;
-	listeners[0].bUnlink = runModConf->bUnlink;
-	listeners[0].bUseSysTimeStamp = runModConf->bUseSysTimeStamp;
-	listeners[0].flags = runModConf->bIgnoreTimestamp ? IGNDATE : NOFLAG;
-	listeners[0].flowCtl = runModConf->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
-	CHKiRet(ratelimitNew(&listeners[0].dflt_ratelimiter, "imuxsock", NULL));
+		listeners[0].fd = -1;
+		listeners[0].hostName = NULL;
+		listeners[0].bParseHost = 0;
+		listeners[0].bCreatePath = 0;
+		listeners[0].ratelimitInterval = runModConf->ratelimitIntervalSysSock;
+		listeners[0].ratelimitBurst = runModConf->ratelimitBurstSysSock;
+		listeners[0].ratelimitSev = runModConf->ratelimitSeveritySysSock;
+		listeners[0].bUseCreds = (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock || runModConf->bAnnotateSysSock || runModConf->bDiscardOwnMsgs || runModConf->bUseSysTimeStamp) ? 1 : 0;
+		listeners[0].bWritePid = runModConf->bWritePidSysSock;
+		listeners[0].bAnnotate = runModConf->bAnnotateSysSock;
+		listeners[0].bParseTrusted = runModConf->bParseTrusted;
+		listeners[0].bDiscardOwnMsgs = runModConf->bDiscardOwnMsgs;
+		listeners[0].bUnlink = runModConf->bUnlink;
+		listeners[0].bUseSysTimeStamp = runModConf->bUseSysTimeStamp;
+		listeners[0].flags = runModConf->bIgnoreTimestamp ? IGNDATE : NOFLAG;
+		listeners[0].flowCtl = runModConf->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
+		CHKiRet(ratelimitNew(&listeners[0].dflt_ratelimiter, "imuxsock", NULL));
+
 		ratelimitSetLinuxLike(listeners[0].dflt_ratelimiter,
-		listeners[0].ratelimitInterval,
-		listeners[0].ratelimitBurst);
-	ratelimitSetSeverity(listeners[0].dflt_ratelimiter,listeners[0].ratelimitSev);
+				      listeners[0].ratelimitInterval,
+				      listeners[0].ratelimitBurst);
+		ratelimitSetSeverity(listeners[0].dflt_ratelimiter,listeners[0].ratelimitSev);
+	}
 
 	sd_fds = sd_listen_fds(0);
 	if(sd_fds < 0) {
@@ -1286,12 +1284,39 @@ ENDcheckCnf
 
 BEGINactivateCnfPrePrivDrop
 	instanceConf_t *inst;
+	int nLstn;
+	int i;
 CODESTARTactivateCnfPrePrivDrop
 	runModConf = pModConf;
+#	ifdef OS_SOLARIS
+		/* under solaris, we must NEVER process the local log socket, because
+		 * it is implemented there differently. If we used it, we would actually
+		 * delete it and render the system partly unusable. So don't do that.
+		 * rgerhards, 2010-03-26
+		 */
+		startIndexUxLocalSockets = 1;
+#	else
+		startIndexUxLocalSockets = runModConf->bOmitLocalLogging ? 1 : 0;
+#	endif
+	/* we first calculate the number of listeners so that we can
+	 * appropriately size the listener array.
+	 */
+	nLstn = 0;
 	for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
-		addListner(inst);
+		++nLstn;
+	}
+	if(nLstn > 0 || startIndexUxLocalSockets == 0) {
+		DBGPRINTF("imuxsock: allocating memory for %d listeners\n", nLstn);
+		CHKmalloc(listeners = realloc(listeners, (1+nLstn)*sizeof(lstn_t)));
+		for(i = 1 ; i < nLstn ; ++i) {
+			listeners[i].sockName = NULL;
+			listeners[i].fd  = -1;
+		}
+		for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
+			addListner(inst);
+		}
+		CHKiRet(activateListeners());
 	}
-	CHKiRet(activateListeners());
 finalize_it:
 ENDactivateCnfPrePrivDrop
 
@@ -1329,6 +1354,11 @@ BEGINrunInput
 #endif
 
 CODESTARTrunInput
+	CHKmalloc(pReadfds);
+	if(startIndexUxLocalSockets == 1 && nfd == 1) {
+		/* No sockets were configured, no reason to run. */
+		ABORT_FINALIZE(RS_RET_OK);
+	}
 	/* this is an endless loop - it is terminated when the thread is
 	 * signalled to do so. This, however, is handled by the framework,
 	 * right into the sleep below.
@@ -1364,7 +1394,7 @@ CODESTARTrunInput
 		if(glbl.GetGlobalInputTermState() == 1)
 			break; /* terminate input! */
 
-		for (i = 0; i < nfd && nfds > 0; i++) {
+		for (i = startIndexUxLocalSockets; i < nfd && nfds > 0; i++) {
 			if(glbl.GetGlobalInputTermState() == 1)
 				ABORT_FINALIZE(RS_RET_FORCE_TERM); /* terminate input! */
 			if ((fd = listeners[i].fd) != -1 && FD_ISSET(fd, pReadfds)) {
@@ -1419,6 +1449,7 @@ ENDafterRun
 
 BEGINmodExit
 CODESTARTmodExit
+	free(listeners);
 	if(pInputName != NULL)
 		prop.Destruct(&pInputName);
 
@@ -1481,7 +1512,6 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
 
 
 BEGINmodInit()
-	int i;
 CODESTARTmodInit
 	*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
 CODEmodInit_QueryRegCFSLineHdlr
@@ -1511,34 +1541,6 @@ CODEmodInit_QueryRegCFSLineHdlr
 	 */
 	pLocalHostIP = glbl.GetLocalHostIP();
 
-	/* init system log socket settings */
-	listeners[0].flags = IGNDATE;
-	listeners[0].sockName = UCHAR_CONSTANT(_PATH_LOG);
-	listeners[0].hostName = NULL;
-	listeners[0].flowCtl = eFLOWCTL_NO_DELAY;
-	listeners[0].fd = -1;
-	listeners[0].bParseHost = 0;
-	listeners[0].bUseCreds = 0;
-	listeners[0].bAnnotate = 0;
-	listeners[0].bParseTrusted = 0;
-	listeners[0].bDiscardOwnMsgs = 1;
-	listeners[0].bUnlink = 1;
-	listeners[0].bCreatePath = 0;
-	listeners[0].bUseSysTimeStamp = 1;
-	if((listeners[0].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn,
-		(void(*)(void*))ratelimitDestruct)) == NULL) {
-		/* in this case, we simply turn off rate-limiting */
-		DBGPRINTF("imuxsock: turning off rate limiting for system socket "
-			  "because we could not create hash table\n");
-		listeners[0].ratelimitInterval = 0;
-	}
-
-	/* initialize socket names */
-	for(i = 1 ; i < MAXFUNIX ; ++i) {
-		listeners[i].sockName = NULL;
-		listeners[i].fd  = -1;
-	}
-
 	/* register config file handlers */
 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketignoremsgtimestamp", 0, eCmdHdlrBinary,
 		NULL, &cs.bIgnoreTimestamp, STD_LOADABLE_MODULE_ID));
-- 
1.9.3