1 /**\file srUtils.c
2  * \brief General utilties that fit nowhere else.
3  *
4  * The namespace for this file is "srUtil".
5  *
6  * \author  Rainer Gerhards <rgerhards@adiscon.com>
7  * \date    2003-09-09
8  *          Coding begun.
9  *
10  * Copyright 2003-2018 Rainer Gerhards and Adiscon GmbH.
11  *
12  * This file is part of the rsyslog runtime library.
13  *
14  * The rsyslog runtime library is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * The rsyslog runtime library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with the rsyslog runtime library.  If not, see <http://www.gnu.org/licenses/>.
26  *
27  * A copy of the GPL can be found in the file "COPYING" in this distribution.
28  * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
29  */
30 #include "config.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <signal.h>
40 #include <assert.h>
41 #include <sys/wait.h>
42 #include <ctype.h>
43 #include <inttypes.h>
44 #include <fcntl.h>
45 
46 #include "rsyslog.h"
47 #include "srUtils.h"
48 #include "obj.h"
49 #include "errmsg.h"
50 #include "glbl.h"
51 
52 #if _POSIX_TIMERS <= 0
53 #include <sys/time.h>
54 #endif
55 
56 /* here we host some syslog specific names. There currently is no better place
57  * to do it, but over here is also not ideal... -- rgerhards, 2008-02-14
58  * rgerhards, 2008-04-16: note in LGPL move: the code tables below exist in
59  * the same way in BSD, so it is not a problem to move them from GPLv3 to LGPL.
60  * And nobody modified them since it was under LGPL, so we can also move it
61  * to ASL 2.0.
62  */
63 syslogName_t	syslogPriNames[] = {
64 	{"alert",	LOG_ALERT},
65 	{"crit",	LOG_CRIT},
66 	{"debug",	LOG_DEBUG},
67 	{"emerg",	LOG_EMERG},
68 	{"err",		LOG_ERR},
69 	{"error",	LOG_ERR},		/* DEPRECATED */
70 	{"info",	LOG_INFO},
71 	{"none",	INTERNAL_NOPRI},	/* INTERNAL */
72 	{"notice",	LOG_NOTICE},
73 	{"panic",	LOG_EMERG},		/* DEPRECATED */
74 	{"warn",	LOG_WARNING},		/* DEPRECATED */
75 	{"warning",	LOG_WARNING},
76 	{"*",		TABLE_ALLPRI},
77 	{NULL,		-1}
78 };
79 
80 #ifndef LOG_AUTHPRIV
81 #	define LOG_AUTHPRIV LOG_AUTH
82 #endif
83 syslogName_t	syslogFacNames[] = {
84 	{"auth",         LOG_AUTH},
85 	{"authpriv",     LOG_AUTHPRIV},
86 	{"cron",         LOG_CRON},
87 	{"daemon",       LOG_DAEMON},
88 	{"kern",         LOG_KERN},
89 	{"lpr",          LOG_LPR},
90 	{"mail",         LOG_MAIL},
91 	{"mark",         LOG_MARK},		/* INTERNAL */
92 	{"news",         LOG_NEWS},
93 	{"ntp",          (12<<3) },             /* NTP, perhaps BSD-specific? */
94 	{"security",     LOG_AUTH},		/* DEPRECATED */
95 	{"bsd_security", (13<<3) },		/* BSD-specific, unfortunatly with duplicate name... */
96 	{"syslog",       LOG_SYSLOG},
97 	{"user",         LOG_USER},
98 	{"uucp",         LOG_UUCP},
99 #if defined(_AIX)  /* AIXPORT : These are necessary for AIX */
100 	{ "caa",         LOG_CAA },
101 	{ "aso",         LOG_ASO },
102 #endif
103 #if defined(LOG_FTP)
104 	{"ftp",          LOG_FTP},
105 #endif
106 #if defined(LOG_AUDIT)
107 	{"audit",        LOG_AUDIT},
108 #endif
109 	{"console",	 (14 << 3)},		/* BSD-specific priority */
110 	{"local0",       LOG_LOCAL0},
111 	{"local1",       LOG_LOCAL1},
112 	{"local2",       LOG_LOCAL2},
113 	{"local3",       LOG_LOCAL3},
114 	{"local4",       LOG_LOCAL4},
115 	{"local5",       LOG_LOCAL5},
116 	{"local6",       LOG_LOCAL6},
117 	{"local7",       LOG_LOCAL7},
118 	{"invld",        LOG_INVLD},
119 	{NULL,           -1},
120 };
121 
122 /* ################################################################# *
123  * private members                                                   *
124  * ################################################################# */
125 
126 /* As this is not a "real" object, there won't be any private
127  * members in this file.
128  */
129 
130 /* ################################################################# *
131  * public members                                                    *
132  * ################################################################# */
133 
srUtilItoA(char * pBuf,int iLenBuf,number_t iToConv)134 rsRetVal srUtilItoA(char *pBuf, int iLenBuf, number_t iToConv)
135 {
136 	int i;
137 	int bIsNegative;
138 	char szBuf[64];	/* sufficiently large for my lifespan and those of my children... ;) */
139 
140 	assert(pBuf != NULL);
141 	assert(iLenBuf > 1);	/* This is actually an app error and as thus checked for... */
142 
143 	if(iToConv < 0)
144 	{
145 		bIsNegative = RSTRUE;
146 		iToConv *= -1;
147 	}
148 	else
149 		bIsNegative = RSFALSE;
150 
151 	/* first generate a string with the digits in the reverse direction */
152 	i = 0;
153 	do
154 	{
155 		szBuf[i++] = iToConv % 10 + '0';
156 		iToConv /= 10;
157 	} while(iToConv > 0);	/* warning: do...while()! */
158 	--i; /* undo last increment - we were pointing at NEXT location */
159 
160 	/* make sure we are within bounds... */
161 	if(i + 2 > iLenBuf)	/* +2 because: a) i starts at zero! b) the \0 byte */
162 		return RS_RET_PROVIDED_BUFFER_TOO_SMALL;
163 
164 	/* then move it to the right direction... */
165 	if(bIsNegative == RSTRUE)
166 		*pBuf++ = '-';
167 	while(i >= 0)
168 		*pBuf++ = szBuf[i--];
169 	*pBuf = '\0';	/* terminate it!!! */
170 
171 	return RS_RET_OK;
172 }
173 
srUtilStrDup(uchar * pOld,size_t len)174 uchar *srUtilStrDup(uchar *pOld, size_t len)
175 {
176 	uchar *pNew;
177 
178 	assert(pOld != NULL);
179 
180 	if((pNew = malloc(len + 1)) != NULL)
181 		memcpy(pNew, pOld, len + 1);
182 
183 	return pNew;
184 }
185 
186 
187 /* creates a path recursively
188  * Return 0 on success, -1 otherwise. On failure, errno * hold the last OS error.
189  * Param "mode" holds the mode that all non-existing directories are to be
190  * created with.
191  * Note that we have a potential race inside that code, a race that even exists
192  * outside of the rsyslog process (if multiple instances run, or other programs
193  * generate directories): If the directory does not exist, a context switch happens,
194  * at that moment another process creates it, then our creation on the context
195  * switch back fails. This actually happened in practice, and depending on the
196  * configuration it is even likely to happen. We can not solve this situation
197  * with a mutex, as that works only within out process space. So the solution
198  * is that we take the optimistic approach, try the creation, and if it fails
199  * with "already exists" we go back and do one retry of the check/create
200  * sequence. That should then succeed. If the directory is still not found but
201  * the creation fails in the similar way, we return an error on that second
202  * try because otherwise we would potentially run into an endless loop.
203  * loop. -- rgerhards, 2010-03-25
204  * The likeliest scenario for a prolonged contest of creating the parent directiories
205  * is within our process space. This can happen with a high probability when two
206  * threads, that want to start logging to files within same directory tree, are
207  * started close to each other. We should fix what we can. -- nipakoo, 2017-11-25
208  */
real_makeFileParentDirs(const uchar * const szFile,const size_t lenFile,const mode_t mode,const uid_t uid,const gid_t gid,const int bFailOnChownFail)209 static int real_makeFileParentDirs(const uchar *const szFile, const size_t lenFile, const mode_t mode,
210 	const uid_t uid, const gid_t gid, const int bFailOnChownFail)
211 {
212 	uchar *p;
213 	uchar *pszWork;
214 	size_t len;
215 
216 	assert(szFile != NULL);
217 	assert(lenFile > 0);
218 
219 	len = lenFile + 1; /* add one for '\0'-byte */
220 	if((pszWork = malloc(len)) == NULL)
221 		return -1;
222 	memcpy(pszWork, szFile, len);
223 	for(p = pszWork+1 ; *p ; p++)
224 		if(*p == '/') {
225 			/* temporarily terminate string, create dir and go on */
226 			*p = '\0';
227 			int bErr = 0;
228 			if(mkdir((char*)pszWork, mode) == 0) {
229 				if(uid != (uid_t) -1 || gid != (gid_t) -1) {
230 					/* we need to set owner/group */
231 					if(chown((char*)pszWork, uid, gid) != 0) {
232 						LogError(errno, RS_RET_DIR_CHOWN_ERROR,
233 							"chown for directory '%s' failed", pszWork);
234 						if(bFailOnChownFail) {
235 							/* ignore if configured to do so */
236 							bErr = 1;
237 						}
238 					}
239 				}
240 			} else if(errno != EEXIST) {
241 				/* EEXIST is ok, means this component exists */
242 				bErr = 1;
243 			}
244 
245 			if(bErr) {
246 				int eSave = errno;
247 				free(pszWork);
248 				errno = eSave;
249 				return -1;
250 			}
251 			*p = '/';
252 		}
253 	free(pszWork);
254 	return 0;
255 }
256 /* note: this small function is the stub for the brain-dead POSIX cancel handling */
makeFileParentDirs(const uchar * const szFile,const size_t lenFile,const mode_t mode,const uid_t uid,const gid_t gid,const int bFailOnChownFail)257 int makeFileParentDirs(const uchar *const szFile, const size_t lenFile, const mode_t mode,
258 		       const uid_t uid, const gid_t gid, const int bFailOnChownFail)
259 {
260 	static pthread_mutex_t mutParentDir = PTHREAD_MUTEX_INITIALIZER;
261 	int r;	/* needs to be declared OUTSIDE of pthread_cleanup... macros! */
262 	pthread_mutex_lock(&mutParentDir);
263 	pthread_cleanup_push(mutexCancelCleanup, &mutParentDir);
264 
265 	r = real_makeFileParentDirs(szFile, lenFile, mode, uid, gid, bFailOnChownFail);
266 
267 	pthread_mutex_unlock(&mutParentDir);
268 	pthread_cleanup_pop(0);
269 	return r;
270 }
271 
272 
273 /* execute a program with a single argument
274  * returns child pid if everything ok, 0 on failure. if
275  * it fails, errno is set. if it fails after the fork(), the caller
276  * can not be notfied for obvious reasons. if bwait is set to 1,
277  * the code waits until the child terminates - that potentially takes
278  * a lot of time.
279  * implemented 2007-07-20 rgerhards
280  */
execProg(uchar * program,int bWait,uchar * arg)281 int execProg(uchar *program, int bWait, uchar *arg)
282 {
283 	int pid;
284 	int sig;
285 	struct sigaction sigAct;
286 
287 	dbgprintf("exec program '%s' with param '%s'\n", program, arg);
288 	pid = fork();
289 	if (pid < 0) {
290 		return 0;
291 	}
292 
293 	if(pid) {       /* Parent */
294 		if(bWait) {
295 			/* waitpid will fail with errno == ECHILD if the child process has already
296 			   been reaped by the rsyslogd main loop (see rsyslogd.c) */
297 			int status;
298 			if(waitpid(pid, &status, 0) == pid) {
299 				glblReportChildProcessExit(program, pid, status);
300 			} else if(errno != ECHILD) {
301 				/* we do not use logerror(), because
302 				* that might bring us into an endless
303 				* loop. At some time, we may
304 				* reconsider this behaviour.
305 				*/
306 				dbgprintf("could not wait on child after executing '%s'",
307 						(char*)program);
308 			}
309 		}
310 		return pid;
311 	}
312 	/* Child */
313 	alarm(0); /* create a clean environment before we exec the real child */
314 
315 	memset(&sigAct, 0, sizeof(sigAct));
316 	sigemptyset(&sigAct.sa_mask);
317 	sigAct.sa_handler = SIG_DFL;
318 
319 	for(sig = 1 ; sig < NSIG ; ++sig)
320 		sigaction(sig, &sigAct, NULL);
321 
322 	execlp((char*)program, (char*) program, (char*)arg, NULL);
323 	/* In the long term, it's a good idea to implement some enhanced error
324 	 * checking here. However, it can not easily be done. For starters, we
325 	 * may run into endless loops if we log to syslog. The next problem is
326 	 * that output is typically not seen by the user. For the time being,
327 	 * we use no error reporting, which is quite consitent with the old
328 	 * system() way of doing things. rgerhards, 2007-07-20
329 	 */
330 	perror("exec");
331 	fprintf(stderr, "exec program was '%s' with param '%s'\n", program, arg);
332 	exit(1); /* not much we can do in this case */
333 }
334 
335 
336 /* skip over whitespace in a standard C string. The
337  * provided pointer is advanced to the first non-whitespace
338  * charater or the \0 byte, if there is none. It is never
339  * moved past the \0.
340  */
skipWhiteSpace(uchar ** pp)341 void skipWhiteSpace(uchar **pp)
342 {
343 	register uchar *p;
344 
345 	assert(pp != NULL);
346 	assert(*pp != NULL);
347 
348 	p = *pp;
349 	while(*p && isspace((int) *p))
350 		++p;
351 	*pp = p;
352 }
353 
354 
355 /* generate a file name from four parts:
356  * <directory name>/<name>.<number>
357  * If number is negative, it is not used. If any of the strings is
358  * NULL, an empty string is used instead. Length must be provided.
359  * lNumDigits is the minimum number of digits that lNum should have. This
360  * is to pretty-print the file name, e.g. lNum = 3, lNumDigits= 4 will
361  * result in "0003" being used inside the file name. Set lNumDigits to 0
362  * to use as few space as possible.
363  * rgerhards, 2008-01-03
364  */
365 PRAGMA_DIAGNOSTIC_PUSH
366 PRAGMA_IGNORE_Wformat_nonliteral
genFileName(uchar ** ppName,uchar * pDirName,size_t lenDirName,uchar * pFName,size_t lenFName,int64_t lNum,int lNumDigits)367 rsRetVal genFileName(uchar **ppName, uchar *pDirName, size_t lenDirName, uchar *pFName,
368 		     size_t lenFName, int64_t lNum, int lNumDigits)
369 {
370 	DEFiRet;
371 	uchar *pName;
372 	uchar *pNameWork;
373 	size_t lenName;
374 	uchar szBuf[128];	/* buffer for number */
375 	char szFmtBuf[32];	/* buffer for snprintf format */
376 	size_t lenBuf;
377 
378 	if(lNum < 0) {
379 		szBuf[0] = '\0';
380 		lenBuf = 0;
381 	} else {
382 		if(lNumDigits > 0) {
383 			snprintf(szFmtBuf, sizeof(szFmtBuf), ".%%0%d" PRId64, lNumDigits);
384 			lenBuf = snprintf((char*)szBuf, sizeof(szBuf), szFmtBuf, lNum);
385 		} else
386 			lenBuf = snprintf((char*)szBuf, sizeof(szBuf), ".%" PRId64, lNum);
387 	}
388 
389 	lenName = lenDirName + 1 + lenFName + lenBuf + 1; /* last +1 for \0 char! */
390 	if((pName = malloc(lenName)) == NULL)
391 		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
392 
393 	/* got memory, now construct string */
394 	memcpy(pName, pDirName, lenDirName);
395 	pNameWork = pName + lenDirName;
396 	*pNameWork++ = '/';
397 	memcpy(pNameWork, pFName, lenFName);
398 	pNameWork += lenFName;
399 	if(lenBuf > 0) {
400 		memcpy(pNameWork, szBuf, lenBuf);
401 		pNameWork += lenBuf;
402 	}
403 	*pNameWork = '\0';
404 
405 	*ppName = pName;
406 
407 finalize_it:
408 	RETiRet;
409 }
410 PRAGMA_DIAGNOSTIC_POP
411 
412 /* get the number of digits required to represent a given number. We use an
413  * iterative approach as we do not like to draw in the floating point
414  * library just for log(). -- rgerhards, 2008-01-10
415  */
getNumberDigits(long lNum)416 int getNumberDigits(long lNum)
417 {
418 	int iDig;
419 
420 	if(lNum == 0)
421 		iDig = 1;
422 	else
423 		for(iDig = 0 ; lNum != 0 ; ++iDig)
424 			lNum /= 10;
425 
426 	return iDig;
427 }
428 
429 
430 /* compute an absolute time timeout suitable for calls to pthread_cond_timedwait()
431  * iTimeout is in milliseconds
432  * rgerhards, 2008-01-14
433  */
434 rsRetVal
timeoutComp(struct timespec * pt,long iTimeout)435 timeoutComp(struct timespec *pt, long iTimeout)
436 {
437 #	if _POSIX_TIMERS <= 0
438 	struct timeval tv;
439 #	endif
440 
441 	assert(pt != NULL);
442 	/* compute timeout */
443 
444 #	if _POSIX_TIMERS > 0
445 	/* this is the "regular" code */
446 	clock_gettime(CLOCK_REALTIME, pt);
447 #	else
448 	gettimeofday(&tv, NULL);
449 	pt->tv_sec = tv.tv_sec;
450 	pt->tv_nsec = tv.tv_usec * 1000;
451 #	endif
452 	pt->tv_sec += iTimeout / 1000;
453 	pt->tv_nsec += (iTimeout % 1000) * 1000000; /* think INTEGER arithmetic! */
454 	if(pt->tv_nsec > 999999999) { /* overrun? */
455 		pt->tv_nsec -= 1000000000;
456 		++pt->tv_sec;
457 	}
458 	return RS_RET_OK; /* so far, this is static... */
459 }
460 
461 long long
currentTimeMills(void)462 currentTimeMills(void)
463 {
464 	struct timespec tm;
465 #	if _POSIX_TIMERS <= 0
466 	struct timeval tv;
467 #	endif
468 
469 #	if _POSIX_TIMERS > 0
470 	clock_gettime(CLOCK_REALTIME, &tm);
471 #	else
472 	gettimeofday(&tv, NULL);
473 	tm.tv_sec = tv.tv_sec;
474 	tm.tv_nsec = tv.tv_usec * 1000;
475 #	endif
476 
477 	return ((long long) tm.tv_sec) * 1000 + (tm.tv_nsec / 1000000);
478 }
479 
480 
481 /* This function is kind of the reverse of timeoutComp() - it takes an absolute
482  * timeout value and computes how far this is in the future. If the value is already
483  * in the past, 0 is returned. The return value is in ms.
484  * rgerhards, 2008-01-25
485  */
486 long
timeoutVal(struct timespec * pt)487 timeoutVal(struct timespec *pt)
488 {
489 	struct timespec t;
490 	long iTimeout;
491 #	if _POSIX_TIMERS <= 0
492 	struct timeval tv;
493 #	endif
494 
495 	assert(pt != NULL);
496 	/* compute timeout */
497 #	if _POSIX_TIMERS > 0
498 	/* this is the "regular" code */
499 	clock_gettime(CLOCK_REALTIME, &t);
500 #	else
501 	gettimeofday(&tv, NULL);
502 	t.tv_sec = tv.tv_sec;
503 	t.tv_nsec = tv.tv_usec * 1000;
504 #	endif
505 	iTimeout = (pt->tv_nsec - t.tv_nsec) / 1000000;
506 	iTimeout += (pt->tv_sec - t.tv_sec) * 1000;
507 
508 	if(iTimeout < 0)
509 		iTimeout = 0;
510 
511 	return iTimeout;
512 }
513 
514 
515 /* cancellation cleanup handler - frees provided mutex
516  * rgerhards, 2008-01-14
517  */
518 void
mutexCancelCleanup(void * arg)519 mutexCancelCleanup(void *arg)
520 {
521 	assert(arg != NULL);
522 	d_pthread_mutex_unlock((pthread_mutex_t*) arg);
523 }
524 
525 
526 /* rsSleep() - a fairly portable way to to sleep. It
527  * will wake up when
528  * a) the wake-time is over
529  * rgerhards, 2008-01-28
530  */
531 void
srSleep(int iSeconds,int iuSeconds)532 srSleep(int iSeconds, int iuSeconds)
533 {
534 	struct timeval tvSelectTimeout;
535 
536 	tvSelectTimeout.tv_sec = iSeconds;
537 	tvSelectTimeout.tv_usec = iuSeconds; /* micro seconds */
538 	select(0, NULL, NULL, NULL, &tvSelectTimeout);
539 }
540 
541 
542 /* From varmojfekoj's mail on why he provided rs_strerror_r():
543  * There are two problems with strerror_r():
544  * I see you've rewritten some of the code which calls it to use only
545  * the supplied buffer; unfortunately the GNU implementation sometimes
546  * doesn't use the buffer at all and returns a pointer to some
547  * immutable string instead, as noted in the man page.
548  *
549  * The other problem is that on some systems strerror_r() has a return
550  * type of int.
551  *
552  * So I've written a wrapper function rs_strerror_r(), which should
553  * take care of all this and be used instead.
554  *
555  * Added 2008-01-30
556  */
rs_strerror_r(int errnum,char * buf,size_t buflen)557 char *rs_strerror_r(int errnum, char *buf, size_t buflen) {
558 #ifndef HAVE_STRERROR_R
559 	char *pszErr;
560 	pszErr = strerror(errnum);
561 	snprintf(buf, buflen, "%s", pszErr);
562 #else
563 #	ifdef STRERROR_R_CHAR_P
564 		char *p = strerror_r(errnum, buf, buflen);
565 		if (p != buf) {
566 			strncpy(buf, p, buflen);
567 			buf[buflen - 1] = '\0';
568 		}
569 #	else
570 		strerror_r(errnum, buf, buflen);
571 #	endif
572 #endif /* #ifdef __hpux */
573 	return buf;
574 }
575 
576 
577 /*  Decode a symbolic name to a numeric value */
decodeSyslogName(uchar * name,syslogName_t * codetab)578 int decodeSyslogName(uchar *name, syslogName_t *codetab)
579 {
580 	register syslogName_t *c;
581 	register uchar *p;
582 	uchar buf[80];
583 
584 	assert(name != NULL);
585 	assert(codetab != NULL);
586 
587 	DBGPRINTF("symbolic name: %s", name);
588 	if(isdigit((int) *name)) {
589 		DBGPRINTF("\n");
590 		return (atoi((char*) name));
591 	}
592 	strncpy((char*) buf, (char*) name, 79);
593 	for(p = buf; *p; p++) {
594 		if (isupper((int) *p))
595 			*p = tolower((int) *p);
596 	}
597 	for(c = codetab; c->c_name; c++) {
598 		if(!strcmp((char*) buf, (char*) c->c_name)) {
599 			DBGPRINTF(" ==> %d\n", c->c_val);
600 			return (c->c_val);
601 		}
602 	}
603 	DBGPRINTF("\n");
604 	return (-1);
605 }
606 
607 
608 /**
609  * getSubString
610  *
611  * Copy a string byte by byte until the occurrence
612  * of a given separator.
613  *
614  * \param ppSrc		Pointer to a pointer of the source array of characters. If a
615 			separator detected the Pointer points to the next char after the
616 			separator. Except if the end of the string is dedected ('\n').
617 			Then it points to the terminator char.
618  * \param pDst		Pointer to the destination array of characters. Here the substing
619 			will be stored.
620  * \param DstSize	Maximum numbers of characters to store.
621  * \param cSep		Separator char.
622  * \ret int		Returns 0 if no error occured.
623  *
624  * rgerhards, 2008-02-12: some notes are due... I will once again fix this function, this time
625  * so that it treats ' ' as a request for whitespace. But in general, the function and its callers
626  * should be changed over time, this is not really very good code...
627  */
getSubString(uchar ** ppSrc,char * pDst,size_t DstSize,char cSep)628 int getSubString(uchar **ppSrc,  char *pDst, size_t DstSize, char cSep)
629 {
630 	uchar *pSrc = *ppSrc;
631 	int iErr = 0; /* 0 = no error, >0 = error */
632 	while((cSep == ' ' ? !isspace(*pSrc) : *pSrc != cSep) && *pSrc != '\n' && *pSrc != '\0' && DstSize>1) {
633 		*pDst++ = *(pSrc)++;
634 		DstSize--;
635 	}
636 	/* check if the Dst buffer was to small */
637 	if ((cSep == ' ' ? !isspace(*pSrc) : *pSrc != cSep) && *pSrc != '\n' && *pSrc != '\0') {
638 		dbgprintf("in getSubString, error Src buffer > Dst buffer\n");
639 		iErr = 1;
640 	}
641 	if (*pSrc == '\0' || *pSrc == '\n')
642 		/* this line was missing, causing ppSrc to be invalid when it
643 		 * was returned in case of end-of-string. rgerhards 2005-07-29
644 		 */
645 		*ppSrc = pSrc;
646 	else
647 		*ppSrc = pSrc+1;
648 	*pDst = '\0';
649 	return iErr;
650 }
651 
652 
653 /* get the size of a file or return appropriate error code. If an error is returned,
654  * *pSize content is undefined.
655  * rgerhards, 2009-06-12
656  */
657 rsRetVal
getFileSize(uchar * pszName,off_t * pSize)658 getFileSize(uchar *pszName, off_t *pSize)
659 {
660 	int ret;
661 	struct stat statBuf;
662 	DEFiRet;
663 
664 	ret = stat((char*) pszName, &statBuf);
665 	if(ret == -1) {
666 		switch(errno) {
667 			case EACCES: ABORT_FINALIZE(RS_RET_NO_FILE_ACCESS);
668 			case ENOTDIR:
669 			case ENOENT:  ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
670 			default:      ABORT_FINALIZE(RS_RET_FILE_NO_STAT);
671 		}
672 	}
673 
674 	*pSize = statBuf.st_size;
675 
676 finalize_it:
677 	RETiRet;
678 }
679 
680 /* Returns 1 if the given string contains a non-escaped glob(3)
681  * wildcard character and 0 otherwise (or if the string is empty).
682  */
683 int
containsGlobWildcard(char * str)684 containsGlobWildcard(char *str)
685 {
686 	char *p;
687 	if(!str) {
688 		return 0;
689 	}
690 	/* From Linux Programmer's Guide:
691 	 * "A string is a wildcard pattern if it contains one of the characters '?', '*', '{' or '['"
692 	 * "One can remove the special meaning of '?', '*', '{' and '[' by preceding them by a backslash"
693 	 */
694 	for(p = str; *p != '\0'; p++) {
695 		if((*p == '?' || *p == '*' || *p == '[' || *p == '{') &&
696 				(p == str || *(p-1) != '\\')) {
697 			return 1;
698 		}
699 	}
700 	return 0;
701 }
702 
seedRandomInsecureNumber(void)703 static void seedRandomInsecureNumber(void)
704 {
705 	struct timespec t;
706 	timeoutComp(&t, 0);
707 	long long x = t.tv_sec * 3 + t.tv_nsec * 2;
708 	srandom((unsigned int) x);
709 }
710 
randomInsecureNumber(void)711 static long int randomInsecureNumber(void)
712 {
713 	return random();
714 }
715 
716 #ifdef OS_LINUX
717 static int fdURandom = -1;
seedRandomNumber(void)718 void seedRandomNumber(void)
719 {
720 	if(fdURandom >= 0) {
721 		/* Already opened. */
722 		return;
723 	}
724 	fdURandom = open("/dev/urandom", O_RDONLY);
725 	if(fdURandom == -1) {
726 		LogError(errno, RS_RET_IO_ERROR, "failed to seed random number generation,"
727 			" will use fallback (open urandom failed)");
728 		seedRandomInsecureNumber();
729 	}
730 }
731 
seedRandomNumberForChild(void)732 void seedRandomNumberForChild(void)
733 {
734 	/* The file descriptor inherited from our parent will have been closed after
735 	 * the fork. Discard this and call seedRandomNumber() to open /dev/urandom
736 	 * again.
737 	 */
738 	fdURandom = -1;
739 	seedRandomNumber();
740 }
741 
randomNumber(void)742 long int randomNumber(void)
743 {
744 	long int ret;
745 	if(fdURandom >= 0) {
746 		if(read(fdURandom, &ret, sizeof(long int)) == -1) {
747 			LogError(errno, RS_RET_IO_ERROR, "failed to generate random number, will"
748 				" use fallback (read urandom failed)");
749 			ret = randomInsecureNumber();
750 		}
751 	} else {
752 		ret = randomInsecureNumber();
753 	}
754 	return ret;
755 }
756 #else
seedRandomNumber(void)757 void seedRandomNumber(void)
758 {
759 	seedRandomInsecureNumber();
760 }
761 
seedRandomNumberForChild(void)762 void seedRandomNumberForChild(void)
763 {
764 	seedRandomNumber();
765 }
766 
randomNumber(void)767 long int randomNumber(void)
768 {
769 	return randomInsecureNumber();
770 }
771 #endif
772 
773 
774 /* process "binary" parameters where this is needed to execute
775  * programs (namely mmexternal and omprog).
776  * Most importantly, split them into argv[] and get the binary name
777  */
ATTR_NONNULL()778 rsRetVal ATTR_NONNULL()
779 split_binary_parameters(uchar **const szBinary, char ***const __restrict__ aParams,
780 	int *const iParams, es_str_t *const param_binary)
781 {
782 	es_size_t iCnt;
783 	es_size_t iStr;
784 	int iPrm;
785 	es_str_t *estrParams = NULL;
786 	es_str_t *estrBinary = param_binary;
787 	es_str_t *estrTmp = NULL;
788 	uchar *c;
789 	int bInQuotes;
790 	DEFiRet;
791 	assert(iParams != NULL);
792 	assert(param_binary != NULL);
793 
794 	/* Search for end of binary name */
795 	c = es_getBufAddr(param_binary);
796 	iCnt = 0;
797 	while(iCnt < es_strlen(param_binary) ) {
798 		if (c[iCnt] == ' ') {
799 			/* Split binary name from parameters */
800 			estrBinary = es_newStrFromSubStr( param_binary, 0, iCnt);
801 			estrParams = es_newStrFromSubStr( param_binary, iCnt+1,
802 					es_strlen(param_binary));
803 			break;
804 		}
805 		iCnt++;
806 	}
807 	*szBinary = (uchar*)es_str2cstr(estrBinary, NULL);
808 	DBGPRINTF("szBinary = '%s'\n", *szBinary);
809 
810 	*iParams = 1; /* we always have argv[0] */
811 	/* count size of argv[] */
812 	if (estrParams != NULL) {
813 		 (*iParams)++; /* last parameter is not counted in loop below! */
814 		if(Debug) {
815 			char *params = es_str2cstr(estrParams, NULL);
816 			dbgprintf("szParams = '%s'\n", params);
817 			free(params);
818 		}
819 		c = es_getBufAddr(estrParams);
820 		for(iCnt = 0 ; iCnt < es_strlen(estrParams) ; ++iCnt) {
821 			if (c[iCnt] == ' ' && c[iCnt-1] != '\\')
822 				 (*iParams)++;
823 		}
824 	}
825 	DBGPRINTF("iParams %d (+1 for NULL terminator)\n", *iParams);
826 
827 	/* create argv[] */
828 	CHKmalloc(*aParams = malloc((*iParams + 1) * sizeof(char*)));
829 	iPrm = 0;
830 	bInQuotes = FALSE;
831 	/* Set first parameter to binary */
832 	(*aParams)[iPrm] = strdup((char*)*szBinary);
833 	iPrm++;
834 	if (estrParams != NULL) {
835 		iCnt = iStr = 0;
836 		c = es_getBufAddr(estrParams); /* Reset to beginning */
837 		while(iCnt < es_strlen(estrParams) ) {
838 			if ( c[iCnt] == ' ' && !bInQuotes ) {
839 				estrTmp = es_newStrFromSubStr( estrParams, iStr, iCnt-iStr);
840 			} else if ( iCnt+1 >= es_strlen(estrParams) ) {
841 				estrTmp = es_newStrFromSubStr( estrParams, iStr, iCnt-iStr+1);
842 			} else if (c[iCnt] == '"') {
843 				bInQuotes = !bInQuotes;
844 			}
845 
846 			if ( estrTmp != NULL ) {
847 				(*aParams)[iPrm] = es_str2cstr(estrTmp, NULL);
848 				iStr = iCnt+1; /* Set new start */
849 				DBGPRINTF("Param (%d): '%s'\n", iPrm, (*aParams)[iPrm]);
850 				es_deleteStr( estrTmp );
851 				estrTmp = NULL;
852 				iPrm++;
853 			}
854 			iCnt++;
855 		}
856 	}
857 	(*aParams)[iPrm] = NULL; /* NULL per argv[] convention */
858 
859 finalize_it:
860 	if(estrBinary != param_binary) {
861 		es_deleteStr(estrBinary);
862 	}
863 	if(estrParams != NULL) {
864 		es_deleteStr(estrParams);
865 	}
866 	RETiRet;
867 }
868