Blame Scripts/Php/Webenv/admin/includes/classes/ldap.php

878a2b
878a2b
/**
878a2b
 * LDAP Access
878a2b
 *
878a2b
 * @category   Logic
878a2b
 * @package    CentOS-News
878a2b
 * @author     Alain Reguera Delgado <alain.reguera@gmail.com>
878a2b
 * @copyright  2009 - CentOS Artwork SIG.
878a2b
 * @license    GPL
878a2b
 */
878a2b
878a2b
class LDAP
878a2b
{
878a2b
878a2b
    var $ldapconn;
878a2b
    var $ldapbind;
878a2b
878a2b
    // LDAP Filter Attributes
878a2b
    var $filter_attrb                     = array();
878a2b
    var $filter_type                      = array();
878a2b
    var $filter_clean                     = array();
878a2b
878a2b
//-----------/* Class initializations
878a2b
878a2b
    function __construct()
878a2b
    {
878a2b
        // Open connection against ldap server
878a2b
        $this->ldapconn = ldap_connect(LDAP_HOST,LDAP_PORT) or die("Could not connect to " . LDAP_HOST . ".");
878a2b
878a2b
        // Set protocol version to use
878a2b
        ldap_set_option($this->ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3) or die("Could not connect to server through LDAPv3.");
878a2b
878a2b
        // Bind
878a2b
        $this->ldapbind = ldap_bind( $this->ldapconn, LDAP_ROOTDN, LDAP_ROOTPW ); 
878a2b
        
878a2b
        // Initialize ldap filter attributes
878a2b
        $this->filter_attrb['cn']                   = 'cn';
878a2b
        $this->filter_attrb['uid']                  = 'uid';
878a2b
        $this->filter_attrb['employeetype']         = ucfirst(translate('employeetype'));
878a2b
        $this->filter_attrb['preferredlanguage']    = ucfirst(translate('language'));
878a2b
878a2b
        // Initialize ldap filter Types
878a2b
        $this->filter_type['=']                     = '=';
878a2b
        $this->filter_type['~=']                    = '~=';
878a2b
878a2b
        // Initialize ldap filter default
878a2b
        $this->filter_clean['attrb']                = 'preferredlanguage';
878a2b
        $this->filter_clean['type']                 = '=';
878a2b
        $this->filter_clean['value']                = LANGUAGE;
878a2b
    }
878a2b
878a2b
//----------- Get entries from ldap server
878a2b
878a2b
    function get_entries( $filter )
878a2b
    {
878a2b
        // Return entries just if filter valid
878a2b
        $search = ldap_search($this->ldapconn,LDAP_DN,$filter);
878a2b
        $entries = ldap_get_entries($this->ldapconn,$search);
878a2b
        return $entries;
878a2b
    }
878a2b
878a2b
//----------// Validate filter value input
878a2b
            // Sanitize filter pattern - Attributes
878a2b
878a2b
    function is_valid( $name , $value )
878a2b
    {
878a2b
        switch ( $name )
878a2b
        {
878a2b
            case 'uid': 
878a2b
                $pattern = '/^([a-z0-9_]|\-|\.)+@(([a-z0-9_]|\-)+\.)+([a-z]{2,6})?$/';
878a2b
                break;
878a2b
878a2b
            case 'preferredlanguage': 
878a2b
                $pattern = '/^[a-zA-Z]{2}$/';
878a2b
                break;
878a2b
878a2b
            case 'filtertype': 
878a2b
                $pattern = '/^(=|~=)$/';
878a2b
                break;
878a2b
878a2b
            case 'employeetype':
878a2b
                $pattern = '/^(writer|administrator)$/';
878a2b
            break;
878a2b
878a2b
            default: 
878a2b
                $pattern = '/^[a-zA-Z0-9_áéíóñúàçèé ]+$/';
878a2b
                break;
878a2b
        }
878a2b
878a2b
        if ( isset( $pattern ) && preg_match( $pattern , $value ))
878a2b
        {
878a2b
            return true;
878a2b
        }
878a2b
        else
878a2b
        {
878a2b
            return false;
878a2b
        }
878a2b
    }
878a2b
878a2b
//---------- Check filter attributes */
878a2b
878a2b
    function sanitize_filter_attribute()
878a2b
    {
878a2b
        $dirty = array();
878a2b
        $clean = array();
878a2b
878a2b
        // Initialize dirty attribute
878a2b
        $dirty['attrb'] = $this->filter_clean['attrb'];
878a2b
878a2b
        // Initialize clean attribute
878a2b
        $clean['attrb'] = $this->filter_clean['attrb'];
878a2b
878a2b
        // Recover dirty attribute values from filter form
878a2b
        if ( isset( $_POST['attribute'] ) )
878a2b
        {
878a2b
            $dirty['attrb'] = $_POST['attribute'];
878a2b
        }
878a2b
878a2b
        // Check dirty attribute
878a2b
        if ( array_key_exists( $dirty['attrb'], $this->filter_attrb ) )
878a2b
        {
878a2b
            // Attribute is not dirty any more. It passed validation.
878a2b
            $clean['attrb'] = $dirty['attrb'];
878a2b
        }
878a2b
878a2b
        return $clean['attrb'];
878a2b
    }
878a2b
878a2b
//---------- Check filter types
878a2b
878a2b
    function sanitize_filter_type()
878a2b
    {
878a2b
        $dirty = array();
878a2b
        $clean = array();
878a2b
878a2b
        $dirty['type'] = $this->filter_clean['type'];
878a2b
        $clear['type'] = $this->filter_clean['type'];
878a2b
878a2b
        // Recover dirty type values from filter form
878a2b
        if ( isset( $_POST['type'] ) )
878a2b
        {
878a2b
            $dirty['type'] = $_POST['type'];
878a2b
        }
878a2b
        else
878a2b
        {
878a2b
            $dirty['type'] = $this->filter_clean['type'];
878a2b
        }
878a2b
878a2b
        // Check dirty types
878a2b
        if ( array_key_exists( $dirty['type'], $this->filter_type ) )
878a2b
        {
878a2b
            // Type is not dirty any more. It passed validation.
878a2b
            $clean['type'] = $dirty['type'];
878a2b
        }
878a2b
878a2b
        return $clean['type'];
878a2b
    }
878a2b
878a2b
//---------- Sanitize filter value
878a2b
878a2b
    function sanitize_filter_value()
878a2b
    {
878a2b
        $dirty = array();
878a2b
        $clean = array();
878a2b
878a2b
        $dirty['value'] = $this->filter_clean['value'];
878a2b
        $clean['value'] = $this->filter_clean['value'];
878a2b
878a2b
        // Recover dirty value from filter form
878a2b
        if ( isset( $_POST['value'] ) )
878a2b
        {
878a2b
            $dirty['value'] = $_POST['value'];
878a2b
        }
878a2b
878a2b
        // Sanitize dirty value, based on supplied attribe
878a2b
        $name  = $this->sanitize_filter_attribute();
878a2b
        $value = $dirty['value'];
878a2b
878a2b
        if ( $this->is_valid( $name, $value ) )
878a2b
        {
878a2b
            // Value is not dirty any more. It passed validation.
878a2b
            $clean['value'] = $value;
878a2b
        }
878a2b
878a2b
        return $clean['value'];
878a2b
    }
878a2b
878a2b
//---------- Build ldap form filter
878a2b
878a2b
    function show_filter()
878a2b
    {
878a2b
        $clean = array();
878a2b
878a2b
        $clean['attrb'] = $this->sanitize_filter_attribute();
878a2b
        $clean['type']  = $this->sanitize_filter_type();
878a2b
        $clean['value']  = $this->sanitize_filter_value();
878a2b
878a2b
        // Start html form
878a2b
        $html = '
';
878a2b
        $html .= '<form name="filter" method="post" action="">';
878a2b
878a2b
        // Build html form fileds. Start with some text
878a2b
        $html .= ucfirst(translate('filtering by')) . ': ';
878a2b
878a2b
        // Build attributes' select form field
878a2b
        $html .= get_user_attrSelector();
878a2b
878a2b
        // Build types' select form field
878a2b
        $html .= '<select name="type">';
878a2b
        foreach ($this->filter_type as $key => $value)
878a2b
        {
878a2b
            if ($clean['type'] == $key )
878a2b
            {
878a2b
                $html .= '<option selected value="'.$key.'">' . $value . '</option>';
878a2b
            }
878a2b
            else
878a2b
            {
878a2b
                $html .= '<option value="'.$key.'">' . $value . '</option>';
878a2b
            }
878a2b
        }
878a2b
        $html .= '</select>';
878a2b
878a2b
        // Build value's text form field
878a2b
        $html .= '<input type="text" name="value" value="'.$clean['value'].'">';
878a2b
878a2b
        // Build submit form button
878a2b
        $html .= '<input type="submit" name="submit_filter" value="'.ucfirst(translate('filter')).'">';
878a2b
878a2b
        // End html form
878a2b
        $html .= '</form>';
878a2b
        $html .= '';
878a2b
        
878a2b
        return $html;
878a2b
    }
878a2b
878a2b
//---------- Build ldap filter string
878a2b
878a2b
    function build_filter_string()
878a2b
    {
878a2b
        $clean['attrb'] = $this->sanitize_filter_attribute();
878a2b
        $clean['type']  = $this->sanitize_filter_type();
878a2b
        $clean['value']  = $this->sanitize_filter_value();
878a2b
878a2b
        return $clean['attrb'] . $clean['type'] . $clean['value'];
878a2b
878a2b
    }
878a2b
878a2b
//----------- Check uniqueness of uid attribute */
878a2b
878a2b
    function is_uid_present( $uid )
878a2b
    {
878a2b
        // Verify that uid entry's value be unique
878a2b
        $filter     = 'uid=' . $uid;
878a2b
        $entry      = $this->get_entries($filter);
878a2b
878a2b
        if ( $uid != '' && $entry['count'] == 1 )
878a2b
        {
878a2b
            return true;
878a2b
        }
878a2b
        else
878a2b
        {
878a2b
            return false;
878a2b
        }
878a2b
    }
878a2b
878a2b
//---------- Prepare userPassword
878a2b
878a2b
    function prepare_userpassword( $userpassword )
878a2b
    {
878a2b
        $dirty['userpassword'] = $userpassword;
878a2b
878a2b
        switch ( LDAP_PASSHASH )
878a2b
        {
878a2b
            case '{MD5}':
878a2b
            $clean['userpassword'] = LDAP_PASSHASH . base64_encode( pack( 'H*', md5( $dirty['userpassword'] ) ) );
878a2b
            break;
878a2b
    
878a2b
            case '{SHA}':
878a2b
            $clean['userpassword'] = LDAP_PASSHASH . base64_encode( pack( 'H*', sha1( $dirty['userpassword'] ) ) );
878a2b
            break;
878a2b
        }
878a2b
878a2b
        return $clean['userpassword'];
878a2b
    }
878a2b
878a2b
//-----------/* Verify modifiable attributes
878a2b
             /* Description : Generally used to redifine entry's input keys and values,
878a2b
             /*               based on is_valid() */
878a2b
             /*      $entry : is an array with entry's keys and values. */
878a2b
878a2b
    function sanitize_entry( $entry )
878a2b
    {
878a2b
        // Define attributes that can be modified
878a2b
        $fields = array('uid', 'cn','userpassword','displayname','preferredlanguage','employeetype');
878a2b
878a2b
        // Verify and validate entry's attributes
878a2b
        foreach ( $fields as $key )
878a2b
        {
878a2b
            if ( isset( $entry[$key] ) && $this->is_valid( $key, $entry[$key] ) ) 
878a2b
            {
878a2b
                // Values that reach this point may be concider "clean".
878a2b
                $clean['entry'][$key] = $entry[$key];
878a2b
            }
878a2b
        }
878a2b
878a2b
        // Return clean entry array or false
878a2b
        if ( isset( $clean['entry'] ) && is_array( $clean['entry'] ) )
878a2b
        {
878a2b
            return $clean['entry'];
878a2b
        }
878a2b
        else
878a2b
        {
878a2b
            return false;
878a2b
        }
878a2b
    }
878a2b
878a2b
//----------/* Initialize useradd values.
878a2b
            /* Description: Used in the useradd form page to initiate form values.
878a2b
            /* $attribute : is an array with the related attributes to check. */
878a2b
878a2b
   function init_useradd_values( $attributes )
878a2b
   {
878a2b
        foreach ( $attributes as $key )
878a2b
        {   
878a2b
            if ( ! isset( $_POST[$key] ) )
878a2b
            {
878a2b
                $entry[$key] = ''; 
878a2b
            }
878a2b
            else
878a2b
            {
878a2b
                if ( isset( $_POST[$key] ) && $this->is_valid($key, $_POST[$key]) )
878a2b
                {
878a2b
                    $entry[$key] = $_POST[$key];
878a2b
                }
878a2b
                else
878a2b
                {
878a2b
                    $entry[$key] = '';
878a2b
                }   
878a2b
            }   
878a2b
        }   
878a2b
        return $entry;
878a2b
   }
878a2b
878a2b
//----------/* Initialize useradmin values and do action if submited 
878a2b
            /* values are different from the actual one.
878a2b
            /* Description: used in the p_users.php to initiate form values.
878a2b
            /*        $id : is the name of the form identification.
878a2b
            /* $attribute : is an array with the related attributes to check. */
878a2b
878a2b
   function init_useradmin_values( $entry, $attributes, $action )
878a2b
   {
878a2b
878a2b
        // First loop to match b in x[b]
878a2b
        for ($i = 0; $i < $entry['count']; $i++)
878a2b
        {
878a2b
            if ( isset( $_POST['uid'][$i] ))
878a2b
            {
878a2b
                // Define entry id
878a2b
                $entry_new['uid'] = $entry[$i]['uid'][0];
878a2b
878a2b
                // Initialize entry cn
878a2b
                // Needed to update sn in the background.
878a2b
                $entry_new['cn'] = $entry[$i]['cn'][0];
878a2b
878a2b
                // Second loop to match x in x[b]
878a2b
                foreach ( $attributes as $key )
878a2b
                {
878a2b
                    // Reset entry value based on input 
878a2b
                    if ( isset( $_POST[$key][$i] ) )
878a2b
                    {
878a2b
                        // Check it is a valid value
878a2b
                        if ( $this->is_valid( $key, $_POST[$key][$i] ) )
878a2b
                        {
878a2b
                            // ... and that it is different from the actual one
878a2b
                            if ( $_POST[$key][$i] != $entry[$i][$key][0] )
878a2b
                            {
878a2b
                
878a2b
                                $entry_new[$key] = $_POST[$key][$i];
878a2b
878a2b
                                // Prepare userPassword.
878a2b
                                // SECURITY: this attribute value should never
878a2b
                                // be verified with the previous one. If
878a2b
                                // verification is done you are providing a
878a2b
                                // way to "guess" the user password by trying
878a2b
                                // passwords until someone reject to update.
878a2b
                                // Not to critic but if you guess it at the
878a2b
                                // first try ;). Keep it unverifiable please.
878a2b
                                if ( $key == 'userpassword' )
878a2b
                                {
878a2b
                                    $newpasswd = $this->prepare_userpassword($_POST[$key][$i]);
878a2b
                                    $entry_new[$key] = $newpasswd;
878a2b
                                }
878a2b
                            }
878a2b
                        }
878a2b
                    }
878a2b
                }
878a2b
            }
878a2b
878a2b
            // Do action if pressent
878a2b
            if ( isset( $entry_new ) )
878a2b
            {
878a2b
                $message = $this->do_action( $entry_new, $action );
878a2b
            }
878a2b
            else
878a2b
            {
878a2b
                $message = show_message(ucfirst(translate('nothing to do')), 'orange');
878a2b
            }
878a2b
        }
878a2b
878a2b
        return $message;
878a2b
   }
878a2b
878a2b
//-----------/*  Do actions (udpate|delete|add) 
878a2b
             /*       $entry : is an array with the entry's key and value information.
878a2b
             /*      $action : is an string telling what to do with the $entry.
878a2b
             /*  Description : Actions are applied to just one entry at the same time. */
878a2b
             /*                The returned value is a message telling what happend with 
878a2b
                               the action requested.*/
878a2b
878a2b
    function do_action( $entry, $action )
878a2b
    {
878a2b
        // Define Entry's DN
878a2b
        if ( isset( $entry['uid'] ) && $this->is_valid( 'uid', $entry['uid'] ) )
878a2b
        {
878a2b
            $dn = 'uid=' . $entry['uid'] . ',' . LDAP_DN;
878a2b
        }
878a2b
        else
878a2b
        {
878a2b
            $message = show_message(ucfirst(translate('a valid uid is required')),'orange');
878a2b
            return $message;
878a2b
        }
878a2b
                
878a2b
        // Define possible actions
878a2b
        $possible_actions = '/^(add|update|delete)$/';
878a2b
        if ( ! preg_match( $possible_actions, $action ) )
878a2b
        {
878a2b
            // There is nothing to do here so exit to finish action intention.
878a2b
            $message = show_message(ucfirst(translate('invalid action')), 'red');
878a2b
            return $message;
878a2b
        }
878a2b
878a2b
        // Define what to do in each action's case 
878a2b
        switch ( $action )
878a2b
        {
878a2b
            case 'update':
878a2b
878a2b
                // If there are valid values then do the update action.
878a2b
                if ( is_array( $entry ) )
878a2b
                {
878a2b
                    // Update sn attribute
878a2b
                    $entry['sn'] = preg_replace('/^([a-zA-Z0-9_]+ ?)/','', $entry['cn']);
878a2b
                    if ( $entry['sn'] == '' )
878a2b
                    {
878a2b
                        $message = show_message(ucfirst(translate('invalid cn')), 'orange');
878a2b
                        return $message;
878a2b
                    }
878a2b
878a2b
                    if (ldap_modify($this->ldapconn, $dn, $entry))
878a2b
                    {
878a2b
                        $message = show_message(ucfirst(translate('data was updated successfully')), 'green');
878a2b
                    }
878a2b
                    else
878a2b
                    {
878a2b
                        $message = show_message(ucfirst(translate('data was not updated')), 'orange');
878a2b
                    }
878a2b
                }
878a2b
            break;
878a2b
878a2b
            // Delete Entry
878a2b
            case 'delete':
878a2b
878a2b
                // Delete Entry
878a2b
                if ( is_array( $entry ) )
878a2b
                {
878a2b
                    if ( ldap_delete( $this->ldapconn, $dn ) )
878a2b
                    {
878a2b
                        $message = show_message(ucfirst(translate('data was deleted successfully')), 'green');
878a2b
                    }
878a2b
                    else
878a2b
                    {
878a2b
                        $message = show_message(ucfirst(translate('data was not deleted')), 'orange');
878a2b
                    }
878a2b
                }
878a2b
            break;
878a2b
878a2b
            // Add Entry
878a2b
            case 'add':
878a2b
878a2b
                // Verify uid presence
878a2b
                if ( $this->is_uid_present( $entry['uid'] ) )
878a2b
                {
878a2b
                    // Abort this action commitment.
878a2b
                    $message = show_message(ucfirst(translate('user identifier already exists')), 'orange');
878a2b
                    return $message;
878a2b
                }
878a2b
                
878a2b
                // Define and validate required attributes
878a2b
                $require_attrs = array('uid', 'userpassword', 'cn', 'displayname', 'preferredlanguage', 'employeetype');
878a2b
                foreach ( $require_attrs as $key )
878a2b
                {
878a2b
                    if ( !isset($entry[$key]) || ! $this->is_valid($key, $entry[$key]))
878a2b
                    {
878a2b
                        $message = show_message(ucfirst(translate('the field')) .' '. translate($key) .' ' . translate('requires a valid value') , 'orange');
878a2b
                        return $message;
878a2b
                    }
878a2b
                }
878a2b
878a2b
                // Prepare userPassword and other attributes.
878a2b
                $entry['userpassword'] = $this->prepare_userpassword($entry['userpassword']);
878a2b
                $entry['objectclass']  = 'inetOrgPerson';
878a2b
                $entry['sn']           = preg_replace('/^([a-zA-Z0-9_]+ ?)/','', $entry['cn']);
878a2b
                if ( $entry['sn'] == '' )
878a2b
                {
878a2b
                    $message = show_message(ucfirst(translate('invalid cn')), 'orange');
878a2b
                    return $message;
878a2b
                }
878a2b
                $entry['mail']         = $entry['uid'];
878a2b
878a2b
                // If there are valid values then do the add action.
878a2b
                if ( ldap_add( $this->ldapconn, $dn, $entry ) )
878a2b
                {
878a2b
                    $message = show_message(ucfirst(translate('user added successfully')), 'green');
878a2b
                }
878a2b
                else
878a2b
                {
878a2b
                    $message = show_message(ucfirst(translate('user was not added')), 'orange');
878a2b
                }
878a2b
            break;
878a2b
        }
878a2b
878a2b
        return $message;
878a2b
    }
878a2b
878a2b
//-------------------/*  Rename entry dn */
878a2b
878a2b
    function rename_dn( $olddn, $newdn, $newparent, $deleteoldrdn )
878a2b
    {
878a2b
        ldap_rename($this->ldapconn, $olddn, $newdn, $newparent, $deleteoldrdn ); 
878a2b
878a2b
        return true;
878a2b
    }
878a2b
878a2b
//-----------/* Display useradmin information
878a2b
             /* Description : Used in p_users.php
878a2b
             /*    $entries : is an array with the entries' keys and values. */
878a2b
878a2b
    function show_useradmin_info( $entries )
878a2b
    {
878a2b
        $html = '
    ';
878a2b
        $html .= '
  • LDAP Host: ' . LDAP_HOST . '
  • ';
    878a2b
            $html .= '
  • Domain Component (dc): ' . LDAP_DN . '
  • ';
    878a2b
            $html .= '
  • ' . $this->show_filter() .'
  • ';
    878a2b
            $html .= '
  • ' . ucfirst(translate('results')) . ': '. $entries['count']; '
  • ';
    878a2b
            $html .= '';
    878a2b
    878a2b
            return $html;
    878a2b
        }
    878a2b
    878a2b
    //-------------------/*  Close connection */
    878a2b
    878a2b
        function __destruct()
    878a2b
        {
    878a2b
            if ( isset( $this->ldapconn ) ) 
    878a2b
            {
    878a2b
                ldap_unbind( $this->ldapconn );
    878a2b
            }
    878a2b
        }
    878a2b
    878a2b
    }
    878a2b
    878a2b
    $ldap = new LDAP;
    878a2b
    ?>