summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/cryprov.h14
-rw-r--r--runtime/glbl.c20
-rw-r--r--runtime/glbl.h2
-rw-r--r--runtime/libgcry.c202
-rw-r--r--runtime/libgcry.h10
-rw-r--r--runtime/lmcry_gcry.c66
-rw-r--r--runtime/queue.c126
-rw-r--r--runtime/queue.h11
-rw-r--r--runtime/rsyslog.h2
-rw-r--r--runtime/ruleset.c6
-rw-r--r--runtime/stream.c8
11 files changed, 407 insertions, 60 deletions
diff --git a/runtime/cryprov.h b/runtime/cryprov.h
index 8496b745..66c1cfd1 100644
--- a/runtime/cryprov.h
+++ b/runtime/cryprov.h
@@ -26,14 +26,22 @@
#include <gcrypt.h>
+/* we unfortunately need to have two different param names depending on the
+ * context in which parameters are set. Other than (re/over)engineering the core
+ * interface, we just define some values to keep track of that.
+ */
+#define CRYPROV_PARAMTYPE_REGULAR 0
+#define CRYPROV_PARAMTYPE_DISK 1
+
/* interface */
BEGINinterface(cryprov) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Construct)(void *ppThis);
- rsRetVal (*SetCnfParam)(void *ppThis, struct nvlst *lst);
+ rsRetVal (*SetCnfParam)(void *ppThis, struct nvlst *lst, int paramType);
rsRetVal (*Destruct)(void *ppThis);
- rsRetVal (*OnFileOpen)(void *pThis, uchar *fn, void *pFileInstData);
+ rsRetVal (*OnFileOpen)(void *pThis, uchar *fn, void *pFileInstData, char openMode);
rsRetVal (*Encrypt)(void *pFileInstData, uchar *buf, size_t *lenBuf);
+ rsRetVal (*Decrypt)(void *pFileInstData, uchar *buf, size_t *lenBuf);
rsRetVal (*OnFileClose)(void *pFileInstData, off64_t offsLogfile);
ENDinterface(cryprov)
-#define cryprovCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define cryprovCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */
#endif /* #ifndef INCLUDED_CRYPROV_H */
diff --git a/runtime/glbl.c b/runtime/glbl.c
index b3fe3a1d..ccb978ba 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -89,6 +89,7 @@ static DEF_ATOMIC_HELPER_MUT(mutTerminateInputs);
#ifdef USE_UNLIMITED_SELECT
static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* size of select() bitmask in bytes */
#endif
+static uchar *SourceIPofLocalClient = NULL; /* [ar] Source IP for local client to be used on multihomed host */
/* tables for interfacing with the v6 config system */
@@ -478,6 +479,23 @@ GetDfltNetstrmDrvrCertFile(void)
}
+/* [ar] Source IP for local client to be used on multihomed host */
+static rsRetVal
+SetSourceIPofLocalClient(uchar *newname)
+{
+ if(SourceIPofLocalClient != NULL) {
+ free(SourceIPofLocalClient); }
+ SourceIPofLocalClient = newname;
+ return RS_RET_OK;
+}
+
+static uchar*
+GetSourceIPofLocalClient(void)
+{
+ return(SourceIPofLocalClient);
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-21
*/
@@ -498,6 +516,8 @@ CODESTARTobjQueryInterface(glbl)
pIf->GetLocalHostIP = GetLocalHostIP;
pIf->SetGlobalInputTermination = SetGlobalInputTermination;
pIf->GetGlobalInputTermState = GetGlobalInputTermState;
+ pIf->GetSourceIPofLocalClient = GetSourceIPofLocalClient; /* [ar] */
+ pIf->SetSourceIPofLocalClient = SetSourceIPofLocalClient; /* [ar] */
#define SIMP_PROP(name) \
pIf->Get##name = Get##name; \
pIf->Set##name = Set##name;
diff --git a/runtime/glbl.h b/runtime/glbl.h
index e95e48f7..413f8225 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -81,6 +81,8 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
/* next change is v9! */
/* v8 - 2012-03-21 */
prop_t* (*GetLocalHostIP)(void);
+ prop_t* (*GetSourceIPofLocalClient)(void); /* [ar] */
+ prop_t* (*SetSourceIPofLocalClient)(uchar*); /* [ar] */
#undef SIMP_PROP
ENDinterface(glbl)
#define glblCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
diff --git a/runtime/libgcry.c b/runtime/libgcry.c
index 51c10af4..3fca50ec 100644
--- a/runtime/libgcry.c
+++ b/runtime/libgcry.c
@@ -49,8 +49,10 @@
#include <errno.h>
#include "rsyslog.h"
+#include "srUtils.h"
#include "libgcry.h"
+#define READBUF_SIZE 4096 /* size of the read buffer */
static rsRetVal
eiWriteRec(gcryfile gf, char *recHdr, size_t lenRecHdr, char *buf, size_t lenBuf)
@@ -90,19 +92,66 @@ finalize_it:
RETiRet;
}
+static rsRetVal
+eiRead(gcryfile gf)
+{
+ ssize_t nRead;
+ DEFiRet;
+
+ if(gf->readBuf == NULL) {
+ CHKmalloc(gf->readBuf = malloc(READBUF_SIZE));
+ }
+
+ nRead = read(gf->fd, gf->readBuf, READBUF_SIZE);
+ if(nRead <= 0) { /* TODO: provide specific EOF case? */
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ gf->readBufMaxIdx = (int16_t) nRead;
+ gf->readBufIdx = 0;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* returns EOF on any kind of error */
+static int
+eiReadChar(gcryfile gf)
+{
+ int c;
+
+ if(gf->readBufIdx >= gf->readBufMaxIdx) {
+ if(eiRead(gf) != RS_RET_OK) {
+ c = EOF;
+ goto finalize_it;
+ }
+ }
+ c = gf->readBuf[gf->readBufIdx++];
+finalize_it:
+ return c;
+}
+
static rsRetVal
eiCheckFiletype(gcryfile gf)
{
char hdrBuf[128];
size_t toRead, didRead;
+ sbool bNeedClose = 0;
DEFiRet;
- CHKiRet(eiOpenRead(gf));
+ if(gf->fd == -1) {
+ bNeedClose = 1;
+ CHKiRet(eiOpenRead(gf));
+ }
+
if(Debug) memset(hdrBuf, 0, sizeof(hdrBuf)); /* for dbgprintf below! */
toRead = sizeof("FILETYPE:")-1 + sizeof(RSGCRY_FILETYPE_NAME)-1 + 1;
didRead = read(gf->fd, hdrBuf, toRead);
- close(gf->fd);
+ if(bNeedClose) {
+ close(gf->fd);
+ gf->fd = -1;
+ }
DBGPRINTF("eiCheckFiletype read %d bytes: '%s'\n", didRead, hdrBuf);
if( didRead != toRead
|| strncmp(hdrBuf, "FILETYPE:" RSGCRY_FILETYPE_NAME "\n", toRead))
@@ -111,6 +160,79 @@ finalize_it:
RETiRet;
}
+/* rectype/value must be EIF_MAX_*_LEN+1 long!
+ * returns 0 on success or something else on error/EOF
+ */
+static rsRetVal
+eiGetRecord(gcryfile gf, char *rectype, char *value)
+{
+ unsigned short i, j;
+ int c;
+ DEFiRet;
+
+ for(i = 0 ; i < EIF_MAX_RECTYPE_LEN ; ++i) {
+ c = eiReadChar(gf);
+ if(c == ':' || c == EOF)
+ break;
+ rectype[i] = c;
+ }
+ if(c != ':') { ABORT_FINALIZE(RS_RET_ERR); }
+ rectype[i] = '\0';
+ j = 0;
+ for(++i ; i < EIF_MAX_VALUE_LEN ; ++i, ++j) {
+ c = eiReadChar(gf);
+ if(c == '\n' || c == EOF)
+ break;
+ value[j] = c;
+ }
+ if(c != '\n') { ABORT_FINALIZE(RS_RET_ERR); }
+ value[j] = '\0';
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal
+eiGetIV(gcryfile gf, uchar *iv, size_t leniv)
+{
+ char rectype[EIF_MAX_RECTYPE_LEN+1];
+ char value[EIF_MAX_VALUE_LEN+1];
+ size_t valueLen;
+ unsigned short i, j;
+ unsigned char nibble;
+ DEFiRet;
+
+ CHKiRet(eiGetRecord(gf, rectype, value));
+ if(strcmp(rectype, "IV")) {
+ DBGPRINTF("no IV record found when expected, record type "
+ "seen is '%s'\n", rectype);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ valueLen = strlen(value);
+ if(valueLen/2 != leniv) {
+ DBGPRINTF("length of IV is %d, expected %d\n",
+ valueLen/2, leniv);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ for(i = j = 0 ; i < valueLen ; ++i) {
+ if(value[i] >= '0' && value[i] <= '9')
+ nibble = value[i] - '0';
+ else if(value[i] >= 'a' && value[i] <= 'f')
+ nibble = value[i] - 'a' + 10;
+ else {
+ DBGPRINTF("invalid IV '%s'\n", value);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ if(i % 2 == 0)
+ iv[j] = nibble << 4;
+ else
+ iv[j++] |= nibble;
+ }
+finalize_it:
+ RETiRet;
+}
+
+
static rsRetVal
eiOpenAppend(gcryfile gf)
{
@@ -180,7 +302,9 @@ eiClose(gcryfile gf, off64_t offsLogfile)
/* 2^64 is 20 digits, so the snprintf buffer is large enough */
len = snprintf(offs, sizeof(offs), "%lld", offsLogfile);
eiWriteRec(gf, "END:", 4, offs, len);
+ free(gf->readBuf);
close(gf->fd);
+ gf->fd = -1;
DBGPRINTF("encryption info file %s: closed\n", gf->eiName);
}
@@ -193,6 +317,7 @@ gcryfileConstruct(gcryctx ctx, gcryfile *pgf, uchar *logfn)
CHKmalloc(gf = calloc(1, sizeof(struct gcryfile_s)));
gf->ctx = ctx;
+ gf->fd = -1;
snprintf(fn, sizeof(fn), "%s%s", logfn, ENCINFO_SUFFIX);
fn[MAXFNAME] = '\0'; /* be on save side */
gf->eiName = (uchar*) strdup(fn);
@@ -246,13 +371,13 @@ addPadding(gcryfile pF, uchar *buf, size_t *plen)
}
static inline void
-removePadding(char *buf, size_t *plen)
+removePadding(uchar *buf, size_t *plen)
{
unsigned len = (unsigned) *plen;
unsigned iSrc, iDst;
- char *frstNUL;
+ uchar *frstNUL;
- frstNUL = strchr(buf, 0x00);
+ frstNUL = (uchar*)strchr((char*)buf, 0x00);
if(frstNUL == NULL)
goto done;
iDst = iSrc = frstNUL - buf;
@@ -343,8 +468,31 @@ seedIV(gcryfile gf, uchar **iv)
}
}
+static inline rsRetVal
+readIV(gcryfile gf, uchar **iv)
+{
+ rsRetVal localRet;
+ DEFiRet;
+
+ do {
+ localRet = eiOpenRead(gf);
+ if(localRet == RS_RET_EI_NO_EXISTS) {
+ /* wait until it is created */
+ srSleep(0, 10000);
+ } else {
+ CHKiRet(localRet);
+ }
+ } while(localRet != RS_RET_OK);
+ CHKiRet(eiCheckFiletype(gf));
+ *iv = malloc(gf->blkLength); /* do NOT zero-out! */
+ CHKiRet(eiGetIV(gf, *iv, (size_t) gf->blkLength));
+dbgprintf("DDDD: read %d bytes of IV\n", (int) gf->blkLength);
+finalize_it:
+ RETiRet;
+}
+
rsRetVal
-rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname)
+rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname, char openMode)
{
gcry_error_t gcryError;
gcryfile gf = NULL;
@@ -352,6 +500,7 @@ rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname)
DEFiRet;
CHKiRet(gcryfileConstruct(ctx, &gf, fname));
+ gf->mode = openMode;
gf->blkLength = gcry_cipher_get_algo_blklen(ctx->algo);
@@ -371,7 +520,12 @@ rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname)
ABORT_FINALIZE(RS_RET_ERR);
}
- seedIV(gf, &iv);
+ if(openMode == 'r') {
+ readIV(gf, &iv);
+ } else {
+ seedIV(gf, &iv);
+ }
+
gcryError = gcry_cipher_setiv(gf->chd, iv, gf->blkLength);
if (gcryError) {
dbgprintf("gcry_cipher_setiv failed: %s/%s\n",
@@ -379,8 +533,10 @@ rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname)
gcry_strerror(gcryError));
ABORT_FINALIZE(RS_RET_ERR);
}
- CHKiRet(eiOpenAppend(gf));
- CHKiRet(eiWriteIV(gf, iv));
+ if(openMode == 'w') {
+ CHKiRet(eiOpenAppend(gf));
+ CHKiRet(eiWriteIV(gf, iv));
+ }
*pgf = gf;
finalize_it:
free(iv);
@@ -389,7 +545,7 @@ finalize_it:
RETiRet;
}
-int
+rsRetVal
rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len)
{
int gcryError;
@@ -410,6 +566,32 @@ finalize_it:
RETiRet;
}
+/* TODO: handle multiple blocks
+ * test-read END record; if present, store offset, else unbounded (current active block)
+ * when decrypting, check if bound is reached. If yes, split into two blocks, get new IV for
+ * second one.
+ */
+rsRetVal
+rsgcryDecrypt(gcryfile pF, uchar *buf, size_t *len)
+{
+ gcry_error_t gcryError;
+ DEFiRet;
+
+ gcryError = gcry_cipher_decrypt(pF->chd, buf, *len, NULL, 0);
+ if(gcryError) {
+ DBGPRINTF("gcry_cipher_decrypt failed: %s/%s\n",
+ gcry_strsource(gcryError),
+ gcry_strerror(gcryError));
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ removePadding(buf, len);
+dbgprintf("DDDD: decrypted, buffer is now '%50.50s'\n", buf);
+
+finalize_it:
+ RETiRet;
+}
+
+
/* module-init dummy for potential later use */
int
diff --git a/runtime/libgcry.h b/runtime/libgcry.h
index b77b0f9e..190f4737 100644
--- a/runtime/libgcry.h
+++ b/runtime/libgcry.h
@@ -38,7 +38,11 @@ struct gcryfile_s {
size_t blkLength; /* size of low-level crypto block */
uchar *eiName; /* name of .encinfo file */
int fd; /* descriptor of .encinfo file (-1 if not open) */
+ char mode; /* 'r': read, 'w': write */
gcryctx ctx;
+ uchar *readBuf;
+ int16_t readBufIdx;
+ int16_t readBufMaxIdx;
};
int gcryGetKeyFromFile(char *fn, char **key, unsigned *keylen);
@@ -50,8 +54,10 @@ rsRetVal rsgcrySetAlgo(gcryctx ctx, uchar *modename);
gcryctx gcryCtxNew(void);
void rsgcryCtxDel(gcryctx ctx);
int gcryfileDestruct(gcryfile gf, off64_t offsLogfile);
-rsRetVal rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname);
-int rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len);
+rsRetVal rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname, char openMode);
+rsRetVal rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len);
+rsRetVal rsgcryDecrypt(gcryfile pF, uchar *buf, size_t *len);
+int gcryGetKeyFromProg(char *cmd, char **key, unsigned *keylen);
/* error states */
#define RSGCRYE_EI_OPEN 1 /* error opening .encinfo file */
diff --git a/runtime/lmcry_gcry.c b/runtime/lmcry_gcry.c
index 0a9b94bc..decb8591 100644
--- a/runtime/lmcry_gcry.c
+++ b/runtime/lmcry_gcry.c
@@ -43,17 +43,30 @@ DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
/* tables for interfacing with the v6 config system */
-static struct cnfparamdescr cnfpdescr[] = {
+static struct cnfparamdescr cnfpdescrRegular[] = {
{ "cry.key", eCmdHdlrGetWord, 0 },
{ "cry.keyfile", eCmdHdlrGetWord, 0 },
{ "cry.keyprogram", eCmdHdlrGetWord, 0 },
{ "cry.mode", eCmdHdlrGetWord, 0 }, /* CBC, ECB, etc */
{ "cry.algo", eCmdHdlrGetWord, 0 }
};
-static struct cnfparamblk pblk =
+static struct cnfparamblk pblkRegular =
{ CNFPARAMBLK_VERSION,
- sizeof(cnfpdescr)/sizeof(struct cnfparamdescr),
- cnfpdescr
+ sizeof(cnfpdescrRegular)/sizeof(struct cnfparamdescr),
+ cnfpdescrRegular
+ };
+
+static struct cnfparamdescr cnfpdescrQueue[] = {
+ { "queue.cry.key", eCmdHdlrGetWord, 0 },
+ { "queue.cry.keyfile", eCmdHdlrGetWord, 0 },
+ { "queue.cry.keyprogram", eCmdHdlrGetWord, 0 },
+ { "queue.cry.mode", eCmdHdlrGetWord, 0 }, /* CBC, ECB, etc */
+ { "queue.cry.algo", eCmdHdlrGetWord, 0 }
+};
+static struct cnfparamblk pblkQueue =
+ { CNFPARAMBLK_VERSION,
+ sizeof(cnfpdescrQueue)/sizeof(struct cnfparamdescr),
+ cnfpdescrQueue
};
@@ -85,7 +98,7 @@ ENDobjDestruct(lmcry_gcry)
* Defaults are expected to have been set during construction.
*/
static rsRetVal
-SetCnfParam(void *pT, struct nvlst *lst)
+SetCnfParam(void *pT, struct nvlst *lst, int paramType)
{
lmcry_gcry_t *pThis = (lmcry_gcry_t*) pT;
int i, r;
@@ -97,34 +110,41 @@ SetCnfParam(void *pT, struct nvlst *lst)
uchar *mode = NULL;
int nKeys; /* number of keys (actually methods) specified */
struct cnfparamvals *pvals;
+ struct cnfparamblk *pblk;
DEFiRet;
+ pblk = (paramType == CRYPROV_PARAMTYPE_REGULAR ) ? &pblkRegular : &pblkQueue;
nKeys = 0;
- pvals = nvlstGetParams(lst, &pblk, NULL);
+ pvals = nvlstGetParams(lst, pblk, NULL);
if(Debug) {
dbgprintf("param blk in lmcry_gcry:\n");
- cnfparamsPrint(&pblk, pvals);
+ cnfparamsPrint(pblk, pvals);
}
- for(i = 0 ; i < pblk.nParams ; ++i) {
+ for(i = 0 ; i < pblk->nParams ; ++i) {
if(!pvals[i].bUsed)
continue;
- if(!strcmp(pblk.descr[i].name, "cry.key")) {
+ if(!strcmp(pblk->descr[i].name, "cry.key") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.key")) {
key = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
++nKeys;
- } else if(!strcmp(pblk.descr[i].name, "cry.keyfile")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.keyfile") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.keyfile")) {
keyfile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
++nKeys;
- } else if(!strcmp(pblk.descr[i].name, "cry.keyprogram")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.keyprogram") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.keyprogram")) {
keyprogram = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
++nKeys;
- } else if(!strcmp(pblk.descr[i].name, "cry.mode")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.mode") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.mode")) {
mode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
- } else if(!strcmp(pblk.descr[i].name, "cry.algo")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.algo") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.algo")) {
algo = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else {
DBGPRINTF("lmcry_gcry: program error, non-handled "
- "param '%s'\n", pblk.descr[i].name);
+ "param '%s'\n", pblk->descr[i].name);
}
}
if(algo != NULL) {
@@ -177,7 +197,7 @@ SetCnfParam(void *pT, struct nvlst *lst)
ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
}
- cnfparamvalsDestruct(pvals, &pblk);
+ cnfparamvalsDestruct(pvals, pblk);
if(key != NULL) {
memset(key, 0, strlen((char*)key));
free(key);
@@ -191,13 +211,14 @@ finalize_it:
static rsRetVal
-OnFileOpen(void *pT, uchar *fn, void *pGF)
+OnFileOpen(void *pT, uchar *fn, void *pGF, char openMode)
{
lmcry_gcry_t *pThis = (lmcry_gcry_t*) pT;
gcryfile *pgf = (gcryfile*) pGF;
DEFiRet;
+dbgprintf("DDDD: open file '%s', mode '%c'\n", fn, openMode);
- CHKiRet(rsgcryInitCrypt(pThis->ctx, pgf, fn));
+ CHKiRet(rsgcryInitCrypt(pThis->ctx, pgf, fn, openMode));
finalize_it:
/* TODO: enable this error message (need to cleanup loop first ;))
errmsg.LogError(0, iRet, "Encryption Provider"
@@ -207,6 +228,16 @@ finalize_it:
}
static rsRetVal
+Decrypt(void *pF, uchar *rec, size_t *lenRec)
+{
+ DEFiRet;
+ iRet = rsgcryDecrypt(pF, rec, lenRec);
+
+ RETiRet;
+}
+
+
+static rsRetVal
Encrypt(void *pF, uchar *rec, size_t *lenRec)
{
DEFiRet;
@@ -234,6 +265,7 @@ CODESTARTobjQueryInterface(lmcry_gcry)
pIf->Destruct = (rsRetVal(*)(void*)) lmcry_gcryDestruct;
pIf->OnFileOpen = OnFileOpen;
pIf->Encrypt = Encrypt;
+ pIf->Decrypt = Decrypt;
pIf->OnFileClose = OnFileClose;
finalize_it:
ENDobjQueryInterface(lmcry_gcry)
diff --git a/runtime/queue.c b/runtime/queue.c
index 85b1e45b..6af4905b 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -12,7 +12,7 @@
* function names - this makes it really hard to read and does not provide much
* benefit, at least I (now) think so...
*
- * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2008-2013 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -118,6 +118,7 @@ static struct cnfparamdescr cnfpdescr[] = {
{ "queue.dequeueslowdown", eCmdHdlrInt, 0 },
{ "queue.dequeuetimebegin", eCmdHdlrInt, 0 },
{ "queue.dequeuetimeend", eCmdHdlrInt, 0 },
+ { "queue.cry.provider", eCmdHdlrGetWord, 0 }
};
static struct cnfparamblk pblk =
{ CNFPARAMBLK_VERSION,
@@ -834,6 +835,10 @@ static rsRetVal qConstructDisk(qqueue_t *pThis)
CHKiRet(strm.SetiMaxFiles(pThis->tVars.disk.pWrite, 10000000));
CHKiRet(strm.SettOperationsMode(pThis->tVars.disk.pWrite, STREAMMODE_WRITE));
CHKiRet(strm.SetsType(pThis->tVars.disk.pWrite, STREAMTYPE_FILE_CIRCULAR));
+ if(pThis->useCryprov) {
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pWrite, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pWrite, pThis->cryprovData));
+ }
CHKiRet(strm.ConstructFinalize(pThis->tVars.disk.pWrite));
CHKiRet(strm.Construct(&pThis->tVars.disk.pReadDeq));
@@ -842,6 +847,10 @@ static rsRetVal qConstructDisk(qqueue_t *pThis)
CHKiRet(strm.SetiMaxFiles(pThis->tVars.disk.pReadDeq, 10000000));
CHKiRet(strm.SettOperationsMode(pThis->tVars.disk.pReadDeq, STREAMMODE_READ));
CHKiRet(strm.SetsType(pThis->tVars.disk.pReadDeq, STREAMTYPE_FILE_CIRCULAR));
+ if(pThis->useCryprov) {
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pReadDeq, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pReadDeq, pThis->cryprovData));
+ }
CHKiRet(strm.ConstructFinalize(pThis->tVars.disk.pReadDeq));
CHKiRet(strm.Construct(&pThis->tVars.disk.pReadDel));
@@ -851,6 +860,10 @@ static rsRetVal qConstructDisk(qqueue_t *pThis)
CHKiRet(strm.SetiMaxFiles(pThis->tVars.disk.pReadDel, 10000000));
CHKiRet(strm.SettOperationsMode(pThis->tVars.disk.pReadDel, STREAMMODE_READ));
CHKiRet(strm.SetsType(pThis->tVars.disk.pReadDel, STREAMTYPE_FILE_CIRCULAR));
+ if(pThis->useCryprov) {
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pReadDel, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pReadDel, pThis->cryprovData));
+ }
CHKiRet(strm.ConstructFinalize(pThis->tVars.disk.pReadDel));
CHKiRet(strm.SetFName(pThis->tVars.disk.pWrite, pThis->pszFilePrefix, pThis->lenFilePrefix));
@@ -1320,6 +1333,7 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread
pThis->iMaxFileSize = 1024 * 1024; /* default is 1 MiB */
pThis->iQueueSize = 0;
pThis->nLogDeq = 0;
+ pThis->useCryprov = 0;
pThis->iMaxQueueSize = iMaxQueueSize;
pThis->pConsumer = pConsumer;
pThis->iNumWorkerThreads = iWorkerThreads;
@@ -2389,6 +2403,13 @@ CODESTARTobjDestruct(qqueue)
free(pThis->pszFilePrefix);
free(pThis->pszSpoolDir);
+ if(pThis->useCryprov) {
+ pThis->cryprov.Destruct(&pThis->cryprovData);
+ obj.ReleaseObj(__FILE__, pThis->cryprovNameFull+2, pThis->cryprovNameFull,
+ (void*) &pThis->cryprov);
+ free(pThis->cryprovName);
+ free(pThis->cryprovNameFull);
+ }
/* some queues do not provide stats and thus have no statsobj! */
if(pThis->statsobj != NULL)
@@ -2672,27 +2693,67 @@ finalize_it:
}
-/* take v6 config list and extract the queue params out of it. Hand the
- * param values back to the caller. Caller is responsible for destructing
- * them when no longer needed. Caller can use this param block to configure
- * all parameters for a newly created queue with one call to qqueueSetParams().
- * rgerhards, 2011-07-22
+/* are any queue params set at all? 1 - yes, 0 - no
+ * We need to evaluate the param block for this function, which is somewhat
+ * inefficient. HOWEVER, this is only done during config load, so we really
+ * don't care... -- rgerhards, 2013-05-10
*/
-rsRetVal
-qqueueDoCnfParams(struct nvlst *lst, struct cnfparamvals **ppvals)
+int
+queueCnfParamsSet(struct nvlst *lst)
{
- *ppvals = nvlstGetParams(lst, &pblk, NULL);
- return RS_RET_OK;
+ int r;
+ struct cnfparamvals *pvals;
+
+ pvals = nvlstGetParams(lst, &pblk, NULL);
+ r = cnfparamvalsIsSet(&pblk, pvals);
+ cnfparamvalsDestruct(pvals, &pblk);
+ return r;
}
-/* are any queue params set at all? 1 - yes, 0 - no */
-int
-queueCnfParamsSet(struct cnfparamvals *pvals)
+static inline rsRetVal
+initCryprov(qqueue_t *pThis, struct nvlst *lst)
{
- return cnfparamvalsIsSet(&pblk, pvals);
-}
+ uchar szDrvrName[1024];
+ DEFiRet;
+ if(snprintf((char*)szDrvrName, sizeof(szDrvrName), "lmcry_%s", pThis->cryprovName)
+ == sizeof(szDrvrName)) {
+ errmsg.LogError(0, RS_RET_ERR, "queue: crypto provider "
+ "name is too long: '%s' - encryption disabled",
+ pThis->cryprovName);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ pThis->cryprovNameFull = ustrdup(szDrvrName);
+
+ pThis->cryprov.ifVersion = cryprovCURR_IF_VERSION;
+ /* The pDrvrName+2 below is a hack to obtain the object name. It
+ * safes us to have yet another variable with the name without "lm" in
+ * front of it. If we change the module load interface, we may re-think
+ * about this hack, but for the time being it is efficient and clean enough.
+ */
+ if(obj.UseObj(__FILE__, szDrvrName, szDrvrName, (void*) &pThis->cryprov)
+ != RS_RET_OK) {
+ errmsg.LogError(0, RS_RET_LOAD_ERROR, "queue: could not load "
+ "crypto provider '%s' - encryption disabled",
+ szDrvrName);
+ ABORT_FINALIZE(RS_RET_CRYPROV_ERR);
+ }
+
+ if(pThis->cryprov.Construct(&pThis->cryprovData) != RS_RET_OK) {
+ errmsg.LogError(0, RS_RET_CRYPROV_ERR, "queue: error constructing "
+ "crypto provider %s dataset - encryption disabled",
+ szDrvrName);
+ ABORT_FINALIZE(RS_RET_CRYPROV_ERR);
+ }
+ CHKiRet(pThis->cryprov.SetCnfParam(pThis->cryprovData, lst, CRYPROV_PARAMTYPE_DISK));
+
+ dbgprintf("loaded crypto provider %s, data instance at %p\n",
+ szDrvrName, pThis->cryprovData);
+ pThis->useCryprov = 1;
+finalize_it:
+ RETiRet;
+}
/* apply all params from param block to queue. Must be called before
* finalizing. This supports the v6 config system. Defaults were already
@@ -2700,15 +2761,25 @@ queueCnfParamsSet(struct cnfparamvals *pvals)
* function.
*/
rsRetVal
-qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals)
+qqueueApplyCnfParam(qqueue_t *pThis, struct nvlst *lst)
{
int i;
+ struct cnfparamvals *pvals;
+
+ pvals = nvlstGetParams(lst, &pblk, NULL);
+ if(Debug) {
+ dbgprintf("queue param blk:\n");
+ cnfparamsPrint(&pblk, pvals);
+ }
for(i = 0 ; i < pblk.nParams ; ++i) {
if(!pvals[i].bUsed)
continue;
if(!strcmp(pblk.descr[i].name, "queue.filename")) {
pThis->pszFilePrefix = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
pThis->lenFilePrefix = es_strlen(pvals[i].val.d.estr);
+ } else if(!strcmp(pblk.descr[i].name, "queue.cry.provider")) {
+ pThis->cryprovName = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
+dbgprintf("DDDD: crypto provider set: '%s'\n", pThis->cryprovName);
} else if(!strcmp(pblk.descr[i].name, "queue.size")) {
pThis->iMaxQueueSize = pvals[i].val.d.n;
} else if(!strcmp(pblk.descr[i].name, "queue.dequeuebatchsize")) {
@@ -2760,12 +2831,27 @@ qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals)
"param '%s'\n", pblk.descr[i].name);
}
}
- if(pThis->qType == QUEUETYPE_DISK && pThis->pszFilePrefix == NULL) {
- errmsg.LogError(0, RS_RET_QUEUE_DISK_NO_FN, "error on queue '%s', disk mode selected, but "
- "no queue file name given; queue type changed to 'linkedList'",
+ if(pThis->qType == QUEUETYPE_DISK) {
+ if(pThis->pszFilePrefix == NULL) {
+ errmsg.LogError(0, RS_RET_QUEUE_DISK_NO_FN, "error on queue '%s', disk mode selected, but "
+ "no queue file name given; queue type changed to 'linkedList'",
+ obj.GetName((obj_t*) pThis));
+ pThis->qType = QUEUETYPE_LINKEDLIST;
+ }
+ }
+
+ if(pThis->pszFilePrefix == NULL && pThis->cryprovName != NULL) {
+ errmsg.LogError(0, RS_RET_QUEUE_CRY_DISK_ONLY, "error on queue '%s', crypto provider can "
+ "only be set for disk or disk assisted queue - ignored",
obj.GetName((obj_t*) pThis));
- pThis->qType = QUEUETYPE_LINKEDLIST;
+ free(pThis->cryprovName);
+ pThis->cryprovName = NULL;
+ }
+
+ if(pThis->cryprovName != NULL) {
+ initCryprov(pThis, lst);
}
+
cnfparamvalsDestruct(pvals, &pblk);
return RS_RET_OK;
}
diff --git a/runtime/queue.h b/runtime/queue.h
index 886fac8d..844523ad 100644
--- a/runtime/queue.h
+++ b/runtime/queue.h
@@ -30,6 +30,7 @@
#include "batch.h"
#include "stream.h"
#include "statsobj.h"
+#include "cryprov.h"
/* support for the toDelete list */
typedef struct toDeleteLst_s toDeleteLst_t;
@@ -168,6 +169,11 @@ struct queue_s {
strm_t *pReadDel; /* current file for deleting */
} disk;
} tVars;
+ sbool useCryprov; /* quicker than checkig ptr (1 vs 8 bytes!) */
+ uchar *cryprovName; /* crypto provider to use */
+ cryprov_if_t cryprov; /* ptr to crypto provider interface */
+ void *cryprovData; /* opaque data ptr for provider use */
+ uchar *cryprovNameFull;/* full internal crypto provider name */
DEF_ATOMIC_HELPER_MUT(mutQueueSize);
DEF_ATOMIC_HELPER_MUT(mutLogDeq);
/* for statistics subsystem */
@@ -197,9 +203,8 @@ rsRetVal qqueueSetFilePrefix(qqueue_t *pThis, uchar *pszPrefix, size_t iLenPrefi
rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThreads,
int iMaxQueueSize, rsRetVal (*pConsumer)(void*,batch_t*, int*));
rsRetVal qqueueEnqObjDirectBatch(qqueue_t *pThis, batch_t *pBatch);
-rsRetVal qqueueDoCnfParams(struct nvlst *lst, struct cnfparamvals **ppvals);
-int queueCnfParamsSet(struct cnfparamvals *pvals);
-rsRetVal qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals);
+int queueCnfParamsSet(struct nvlst *lst);
+rsRetVal qqueueApplyCnfParam(qqueue_t *pThis, struct nvlst *lst);
void qqueueSetDefaultsRulesetQueue(qqueue_t *pThis);
void qqueueSetDefaultsActionQueue(qqueue_t *pThis);
void qqueueDbgPrint(qqueue_t *pThis);
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 47b34783..e8c2eb68 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -413,6 +413,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_CRY_INVLD_ALGO = -2326,/**< user specified invalid (unkonwn) crypto algorithm */
RS_RET_CRY_INVLD_MODE = -2327,/**< user specified invalid (unkonwn) crypto mode */
RS_RET_QUEUE_DISK_NO_FN = -2328,/**< disk queue configured, but filename not set */
+ /* up to 2350 reserved for 7.4 */
+ RS_RET_QUEUE_CRY_DISK_ONLY = -2351,/**< crypto provider only supported for disk-associated queues */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/runtime/ruleset.c b/runtime/ruleset.c
index e3348938..aacbdf57 100644
--- a/runtime/ruleset.c
+++ b/runtime/ruleset.c
@@ -928,7 +928,6 @@ rsRetVal
rulesetProcessCnf(struct cnfobj *o)
{
struct cnfparamvals *pvals;
- struct cnfparamvals *queueParams;
rsRetVal localRet;
uchar *rsName = NULL;
uchar *parserName;
@@ -974,11 +973,10 @@ rulesetProcessCnf(struct cnfobj *o)
}
/* pick up ruleset queue parameters */
- qqueueDoCnfParams(o->nvlst, &queueParams);
- if(queueCnfParamsSet(queueParams)) {
+ if(queueCnfParamsSet(o->nvlst)) {
rsname = (pRuleset->pszName == NULL) ? (uchar*) "[ruleset]" : pRuleset->pszName;
DBGPRINTF("adding a ruleset-specific \"main\" queue for ruleset '%s'\n", rsname);
- CHKiRet(createMainQueue(&pRuleset->pQueue, rsname, queueParams));
+ CHKiRet(createMainQueue(&pRuleset->pQueue, rsname, o->nvlst));
}
finalize_it:
diff --git a/runtime/stream.c b/runtime/stream.c
index b781324a..e411577f 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -257,7 +257,8 @@ doPhysOpen(strm_t *pThis)
if(pThis->cryprov != NULL) {
CHKiRet(pThis->cryprov->OnFileOpen(pThis->cryprovData,
- pThis->pszCurrFName, &pThis->cryprovFileData));
+ pThis->pszCurrFName, &pThis->cryprovFileData,
+ (pThis->tOperationsMode == STREAMMODE_READ) ? 'r' : 'w'));
}
finalize_it:
RETiRet;
@@ -568,11 +569,16 @@ strmReadBuf(strm_t *pThis)
CHKiRet(strmOpenFile(pThis));
iLenRead = read(pThis->fd, pThis->pIOBuf, pThis->sIOBufSize);
DBGOPRINT((obj_t*) pThis, "file %d read %ld bytes\n", pThis->fd, iLenRead);
+ /* end crypto */
if(iLenRead == 0) {
CHKiRet(strmHandleEOF(pThis));
} else if(iLenRead < 0)
ABORT_FINALIZE(RS_RET_IO_ERROR);
else { /* good read */
+ /* here we place our crypto interface */
+ if(pThis->cryprov != NULL) {
+ pThis->cryprov->Decrypt(pThis->cryprovFileData, pThis->pIOBuf, &iLenRead);
+ }
pThis->iBufPtrMax = iLenRead;
bRun = 0; /* exit loop */
}