Download | Plain Text | Line Numbers
#include <assert.h>
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "../cipher.h"
#define BLOCKSIZE 8192
#define SET_LEN(sv, len) \
do { SvPVX(sv)[len] = '\0'; SvCUR_set(sv, len); } while (0)
/* Internal defines */
#ifdef PERL_FILTER_EXISTS
# define CORE_FILTER_COUNT \
((PL_parser && PL_parser->rsfp_filters) ? av_len(PL_parser->rsfp_filters) : 0)
#else
# define CORE_FILTER_COUNT \
((PL_rsfp_filters) ? av_len(PL_rsfp_filters) : 0)
#endif
#define FILTER_COUNT(s) IoPAGE(s)
#define FILTER_LINE_NO(s) IoLINES(s)
#define FIRST_TIME(s) IoLINES_LEFT(s)
#define CIPHER_GV(s) IoFMT_GV(s)
#define CIPHER_SV(s) ((SV *) CIPHER_GV(s))
#define CIPHER_BUFFER(s) ((ctx_t *)SvPVX(CIPHER_SV(s)))
#define CLEAR_CIPHER_SV(s) SvCUR_set(CIPHER_SV(s), 0)
#define ENCRYPT_GV(s) IoTOP_GV(s)
#define ENCRYPT_SV(s) ((SV *) ENCRYPT_GV(s))
#define ENCRYPT_BUFFER(s) SvPVX(ENCRYPT_SV(s))
#define CLEAR_ENCRYPT_SV(s) SvCUR_set(ENCRYPT_SV(s), 0)
#define DECRYPT_SV(s) s
#define DECRYPT_BUFFER(s) SvPVX(DECRYPT_SV(s))
#define CLEAR_DECRYPT_SV(s) SvCUR_set(DECRYPT_SV(s), 0)
#define DECRYPT_BUFFER_LEN(s) SvCUR(DECRYPT_SV(s))
#define DECRYPT_OFFSET(s) IoPAGE_LEN(DECRYPT_SV(s))
#define SET_DECRYPT_BUFFER_LEN(s, n) SvCUR_set(DECRYPT_SV(s), n)
static unsigned
decrypt(SV *in_cipher, SV *in_sv, SV *out_sv)
{
/* here is where the actual decryption takes place */
ctx_t *cipher = (ctx_t *)SvPVX(in_cipher);
char *in_buffer = (char *)SvPVX(in_sv);
char *out_buffer;
size_t in_len = SvCUR(in_sv);
size_t out_len;
/* make certain that the output buffer is big enough
* as the output from the decryption can never be larger than
* the input buffer, make it that size
*/
SvGROW(out_sv, in_len);
out_buffer = (char *)SvPVX(out_sv);
/* decrypt */
out_len = CipherUpdate(cipher, in_buffer, in_len);
/* input has been consumed, so set length to 0 */
SET_LEN(in_sv, 0);
/* set decrypt buffer length */
assert(out_len <= BLOCKSIZE);
SET_LEN(out_sv, out_len);
/* return the size of the decrypt buffer */
return out_len;
}
static int
readblock(int idx, SV *sv, unsigned size)
{
/* read *exactly* size bytes from the next filter */
int i = size;
while (1)
{
int n = FILTER_READ(idx, sv, i);
/* eof/error when nothing read so far */
if (n <= 0 && i == size)
return n;
/* eof/error when something already read */
if (n <= 0)
return size - i;
if (n == i)
return size;
i -= n;
}
}
static void
pre_decrypt(int idx)
{}
static void
post_decrypt(int idx)
{}
static I32
filter_decrypt(pTHX_ int idx, SV *buf_sv, int maxlen)
{
char *out_ptr;
char *p;
char *nl = "\n";
int n;
SV *my_sv = FILTER_DATA(idx);
/* check if this is the first time through */
if (FIRST_TIME(my_sv))
{
/* mild paranoia mode - make sure that no extra filters have
* been applied on the same line as the use Filter::decrypt
*/
if (CORE_FILTER_COUNT > FILTER_COUNT(my_sv))
croak("too many filters");
/* as this is the first time through, so deal with any
* initialisation required
*/
pre_decrypt(idx);
FIRST_TIME(my_sv) = FALSE;
SET_LEN(DECRYPT_SV(my_sv), 0);
SET_LEN(ENCRYPT_SV(my_sv), 0);
DECRYPT_OFFSET(my_sv) = 0;
}
#ifdef DEBUG
warn("**** In filter_decrypt - maxlen = %d, len buf = %d idx = %d\n",
maxlen, SvCUR(buf_sv), idx);
#endif
while (1)
{
/* anything left from last time */
if ((n = SvCUR(DECRYPT_SV(my_sv))))
{
out_ptr = SvPVX(DECRYPT_SV(my_sv)) + DECRYPT_OFFSET(my_sv);
if (maxlen)
{
/* want a block */
#ifdef DEBUG
warn("BLOCK(%d): size = %d, maxlen = %d\n", idx, n, maxlen);
#endif
sv_catpvn(buf_sv, out_ptr, (maxlen > n) ? n : maxlen);
if (n <= maxlen)
{
DECRYPT_OFFSET(my_sv) = 0;
SET_LEN(DECRYPT_SV(my_sv), 0);
}
else
{
DECRYPT_OFFSET(my_sv) += maxlen;
SvCUR_set(DECRYPT_SV(my_sv), n - maxlen);
}
return SvCUR(buf_sv);
}
else
{
/* want lines */
if ((p = ninstr(out_ptr, out_ptr + n, nl, nl + 1)))
{
sv_catpvn(buf_sv, out_ptr, p - out_ptr + 1);
n = n - (p - out_ptr + 1);
DECRYPT_OFFSET(my_sv) += (p - out_ptr + 1);
SvCUR_set(DECRYPT_SV(my_sv), n);
#ifdef DEBUG
warn("recycle(%d): leaving %d, returning %d [%.999s]\n",
idx, n, SvCUR(buf_sv), SvPVX(buf_sv));
#endif
return SvCUR(buf_sv);
}
else
{
/* no EOL, so append the complete buffer */
sv_catpvn(buf_sv, out_ptr, n);
}
}
}
SET_LEN(DECRYPT_SV(my_sv), 0);
DECRYPT_OFFSET(my_sv) = 0;
/* read at most BLOCKSIZE - 1 bytes from the file into the encrypt buffer:
* - 1 char ("#"-char) will be prepended during first call of CipherUpdate()
* - 1 char is needed for the string termination BUT perl already
* allocates +1 byte with newSV()
*/
if ((n = readblock(idx + 1, ENCRYPT_SV(my_sv), BLOCKSIZE - 1)) <= 0)
{
/* either EOF or an error */
#ifdef DEBUG
warn("filter_read(%d): returned %d, returning %d\n", idx, n,
(SvCUR(buf_sv) > 0) ? SvCUR(buf_sv) : n);
#endif
/* if the decrypt code needs to tidy up on EOF/error,
* now is the time - here is a hook
*/
post_decrypt(idx);
filter_del(filter_decrypt);
/* if error, return the code */
if (n < 0)
return n;
/* return what we have so far else signal eof */
return (SvCUR(buf_sv) > 0) ? SvCUR(buf_sv) : n;
}
#ifdef DEBUG
else
warn("filter_read(%d): read %d bytes\n", idx, n);
#endif
#ifdef DEBUG
warn("filter_decrypt(%d): sub-filter returned %d: '%.999s'\n",
idx, n, SvPV(my_sv, PL_na));
#endif
/* now decrypt a block */
n = decrypt(CIPHER_SV(my_sv), ENCRYPT_SV(my_sv), DECRYPT_SV(my_sv));
#ifdef DEBUG
warn("decrypt(%d): returned %d [%.999s]\n", idx, n, SvPVX(DECRYPT_SV(my_sv)));
#endif
}
}
MODULE = Confixx::Filter PACKAGE = Confixx::Filter
PROTOTYPES: DISABLE
BOOT:
{
#ifndef BYPASS
/* don't run if this module is dynamically linked */
if (!isALPHA(SvPV(GvSV(CvFILEGV(cv)), PL_na)[0]))
croak("module is dynamically linked. Recompile as a static module");
#ifdef DEBUGGING
/* don't run if compiled with DEBUGGING */
croak("recompile without -DDEBUGGING");
#endif
/* double check that DEBUGGING hasn't been enabled */
if (PL_debug)
croak("debugging flags detected");
#endif
}
void
import(module)
SV *module
PPCODE:
{
int ret;
SV *sv;
/* main/decrypted SV */
DECRYPT_SV(sv) = newSV(BLOCKSIZE);
(void) SvPOK_only(DECRYPT_SV(sv));
SET_LEN(DECRYPT_SV(sv), 0);
/* add filter */
filter_add(filter_decrypt, DECRYPT_SV(sv));
/* cipher SV */
CIPHER_GV(sv) = (GV *)newSV(sizeof(ctx_t));
(void) SvPOK_only(CIPHER_GV(sv));
(void) memset(CIPHER_BUFFER(sv), 0, sizeof(ctx_t));
ret = CipherInit(CIPHER_BUFFER(sv));
if (ret != 256)
croak("unexpected return value of CipherInit(): %d\n", ret);
/* copy pointer to output buffer inside ciphers first bytes */
CIPHER_BUFFER(sv)->out = DECRYPT_BUFFER(sv);
/* encrypted SV */
ENCRYPT_GV(sv) = (GV *)newSV(BLOCKSIZE);
(void) SvPOK_only(ENCRYPT_SV(sv));
SET_LEN(ENCRYPT_SV(sv), 0);
/* enable first time flag */
FIRST_TIME(sv) = TRUE;
/* remember how many filters are enabled */
FILTER_COUNT(sv) = CORE_FILTER_COUNT;
/* and the line number */
FILTER_LINE_NO(sv) = PL_curcop->cop_line;
}
void
unimport(...)
PPCODE:
//filter_del(filter_decrypt);