<?php
/*
 * Copyright 1999 - 2003 by Gero Kohnert
 *
 * CVS Info:  $Id: auth_ldap.pinc,v 1.16 2005/05/03 13:18:49 saraj Exp $
 * $Author: saraj $
 *
 * code by Dimitri Fontaine <dfontaine@cvf.fr>
 * Patches and ldap filter by Frederic Olivie <alf@club-internet.fr>
 */

require_once 'auth.pinc';

#
# Globally diable PWLOST SUPPORT
#
$tutos[pwlostsupport] = 0;

/**
 * Authentification base class
 *
 * @modulegroup BASE
 * @module auth_ldap
 * @package BASE
 */
class auth_ldap extends auth{
  /**
   * get the password
   */
  function getpw() {
    if ( isset($_POST['pw']) ) {
      return $_POST['pw'];
    } elseif ( isset($_GET['pw']) ) {
      return $_GET['pw'];
    }
    return;
  }
  /**
   * get the username
   */
  function getuname() {
    if ( isset($_POST['uname']) ) {
      return trim($_POST['uname']);
    } elseif ( isset($_GET['uname']) ) {
      return trim($_GET['uname']);
    }
    return;
  }
  /**
   * Check for permmision
   */
  function check() {
    global $current_user,$lang,$tutos;

    $r = array();

    if ( ! function_exists('ldap_connect')) {
      $r[0] = "LDAP not available";
      $r[1] = $r[0];
      return $r;
    }

    $query =
      "SELECT p.*, a.*,p.id as u_id FROM ". $this->dbconn->prefix ."people p, ". $this->dbconn->prefix ."addresses a ".
      "WHERE  login = ". $this->dbconn->String($this->getuname()).
      "       AND p.adr_id = a.id";

    $result = $this->dbconn->Exec($query);

    if ( ! $result ) {
      ReadLang($lang);
      $r[0] = "No Result for ". $this->getuname() ." / ". $this->getpw();
      $r[1] = $lang['Err0026'];
      return $r;
    }

    if ( 1 != $result->numrows()) {
      ReadLang($lang);
      $r[0]  = "not unique ";
      $r[0] .= $result->numrows() ." Result for ". $this->getuname() ." / ". $this->getpw();
      $r[1]  = $lang['Err0027'];
      return $r;
    }

    /* OK there is one user so lets check */

    $ds = ldap_connect($tutos[ldapauthserver]["host"],
                       $tutos[ldapauthserver]["port"]);

    if( ! $ds ) {
      ReadLang($lang);
      $r[0] =  "unable to connect to ldapserver ";
      $r[0] .= $tutos[ldapauthserver]["host"].":";
      $r[0] .= $tutos[ldapauthserver]["port"];
      $r[1] = $r[0];
      return $r;
    }

    # uncomment if neccessary
    # ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);

    if( $tutos[ldapauth_user] != 0 ) {
      /* In this case, we try to bind the LDAP server with the given
       * user/passwd pair
       */
      $dn = $tutos[ldapauthserver]["userdn"]."=".$this->getuname().",". $tutos[ldapauthserver]["basedn"];
    
      // echo $dn;
      $res = ldap_bind($ds,$dn,$this->getpw());
    
      if( ! $res ) {
        $errno = ldap_errno($ds);
        ReadLang($lang);
        $r[0]  = " (error ". $errno ." ";
        $r[0] .= ldap_err2str($errno) .")";
        $r[1]  = $r[0];
        $r[2]  = $lang['Err0027'];
        return $r;
      }

      // We could bind. carry on and check filter if we have one
      if (isset($tutos[ldapauthserver]["filter"])) {
        $filter = $tutos[ldapauthserver]["filter"] ;
        $filter = str_replace("%u", $this->getuname(), $filter) ;
        $sr = ldap_search($ds, $tutos[ldapauthserver]["basedn"], $filter) ;

        // Check if we got an entry back
        $info = ldap_get_entries($ds, $sr);

        if ($info["count"] == 0) {
   	      // No entry. The filter did not pass the test
          ReadLang($lang);
          $r[0] = "User " . $this->getuname() . " did not pass ldap filter " . $filter ;
		  $r[0] .= " or is not present in ldap db" ;
  		  $r[1] = $lang['Err0027'];
		  @ldap_unbind($ds);
		  @ldap_close($ds);
		  return $r ;
        }
      }
      // We found a potential candidate. Use him.

      $current_user= new tutos_user($this->dbconn);
      $current_user->read_result($result,0);
      $result->free(); 

      @ldap_unbind($ds);
      @ldap_close($ds);

      return;
    } else {
      /* In this case we have to bind to the LDAP server either anonymously
       * or with a granted account, and fetch the LDAP crypted (or not) 
       * passwd, to compare with the one given by the user
       */
      if( $tutos[ldapauth_anonymous] == 1 ) {
        // this is an "anonymous" bind
        $res = ldap_bind($ds);
      } else {
        $res = ldap_bind($ds,
               $tutos[ldapauthserver]["binddn"],
               $tutos[ldapauthserver]["passwd"]);
      }

      if( ! $res ) {
        $errno = ldap_errno($ds);
        ReadLang($lang);
        $r[0]  = " (error ". $errno ." ";
        $r[0] .= ldap_err2str($errno) .")";
        $r[1]  = $r[0];
        $r[2]  = $lang['Err0027'];
        return $r;
      }

      // Build filter if we have one
      if (isset($tutos[ldapauthserver]["filter"])) {
        $filter = $tutos[ldapauthserver]["filter"] ;
        $filter = str_replace("%u", $this->getuname(), $filter) ;
      } else {
        $filter = $tutos[ldapauthserver]["userdn"]."=".$this->getuname() ;
      }

      $sr = ldap_search($ds,
			$tutos[ldapauthserver]["basedn"],
			$filter) ;

      if( ! $sr ) {
        $errno = ldap_errno($ds);
        ReadLang($lang);
        $r[0]  = ldap_error($ds) ." (error ". $errno ." ";
        $r[0] .= ldap_err2str($errno) .")";
        $r[1]  = $r[0];
        return $r;
      }

      if ( ldap_count_entries($ds,$sr) == 0 ) {
        ReadLang($lang);
        $r[0]  = "not unique ". $result->numrows();
        $r[0] .= " Result for ". $this->getuname() ." / ". $this->getpw();
        $r[1]  = $lang['Err0027'];
        return $r;
      }

      $entries = ldap_get_entries($ds, $sr);
      // echo "pass: ".$entries[0]['userpassword'][0]."<br>\n";

      $passwd = $this->getpw();
      $encryptedPassword = trim($entries[0]['userpassword'][0]);

      // We read the salt argument from the current encrypted password  
      if( $tutos[ldapauth_pw_enc] == 1 ) {
        if (!strncasecmp($encryptedPassword, "{crypt}", strlen("{crypt}"))) {
	  // Treat the standard DES crypt format
	  $encryptedPassword = substr($encryptedPassword, strlen("{crypt}")) ;
	  $passwd = crypt(trim($passwd), $encryptedPassword);
	}
	else if (!strncmp($encryptedPassword, "{md5}", strlen("{md5}"))) {
	  // Treat the MD5 crypt format
	  $encryptedPassword = substr($encryptedPassword, strlen("{md5}")) ;
	  $passwd = md5($passwd) ;
	}
	else {
          $salt = '';
          $separator = '$';
          $numberOccurencySeparator = 0;
          for( $i = 0; $i < strlen ($encryptedPassword); $i ++) {  
            if( strcmp ($encryptedPassword [$i], $separator) == 0) {
              $numberOccurencySeparator ++;
              if ($numberOccurencySeparator == 3)
                break;
            }
            $salt .= $encryptedPassword [$i];
          }
          $passwd = crypt(trim($this->getpw()), $salt);
		}
      }

      if( strcmp($encryptedPassword, $passwd) != 0 ) {
        ReadLang($lang);
        $r = array();
        $r[0]  = "LDAP auth failed: bad passwd";
        $r[1]  = $lang['Err0027'];
        return $r;
      }

      // We create the user only when the ldap auth
      // has succeeded
      $current_user= new tutos_user($this->dbconn);
      $current_user->read_result($result,0);
      $result->free();
      return;
    }
  }
}
?>