mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 02:42:48 +00:00
262 lines
5.4 KiB
C++
262 lines
5.4 KiB
C++
/* vi: ts=8 sts=4 sw=4
|
|
*
|
|
* This file is part of the KDE project, module kdesu.
|
|
* Copyright (C) 2000 Geert Jansen <jansen@kde.org>
|
|
*
|
|
* This is free software; you can use this library under the GNU Library
|
|
* General Public License, version 2. See the file "COPYING.LIB" for the
|
|
* exact licensing terms.
|
|
*
|
|
* ssh.cpp: Execute a program on a remote machine using ssh.
|
|
*/
|
|
|
|
#include "ssh.h"
|
|
#include "kcookie.h"
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <QtCore/QBool>
|
|
|
|
#include <kdebug.h>
|
|
#include <klocale.h>
|
|
#include <kstandarddirs.h>
|
|
|
|
extern int kdesuDebugArea();
|
|
|
|
namespace KDESu {
|
|
|
|
using namespace KDESuPrivate;
|
|
|
|
class SshProcess::SshProcessPrivate
|
|
{
|
|
public:
|
|
SshProcessPrivate(const QByteArray &host)
|
|
: m_Host( host )
|
|
, m_Stub( "kdesu_stub" )
|
|
{}
|
|
QByteArray m_Prompt;
|
|
QByteArray m_Host;
|
|
QByteArray m_Error;
|
|
QByteArray m_Stub;
|
|
};
|
|
|
|
|
|
SshProcess::SshProcess(const QByteArray &host, const QByteArray &user, const QByteArray &command)
|
|
: d( new SshProcessPrivate(host) )
|
|
{
|
|
m_User = user;
|
|
m_Command = command;
|
|
srand(time(0L));
|
|
}
|
|
|
|
|
|
SshProcess::~SshProcess()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void SshProcess::setHost(const QByteArray &host)
|
|
{
|
|
d->m_Host = host;
|
|
}
|
|
|
|
|
|
void SshProcess::setStub(const QByteArray &stub)
|
|
{
|
|
d->m_Stub = stub;
|
|
}
|
|
|
|
|
|
int SshProcess::checkInstall(const char *password)
|
|
{
|
|
return exec(password, 1);
|
|
}
|
|
|
|
|
|
int SshProcess::checkNeedPassword()
|
|
{
|
|
return exec(0L, 2);
|
|
}
|
|
|
|
|
|
int SshProcess::exec(const char *password, int check)
|
|
{
|
|
if (check)
|
|
setTerminal(true);
|
|
|
|
QList<QByteArray> args;
|
|
args += "-l"; args += m_User;
|
|
args += "-o"; args += "StrictHostKeyChecking=no";
|
|
args += d->m_Host; args += d->m_Stub;
|
|
|
|
if (StubProcess::exec("ssh", args) < 0)
|
|
{
|
|
return check ? SshNotFound : -1;
|
|
}
|
|
|
|
int ret = ConverseSsh(password, check);
|
|
if (ret < 0)
|
|
{
|
|
if (!check)
|
|
kError(kdesuDebugArea()) << k_lineinfo << "Conversation with ssh failed.";
|
|
return ret;
|
|
}
|
|
if (check == 2)
|
|
{
|
|
if (ret == 1)
|
|
{
|
|
kill(m_Pid, SIGTERM);
|
|
waitForChild();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (m_bErase && password)
|
|
memset(const_cast<char *>(password), 0, qstrlen(password));
|
|
|
|
ret = ConverseStub(check);
|
|
if (ret < 0)
|
|
{
|
|
if (!check)
|
|
kError(kdesuDebugArea()) << k_lineinfo << "Conversation with kdesu_stub failed.";
|
|
return ret;
|
|
}
|
|
else if (ret == 1)
|
|
{
|
|
kill(m_Pid, SIGTERM);
|
|
waitForChild();
|
|
ret = SshIncorrectPassword;
|
|
}
|
|
|
|
if (check == 1)
|
|
{
|
|
waitForChild();
|
|
return 0;
|
|
}
|
|
|
|
setExitString("Waiting for forwarded connections to terminate");
|
|
ret = waitForChild();
|
|
return ret;
|
|
}
|
|
|
|
QByteArray SshProcess::prompt() const
|
|
{
|
|
return d->m_Prompt;
|
|
}
|
|
|
|
QByteArray SshProcess::error() const
|
|
{
|
|
return d->m_Error;
|
|
}
|
|
|
|
|
|
/*
|
|
* Conversation with ssh.
|
|
* If check is 0, this waits for either a "Password: " prompt,
|
|
* or the header of the stub. If a prompt is received, the password is
|
|
* written back. Used for running a command.
|
|
* If check is 1, operation is the same as 0 except that if a stub header is
|
|
* received, the stub is stopped with the "stop" command. This is used for
|
|
* checking a password.
|
|
* If check is 2, operation is the same as 1, except that no password is
|
|
* written. The prompt is saved to m_Prompt. Used for checking the need for
|
|
* a password.
|
|
*/
|
|
|
|
int SshProcess::ConverseSsh(const char *password, int check)
|
|
{
|
|
unsigned i, j, colon;
|
|
|
|
QByteArray line;
|
|
int state = 0;
|
|
|
|
while (state < 2)
|
|
{
|
|
line = readLine();
|
|
const uint len = line.length();
|
|
if (line.isNull())
|
|
return -1;
|
|
|
|
switch (state) {
|
|
case 0:
|
|
// Check for "kdesu_stub" header.
|
|
if (line == "kdesu_stub")
|
|
{
|
|
unreadLine(line);
|
|
return 0;
|
|
}
|
|
|
|
// Match "Password: " with the regex ^[^:]+:[\w]*$.
|
|
for (i=0,j=0,colon=0; i<len; ++i)
|
|
{
|
|
if (line[i] == ':')
|
|
{
|
|
j = i; colon++;
|
|
continue;
|
|
}
|
|
if (!isspace(line[i]))
|
|
j++;
|
|
}
|
|
if ((colon == 1) && (line[j] == ':'))
|
|
{
|
|
if (check == 2)
|
|
{
|
|
d->m_Prompt = line;
|
|
return SshNeedsPassword;
|
|
}
|
|
if (WaitSlave())
|
|
return -1;
|
|
write(fd(), password, strlen(password));
|
|
write(fd(), "\n", 1);
|
|
state++;
|
|
break;
|
|
}
|
|
|
|
// Warning/error message.
|
|
d->m_Error += line; d->m_Error += '\n';
|
|
if (m_bTerminal)
|
|
fprintf(stderr, "ssh: %s\n", line.constData());
|
|
break;
|
|
|
|
case 1:
|
|
if (line.isEmpty())
|
|
{
|
|
state++;
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Display redirection is handled by ssh natively.
|
|
QByteArray SshProcess::display()
|
|
{
|
|
return "no";
|
|
}
|
|
|
|
|
|
QByteArray SshProcess::displayAuth()
|
|
{
|
|
return "no";
|
|
}
|
|
|
|
void SshProcess::virtual_hook( int id, void* data )
|
|
{ StubProcess::virtual_hook( id, data ); }
|
|
|
|
}
|