You are here

restrict_by_ip.module in Restrict Login or Role Access by IP Address 6.2

Allows the admin to select which ip addresses role or a user can login from for this site Some of the code below is taken from the cck_ipaddress_module

File

restrict_by_ip.module
View source
<?php

/**
 * @file
 * Allows the admin to select which ip addresses role or a user  can login from for this site
 * Some of the code below is taken from the cck_ipaddress_module
*/

/**
 * This just checks the database for any roles associated with that user
 * that are in the restrict_by_ip table. From there it does a ip check 
 * on each one of them to see if they are within the range of ip's allowed for that
 * role.
 */
function restrict_by_ip_role_check(&$user) {

  //now do the resrict by ip check, remove roles from above array that should not be there

  //get all possible roles for the given user (other than annonmyous role and )
  $result = db_query('select rip.rid, rip.restrict_by_ip_address from {restrict_by_ip} rip left join {users_roles} ur ON ur.rid = rip.rid where ur.uid = %d', intval($user->uid));
  $ip2check = $_SERVER['REMOTE_ADDR'];
  while ($role = db_fetch_object($result)) {
    $ipaddresses = explode(";", $role->restrict_by_ip_address);
    foreach ($ipaddresses as $ipaddress) {
      if (!_restrict_by_ip_cidrcheck($ip2check, $ipaddress)) {

        //unset a role if its not within the allowed ip range for this role
        unset($user->roles[$role->rid]);
      }
    }
  }
}

/**
 * Hook to the admin_permissions submit function
 */
function restrict_by_ip_user_admin_perm_submit($form, &$form_state) {
  $rid = $form_state['values']['rid'];
  $role_restrict_by_ip_type = $form_state['values']['restrict_by_ip_type'];
  $restrict_by_ip_address = $form_state['values']['restrict_by_ip_address'];
  if ($role_restrict_by_ip_type == "1") {
    if (db_result(db_query('SELECT rid FROM {restrict_by_ip} WHERE rid = %d', $rid))) {
      db_query("UPDATE {restrict_by_ip} SET restrict_by_ip_type = %d, restrict_by_ip_address = '%s' WHERE rid = %d", intval($role_restrict_by_ip_type), t($restrict_by_ip_address), intval($rid));
    }
    else {
      db_query("INSERT INTO {restrict_by_ip} (rid, restrict_by_ip_type, restrict_by_ip_address) VALUES ( %d ,%d, '%s' )", intval($rid), intval($role_restrict_by_ip_type), t($restrict_by_ip_address));
    }
  }
  else {
    db_query("DELETE FROM {restrict_by_ip} WHERE rid=%d", intval($rid));
  }
}

/**
 * Hook for the permissions validate function. Checks to make sure the ip-address is valid.
 */
function restrict_by_ip_user_admin_perm_validate($form, &$form_state) {

  // Seperate the ip address by semi-colon delimiter
  $ret = TRUE;
  $sms = "Retrict by IP Address setting not updated to role";
  if ($form_state['values']['rip']['restrict_by_ip_type']) {
    $ret = _restrict_by_ip_validate_ip($form_state['values']['restrict_by_ip_address'], $sms);
  }
  return $ret;
}

/**
 * Hook to the admin_permissions form
 */
