ldap_addressbook-master/LDAPDirectory.inc

LDAPDirectory.inc
<?php //Dear emacs, please make this buffer -*- php -*-


/**
 * @file
 * An abstraction that represents a directory (actually the equivalent of a
 * Distinguished Name, or DN) in a LDAP server.
 *
 * Copyright (C) 2006 Andre dos Anjos
 *
 * This file is part of the ldap_addresbook module for Drupal.
 *
 * The ldap_addressbook module 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
 **/

require_once('Format.inc');

/**
 * This abstraction represents an LDAP user.
 */
class DirUser {
  var $dn; //The DN of the user in the LDAP database
  var $passwd; //The password for this user
  
  /**
   * Constructor
   *
   * @param $dn The DN of the user in an LDAP database
   * @param $passwd That user's password
   */
  function DirUser($dn, $passwd) {
    $this->dn = $dn;
    $this->passwd = $passwd;
  }

}

/**
 * This abstraction represents a directory sitting in an LDAP server. It allows
 * the user to search, add, modify and browse the LDAP server. It is
 * drupal-aware and will output messages directly to drupal in case of
 * problems.
 */
class LDAPDirectory {
  var $host; //The host where this directory is located at
  var $port; //The port number on the host that the server is bound to
  var $dir; //The DN name of directory in the LDAP server
  var $proto; //The protocol version to use for communication

  /**
   * Constructor
   *
   * @param $host The host where this directory is located at
   * @param $port The port number on the host that the server is bound to
   * @param $dir The DN name of directory in the LDAP server
   * @param $proto The protocol version to use
   */
  function LDAPDirectory($host, $port, $dir, $proto) {
    $this->host = $host;
    $this->port = (int)$port;
    $this->dir = $dir;
    $this->proto = (int)$proto;
    if ($this->proto != 2 and $this->proto != 3) {
      drupal_set_message
        (t("Protocol version can only be 2 or 3. I cannot use '$proto'"), 
         'error');
    }
  }

  /**
   * Tests the connection to the LDAP server. Returns true if everything goes
   * fine or false otherwise.
   *
   * @see ldap_connect()
   */
  function _test_connection() {
    $connection = ldap_connect($this->host, $this->port);
    if (!$connection) return FALSE;
    ldap_close($connection);
    return TRUE;
  }

  /**
   * Connects and binds to the LDAP server, using the given user or anonymously
   * if no user is given.
   *
   * @param $user The user with which to bind to the LDAP server, or FALSE, in
   * which case I'll try to bind anonymously.
   *
   * @return The connection, if every thing goes fine otherwise FALSE
   *
   * @see ldap_connect()
   * @see ldap_bind()
   * @see DirUser
   */
  function _connect($user=FALSE) {
    $connection = ldap_connect($this->host, $this->port);
    if (!$connection) {
      drupal_set_message
        (t("Cannot connect to LDAP server at ldap://$this->host:$this->port"),
         'error');
      return FALSE;
    }

    if (!ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 
                         $this->proto)) {
      drupal_set_message(t("Cannot set the LDAP protocol to version $this->prot"), 'error');
      $this->_disconnect($connection);
      return FALSE;
    }

    if (!$user) { //go annonymously
      $bind = ldap_bind($connection);
      if (!$bind) {
        drupal_set_message(t("Cannot bind to the LDAP server (ldap://$this->host:$this->port) anonymously"), 'error');
        $this->_disconnect($connection);
        return FALSE;
      }
    }
    else { //bind with the user
      $bind = ldap_bind($connection, $user->dn, $user->passwd);
      if (!$bind) {
        drupal_set_message(t("Cannot bind to the LDAP server (ldap://$this->host:$this->port) as user (DN) '$user->dn'"), 'error');
        $this->_disconnect($connection);
        return FALSE;
      }
    }

