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

📄 rlm_perl.c

📁 RADIUS认证协议
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * rlm_perl.c * * Version:    $Id: rlm_perl.c,v 1.13 2004/02/26 19:04:34 aland Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Copyright 2002  The FreeRADIUS server project * Copyright 2002  Boian Jordanov <bjordanov@orbitel.bg> */#include "autoconf.h"#include "libradius.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include "radiusd.h"#include "modules.h"#include "conffile.h"#ifdef DEBUG#undef DEBUG#endif#ifdef INADDR_ANY#undef INADDR_ANY#endif#ifdef INADDR_NONE#undef INADDR_NONE#endif#include <EXTERN.h>#include <perl.h>#include <XSUB.h>#include <dlfcn.h>#include <semaphore.h>static const char rcsid[] = "$Id: rlm_perl.c,v 1.13 2004/02/26 19:04:34 aland Exp $";/* *	Define a structure for our module configuration. * *	These variables do not need to be in a structure, but it's *	a lot cleaner to do so, and a pointer to the structure can *	be used as the instance handle. */typedef struct perl_inst {	/* Name of the perl module */	char	*module;	/* Name of the functions for each module method */	char	*func_authorize;	char	*func_authenticate;	char	*func_accounting;	char	*func_start_accounting;	char	*func_stop_accounting;	char	*func_preacct;	char	*func_checksimul;	char	*func_detach;	char	*func_xlat;	char	*xlat_name;	char	*perl_flags;} PERL_INST;/* *	A mapping of configuration file names to internal variables. * *	Note that the string is dynamically allocated, so it MUST *	be freed.  When the configuration file parse re-reads the string, *	it free's the old one, and strdup's the new one, placing the pointer *	to the strdup'd string into 'config.string'.  This gets around *	buffer over-flows. */static CONF_PARSER module_config[] = {	{ "module",  PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,module), NULL,  "module"},	{ "func_authorize", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_authorize), NULL, "authorize"},	{ "func_authenticate", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_authenticate), NULL, "authenticate"},	{ "func_accounting", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_accounting), NULL, "accounting"},	{ "func_preacct", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_preacct), NULL, "preacct"},	{ "func_checksimul", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_checksimul), NULL, "checksimul"},	{ "func_detach", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_detach), NULL, "detach"},	{ "func_xlat", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_xlat), NULL, "xlat"},	{ "perl_flags", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,perl_flags), NULL, NULL},	{ "func_start_accounting", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_start_accounting), NULL, NULL},	{ "func_stop_accounting", PW_TYPE_STRING_PTR,	  offsetof(PERL_INST,func_stop_accounting), NULL, NULL},	{ NULL, -1, 0, NULL, NULL }		/* end the list */};/* * man perlembed */EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);/* *	We share one perl interpreter among all of the instances *	of this module. And clone it for every thread if we have perl *	with -Duseithreads compiled in */static PerlInterpreter	*interp;#ifdef USE_ITHREADS/* * Pool of Perl's clones (genetically cloned) ;) * */typedef struct pool_handle {	struct pool_handle	*next;	struct pool_handle	*prev;	enum {busy, idle} 	status;	unsigned int		request_count;	PerlInterpreter		*clone;} POOL_HANDLE;typedef struct PERL_POOL {	POOL_HANDLE	*head;	POOL_HANDLE	*tail;	int		current_clones;	int		active_clones;	int		max_clones;	int		start_clones;	int		min_spare_clones;	int		max_spare_clones;	int		max_request_per_clone;	int		cleanup_delay;	perl_mutex 	mutex;	time_t		time_when_last_added;} PERL_POOL;static PERL_POOL perl_pool;static const CONF_PARSER pool_conf[] = {	{ "max_clones", PW_TYPE_INTEGER, 0, &perl_pool.max_clones,		"32"},	{ "start_clones",PW_TYPE_INTEGER, 0, &perl_pool.start_clones,		"5"},	{ "min_spare_clones",PW_TYPE_INTEGER, 0, &perl_pool.min_spare_clones,	"3"},	{ "max_spare_clones",PW_TYPE_INTEGER, 0, &perl_pool.max_spare_clones,	"3"},	{ "cleanup_delay",PW_TYPE_INTEGER, 0, &perl_pool.cleanup_delay,		"5"},	{ "max_request_per_clone",PW_TYPE_INTEGER, 0, &perl_pool.max_request_per_clone,	"0"},	{ NULL, -1, 0, NULL, NULL }		/* end the list */};#define dl_librefs "DynaLoader::dl_librefs"#define dl_modules "DynaLoader::dl_modules"static void rlm_perl_clear_handles(pTHX){	AV *librefs = get_av(dl_librefs, FALSE);	if (librefs) {		av_clear(librefs);	}}static void **rlm_perl_get_handles(pTHX){	I32 i;	AV *librefs = get_av(dl_librefs, FALSE);	AV *modules = get_av(dl_modules, FALSE);	void **handles;	if (!librefs) {		radlog(L_ERR,		   "Could not get @%s for unloading.\n",		   dl_librefs);		return NULL;	}	if (!(AvFILL(librefs) >= 0)) {		return NULL;	}	handles = (void **)rad_malloc(sizeof(void *) * (AvFILL(librefs)+2));	for (i=0; i<=AvFILL(librefs); i++) {		void *handle;		SV *handle_sv = *av_fetch(librefs, i, FALSE);		if(!handle_sv) {		    radlog(L_ERR,			       "Could not fetch $%s[%d]!\n",			       dl_librefs, (int)i);		    continue;		}		handle = (void *)SvIV(handle_sv);		if (handle) {		    handles[i] = handle;		}	}	av_clear(modules);	av_clear(librefs);	handles[i] = (void *)0;	return handles;}static void rlm_perl_close_handles(void **handles){	int i;	if (!handles) {		return;	}	for (i=0; handles[i]; i++) {		radlog(L_DBG, "close 0x%lx\n", (unsigned long)handles[i]);		dlclose(handles[i]);	}	free(handles);}static PerlInterpreter *rlm_perl_clone(){	PerlInterpreter *clone;	UV	clone_flags = CLONEf_KEEP_PTR_TABLE;	PERL_SET_CONTEXT(interp);	clone = perl_clone(interp, clone_flags);	{		dTHXa(clone);	}	ptr_table_free(PL_ptr_table);	PL_ptr_table = NULL;	PERL_SET_CONTEXT(aTHX);    	rlm_perl_clear_handles(aTHX);	return clone;}static void rlm_perl_destruct(PerlInterpreter *perl){	char **orig_environ = NULL;	dTHXa(perl);	PERL_SET_CONTEXT(perl);	PL_perl_destruct_level = 2;	PL_origenviron = environ;	{		dTHXa(perl);	}	/*	 * FIXME: This shouldn't happen	 *	 */	while (PL_scopestack_ix > 1 ){		LEAVE;	}	perl_destruct(perl);	perl_free(perl);	if (orig_environ) {		environ = orig_environ;	}}static void rlm_destroy_perl(PerlInterpreter *perl){	void	**handles;	dTHXa(perl);	PERL_SET_CONTEXT(perl);	handles = rlm_perl_get_handles(aTHX);	rlm_perl_destruct(perl);	rlm_perl_close_handles(handles);}static void delete_pool_handle(POOL_HANDLE *handle){        POOL_HANDLE *prev;        POOL_HANDLE *next;        prev = handle->prev;        next = handle->next;        if (prev == NULL) {                perl_pool.head = next;        } else {                prev->next = next;        }        if (next == NULL) {                perl_pool.tail = prev;        } else {                next->prev = prev;        }	perl_pool.current_clones--;}static void move2tail(POOL_HANDLE *handle){	POOL_HANDLE *prev;	POOL_HANDLE *next;	if (perl_pool.head == NULL) {		handle->prev = NULL;		handle->next = NULL;		perl_pool.head = handle;		perl_pool.tail = handle;		return;	}	if (perl_pool.tail == handle) {		return;	}	prev = handle->prev;	next = handle->next;	if ((next != NULL) ||			(prev != NULL)) {		if (next == NULL) {			return;		}		if (prev == NULL) {			perl_pool.head = next;			next->prev = NULL;		} else {			prev->next = next;			next->prev = prev;		}	}	handle->next = NULL;	prev = perl_pool.tail;	perl_pool.tail = handle;	handle->prev = prev;	prev->next = handle;}static POOL_HANDLE *pool_grow () {	POOL_HANDLE *handle;	time_t	now;	if (perl_pool.max_clones == perl_pool.current_clones) {		return NULL;	}	handle = (POOL_HANDLE *)rad_malloc(sizeof(POOL_HANDLE));	if (!handle) {		radlog(L_ERR,"Could not find free memory for pool. Aborting");		return NULL;	}	handle->prev = NULL;	handle->next = NULL;	handle->status = idle;	handle->clone = rlm_perl_clone();	handle->request_count = 0;	perl_pool.current_clones++;	move2tail(handle);	now = time(NULL);	perl_pool.time_when_last_added = now;	return handle;}static POOL_HANDLE *pool_pop(){	POOL_HANDLE	*handle;	POOL_HANDLE	*found;	POOL_HANDLE	*tmp;	/*	 * Lock the pool and be fast other thread maybe	 * waiting for us to finish	 */	MUTEX_LOCK(&perl_pool.mutex);	found = NULL;	for (handle = perl_pool.head; handle ; handle = tmp) {		tmp = handle->next;		if (handle->status == idle){			found = handle;			break;		}	}	if (found == NULL) {		if (perl_pool.current_clones < perl_pool.max_clones ) {			found = pool_grow();			perl_pool.current_clones++;			if (found == NULL) {				radlog(L_ERR,"Cannot grow pool returning");				MUTEX_UNLOCK(&perl_pool.mutex);				return NULL;			}		} else {			radlog(L_ERR,"reached maximum clones %d cannot grow",					perl_pool.current_clones);			MUTEX_UNLOCK(&perl_pool.mutex);			return NULL;		}	}	move2tail(found);	found->status = busy;	perl_pool.active_clones++;	found->request_count++;	/*	 * Hurry Up	 */	MUTEX_UNLOCK(&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) {	POOL_HANDLE *tmp, *tmp2;	int spare, i, t;	time_t	now;	/*	 * Lock it	 */	MUTEX_LOCK(&perl_pool.mutex);	handle->status = idle;	perl_pool.active_clones--;	spare = perl_pool.current_clones - perl_pool.active_clones;	radlog(L_DBG,"perl_pool total/active/spare [%d/%d/%d]"			, perl_pool.current_clones, perl_pool.active_clones, spare);	if (spare < perl_pool.min_spare_clones) {		t = perl_pool.min_spare_clones - spare;		for (i=0;i<t; i++) {			if ((tmp = pool_grow()) == NULL) {				MUTEX_UNLOCK(&perl_pool.mutex);				return -1;			}		}		MUTEX_UNLOCK(&perl_pool.mutex);		return 0;	}	now = time(NULL);	if ((now - perl_pool.time_when_last_added) < perl_pool.cleanup_delay) {		MUTEX_UNLOCK(&perl_pool.mutex);		return 0;	}	if (spare > perl_pool.max_spare_clones) {		spare -= perl_pool.max_spare_clones;		for (tmp = 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);				perl_pool.current_clones--;				spare--;				break;			}		}	}	/*	 * Hurry Up :)	 */	MUTEX_UNLOCK(&perl_pool.mutex);	return 0;}static int init_pool (CONF_SECTION *conf) {	POOL_HANDLE 	*handle;	int t;	MUTEX_INIT(&perl_pool.mutex);	/*	 * Read The Config	 *	 */	cf_section_parse(conf,NULL,pool_conf);	for(t = 0;t < perl_pool.start_clones ;t++){		if ((handle = pool_grow()) == 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. */static int perl_init(void){	if ((interp = perl_alloc()) == NULL) {		radlog(L_INFO, "rlm_perl: No memory for allocating new perl !");		return -1;	}	perl_construct(interp);	PL_perl_destruct_level = 2;	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,		     int freespace, RADIUS_ESCAPE_STRING func){

⌨️ 快捷键说明

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