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

📄 rlm_ldap.c

📁 RADIUS认证协议
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * rlm_ldap.c	LDAP authorization and authentication module. * *   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 * * This module is based on LDAP patch to Cistron radiusd by James Golovich * <james@wwnet.net>, which in turn was based mostly on a Mysql+Cistron patch * from <oyarzun@wilmington.net> * * 17 Jan 2000,	Adrian Pavlykevych <pam@polynet.lviv.ua> *	- OpenLDAP SDK porting, basic TLS support, LDAP authorization, *	  fault tolerance with multiple LDAP server support * 24 May 2000,	Adrian Pavlykevych <pam@polynet.lviv.ua> *	- Converting to new configuration file format, futher improvements *	  in fault tolerance, threaded operation * 12 Dec 2000,	Adrian Pavlykevych <pam@polynet.lviv.ua> *	- Added preliminary support for multiple instances * 	- moved all instance configuration into dynamicly allocated structure *	- Removed connection maintenance thread and all attempts for multihreading *	  the module itself. OpenLDAP SDK is not thread safe when used with shared *	  LDAP connection. *	- Added configuration option for defining LDAP attribute of user object, *	  which controls remote access. * 16 Feb 2001, Hannu Laurila <hannu.laurila@japo.fi> * 	- LDAP<->RADIUS attribute mappings are now read from a file *  	- Support for generic RADIUS check and reply attribute. * Jun 2001, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Fix: check and reply attributes from LDAP _replace_ existing ones *	- Added "default_profile" directive, which points to radiusProfile *	  object, which contains default values for RADIUS users *	- Added "profile_attribute" directive, which specifies user object *	  attribute pointing to radiusProfile object. * Nov 2001, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Added support for adding the user password to the check. Based on *	  the password_header directive rlm_ldap will strip the *	  password header if needed. This will make support for CHAP much easier. *	- Added module messages when we reject a user. *	- Added ldap_groupcmp to allow searching for user group membership. *	- Added ldap_xlat to allow ldap urls in xlat strings. Something like: *	  %{ldap:ldap:///dc=company,dc=com?cn?sub?uid=user} * Nov 2001, Gordon Tetlow <gordont@gnf.org> *	- Do an xlat on the access_group attribute. * Dec 2001, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Added ldap caching for the default/regular profiles and group entries. *	- Fixed a memory leak in ldap_xlat. *	- Removed dict_attrbyname from ldap_pairget. They are not needed. *	- Moved the radius_xlat's for filter and basedn in ldap_authenticate() to *	  the right place. *	- Made the module thread safe. We create a connection pool and each thread *	  will call ldap_get_conn to lock one of the ldap connections and release with *	  a call to ldap_release_conn when it has finished. *	- Request only the user attributes that interest us (radius attributes,regular *	  profile,user password and access attribute). * Mar 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Fixed a bug where the ldap server will kill the idle connections from the ldap *	  connection pool. We now check if ldap_search returns LDAP_SERVER_DOWN and try to *	  reconnect if it does. Bug noted by Dan Perik <dan_perik-work@ntm.org.pg> * May 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Instead of the Group attribute we now have the Ldap-Group attribute, to avoid *	  collisions with other modules *	- If perform_search fails check the ld != NULL before using it. Based on a bug report *	  by John <jhogenmiller@pennswoods.net> * Jun 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Add the ability to do a paircmp on the check items. Add a compare_check_items boolean *	  configuration directive which defaults to no. If it is set then we will do a compare *	- Add another configuration directive. access_attr_used_for_allow. If it is set to yes *	  then the access_attr will be used to allow user access. If it is set to no then it will *	  be used to deny user access. *	- Remember to free inst->atts in ldap_detach() *	- Add a forgotten ldap_free_urldesc in ldap_xlat() *	- Add a variable locked in the LDAP_CONN structure. We use this to avoid deadlocks. The mutex *	  we are using is of type fast and can deadlock if the same thread tries to relock it. That *	  could happen in case of calls to xlat. *	- When ldap_search returns NO_SUCH_OBJECT don't return fail but notfound * Jul 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Fix the logic when we get an LDAP_SERVER_DOWN or we have conn->ld == NULL in perform_search *	- Try to minimize the penalty of having the ldap server go down. The comments before *	  MAX_FAILED_CONNS_* definitions should explain things. *	- Check for a number of error codes from ldap_search and log corresponding error messages *	  We should only reconnect when that can help things. *	- In ldap_groupcmp instead of first searching for the group object and then checking user *	  group membership combine them in one ldap search operation. That should make group *	  membership checks a lot faster. *	- Remember to do ldap_release_conn and ldap_msgfree when we do paircmp and the result is reject * Aug 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Add support for group membership attribute inside the user entry in ldap_groupcmp. The attribute *	  can either contain the name or the DN of the group. Added the groupmembership_attribute *	  configuration directive *	- Move the ldap_{get,release}_conn in ldap_groupcmp so that we hold a connection for the minimum time. *	- Now that ldap_groupcmp is complete we really don't need access_group. Removed it. *	- Remember to free groupmembership_attribute in ldap_detach *	- Don't delete existing generic attributes in ldap_pairget when adding new ones. Since generic attributes *	  have operators we don't need to try to be cleaver. * Sep 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Fix a crash in ldap_pairget when the attribute value is larger than the buffer size *	  Bug report by Stefan Radovanovici <sra@rtsffm.com> *	- If we add a check item then use the == operator. Based on an idea by Allister Maguire <amaguire@gnc.net.nz> *	- Only add a failure message for bind as user failed in ldap_authenticate if the result of ldap_connect was *	  RLM_MODULE_REJECT *	- Make tls_mode a configurable option. Patch from John <jhogenmiller@pennswoods.net> *	- Allow multiple regular profiles for an entry * Oct 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Disable cache after searching for the default profile *	- Use the MAX_FAILED_CONNS_* in ldap_authenticate() when calling ldap_connect() * Nov 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Set LDAP version to V3 before binding. Now freeradius should work with openldap21 * Dec 2002, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Set default values for the server and basedn parameters * Feb 2003, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Add support for ldap_initialize. That way we can specify the server as an ldap url. *	  Based on ideas from Derrik Pates <dpates@dsdk12.net> * Mar 2003, Kostas Kalevras <kkalev@noc.ntua.gr> * 	- Add an ldap_escape_func. Escape the * character from the filter so that we can avoid * 	  the trivial DoS of username=* * 	- Remove the caching code. It does not exist in openldap21. *	  Based on a report from Mike Denka <mdenk@whidbey.net> * May 2003, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Don't do a double free on the attribute maps. Bug noted by Derrik Pates <dpates@dsdk12.net> *	- Apply a patch from Alexander M. Pravking <fduch@antar.bryansk.ru> to do an xlat on the *	  retrieved attributes. * Aug 2003, Kostas Kalevras <kkalev@noc.ntua.gr> *	- In case of a bad search filter, print out the corresponding filter * Sep 2003, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Compile even if we don't have pthread's * Oct 2003, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Add a new configuration directive, base_filter which is used for base scope searches *	  (When searching for the default/regular profiles for example) * Nov 2003, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Add a new configuration directive, do_xlat (default: yes). If set we use pairxlatmove *	  on the radius attributes, else we fall back to the plain old pairadd. That way people *	  can fall back on the 0.8.1 behaviour without making changes to their ldap database or *	  gain a little performance by not using pairxlatmove * Dec 2003, Kostas Kalevras <kkalev@noc.ntua.gr> *	- Add a patch from Jon Miner <miner@doit.wisc.edu> to add the ability to configure *	  various LDAP TLS options *	- Only call pairfree if we are using pairxlatmove not for pairadd * Mar 2004, Kostas Kalevras <kkalev@noc.ntua.gr> *	- If we are passed an empty password log a module failure message not an error message * Apr 2004, Kostas Kalveras <kkalev@noc.ntua.gr> *	- Add a patch from Tarun Bhushan <tarun.bhushan@macquarie.com> to add a tls_mode boolean *	  directive so that we can enable TLS connetions even if port is not set to 636 *	- Add an error message if ldap_initialize() is not available and we are passed a URL like *	  'server' directive. *	- Add a per instance Ldap-Group attribute (of the form <instance>-Ldap-Group) and register *	  a corresponding ldap_groupcmp function *	- Small change to ldap_get_conn to fix problems on some platforms */static const char rcsid[] = "$Id: rlm_ldap.c,v 1.122.2.7 2005/08/29 16:09:56 aland Exp $";#include "autoconf.h"#include	<sys/types.h>#include	<sys/socket.h>#include	<sys/time.h>#include	<netinet/in.h>#include	<stdio.h>#include	<stdlib.h>#include	<netdb.h>#include	<pwd.h>#include	<time.h>#include	<ctype.h>#include	<string.h>#include	<lber.h>#include        <ldap.h>#include	<errno.h>#include	<unistd.h>#include	<pthread.h>#include        "libradius.h"#include	"radiusd.h"#include	"conffile.h"#include	"modules.h"#include	"rad_assert.h"#ifndef HAVE_PTHREAD_H/* *      This is a lot simpler than putting ifdef's around *      every use of the pthread functions. */#define pthread_mutex_lock(a)#define pthread_mutex_unlock(a)#define pthread_mutex_init(a,b)#define pthread_mutex_destroy(a)#endif#define MAX_FILTER_STR_LEN	1024#define TIMELIMIT 5/* * These are used in case ldap_search returns LDAP_SERVER_DOWN * In that case we do conn->failed_conns++ and then check it: * If conn->failed_conns <= MAX_FAILED_CONNS_START then we try * to reconnect * conn->failed_conns is also checked on entrance in perform_search: * If conn->failed_conns > MAX_FAILED_CONNS_START then we don't * try to do anything and we just do conn->failed_conns++ and * return RLM_MODULE_FAIL * if conn->failed_conns >= MAX_FAILED_CONNS_END then we give it * another chance and we set it to MAX_FAILED_CONNS_RESTART and * try to reconnect. * * * We are assuming that the majority of the LDAP_SERVER_DOWN cases * will either be an ldap connection timeout or a temporary ldap * server problem. * As a result we make a few attempts to reconnect hoping that the problem * will soon go away. If it does not go away then we just return * RLM_MODULE_FAIL on entrance in perform_search until conn->failed_conns * gets to MAX_FAILED_CONNS_END. After that we give it one more chance by * going back to MAX_FAILED_CONNS_RESTART * */#define MAX_FAILED_CONNS_END		20#define MAX_FAILED_CONNS_RESTART	4#define MAX_FAILED_CONNS_START		5#ifdef NOVELL_UNIVERSAL_PASSWORD/* Universal Password Length */#define UNIVERSAL_PASS_LEN 256int nmasldap_get_password(	LDAP	 *ld,	char     *objectDN,	size_t   *pwdSize,	/* in bytes */	char     *pwd );#endif/* linked list of mappings between RADIUS attributes and LDAP attributes */struct TLDAP_RADIUS {	char*                 attr;	char*                 radius_attr;	struct TLDAP_RADIUS*  next;};typedef struct TLDAP_RADIUS TLDAP_RADIUS;typedef struct ldap_conn {	LDAP		*ld;	char		bound;	char		locked;	int		failed_conns;#ifdef HAVE_PTHREAD_H	pthread_mutex_t	mutex;#endif} LDAP_CONN;typedef struct {	char           *server;	int             port;	int             timelimit;	struct timeval  net_timeout;	struct timeval  timeout;	int             debug;	int             tls_mode;	int		start_tls;	int		num_conns;	int		do_comp;	int		do_xlat;	int		default_allow;	int		failed_conns;	int		is_url;	char           *login;	char           *password;	char           *filter;	char           *base_filter;	char           *basedn;	char           *default_profile;	char           *profile_attr;	char           *access_attr;	char           *passwd_hdr;	char           *passwd_attr;	char           *dictionary_mapping;	char	       *groupname_attr;	char	       *groupmemb_filt;	char           *groupmemb_attr;	char		**atts;	TLDAP_RADIUS   *check_item_map;	TLDAP_RADIUS   *reply_item_map;	LDAP_CONN	*conns;#ifdef NOVELL	LDAP_CONN *apc_conns;#endif	int             ldap_debug; /* Debug flag for LDAP SDK */	char		*xlat_name; /* name used to xlat */	char		*tls_cacertfile;	char		*tls_cacertdir;	char		*tls_certfile;	char		*tls_keyfile;	char		*tls_randfile;	char		*tls_require_cert;#ifdef NOVELL	int			edir_account_policy_check;#endif}               ldap_instance;/* The default setting for TLS Certificate Verification */#define TLS_DEFAULT_VERIFY "allow"static CONF_PARSER module_config[] = {	{"server", PW_TYPE_STRING_PTR, offsetof(ldap_instance,server), NULL, "localhost"},	{"port", PW_TYPE_INTEGER, offsetof(ldap_instance,port), NULL, "389"},	/* wait forever on network activity */	{"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"},	/* wait forever for search results */	{"timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,timeout.tv_sec), NULL, "20"},	/* allow server unlimited time for search (server-side limit) */	{"timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance,timelimit), NULL, "20"},	{"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance,login), NULL, ""},	{"tls_mode", PW_TYPE_BOOLEAN, offsetof(ldap_instance,tls_mode), NULL, "no"},	{"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance,start_tls), NULL, "no"},	{"tls_cacertfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertfile), NULL, NULL},	{"tls_cacertdir", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertdir), NULL, NULL},	{"tls_certfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_certfile), NULL, NULL},	{"tls_keyfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_keyfile), NULL, NULL},	{"tls_randfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_randfile), NULL, NULL},	{"tls_require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},	{"password", PW_TYPE_STRING_PTR, offsetof(ldap_instance,password), NULL, ""},	{"basedn", PW_TYPE_STRING_PTR, offsetof(ldap_instance,basedn), NULL, "o=notexist"},	{"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,filter), NULL, "(uid=%u)"},	{"base_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"},	{"default_profile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,default_profile), NULL, NULL},	{"profile_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,profile_attr), NULL, NULL},	{"password_header", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_hdr), NULL, NULL},	{"password_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_attr), NULL, NULL},	/* LDAP attribute name that controls remote access */	{"access_attr", PW_TYPE_STRING_PTR, offsetof(ldap_instance,access_attr), NULL, NULL},	/* file with mapping between LDAP and RADIUS attributes */	{"groupname_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupname_attr), NULL, "cn"},	{"groupmembership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},	{"groupmembership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_attr), NULL, NULL},	{"dictionary_mapping", PW_TYPE_STRING_PTR, offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"},	{"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},	{"ldap_connections_number", PW_TYPE_INTEGER, offsetof(ldap_instance,num_conns), NULL, "5"},	{"compare_check_items", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_comp), NULL, "no"},	{"access_attr_used_for_allow", PW_TYPE_BOOLEAN, offsetof(ldap_instance,default_allow), NULL, "yes"},	{"do_xlat", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_xlat), NULL, "yes"},#ifdef NOVELL	{"edir_account_policy_check", PW_TYPE_BOOLEAN, offsetof(ldap_instance,edir_account_policy_check), NULL, "yes"},#endif	{NULL, -1, 0, NULL, NULL}};#define ld_valid                ld_options.ldo_valid#define LDAP_VALID_SESSION      0x2#define LDAP_VALID(ld)  ( (ld)->ld_valid == LDAP_VALID_SESSION )#ifdef FIELDCPYstatic void     fieldcpy(char *, char **);#endifstatic VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,char);static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);static int ldap_xlat(void *, REQUEST *, char *, char *, size_t, RADIUS_ESCAPE_STRING);static LDAP    *ldap_connect(void *instance, const char *, const char *, int, int *, char **);static int     read_mappings(ldap_instance* inst);static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance){	ldap_instance *inst = instance;	register int i = 0;	for(i=0;i<inst->num_conns;i++){		DEBUG("rlm_ldap: ldap_get_conn: Checking Id: %d",i);		if (conns[i].locked == 0 && pthread_mutex_trylock(&(conns[i].mutex)) == 0){			*ret = &conns[i];			conns[i].locked = 1;			DEBUG("rlm_ldap: ldap_get_conn: Got Id: %d",i);

⌨️ 快捷键说明

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