Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Increase robustness of VPN UI dbus interface
Previously when contacted by connman to generate a VPN credentials UI,
the code would assume values received by dbus were well-structured. This
change checks the contents more carefully and adds missing values.

The interface also now supports the 'control' Requirement.
  • Loading branch information
llewelld committed Jun 4, 2019
1 parent af22e3e commit c8273b9
Showing 1 changed file with 47 additions and 26 deletions.
73 changes: 47 additions & 26 deletions src/vpnagent.cpp
Expand Up @@ -77,14 +77,19 @@ void VpnAgent::respond(const QString &path, const QVariantMap &details)
QVariantMap response;
for (QVariantMap::const_iterator it = details.cbegin(), end = details.cend(); it != end; ++it) {
const QString name(it.key());
if (name == QStringLiteral("storeCredentials")) {
storeCredentials = it.value().value<bool>();
const QVariantMap &field(it.value().value<QVariantMap>());
const QVariant fieldValue = field.value(QStringLiteral("Value"));
const QString fieldRequirement = field.value(QStringLiteral("Requirement")).toString();
const QString fieldType = field.value(QStringLiteral("Type")).toString();
if ((name == QStringLiteral("storeCredentials"))
&& (fieldRequirement == QStringLiteral("control"))
&& (fieldType == QStringLiteral("boolean"))) {
storeCredentials = fieldValue.toBool();
} else {
const QVariantMap &field(it.value().value<QVariantMap>());
const QVariant fieldValue = field.value(QStringLiteral("Value"));
const QString fieldRequirement = field.value(QStringLiteral("Requirement")).toString();
if (fieldRequirement == QStringLiteral("mandatory") ||
(fieldRequirement != QStringLiteral("informational") && fieldValue.isValid())) {
(fieldRequirement != QStringLiteral("informational")
&& fieldRequirement != QStringLiteral("control")
&& fieldValue.isValid())) {
response.insert(it.key(), fieldValue);
}
}
Expand Down Expand Up @@ -151,55 +156,67 @@ void VpnAgent::ReportError(const QDBusObjectPath &path, const QString &message)
namespace {

template<typename T>
QVariant extract(const QDBusArgument &arg)
T extract(const QDBusArgument &arg)
{
T rv;
arg >> rv;
return QVariant::fromValue(rv);
return rv;
}

// Extracts a boolean value and removes it from the map
bool ExtractRequestBool(QVariantMap &extracted, const QString key, bool defaultValue) {
bool ExtractRequestBool(QVariantMap &extracted, const QString &key, bool defaultValue) {
bool result = defaultValue;
QVariantMap::iterator it = extracted.find(key);
while (it != extracted.end()) {
bool found = false;
if (it.key() == key) {
QVariantMap field(it.value().value<QVariantMap>());
QString type = field.value(QStringLiteral("Type")).toString();
QString requirement = field.value(QStringLiteral("Requirement")).toString();
QString value = field.value(QStringLiteral("Value")).toString();
const QVariantMap field(it.value().value<QVariantMap>());
const QString type = field.value(QStringLiteral("Type")).toString();
const QString requirement = field.value(QStringLiteral("Requirement")).toString();

if ((type == QStringLiteral("string")) && (requirement == QStringLiteral("mandatory"))) {
qDebug() << "VPNUI extracted " << it.key() << ": " << value;
result = (value == QStringLiteral("1"));
if ((type == QStringLiteral("boolean")) && (requirement == QStringLiteral("control"))) {
result = field.value(QStringLiteral("Value")).toBool();
it = extracted.erase(it);
found = true;
break;
}
}
if (!found) {
it++;
}
it++;
}
return result;
}

void CompleteEmptyValues(QVariantMap &field) {
if (!field.contains(QStringLiteral("Requirement"))) {
field.insert(QStringLiteral("Requirement"), QVariant(QStringLiteral("optional")));
}
if (!field.contains(QStringLiteral("Type"))) {
field.insert(QStringLiteral("Type"), QVariant(QStringLiteral("string")));
}
if (!field.contains(QStringLiteral("Value"))) {
const QString fieldType = field.value(QStringLiteral("Type")).toString();
if (fieldType == "boolean") {
field.insert(QStringLiteral("Value"), false);
}
else {
field.insert(QStringLiteral("Value"), QStringLiteral(""));
}
}
}

}

QVariantMap VpnAgent::RequestInput(const QDBusObjectPath &path, const QVariantMap &details)
{
// Extract the details from DBus marshalling
QVariantMap extracted(details);
for (QVariantMap::iterator it = extracted.begin(), end = extracted.end(); it != end; ++it) {
*it = extract<QVariantMap>(it.value().value<QDBusArgument>());
QVariantMap field = extract<QVariantMap>(it.value().value<QDBusArgument>());
CompleteEmptyValues(field);
*it = QVariant::fromValue(field);
}

const bool allowCredentialStorage(ExtractRequestBool(extracted, "AllowStoreCredentials", true));
const bool allowCredentialRetrieval(ExtractRequestBool(extracted, "AllowRetrieveCredentials", true));

qDebug() << "VPNUI final AllowStoreCredentials: " << allowCredentialStorage;
qDebug() << "VPNUI final AllowRetrieveCredentials: " << allowCredentialRetrieval;

// Can we supply the requested data from stored credentials?
const QString objectPath(path.path());
const bool storeCredentials(m_connections->connectionCredentialsEnabled(objectPath));
Expand Down Expand Up @@ -261,7 +278,11 @@ QVariantMap VpnAgent::RequestInput(const QDBusObjectPath &path, const QVariantMa
}

if (allowCredentialStorage) {
extracted.insert(QStringLiteral("storeCredentials"), QVariant::fromValue(storeCredentials));
QVariantMap field;
field.insert(QStringLiteral("Requirement"), QVariant::fromValue(QStringLiteral("control")));
field.insert(QStringLiteral("Type"), QVariant::fromValue(QStringLiteral("boolean")));
field.insert(QStringLiteral("Value"), QVariant::fromValue(storeCredentials));
extracted.insert(QStringLiteral("storeCredentials"), field);
}

// Inform the caller that the reponse will be asynchronous
Expand Down

0 comments on commit c8273b9

Please sign in to comment.