⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rlm_perl.c

📁 RADIUS认证协议
💻 C
📖 第 1 页 / 共 2 页
字号:
	PERL_INST	*inst= (PERL_INST *) instance;	PerlInterpreter *perl;	char		params[1024], *tmp_ptr, *ptr, *tmp;	int		count, ret;	STRLEN		n_a;	perl = interp;#ifdef USE_ITHREADS	POOL_HANDLE	*handle;	if ((handle = pool_pop()) == NULL) {		return 0;	}	perl = handle->clone;	radlog(L_DBG,"Found a interpetator 0x%lx",(unsigned long) perl);	{	dTHXa(perl);	}#endif	{	dSP;	ENTER;SAVETMPS;	/*	 * 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;	}	ptr = strtok(params, " ");	PUSHMARK(SP);	XPUSHs(sv_2mortal(newSVpv(ptr,0)));	while ((tmp_ptr = strtok(NULL, " ")) != NULL) {		XPUSHs(sv_2mortal(newSVpv(tmp_ptr,0)));	}	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));		return 0;	}	if (count > 0) {		tmp = POPp;		ret = strlen(tmp);		strncpy(out,tmp,ret);		radlog(L_DBG,"rlm_perl: Len is %d , out is %s freespace is %d",		       ret, out,freespace);		PUTBACK ;		FREETMPS ;		LEAVE ;		if (ret <= freespace)			return ret;	}	}#ifdef USE_ITHREADS	pool_release(handle);#endif	return 0;}/* *	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 = newHV();	HV		*rad_check_hv = newHV();	HV		*rad_request_hv = newHV();	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;	}	exitstatus = perl_parse(interp, xs_init, argc, embed, NULL);#if PERL_REVISION >= 5 && PERL_VERSION >=8	PL_exit_flags |= PERL_EXIT_DESTRUCT_END;#endif	if(!exitstatus) {		exitstatus = perl_run(interp);	} else {		radlog(L_INFO,"rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module);		return (-1);	}        newXS("radiusd::radlog",XS_radiusd_radlog, "rlm_perl.c");	rad_reply_hv = get_hv("RAD_REPLY",1);        rad_check_hv = get_hv("RAD_CHECK",1);        rad_request_hv = get_hv("RAD_REQUEST",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)) == -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_clear(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((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;	}}/* * *     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) {       char            *val;       int             val_len;       VALUE_PAIR      *vpp;       if ((sv != NULL) && (SvPOK(sv))) {               val = SvPV(sv, val_len);               vpp = pairmake(key, val, T_OP_EQ);               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) + ret;                       }               } else ret = pairadd_sv(vp, key, res_sv) + 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;#ifdef USE_ITHREADS	POOL_HANDLE	*handle;	if ((handle = pool_pop()) == 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);	}#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);	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);	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 (count == 1) {		exitstatus = POPi;		if (exitstatus >= 100 || exitstatus < 0) {			exitstatus = RLM_MODULE_FAIL;		}	}	PUTBACK;	FREETMPS;	LEAVE;	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));	}	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 0	/*	 *	Do we want to allow this?	 */	if ((get_hv_content(rad_request_hv, &vp)) > 0 ) {		pairfree(&request->packet->vps);		request->packet->vps = vp;	}#endif	}#ifdef USE_ITHREADS	pool_release(handle);	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);}/* * 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;	for (handle = perl_pool.head; handle; handle = handle->next) {		radlog(L_INFO,"Detach perl 0x%lx", (unsigned long) handle->clone);		/*		 * Wait until clone becomes idle		 *		 */		while (handle->status == busy) {		}		/*		 * Give a clones chance to run detach function		 */		{		dTHXa(handle->clone);		PERL_SET_CONTEXT(handle->clone);		{		dSP; 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;		radlog(L_INFO,"detach at 0x%lx returned status %d",				(unsigned long) handle->clone, exitstatus);		}		}	}	/*	 *	 * FIXME: For more efficienty we don't	 * free entire pool. We only reread config flags thus way	 * we can extend pool_size.	 *	 */	{	dTHXa(interp);	PERL_SET_CONTEXT(interp);#endif /* USE_ITHREADS */	{	dSP;	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;	}#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_detach) free(inst->func_detach);	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 */		NULL,                   /* pre-proxy */		NULL,                   /* post-proxy */		NULL                    /* post-auth */	},	perl_detach,			/* detach */	NULL,				/* destroy */};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -