Skip to content

Commit 70148ec

Browse files
author
Till Brehm
committed
Merge branch 'master' into 'master'
API SOAP security fix See merge request !608
2 parents 4cab9fb + f0cae38 commit 70148ec

File tree

1 file changed

+89
-51
lines changed

1 file changed

+89
-51
lines changed

interface/lib/classes/remoting.inc.php

Lines changed: 89 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ public function login($username, $password, $client_login = false)
7171
{
7272
global $app, $conf;
7373

74+
$error = array();
75+
7476
// Maintenance mode
7577
$app->uses('ini_parser,getconf');
7678
$server_config_array = $app->getconf->get_global_config('misc');
@@ -80,70 +82,60 @@ public function login($username, $password, $client_login = false)
8082
}
8183

8284
if(empty($username)) {
83-
throw new SoapFault('login_username_empty', 'The login username is empty.');
84-
return false;
85+
$error = array('faultcode' => 'login_username_empty', 'faultstring' => 'The login username is empty.');
8586
}
8687

8788
if(empty($password)) {
88-
throw new SoapFault('login_password_empty', 'The login password is empty.');
89-
return false;
89+
$error = array('faultcode' => 'login_password_empty', 'faultstring' => 'The login password is empty.');
9090
}
9191

9292
//* Delete old remoting sessions
9393
$sql = "DELETE FROM remote_session WHERE tstamp < UNIX_TIMESTAMP()";
9494
$app->db->query($sql);
9595

96-
if($client_login == true) {
97-
$sql = "SELECT * FROM sys_user WHERE USERNAME = ?";
98-
$user = $app->db->queryOneRecord($sql, $username);
99-
if($user) {
100-
$saved_password = stripslashes($user['passwort']);
96+
$ip = md5($_SERVER['REMOTE_ADDR']);
97+
$sql = "SELECT * FROM `attempts_login` WHERE `ip`= ? AND `login_time` > (NOW() - INTERVAL 1 MINUTE) LIMIT 1";
98+
$alreadyfailed = $app->db->queryOneRecord($sql, $ip);
10199

102-
if(substr($saved_password, 0, 3) == '$1$') {
103-
//* The password is crypt-md5 encrypted
104-
$salt = '$1$'.substr($saved_password, 3, 8).'$';
100+
if($alreadyfailed['times'] > 5) {
101+
throw new SoapFault('error_user_too_many_logins', 'Too many failed logins');
102+
return false;
103+
}
105104

106-
if(crypt(stripslashes($password), $salt) != $saved_password) {
107-
throw new SoapFault('client_login_failed', 'The login failed. Username or password wrong.');
108-
return false;
105+
if (empty($error)) {
106+
107+
if($client_login == true) {
108+
$sql = "SELECT * FROM sys_user WHERE USERNAME = ?";
109+
$user = $app->db->queryOneRecord($sql, $username);
110+
if($user) {
111+
$saved_password = stripslashes($user['passwort']);
112+
113+
if(substr($saved_password, 0, 3) == '$1$') {
114+
//* The password is crypt-md5 encrypted
115+
$salt = '$1$'.substr($saved_password, 3, 8).'$';
116+
117+
if(crypt(stripslashes($password), $salt) != $saved_password) {
118+
$error = array('faultcode' => 'client_login_failed', 'faultstring' => 'The login failed. Username or password wrong.');
119+
}
120+
} else {
121+
//* The password is md5 encrypted
122+
if(md5($password) != $saved_password) {
123+
$error = array('faultcode' => 'client_login_failed', 'faultstring' => 'The login failed. Username or password wrong.');
124+
}
109125
}
110126
} else {
111-
//* The password is md5 encrypted
112-
if(md5($password) != $saved_password) {
113-
throw new SoapFault('client_login_failed', 'The login failed. Username or password wrong.');
114-
return false;
115-
}
127+
$error = array('faultcode' => 'client_login_failed', 'faultstring' => 'The login failed. Username or password wrong.');
128+
}
129+
if($user['active'] != 1) {
130+
$error = array('faultcode' => 'client_login_failed', 'faultstring' => 'The login failed. User is blocked.');
116131
}
117-
} else {
118-
throw new SoapFault('client_login_failed', 'The login failed. Username or password wrong.');
119-
return false;
120-
}
121-
if($user['active'] != 1) {
122-
throw new SoapFault('client_login_failed', 'The login failed. User is blocked.');
123-
return false;
124-
}
125132

126-
// now we need the client data
127-
$client = $app->db->queryOneRecord("SELECT client.can_use_api FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ?", $user['default_group']);
128-
if(!$client || $client['can_use_api'] != 'y') {
129-
throw new SoapFault('client_login_failed', 'The login failed. Client may not use api.');
130-
return false;
131-
}
133+
// now we need the client data
134+
$client = $app->db->queryOneRecord("SELECT client.can_use_api FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ?", $user['default_group']);
135+
if(!$client || $client['can_use_api'] != 'y') {
136+
$error = array('faultcode' => 'client_login_failed', 'faultstring' => 'The login failed. Client may not use api.');
137+
}
132138

133-
//* Create a remote user session
134-
//srand ((double)microtime()*1000000);
135-
$remote_session = md5(mt_rand().uniqid('ispco'));
136-
$remote_userid = $user['userid'];
137-
$remote_functions = '';
138-
$tstamp = time() + $this->session_timeout;
139-
$sql = 'INSERT INTO remote_session (remote_session,remote_userid,remote_functions,client_login,tstamp'
140-
.') VALUES (?, ?, ?, 1, $tstamp)';
141-
$app->db->query($sql, $remote_session,$remote_userid,$remote_functions,$tstamp);
142-
return $remote_session;
143-
} else {
144-
$sql = "SELECT * FROM remote_user WHERE remote_username = ? and remote_password = md5(?)";
145-
$remote_user = $app->db->queryOneRecord($sql, $username, $password);
146-
if($remote_user['remote_userid'] > 0) {
147139
//* Create a remote user session
148140
//srand ((double)microtime()*1000000);
149141
$remote_session = md5(mt_rand().uniqid('ispco'));
@@ -153,11 +145,57 @@ public function login($username, $password, $client_login = false)
153145
$sql = 'INSERT INTO remote_session (remote_session,remote_userid,remote_functions,tstamp'
154146
.') VALUES (?, ?, ?, ?)';
155147
$app->db->query($sql, $remote_session,$remote_userid,$remote_functions,$tstamp);
156-
return $remote_session;
157148
} else {
158-
throw new SoapFault('login_failed', 'The login failed. Username or password wrong.');
149+
$sql = "SELECT * FROM remote_user WHERE remote_username = ? and remote_password = md5(?)";
150+
$remote_user = $app->db->queryOneRecord($sql, $username, $password);
151+
if($remote_user['remote_userid'] > 0) {
152+
//* Create a remote user session
153+
//srand ((double)microtime()*1000000);
154+
$remote_session = md5(mt_rand().uniqid('ispco'));
155+
$remote_userid = $remote_user['remote_userid'];
156+
$remote_functions = $remote_user['remote_functions'];
157+
$tstamp = time() + $this->session_timeout;
158+
$sql = 'INSERT INTO remote_session (remote_session,remote_userid,remote_functions,tstamp'
159+
.') VALUES (?, ?, ?, ?)';
160+
$app->db->query($sql, $remote_session,$remote_userid,$remote_functions,$tstamp);
161+
} else {
162+
$error = array('faultcode' => 'login_failed', 'faultstring' => 'The login failed. Username or password wrong.');
163+
}
164+
}
165+
166+
}
167+
168+
if (! empty($error)) {
169+
if(! $alreadyfailed['times']) {
170+
//* user login the first time wrong
171+
$sql = "INSERT INTO `attempts_login` (`ip`, `times`, `login_time`) VALUES (?, 1, NOW())";
172+
$app->db->query($sql, $ip);
173+
} elseif($alreadyfailed['times'] >= 1) {
174+
//* update times wrong
175+
$sql = "UPDATE `attempts_login` SET `times`=`times`+1, `login_time`=NOW() WHERE `ip` = ? AND `login_time` < NOW() ORDER BY `login_time` DESC LIMIT 1";
176+
$app->db->query($sql, $ip);
177+
}
178+
179+
$authlog = 'Failed login for user \''. $username .'\' from '. $_SERVER['REMOTE_ADDR'] .' at '. date('Y-m-d H:i:s') . ' (api)';
180+
$authlog_handle = fopen($conf['ispconfig_log_dir'].'/auth.log', 'a');
181+
fwrite($authlog_handle, $authlog ."\n");
182+
fclose($authlog_handle);
183+
184+
throw new SoapFault($error['faultcode'], $error['faultstring']);
159185
return false;
186+
} else {
187+
// User login right, so attempts can be deleted
188+
$sql = "DELETE FROM `attempts_login` WHERE `ip`=?";
189+
$app->db->query($sql, $ip);
190+
191+
$authlog = 'Successful login for user \''. $username .'\' from '. $_SERVER['REMOTE_ADDR'] .' at '. date('Y-m-d H:i:s') . ' (api)';
192+
$authlog_handle = fopen($conf['ispconfig_log_dir'].'/auth.log', 'a');
193+
fwrite($authlog_handle, $authlog ."\n");
194+
fclose($authlog_handle);
160195
}
196+
197+
if (isset($remote_session)) {
198+
return $remote_session;
161199
}
162200

163201
}
@@ -552,4 +590,4 @@ public function get_function_list($session_id)
552590

553591
}
554592

555-
?>
593+
?>

0 commit comments

Comments
 (0)