📄 rlm_perl.c
字号:
break; } } if (found == NULL) { if (inst->perl_pool->current_clones < inst->perl_pool->max_clones ) { found = pool_grow(inst); if (found == NULL) { radlog(L_ERR,"Cannot grow pool returning"); MUTEX_UNLOCK(&inst->perl_pool->mutex); return NULL; } } else { radlog(L_ERR,"rlm_perl:: reached maximum clones %d cannot grow", inst->perl_pool->current_clones); MUTEX_UNLOCK(&inst->perl_pool->mutex); return NULL; } } move2tail(found, inst); found->status = busy; MUTEX_LOCK(&found->lock); inst->perl_pool->active_clones++; found->request_count++; /* * Hurry Up */ MUTEX_UNLOCK(&inst->perl_pool->mutex); radlog(L_DBG,"perl_pool: item 0x%lx asigned new request. Handled so far: %d", (unsigned long) found->clone, found->request_count); return found;}static int pool_release(POOL_HANDLE *handle, PERL_INST *inst) { POOL_HANDLE *tmp, *tmp2; int spare, i, t; time_t now; /* * Lock it */ MUTEX_LOCK(&inst->perl_pool->mutex); /* * If detach is set then just release the mutex */ if (inst->perl_pool->detach == yes ) { handle->status = idle; MUTEX_UNLOCK(&handle->lock); MUTEX_UNLOCK(&inst->perl_pool->mutex); return 0; } MUTEX_UNLOCK(&handle->lock); handle->status = idle; inst->perl_pool->active_clones--; spare = inst->perl_pool->current_clones - inst->perl_pool->active_clones; radlog(L_DBG,"perl_pool total/active/spare [%d/%d/%d]" , inst->perl_pool->current_clones, inst->perl_pool->active_clones, spare); if (spare < inst->perl_pool->min_spare_clones) { t = inst->perl_pool->min_spare_clones - spare; for (i=0;i<t; i++) { if ((tmp = pool_grow(inst)) == NULL) { MUTEX_UNLOCK(&inst->perl_pool->mutex); return -1; } } MUTEX_UNLOCK(&inst->perl_pool->mutex); return 0; } now = time(NULL); if ((now - inst->perl_pool->time_when_last_added) < inst->perl_pool->cleanup_delay) { MUTEX_UNLOCK(&inst->perl_pool->mutex); return 0; } if (spare > inst->perl_pool->max_spare_clones) { spare -= inst->perl_pool->max_spare_clones; for (tmp = inst->perl_pool->head; (tmp !=NULL ) && (spare > 0) ; tmp = tmp2) { tmp2 = tmp->next; if(tmp->status == idle) { rlm_destroy_perl(tmp->clone); delete_pool_handle(tmp,inst); spare--; break; } } } /* * If the clone have reached max_request_per_clone clean it. */ if (inst->perl_pool->max_request_per_clone > 0 ) { if (handle->request_count > inst->perl_pool->max_request_per_clone) { rlm_destroy_perl(handle->clone); delete_pool_handle(handle,inst); } } /* * Hurry Up :) */ MUTEX_UNLOCK(&inst->perl_pool->mutex); return 0;}static int init_pool (CONF_SECTION *conf, PERL_INST *inst) { POOL_HANDLE *handle; int t; PERL_POOL *pool; pool = rad_malloc(sizeof(PERL_POOL)); memset(pool,0,sizeof(PERL_POOL)); inst->perl_pool = pool; MUTEX_INIT(&pool->mutex); /* * Read The Config * */ cf_section_parse(conf,pool,pool_conf); inst->perl_pool = pool; inst->perl_pool->detach = no; for(t = 0;t < inst->perl_pool->start_clones ;t++){ if ((handle = pool_grow(inst)) == NULL) { return -1; } } return 1;}#endif/* * Do any per-module initialization. e.g. set up connections * to external databases, read configuration files, set up * dictionary entries, etc. * * Try to avoid putting too much stuff in here - it's better to * do it in instantiate() where it is not global. * I use one global interpetator to make things more fastest for * Threading env I clone new perl from this interp. */static int perl_init(void){ return 0;}static void xs_init(pTHX){ char *file = __FILE__; /* DynaLoader is a special case */ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);}/* * * This is wrapper for radlog * Now users can call radiusd::radlog(level,msg) wich is the same * calling radlog from C code. * Boyan */static XS(XS_radiusd_radlog){ dXSARGS; if (items !=2) croak("Usage: radiusd::radlog(level, message)"); { int level; char *msg; level = (int) SvIV(ST(0)); msg = (char *) SvPV(ST(1), PL_na); /* * Because 'msg' is a 'char *', we don't want '%s', etc. * in it to give us printf-style vulnerabilities. */ radlog(level, "rlm_perl: %s", msg); } XSRETURN_NO;}/* * The xlat function */static int perl_xlat(void *instance, REQUEST *request, char *fmt, char * out, size_t freespace, RADIUS_ESCAPE_STRING func){ PERL_INST *inst= (PERL_INST *) instance; PerlInterpreter *perl; char params[1024], *ptr, *tmp; int count, ret=0; STRLEN n_a; /* * Do an xlat on the provided string (nice recursive operation). */ if (!radius_xlat(params, sizeof(params), fmt, request, func)) { radlog(L_ERR, "rlm_perl: xlat failed."); return 0; }#ifndef USE_ITHREADS perl = inst->perl;#endif#ifdef USE_ITHREADS POOL_HANDLE *handle; if ((handle = pool_pop(instance)) == NULL) { return 0; } perl = handle->clone; radlog(L_DBG,"Found a interpetator 0x%lx",(unsigned long) perl); { dTHXa(perl); }#endif PERL_SET_CONTEXT(perl); { dSP; ENTER;SAVETMPS; ptr = strtok(params, " "); PUSHMARK(SP); while (ptr != NULL) { XPUSHs(sv_2mortal(newSVpv(ptr,0))); ptr = strtok(NULL, " "); } PUTBACK; count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL); SPAGAIN; if (SvTRUE(ERRSV)) { radlog(L_ERR, "rlm_perl: perl_xlat exit %s\n", SvPV(ERRSV,n_a)); POPs ; } else if (count > 0) { tmp = POPp; strNcpy(out,tmp,freespace); ret = strlen(out); radlog(L_DBG,"rlm_perl: Len is %d , out is %s freespace is %d", ret, out,freespace); } PUTBACK ; FREETMPS ; LEAVE ; }#ifdef USE_ITHREADS pool_release(handle, instance);#endif return ret;}/* * Do any per-module initialization that is separate to each * configured instance of the module. e.g. set up connections * to external databases, read configuration files, set up * dictionary entries, etc. * * If configuration information is given in the config section * that must be referenced in later calls, store a handle to it * in *instance otherwise put a null pointer there. * * Boyan: * Setup a hashes wich we will use later * parse a module and give him a chance to live * */static int perl_instantiate(CONF_SECTION *conf, void **instance){ PERL_INST *inst = (PERL_INST *) instance; HV *rad_reply_hv; HV *rad_check_hv; HV *rad_request_hv; HV *rad_request_proxy_hv; HV *rad_request_proxy_reply_hv; AV *end_AV; char *embed[4], *xlat_name; int exitstatus = 0, argc=0; /* * Set up a storage area for instance data */ inst = rad_malloc(sizeof(PERL_INST)); memset(inst, 0, sizeof(PERL_INST)); /* * If the configuration parameters can't be parsed, then * fail. */ if (cf_section_parse(conf, inst, module_config) < 0) { free(inst); return -1; } embed[0] = NULL; if (inst->perl_flags) { embed[1] = inst->perl_flags; embed[2] = inst->module; embed[3] = "0"; argc = 4; } else { embed[1] = inst->module; embed[2] = "0"; argc = 3; }#ifdef USE_ITHREADS inst->perl = interp; if ((inst->perl = perl_alloc()) == NULL) { radlog(L_DBG, "rlm_perl: No memory for allocating new perl !"); return (-1); } perl_construct(inst->perl); PL_perl_destruct_level = 2; { dTHXa(inst->perl); } PERL_SET_CONTEXT(inst->perl);#else if ((inst->perl = perl_alloc()) == NULL) { radlog(L_ERR, "rlm_perl: No memory for allocating new perl !"); return -1; } perl_construct(inst->perl);#endif#if PERL_REVISION >= 5 && PERL_VERSION >=8 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;#endif exitstatus = perl_parse(inst->perl, xs_init, argc, embed, NULL); end_AV = PL_endav; PL_endav = Nullav; if(!exitstatus) { exitstatus = perl_run(inst->perl); } else { radlog(L_ERR,"rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module); return (-1); } PL_endav = end_AV; newXS("radiusd::radlog",XS_radiusd_radlog, "rlm_perl.c"); rad_reply_hv = newHV(); rad_check_hv = newHV(); rad_request_hv = newHV(); rad_request_proxy_hv = newHV(); rad_request_proxy_reply_hv = newHV(); rad_reply_hv = get_hv("RAD_REPLY",1); rad_check_hv = get_hv("RAD_CHECK",1); rad_request_hv = get_hv("RAD_REQUEST",1); rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1); rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1); xlat_name = cf_section_name2(conf); if (xlat_name == NULL) xlat_name = cf_section_name1(conf); if (xlat_name){ inst->xlat_name = strdup(xlat_name); xlat_register(xlat_name, perl_xlat, inst); }#ifdef USE_ITHREADS if ((init_pool(conf, inst)) == -1) { radlog(L_ERR,"Couldn't init a pool of perl clones. Exiting"); return -1; }#endif *instance = inst; return 0;}/* * get the vps and put them in perl hash * If one VP have multiple values it is added as array_ref * Example for this is Cisco-AVPair that holds multiple values. * Which will be available as array_ref in $RAD_REQUEST{'Cisco-AVPair'} */static void perl_store_vps(VALUE_PAIR *vp, HV *rad_hv){ VALUE_PAIR *nvp, *vpa, *vpn; AV *av; char buffer[1024]; int attr, len; hv_undef(rad_hv); nvp = paircopy(vp); while (nvp != NULL) { attr = nvp->attribute; vpa = paircopy2(nvp,attr); if (vpa->next) { av = newAV(); vpn = vpa; while (vpn) { len = vp_prints_value(buffer, sizeof(buffer), vpn, FALSE); av_push(av, newSVpv(buffer, len)); vpn = vpn->next; } hv_store(rad_hv, nvp->name, strlen(nvp->name), newRV_noinc((SV *) av), 0); } else { len = vp_prints_value(buffer, sizeof(buffer), vpa, FALSE); hv_store(rad_hv, vpa->name, strlen(vpa->name), newSVpv(buffer, len), 0); } pairfree(&vpa); vpa = nvp; while ((vpa != NULL) && (vpa->attribute == attr)) vpa = vpa->next; pairdelete(&nvp, attr); nvp = vpa;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -