diff options
Diffstat (limited to 'kpackage/kpPty.cpp')
-rw-r--r-- | kpackage/kpPty.cpp | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/kpackage/kpPty.cpp b/kpackage/kpPty.cpp new file mode 100644 index 0000000..b395483 --- /dev/null +++ b/kpackage/kpPty.cpp @@ -0,0 +1,446 @@ +/* +** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au> +** +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU 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 General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ + + +#include "../config.h" + +#include <qtimer.h> +#include <qregexp.h> + +#include <kprocctrl.h> +#include <kpty.h> +#include <kdebug.h> +#include <kpassdlg.h> + +#include <kpPty.h> +#include <kpackage.h> +#include <kpTerm.h> +#include <options.h> +#include <utils.h> + +#define SHPROMPT "# " +const int TIMEOUT = -3; +const int PASSWORD = -2; +const int PROMPT = -1; + +extern Opts *opts; +////////////////////////////////////////////////////////////////////////////// + +kpKProcIO::kpKProcIO ( QTextCodec *_codec) + : KProcIO(_codec) +{ +} + +kpKProcIO::~kpKProcIO() +{ +} + +bool kpKProcIO::sstart (RunMode runmode) +{ + + connect (this, SIGNAL (receivedStdout (KProcess *, char *, int)), + this, SLOT (received (KProcess *, char *, int))); + + + connect (this, SIGNAL (wroteStdin(KProcess *)), + this, SLOT (sent (KProcess *))); + + return KProcess::start (runmode,( KProcess::Communication) ( KProcess::Stdin | KProcess::Stdout)); +} + +////////////////////////////////////////////////////////////////////////////// + +kpPty::kpPty() : QObject() +{ + pty = new kpKProcIO(); + pty->setUsePty(KProcess::All, false); + + connect(pty, SIGNAL(readReady(KProcIO *)), this, + SLOT(readLines())); + connect(pty, SIGNAL(processExited(KProcess *)), this, + SLOT(done())); + pty->pty()->setWinSize(0,80); + tm = new QTimer(this); + connect(tm, SIGNAL(timeout()), this, SLOT(slotTimeout())); + + eventLoop = FALSE; + inSession = FALSE; + pUnterm = FALSE; + loginSession = FALSE; + + codec = QTextCodec::codecForLocale(); + QMap<QString, QCString> passwords; +} + + +kpPty::~kpPty() +{ +} + +void kpPty::startSu() +{ + kdDebug() << "startSu()\n"; + pty->setEnvironment("PS1", SHPROMPT); +#if defined(__FreeBSD__) || defined(__bsdi__) + (*pty) << "su"; +#else + (*pty) << "su" << "-s" << "/bin/sh"; +#endif + +} + +void kpPty::startSudo() +{ + kdDebug() << "startSudo()\n"; + pty->setEnvironment("PS1", SHPROMPT); + (*pty) << "sudo" << "-p" << "Password: " << "/bin/sh"; +} + +void kpPty::startSsh() +{ + kdDebug() << "startSsh()\n"; + (*pty) << "/usr/bin/ssh" << "-t" << "-l" << "root"; + if (hostName.isEmpty()) { + (*pty) << "-o" << "StrictHostKeyChecking=no" << "localhost"; + } else { + (*pty) << hostName; + } + (*pty) << "env PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin PS1='" SHPROMPT "' sh"; +} + +bool kpPty::needSession(bool needRoot) +{ + return (!hostName.isEmpty() || needRoot); +} + +bool kpPty::startSession(bool needRoot) +{ + bool interact = FALSE; // Have interacted with user, prevents loops + bool passwordTried = FALSE; // Have tried the current save password, so need to put up dialog + pUnterm = FALSE; + kdDebug() << "kpPty::startSession\n"; + if (!inSession && needSession(needRoot)) { + // Assume !needRoot actions are simple executables + kdDebug() << "kpPty::startSession TRUE\n"; + loginSession = TRUE; + int ret; + QString s = "echo START=$?\n"; + + FULL_RESTART: + interact = FALSE; + retList.clear(); + pty->resetAll(); + + QString passMsg; + kdDebug() << "privCmd=" << opts->privCmd << "\n"; + if (opts->privCmd == Opts::SSHcmd || !hostName.isEmpty()) { + passMsg = i18n("The action you requested uses ssh. Please enter the password or pass phrase.\n"); + startSsh(); + } else if (opts->privCmd == Opts::SUcmd) { + passMsg = i18n("The action you requested needs root privileges. Please enter root's password.\n"); + startSu(); + } else if (opts->privCmd == Opts::SUDOcmd) { + passMsg = i18n("The action you requested needs root privileges. Please enter your SUDO password.\n"); + startSudo(); + } + pty->sstart(KProcess::NotifyOnExit); + + RESTART: + tm->start(6*1000, TRUE); + eventLoop = TRUE; + kdDebug() << "Loopst\n"; + kapp->enter_loop(); + kdDebug() << "Loopfn Result=" << Result << "\n"; + tm->stop(); + if (Result == TIMEOUT) { // timeout + interact = TRUE; + // kdDebug() << "Line=" << retList.last() << "\n"; + kpstart->addText(retList); + kpstart->run("", i18n("Login Problem: Please login manually")); + + ret = kpstart->exec(); + kdDebug() << "Sret=" << ret << "\n"; + if (ret) { + inSession = FALSE; + } else { + inSession = TRUE; + } + } else if (Result == PASSWORD) { // We got a password prompt + QCString pass; + int res; + interact = TRUE; + // kdDebug() << "H=" << hostName << " PH=" << passwords[hostName] << " PT=" << passwordTried <<"\n"; + if (passwords[hostName] != 0 && !passwordTried) { + pass = passwords[hostName]; + res = 1; + } else { + kdDebug() << "Passwd=" << retList.last() << "\n"; + QString msg = passMsg; + // kdDebug() << "privCmd=" << opts->privCmd << " host=" << hostName.isEmpty() << "\n"; + if (opts->privCmd == Opts::SSHcmd || !hostName.isEmpty()) { + msg += retList.last(); + } + int keep = 1; + res = KPasswordDialog::getPassword(pass,msg,&keep); + // kdDebug() << "Pass=" << pass << " Keep=" << keep << " Res=" << res << "\n"; + if (keep) { + passwords[hostName] = pass; + } else { + passwords.remove(hostName); + } + } + pty->writeStdin(pass.append("\n"), false); + passwordTried = TRUE; + if (res) { + retList.clear(); + goto RESTART; + } else { + inSession = FALSE; + } + } else if (Result == PROMPT) { // Got Prompt + inSession = TRUE; + kdDebug() << "kpPty::startSession TRUE\n"; + } else { // process return code + pty->writeStdin(QCString("\04"), false); // SU doesn't listen to ^C + if (interact) { + goto FULL_RESTART; + } else { + QString errMsg = retList.join(" "); + KpMsgE(errMsg, TRUE); + inSession = FALSE; + } + } + } else { + kdDebug() << "kpPty::startSession Not needed\n"; + } + + loginSession = FALSE; + if (!inSession) + close(); + + return inSession; +} + +void kpPty::breakUpCmd(const QString &cmd) +{ + kdDebug() << " kpPty::run CMD=\""<< cmd <<"\" pty = " << pty << endl; + + bool quote = FALSE; + QString s; + QStringList cl = QStringList::split(" ", cmd); + + for ( QStringList::Iterator it = cl.begin(); it != cl.end(); ++it ) { + int lastPt = (*it).length() - 1; + if ((*it)[0] == '\'') { // Start of quoted string + s = *it; + if ((*it)[lastPt] == '\'') { // Also End of quoted string + s.replace("'",""); + (*pty) << s; + quote = FALSE; + } else { + s += " "; + quote = TRUE; + } + } else if ((*it)[lastPt] == '\'') { // End of quoted string + s += *it; + s.replace("'",""); + (*pty) << s; + quote = FALSE; + } else if (quote) { + s += *it; + s += " "; + } else { + (*pty) << (*it); + } + } +} + +QStringList kpPty::run(const QString &cmd, bool inLoop, bool needRoot) +{ + Result = 0; + + pUnterm = FALSE; + + if (!inSession && !needSession(needRoot)) { + // Assume !needRoot actions are simple executables + pty->resetAll(); + breakUpCmd(cmd); + pty->setEnvironment("TERM", "dumb"); + if (!pty->sstart(KProcess::NotifyOnExit)) { + kdDebug() << " kpPty::run execute=0\n"; + return 0; + } + } else { + if (startSession(needRoot)) { + kdDebug() << "CMDroot='"<< cmd <<"'\n"; + QString s = cmd + ";echo RESULT=$?"; + pty->writeStdin(s); + kdDebug() << " kpPty::run session\n"; + } else { + kdDebug() << " kpPty::run other=0\n"; + return 0; + } + } + + retList.clear(); + + if (inLoop) { + eventLoop = TRUE; + kapp->enter_loop(); + + return retList; + } else { + return 0; + } +} + +void kpPty::close() { + // kdDebug() << "kpPty::close\n"; + + pty->closeAll(); + while(pty->isRunning()) { + KProcessController::theKProcessController->waitForProcessExit(1); + } + inSession = false; +} + +void kpPty::finish(int ret) +{ + kdDebug() << "kpPty::finish " << ret << "\n"; + + QStringList::Iterator l; + Result = ret; + + if (ret == PROMPT) { // Called program executed in session + if (!retList.empty()) { + l = retList.fromLast(); + if ((*l).right(2) == SHPROMPT) { + retList.remove(l); // Remove prompt + } + } + + if (!retList.empty()) { + int p; + l = retList.fromLast(); + if ((p = (*l).find("RESULT=")) >= 0) { + ret = (*l).mid(p+7).toInt(0,10); + retList.remove(l); // Remove return code + } else { + ret = 666; + } + } + + if (!retList.empty()) { + l = retList.begin(); + if ( l != retList.end()) { + if ((*l).find("RESULT=") >= 0) { + retList.remove(l); // Remove command at start + } + } + } + } + emit result(retList,ret); + + + if (eventLoop) { + eventLoop = FALSE; + kapp->exit_loop(); + } +} + +void kpPty::readLines() +{ + bool unterm = FALSE; + + QString stext; + while(pty->readln(stext, false, &unterm) >= 0) + { + stext = codec->toUnicode(stext.ascii(), stext.length()); + emit textIn(stext, !unterm); +// kdDebug() << "[" << pUnterm << "-" << unterm << "-" << stext << ">\n"; + if (pUnterm) { + QStringList::Iterator lst = retList.fromLast(); + if (lst != retList.end()) + { + stext = *lst + stext; + retList.remove(lst); + } + } + int i; + if (!unterm) + { + while (stext.endsWith("\r")) { + stext.truncate(stext.length()-1); + } + + i = stext.findRev('\r'); + if (i > -1) { + stext = stext.mid(i+1); + } + } + + pUnterm = unterm; + + retList << stext; + // kdDebug() << "++" << stext << "\n"; + if (stext.right(2) == SHPROMPT) { // Shell prompt + emit textIn("\r \n", false); + finish(PROMPT); + } else if (loginSession) { + QRegExp rx( "^[^:]+:[\\s]*$"); // Password prompt + if (rx.search(retList.last()) >= 0) { + kdDebug() << loginSession << " " <<retList.last()<< " Match password p\n"; + finish(PASSWORD); + } + } + } + pty->ackRead(); +} + +void kpPty::keyOut(char ch) +{ + QCString s(2); + s[0] = ch; + s[1] = '\0'; + pty->writeStdin(s, false); +} + +void kpPty::done() +{ + int ret = pty->exitStatus(); + QString stext; + + //kdDebug() << "Done (" << ret << ")" << endl; + + finish(ret); +} + +void kpPty::slotTimeout() +{ + kdDebug() << "Timeout..............\n"; + finish(TIMEOUT); +} +#include "kpPty.moc" |