源码开发语言/平台
当前位置:
& 查看源码
rlm_ldap.c
rlm_ldap.c:源码内容
&*&rlm_ldap.c&LDAP&authorization&and&authentication&module.
&*&This&module&is&based&on&LDAP&patch&to&Cistron&radiusd&by&James&Golovich&
&*&&&,&which&in&turn&was&based&mostly&on&a&Mysql+Cistron&patch&
&*&from&&&
&*&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¬&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¬&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¬ed&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&&&
&*&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¬found
&*&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&&&
&* -&If&we&add&a&check&item&then&use&the&==&operator.&Based&on&an&idea&by&Allister&Maguire&&.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&&&
&* -&Allow&multiple®ular&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¶meters
&*&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&&&
&*&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¬&exist&in&openldap21.
&* &&Based&on&a&report&from&Mike&Denka&&&
&*&May&2003,&Kostas&Kalevras&&kkalev@noc.ntua.gr&
&* -&Don't&do&a&double&free&on&the&attribute&maps.&Bug¬ed&by&Derrik&Pates&&&
&* -&Apply&a&patch&from&Alexander&M.&Pravking&&fduch@antar.bryansk.ru&&to&do&an&xlat&on&the
&* &&retrieved&attributes.
static&const&char&rcsid[]&=&&$Id:&rlm_ldap.c,v&1.108&&19:07:08&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&
#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¬&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
#define&MAX_FAILED_CONNS_RESTART 4
#define&MAX_FAILED_CONNS_START
/*&linked&list&of&mappings&between&RADIUS&attributes&and&LDAP&attributes&*/
struct&TLDAP_RADIUS&{
char*&&&&&&&&&&&&&&&&&
char*&&&&&&&&&&&&&&&&&radius_
struct&TLDAP_RADIUS*&&
typedef&struct&TLDAP_RADIUS&TLDAP_RADIUS;
typedef&struct&ldap_conn&{
pthread_mutex_t
}&LDAP_CONN;
typedef&struct&{
char&&&&&&&&&&&*
int&&&&&&&&&&&&&
int&&&&&&&&&&&&&
struct&timeval&&net_
struct&timeval&&
int&&&&&&&&&&&&&
int&&&&&&&&&&&&&tls_
char&&&&&&&&&&&*
char&&&&&&&&&&&*
char&&&&&&&&&&&*
char&&&&&&&&&&&*
char&&&&&&&&&&&*default_
char&&&&&&&&&&&*profile_
char&&&&&&&&&&&*access_
char&&&&&&&&&&&*passwd_
char&&&&&&&&&&&*passwd_
char&&&&&&&&&&&*dictionary_
char &&&&&&&*groupname_
char &&&&&&&*groupmemb_
char&&&&&&&&&&&*groupmemb_
TLDAP_RADIUS&&&*check_item_
TLDAP_RADIUS&&&*reply_item_
LDAP_CONN *
int&&&&&&&&&&&&&ldap_&/*&Debug&flag&for&LDAP&SDK&*/
*xlat_&/*&name&used&to&xlat&*/
}&&&&&&&&&&&&&&&ldap_
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,&&&},
{&start_tls&,&PW_TYPE_BOOLEAN,&offsetof(ldap_instance,start_tls),&NULL,&&no&},
{&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)&},
{&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&},
{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&FIELDCPY
static&void&&&&&fieldcpy(char&*,&char&**);
static&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&*,int,&RADIUS_ESCAPE_STRING);
static&LDAP&&&&*ldap_connect(void&*instance,&const&char&*,&const&char&*,&int,&int&*);
static&int&&&&&read_mappings(ldap_instance*&inst);
static&inline&int&ldap_get_conn(LDAP_CONN&*conns,LDAP_CONN&**ret,void&*instance)
ldap_instance&*inst&=&
register&int&i&=&0;
for(;i&inst-&num_i++){
if&(conns[i].locked&==&0&&&&pthread_mutex_trylock(&(conns[i].mutex))&==&0){
*ret&=&&conns[i];
conns[i].locked&=&1;
DEBUG(&ldap_get_conn:&Got&Id:&%d&,i);
return&-1;
static&inline&void&ldap_release_conn(int&i,&LDAP_CONN&*conns)
DEBUG(&ldap_release_conn:&Release&Id:&%d&,i);
conns[i].locked&=&0;
pthread_mutex_unlock(&(conns[i].mutex));
/*************************************************************************
&* Function:&rlm_ldap_instantiate
&* Purpose:&Uses§ion&of&radiusd&config&file&passed&as¶meter
&to&create&an&instance&of&the&module.
&*************************************************************************/
static&int&
ldap_instantiate(CONF_SECTION&*&conf,&void&**instance)
ldap_instance&&*
int&i&=&0;
int&atts_num&=&0;
int&reply_map_num&=&0;
int&check_map_num&=&0;
int&att_map[3]&=&{0,0,0};
TLDAP_RADIUS&*
char&*xlat_
inst&=&rad_malloc(sizeof&*inst);
if&(!inst)&{
return&-1;
memset(inst,&0,&sizeof(*inst));
if&(cf_section_parse(conf,&inst,&module_config)&&&0)&{
free(inst);
return&-1;
if&(inst-&server&==&NULL)&{
radlog(L_ERR,&&rlm_ldap:&missing&'server'&directive.&);
free(inst);
return&-1;
inst-&is_url&=&0;
#ifdef&HAVE_LDAP_INITIALIZE
if&(ldap_is_ldap_url(inst-&server)){
inst-&is_url&=&1;
inst-&port&=&0;
inst-&timeout.tv_usec&=&0;
inst-&net_timeout.tv_usec&=&0;
/*&workaround&for&servers&which&support&LDAPS&but¬&START&TLS&*/
if(inst-&port&==&LDAPS_PORT)
inst-&tls_mode&=&LDAP_OPT_X_TLS_HARD;
inst-&tls_mode&=&0;
inst-&reply_item_map&=&NULL;
inst-&check_item_map&=&NULL;
inst-&conns&=&NULL;
inst-&failed_conns&=&0;
paircompare_register(PW_LDAP_GROUP,&PW_USER_NAME,&ldap_groupcmp,&inst);
DEBUG(&conns:&%p&,inst-&conns);
xlat_name&=&cf_section_name2(conf);
if&(xlat_name&==&NULL)&{
xlat_name&=&cf_section_name1(conf);
rad_assert(xlat_name&!=&NULL);&/*&or&all&hell&breaks&loose&*/
inst-&xlat_name&=&strdup(xlat_name);
xlat_register(xlat_name,ldap_xlat,inst);
if&(inst-&num_conns&&=&0){
radlog(L_ERR,&&rlm_ldap:&Invalid&ldap&connections&number&passed.&);
free(inst);
return&-1;
inst-&conns&=&(LDAP_CONN&*)malloc(sizeof(LDAP_CONN)*inst-&num_conns);
if&(inst-&conns&==&NULL){
radlog(L_ERR,&&rlm_ldap:&Could¬&allocate&memory.&Aborting.&);
free(inst);
return&-1;
for(;i&inst-&num_i++){
inst-&conns[i].bound&=&0;
inst-&conns[i].locked&=&0;
inst-&conns[i].failed_conns&=&0;
inst-&conns[i].ld&=&NULL;
pthread_mutex_init(&inst-&conns[i].mutex,&NULL);
if&(read_mappings(inst)&!=&0)&{
radlog(L_ERR,&&rlm_ldap:&Reading&dictionary&mappings&from&file&%s&failed&,
&&&&&&&inst-&dictionary_mapping);
radlog(L_ERR,&&rlm_ldap:&Proceeding&with&no&mappings&);
pair&=&inst-&check_item_
while(pair&!=&NULL){
atts_num++;
pair&=&pair-&
check_map_num&=&(atts_num&-&1);
pair&=&inst-&reply_item_
while(pair&!=&NULL){
atts_num++;
pair&=&pair-&
reply_map_num&=&(atts_num&-&1);
if&(inst-&profile_attr)
atts_num++;
if&(inst-&passwd_attr)
atts_num++;
if&(inst-&access_attr)
atts_num++;
inst-&atts&=&(char&**)malloc(sizeof(char&*)*(atts_num&+&1));
if&(inst-&atts&==&NULL){
radlog(L_ERR,&&rlm_ldap:&Could¬&allocate&memory.&Aborting.&);
free(inst);
return&-1;
pair&=&inst-&check_item_
for(i=0;i&atts_i++){
if&(i&&=&check_map_num&){
inst-&atts[i]&=&pair-&
if&(i&==&check_map_num)
pair&=&inst-&reply_item_
pair&=&pair-&
else&if&(i&&=&reply_map_num){
inst-&atts[i]&=&pair-&
pair&=&pair-&
if&(inst-&profile_attr&&&&!att_map[0]){
inst-&atts[i]&=&inst-&profile_
att_map[0]&=&1;
else&if&(inst-&passwd_attr&&&&!att_map[1]){
inst-&atts[i]&=&inst-&passwd_
att_map[1]&=&1;
else&if&(inst-&access_attr&&&&!att_map[2]){
inst-&atts[i]&=&inst-&access_
att_map[2]&=&1;
inst-&atts[atts_num]&=&NULL;
DEBUG(&conns:&%p&,inst-&conns);
*instance&=&
&*&read_mappings(...)&reads&a&ldap&-&radius&mappings&file&to&inst-&reply_item_map&and&inst-&check_item_map
#define&MAX_LINE_LEN&160
#define&GENERIC_ATTRIBUTE_ID&&$GENERIC$&
static&int
read_mappings(ldap_instance*&inst)
/*&all&buffers&are&of&MAX_LINE_LEN&so&we&can&use&sscanf&without&being&afraid&of&buffer&overflows&*/
char&buf[MAX_LINE_LEN],&itemType[MAX_LINE_LEN],&radiusAttribute[MAX_LINE_LEN],&ldapAttribute[MAX_LINE_LEN];
/*&open&the&mappings&file&for&reading&*/
filename&=&inst-&dictionary_
DEBUG(&rlm_ldap:&reading&ldap&-&radius&mappings&from&file&%s&,&filename);
mapfile&=&fopen(filename,&&r&);
if&(mapfile&==&NULL)&{
radlog(L_ERR,&&rlm_ldap:&Opening&file&%s&failed&,&filename);
return&-1;&/*&error&*/
/*&read&file&line&by&line.&Note&that&if&line&length&exceed&MAX_LINE_LEN,&line&numbers&will&be&mixed&up&*/
linenumber&=&0;
while&(fgets(buf,&sizeof&buf,&mapfile)!=NULL)&{
int&token_
TLDAP_RADIUS*&
linenumber++;
/*&strip&comments&*/
ptr&=&strchr(buf,&'#');
if&(ptr)&*ptr&=&0;
/*&empty&line&*/
if&(buf[0]&==&0)&
/*&extract&tokens&from&the&string&*/
token_count&=&sscanf(buf,&&%s&%s&%s&,&itemType,&radiusAttribute,&ldapAttribute);
if&(token_count&&=&0)&/*&no&tokens&*/
if&(token_count&!=&3)&{
radlog(L_ERR,&&rlm_ldap:&Skipping&%s&line&%i:&%s&,&filename,&linenumber,&buf);
radlog(L_ERR,&&rlm_ldap:&Expected&3&tokens&&
&&&&&&&&(Item&type,&RADIUS&Attribute&and&LDAP&Attribute)&but&found&only&%i&,&token_count);
/*&create&new&TLDAP_RADIUS&list&node&*/
pair&=&rad_malloc(sizeof(TLDAP_RADIUS));
pair-&attr&=&strdup(ldapAttribute);
pair-&radius_attr&=&strdup(radiusAttribute);
if&(&(pair-&attr&==&NULL)&||&(pair-&radius_attr&==&NULL)&)&{
radlog(L_ERR,&&rlm_ldap:&Out&of&memory&);
if&(pair-&attr)&free(pair-&attr);
if&(pair-&radius_attr)&free(pair-&radius_attr);
free(pair);
fclose(mapfile);
return&-1;
/*&push&node&to&correct&list&*/
if&(strcasecmp(itemType,&&checkItem&)&==&0)&{
pair-&next&=&inst-&check_item_
inst-&check_item_map&=&
}&else&if&(strcasecmp(itemType,&&replyItem&)&==&0)&{
pair-&next&=&inst-&reply_item_
inst-&reply_item_map&=&
radlog(L_ERR,&&rlm_ldap:&file&%s:&skipping&line&%i:&unknown&itemType&%s&,&
&&&&&&&filename,&linenumber,&itemType);
free(pair-&attr);
free(pair-&radius_attr);
free(pair);
DEBUG(&rlm_ldap:&LDAP&%s&mapped&to&RADIUS&%s&,
&&&&&&pair-&attr,&pair-&radius_attr);
fclose(mapfile);
return&0;&/*&success&*/
static&int&
perform_search(void&*instance,&LDAP_CONN&*conn,&char&*search_basedn,&int&scope,&char&*filter,&
char&**attrs,&LDAPMessage&**&result)
int&&&&&&&&&&&&&res&=&RLM_MODULE_OK;
ldap_errno&=&0;
ldap_instance&&*inst&=&
search_retry&=&0;
*result&=&NULL;
if&(!conn){
radlog(L_ERR,&&rlm_ldap:&NULL&connection&handle&passed&);
return&RLM_MODULE_FAIL;
if&(conn-&failed_conns&&&MAX_FAILED_CONNS_START){
conn-&failed_conns++;
if&(conn-&failed_conns&&=&MAX_FAILED_CONNS_END){
conn-&failed_conns&=&MAX_FAILED_CONNS_RESTART;
conn-&bound&=&0;
if&(!conn-&bound&||&conn-&ld&==&NULL)&{
DEBUG2(&rlm_ldap:&attempting&LDAP&reconnection&);
if&(conn-&ld){
DEBUG2(&rlm_ldap:&closing&existing&LDAP&connection&);
ldap_unbind_s(conn-&ld);
if&((conn-&ld&=&ldap_connect(instance,&inst-&login,&inst-&password,&0,&&res))&==&NULL)&{
radlog(L_ERR,&&rlm_ldap:&(re)connection&attempt&failed&);
if&(search_retry&==&0)
conn-&failed_conns++;
return&(RLM_MODULE_FAIL);
conn-&bound&=&1;
conn-&failed_conns&=&0;
DEBUG2(&rlm_ldap:&performing&search&in&%s,&with&filter&%s&,&search_basedn&?&search_basedn&:&&(null)&&,&filter);
switch&(ldap_search_st(conn-&ld,&search_basedn,&scope,&filter,&attrs,&0,&&(inst-&timeout),&result))&{
case&LDAP_SUCCESS:
case&LDAP_NO_SUCH_OBJECT:
case&LDAP_SERVER_DOWN:
radlog(L_ERR,&&rlm_ldap:&ldap_search()&failed:&LDAP&connection&lost.&);
conn-&failed_conns++;
if&(search_retry&==&0){
if&(conn-&failed_conns&&=&MAX_FAILED_CONNS_START){
radlog(L_INFO,&&rlm_ldap:&Attempting&reconnect&);
search_retry&=&1;
conn-&bound&=&0;
ldap_msgfree(*result);
ldap_msgfree(*result);
return&RLM_MODULE_FAIL;
case&LDAP_INSUFFICIENT_ACCESS:
radlog(L_ERR,&&rlm_ldap:&ldap_search()&failed:&Insufficient&access.&Check&the&identity&and&password&configuration&directives.&);
ldap_msgfree(*result);
return&RLM_MODULE_FAIL;
case&LDAP_TIMEOUT:
radlog(L_ERR,&&rlm_ldap:&ldap_search()&failed:&Timed&out&while&waiting&for&server&to&respond.&Please&increase&the&timeout.&);
ldap_msgfree(*result);
return&RLM_MODULE_FAIL;
case&LDAP_TIMELIMIT_EXCEEDED:
case&LDAP_BUSY:
case&LDAP_UNAVAILABLE:
/*&We&don't&need&to&reconnect&in&these&cases&so&we&don't&set&conn-&bound&*/
ldap_get_option(conn-&ld,&LDAP_OPT_ERROR_NUMBER,&&ldap_errno);
radlog(L_ERR,&&rlm_ldap:&ldap_search()&failed:&%s&,&ldap_err2string(ldap_errno));
ldap_msgfree(*result);
return&(RLM_MODULE_FAIL);
ldap_get_option(conn-&ld,&LDAP_OPT_ERROR_NUMBER,&&ldap_errno);
radlog(L_ERR,&&rlm_ldap:&ldap_search()&failed:&%s&,&ldap_err2string(ldap_errno));
conn-&bound&=&0;
ldap_msgfree(*result);
return&(RLM_MODULE_FAIL);
if&((ldap_count_entries(conn-&ld,&*result))&!=&1)&{
DEBUG(&rlm_ldap:&object¬&found&or&got&ambiguous&search&result&);
res&=&RLM_MODULE_NOTFOUND;
ldap_msgfree(*result);
&* Translate&the&LDAP&queries.
static&int&ldap_escape_func(char&*out,&int&outlen,&const&char&*in)
int&len&=&0;
while&(in[0])&{
&*&&Only&one&byte&left.
if&(outlen&&=&1)&{
if&(strchr(&*&,&*in))&{
&* Else&it's&a&nice&character.
*out&=&'