Skip to content

Commit d6ac29b

Browse files
author
Florian Schaal
committed
Option to limit access for remote-user to specified IP(s) / hostname(s) (#4881)
1 parent d8f1b94 commit d6ac29b

File tree

8 files changed

+131
-0
lines changed

8 files changed

+131
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
ALTER TABLE `web_domain` ADD COLUMN `ssl_letsencrypt_exclude` enum('n','y') NOT NULL DEFAULT 'n' AFTER `ssl_letsencrypt`;
2+
ALTER TABLE `remote_user` ADD `remote_access` ENUM('y','n') NOT NULL DEFAULT 'y' AFTER `remote_password`;
3+
ALTER TABLE `remote_user` ADD `remote_ips` TEXT AFTER `remote_access`;

install/sql/ispconfig3.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,8 @@ CREATE TABLE `remote_user` (
12461246
`sys_perm_other` varchar(5) default NULL,
12471247
`remote_username` varchar(64) NOT NULL DEFAULT '',
12481248
`remote_password` varchar(64) NOT NULL DEFAULT '',
1249+
`remote_access` enum('y','n') NOT NULL DEFAULT 'y',
1250+
`remote_ips` TEXT,
12491251
`remote_functions` text,
12501252
PRIMARY KEY (`remote_userid`)
12511253
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

interface/lib/classes/remoting.inc.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,41 @@ public function login($username, $password, $client_login = false)
144144
$sql = "SELECT * FROM remote_user WHERE remote_username = ? and remote_password = md5(?)";
145145
$remote_user = $app->db->queryOneRecord($sql, $username, $password);
146146
if($remote_user['remote_userid'] > 0) {
147+
$allowed_ips = explode(',',$remote_user['remote_ips']);
148+
foreach($allowed_ips as $i => $allowed) {
149+
if(!filter_var($allowed, FILTER_VALIDATE_IP)) {
150+
// get the ip for a hostname
151+
unset($allowed_ips[$i]);
152+
$temp=dns_get_record($allowed, DNS_A+DNS_AAAA);
153+
foreach($temp as $t) {
154+
if(isset($t['ip'])) $allowed_ips[] = $t['ip'];
155+
if(isset($t['ipv6'])) $allowed_ips[] = $t['ipv6'];
156+
}
157+
unset($temp);
158+
}
159+
}
160+
$allowed_ips[] = '127.0.0.1';
161+
$allowed_ips[] = '::1';
162+
$allowed_ips=array_unique($allowed_ips);
163+
$ip = $_SERVER['REMOTE_ADDR'];
164+
$remote_allowed = @($ip == '::1' || $ip == '127.0.0.1')?true:false;
165+
if(!$remote_allowed && $remote_user['remote_access'] == 'y') {
166+
if(trim($remote_user['remote_ips']) == '') {
167+
$remote_allowed=true;
168+
} else {
169+
$ip = inet_pton($_SERVER['REMOTE_ADDR']);
170+
foreach($allowed_ips as $allowed) {
171+
if($ip == inet_pton(trim($allowed))) {
172+
$remote_allowed=true;
173+
break;
174+
}
175+
}
176+
}
177+
}
178+
if(!$remote_allowed) {
179+
throw new SoapFault('login_failed', 'The login is not allowed from '.$_SERVER['REMOTE_ADDR']);
180+
return false;
181+
}
147182
//* Create a remote user session
148183
//srand ((double)microtime()*1000000);
149184
$remote_session = md5(mt_rand().uniqid('ispco'));
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
/*
4+
Copyright (c) 2017, Florian Schaal , schaal @it UG
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without modification,
8+
are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice,
11+
this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
* Neither the name of ISPConfig nor the names of its contributors
16+
may be used to endorse or promote products derived from this software without
17+
specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
class validate_remote_user {
32+
33+
function valid_remote_ip($field_name, $field_value, $validator) {
34+
global $app;
35+
36+
$values = explode(',', $field_value);
37+
$regex = '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/';
38+
foreach($values as $cur_value) {
39+
$cur_value = trim($cur_value);
40+
$valid = true;
41+
if(function_exists('filter_var')) {
42+
if(!filter_var($cur_value, FILTER_VALIDATE_IP)) {
43+
$valid = false;
44+
if(preg_match($regex, $cur_value)) $valid = true;
45+
}
46+
} else return "function filter_var missing <br />\r\n";
47+
48+
if($valid == false) {
49+
$errmsg = $validator['errmsg'];
50+
if(isset($app->tform->wordbook[$errmsg])) {
51+
return $app->tform->wordbook[$errmsg]."<br>\r\n";
52+
} else {
53+
return $errmsg."<br>\r\n";
54+
}
55+
}
56+
}
57+
}
58+
59+
}

interface/web/admin/form/remote_user.tform.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,27 @@
115115
'width' => '30',
116116
'maxlength' => '255'
117117
),
118+
'remote_access' => array (
119+
'datatype' => 'VARCHAR',
120+
'formtype' => 'CHECKBOX',
121+
'default' => 'n',
122+
'value' => array(0 => 'n', 1 => 'y')
123+
),
124+
'remote_ips' => array (
125+
'datatype' => 'TEXT',
126+
'formtype' => 'TEXT',
127+
'validators' => array (
128+
0 => array (
129+
'type' => 'CUSTOM',
130+
'class' => 'validate_remote_user',
131+
'function' => 'valid_remote_ip',
132+
'errmsg' => 'remote_user_error_ips'),
133+
),
134+
'default' => '',
135+
'value' => '',
136+
'width' => '60',
137+
'searchable' => 2
138+
),
118139
'remote_functions' => array (
119140
'datatype' => 'TEXT',
120141
'formtype' => 'CHECKBOXARRAY',

interface/web/admin/lib/lang/de_remote_user.lng

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,7 @@ $wb['generate_password_txt'] = 'Passwort erzeugen';
4444
$wb['repeat_password_txt'] = 'Passwort wiederholen';
4545
$wb['password_mismatch_txt'] = 'Die Passwörter stimmen nicht überein.';
4646
$wb['password_match_txt'] = 'Die Passwörter stimmen überein.';
47+
$wb['remote_user_error_ips'] = 'Mindestens eine eingegebene IP-Adresse oder ein Hostname ist ungueltig.';
48+
$wb['remote_access_txt'] = 'Entfernter Zugriff';
49+
$wb['remote_ips_txt'] = 'Entfernter Zugriff IP / Hostname (Mehrere mit Komma trennen, keine Angabe für <i>alle</i>)';
4750
?>

interface/web/admin/lib/lang/en_remote_user.lng

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,7 @@ $wb['generate_password_txt'] = 'Generate Password';
4444
$wb['repeat_password_txt'] = 'Repeat Password';
4545
$wb['password_mismatch_txt'] = 'The passwords do not match.';
4646
$wb['password_match_txt'] = 'The passwords do match.';
47+
$wb['remote_access_txt'] = 'Remote Access';
48+
$wb['remote_ips_txt'] = 'Remote Access IPs / Hostnames (separate by , and leave blank for <i>any</i>)';
49+
$wb['remote_user_error_ips'] = 'At least one of the entered ip addresses or hostnames is invalid.';
4750
?>

interface/web/admin/templates/remote_user_edit.htm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ <h1><tmpl_var name="list_head_txt"></h1>
3636
<div id="confirmpasswordOK" style="display:none;" class="confirmpasswordok">{tmpl_var name='password_match_txt'}</div>
3737
</div>
3838
</div>
39+
<div class="form-group">
40+
<label class="col-sm-3 control-label">{tmpl_var name='remote_access_txt'}</label>
41+
<div class="col-sm-9">{tmpl_var name='remote_access'}</div></div>
42+
<div class="form-group">
43+
<label for="remote_ips" class="col-sm-3 control-label">{tmpl_var name='remote_ips_txt'}</label>
44+
<div class="col-sm-9"><input type="text" name="remote_ips" id="remote_ips" value="{tmpl_var name='remote_ips'}" class="form-control" /></div></div>
3945
<div class="form-group">
4046
<label class="col-sm-3 control-label">{tmpl_var name='function_txt'}</label>
4147
<div class="col-sm-9">

0 commit comments

Comments
 (0)