/* parse a character from the config line * added 2007-07-17 by rgerhards * TODO: enhance this function to handle different classes of characters * HINT: check if char is ' and, if so, use 'c' where c may also be things * like \t etc. */ static rsRetVal doGetChar(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal) { DEFiRet; assert(pp != NULL); assert(*pp != NULL); skipWhiteSpace(pp); /* skip over any whitespace */ /* if we are not at a '\0', we have our new char - no validity checks here... */ if(**pp == '\0') { errmsg.LogError(0, RS_RET_NOT_FOUND, "No character available"); iRet = RS_RET_NOT_FOUND; } else { if(pSetHdlr == NULL) { /* we should set value directly to var */ *((uchar*)pVal) = **pp; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, **pp)); } ++(*pp); /* eat processed char */ } finalize_it: RETiRet; }
/* Parse and a word config line option. A word is a consequtive * sequence of non-whitespace characters. pVal must be * a pointer to a string which is to receive the option * value. The returned string must be freed by the caller. * rgerhards, 2007-09-07 * To facilitate multiple instances of the same command line * directive, doGetWord() now checks if pVal is already a * non-NULL pointer. If so, we assume it was created by a previous * incarnation and is automatically freed. This happens only when * no custom handler is defined. If it is, the customer handler * must do the cleanup. I have checked and this was al also memory * leak with some code. Obviously, not a large one. -- rgerhards, 2007-12-20 * Just to clarify: if pVal is parsed to a custom handler, this handler * is responsible for freeing pVal. -- rgerhards, 2008-03-20 */ static rsRetVal doGetWord(uchar **pp, rsRetVal (*pSetHdlr)(void*, uchar*), void *pVal) { DEFiRet; cstr_t *pStrB = NULL; uchar *pNewVal; ASSERT(pp != NULL); ASSERT(*pp != NULL); CHKiRet(getWord(pp, &pStrB)); CHKiRet(cstrConvSzStrAndDestruct(&pStrB, &pNewVal, 0)); DBGPRINTF("doGetWord: get newval '%s' (len %d), hdlr %p\n", pNewVal, (int) ustrlen(pNewVal), pSetHdlr); /* we got the word, now set it */ if(pSetHdlr == NULL) { /* we should set value directly to var */ if(*((uchar**)pVal) != NULL) free(*((uchar**)pVal)); /* free previous entry */ *((uchar**)pVal) = pNewVal; /* set new one */ } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, pNewVal)); } skipWhiteSpace(pp); /* skip over any whitespace */ finalize_it: if(iRet != RS_RET_OK) { if(pStrB != NULL) cstrDestruct(&pStrB); } RETiRet; }
/* parse a syslog name from the string. This is the generic code that is * called by the facility/severity functions. Note that we do not check the * validity of numerical values, something that should probably change over * time (TODO). -- rgerhards, 2008-02-14 */ static rsRetVal doSyslogName(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal, syslogName_t *pNameTable) { DEFiRet; cstr_t *pStrB; int iNewVal; ASSERT(pp != NULL); ASSERT(*pp != NULL); CHKiRet(getWord(pp, &pStrB)); /* get word */ iNewVal = decodeSyslogName(cstrGetSzStr(pStrB), pNameTable); if(pSetHdlr == NULL) { /* we should set value directly to var */ *((int*)pVal) = iNewVal; /* set new one */ } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, iNewVal)); } skipWhiteSpace(pp); /* skip over any whitespace */ finalize_it: if(pStrB != NULL) rsCStrDestruct(&pStrB); RETiRet; }
/* Parse a number from the configuration line. * rgerhards, 2007-07-31 */ static rsRetVal doGetInt(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal) { uchar *p; DEFiRet; int64 i; assert(pp != NULL); assert(*pp != NULL); CHKiRet(doGetSize(pp, NULL,&i)); p = *pp; if(i > 2147483648ll) { /*2^31*/ errmsg.LogError(0, RS_RET_INVALID_VALUE, "value %lld too large for integer argument.", i); ABORT_FINALIZE(RS_RET_INVALID_VALUE); } if(pSetHdlr == NULL) { /* we should set value directly to var */ *((int*)pVal) = (int) i; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, (int) i)); } *pp = p; finalize_it: RETiRet; }
/* Parse a number from the configuration line. * rgerhards, 2007-07-31 */ static rsRetVal doGetInt(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal) { uchar *p; DEFiRet; int64 i; assert(pp != NULL); assert(*pp != NULL); CHKiRet(parseIntVal(pp, &i)); p = *pp; if(pSetHdlr == NULL) { /* we should set value directly to var */ *((int*)pVal) = (int) i; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, (int) i)); } *pp = p; finalize_it: RETiRet; }
/* Parse a number from the configuration line. This is more or less * a shell to call the custom handler. * rgerhards, 2007-07-31 */ static rsRetVal doCustomHdlr(uchar **pp, rsRetVal (*pSetHdlr)(uchar**, void*), void *pVal) { DEFiRet; assert(pp != NULL); assert(*pp != NULL); CHKiRet(pSetHdlr(pp, pVal)); finalize_it: RETiRet; }
/* extract a groupname and return its gid. * rgerhards, 2007-07-17 */ static rsRetVal doGetGID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal) { struct group *pgBuf = NULL; struct group gBuf; DEFiRet; uchar szName[256]; int bufSize = 1024; char * stringBuf = NULL; int err; assert(pp != NULL); assert(*pp != NULL); if(getSubString(pp, (char*) szName, sizeof(szName), ' ') != 0) { errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract group name"); ABORT_FINALIZE(RS_RET_NOT_FOUND); } do { char *p; /* Increase bufsize and try again.*/ bufSize *= 2; CHKmalloc(p = realloc(stringBuf, bufSize)); stringBuf = p; err = getgrnam_r((char*)szName, &gBuf, stringBuf, bufSize, &pgBuf); } while((pgBuf == NULL) && (err == ERANGE)); if(pgBuf == NULL) { if (err != 0) { errmsg.LogError(err, RS_RET_NOT_FOUND, "Query for group '%s' resulted in an error", szName); } else { errmsg.LogError(0, RS_RET_NOT_FOUND, "ID for group '%s' could not be found", szName); } iRet = RS_RET_NOT_FOUND; } else { if(pSetHdlr == NULL) { /* we should set value directly to var */ *((gid_t*)pVal) = pgBuf->gr_gid; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, pgBuf->gr_gid)); } dbgprintf("gid %d obtained for group '%s'\n", (int) pgBuf->gr_gid, szName); } skipWhiteSpace(pp); /* skip over any whitespace */ finalize_it: free(stringBuf); RETiRet; }
/* Parse and interpet a $FileCreateMode and $umask line. This function * pulls the creation mode and, if successful, stores it * into the global variable so that the rest of rsyslogd * opens files with that mode. Any previous value will be * overwritten. * HINT: if we store the creation mode in selector_t, we * can even specify multiple modes simply be virtue of * being placed in the right section of rsyslog.conf * rgerhards, 2007-07-4 (happy independence day to my US friends!) * Parameter **pp has a pointer to the current config line. * On exit, it will be updated to the processed position. */ static rsRetVal doFileCreateMode(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal) { uchar *p; DEFiRet; uchar errMsg[128]; /* for dynamic error messages */ int iVal; assert(pp != NULL); assert(*pp != NULL); skipWhiteSpace(pp); /* skip over any whitespace */ p = *pp; /* for now, we parse and accept only octal numbers * Sequence of tests is important, we are using boolean shortcuts * to avoid addressing invalid memory! */ if(!( (*p == '0') && (*(p+1) && *(p+1) >= '0' && *(p+1) <= '7') && (*(p+2) && *(p+2) >= '0' && *(p+2) <= '7') && (*(p+3) && *(p+3) >= '0' && *(p+3) <= '7') ) ) { snprintf((char*) errMsg, sizeof(errMsg)/sizeof(uchar), "value must be octal (e.g 0644)."); errno = 0; errmsg.LogError(0, RS_RET_INVALID_VALUE, "%s", errMsg); ABORT_FINALIZE(RS_RET_INVALID_VALUE); } /* we reach this code only if the octal number is ok - so we can now * compute the value. */ iVal = (*(p+1)-'0') * 64 + (*(p+2)-'0') * 8 + (*(p+3)-'0'); if(pSetHdlr == NULL) { /* we should set value directly to var */ *((int*)pVal) = iVal; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, iVal)); } p += 4; /* eat the octal number */ *pp = p; finalize_it: RETiRet; }
/* Parse a size from the configuration line. This is basically an integer * syntax, but modifiers may be added after the integer (e.g. 1k to mean * 1024). The size must immediately follow the number. Note that the * param value must be int64! * rgerhards, 2008-01-09 */ static rsRetVal doGetSize(uchar **pp, rsRetVal (*pSetHdlr)(void*, int64), void *pVal) { DEFiRet; int64 i; assert(pp != NULL); assert(*pp != NULL); CHKiRet(parseIntVal(pp, &i)); /* we now check if the next character is one of our known modifiers. * If so, we accept it as such. If not, we leave it alone. tera and * above does not make any sense as that is above a 32-bit int value. */ switch(**pp) { /* traditional binary-based definitions */ case 'k': i *= 1024; ++(*pp); break; case 'm': i *= 1024 * 1024; ++(*pp); break; case 'g': i *= 1024 * 1024 * 1024; ++(*pp); break; case 't': i *= (int64) 1024 * 1024 * 1024 * 1024; ++(*pp); break; /* tera */ case 'p': i *= (int64) 1024 * 1024 * 1024 * 1024 * 1024; ++(*pp); break; /* peta */ case 'e': i *= (int64) 1024 * 1024 * 1024 * 1024 * 1024 * 1024; ++(*pp); break; /* exa */ /* and now the "new" 1000-based definitions */ case 'K': i *= 1000; ++(*pp); break; case 'M': i *= 1000000; ++(*pp); break; case 'G': i *= 1000000000; ++(*pp); break; /* we need to use the multiplication below because otherwise * the compiler gets an error during constant parsing */ case 'T': i *= (int64) 1000 * 1000000000; ++(*pp); break; /* tera */ case 'P': i *= (int64) 1000000 * 1000000000; ++(*pp); break; /* peta */ case 'E': i *= (int64) 1000000000 * 1000000000; ++(*pp); break; /* exa */ } /* done */ if(pSetHdlr == NULL) { /* we should set value directly to var */ *((int64*)pVal) = i; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, i)); } finalize_it: RETiRet; }
/* extract a username and return its uid. * rgerhards, 2007-07-17 */ static rsRetVal doGetUID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal) { struct passwd *ppwBuf; struct passwd pwBuf; DEFiRet; uchar szName[256]; char stringBuf[2048]; /* I hope this is large enough... */ assert(pp != NULL); assert(*pp != NULL); if(getSubString(pp, (char*) szName, sizeof(szName), ' ') != 0) { errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract user name"); ABORT_FINALIZE(RS_RET_NOT_FOUND); } getpwnam_r((char*)szName, &pwBuf, stringBuf, sizeof(stringBuf), &ppwBuf); if(ppwBuf == NULL) { errmsg.LogError(0, RS_RET_NOT_FOUND, "ID for user '%s' could not be found or error", (char*)szName); iRet = RS_RET_NOT_FOUND; } else { if(pSetHdlr == NULL) { /* we should set value directly to var */ *((uid_t*)pVal) = ppwBuf->pw_uid; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, ppwBuf->pw_uid)); } dbgprintf("uid %d obtained for user '%s'\n", (int) ppwBuf->pw_uid, szName); } skipWhiteSpace(pp); /* skip over any whitespace */ finalize_it: RETiRet; }
/* Parse and process an binary cofig option. pVal must be * a pointer to an integer which is to receive the option * value. * rgerhards, 2007-07-15 */ static rsRetVal doBinaryOptionLine(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal) { int iOption; DEFiRet; assert(pp != NULL); assert(*pp != NULL); if((iOption = doParseOnOffOption(pp)) == -1) return RS_RET_ERR; /* nothing left to do */ if(pSetHdlr == NULL) { /* we should set value directly to var */ *((int*)pVal) = iOption; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, iOption)); } skipWhiteSpace(pp); /* skip over any whitespace */ finalize_it: RETiRet; }