Mercurial > trustbridge
view ui/installwrapper.cpp @ 1159:0ddb173bcd8b
(issue36) Use 8 bit encoding for cinst process start
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Thu, 18 Sep 2014 15:46:49 +0200 |
parents | a7a72353d6d2 |
children | 2a1206932f53 |
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "installwrapper.h" #include <QFileInfo> #include <QProcess> #include <QTemporaryFile> #include <QApplication> #include <QDir> #include <QDebug> #include "logging.h" #include "util.h" #include "binverify.h" #define INSTALL_TIMEOUT 3600000 /* Wait up to an hour */ InstallWrapper::InstallWrapper(QObject* parent, const QString& path, const QStringList& choices): QThread(parent), mCertListFile(path), mChoices(choices) { } QFileInfo getCinstProcInfo() { QFileInfo fi(QCoreApplication::applicationFilePath()); QDir myDir = fi.absoluteDir(); QString instProcName = "cinst"; if (!fi.suffix().isEmpty()) { instProcName += "." + fi.suffix(); } return QFileInfo(myDir.absoluteFilePath(instProcName)); } bool InstallWrapper::writeChoices(QTemporaryFile* choicesFile) const { if (!choicesFile->open()) { return false; } foreach (const QString &b64data, mChoices) { syslog_info_printf ("Selected certificate: %s\n", b64data.toLatin1().constData()); if (choicesFile->write(b64data.toLatin1()) == -1) { return false; } if (choicesFile->write("\n") == -1) { return false; } } choicesFile->close(); return true; } void InstallWrapper::run() { /* TODO: We need errorcodes here so that we can see if a user * cancled the UAC elevation */ QTemporaryFile choicesFile; QFileInfo cinstProcInfo = getCinstProcInfo(); QString cinstFileName = QDir::toNativeSeparators( getCinstProcInfo().absoluteFilePath()); if (!cinstProcInfo.isExecutable()) { emit error(tr("Could not find certificate installation process.")); return; } if (!writeChoices(&choicesFile)) { emit error(tr("Failed to write temporary file.")); return; } #ifdef WIN32 bin_verify_result vres = verify_binary(cinstFileName.toUtf8().constData(), cinstFileName.toUtf8().size()); if (vres.result != VerifyValid) { emit error(tr("Integrity check of the certificate installation process failed. ") + "\n" + tr("Please reinstall the software.")); return; } /* QProcess on Windows uses CreateProcess but we have to * use the runas shell command to get the UAC prompt if necessary. * So we have to handle the process ourself. Starting with * shell execute also means that we can not have stdout and stderr * redirection. This is the reason we use command line parameters * and not a pipe for communication. In debug mode the installer * also makes use of output debug string. */ DWORD retval = 0; SHELLEXECUTEINFOA shExecInfo; memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOA)); /* Windows needs each parameter packed in " */ QString parameters = "\"list=" + mCertListFile + "\" \"choices=" + choicesFile.fileName() + "\""; if (g_debug) { parameters += " --debug"; } shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOA); shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; if (!is_system_install()) { shExecInfo.lpVerb = "open"; } else { shExecInfo.lpVerb = "runas"; } shExecInfo.lpFile = strdup(cinstFileName.toLocal8Bit().constData()); shExecInfo.lpParameters = strdup(parameters.toUtf8().constData()); qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; if (!ShellExecuteExA(&shExecInfo)) { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error(tr("Error executing process: %1").arg(qerrmsg)); fclose(vres.fptr); free((void*)shExecInfo.lpFile); free((void*)shExecInfo.lpParameters); return; } retval = WaitForSingleObject(shExecInfo.hProcess, INSTALL_TIMEOUT); free((void*)shExecInfo.lpFile); free((void*)shExecInfo.lpParameters); shExecInfo.lpFile = NULL; shExecInfo.lpParameters = NULL; if (retval != WAIT_OBJECT_0) { if (retval == WAIT_FAILED) { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error (tr("Error monitoring process: %1").arg(qerrmsg)); fclose(vres.fptr); return; } else { emit error (tr("Certificate installation timed out.")); fclose(vres.fptr); return; } } if (GetExitCodeProcess(shExecInfo.hProcess, &retval)) { if (retval == STILL_ACTIVE) { qDebug() << "Process still running, huh.."; } } else { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error (tr("Failed to check process status: %1").arg(qerrmsg)); CloseHandle(shExecInfo.hProcess); fclose(vres.fptr); return; } CloseHandle(shExecInfo.hProcess); fclose(vres.fptr); if (retval != 0) { /* TODO make this nicer */ emit error (tr("The process failed with return code. %1").arg(retval)); return; } #else /* WIN32 */ QProcess installerProcess; QStringList parameters; choicesFile.setAutoRemove(false); parameters << "list=" + mCertListFile << "choices=" + choicesFile.fileName(); if (g_debug) { parameters << "--debug"; } bool sudo_started = false; bool use_sudo = is_admin() && is_system_install(); if (use_sudo) { QStringList sudoPrograms; sudoPrograms << "pkexec" << "kdesudo" << "sudo"; QStringList sudoParams; sudoParams << cinstProcInfo.absoluteFilePath() << parameters; installerProcess.setArguments(sudoParams); foreach (const QString &sProg, sudoPrograms) { installerProcess.setProgram(sProg); qDebug() << "Starting process " << sProg <<" params: " << sudoParams; installerProcess.start(); if (!installerProcess.waitForStarted() || installerProcess.state() == QProcess::NotRunning) { continue; } else { sudo_started = true; break; } } } /* Fallback to start without sudo */ if (!use_sudo || !sudo_started) { installerProcess.setProgram(cinstProcInfo.absoluteFilePath()); installerProcess.setArguments(parameters); qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; installerProcess.start(); if (!installerProcess.waitForStarted() || installerProcess.state() == QProcess::NotRunning) { emit error (tr("Failed to start installer process.")); return; } } installerProcess.waitForFinished(); if (installerProcess.exitStatus() == QProcess::CrashExit) { /* Woops */ emit error (tr("Failed to complete installation.")); return; } else if (installerProcess.exitStatus() != QProcess::NormalExit) { /* Can not Happen. there are only those two values but maybe * qt changed.. */ emit error (tr("Failed to complete installation.")); return; } if (installerProcess.exitCode() == 0) { qDebug() << "output: " << installerProcess.readAllStandardOutput(); } else { /* TODO handle errors defined by errorcodes.h */ qDebug() << "Installer Process returned: " << installerProcess.exitCode(); qDebug() << "output: " << installerProcess.readAllStandardOutput(); return; } #endif emit installationSuccessful(); }