summaryrefslogtreecommitdiff
path: root/inc/auth/ldap.php
diff options
context:
space:
mode:
Diffstat (limited to 'inc/auth/ldap.php')
-rw-r--r--inc/auth/ldap.php281
1 files changed, 281 insertions, 0 deletions
diff --git a/inc/auth/ldap.php b/inc/auth/ldap.php
new file mode 100644
index 000000000..2f0f4f1ff
--- /dev/null
+++ b/inc/auth/ldap.php
@@ -0,0 +1,281 @@
+<?php
+/**
+ * LDAP authentication backend
+ *
+ * tested with openldap 2.x on Debian only
+ *
+ * PHPs LDAP extension is needed
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+
+//check for LDAP extension on load
+if(!function_exists('ldap_connect'))
+ msg("LDAP extension not found",-1);
+
+/**
+ * Connect to the LDAP server
+ *
+ * Holds the connection in global scope for multiple use
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function auth_ldap_connect(){
+ global $LDAP_CONNECTION;
+ global $conf;
+ $cnf = $conf['auth']['ldap'];
+
+ if(!$LDAP_CONNECTION){
+ $LDAP_CONNECTION = @ldap_connect($cnf['server']);
+ if(!$LDAP_CONNECTION){
+ msg("LDAP: couldn't connect to LDAP server",-1);
+ return false;
+ }
+ //set protocol version
+ if($cnf['version']){
+ if(!@ldap_set_option($LDAP_CONNECTION,
+ LDAP_OPT_PROTOCOL_VERSION,
+ $cnf['version'])){
+ msg('Setting LDAP Protocol version '.$cnf['version'].' failed',-1);
+ if($cnf['debug'])
+ msg('LDAP errstr: '.htmlspecialchars(ldap_error($LDAP_CONNECTION)),0);
+
+ } else {
+ //use TLS (needs version 3)
+ if($cnf['starttls']) {
+ if (!@ldap_start_tls($LDAP_CONNECTION)){
+ msg('Starting TLS failed',-1);
+ if($cnf['debug'])
+ msg('LDAP errstr: '.htmlspecialchars(ldap_error($LDAP_CONNECTION)),0);
+ }
+ }
+ // needs version 3
+ if(isset($cnf['referrals'])) {
+ if(!@ldap_set_option($LDAP_CONNECTION,
+ LDAP_OPT_REFERRALS,
+ $cnf['referrals'])){
+ msg('Setting LDAP referrals to off failed',-1);
+ if($cnf['debug'])
+ msg('LDAP errstr: '.htmlspecialchars(ldap_error($LDAP_CONNECTION)),0);
+ }
+ }
+ }
+ }
+ }
+ return $LDAP_CONNECTION;
+}
+
+/**
+ * Check user+password [required auth function]
+ *
+ * Checks if the given user exists and the given
+ * plaintext password is correct by trying to bind
+ * to the LDAP server
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @return bool
+ */
+function auth_checkPass($user,$pass){
+ global $conf;
+ $cnf = $conf['auth']['ldap'];
+
+ //reject empty password
+ if(empty($pass)) return false;
+
+ //connect to LDAP Server
+ $conn = auth_ldap_connect();
+ if(!$conn) return false;
+
+ // indirect user bind
+ if(!empty($cnf['binddn']) and !empty($cnf['bindpw'])) {
+ //use superuser credentials
+ if(!@ldap_bind($conn,$cnf['binddn'],$cnf['bindpw'])){
+ if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0);
+ return false;
+ }
+
+ // special bind string
+ } else if(!empty($cnf['binddn']) and !empty($cnf['usertree']) and !empty($cnf['userfilter'])) {
+ $dn = auth_ldap_makeFilter($cnf['binddn'], array('user'=>$user,'server'=>$cnf['server']));
+
+ // direct user bind
+ } else if(strpos($cnf['usertree'], '%{user}')) {
+ $dn = auth_ldap_makeFilter($cnf['usertree'], array('user'=>$user,'server'=>$cnf['server']));
+
+ // Anonymous bind
+ } else {
+ if(!@ldap_bind($conn)){
+ msg("LDAP: can not bind anonymously",-1);
+ if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0);
+ return false;
+ }
+ }
+
+ // Try to bind to with the dn if we have one.
+ if(!empty($dn)) {
+ // User/Password bind
+ if(!@ldap_bind($conn,$dn,$pass)){
+ if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0);
+ return false;
+ }
+ return true;
+ } else {
+ // See if we can find the user
+ $info = auth_getUserData($user);
+ if(empty($info['dn'])) {
+ return false;
+ } else {
+ $dn = $info['dn'];
+ }
+ // Try to bind with the dn provided
+ if(!@ldap_bind($conn,$dn,$pass)){
+ if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0);
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Return user info [required auth function]
+ *
+ * Returns info about the given user needs to contain
+ * at least these fields:
+ *
+ * name string full name of the user
+ * mail string email addres of the user
+ * grps array list of groups the user is in
+ *
+ * This LDAP specific function returns the following
+ * addional fields:
+ *
+ * dn string distinguished name (DN)
+ * uid string Posix User ID
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Trouble
+ * @author Dan Allen <dan.j.allen@gmail.com>
+ * @auhtor <evaldas.auryla@pheur.org>
+ */
+function auth_getUserData($user){
+ global $conf;
+ $cnf = $conf['auth']['ldap'];
+
+ //connect to LDAP Server
+ $conn = auth_ldap_connect();
+ if(!$conn) return false;
+
+ $info['user']= $user;
+ $info['server']= $cnf['server'];
+
+ //get info for given user
+ $base = auth_ldap_makeFilter($cnf['usertree'], $info);
+ if(!empty($cnf['userfilter'])) {
+ $filter = auth_ldap_makeFilter($cnf['userfilter'], $info);
+ } else {
+ $filter = "(ObjectClass=*)";
+ }
+
+ $sr = @ldap_search($conn, $base, $filter);
+ $result = @ldap_get_entries($conn, $sr);
+ if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0);
+
+ // Don't accept more or less than one response
+ if($result['count'] != 1){
+ return false; //user not found
+ }
+
+ $user_result = $result[0];
+
+ //general user info
+ $info['dn']= $user_result['dn'];
+ $info['mail']= $user_result['mail'][0];
+ $info['name']= $user_result['cn'][0];
+
+ #overwrite if other attribs are specified.
+ foreach($cnf['mapping'] as $localkey => $key) {
+ if(is_array($key)) {
+ //use regexp to clean up user_result
+ list($key, $regexp) = each($key);
+ foreach($user_result[$key] as $grp){
+ if (preg_match($regexp,$grp,$match)) {
+ if($localkey == 'grps') {
+ $info[$localkey][] = $match[1];
+ } else {
+ $info[$localkey] = $match[1];
+ }
+ }
+ }
+ } else {
+ $info[$localkey] = $user_result[$key][0];
+ }
+ }
+
+ //get groups for given user if grouptree is given
+ if (!empty($cnf['grouptree'])) {
+ $base = auth_ldap_makeFilter($cnf['grouptree'], $user_result);
+ $filter = auth_ldap_makeFilter($cnf['groupfilter'], $user_result);
+
+ $sr = @ldap_search($conn, $base, $filter);
+ if(!$sr){
+ msg("LDAP: Reading group memberships failed",-1);
+ if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0);
+ return false;
+ }
+ $result = ldap_get_entries($conn, $sr);
+ foreach($result as $grp){
+ if(!empty($grp['cn'][0]))
+ $info['grps'][] = $grp['cn'][0];
+ }
+ }
+
+ //if no groups were found always return the default group
+ if(!count($info['grps'])) $info['grps'][] = $conf['defaultgroup'];
+
+ return $info;
+}
+
+/**
+ * Create a new User [required auth function]
+ *
+ * Not implemented
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function auth_createUser($user,$pass,$name,$mail){
+ msg("Sorry. Creating users is not supported by the LDAP backend",-1);
+ return null;
+}
+
+
+/**
+ * Make ldap filter strings.
+ *
+ * Used by auth_getUserData to make the filter
+ * strings for grouptree and groupfilter
+ *
+ * filter string ldap search filter with placeholders
+ * placeholders array array with the placeholders
+ *
+ * @author Troels Liebe Bentsen <tlb@rapanden.dk>
+ * @return string
+ */
+function auth_ldap_makeFilter($filter, $placeholders) {
+ preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
+ //replace each match
+ foreach ($matches[1] as $match) {
+ //take first element if array
+ if(is_array($placeholders[$match])) {
+ $value = $placeholders[$match][0];
+ } else {
+ $value = $placeholders[$match];
+ }
+ $filter = str_replace('%{'.$match.'}', $value, $filter);
+ }
+ return $filter;
+}
+
+//Setup VIM: ex: et ts=2 enc=utf-8 :