1*f4476bd9SJan Schumann<?php 2*f4476bd9SJan Schumann/** 3*f4476bd9SJan Schumann * Plugin auth provider 4*f4476bd9SJan Schumann * 5*f4476bd9SJan Schumann * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6*f4476bd9SJan Schumann * @author Jan Schumann <js@schumann-it.com> 7*f4476bd9SJan Schumann */ 8*f4476bd9SJan Schumann// must be run within Dokuwiki 9*f4476bd9SJan Schumannif(!defined('DOKU_INC')) die(); 10*f4476bd9SJan Schumann 11*f4476bd9SJan Schumann/** 12*f4476bd9SJan Schumann * LDAP authentication backend 13*f4476bd9SJan Schumann * 14*f4476bd9SJan Schumann * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 15*f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 16*f4476bd9SJan Schumann * @author Chris Smith <chris@jalakaic.co.uk> 17*f4476bd9SJan Schumann * @author Jan Schumann <js@schumann-it.com> 18*f4476bd9SJan Schumann */ 19*f4476bd9SJan Schumannclass auth_plugin_authldap extends DokuWiki_Auth_Plugin 20*f4476bd9SJan Schumann{ 21*f4476bd9SJan Schumann var $cnf = null; 22*f4476bd9SJan Schumann var $con = null; 23*f4476bd9SJan Schumann var $bound = 0; // 0: anonymous, 1: user, 2: superuser 24*f4476bd9SJan Schumann 25*f4476bd9SJan Schumann /** 26*f4476bd9SJan Schumann * Constructor 27*f4476bd9SJan Schumann */ 28*f4476bd9SJan Schumann function auth_plugin_authldap(){ 29*f4476bd9SJan Schumann global $conf; 30*f4476bd9SJan Schumann $this->cnf = $conf['auth']['ldap']; 31*f4476bd9SJan Schumann 32*f4476bd9SJan Schumann // ldap extension is needed 33*f4476bd9SJan Schumann if(!function_exists('ldap_connect')) { 34*f4476bd9SJan Schumann if ($this->cnf['debug']) 35*f4476bd9SJan Schumann msg("LDAP err: PHP LDAP extension not found.",-1,__LINE__,__FILE__); 36*f4476bd9SJan Schumann $this->success = false; 37*f4476bd9SJan Schumann return; 38*f4476bd9SJan Schumann } 39*f4476bd9SJan Schumann 40*f4476bd9SJan Schumann if(empty($this->cnf['groupkey'])) $this->cnf['groupkey'] = 'cn'; 41*f4476bd9SJan Schumann if(empty($this->cnf['userscope'])) $this->cnf['userscope'] = 'sub'; 42*f4476bd9SJan Schumann if(empty($this->cnf['groupscope'])) $this->cnf['groupscope'] = 'sub'; 43*f4476bd9SJan Schumann 44*f4476bd9SJan Schumann // auth_ldap currently just handles authentication, so no 45*f4476bd9SJan Schumann // capabilities are set 46*f4476bd9SJan Schumann } 47*f4476bd9SJan Schumann 48*f4476bd9SJan Schumann /** 49*f4476bd9SJan Schumann * Check user+password 50*f4476bd9SJan Schumann * 51*f4476bd9SJan Schumann * Checks if the given user exists and the given 52*f4476bd9SJan Schumann * plaintext password is correct by trying to bind 53*f4476bd9SJan Schumann * to the LDAP server 54*f4476bd9SJan Schumann * 55*f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 56*f4476bd9SJan Schumann * @return bool 57*f4476bd9SJan Schumann */ 58*f4476bd9SJan Schumann function checkPass($user,$pass){ 59*f4476bd9SJan Schumann // reject empty password 60*f4476bd9SJan Schumann if(empty($pass)) return false; 61*f4476bd9SJan Schumann if(!$this->_openLDAP()) return false; 62*f4476bd9SJan Schumann 63*f4476bd9SJan Schumann // indirect user bind 64*f4476bd9SJan Schumann if($this->cnf['binddn'] && $this->cnf['bindpw']){ 65*f4476bd9SJan Schumann // use superuser credentials 66*f4476bd9SJan Schumann if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){ 67*f4476bd9SJan Schumann if($this->cnf['debug']) 68*f4476bd9SJan Schumann msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 69*f4476bd9SJan Schumann return false; 70*f4476bd9SJan Schumann } 71*f4476bd9SJan Schumann $this->bound = 2; 72*f4476bd9SJan Schumann }else if($this->cnf['binddn'] && 73*f4476bd9SJan Schumann $this->cnf['usertree'] && 74*f4476bd9SJan Schumann $this->cnf['userfilter']) { 75*f4476bd9SJan Schumann // special bind string 76*f4476bd9SJan Schumann $dn = $this->_makeFilter($this->cnf['binddn'], 77*f4476bd9SJan Schumann array('user'=>$user,'server'=>$this->cnf['server'])); 78*f4476bd9SJan Schumann 79*f4476bd9SJan Schumann }else if(strpos($this->cnf['usertree'], '%{user}')) { 80*f4476bd9SJan Schumann // direct user bind 81*f4476bd9SJan Schumann $dn = $this->_makeFilter($this->cnf['usertree'], 82*f4476bd9SJan Schumann array('user'=>$user,'server'=>$this->cnf['server'])); 83*f4476bd9SJan Schumann 84*f4476bd9SJan Schumann }else{ 85*f4476bd9SJan Schumann // Anonymous bind 86*f4476bd9SJan Schumann if(!@ldap_bind($this->con)){ 87*f4476bd9SJan Schumann msg("LDAP: can not bind anonymously",-1); 88*f4476bd9SJan Schumann if($this->cnf['debug']) 89*f4476bd9SJan Schumann msg('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 90*f4476bd9SJan Schumann return false; 91*f4476bd9SJan Schumann } 92*f4476bd9SJan Schumann } 93*f4476bd9SJan Schumann 94*f4476bd9SJan Schumann // Try to bind to with the dn if we have one. 95*f4476bd9SJan Schumann if(!empty($dn)) { 96*f4476bd9SJan Schumann // User/Password bind 97*f4476bd9SJan Schumann if(!@ldap_bind($this->con,$dn,$pass)){ 98*f4476bd9SJan Schumann if($this->cnf['debug']){ 99*f4476bd9SJan Schumann msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__); 100*f4476bd9SJan Schumann msg('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)),0); 101*f4476bd9SJan Schumann } 102*f4476bd9SJan Schumann return false; 103*f4476bd9SJan Schumann } 104*f4476bd9SJan Schumann $this->bound = 1; 105*f4476bd9SJan Schumann return true; 106*f4476bd9SJan Schumann }else{ 107*f4476bd9SJan Schumann // See if we can find the user 108*f4476bd9SJan Schumann $info = $this->getUserData($user,true); 109*f4476bd9SJan Schumann if(empty($info['dn'])) { 110*f4476bd9SJan Schumann return false; 111*f4476bd9SJan Schumann } else { 112*f4476bd9SJan Schumann $dn = $info['dn']; 113*f4476bd9SJan Schumann } 114*f4476bd9SJan Schumann 115*f4476bd9SJan Schumann // Try to bind with the dn provided 116*f4476bd9SJan Schumann if(!@ldap_bind($this->con,$dn,$pass)){ 117*f4476bd9SJan Schumann if($this->cnf['debug']){ 118*f4476bd9SJan Schumann msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__); 119*f4476bd9SJan Schumann msg('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)),0); 120*f4476bd9SJan Schumann } 121*f4476bd9SJan Schumann return false; 122*f4476bd9SJan Schumann } 123*f4476bd9SJan Schumann $this->bound = 1; 124*f4476bd9SJan Schumann return true; 125*f4476bd9SJan Schumann } 126*f4476bd9SJan Schumann 127*f4476bd9SJan Schumann return false; 128*f4476bd9SJan Schumann } 129*f4476bd9SJan Schumann 130*f4476bd9SJan Schumann /** 131*f4476bd9SJan Schumann * Return user info 132*f4476bd9SJan Schumann * 133*f4476bd9SJan Schumann * Returns info about the given user needs to contain 134*f4476bd9SJan Schumann * at least these fields: 135*f4476bd9SJan Schumann * 136*f4476bd9SJan Schumann * name string full name of the user 137*f4476bd9SJan Schumann * mail string email addres of the user 138*f4476bd9SJan Schumann * grps array list of groups the user is in 139*f4476bd9SJan Schumann * 140*f4476bd9SJan Schumann * This LDAP specific function returns the following 141*f4476bd9SJan Schumann * addional fields: 142*f4476bd9SJan Schumann * 143*f4476bd9SJan Schumann * dn string distinguished name (DN) 144*f4476bd9SJan Schumann * uid string Posix User ID 145*f4476bd9SJan Schumann * inbind bool for internal use - avoid loop in binding 146*f4476bd9SJan Schumann * 147*f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 148*f4476bd9SJan Schumann * @author Trouble 149*f4476bd9SJan Schumann * @author Dan Allen <dan.j.allen@gmail.com> 150*f4476bd9SJan Schumann * @author <evaldas.auryla@pheur.org> 151*f4476bd9SJan Schumann * @author Stephane Chazelas <stephane.chazelas@emerson.com> 152*f4476bd9SJan Schumann * @return array containing user data or false 153*f4476bd9SJan Schumann */ 154*f4476bd9SJan Schumann function getUserData($user,$inbind=false) { 155*f4476bd9SJan Schumann global $conf; 156*f4476bd9SJan Schumann if(!$this->_openLDAP()) return false; 157*f4476bd9SJan Schumann 158*f4476bd9SJan Schumann // force superuser bind if wanted and not bound as superuser yet 159*f4476bd9SJan Schumann if($this->cnf['binddn'] && $this->cnf['bindpw'] && $this->bound < 2){ 160*f4476bd9SJan Schumann // use superuser credentials 161*f4476bd9SJan Schumann if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){ 162*f4476bd9SJan Schumann if($this->cnf['debug']) 163*f4476bd9SJan Schumann msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 164*f4476bd9SJan Schumann return false; 165*f4476bd9SJan Schumann } 166*f4476bd9SJan Schumann $this->bound = 2; 167*f4476bd9SJan Schumann }elseif($this->bound == 0 && !$inbind) { 168*f4476bd9SJan Schumann // in some cases getUserData is called outside the authentication workflow 169*f4476bd9SJan Schumann // eg. for sending email notification on subscribed pages. This data might not 170*f4476bd9SJan Schumann // be accessible anonymously, so we try to rebind the current user here 171*f4476bd9SJan Schumann list($loginuser,$loginsticky,$loginpass) = auth_getCookie(); 172*f4476bd9SJan Schumann if($loginuser && $loginpass){ 173*f4476bd9SJan Schumann $loginpass = PMA_blowfish_decrypt($loginpass, auth_cookiesalt(!$loginsticky)); 174*f4476bd9SJan Schumann $this->checkPass($loginuser, $loginpass); 175*f4476bd9SJan Schumann } 176*f4476bd9SJan Schumann } 177*f4476bd9SJan Schumann 178*f4476bd9SJan Schumann $info['user'] = $user; 179*f4476bd9SJan Schumann $info['server'] = $this->cnf['server']; 180*f4476bd9SJan Schumann 181*f4476bd9SJan Schumann //get info for given user 182*f4476bd9SJan Schumann $base = $this->_makeFilter($this->cnf['usertree'], $info); 183*f4476bd9SJan Schumann if(!empty($this->cnf['userfilter'])) { 184*f4476bd9SJan Schumann $filter = $this->_makeFilter($this->cnf['userfilter'], $info); 185*f4476bd9SJan Schumann } else { 186*f4476bd9SJan Schumann $filter = "(ObjectClass=*)"; 187*f4476bd9SJan Schumann } 188*f4476bd9SJan Schumann 189*f4476bd9SJan Schumann $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['userscope']); 190*f4476bd9SJan Schumann $result = @ldap_get_entries($this->con, $sr); 191*f4476bd9SJan Schumann if($this->cnf['debug']){ 192*f4476bd9SJan Schumann msg('LDAP user search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 193*f4476bd9SJan Schumann msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__); 194*f4476bd9SJan Schumann } 195*f4476bd9SJan Schumann 196*f4476bd9SJan Schumann // Don't accept more or less than one response 197*f4476bd9SJan Schumann if(!is_array($result) || $result['count'] != 1){ 198*f4476bd9SJan Schumann return false; //user not found 199*f4476bd9SJan Schumann } 200*f4476bd9SJan Schumann 201*f4476bd9SJan Schumann $user_result = $result[0]; 202*f4476bd9SJan Schumann ldap_free_result($sr); 203*f4476bd9SJan Schumann 204*f4476bd9SJan Schumann // general user info 205*f4476bd9SJan Schumann $info['dn'] = $user_result['dn']; 206*f4476bd9SJan Schumann $info['gid'] = $user_result['gidnumber'][0]; 207*f4476bd9SJan Schumann $info['mail'] = $user_result['mail'][0]; 208*f4476bd9SJan Schumann $info['name'] = $user_result['cn'][0]; 209*f4476bd9SJan Schumann $info['grps'] = array(); 210*f4476bd9SJan Schumann 211*f4476bd9SJan Schumann // overwrite if other attribs are specified. 212*f4476bd9SJan Schumann if(is_array($this->cnf['mapping'])){ 213*f4476bd9SJan Schumann foreach($this->cnf['mapping'] as $localkey => $key) { 214*f4476bd9SJan Schumann if(is_array($key)) { 215*f4476bd9SJan Schumann // use regexp to clean up user_result 216*f4476bd9SJan Schumann list($key, $regexp) = each($key); 217*f4476bd9SJan Schumann if($user_result[$key]) foreach($user_result[$key] as $grp){ 218*f4476bd9SJan Schumann if (preg_match($regexp,$grp,$match)) { 219*f4476bd9SJan Schumann if($localkey == 'grps') { 220*f4476bd9SJan Schumann $info[$localkey][] = $match[1]; 221*f4476bd9SJan Schumann } else { 222*f4476bd9SJan Schumann $info[$localkey] = $match[1]; 223*f4476bd9SJan Schumann } 224*f4476bd9SJan Schumann } 225*f4476bd9SJan Schumann } 226*f4476bd9SJan Schumann } else { 227*f4476bd9SJan Schumann $info[$localkey] = $user_result[$key][0]; 228*f4476bd9SJan Schumann } 229*f4476bd9SJan Schumann } 230*f4476bd9SJan Schumann } 231*f4476bd9SJan Schumann $user_result = array_merge($info,$user_result); 232*f4476bd9SJan Schumann 233*f4476bd9SJan Schumann //get groups for given user if grouptree is given 234*f4476bd9SJan Schumann if ($this->cnf['grouptree'] || $this->cnf['groupfilter']) { 235*f4476bd9SJan Schumann $base = $this->_makeFilter($this->cnf['grouptree'], $user_result); 236*f4476bd9SJan Schumann $filter = $this->_makeFilter($this->cnf['groupfilter'], $user_result); 237*f4476bd9SJan Schumann $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['groupscope'], array($this->cnf['groupkey'])); 238*f4476bd9SJan Schumann if($this->cnf['debug']){ 239*f4476bd9SJan Schumann msg('LDAP group search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 240*f4476bd9SJan Schumann msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__); 241*f4476bd9SJan Schumann } 242*f4476bd9SJan Schumann if(!$sr){ 243*f4476bd9SJan Schumann msg("LDAP: Reading group memberships failed",-1); 244*f4476bd9SJan Schumann return false; 245*f4476bd9SJan Schumann } 246*f4476bd9SJan Schumann $result = ldap_get_entries($this->con, $sr); 247*f4476bd9SJan Schumann ldap_free_result($sr); 248*f4476bd9SJan Schumann 249*f4476bd9SJan Schumann if(is_array($result)) foreach($result as $grp){ 250*f4476bd9SJan Schumann if(!empty($grp[$this->cnf['groupkey']][0])){ 251*f4476bd9SJan Schumann if($this->cnf['debug']) 252*f4476bd9SJan Schumann msg('LDAP usergroup: '.htmlspecialchars($grp[$this->cnf['groupkey']][0]),0,__LINE__,__FILE__); 253*f4476bd9SJan Schumann $info['grps'][] = $grp[$this->cnf['groupkey']][0]; 254*f4476bd9SJan Schumann } 255*f4476bd9SJan Schumann } 256*f4476bd9SJan Schumann } 257*f4476bd9SJan Schumann 258*f4476bd9SJan Schumann // always add the default group to the list of groups 259*f4476bd9SJan Schumann if(!in_array($conf['defaultgroup'],$info['grps'])){ 260*f4476bd9SJan Schumann $info['grps'][] = $conf['defaultgroup']; 261*f4476bd9SJan Schumann } 262*f4476bd9SJan Schumann return $info; 263*f4476bd9SJan Schumann } 264*f4476bd9SJan Schumann 265*f4476bd9SJan Schumann /** 266*f4476bd9SJan Schumann * Most values in LDAP are case-insensitive 267*f4476bd9SJan Schumann */ 268*f4476bd9SJan Schumann function isCaseSensitive(){ 269*f4476bd9SJan Schumann return false; 270*f4476bd9SJan Schumann } 271*f4476bd9SJan Schumann 272*f4476bd9SJan Schumann /** 273*f4476bd9SJan Schumann * Bulk retrieval of user data 274*f4476bd9SJan Schumann * 275*f4476bd9SJan Schumann * @author Dominik Eckelmann <dokuwiki@cosmocode.de> 276*f4476bd9SJan Schumann * @param start index of first user to be returned 277*f4476bd9SJan Schumann * @param limit max number of users to be returned 278*f4476bd9SJan Schumann * @param filter array of field/pattern pairs, null for no filter 279*f4476bd9SJan Schumann * @return array of userinfo (refer getUserData for internal userinfo details) 280*f4476bd9SJan Schumann */ 281*f4476bd9SJan Schumann function retrieveUsers($start=0,$limit=-1,$filter=array()) { 282*f4476bd9SJan Schumann if(!$this->_openLDAP()) return false; 283*f4476bd9SJan Schumann 284*f4476bd9SJan Schumann if (!isset($this->users)) { 285*f4476bd9SJan Schumann // Perform the search and grab all their details 286*f4476bd9SJan Schumann if(!empty($this->cnf['userfilter'])) { 287*f4476bd9SJan Schumann $all_filter = str_replace('%{user}', '*', $this->cnf['userfilter']); 288*f4476bd9SJan Schumann } else { 289*f4476bd9SJan Schumann $all_filter = "(ObjectClass=*)"; 290*f4476bd9SJan Schumann } 291*f4476bd9SJan Schumann $sr=ldap_search($this->con,$this->cnf['usertree'],$all_filter); 292*f4476bd9SJan Schumann $entries = ldap_get_entries($this->con, $sr); 293*f4476bd9SJan Schumann $users_array = array(); 294*f4476bd9SJan Schumann for ($i=0; $i<$entries["count"]; $i++){ 295*f4476bd9SJan Schumann array_push($users_array, $entries[$i]["uid"][0]); 296*f4476bd9SJan Schumann } 297*f4476bd9SJan Schumann asort($users_array); 298*f4476bd9SJan Schumann $result = $users_array; 299*f4476bd9SJan Schumann if (!$result) return array(); 300*f4476bd9SJan Schumann $this->users = array_fill_keys($result, false); 301*f4476bd9SJan Schumann } 302*f4476bd9SJan Schumann $i = 0; 303*f4476bd9SJan Schumann $count = 0; 304*f4476bd9SJan Schumann $this->_constructPattern($filter); 305*f4476bd9SJan Schumann $result = array(); 306*f4476bd9SJan Schumann 307*f4476bd9SJan Schumann foreach ($this->users as $user => &$info) { 308*f4476bd9SJan Schumann if ($i++ < $start) { 309*f4476bd9SJan Schumann continue; 310*f4476bd9SJan Schumann } 311*f4476bd9SJan Schumann if ($info === false) { 312*f4476bd9SJan Schumann $info = $this->getUserData($user); 313*f4476bd9SJan Schumann } 314*f4476bd9SJan Schumann if ($this->_filter($user, $info)) { 315*f4476bd9SJan Schumann $result[$user] = $info; 316*f4476bd9SJan Schumann if (($limit >= 0) && (++$count >= $limit)) break; 317*f4476bd9SJan Schumann } 318*f4476bd9SJan Schumann } 319*f4476bd9SJan Schumann return $result; 320*f4476bd9SJan Schumann 321*f4476bd9SJan Schumann 322*f4476bd9SJan Schumann } 323*f4476bd9SJan Schumann 324*f4476bd9SJan Schumann /** 325*f4476bd9SJan Schumann * Make LDAP filter strings. 326*f4476bd9SJan Schumann * 327*f4476bd9SJan Schumann * Used by auth_getUserData to make the filter 328*f4476bd9SJan Schumann * strings for grouptree and groupfilter 329*f4476bd9SJan Schumann * 330*f4476bd9SJan Schumann * filter string ldap search filter with placeholders 331*f4476bd9SJan Schumann * placeholders array array with the placeholders 332*f4476bd9SJan Schumann * 333*f4476bd9SJan Schumann * @author Troels Liebe Bentsen <tlb@rapanden.dk> 334*f4476bd9SJan Schumann * @return string 335*f4476bd9SJan Schumann */ 336*f4476bd9SJan Schumann function _makeFilter($filter, $placeholders) { 337*f4476bd9SJan Schumann preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER); 338*f4476bd9SJan Schumann //replace each match 339*f4476bd9SJan Schumann foreach ($matches[1] as $match) { 340*f4476bd9SJan Schumann //take first element if array 341*f4476bd9SJan Schumann if(is_array($placeholders[$match])) { 342*f4476bd9SJan Schumann $value = $placeholders[$match][0]; 343*f4476bd9SJan Schumann } else { 344*f4476bd9SJan Schumann $value = $placeholders[$match]; 345*f4476bd9SJan Schumann } 346*f4476bd9SJan Schumann $value = $this->_filterEscape($value); 347*f4476bd9SJan Schumann $filter = str_replace('%{'.$match.'}', $value, $filter); 348*f4476bd9SJan Schumann } 349*f4476bd9SJan Schumann return $filter; 350*f4476bd9SJan Schumann } 351*f4476bd9SJan Schumann 352*f4476bd9SJan Schumann /** 353*f4476bd9SJan Schumann * return 1 if $user + $info match $filter criteria, 0 otherwise 354*f4476bd9SJan Schumann * 355*f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 356*f4476bd9SJan Schumann */ 357*f4476bd9SJan Schumann function _filter($user, $info) { 358*f4476bd9SJan Schumann foreach ($this->_pattern as $item => $pattern) { 359*f4476bd9SJan Schumann if ($item == 'user') { 360*f4476bd9SJan Schumann if (!preg_match($pattern, $user)) return 0; 361*f4476bd9SJan Schumann } else if ($item == 'grps') { 362*f4476bd9SJan Schumann if (!count(preg_grep($pattern, $info['grps']))) return 0; 363*f4476bd9SJan Schumann } else { 364*f4476bd9SJan Schumann if (!preg_match($pattern, $info[$item])) return 0; 365*f4476bd9SJan Schumann } 366*f4476bd9SJan Schumann } 367*f4476bd9SJan Schumann return 1; 368*f4476bd9SJan Schumann } 369*f4476bd9SJan Schumann 370*f4476bd9SJan Schumann function _constructPattern($filter) { 371*f4476bd9SJan Schumann $this->_pattern = array(); 372*f4476bd9SJan Schumann foreach ($filter as $item => $pattern) { 373*f4476bd9SJan Schumann// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters 374*f4476bd9SJan Schumann $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters 375*f4476bd9SJan Schumann } 376*f4476bd9SJan Schumann } 377*f4476bd9SJan Schumann 378*f4476bd9SJan Schumann /** 379*f4476bd9SJan Schumann * Escape a string to be used in a LDAP filter 380*f4476bd9SJan Schumann * 381*f4476bd9SJan Schumann * Ported from Perl's Net::LDAP::Util escape_filter_value 382*f4476bd9SJan Schumann * 383*f4476bd9SJan Schumann * @author Andreas Gohr 384*f4476bd9SJan Schumann */ 385*f4476bd9SJan Schumann function _filterEscape($string){ 386*f4476bd9SJan Schumann return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e', 387*f4476bd9SJan Schumann '"\\\\\".join("",unpack("H2","$1"))', 388*f4476bd9SJan Schumann $string); 389*f4476bd9SJan Schumann } 390*f4476bd9SJan Schumann 391*f4476bd9SJan Schumann /** 392*f4476bd9SJan Schumann * Opens a connection to the configured LDAP server and sets the wanted 393*f4476bd9SJan Schumann * option on the connection 394*f4476bd9SJan Schumann * 395*f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 396*f4476bd9SJan Schumann */ 397*f4476bd9SJan Schumann function _openLDAP(){ 398*f4476bd9SJan Schumann if($this->con) return true; // connection already established 399*f4476bd9SJan Schumann 400*f4476bd9SJan Schumann $this->bound = 0; 401*f4476bd9SJan Schumann 402*f4476bd9SJan Schumann $port = ($this->cnf['port']) ? $this->cnf['port'] : 389; 403*f4476bd9SJan Schumann $this->con = @ldap_connect($this->cnf['server'],$port); 404*f4476bd9SJan Schumann if(!$this->con){ 405*f4476bd9SJan Schumann msg("LDAP: couldn't connect to LDAP server",-1); 406*f4476bd9SJan Schumann return false; 407*f4476bd9SJan Schumann } 408*f4476bd9SJan Schumann 409*f4476bd9SJan Schumann //set protocol version and dependend options 410*f4476bd9SJan Schumann if($this->cnf['version']){ 411*f4476bd9SJan Schumann if(!@ldap_set_option($this->con, LDAP_OPT_PROTOCOL_VERSION, 412*f4476bd9SJan Schumann $this->cnf['version'])){ 413*f4476bd9SJan Schumann msg('Setting LDAP Protocol version '.$this->cnf['version'].' failed',-1); 414*f4476bd9SJan Schumann if($this->cnf['debug']) 415*f4476bd9SJan Schumann msg('LDAP version set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 416*f4476bd9SJan Schumann }else{ 417*f4476bd9SJan Schumann //use TLS (needs version 3) 418*f4476bd9SJan Schumann if($this->cnf['starttls']) { 419*f4476bd9SJan Schumann if (!@ldap_start_tls($this->con)){ 420*f4476bd9SJan Schumann msg('Starting TLS failed',-1); 421*f4476bd9SJan Schumann if($this->cnf['debug']) 422*f4476bd9SJan Schumann msg('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 423*f4476bd9SJan Schumann } 424*f4476bd9SJan Schumann } 425*f4476bd9SJan Schumann // needs version 3 426*f4476bd9SJan Schumann if(isset($this->cnf['referrals'])) { 427*f4476bd9SJan Schumann if(!@ldap_set_option($this->con, LDAP_OPT_REFERRALS, 428*f4476bd9SJan Schumann $this->cnf['referrals'])){ 429*f4476bd9SJan Schumann msg('Setting LDAP referrals to off failed',-1); 430*f4476bd9SJan Schumann if($this->cnf['debug']) 431*f4476bd9SJan Schumann msg('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 432*f4476bd9SJan Schumann } 433*f4476bd9SJan Schumann } 434*f4476bd9SJan Schumann } 435*f4476bd9SJan Schumann } 436*f4476bd9SJan Schumann 437*f4476bd9SJan Schumann //set deref mode 438*f4476bd9SJan Schumann if($this->cnf['deref']){ 439*f4476bd9SJan Schumann if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->cnf['deref'])){ 440*f4476bd9SJan Schumann msg('Setting LDAP Deref mode '.$this->cnf['deref'].' failed',-1); 441*f4476bd9SJan Schumann if($this->cnf['debug']) 442*f4476bd9SJan Schumann msg('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); 443*f4476bd9SJan Schumann } 444*f4476bd9SJan Schumann } 445*f4476bd9SJan Schumann 446*f4476bd9SJan Schumann $this->canDo['getUsers'] = true; 447*f4476bd9SJan Schumann return true; 448*f4476bd9SJan Schumann } 449*f4476bd9SJan Schumann 450*f4476bd9SJan Schumann /** 451*f4476bd9SJan Schumann * Wraps around ldap_search, ldap_list or ldap_read depending on $scope 452*f4476bd9SJan Schumann * 453*f4476bd9SJan Schumann * @param $scope string - can be 'base', 'one' or 'sub' 454*f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 455*f4476bd9SJan Schumann */ 456*f4476bd9SJan Schumann function _ldapsearch($link_identifier, $base_dn, $filter, $scope='sub', $attributes=null, 457*f4476bd9SJan Schumann $attrsonly=0, $sizelimit=0, $timelimit=0, $deref=LDAP_DEREF_NEVER){ 458*f4476bd9SJan Schumann if(is_null($attributes)) $attributes = array(); 459*f4476bd9SJan Schumann 460*f4476bd9SJan Schumann if($scope == 'base'){ 461*f4476bd9SJan Schumann return @ldap_read($link_identifier, $base_dn, $filter, $attributes, 462*f4476bd9SJan Schumann $attrsonly, $sizelimit, $timelimit, $deref); 463*f4476bd9SJan Schumann }elseif($scope == 'one'){ 464*f4476bd9SJan Schumann return @ldap_list($link_identifier, $base_dn, $filter, $attributes, 465*f4476bd9SJan Schumann $attrsonly, $sizelimit, $timelimit, $deref); 466*f4476bd9SJan Schumann }else{ 467*f4476bd9SJan Schumann return @ldap_search($link_identifier, $base_dn, $filter, $attributes, 468*f4476bd9SJan Schumann $attrsonly, $sizelimit, $timelimit, $deref); 469*f4476bd9SJan Schumann } 470*f4476bd9SJan Schumann } 471*f4476bd9SJan Schumann}