Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Network
KIO Extras
Commits
fd9bd198
Commit
fd9bd198
authored
Oct 08, 2021
by
Harald Sitter
🏳️🌈
Browse files
sftp: bump libssh requirement to at least 0.8.3
even that is very generous. it's 0.8.3 has been out for more than 3 years
parent
fba3079e
Changes
2
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
fd9bd198
...
...
@@ -98,7 +98,7 @@ if(NOT WIN32)
)
endif
()
find_package
(
libssh 0.
7.0
MODULE
)
find_package
(
libssh 0.
8.3
MODULE
)
set_package_properties
(
libssh PROPERTIES DESCRIPTION
"the SSH library with SFTP support"
URL
"https://www.libssh.org/"
TYPE OPTIONAL
...
...
sftp/kio_sftp.cpp
View file @
fd9bd198
...
...
@@ -595,14 +595,12 @@ Result SFTPInternal::sftpOpenConnection(const AuthInfo &info)
return
Result
::
fail
(
KIO
::
ERR_INTERNAL
,
i18n
(
"Could not set a timeout."
));
}
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 8, 0)
// Disable Nagle's Algorithm (TCP_NODELAY). Usually faster for sftp.
bool
nodelay
=
true
;
rc
=
ssh_options_set
(
mSession
,
SSH_OPTIONS_NODELAY
,
&
nodelay
);
if
(
rc
<
0
)
{
return
Result
::
fail
(
KIO
::
ERR_INTERNAL
,
i18n
(
"Could not disable Nagle's Algorithm."
));
}
#endif // 0.8.0
// Don't use any compression
rc
=
ssh_options_set
(
mSession
,
SSH_OPTIONS_COMPRESSION_C_S
,
"none"
);
...
...
@@ -669,7 +667,6 @@ Result SFTPInternal::sftpOpenConnection(const AuthInfo &info)
return
Result
::
pass
();
}
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 8, 3)
Result
SFTPInternal
::
openConnection
()
{
if
(
mConnected
)
{
...
...
@@ -987,301 +984,6 @@ Result SFTPInternal::openConnection()
return
Result
::
pass
();
}
#else // < 0.8.0
Result
SFTPInternal
::
openConnection
()
{
if
(
mConnected
)
{
return
Result
::
pass
();
}
if
(
mHost
.
isEmpty
())
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"openConnection(): Need hostname..."
;
return
Result
::
fail
(
KIO
::
ERR_UNKNOWN_HOST
);
}
AuthInfo
info
;
info
.
url
.
setScheme
(
"sftp"
);
info
.
url
.
setHost
(
mHost
);
if
(
mPort
>
0
&&
mPort
!=
DEFAULT_SFTP_PORT
)
{
info
.
url
.
setPort
(
mPort
);
}
info
.
url
.
setUserName
(
mUsername
);
info
.
username
=
mUsername
;
// Check for cached authentication info if no password is specified...
if
(
mPassword
.
isEmpty
())
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"checking cache: info.username ="
<<
info
.
username
<<
", info.url ="
<<
info
.
url
.
toDisplayString
();
q
->
checkCachedAuthentication
(
info
);
}
else
{
info
.
password
=
mPassword
;
}
// Start the ssh connection.
QString
msg
;
// msg for dialog box
QString
caption
;
// dialog box caption
unsigned
char
*
hash
=
nullptr
;
// the server hash
ssh_key
srv_pubkey
;
char
*
hexa
;
size_t
hlen
;
int
rc
,
state
;
// Attempt to start a ssh session and establish a connection with the server.
const
auto
openResult
=
sftpOpenConnection
(
info
);
if
(
!
openResult
.
success
)
{
return
openResult
;
}
qCDebug
(
KIO_SFTP_LOG
)
<<
"Getting the SSH server hash"
;
/* get the hash */
rc
=
ssh_get_publickey
(
mSession
,
&
srv_pubkey
);
if
(
rc
<
0
)
{
const
auto
result
=
Result
::
fail
(
KIO
::
ERR_SLAVE_DEFINED
,
QString
::
fromUtf8
(
ssh_get_error
(
mSession
)));
closeConnection
();
return
result
;
}
rc
=
ssh_get_publickey_hash
(
srv_pubkey
,
SSH_PUBLICKEY_HASH_SHA1
,
&
hash
,
&
hlen
);
ssh_key_free
(
srv_pubkey
);
if
(
rc
<
0
)
{
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_SLAVE_DEFINED
,
i18n
(
"Could not create hash from server public key"
));
}
qCDebug
(
KIO_SFTP_LOG
)
<<
"Checking if the SSH server is known"
;
/* check the server public key hash */
state
=
ssh_is_server_known
(
mSession
);
switch
(
state
)
{
case
SSH_SERVER_KNOWN_OK
:
break
;
case
SSH_SERVER_FOUND_OTHER
:
{
ssh_string_free_char
((
char
*
)
hash
);
const
QString
errorString
=
i18n
(
"The host key for this server was "
"not found, but another type of key exists.
\n
"
"An attacker might change the default server key to confuse your "
"client into thinking the key does not exist.
\n
"
"Please contact your system administrator.
\n
%1"
,
QString
::
fromUtf8
(
ssh_get_error
(
mSession
)));
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_SLAVE_DEFINED
,
errorString
);
}
case
SSH_SERVER_KNOWN_CHANGED
:
{
hexa
=
ssh_get_hexa
(
hash
,
hlen
);
ssh_string_free_char
((
char
*
)
hash
);
/* TODO print known_hosts file, port? */
const
QString
errorString
=
i18n
(
"The host key for the server %1 has changed.
\n
"
"This could either mean that DNS SPOOFING is happening or the IP "
"address for the host and its host key have changed at the same time.
\n
"
"The fingerprint for the key sent by the remote host is:
\n
%2
\n
"
"Please contact your system administrator.
\n
%3"
,
mHost
,
QString
::
fromUtf8
(
hexa
),
QString
::
fromUtf8
(
ssh_get_error
(
mSession
)));
ssh_string_free_char
(
hexa
);
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_SLAVE_DEFINED
,
errorString
);
}
case
SSH_SERVER_FILE_NOT_FOUND
:
case
SSH_SERVER_NOT_KNOWN
:
{
hexa
=
ssh_get_hexa
(
hash
,
hlen
);
ssh_string_free_char
((
char
*
)
hash
);
caption
=
i18n
(
"Warning: Cannot verify host's identity."
);
msg
=
i18n
(
"The authenticity of host %1 cannot be established.
\n
"
"The key fingerprint is: %2
\n
"
"Are you sure you want to continue connecting?"
,
mHost
,
hexa
);
ssh_string_free_char
(
hexa
);
if
(
KMessageBox
::
Yes
!=
q
->
messageBox
(
SlaveBase
::
WarningYesNo
,
msg
,
caption
))
{
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_USER_CANCELED
);
}
/* write the known_hosts file */
qCDebug
(
KIO_SFTP_LOG
)
<<
"Adding server to known_hosts file."
;
if
(
ssh_write_knownhost
(
mSession
)
<
0
)
{
const
QString
errorString
=
QString
::
fromUtf8
(
ssh_get_error
(
mSession
));
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_USER_CANCELED
,
errorString
);
}
break
;
}
case
SSH_SERVER_ERROR
:
ssh_string_free_char
((
char
*
)
hash
);
return
Result
::
fail
(
KIO
::
ERR_SLAVE_DEFINED
,
QString
::
fromUtf8
(
ssh_get_error
(
mSession
)));
}
qCDebug
(
KIO_SFTP_LOG
)
<<
"Trying to authenticate with the server"
;
// Try to login without authentication
rc
=
ssh_userauth_none
(
mSession
,
nullptr
);
if
(
rc
==
SSH_AUTH_ERROR
)
{
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Authentication failed."
));
}
// This NEEDS to be called after ssh_userauth_none() !!!
int
method
=
ssh_auth_list
(
mSession
);
if
(
rc
!=
SSH_AUTH_SUCCESS
&&
method
==
0
)
{
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Authentication failed. The server "
"didn't send any authentication methods"
));
}
// Try to authenticate with public key first
if
(
rc
!=
SSH_AUTH_SUCCESS
&&
(
method
&
SSH_AUTH_METHOD_PUBLICKEY
))
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Trying to authenticate with public key"
;
for
(;;)
{
rc
=
ssh_userauth_publickey_auto
(
mSession
,
nullptr
,
nullptr
);
if
(
rc
==
SSH_AUTH_ERROR
)
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Public key authentication failed:"
<<
QString
::
fromUtf8
(
ssh_get_error
(
mSession
));
closeConnection
();
clearPubKeyAuthInfo
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Authentication failed."
));
}
else
if
(
rc
!=
SSH_AUTH_DENIED
||
!
mPublicKeyAuthInfo
||
!
mPublicKeyAuthInfo
->
isModified
())
{
clearPubKeyAuthInfo
();
break
;
}
}
}
// Try to authenticate with GSSAPI
if
(
rc
!=
SSH_AUTH_SUCCESS
&&
(
method
&
SSH_AUTH_METHOD_GSSAPI_MIC
))
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Trying to authenticate with GSSAPI"
;
rc
=
ssh_userauth_gssapi
(
mSession
);
if
(
rc
==
SSH_AUTH_ERROR
)
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Public key authentication failed:"
<<
QString
::
fromUtf8
(
ssh_get_error
(
mSession
));
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Authentication failed."
));
}
}
// Try to authenticate with keyboard interactive
if
(
rc
!=
SSH_AUTH_SUCCESS
&&
(
method
&
SSH_AUTH_METHOD_INTERACTIVE
))
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Trying to authenticate with keyboard interactive"
;
AuthInfo
info2
(
info
);
rc
=
authenticateKeyboardInteractive
(
info2
);
if
(
rc
==
SSH_AUTH_SUCCESS
)
{
info
=
info2
;
}
else
if
(
rc
==
SSH_AUTH_ERROR
)
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Keyboard interactive authentication failed:"
<<
QString
::
fromUtf8
(
ssh_get_error
(
mSession
));
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Authentication failed."
));
}
}
// Try to authenticate with password
if
(
rc
!=
SSH_AUTH_SUCCESS
&&
(
method
&
SSH_AUTH_METHOD_PASSWORD
))
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Trying to authenticate with password"
;
info
.
caption
=
i18n
(
"SFTP Login"
);
info
.
prompt
=
i18n
(
"Please enter your username and password."
);
info
.
comment
=
info
.
url
.
url
();
info
.
commentLabel
=
i18n
(
"Site:"
);
bool
isFirstLoginAttempt
=
true
;
for
(;;)
{
if
(
!
isFirstLoginAttempt
||
info
.
password
.
isEmpty
())
{
info
.
keepPassword
=
true
;
// make the "keep Password" check box visible to the user.
info
.
setModified
(
false
);
QString
username
(
info
.
username
);
const
QString
errMsg
(
isFirstLoginAttempt
?
QString
()
:
i18n
(
"Incorrect username or password"
));
qCDebug
(
KIO_SFTP_LOG
)
<<
"Username:"
<<
username
<<
"first attempt?"
<<
isFirstLoginAttempt
<<
"error:"
<<
errMsg
;
// Handle user canceled or dialog failed to open...
int
errCode
=
q
->
openPasswordDialogV2
(
info
,
errMsg
);
if
(
errCode
!=
KJob
::
NoError
)
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"User canceled password/retry dialog"
;
closeConnection
();
return
Result
::
fail
(
errCode
);
}
// If the user name changes, we have to restablish connection again
// since the user name must always be set before calling ssh_connect.
if
(
wasUsernameChanged
(
username
,
info
))
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Username changed to"
<<
info
.
username
;
if
(
!
info
.
url
.
userName
().
isEmpty
())
{
info
.
url
.
setUserName
(
info
.
username
);
}
closeConnection
();
const
auto
result
=
sftpOpenConnection
(
info
);
if
(
!
result
.
success
)
{
return
result
;
}
}
}
rc
=
ssh_userauth_password
(
mSession
,
info
.
username
.
toUtf8
().
constData
(),
info
.
password
.
toUtf8
().
constData
());
if
(
rc
==
SSH_AUTH_SUCCESS
)
{
break
;
}
else
if
(
rc
==
SSH_AUTH_ERROR
)
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Password authentication failed:"
<<
QString
::
fromUtf8
(
ssh_get_error
(
mSession
));
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Authentication failed."
));
}
isFirstLoginAttempt
=
false
;
// failed attempt to login.
info
.
password
.
clear
();
// clear the password after failed attempts.
}
}
// If we're still not authenticated then we need to leave.
if
(
rc
!=
SSH_AUTH_SUCCESS
)
{
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Authentication failed."
));
}
// start sftp session
qCDebug
(
KIO_SFTP_LOG
)
<<
"Trying to request the sftp session"
;
mSftp
=
sftp_new
(
mSession
);
if
(
mSftp
==
nullptr
)
{
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Unable to request the SFTP subsystem. "
"Make sure SFTP is enabled on the server."
));
}
qCDebug
(
KIO_SFTP_LOG
)
<<
"Trying to initialize the sftp session"
;
if
(
sftp_init
(
mSftp
)
<
0
)
{
closeConnection
();
return
Result
::
fail
(
KIO
::
ERR_CANNOT_LOGIN
,
i18n
(
"Could not initialize the SFTP session."
));
}
// Login succeeded!
q
->
infoMessage
(
i18n
(
"Successfully connected to %1"
,
mHost
));
if
(
info
.
keepPassword
)
{
qCDebug
(
KIO_SFTP_LOG
)
<<
"Caching info.username = "
<<
info
.
username
<<
", info.url = "
<<
info
.
url
.
toDisplayString
();
q
->
cacheAuthentication
(
info
);
}
// Update the original username in case it was changed!
if
(
!
mUsername
.
isEmpty
())
{
mUsername
=
info
.
username
;
}
q
->
setTimeoutSpecialCommand
(
KIO_SFTP_SPECIAL_TIMEOUT
);
mConnected
=
true
;
q
->
connected
();
info
.
password
.
fill
(
'x'
);
info
.
password
.
clear
();
return
Result
::
pass
();
}
#endif // 0.8.0
void
SFTPInternal
::
closeConnection
()
{
qCDebug
(
KIO_SFTP_LOG
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment