📄 rlm_perl.c
字号:
}}/* * * Verify that a Perl SV is a string and save it in FreeRadius * Value Pair Format * */static int pairadd_sv(VALUE_PAIR **vp, char *key, SV *sv, int operator) { char *val; VALUE_PAIR *vpp; if (SvOK(sv)) { val = SvPV_nolen(sv); vpp = pairmake(key, val, operator); if (vpp != NULL) { pairadd(vp, vpp); radlog(L_DBG, "rlm_perl: Added pair %s = %s", key, val); return 1; } else { radlog(L_DBG, "rlm_perl: ERROR: Failed to create pair %s = %s", key, val); } } return 0;}/* * Boyan : * Gets the content from hashes */static int get_hv_content(HV *my_hv, VALUE_PAIR **vp){ SV *res_sv, **av_sv; AV *av; char *key; I32 key_len, len, i, j; int ret=0; for (i = hv_iterinit(my_hv); i > 0; i--) { res_sv = hv_iternextsv(my_hv,&key,&key_len); if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) { av = (AV*)SvRV(res_sv); len = av_len(av); for (j = 0; j <= len; j++) { av_sv = av_fetch(av, j, 0); ret = pairadd_sv(vp, key, *av_sv, T_OP_ADD) + ret; } } else ret = pairadd_sv(vp, key, res_sv, T_OP_EQ) + ret; } return ret;}/* * Call the function_name inside the module * Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST * */static int rlmperl_call(void *instance, REQUEST *request, char *function_name){ PERL_INST *inst = instance; VALUE_PAIR *vp; int exitstatus=0, count; STRLEN n_a; HV *rad_reply_hv; HV *rad_check_hv; HV *rad_request_hv; HV *rad_request_proxy_hv; HV *rad_request_proxy_reply_hv;#ifdef USE_ITHREADS POOL_HANDLE *handle; if ((handle = pool_pop(instance)) == NULL) { return RLM_MODULE_FAIL; } radlog(L_DBG,"found interpetator at address 0x%lx",(unsigned long) handle->clone); { dTHXa(handle->clone); PERL_SET_CONTEXT(handle->clone); }#else PERL_SET_CONTEXT(inst->perl); radlog(L_DBG,"Using perl at 0x%lx",(unsigned long) inst->perl);#endif { dSP; ENTER; SAVETMPS; /* * Radius has told us to call this function, but none * is defined. */ if (!function_name) { return RLM_MODULE_FAIL; } 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); perl_store_vps(request->reply->vps, rad_reply_hv); perl_store_vps(request->config_items, rad_check_hv); perl_store_vps(request->packet->vps, rad_request_hv); if (request->proxy != NULL) { perl_store_vps(request->proxy->vps, rad_request_proxy_hv); } else { hv_undef(rad_request_proxy_hv); } if (request->proxy_reply !=NULL) { perl_store_vps(request->proxy_reply->vps, rad_request_proxy_reply_hv); } else { hv_undef(rad_request_proxy_reply_hv); } vp = NULL; PUSHMARK(SP); /* * This way %RAD_xx can be pushed onto stack as sub parameters. * XPUSHs( newRV_noinc((SV *)rad_request_hv) ); * XPUSHs( newRV_noinc((SV *)rad_reply_hv) ); * XPUSHs( newRV_noinc((SV *)rad_check_hv) ); * PUTBACK; */ count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS); SPAGAIN; if (SvTRUE(ERRSV)) { radlog(L_ERR, "rlm_perl: perl_embed:: module = %s , func = %s exit status= %s\n", inst->module, function_name, SvPV(ERRSV,n_a)); POPs; } if (count == 1) { exitstatus = POPi; if (exitstatus >= 100 || exitstatus < 0) { exitstatus = RLM_MODULE_FAIL; } } PUTBACK; FREETMPS; LEAVE; if ((get_hv_content(rad_reply_hv, &vp)) > 0 ) { pairmove(&request->reply->vps, &vp); pairfree(&vp); } if ((get_hv_content(rad_check_hv, &vp)) > 0 ) { pairmove(&request->config_items, &vp); pairfree(&vp); } if ((get_hv_content(rad_request_proxy_reply_hv, &vp)) > 0 && request->proxy_reply != NULL) { pairfree(&request->proxy_reply->vps); pairmove(&request->proxy_reply->vps, &vp); pairfree(&vp); } }#ifdef USE_ITHREADS pool_release(handle,instance); radlog(L_DBG,"Unreserve perl at address 0x%lx", (unsigned long) handle->clone);#endif return exitstatus;}/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */static int perl_authorize(void *instance, REQUEST *request){ return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_authorize);}/* * Authenticate the user with the given password. */static int perl_authenticate(void *instance, REQUEST *request){ return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_authenticate);}/* * Massage the request before recording it or proxying it */static int perl_preacct(void *instance, REQUEST *request){ return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_preacct);}/* * Write accounting information to this modules database. */static int perl_accounting(void *instance, REQUEST *request){ VALUE_PAIR *pair; int acctstatustype=0; if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL) { acctstatustype = pair->lvalue; } else { radlog(L_ERR, "Invalid Accounting Packet"); return RLM_MODULE_INVALID; } switch (acctstatustype) { case PW_STATUS_START: if (((PERL_INST *)instance)->func_start_accounting) { return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_start_accounting); } else { return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_accounting); } break; case PW_STATUS_STOP: if (((PERL_INST *)instance)->func_stop_accounting) { return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_stop_accounting); } else { return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_accounting); } break; default: return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_accounting); }}/* * Check for simultaneouse-use */static int perl_checksimul(void *instance, REQUEST *request){ return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_checksimul);}/* * Pre-Proxy request */static int perl_pre_proxy(void *instance, REQUEST *request){ return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_pre_proxy);}/* * Post-Proxy request */static int perl_post_proxy(void *instance, REQUEST *request){ return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_post_proxy);}/* * Pre-Auth request */static int perl_post_auth(void *instance, REQUEST *request){ return rlmperl_call(instance, request, ((PERL_INST *)instance)->func_post_auth);}/* * Detach a instance give a chance to a module to make some internal setup ... */static int perl_detach(void *instance){ PERL_INST *inst = (PERL_INST *) instance; int exitstatus=0,count=0;#ifdef USE_ITHREADS POOL_HANDLE *handle, *tmp, *tmp2; MUTEX_LOCK(&inst->perl_pool->mutex); inst->perl_pool->detach = yes; MUTEX_UNLOCK(&inst->perl_pool->mutex); for (handle = inst->perl_pool->head; handle != NULL; handle = handle->next) { radlog(L_DBG,"Detach perl 0x%lx", (unsigned long) handle->clone); /* * Wait until clone becomes idle */ MUTEX_LOCK(&handle->lock); /* * Give a clones chance to run detach function */ { dTHXa(handle->clone); PERL_SET_CONTEXT(handle->clone); { dSP; ENTER; SAVETMPS; PUSHMARK(SP); count = call_pv(inst->func_detach, G_SCALAR | G_EVAL ); SPAGAIN; if (count == 1) { exitstatus = POPi; /* * FIXME: bug in perl * */ if (exitstatus >= 100 || exitstatus < 0) { exitstatus = RLM_MODULE_FAIL; } } PUTBACK; FREETMPS; LEAVE; radlog(L_DBG,"detach at 0x%lx returned status %d", (unsigned long) handle->clone, exitstatus); } } MUTEX_UNLOCK(&handle->lock); } /* * Free handles */ for (tmp = inst->perl_pool->head; tmp !=NULL ; tmp = tmp2) { tmp2 = tmp->next; radlog(L_DBG,"rlm_perl:: Destroy perl"); rlm_perl_destruct(tmp->clone); delete_pool_handle(tmp,inst); } { dTHXa(inst->perl);#endif /* USE_ITHREADS */ PERL_SET_CONTEXT(inst->perl); { dSP; ENTER; SAVETMPS; PUSHMARK(SP); count = call_pv(inst->func_detach, G_SCALAR | G_EVAL ); SPAGAIN; if (count == 1) { exitstatus = POPi; if (exitstatus >= 100 || exitstatus < 0) { exitstatus = RLM_MODULE_FAIL; } } PUTBACK; FREETMPS; LEAVE; }#ifdef USE_ITHREADS }#endif xlat_unregister(inst->xlat_name, perl_xlat); free(inst->xlat_name); if (inst->func_authorize) free(inst->func_authorize); if (inst->func_authenticate) free(inst->func_authenticate); if (inst->func_accounting) free(inst->func_accounting); if (inst->func_preacct) free(inst->func_preacct); if (inst->func_checksimul) free(inst->func_checksimul); if (inst->func_pre_proxy) free(inst->func_pre_proxy); if (inst->func_post_proxy) free(inst->func_post_proxy); if (inst->func_post_auth) free(inst->func_post_auth); if (inst->func_detach) free(inst->func_detach);#ifdef USE_ITHREADS free(inst->perl_pool->head); free(inst->perl_pool->tail); MUTEX_DESTROY(&inst->perl_pool->mutex); free(inst->perl_pool); rlm_perl_destruct(inst->perl);#else perl_destruct(inst->perl); perl_free(inst->perl);#endif free(inst); return exitstatus;}/* * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. * * If the module needs to temporarily modify it's instantiation * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE. * The server will then take care of ensuring that the module * is single-threaded. */module_t rlm_perl = { "perl", /* Name */#ifdef USE_ITHREADS RLM_TYPE_THREAD_SAFE, /* type */#else RLM_TYPE_THREAD_UNSAFE,#endif perl_init, /* initialization */ perl_instantiate, /* instantiation */ { perl_authenticate, perl_authorize, perl_preacct, perl_accounting, perl_checksimul, /* check simul */ perl_pre_proxy, /* pre-proxy */ perl_post_proxy, /* post-proxy */ perl_post_auth /* post-auth */ }, perl_detach, /* detach */ NULL, /* destroy */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -