Files
qt-creator/tests/manual/ssh/sftp/argumentscollector.cpp
Christian Kandeler 9e5a9110ca SSH: Implement and make use of RFC 4256.
There is now at least one Linux distribution (openSUSE 12.3) that
disables the "password" authentication method in its default
sshd_config, while others allow it, but disable "keyboard-interactive".
This patch tackles the problem as follows:
    1) Implement RFC 4256 ("keyboard-interactive") and make this method
available in the API.
    2) In addition, the API offers to try both password-based methods
one after the other, until one has succeeded or all have failed.
    3) Dialogs continue to offer just the choice between "Password" and
"Key", as to not confuse users. Internally, "Password" uses the feature
described in 2).

Task-number: QTCREATORBUG-9568
Change-Id: Ic81bd5d2dc4b1332ea1a8be938c19811c21a9087
Reviewed-by: hjk <hjk121@nokiamail.com>
Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
2013-06-20 15:21:41 +02:00

170 lines
6.9 KiB
C++

/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "argumentscollector.h"
#include <iostream>
using namespace QSsh;
using namespace std;
ArgumentsCollector::ArgumentsCollector(const QStringList &args)
: m_arguments(args)
{
}
Parameters ArgumentsCollector::collect(bool &success) const
{
Parameters parameters;
parameters.sshParams.options &= ~SshIgnoreDefaultProxy;
try {
bool authTypeGiven = false;
bool portGiven = false;
bool timeoutGiven = false;
bool smallFileCountGiven = false;
bool bigFileSizeGiven = false;
bool proxySettingGiven = false;
int pos;
int port;
for (pos = 1; pos < m_arguments.count() - 1; ++pos) {
if (checkAndSetStringArg(pos, parameters.sshParams.host, "-h")
|| checkAndSetStringArg(pos, parameters.sshParams.userName, "-u"))
continue;
if (checkAndSetIntArg(pos, port, portGiven, "-p")
|| checkAndSetIntArg(pos, parameters.sshParams.timeout, timeoutGiven, "-t")
|| checkAndSetIntArg(pos, parameters.smallFileCount, smallFileCountGiven, "-c")
|| checkAndSetIntArg(pos, parameters.bigFileSize, bigFileSizeGiven, "-s"))
continue;
if (checkAndSetStringArg(pos, parameters.sshParams.password, "-pwd")) {
if (!parameters.sshParams.privateKeyFile.isEmpty())
throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive."));
parameters.sshParams.authenticationType
= SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods;
authTypeGiven = true;
continue;
}
if (checkAndSetStringArg(pos, parameters.sshParams.privateKeyFile, "-k")) {
if (!parameters.sshParams.password.isEmpty())
throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive."));
parameters.sshParams.authenticationType
= SshConnectionParameters::AuthenticationTypePublicKey;
authTypeGiven = true;
continue;
}
if (!checkForNoProxy(pos, parameters.sshParams.options, proxySettingGiven))
throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos));
}
Q_ASSERT(pos <= m_arguments.count());
if (pos == m_arguments.count() - 1) {
if (!checkForNoProxy(pos, parameters.sshParams.options, proxySettingGiven))
throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos));
}
if (!authTypeGiven)
throw ArgumentErrorException(QLatin1String("No authentication argument given."));
if (parameters.sshParams.host.isEmpty())
throw ArgumentErrorException(QLatin1String("No host given."));
if (parameters.sshParams.userName.isEmpty())
throw ArgumentErrorException(QLatin1String("No user name given."));
parameters.sshParams.port = portGiven ? port : 22;
if (!timeoutGiven)
parameters.sshParams.timeout = 30;
if (!smallFileCountGiven)
parameters.smallFileCount = 1000;
if (!bigFileSizeGiven)
parameters.bigFileSize = 1024;
success = true;
} catch (ArgumentErrorException &ex) {
cerr << "Error: " << qPrintable(ex.error) << endl;
printUsage();
success = false;
}
return parameters;
}
void ArgumentsCollector::printUsage() const
{
cerr << "Usage: " << qPrintable(m_arguments.first())
<< " -h <host> -u <user> "
<< "-pwd <password> | -k <private key file> [ -p <port> ] "
<< "[ -t <timeout> ] [ -c <small file count> ] "
<< "[ -s <big file size in MB> ] [ -no-proxy ]" << endl;
}
bool ArgumentsCollector::checkAndSetStringArg(int &pos, QString &arg, const char *opt) const
{
if (m_arguments.at(pos) == QLatin1String(opt)) {
if (!arg.isEmpty()) {
throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt)
+ QLatin1String(" was given twice."));
}
arg = m_arguments.at(++pos);
if (arg.isEmpty() && QLatin1String(opt) != QLatin1String("-pwd"))
throw ArgumentErrorException(QLatin1String("empty argument not allowed here."));
return true;
}
return false;
}
bool ArgumentsCollector::checkAndSetIntArg(int &pos, int &val,
bool &alreadyGiven, const char *opt) const
{
if (m_arguments.at(pos) == QLatin1String(opt)) {
if (alreadyGiven) {
throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt)
+ QLatin1String(" was given twice."));
}
bool isNumber;
val = m_arguments.at(++pos).toInt(&isNumber);
if (!isNumber) {
throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt)
+ QLatin1String(" needs integer argument"));
}
alreadyGiven = true;
return true;
}
return false;
}
bool ArgumentsCollector::checkForNoProxy(int &pos, SshConnectionOptions &options,
bool &alreadyGiven) const
{
if (m_arguments.at(pos) == QLatin1String("-no-proxy")) {
if (alreadyGiven)
throw ArgumentErrorException(QLatin1String("proxy setting given twice."));
options |= SshIgnoreDefaultProxy;
alreadyGiven = true;
return true;
}
return false;
}