function restrict_by_ip_form_user_admin_perm_alter(&$form, $form_state) {
  $rid = arg(3);

  //check to make sure its a single role we are editing

  //and that it is not a annonymous user or simply an "authenticated user"

  //we could change this later?
  if (isset($rid) && intval($rid) > 2) {
    $roledata_restrict_by_ip_type = "0";

    // Grab the current restrict by ip data if it exists
    $found = db_result(db_query('SELECT count(*) FROM {restrict_by_ip} WHERE rid = %d', intval($rid)));
    if ($found) {
      $roledata = db_fetch_object(db_query('SELECT * FROM {restrict_by_ip} WHERE rid = %d', intval($rid)));
      $roledata_restrict_by_ip_type = "1";
      $roledata_restrict_by_ip_address = $roledata->restrict_by_ip_address;
    }
    $form['rip'] = array(
      '#type' => 'fieldset',
      '#attributes' => array(
        'class' => 'restrict-by-ip',
      ),
      '#title' => t('Restrict by IP settings'),
      '#collapsible' => FALSE,
    );
    $form['rip']['rid'] = array(
      '#type' => 'value',
      '#value' => $rid,
    );
    $form['rip']['restrict_by_ip_type'] = array(
      '#type' => 'radios',
      '#title' => t('Restrict By IP'),
      '#default_value' => $roledata_restrict_by_ip_type,
      '#options' => array(
        t('No'),
        t('Yes'),
      ),
    );
    $form['rip']['restrict_by_ip_address'] = array(
      '#type' => 'textfield',
      '#default_value' => $roledata_restrict_by_ip_address,
      '#size' => 128,
      '#maxlength' => 128,
      '#description' => t('Enter IP Address Ranges in CIDR Notation seperated with semi-colons, with no trailing semi-colon. E.G. 10.20.30.0/24;192.168.199.1/32;1.0.0.0/8<br />For more information on CIDR notation <a href="http://www.brassy.net/2007/mar/cidr_basic_subnetting" target="_blank">click here</a>.'),
    );
    $form['#submit'] = array(
      'restrict_by_ip_user_admin_perm_submit',
      'user_admin_perm_submit',
    );
    $form['#validate'] = array(
      'restrict_by_ip_user_admin_perm_validate',
    );

    //unset the submit just so we can add the button again

    //this way restrict ip does not show up at bottom of page

    //I do not know any other way to do this?
    unset($form['submit']);
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => 'Save Permissions',
    );
  }
}

/**
 * Implementation of hook_help()
 */
function restrict_by_ip_help($section) {
  switch ($section) {
    case 'admin/help#restrict_by_ip':
      $output = '<p>The site administrator can limit a user to only be able to login from certain IP Addresses or ranges of IP Addresses using CIDR notation.</p>';
      break;
  }
  return $output;
}

/**
 * Implementation of hook_menu()
 * Add a menu item to the ddminister >> site building menu for displaying the restrict_by_ip
 */
function restrict_by_ip_menu() {
  $items = array();
  $items['admin/settings/restrict_by_ip'] = array(
    'title' => t('Restrict by IP settings'),
    'description' => t('Limit the IP address a user is allowed to login from.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'restrict_by_ip_settings',
    ),
    'access arguments' => array(
      'administer restrict by ip',
    ),
  );
  return $items;
}

/**
 * Implementation of hook_perm()
 */
function restrict_by_ip_perm() {
  return array(
    'administer restrict by ip',
  );
}

/**
 * Menu callback to configure module settings
 */
function restrict_by_ip_settings() {

  //from here is default
  $form = array();
  $form['restrict_by_ip_error_page'] = array(
    '#type' => 'textfield',
    '#title' => t('Login denied page'),
    '#description' => t("This the address of the page to which the user will be redirected if they are not allowed to login. If you don't set this the user will not know why they couldn't login"),
    '#weight' => -5,
    '#default_value' => variable_get('restrict_by_ip_error_page', ''),
    '#required' => TRUE,
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_user()
 */
function restrict_by_ip_user($type, &$edit, &$account, $category = NULL) {
  global $user;
  switch ($type) {
    case 'login':
      return _restrict_by_ip_login($user);
      break;
    case 'form':
    case 'register':
      return _restrict_by_ip_form($account->uid);
      break;
    case 'insert':
    case 'update':
      return _restrict_by_ip_update($account->uid, $edit);
      break;
    case 'submit':

      //Drupal Bug: http://drupal.org/node/321787 - using for edit user will still update user data if error
      return _restrict_by_ip_validate($edit, 1);
      break;
    case 'validate':

      //Drupal Bug: http://drupal.org/node/321787 - not fired when editing user only on new user
      return _restrict_by_ip_validate($edit, 2);
      break;
    case 'delete':
      return _restrict_by_ip_delete($account->uid);
      break;
  }
}

/**
 * Login function
 * Checks the user's ip address on login
 * If they are not restricted, or logging in from the appropriate address
 * allow logon to continue. If not redirect to a designated page
 */
function _restrict_by_ip_login(&$user) {
  if ($user->uid > 1) {
    $usrdata = db_fetch_object(db_query('SELECT * FROM {restrict_by_ip} WHERE uid = %d', $user->uid));
    $logonvalid = FALSE;
    $ip2check = $_SERVER['REMOTE_ADDR'];

    // If the user has restrict by ip address set
    if ($usrdata->restrict_by_ip_type) {
      $ipaddresses = explode(";", $usrdata->restrict_by_ip_address);

      // Check each valid ip address in database against users ip address
      // If one matches allow logon
      foreach ($ipaddresses as $ipaddress) {
        if (_restrict_by_ip_cidrcheck($ip2check, $ipaddress)) {
          $logonvalid = TRUE;
        }

        //else if(_restrict_by_role($user->$roles){}
      }

      // Restrict by ip address is set and no addresses match users ip address
      if (!$logonvalid) {

        // Log the error with the ip address
        watchdog('user', t('Session closed for %name - Invalid IP. ' . $ip2check, array(
          '%name' => $user->name,
        )));

        // Destroy the current session
        session_destroy();
        module_invoke_all('user', 'logout', NULL, $user);

        // Load the anonymous user
        $user = drupal_anonymous_user();

        // unset destination required to force them to the ip page during drupal_goto()
        if (isset($_REQUEST['destination'])) {
          unset($_REQUEST['destination']);
        }

        // Goto the page detailed in the site configuration - restrict by ip - settings page
        drupal_goto(variable_get('restrict_by_ip_error_page', '0'));
      }
    }
    return $logonvalid;
  }
  else {
    return TRUE;
  }
}

/**
 * Form and register function
 * Insert the restrict by ip form into the user settings and new user forms for authorised users
 */
function _restrict_by_ip_form($uid) {
  global $user;

  //new code here
  if (user_access('administer site configuration') || user_access('administer restrict by ip')) {
    $form = array();
    drupal_add_css(drupal_get_path('module', 'restrict_by_ip') . '/restrict_by_ip.css', 'module', 'screen', FALSE);
    $usrdata_restrict_by_ip_type = "0";
    $usrdata_restrict_by_ip_address = "";

    // Grab the current restrict by ip data if it exists
    $found = db_result(db_query('SELECT count(*) FROM {restrict_by_ip} WHERE uid = %d', $uid));
    if ($found) {
      $usrdata = db_fetch_object(db_query('SELECT * FROM {restrict_by_ip} WHERE uid = %d', $uid));
      $usrdata_restrict_by_ip_type = "1";
      $usrdata_restrict_by_ip_address = $usrdata->restrict_by_ip_address;
    }
    $form['#multistep'] = TRUE;
    $form['#redirect'] = FALSE;
    $form['rip'] = array(
      '#type' => 'fieldset',
      '#attributes' => array(
        'class' => 'restrict-by-ip',
      ),
      '#title' => t('Restrict by IP settings'),
      '#weight' => 5,
      '#collapsible' => FALSE,
    );
    $form['rip']['restrict_by_ip_type'] = array(
      '#type' => 'radios',
      '#title' => t('Restrict By IP'),
      '#default_value' => t($usrdata_restrict_by_ip_type),
      '#options' => array(
        t('No'),
        t('Yes'),
      ),
    );
    $form['rip']['restrict_by_ip_address'] = array(
      '#type' => 'textfield',
      '#default_value' => t($usrdata_restrict_by_ip_address),
      '#size' => 128,
      '#maxlength' => 128,
      '#description' => t('Enter IP Address Ranges in CIDR Notation seperated with semi-colons, with no trailing semi-colon. E.G. 10.20.30.0/24;192.168.199.1/32;1.0.0.0/8<br />For more information on CIDR notation <a href="http://www.brassy.net/2007/mar/cidr_basic_subnetting" target="_blank">click here</a>.'),
    );
    return $form;
  }
  else {
    return FALSE;
  }
}

/**
 * Update and insert function
 * Update or create new restrict by ip database entry from the form data
 */
function _restrict_by_ip_update($uid, &$edit) {
  if (user_access('administer site configuration') || user_access('administer restrict by ip')) {
    $form = array();
    if ($edit['restrict_by_ip_type']) {
      if (db_result(db_query('SELECT uid FROM {restrict_by_ip} WHERE uid = %d', $uid))) {
        db_query("UPDATE {restrict_by_ip} SET restrict_by_ip_type = %d, restrict_by_ip_address = '%s' WHERE uid = %d", intval($edit['restrict_by_ip_type']), $edit['restrict_by_ip_address'], $uid);
      }
      else {
        db_query("INSERT INTO {restrict_by_ip} (uid, restrict_by_ip_type, restrict_by_ip_address) VALUES ( %d ,%d ,'%s')", $uid, intval($edit['restrict_by_ip_type']), $edit['restrict_by_ip_address']);
      }
    }
    else {
      db_query("DELETE FROM {restrict_by_ip} WHERE uid=%d", $uid);

      // Attempting here to get the form to delete the ip address data if 'no' to restrict by ip address is selected
      // Not working needs more investigation
      if (isset($form['rip'])) {
        $form['newform'] = array(
          '#type' => 'textfield',
          '#default_value' => t(''),
          '#size' => 128,
          '#maxlength' => 128,
          '#description' => t('Enter IP Address Ranges in CIDR Notation seperated with semi-colons, with no trailing semi-colon. E.G. 10.20.30.0/24;192.168.199.1/32;1.0.0.0/8<br />For more information on CIDR notation <a href="http://www.brassy.net/2007/mar/cidr_basic_subnetting" target="_blank">click here</a>.'),
        );
        $form['rip']['restrict_by_ip_address'] = $form['newform'];
        unset($form['newform']);
      }
    }
    unset($edit['restrict_by_ip_type']);
    unset($edit['restrict_by_ip_address']);
    return TRUE;
  }
  else {
    return FALSE;
  }
}

/**
 * Validate function
 * Validate the restrict by ip form data
 */
function _restrict_by_ip_validate(&$edit, $call) {
  $ret = TRUE;

  // Set up error messages for new user and edit user
  $sms = "Retrict by IP Address setting not updated to user";
  if ($call == 2) {
    $sms = "User not added";
  }

  // Only validate is 'yes' is selected for restrict by ip
  if ($edit['restrict_by_ip_type']) {

    // Seperate the ip address by semi-colon delimiter
    $ret = _restrict_by_ip_validate_ip($edit['restrict_by_ip_address'], $sms);
  }
  if (!$ret) {
    unset($edit['restrict_by_ip_type']);
    unset($edit['restrict_by_ip_address']);
  }
  return $ret;
}

/**
 * User deleted function
 * Remove the restrict by ip data from the database table
 */
function _restrict_by_ip_delete($uid) {
  if ($uid > 1) {
    return db_query("DELETE FROM {restrict_by_ip} WHERE uid=%d", $uid);
  }
  else {
    return FALSE;
  }
}

/**
 * This function just makes sure the user input for the ip address
 * section is valid. $sms is the error message if the ip validation fails
 */
function _restrict_by_ip_validate_ip($ip_address, $sms) {
  $ret = TRUE;
  $ipaddresses = explode(";", $ip_address);
  $j = 1;

  // Check each ip address individually
  foreach ($ipaddresses as $ipaddress) {

    // Seperate in to address and cidr mask
    $cidr = explode("/", $ipaddress);

    // Check address and cidr mask entered
    if (count($cidr) == 2) {
      $ipaddr = explode(".", $cidr[0]);

      // Check four quads entered
      if (count($ipaddr) == 4) {

        // Check each quad is valid - numeric and 0 < value < 255
        for ($i = 0; $i < 4; $i++) {
          if (!is_numeric($ipaddr[$i]) || $ipaddr[$i] < 0 || $ipaddr[$i] > 255) {
            form_set_error('restrict_by_ip_address', t($sms . '. Illegal value for the an IP Address. Each IP Address must be valid. Check IP Address No. ' . $j));
            $ret = FALSE;
          }
        }

        // Check cidr mask value - numeric and 0 < value < 33
        if (!is_numeric($cidr[1]) || $cidr[1] < 1 || $cidr[1] > 32) {
          form_set_error('restrict_by_ip_address', t($sms . '. Illegal value for the CIDR value. Check CIDR No. ' . $j));
          $ret = FALSE;
        }
      }
      else {
        form_set_error('restrict_by_ip_address', t($sms . '. IP Address Incorrect Number of Quads. Check IP Address No. ' . $j));
        $ret = FALSE;
      }
    }
    else {
      form_set_error('restrict_by_ip_address', t($sms . '. IP Address in Incorrect Format. Check IP Address No. ' . $j));
      $ret = FALSE;
    }
    $j++;
  }
  return $ret;
}

/**
 * Check ip address against a network in cidr notation. E.g:
 * _restrict_by_ip_cidrcheck('192.168.10.100','192.168.10.0/24'); returns 1
 * _restrict_by_ip_cidrcheck('192.168.10.100','192.168.12.0/24'); returns 0
 */
function _restrict_by_ip_cidrcheck($iptocheck, $ipslashcidr) {

  // Seperate ip address and cidr mask
  $netmask = explode("/", $ipslashcidr);

  // Get valid network as long
  $ip_net = ip2long($netmask[0]);

  // Get valid network mask as long
  $ip_mask = ~((1 << 32 - $netmask[1]) - 1);

  // Get ip address to check as long
  $ip_ip = ip2long($iptocheck);

  // Mask ip address to check to get subnet
  $ip_ip_net = $ip_ip & $ip_mask;

  // Only returns 1 if the valid network

  //and the subnet of the ip address

  //to check are the same
  return $ip_ip_net == $ip_net;
}

Functions

Namesort descending Description
restrict_by_ip_form_user_admin_perm_alter Hook to the admin_permissions form
restrict_by_ip_help Implementation of hook_help()
restrict_by_ip_menu Implementation of hook_menu() Add a menu item to the ddminister >> site building menu for displaying the restrict_by_ip
restrict_by_ip_perm Implementation of hook_perm()
restrict_by_ip_role_check This just checks the database for any roles associated with that user that are in the restrict_by_ip table. From there it does a ip check on each one of them to see if they are within the range of ip's allowed for that role.
restrict_by_ip_settings Menu callback to configure module settings
restrict_by_ip_user Implementation of hook_user()
restrict_by_ip_user_admin_perm_submit Hook to the admin_permissions submit function
restrict_by_ip_user_admin_perm_validate Hook for the permissions validate function. Checks to make sure the ip-address is valid.
_restrict_by_ip_cidrcheck Check ip address against a network in cidr notation. E.g: _restrict_by_ip_cidrcheck('192.168.10.100','192.168.10.0/24'); returns 1 _restrict_by_ip_cidrcheck('192.168.10.100','192.168.12.0/24'); returns 0
_restrict_by_ip_delete User deleted function Remove the restrict by ip data from the database table
_restrict_by_ip_form Form and register function Insert the restrict by ip form into the user settings and new user forms for authorised users
_restrict_by_ip_login Login function Checks the user's ip address on login If they are not restricted, or logging in from the appropriate address allow logon to continue. If not redirect to a designated page
_restrict_by_ip_update Update and insert function Update or create new restrict by ip database entry from the form data
_restrict_by_ip_validate Validate function Validate the restrict by ip form data
_restrict_by_ip_validate_ip This function just makes sure the user input for the ip address section is valid. $sms is the error message if the ip validation fails