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