    //if you get here, it is safe to return a connection
    return $connection;
  }

  /**
   * Disconnection is the easiest to implement:)
   *
   * @see ldap_unbind()
   */
  function _disconnect($connection) {
    //ldap_unbind() is said to be more "correct" than ldap_close()
    if ($connection) ldap_unbind($connection);
  }

  /**
   * Add a new entry to this directory
   *
   * @param $dn The distinguished name of the entry to add
   * @param $info The card information for the new entry, as expected by the
   * PHP standard function ldap_add()
   * @param $user The user with writing permissions to do this task. A value
   * of FALSE will make me attempt to do it anonymously.
   *
   * @return <tt>TRUE</tt> if the operation is successful or <tt>FALSE</tt>
   * otherwise.
   *
   * @see ldap_add()
   * @see DirUser
   */
  function add($dn, $info, $user=FALSE) {
    $connection = $this->_connect($user);
    if (!$connection) return FALSE;
    $result = ldap_add($connection, $dn, $info);
    $this->_disconnect($connection);

    if (!$result) {
      //could not perform the addition
      drupal_set_message
        (t("I could not add the LDAP addressbook entry '$dn'."), 'error');
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Add a new contact to this directory
   *
   * @param $info The card information for the new entry, as expected by the
   * PHP standard function ldap_add(), excluding the 'cn' entry that will be
   * used to create the distinguished name.
   * @param $user The user with writing permissions to do this task. A value
   * of FALSE will make me attempt to do it anonymously.
   *
   * @return <tt>TRUE</tt> if the operation is successful or <tt>FALSE</tt>
   * otherwise.
   *
   * @see ldap_add()
   * @see DirUser
   */
  function add_person($info, $user=FALSE) {

    //check for the givenName and sn
    if (!array_key_exists('givenname', $info)) {
      drupal_set_message
        (t("To add an entry, I need the attribute ")._lat('givenname'), 
         'error');
      return FALSE;
    }
    if (!array_key_exists('sn', $info)) {
      drupal_set_message
        (t("To add an entry, I need the attribute ")._lat('sn'), 'error');
      return FALSE;
    }

    //build the DN
    $cn = $info['givenname'].' '.$info['sn'];
    $info['cn'] = $cn;
    $dn = "cn=$cn,$this->dir";
    //makes sure we get the right ObjectClass
    $info['ObjectClass'] = array('top', 'inetOrgPerson');
    return $this->add($dn, $info, $user);
  }

  /**
   * This will remove an entry from this directory.
   *
   * @param $user The user with writing permissions to do this task. A value
   * of FALSE will make me attempt to do it anonymously.
   * @param $cn The CN value of the entry you want to remove 
   *
   * @return <tt>TRUE</tt> if the operation is successful or <tt>FALSE</tt>
   * otherwise.
   *
   * @see ldap_delete()
   * @see DirUser
   */
  function delete ($cn, $user=FALSE) {
    //build the DN
    $dn = "cn=$cn,$this->dir";
    $connection = $this->_connect($user);
    if (!$connection) return FALSE;
    $result = ldap_delete($connection, $dn);
    $this->_disconnect($connection);

    if (!$result) {
      //could not perform the deletion
      drupal_set_message
        (t("I could not delete the LDAP addressbook entry '$cn'."), 'error');
      return FALSE;
    }

    return TRUE;
  }

  /**
   * This will modify an entry in this directory.
   *
   * @param $info The card information for the new entry, as expected by the
   * PHP standard function ldap_add(), excluding the 'cn' entry.
   * @param $user The user with writing permissions to do this task. A value
   * of FALSE will make me attempt to do it anonymously.
   *
   * @return <tt>TRUE</tt> if the operation is successful or <tt>FALSE</tt>
   * otherwise.
   *
   * @see ldap_modify()
   * @see DirUser
   */
  function modify ($info, $user=FALSE) {

    //check for the givenName and sn
    //trigger_error(implode(',',array_keys($info)));
    if (!array_key_exists('givenname', $info)) {
      drupal_set_message
        (t("To modify an entry, I need the attribute ")._lat('givenname'), 
         'error');
      return FALSE;
    }
    if (!array_key_exists('sn', $info)) {
      drupal_set_message
        (t("To modify an entry, I need the attribute ")._lat('sn'), 'error');
      return FALSE;
    }

    $cn = $info['givenname'].' '.$info['sn'];

    $connection = $this->_connect($user);
    if (!$connection) return FALSE;

    //check if we still have cn = givenName + sn
    if ($info['cn'] != $cn) {
      $oldcn = $info['cn'];
      drupal_set_message(t("Replacing entry $oldcn by $cn"));
      $info = $this->get_one($oldcn, $user);
      foreach ($info as $key => $field) $info[$key] = $field;
      $info['cn'] = $cn;
      $retval = TRUE;
      if (! $this->delete($oldcn, $user)) $retval = FALSE;
      if (! $this->add_person($info, $user)) $retval = FALSE;
      $this->_disconnect($connection);
      return $retval;
    }

    //build the DN
    $dn = "cn=$cn,$this->dir";
    $result = ldap_modify($connection, $dn, $info);
    $this->_disconnect($connection);

    if (!$result) {
      //could not perform the addition
      drupal_set_message
        (t("I could not modify the LDAP addressbook entry '$cn'."), 'error');
      return FALSE;
    }

    drupal_set_message(t("Successfuly changed LDAP addressbook entry $cn"));
    return TRUE;
  }

  /**
   * Implements a modified (binary-safe) function to return the entries, so it
   * correctly return things like jpeg photos and other binary entries.
   * 
   * @param $connection The LDAP connection, properly bound
   * @param $search_result The results after ldap_search() has been called.
   *
   * @return An array that contains the entries organized as in the
   * result. Every entry is an array with the LDAP field properties. No
   * "count" fields are available at this version of the result array
   */
  function _format_entries($connection, $search_result) {
    $i=0;
    $retval = array();
    for ($entry=ldap_first_entry($connection, $search_result); 
         $entry != FALSE;
         $entry=ldap_next_entry($connection, $entry)) {
      $attributes = ldap_get_attributes($connection, $entry);
      $j = 0;
      for($j; $j<$attributes['count']; $j++) {
        $values = ldap_get_values_len($connection, $entry, $attributes[$j]);
        $retval[$i][strtolower($attributes[$j])] = $values;
      }
      $i++;
    }
    return $retval;
  }

  /**
   * Do a search in the current directory for all entries.
   *
   * @param $filter The filter should conform to the string representation for
   * search filters as defined in RFC 2254. If this variable is not provided,
   * the default filter (objectClass=*) is used instead.
   * @param $user The user with reading permissions to do this task. A value
   * of FALSE will make me attempt to do it anonymously.
   * @param $sort The sorting criteria to apply, in reverse order, as an
   * array. The keys here are checked against $fields bellow, if that is set,
   * so don't worry too much.
   * @param $fields An array containing the LDAP fields you want to
   * retrieve. The default is to retrive all the available fields for every
   * entry.
   * @param $sub If the scope of the search should be sub(tree). Otherwise, if
   * unset or FALSE, the search will be realized only in the current
   * directory. Not on subdirectories.
   *
   * @return An array where every entry is the CN value of the LDAP entry and
   * the contents of every entry is an array with the entries fields. An empty
   * array means the search has not found any matches. A value of FALSE as
   * return value indicates there were problems.
   */
  function search_any($filter='', $user=FALSE, $sort=array('cn'),
                      $fields=NULL, $sub=FALSE) {
    if (empty($filter)) $filter='(objectClass=*)';

    $connection = $this->_connect($user);
    if (!$connection) return FALSE;

    //set the scope
    $result = FALSE;
    if ($sub) 
      $result = ldap_search($connection, $this->dir, $filter, $fields);
    else 
      $result = ldap_list($connection, $this->dir, $filter, $fields);

    if (!$result) {
      drupal_set_message(t('Cannot search the LDAP directory '.$this->dir),
                         'error');
      $this->_disconnect($connection);
      return FALSE;
    }

    //the sorting in reverse order
    foreach ($sort as $s) {
      if (is_null($fields)) ldap_sort($connection, $result, $s);
      else if (in_array($s, $fields)) ldap_sort($connection, $result, $s);
    }

    //get into a PHPified version of the answer
    $info = $this->_format_entries($connection, $result);

    $this->_disconnect($connection);
    return $info;
  }

  /**
   * Do a search in the current directory for all entries of the Person
   * type. The search is always only for the current directory, not includding
   * subdirectories.
   *
   * @param $filter The filter should conform to the string representation for
   * search filters as defined in RFC 2254. If not provided, the default
   * filter, (objectClass=Person), is used. If provided, it is added as an
   * logical AND clause to (objectClass=Person).
   * @param $user The user with reading permissions to do this task. A value
   * of FALSE will make me attempt to do it anonymously.
   * @param $sort The sorting criteria to apply, in reverse order, as an
   * array. The keys here are checked against $fields bellow, if that is set,
   * so don't worry too much.
   * @param $fields An array containing the LDAP fields you want to
   * retrieve. The default is to retrive all the available fields for every
   * entry.
   *
   * @return An array where every entry is the CN value of the LDAP entry and
   * the contents of every entry is an array with the entries fields. An empty
   * array means the search has not found any matches. A value of FALSE as
   * return value indicates there were problems.
   */
  function search_person($filter='', $user=FALSE, $sort=array('cn'),
                         $fields=NULL) {
    if (empty($filter)) $filter='(objectClass=Person)';
    else $filter="(&(objectClass=Person)$filter)";
    return $this->search_any($filter, $user, $sort, $fields, FALSE);
  }

  /**
   * Returns an array with the entry's properties or FALSE in the case there
   * are no entries with the assigned CN.
   *
   * @param $cn The CN entry of the contact you are searching for.
   * @param $user The user with reading permissions to do this task. A value
   * of FALSE will make me attempt to do it anonymously.
   * @param $fields An array containing the LDAP fields you want to
   * retrieve. The default is to retrive all the available fields for every
   * entry.
   *
   * @return An array where every entry is the CN value of the LDAP entry and
   * the contents of every entry is an array with the entries fields. An empty
   * array means the search has not found any matches. A value of FALSE as
   * return value indicates there were problems.
   */
  function get_one($cn, $user=FALSE, $fields=NULL) {
    $result = $this->search_person("(cn=$cn)", $user, array(), $fields);
    if (count($result) != 1) return FALSE;
    return $result[0];
  }

  /**
   * This function will check if a directory exists and either return TRUE
   * or FALSE
   *
   * @param $rdn The reduced distinguished name of subdirectory to find
   */
  function is_dir($dn, $user=FALSE) {
    $connection = $this->_connect($user);
    $base = explode(',',$dn);
    $search_dir = explode('=', $base[0]);
    unset($base[0]);
    $base = implode(',',$base);
    if (!$connection) return FALSE;
    $result = ldap_list($connection, $base, '(objectClass=organizationalUnit)');
    if (!$result) {
      drupal_set_message(t("I could not check directory in LDAP server"), 
                         'eror');
      $this->_disconnect($connection);
      return FALSE;
    }
    $info = $this->_format_entries($connection, $result);
    foreach ($info as $i) {
      if ($i[trim($search_dir[0])][0] == trim($search_dir[1])) return TRUE;
    }
    return FALSE;
  }

}

/**
 * This class extends the LDAPDirectory class above by fusioning it with the
 * Drupal preference system. The outcome is that when you create an instance
 * of this class, all configuration options do not need to be specified.
 */
class DrupalDirectory extends LDAPDirectory {

  /**
   * The constructor, gets the variables from Drupal and builds the underlying
   * LDAPDirectory.
   */
  function DrupalDirectory ($dir='') {
    if (empty($dir)) 
      $dir = variable_get('ldap_addressbook_base', 
                          'ou=addressbook,dc=example,dc=com');
    parent::LDAPDirectory(variable_get('ldap_addressbook_host', 'localhost'),
                          variable_get('ldap_addressbook_port', '389'),
                          $dir, variable_get('ldap_addressbook_version', '3'));
  }

  /**
   * Returns the user
   */
  function user() {
    $user = new DirUser(variable_get('ldap_addressbook_user', 
                                     'cn=Manager,dc=example,dc=com'),
                        variable_get('ldap_addressbook_user_pass', ''));
    return $user;
  }

  /**
   * Returns if we should be doing anonymous reading or not
   */
  function read_anonymously() {
    return (bool)variable_get('ldap_addressbook_anonymous', '1');
  }

  /**
   * Returns the reader user or FALSE in case I have to read anonymously
   */
  function _reader() {
    if ($this->read_anonymously()) return FALSE;
    return $this->user();
  }

  /**
   * Returns the fields of interest in your addresbook
   */
  function fields() {
    $default_fields = array('jpegphoto', 'givenname', 'cn', 'sn', 
                            'mail', 'homepostaladdress', 'postaladdress',
                            'postalcode', 'telephonenumber', 'homephone', 
                            'mobile', 'o', 'labeleduri', 'title');
    $retval = strtolower(variable_get('ldap_addressbook_fields', 
                                      implode(' ', $default_fields)));
    return explode(' ', $retval);
  }

  /**
   * Returns the main person filter
   */
  function person_filter() {
    return variable_get('ldap_addressbook_person_filter', 
                        '(objectClass=Person)');
  }

  /**
   * Returns the user addressbook template
   */
  function userbook_template() {
    return variable_get('ldap_addressbook_private_template', 
                        'ou=%s,ou=addressbook,dc=example,dc=com');
  }

  /**
   * The password hashing strategy.
   */
  function password_hash() {
    return variable_get('ldap_addressbook_password_hash',
                        'clear');
  }

  /**
   * Returns the subdirectory filter
   */
  function subdir_filter() {
    return variable_get('ldap_addressbook_subdir_filter',
                        '(objectClass=organizationalUnit)');
  }

  /**
   * Returns the fields of interest in your addresbook when you want to
   * compute summary entries (more compact addressbook cards).
   */
  function summary_fields() {
    $default_summary = array('jpegphoto', 'cn', 'mail', 'telephonenumber', 
                             'mobile', 'labeleduri');
    $retval = strtolower(variable_get('ldap_addressbook_summary', 
                                      implode(' ', $default_summary)));
    return explode(' ', $retval);
  }

  /**
   * Returns the maximum jpeg size you can have in the addressbook.
   */
  function maximum_jpeg_size() {
    return (int)variable_get('ldap_addressbook_jpeg_size', 200);
  }

  /**
   * Returns the path that I should use for storing temporary files
   */
  function tmp_path() {
    return variable_get('ldap_addressbook_tmp',
                        file_directory_path().'/tmp');
  }

  /**
   * Returns this module name
   */
  function module_name() { return 'ldap_addressbook'; }
    
  /**
   * @see LDAPDirectory::add()
   */
  function add($info, $privacy) {
    if ($privacy != 'global' && $privacy != 'private') {
      drupal_set_message(t('Privacy attribute, for addition, can only assume values "global" or "private"'), 'error');
      return FALSE;
    }
    else if ($privacy == 'global') return parent::add_person($info, $this->user());
    else { 
      $user_dn = $this->private_book();
      if (!$user_dn) {
        drupal_set_message(t('Cannot access private addressbook for addition'), 'error');
        return FALSE;
      }
      $user_dir = new LDAPDirectory
        (variable_get('ldap_addressbook_host', 'localhost'), 
         variable_get('ldap_addressbook_port', '389'), $user_dn,
         variable_get('ldap_addressbook_version', '3')); 
      return $user_dir->add_person($info, $this->user());
    }
  }

  /**
   * @see LDAPDirectory::delete()
   */
  function delete($cn, $privacy) { 
    if ($privacy != 'global' && $privacy != 'private') {
      drupal_set_message(t('Privacy attribute, for deletion, can only assume values "global" or "private"'), 'error');
      return FALSE;
    }
    else if ($privacy == 'global') return parent::delete($cn, $this->user());
    else { 
      $user_dn = $this->private_book();
      if (!$user_dn) return FALSE;
      $user_dir = new LDAPDirectory
        (variable_get('ldap_addressbook_host', 'localhost'),
         variable_get('ldap_addressbook_port', '389'), $user_dn, 
         variable_get('ldap_addressbook_version', '3'));
      return $user_dir->delete($cn, $this->user());
    }
  }

  /**
   * @see LDAPDirectory::modify()
   */
  function modify ($info) {
    return parent::modify($info, $this->user());
  }

  /**
   * @see LDAPDirectory::search() <- problem with recursion
   *
   * @param $privacy Defines the scope of the search. A value of "global" will
   * only search the global addressbook. A value of "private" will only search
   * the user's addressbook if there is any. A value of "all" will search both
   * addressbooks.
   */
  function search($filter='', $sort=array('cn'), 
                  $fields=NULL, $privacy="all") {
    $info = array('global' => array(),
                  'private' => array());

    if ($privacy == 'global' || $privacy == 'all')
      $info['global'] =
        parent::search_person($filter, $this->_reader(), $sort, $fields);

    if ($privacy == 'private' || $privacy == 'all') { 
      $user_dn = $this->private_book();
      if ($user_dn) {
        $user_dir = new LDAPDirectory
          (variable_get('ldap_addressbook_host', 'localhost'),
           variable_get('ldap_addressbook_port', '389'), $user_dn, 
           variable_get('ldap_addressbook_version', '3'));
        $info['private'] = 
          $user_dir->search_person($filter, $this->_reader(),
                                   $sort, $fields);
      }
      else {
        if ($privacy == 'private') {
          //if the user is search explicetly for a private addressbook...
          drupal_set_message(t('You do <b>not</b> seem to have a private addressbook I can search at. Ask the LDAP addressbook administrator to create one for you.'), 'error');
          return FALSE;
        }
      }
    }
    return $info;
  }

  /**
   * Checks if the current user can use/have a private addressbook available. 
   */
  function private_book() {
    if (!user_access('Have private LDAP addressbook')) return FALSE;
    global $user; //get the current user's name
    $user_dn = sprintf($this->userbook_template(), $user->name);
    $check = parent::is_dir($user_dn, $this->_reader());
    if ($check) return $user_dn;
    return FALSE;
  }

  /**
   * @see LDAPDirectory::get_one()
   */
  function get_one($privacy, $cn) {
    if ($privacy == 'global')
      return parent::get_one($cn, $this->_reader(), $this->fields());
    else if ($privacy == 'private') {
      if (user_access('Have private LDAP addressbook')) {
        global $user; //get the current user's name
        $user_dn = sprintf($this->userbook_template(), $user->name);
        if (parent::is_dir($user_dn, $this->_reader())) {
          $user_dir = new LDAPDirectory
            (variable_get('ldap_addressbook_host', 'localhost'),
             variable_get('ldap_addressbook_port', '389'), $user_dn, 
             variable_get('ldap_addressbook_version', '3'));
            return $user_dir->get_one($cn, $this->_reader(), $this->fields());
        }
      }
      else {
        drupal_access_denied(); //?
        return FALSE;
      }
    }
    else {
      drupal_set_message(t("Cannot accept privacy '$privacy' to get a single entry in the LDAP addressbook. Check the cause of error or submit a bug report!"), 'error');
    }
    drupal_access_denied(); //?
  }

}

/**
 * A hashing system for preparing hashed password to be used with LDAP. This
 * function source code was copied from the phpLDAPAdmin project.
 *
 * @param $secret The value to hash, not previously encripted
 * @param $algo The algorithm to use. Must be one of crypt, ext_des, md5crypt,
 * blowfish, md5, sha, smd5, ssha, or clear.
 *
 * @return The hashed valued, ready to be used with LDAP, if the algorithm is
 * supported, or FALSE otherwise.
 */

function _lab_hash( $secret, $algo ) {
  $algo = strtolower( $algo );

  $hash = '';
  switch ( $algo ) {

  case 'crypt':
    $hash = '{CRYPT}' . crypt( $secret, random_salt(2) );
    break;

  case 'ext_des':
    // extended des crypt. see OpenBSD crypt man page.
    if ( ! defined( 'CRYPT_EXT_DES' ) || CRYPT_EXT_DES == 0 ) {
      drupal_set_message(t("Your PHP installation does not contain support for the hashing algorithm '$algo'"), 'error');
      return FALSE;
    }
    $hash = '{CRYPT}' . crypt( $secret, '_' . random_salt(8) );
    break;

  case 'md5crypt':
    if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 ) {
      drupal_set_message(t("Your PHP installation does not contain support for the hashing algorithm '$algo'"), 'error');
      return FALSE;
    }
    $hash = '{CRYPT}' . crypt( $secret , '$1$' . random_salt(9) );
    break;

  case 'blowfish':
    if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 ) {
      drupal_set_message(t("Your PHP installation does not contain support for the hashing algorithm '$algo'"), 'error');
      return FALSE;
    }
    // hardcoded to second blowfish version and set number of rounds
    $hash = '{CRYPT}' . crypt( $secret , '$2a$12$' . random_salt(13) );
    break;

  case 'md5':
    $hash = '{MD5}' . base64_encode( pack( 'H*' , md5($secret) ) );
    break;

  case 'sha':
    if( function_exists('sha1') ) {
      // use php 4.3.0+ sha1 function, if it is available.
      $hash = '{SHA}' . base64_encode( pack( 'H*' , sha1($secret) ) );

    } else if ( function_exists( 'mhash' ) ) {
      $hash = '{SHA}' . base64_encode( mhash( MHASH_SHA1, $secret) );

    } else {
      drupal_set_message(t("Your PHP installation does not contain support for the hashing algorithm '$algo'"), 'error');
      return FALSE;
    }
    break;

  case 'ssha':
    if(function_exists( 'mhash' ) && function_exists('mhash_keygen_s2k')) {
      mt_srand( (double) microtime() * 1000000 );
      $salt = mhash_keygen_s2k(MHASH_SHA1, $secret, 
                               substr(pack("h*", md5(mt_rand())), 0, 8), 4);
      $hash = "{SSHA}".base64_encode(mhash(MHASH_SHA1, $secret.$salt).$salt);

    } else {
      drupal_set_message(t("Your PHP installation does not contain support for the hashing algorithm '$algo'"), 'error');
      return FALSE;
    }
    break;

  case 'smd5':
    if(function_exists( 'mhash' ) && function_exists('mhash_keygen_s2k')) {
      mt_srand( (double) microtime() * 1000000 );
      $salt = mhash_keygen_s2k(MHASH_MD5, $secret,
                               substr(pack("h*", md5(mt_rand())), 0, 8), 4);
      $hash = "{SMD5}".base64_encode(mhash(MHASH_MD5, $secret.$salt).$salt);

    } else {
      drupal_set_message(t("Your PHP installation does not contain support for the hashing algorithm '$algo'"), 'error');
      return FALSE;
    }
    break;

  case 'clear':
  default:
    $hash = $secret;
  }

  return $hash;
}

?>

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc