Skip to content

Commit

Permalink
Merge pull request #29 from rdoeffinger/webdav
Browse files Browse the repository at this point in the history
Add WebDAV support.
  • Loading branch information
annejan committed Apr 20, 2015
2 parents 180587a + 3f26c15 commit 651a2aa
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 1 deletion.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,31 @@ qtpass

QtPass is a gui for [pass](http://www.passwordstore.org/)

Security considerations
-----------------------
Using this program will not magically keep your passwords secure against
compromised computers even if you use it in combination with a smartcard.
It does protect future and changed passwords though against anyone with access to
your password store only but not your keys.
Used with a smartcard it also protects against anyone just monitoring/copying
all files/keystrokes on that machine and such an attacker would only gain access
to the passwords you actually use.
Once you plug in your smartcard and enter your PIN (or due to CVE-2015-3298
even without your PIN) all your passwords available to the machine can be
decrypted by it, if there is malicious software targeted specifically against
it installed (or at least one that knows how to use a smartcard).
To get better protection out of use with a smartcard even against a targeted
attack I can think of at least two options:
* The smartcard must require explicit confirmation for each decryption operation.
Or if it just provides a counter for decrypted data you could at least notice
an attack afterwards, though at quite some effort on your part.
* Use a different smartcard for each (group of) key.
* If using a YubiKey or U2F module or similar that requires a "button" press for
other authentication methods you can use one OTP/U2F enabled WebDAV account per
password (or groups of passwords) as a quite inconvenient workaround.
Unfortunately I do not know of any WebDAV service with OTP support except ownCloud
(so you would have to run your own server).

Current state
-------------
* Using pass or directly with git and gpg2
Expand Down
80 changes: 79 additions & 1 deletion mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include <QInputDialog>
#include <QMessageBox>
#include <QTimer>
#ifdef Q_OS_WIN
#include <windows.h>
#undef DELETE
#endif

/**
* @brief MainWindow::MainWindow
Expand All @@ -15,7 +19,8 @@
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
process(new QProcess(this))
process(new QProcess(this)),
fusedav(this)
{
// connect(process.data(), SIGNAL(readyReadStandardOutput()), this, SLOT(readyRead()));
connect(process.data(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));
Expand All @@ -29,6 +34,14 @@ MainWindow::MainWindow(QWidget *parent) :
*/
MainWindow::~MainWindow()
{
#ifdef Q_OS_WIN
if (useWebDav) WNetCancelConnection2A(passStore.toUtf8().constData(), 0, 1);
#else
if (fusedav.state() == QProcess::Running) {
fusedav.terminate();
fusedav.waitForFinished(2000);
}
#endif
}

void MainWindow::normalizePassStore() {
Expand All @@ -49,6 +62,59 @@ QSettings &MainWindow::getSettings() {
return *settings;
}

void MainWindow::mountWebDav() {
#ifdef Q_OS_WIN
char dst[20] = {0};
NETRESOURCEA netres;
memset(&netres, 0, sizeof(netres));
netres.dwType = RESOURCETYPE_DISK;
netres.lpLocalName = 0;
netres.lpRemoteName = webDavUrl.toUtf8().data();
DWORD size = sizeof(dst);
DWORD r = WNetUseConnectionA(reinterpret_cast<HWND>(effectiveWinId()), &netres, webDavPassword.toUtf8().constData(),
webDavUser.toUtf8().constData(), CONNECT_TEMPORARY | CONNECT_INTERACTIVE | CONNECT_REDIRECT,
dst, &size, 0);
if (r == NO_ERROR) {
passStore = dst;
} else {
char message[256] = {0};
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, r, 0, message, sizeof(message), 0);
ui->textBrowser->setTextColor(Qt::red);
ui->textBrowser->setText(tr("Failed to connect WebDAV:\n") + message + " (0x" + QString::number(r, 16) + ")");
}
#else
fusedav.start("fusedav -o nonempty -u \"" + webDavUser + "\" " + webDavUrl + " \"" + passStore + '"');
fusedav.waitForStarted();
if (fusedav.state() == QProcess::Running) {
QString pwd = webDavPassword;
bool ok = true;
if (pwd.isEmpty()) {
pwd = QInputDialog::getText(this, tr("QtPass WebDAV password"),
tr("Enter password to connect to WebDAV:"), QLineEdit::Password, "", &ok);
}
if (ok && !pwd.isEmpty()) {
fusedav.write(pwd.toUtf8() + '\n');
fusedav.closeWriteChannel();
fusedav.waitForFinished(2000);
} else {
fusedav.terminate();
}
}
QString error = fusedav.readAllStandardError();
int prompt = error.indexOf("Password:");
if (prompt >= 0) {
error.remove(0, prompt + 10);
}
if (fusedav.state() != QProcess::Running) {
error = tr("fusedav exited unexpectedly\n") + error;
}
if (error.size() > 0) {
ui->textBrowser->setTextColor(Qt::red);
ui->textBrowser->setText(tr("Failed to start fusedav to connect WebDAV:\n") + error);
}
#endif
}

/**
* @brief MainWindow::checkConfig
*/
Expand Down Expand Up @@ -87,10 +153,22 @@ void MainWindow::checkConfig() {
}
gpgHome = settings.value("gpgHome").toString();

useWebDav = (settings.value("useWebDav") == "true");
webDavUrl = settings.value("webDavUrl").toString();
webDavUser = settings.value("webDavUser").toString();
webDavPassword = settings.value("webDavPassword").toString();

if (passExecutable == "" && (gitExecutable == "" || gpgExecutable == "")) {
config();
}

// TODO: this needs to be before we try to access the store,
// but it would be better to do it after the Window is shown,
// as the long delay it can cause is irritating otherwise.
if (useWebDav) {
mountWebDav();
}

model.setNameFilters(QStringList() << "*.gpg");
model.setNameFilterDisables(false);

Expand Down
6 changes: 6 additions & 0 deletions mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ private slots:
QString gitExecutable;
QString gpgExecutable;
QString gpgHome;
bool useWebDav;
QString webDavUrl;
QString webDavUser;
QString webDavPassword;
QProcess fusedav;
QString clippedPass;
actionType currentAction;
QString lastDecrypt;
Expand All @@ -87,6 +92,7 @@ private slots:
QSettings &getSettings();
QList<UserInfo> listKeys(QString keystring = "");
QString getRecipientString(QString for_file, QString separator = " ");
void mountWebDav();
};

#endif // MAINWINDOW_H

0 comments on commit 651a2aa

Please sign in to comment.