| 1 |
<?php
|
| 2 |
// $Id: restrict_by_ip.module,v 1.13 2009/03/25 01:45:28 peligrorice Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Allows the admin to select which ip addresses a user can login from for this site
|
| 7 |
* Some of the code below is taken from the cck_ipaddress_module
|
| 8 |
*/
|
| 9 |
|
| 10 |
/**
|
| 11 |
* Implementation of hook_help()
|
| 12 |
*/
|
| 13 |
function restrict_by_ip_help($section) {
|
| 14 |
switch ($section) {
|
| 15 |
case 'admin/help#restrict_by_ip':
|
| 16 |
$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>';
|
| 17 |
break;
|
| 18 |
}
|
| 19 |
return $output;
|
| 20 |
}
|
| 21 |
|
| 22 |
/**
|
| 23 |
* Implementation of hook_menu()
|
| 24 |
* Add a menu item to the ddminister >> site building menu for displaying the restrict_by_ip
|
| 25 |
*/
|
| 26 |
function restrict_by_ip_menu() {
|
| 27 |
$items = array();
|
| 28 |
$items['admin/settings/restrict_by_ip'] = array(
|
| 29 |
'title' => t('Restrict by IP settings'),
|
| 30 |
'description' => t('Limit the IP address a user is allowed to login from.'),
|
| 31 |
'page callback' => 'drupal_get_form',
|
| 32 |
'page arguments' => array('restrict_by_ip_settings'),
|
| 33 |
'access arguments' => array('administer restrict by ip'),
|
| 34 |
);
|
| 35 |
return $items;
|
| 36 |
}
|
| 37 |
|
| 38 |
/**
|
| 39 |
* Implementation of hook_perm()
|
| 40 |
*/
|
| 41 |
function restrict_by_ip_perm() {
|
| 42 |
return array('administer restrict by ip');
|
| 43 |
}
|
| 44 |
|
| 45 |
/**
|
| 46 |
* Menu callback to configure module settings
|
| 47 |
*/
|
| 48 |
function restrict_by_ip_settings() {
|
| 49 |
$form = array();
|
| 50 |
$form['restrict_by_ip_error_page'] = array(
|
| 51 |
'#type' => 'textfield',
|
| 52 |
'#title' => t('Login denied page'),
|
| 53 |
'#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"),
|
| 54 |
'#weight' => -5,
|
| 55 |
'#default_value' => variable_get('restrict_by_ip_error_page', ''),
|
| 56 |
'#required' => TRUE,
|
| 57 |
);
|
| 58 |
return system_settings_form($form);
|
| 59 |
}
|
| 60 |
|
| 61 |
/**
|
| 62 |
* Implementation of hook_user()
|
| 63 |
*/
|
| 64 |
function restrict_by_ip_user($type, &$edit, &$account, $category = NULL) {
|
| 65 |
global $user;
|
| 66 |
switch ($type) {
|
| 67 |
case 'login':
|
| 68 |
return _restrict_by_ip_login($user);
|
| 69 |
break;
|
| 70 |
case 'form':
|
| 71 |
case 'register':
|
| 72 |
return _restrict_by_ip_form($account->uid);
|
| 73 |
break;
|
| 74 |
case 'insert':
|
| 75 |
case 'update':
|
| 76 |
return _restrict_by_ip_update($account->uid, $edit);
|
| 77 |
break;
|
| 78 |
case 'submit': //Drupal Bug: http://drupal.org/node/321787 - using for edit user will still update user data if error
|
| 79 |
return _restrict_by_ip_validate($edit, 1);
|
| 80 |
break;
|
| 81 |
case 'validate': //Drupal Bug: http://drupal.org/node/321787 - not fired when editing user only on new user
|
| 82 |
return _restrict_by_ip_validate($edit, 2);
|
| 83 |
break;
|
| 84 |
case 'delete':
|
| 85 |
return _restrict_by_ip_delete($account->uid);
|
| 86 |
break;
|
| 87 |
}
|
| 88 |
}
|
| 89 |
|
| 90 |
/**
|
| 91 |
* Login function
|
| 92 |
* Checks the user's ip address on login
|
| 93 |
* If they are not restricted, or logging in from the appropriate address
|
| 94 |
* allow logon to continue. If not redirect to a designated page
|
| 95 |
*/
|
| 96 |
function _restrict_by_ip_login(&$user) {
|
| 97 |
if ($user -> uid > 1) {
|
| 98 |
$usrdata = db_fetch_object(db_query('SELECT * FROM {restrict_by_ip} WHERE uid = %d', $user->uid));
|
| 99 |
$logonvalid = FALSE;
|
| 100 |
$ip2check = $_SERVER['REMOTE_ADDR'];
|
| 101 |
// If the user has restrict by ip address set
|
| 102 |
if ($usrdata->restrict_by_ip_type) {
|
| 103 |
$ipaddresses = explode(";", $usrdata->restrict_by_ip_address);
|
| 104 |
// Check each valid ip address in database against users ip address
|
| 105 |
// If one matches allow logon
|
| 106 |
foreach ($ipaddresses as $ipaddress) {
|
| 107 |
if (_restrict_by_ip_cidrcheck($ip2check, $ipaddress)) {
|
| 108 |
$logonvalid = TRUE;
|
| 109 |
}
|
| 110 |
}
|
| 111 |
// Restrict by ip address is set and no addresses match users ip address
|
| 112 |
if (!$logonvalid) {
|
| 113 |
// Log the error with the ip address
|
| 114 |
watchdog('user', t('Session closed for %name - Invalid IP. '.$ip2check, array('%name' => $user->name)));
|
| 115 |
// Destroy the current session
|
| 116 |
session_destroy();
|
| 117 |
module_invoke_all('user', 'logout', NULL, $user);
|
| 118 |
// Load the anonymous user
|
| 119 |
$user = drupal_anonymous_user();
|
| 120 |
// unset destination required to force them to the ip page during drupal_goto()
|
| 121 |
if (isset($_REQUEST['destination'])) {
|
| 122 |
unset($_REQUEST['destination']);
|
| 123 |
}
|
| 124 |
// Goto the page detailed in the site configuration - restrict by ip - settings page
|
| 125 |
drupal_goto(variable_get('restrict_by_ip_error_page', '0'));
|
| 126 |
}
|
| 127 |
}
|
| 128 |
return $logonvalid;
|
| 129 |
}
|
| 130 |
else{
|
| 131 |
return TRUE;
|
| 132 |
}
|
| 133 |
}
|
| 134 |
|
| 135 |
/**
|
| 136 |
* Form and register function
|
| 137 |
* Insert the restrict by ip form into the user settings and new user forms for authorised users
|
| 138 |
*/
|
| 139 |
function _restrict_by_ip_form($uid) {
|
| 140 |
if (user_access('administer site configuration') || user_access('administer restrict by ip')) {
|
| 141 |
$form = array();
|
| 142 |
drupal_add_css(drupal_get_path('module', 'restrict_by_ip').'/restrict_by_ip.css', 'module', 'screen', FALSE);
|
| 143 |
$usrdata_restrict_by_ip_type = "0";
|
| 144 |
$usrdata_restrict_by_ip_address = "";
|
| 145 |
// Grab the current restrict by ip data if it exists
|
| 146 |
$found=db_result(db_query('SELECT count(*) FROM {restrict_by_ip} WHERE uid = %d', $uid));
|
| 147 |
if($found) {
|
| 148 |
$usrdata = db_fetch_object(db_query('SELECT * FROM {restrict_by_ip} WHERE uid = %d', $uid));
|
| 149 |
$usrdata_restrict_by_ip_type = "1";
|
| 150 |
$usrdata_restrict_by_ip_address = $usrdata->restrict_by_ip_address;
|
| 151 |
}
|
| 152 |
$form['#multistep'] = TRUE;
|
| 153 |
$form['#redirect'] = FALSE;
|
| 154 |
$form['rip'] = array(
|
| 155 |
'#type' => 'fieldset',
|
| 156 |
'#attributes' => array('class' => 'restrict-by-ip'),
|
| 157 |
'#title' => t('Restrict by IP settings'),
|
| 158 |
'#weight' => 5,
|
| 159 |
'#collapsible' => FALSE,
|
| 160 |
);
|
| 161 |
$form['rip']['restrict_by_ip_type'] = array(
|
| 162 |
'#type' => 'radios',
|
| 163 |
'#title' => t('Restrict By IP'),
|
| 164 |
'#default_value' => t($usrdata_restrict_by_ip_type),
|
| 165 |
'#options' => array(t('No'), t('Yes')),
|
| 166 |
);
|
| 167 |
$form['rip']['restrict_by_ip_address'] = array(
|
| 168 |
'#type' => 'textfield',
|
| 169 |
'#default_value' => t($usrdata_restrict_by_ip_address),
|
| 170 |
'#size' => 128,
|
| 171 |
'#maxlength' => 128,
|
| 172 |
'#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>.'),
|
| 173 |
);
|
| 174 |
return $form;
|
| 175 |
}
|
| 176 |
else {
|
| 177 |
return FALSE;
|
| 178 |
}
|
| 179 |
}
|
| 180 |
|
| 181 |
/**
|
| 182 |
* Update and insert function
|
| 183 |
* Update or create new restrict by ip database entry from the form data
|
| 184 |
*/
|
| 185 |
function _restrict_by_ip_update($uid, &$edit) {
|
| 186 |
if (user_access('administer site configuration') || user_access('administer restrict by ip')) {
|
| 187 |
$form = array();
|
| 188 |
if ($edit['restrict_by_ip_type']) {
|
| 189 |
if (db_result(db_query('SELECT uid FROM {restrict_by_ip} WHERE uid = %d', $uid))) {
|
| 190 |
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);
|
| 191 |
}
|
| 192 |
else {
|
| 193 |
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']);
|
| 194 |
}
|
| 195 |
}
|
| 196 |
else {
|
| 197 |
db_query("DELETE FROM {restrict_by_ip} WHERE uid=%d", $uid);
|
| 198 |
// Attempting here to get the form to delete the ip address data if 'no' to restrict by ip address is selected
|
| 199 |
// Not working needs more investigation
|
| 200 |
if (isset($form['rip'])) {
|
| 201 |
$form['newform'] = array(
|
| 202 |
'#type' => 'textfield',
|
| 203 |
'#default_value' => t(''),
|
| 204 |
'#size' => 128,
|
| 205 |
'#maxlength' => 128,
|
| 206 |
'#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>.'),
|
| 207 |
);
|
| 208 |
$form['rip']['restrict_by_ip_address'] = $form['newform'];
|
| 209 |
unset($form['newform']);
|
| 210 |
}
|
| 211 |
}
|
| 212 |
unset($edit['restrict_by_ip_type']);
|
| 213 |
unset($edit['restrict_by_ip_address']);
|
| 214 |
return TRUE;
|
| 215 |
}
|
| 216 |
else {
|
| 217 |
return FALSE;
|
| 218 |
}
|
| 219 |
}
|
| 220 |
|
| 221 |
/**
|
| 222 |
* Validate function
|
| 223 |
* Validate the restrict by ip form data
|
| 224 |
*/
|
| 225 |
function _restrict_by_ip_validate(&$edit , $call) {
|
| 226 |
$ret = TRUE;
|
| 227 |
// Set up error messages for new user and edit user
|
| 228 |
$sms = "Retrict by IP Address setting not updated";
|
| 229 |
if ($call == 2) {
|
| 230 |
$sms = "User not added";
|
| 231 |
}
|
| 232 |
// Only validate is 'yes' is selected for restrict by ip
|
| 233 |
if ($edit['restrict_by_ip_type']) {
|
| 234 |
// Seperate the ip address by semi-colon delimiter
|
| 235 |
$ipaddresses = explode(";", $edit['restrict_by_ip_address']);
|
| 236 |
$j = 1;
|
| 237 |
// Check each ip address individually
|
| 238 |
foreach ($ipaddresses as $ipaddress) {
|
| 239 |
// Seperate in to address and cidr mask
|
| 240 |
$cidr = explode("/", $ipaddress);
|
| 241 |
// Check address and cidr mask entered
|
| 242 |
if (count($cidr) == 2) {
|
| 243 |
$ipaddr = explode(".", $cidr[0]);
|
| 244 |
// Check four quads entered
|
| 245 |
if (count($ipaddr) == 4) {
|
| 246 |
// Check each quad is valid - numeric and 0 < value < 255
|
| 247 |
for ($i=0; $i<4; $i++) {
|
| 248 |
if ((!is_numeric($ipaddr[$i])) || ($ipaddr[$i] < 0) || ($ipaddr[$i] > 255)) {
|
| 249 |
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));
|
| 250 |
$ret = FALSE;
|
| 251 |
}
|
| 252 |
}
|
| 253 |
// Check cidr mask value - numeric and 0 < value < 33
|
| 254 |
if((!is_numeric($cidr[1])) || ($cidr[1]<1) || ($cidr[1]>32)) {
|
| 255 |
form_set_error('restrict_by_ip_address', t($sms.'. Illegal value for the CIDR value. Check CIDR No. '.$j));
|
| 256 |
$ret = FALSE;
|
| 257 |
}
|
| 258 |
}
|
| 259 |
else {
|
| 260 |
form_set_error('restrict_by_ip_address', t($sms.'. IP Address Incorrect Number of Quads. Check IP Address No. '.$j));
|
| 261 |
$ret = FALSE;
|
| 262 |
}
|
| 263 |
}
|
| 264 |
else {
|
| 265 |
form_set_error('restrict_by_ip_address', t($sms.'. IP Address in Incorrect Format. Check IP Address No. '.$j));
|
| 266 |
$ret = FALSE;
|
| 267 |
}
|
| 268 |
$j++;
|
| 269 |
}
|
| 270 |
}
|
| 271 |
if (!$ret) {
|
| 272 |
unset($edit['restrict_by_ip_type']);
|
| 273 |
unset($edit['restrict_by_ip_address']);
|
| 274 |
}
|
| 275 |
return $ret;
|
| 276 |
}
|
| 277 |
|
| 278 |
/**
|
| 279 |
* User deleted function
|
| 280 |
* Remove the restrict by ip data from the database table
|
| 281 |
*/
|
| 282 |
function _restrict_by_ip_delete($uid) {
|
| 283 |
if ($uid > 1) {
|
| 284 |
return db_query("DELETE FROM {restrict_by_ip} WHERE uid=%d", $uid);
|
| 285 |
}
|
| 286 |
else {
|
| 287 |
return FALSE;
|
| 288 |
}
|
| 289 |
}
|
| 290 |
|
| 291 |
/**
|
| 292 |
* Check ip address against a network in cidr notation. E.g:
|
| 293 |
* _restrict_by_ip_cidrcheck('192.168.10.100','192.168.10.0/24'); returns 1
|
| 294 |
* _restrict_by_ip_cidrcheck('192.168.10.100','192.168.12.0/24'); returns 0
|
| 295 |
*/
|
| 296 |
function _restrict_by_ip_cidrcheck($iptocheck, $ipslashcidr) {
|
| 297 |
// Seperate ip address and cidr mask
|
| 298 |
$netmask = explode("/", $ipslashcidr);
|
| 299 |
// Get valid network as long
|
| 300 |
$ip_net = ip2long($netmask[0]);
|
| 301 |
// Get valid network mask as long
|
| 302 |
$ip_mask = ~((1 << (32 - $netmask[1])) - 1);
|
| 303 |
// Get ip address to check as long
|
| 304 |
$ip_ip = ip2long($iptocheck);
|
| 305 |
// Mask ip address to check to get subnet
|
| 306 |
$ip_ip_net = $ip_ip & $ip_mask;
|
| 307 |
// Only returns 1 if the valid network
|
| 308 |
//and the subnet of the ip address
|
| 309 |
//to check are the same
|
| 310 |
return ($ip_ip_net == $ip_net);
|
| 311 |
}
|