#include #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);