diff options
Diffstat (limited to 'src/helpers/sshagent.cpp')
-rw-r--r-- | src/helpers/sshagent.cpp | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/helpers/sshagent.cpp b/src/helpers/sshagent.cpp new file mode 100644 index 0000000..ccde212 --- /dev/null +++ b/src/helpers/sshagent.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2003 Christian Loose <[email protected]> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "sshagent.h" +#include "kdesvn-config.h" + +#include <qregexp.h> +#include <kapplication.h> +#include <kdeversion.h> +#include <kprocess.h> +#include <kdebug.h> + +#include <stdlib.h> + + +// initialize static member variables +bool SshAgent::m_isRunning = false; +bool SshAgent::m_isOurAgent = false; +bool SshAgent::m_addIdentitiesDone = false; +QString SshAgent::m_authSock = QString::null; +QString SshAgent::m_pid = QString::null; + + +SshAgent::SshAgent(QObject* parent, const char* name) + : QObject(parent, name) +{ +} + + +SshAgent::~SshAgent() +{ +} + + +bool SshAgent::querySshAgent() +{ + if( m_isRunning ) + return true; + + // Did the user already start a ssh-agent process? + char* pid; + if( (pid = ::getenv("SSH_AGENT_PID")) != 0 ) + { + m_pid = QString::fromLocal8Bit(pid); + + char* sock = ::getenv("SSH_AUTH_SOCK"); + if( sock ) + m_authSock = QString::fromLocal8Bit(sock); + /* make sure that we have a askpass program. + * on some systems something like that isn't installed.*/ +#ifdef FORCE_ASKPASS + kdDebug()<<"Using test askpass"<<endl; +#ifdef HAS_SETENV + ::setenv("SSH_ASKPASS",FORCE_ASKPASS,1); +#else + ::putenv("SSH_ASKPASS="FORCE_ASKPASS); +#endif +#else +/* + char*agent = ::getenv("SSH_ASKPASS"); + if (!agent) { +*/ +#ifdef HAS_SETENV + ::setenv("SSH_ASKPASS", "kdesvnaskpass",1); +#else + ::putenv("SSH_ASKPASS=kdesvnaskpass"); +#endif +/* + } +*/ +#endif + m_isOurAgent = false; + m_isRunning = true; + } + // We have to start a new ssh-agent process + else + { + m_isOurAgent = true; + m_isRunning = startSshAgent(); + } + + return m_isRunning; +} + + +bool SshAgent::addSshIdentities(bool force) +{ + if (m_addIdentitiesDone && !force) { + return true; + } + + + if( !m_isRunning || (!m_isOurAgent&&!force)) { + return false; + } + + // add identities to ssh-agent + KProcess proc; + + proc.setEnvironment("SSH_AGENT_PID", m_pid); + proc.setEnvironment("SSH_AUTH_SOCK", m_authSock); + +#ifdef FORCE_ASKPASS + kdDebug()<<"Using test askpass"<<endl; + proc.setEnvironment("SSH_ASKPASS",FORCE_ASKPASS); +#else + char*agent = 0; +/* + if (force) { + agent = ::getenv("SSH_ASKPASS"); + } +*/ + if (!agent) { + proc.setEnvironment("SSH_ASKPASS", "kdesvnaskpass"); + } +#endif + + proc << "ssh-add"; + + connect(&proc, SIGNAL(receivedStdout(KProcess*, char*, int)), + SLOT(slotReceivedStdout(KProcess*, char*, int))); + connect(&proc, SIGNAL(receivedStderr(KProcess*, char*, int)), + SLOT(slotReceivedStderr(KProcess*, char*, int))); + + proc.start(KProcess::DontCare, KProcess::AllOutput); + + // wait for process to finish + // TODO CL use timeout? + proc.wait(); + + m_addIdentitiesDone = proc.normalExit() && proc.exitStatus() == 0; + return m_addIdentitiesDone; +} + + +void SshAgent::killSshAgent() +{ + if( !m_isRunning || !m_isOurAgent ) + return; + + KProcess proc; + + proc << "kill" << m_pid; + + proc.start(KProcess::DontCare, KProcess::NoCommunication); +} + + +void SshAgent::slotProcessExited(KProcess*) +{ + QRegExp cshPidRx("setenv SSH_AGENT_PID (\\d*);"); + QRegExp cshSockRx("setenv SSH_AUTH_SOCK (.*);"); + + QRegExp bashPidRx("SSH_AGENT_PID=(\\d*).*"); + QRegExp bashSockRx("SSH_AUTH_SOCK=(.*\\.\\d*);.*"); + QStringList m_outputLines = QStringList::split("\n",m_Output); + + QStringList::Iterator it = m_outputLines.begin(); + QStringList::Iterator end = m_outputLines.end(); + for( ; it != end; ++it ) + { + if( m_pid.isEmpty() ) + { + int pos = cshPidRx.search(*it); + if( pos > -1 ) + { + m_pid = cshPidRx.cap(1); + continue; + } + + pos = bashPidRx.search(*it); + if( pos > -1 ) + { + m_pid = bashPidRx.cap(1); + continue; + } + } + + if( m_authSock.isEmpty() ) + { + int pos = cshSockRx.search(*it); + if( pos > -1 ) + { + m_authSock = cshSockRx.cap(1); + continue; + } + + pos = bashSockRx.search(*it); + if( pos > -1 ) + { + m_authSock = bashSockRx.cap(1); + continue; + } + } + } + +} + + +void SshAgent::slotReceivedStdout(KProcess* proc, char* buffer, int buflen) +{ + Q_UNUSED(proc); + + QString output = QString::fromLocal8Bit(buffer, buflen); + m_Output+=output; +} + + +void SshAgent::slotReceivedStderr(KProcess* proc, char* buffer, int buflen) +{ + Q_UNUSED(proc); + + QString output = QString::fromLocal8Bit(buffer, buflen); + m_Output+=output; +} + + +bool SshAgent::startSshAgent() +{ + KProcess proc; + + proc << "ssh-agent"; + + connect(&proc, SIGNAL(processExited(KProcess*)), + SLOT(slotProcessExited(KProcess*))); + connect(&proc, SIGNAL(receivedStdout(KProcess*, char*, int)), + SLOT(slotReceivedStdout(KProcess*, char*, int))); + connect(&proc, SIGNAL(receivedStderr(KProcess*, char*, int)), + SLOT(slotReceivedStderr(KProcess*, char*, int)) ); + + proc.start(KProcess::NotifyOnExit, KProcess::All); + + // wait for process to finish + // TODO CL use timeout? + proc.wait(); + + return (proc.normalExit() && proc.exitStatus() == 0); +} + +#include "sshagent.moc" |