Sponsoring The Perl Toolchain Summit 2025: Help make this important event another success Learn more

#include "mod_perl.h"
#ifdef PERL_SAFE_STARTUP
static IV opset_len = 0;
static void opmask_add(char *bitmask)
{
int i,j;
int myopcode = 0;
if(!opset_len)
opset_len = (maxo + 7) / 8;
for (i=0; i < opset_len; i++) {
U16 bits = bitmask[i];
if (!bits) {
myopcode += 8;
continue;
}
for (j=0; j < 8 && myopcode < maxo; )
op_mask[myopcode++] |= bits & (1 << j++);
}
}
#ifdef PERL_DEFAULT_OPMASK
/*PerlOpmask directive is disabled*/
#define op_names_init()
#define get_op_bitspec(op,f) Nullsv
#define set_opset_bits(bitmap, bitspec, on, op)
#define read_opmask(s,p,f) NULL
char *mod_perl_set_opmask(request_rec *r, SV *sv)
{
croak("Can't override Opmask");
}
#else
static HV *op_named_bits = Nullhv;
static void op_names_init(void)
{
int i;
if(op_named_bits) return;
op_named_bits = newHV();
for(i=0; i < maxo; ++i) {
hv_store(op_named_bits, op_name[i], strlen(op_name[i]),
newSViv(i), 0);
}
}
static SV *get_op_bitspec(char *opname, int fatal)
{
SV **svp;
int len = strlen(opname);
svp = hv_fetch(op_named_bits, opname, len, 0);
if (!svp || !SvOK(*svp)) {
if(fatal)
croak("mod_perl: unknown operator name \"%s\"", opname);
else
return Nullsv;
}
return *svp;
}
static void set_opset_bits(char *bitmap, SV *bitspec, int on, char *opname)
{
if (SvIOK(bitspec)) {
int myopcode = SvIV(bitspec);
int offset = myopcode >> 3;
int bit = myopcode & 0x07;
if (myopcode >= maxo || myopcode < 0)
croak("mod_perl: opcode \"%s\" value %d is invalid",
opname, myopcode);
if (on)
bitmap[offset] |= 1 << bit;
else
bitmap[offset] &= ~(1 << bit);
}
else
croak("mod_perl: invalid bitspec for \"%s\" (type %u)",
opname, (unsigned)SvTYPE(bitspec));
}
static char *read_opmask(server_rec *s, pool *p, char *file)
{
#if HAS_MMN_130
char opname[MAX_STRING_LEN];
char *mask = (char *)ap_pcalloc(p, maxo);
configfile_t *cfg = ap_pcfg_openfile(p, file);
if(!cfg) {
ap_log_error(APLOG_MARK, APLOG_CRIT, s,
"mod_perl: unable to open PerlOpmask file %s", file);
exit(1);
}
op_names_init();
while (!(ap_cfg_getline(opname, MAX_STRING_LEN, cfg))) {
SV *bitspec;
if(*opname == '#') continue;
if((bitspec = get_op_bitspec(opname, TRUE))) {
set_opset_bits(mask, bitspec, TRUE, opname);
}
}
ap_cfg_closefile(cfg);
return mask;
#else
croak("Need Apache 1.3.0+ to use PerlOpmask directive");
#endif /*HAS_MMN_130*/
}
static char *av2opmask(pool *p, AV *av)
{
I32 i;
char *mask;
mask = (char *)ap_pcalloc(p, maxo);
op_names_init();
for(i=0; i<=AvFILL(av); i++) {
SV *sv = *av_fetch(av, i, FALSE);
char *opname = SvPV(sv,na);
SV *bitspec;
if((bitspec = get_op_bitspec(opname, TRUE))) {
set_opset_bits(mask, bitspec, TRUE, opname);
}
}
return mask;
}
/*
* $Mask ||= $r->set_opmask([qw(system backtick)]);
* $r->set_opmask(\$Mask) if $Mask;
* $r->set_opmask($filename)
*/
char *mod_perl_set_opmask(request_rec *r, SV *sv)
{
char *mask;
#ifndef PERL_ORALL_OPMASK
croak("Can't override Opmask");
#endif
dOPMask;
SAVEPPTR(op_mask);
if(SvROK(sv)) {
if(SvTYPE(SvRV(sv)) == SVt_PVAV)
mask = av2opmask(r->pool, (AV*)SvRV(sv));
else
mask = SvPV((SV*)SvRV(sv),na);
}
else {
mask = read_opmask(r->server, r->pool, SvPV(sv,na));
}
opmask_add(mask);
MP_TRACE_g(mod_perl_dump_opmask());
return mask;
}
#endif /*PERL_DEFAULT_OPMASK*/
#include "op_mask.c"
#ifdef PERL_DEFAULT_OPMASK
#define MP_HAS_OPMASK cls
#define MP_DEFAULT_OPMASK 1
#else
#define MP_HAS_OPMASK cls->PerlOpmask
#define MP_DEFAULT_OPMASK !strcasecmp(cls->PerlOpmask, "default")
#endif
#if 0
static char *default_opmask = NULL;
static void reset_default_opmask(void *data)
{
char *mask = (char *)data;
mask = NULL;
}
#endif
void mod_perl_init_opmask(server_rec *s, pool *p)
{
dPSRV(s);
char *local_opmask = NULL;
if(!MP_HAS_OPMASK)
return;
if(MP_DEFAULT_OPMASK) {
#if 0
if(!default_opmask) {
default_opmask = uudecode(p, MP_op_mask);
register_cleanup(p, (void*)default_opmask,
reset_default_opmask, mod_perl_noop);
}
#endif
local_opmask = uudecode(p, MP_op_mask);
MP_TRACE_g(fprintf(stderr, "mod_perl: using PerlOpmask %s\n",
cls->PerlOpmask ? cls->PerlOpmask : "__DEFAULT__"));
}
else {
MP_TRACE_g(fprintf(stderr, "mod_perl: using PerlOpmask %s\n",
cls->PerlOpmask));
local_opmask = read_opmask(s, p,
server_root_relative(p, cls->PerlOpmask));
}
opmask_add(local_opmask);
}
void mod_perl_dump_opmask(void)
{
#ifdef PERL_TRACE
int i;
if(!op_mask) return;
fprintf(stderr, "op_mask=\n");
for(i=0; i < maxo; i++) {
if(!op_mask[i]) continue;
fprintf(stderr, "%s (%s)\n", op_name[i], op_desc[i]);
}
#endif
}
#else
void mod_perl_init_opmask(server_rec *s, pool *p)
{
}
void mod_perl_dump_opmask(void)
{
}
char *mod_perl_set_opmask(request_rec *r, SV *sv)
{
croak("Can't override Opmask");
return NULL; /* C++ emits an error message otherwise
* because of a missing return value.
*/
}
#endif /*PERL_SAFE_STARTUP*/