| #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*/ |