diff options
Diffstat (limited to 'kioslave/sftp')
-rw-r--r-- | kioslave/sftp/AUTHORS | 3 | ||||
-rw-r--r-- | kioslave/sftp/CHANGELOG | 59 | ||||
-rw-r--r-- | kioslave/sftp/CMakeLists.txt | 37 | ||||
-rw-r--r-- | kioslave/sftp/DEBUGGING | 12 | ||||
-rw-r--r-- | kioslave/sftp/Makefile.am | 25 | ||||
-rw-r--r-- | kioslave/sftp/TODO | 5 | ||||
-rw-r--r-- | kioslave/sftp/atomicio.cpp | 67 | ||||
-rw-r--r-- | kioslave/sftp/atomicio.h | 39 | ||||
-rw-r--r-- | kioslave/sftp/kio_sftp.cpp | 2282 | ||||
-rw-r--r-- | kioslave/sftp/kio_sftp.h | 149 | ||||
-rw-r--r-- | kioslave/sftp/ksshprocess.cpp | 1114 | ||||
-rw-r--r-- | kioslave/sftp/ksshprocess.h | 623 | ||||
-rw-r--r-- | kioslave/sftp/ksshprocesstest.cpp | 98 | ||||
-rw-r--r-- | kioslave/sftp/process.cpp | 493 | ||||
-rw-r--r-- | kioslave/sftp/process.h | 148 | ||||
-rw-r--r-- | kioslave/sftp/sftp.h | 91 | ||||
-rw-r--r-- | kioslave/sftp/sftp.protocol | 84 | ||||
-rw-r--r-- | kioslave/sftp/sftpfileattr.cpp | 346 | ||||
-rw-r--r-- | kioslave/sftp/sftpfileattr.h | 261 |
19 files changed, 0 insertions, 5936 deletions
diff --git a/kioslave/sftp/AUTHORS b/kioslave/sftp/AUTHORS deleted file mode 100644 index c763d00bc..000000000 --- a/kioslave/sftp/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -Dawit Alemayehu <adawit@kde.org> -Lucas Fisher <ljfisher@iastate.edu> - diff --git a/kioslave/sftp/CHANGELOG b/kioslave/sftp/CHANGELOG deleted file mode 100644 index b60e7f44b..000000000 --- a/kioslave/sftp/CHANGELOG +++ /dev/null @@ -1,59 +0,0 @@ -- add dialog to ask for username -- rename() causes SSH to die -- How to handle overwrite? -- After the user cancels with the stop button, we get ERR_CANNOT_LAUNCH_PROCESS - errors, until we kill the ioslave. Same thing after trying the wrong passwd - too many times. - This is happening because TDEProcess thinks that the ssh process is still running - even though it exited. -- How to handle password and caching? - - Write our own askpass program using kde - - set env SSH_ASKPASS_PROGRAM before launching - -how to do this? TDEProcess doesn't give us access to env variables. - - Our askpass program can probably talk to the tdesu daemon to implement caching. -- chmod() succeeds, but konqueror always puts permissions to 0 afterwards. The properties - dialog is right though. - Nevermind - ftp ioslave does this too! Maybe a bug with konqueror. -- stat does not give us group and owner names, only numbers. We could cache the uid/name and - gid/name so we can give names when doing a stat also. - -7-13-2001 - ReadLink stopped working. sftp server always retuns a file not found error - - Need to implement 64 bit file lengths-->write DataStream << for u_int64 - Still need to offer 32 bit size since this is what kde wants. ljf - - rename() isn't exactly causing ioslave to die. The stat of the file we are - going to rename is killing the slave. The slave dies in the statEntry() call. - I don't know what I am putting in the UDS entry that is causing this. ljf -7-14-2001 - got put, mimetype working ljf - - fixed readlink problem - I was sending the wrong path. doh! ljf -7-17-2001 - If the user changes the host, the slave doesn't change host! setHost() is not - called, nor is another ioslave spawned. I have not investigated the problem - yet. ljf -7-21-2001 - got slave working with kde 2.2 cvs -7-22-2001 - probable solution to getting password prompt -- open with controlling - but don't connect stdin/out to terminal. duh! -8-9-2001 - Doh! I haven't kept very good logs. Look at the cvs logs for better info. - - At this point kio_sftp is using KSshProcess which I wrote in order to make - a standard interface to the various version of ssh out there. So far it is - working fairly well. We also now report host key changes to the user and - allow them to choose whether or not to continue. This is a big improvement. - - Todo: support use of keys and ssh agent - put()'s resume functionality needs some work -1-26-2002 - Rewrote put() following the ftp::put() so it should behave the same way - - increase the size of the data packet we ask for in ::get up to 60k. - Through-put increases nicely. - - Call closeConnection() from construction. Keeps from having unused ssh - processes laying around after failed operations. -2-19-2002 - get() now emits mimetype, fixes problem with konqi not downloading file for - viewing in kpart. - - get port number using getservbyname instead of hard coding it. -2-27-2002 - testing before committing back to cvs, test with openssh 3, ssh 3 -6-?-2002 - rewrote openConnection() to using new KSshProcess connect proceedures -7-20-2002 - Don't put up a message box when auth fails because of now or changed key, - the call to error() will put up the dialog. - - Connect fails and no more password are prompted for when we get - ERR_AUTH_FAILED from KSshProcess. -9-15-2002 - stuff -9-29-2002 - the last i18n string updates, fixed problem with uploading files to - openssh server. -5-8-2003 - check whether operation types are supported by the negotiated sftp - protocol version diff --git a/kioslave/sftp/CMakeLists.txt b/kioslave/sftp/CMakeLists.txt deleted file mode 100644 index c068166b0..000000000 --- a/kioslave/sftp/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -################################################# -# -# (C) 2010-2011 Serghei Amelian -# serghei (DOT) amelian (AT) gmail.com -# -# Improvements and feedback are welcome -# -# This file is released under GPL >= 2 -# -################################################# - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR} - ${TDE_INCLUDE_DIR} - ${TQT_INCLUDE_DIRS} -) - -link_directories( - ${TQT_LIBRARY_DIRS} -) - - -##### other data ################################ - -install( FILES sftp.protocol DESTINATION ${SERVICES_INSTALL_DIR} ) - - -##### kio_sftp (module) ######################### - -set( target kio_sftp ) - -tde_add_kpart( ${target} AUTOMOC - SOURCES process.cpp atomicio.cpp kio_sftp.cpp sftpfileattr.cpp ksshprocess.cpp - LINK kio-shared - DESTINATION ${PLUGIN_INSTALL_DIR} -) diff --git a/kioslave/sftp/DEBUGGING b/kioslave/sftp/DEBUGGING deleted file mode 100644 index 89ae8fe18..000000000 --- a/kioslave/sftp/DEBUGGING +++ /dev/null @@ -1,12 +0,0 @@ -DEBUGGING - -The best way to debug this slave is to send debug info to a -file using 'kdebugDialog --fullmode'. Then you can 'tail -f' the file to -see debug messages in real-time. - -I also suggest getting the openssh source and recompiling sftp-server to -send messages to the auth log. This can be done in sftp-server.c be defining -DEBUG_SFTP_SERVER. - -You can do the same with the ssh client by finding the two calls to log_init() -in ssh.c and changing the last argument from 1 to 0 and recompiling. diff --git a/kioslave/sftp/Makefile.am b/kioslave/sftp/Makefile.am deleted file mode 100644 index abbb91323..000000000 --- a/kioslave/sftp/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -## Makefile.am of tdebase/kioslave/sftp - -INCLUDES = $(all_includes) -AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor -METASOURCES = AUTO - -####### Files - -check_PROGRAMS = ksshprocesstest - -ksshprocesstest_SOURCES = ksshprocesstest.cpp -ksshprocesstest_LDADD = $(LIB_KSYCOCA) ksshprocess.lo process.lo atomicio.lo - -kde_module_LTLIBRARIES = kio_sftp.la - -kio_sftp_la_SOURCES = process.cpp atomicio.cpp kio_sftp.cpp sftpfileattr.cpp ksshprocess.cpp -kio_sftp_la_LIBADD = $(LIB_KIO) -kio_sftp_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -noinst_HEADERS = atomicio.h kio_sftp.h ksshprocess.h process.h sftpfileattr.h sftp.h - -kdelnk_DATA = sftp.protocol -kdelnkdir = $(kde_servicesdir) - -messages: - $(XGETTEXT) *.cpp -o $(podir)/kio_sftp.pot diff --git a/kioslave/sftp/TODO b/kioslave/sftp/TODO deleted file mode 100644 index 0f1411317..000000000 --- a/kioslave/sftp/TODO +++ /dev/null @@ -1,5 +0,0 @@ -TODO: -===== - -- Support for use of public keys, maybe ssh-agent, a key management app, etc. - diff --git a/kioslave/sftp/atomicio.cpp b/kioslave/sftp/atomicio.cpp deleted file mode 100644 index 057f20fe9..000000000 --- a/kioslave/sftp/atomicio.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -//#include "includes.h" -//RCSID("$OpenBSD: atomicio.c,v 1.9 2001/03/02 18:54:30 deraadt Exp $"); - -//#include "xmalloc.h" -#include "atomicio.h" -#include <unistd.h> -#include <errno.h> -#include <kdebug.h> - -/* - * ensure all of data on socket comes through. f==read || f==write - */ - -ssize_t atomicio(int fd, char *_s, size_t n, bool read) -{ - char *s = _s; - ssize_t res; - ssize_t pos = 0; - - while (n > pos) { - if( read) - res = ::read(fd, s + pos, n - pos); - else - res = ::write(fd, s + pos, n - pos); - - switch (res) { - case -1: - kdDebug() << "atomicio(): errno=" << errno << endl; -#ifdef EWOULDBLOCK - if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) -#else - if (errno == EINTR || errno == EAGAIN) -#endif - continue; - case 0: - return (res); - default: - pos += res; - } - } - return (pos); -} diff --git a/kioslave/sftp/atomicio.h b/kioslave/sftp/atomicio.h deleted file mode 100644 index 4468757d5..000000000 --- a/kioslave/sftp/atomicio.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef atomicio_h -#define atomicio_h - -/* $OpenBSD: atomicio.h,v 1.3 2001/03/02 18:54:30 deraadt Exp $ */ - -/* - * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <unistd.h> - -/* - * Ensure all of data on socket comes through. f==read || f==write - */ -ssize_t atomicio(int fd, char *_s, size_t n, bool read = true); - -#endif diff --git a/kioslave/sftp/kio_sftp.cpp b/kioslave/sftp/kio_sftp.cpp deleted file mode 100644 index 73f5bfc6d..000000000 --- a/kioslave/sftp/kio_sftp.cpp +++ /dev/null @@ -1,2282 +0,0 @@ -/*************************************************************************** - sftp.cpp - description - ------------------- - begin : Fri Jun 29 23:45:40 CDT 2001 - copyright : (C) 2001 by Lucas Fisher - email : ljfisher@purdue.edu - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ - -/* -DEBUGGING -We are pretty much left with kdDebug messages for debugging. We can't use a gdb -as described in the ioslave DEBUG.howto because tdeinit has to run in a terminal. -Ssh will detect this terminal and ask for a password there, but will just get garbage. -So we can't connect. -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <fcntl.h> - -#include <tqcstring.h> -#include <tqstring.h> -#include <tqobject.h> -#include <tqstrlist.h> -#include <tqfile.h> -#include <tqbuffer.h> - -#include <stdlib.h> -#include <unistd.h> -#include <signal.h> -#include <errno.h> -#include <ctype.h> -#include <time.h> -#include <netdb.h> -#include <string.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include <kapplication.h> -#include <kuser.h> -#include <kdebug.h> -#include <kmessagebox.h> -#include <kinstance.h> -#include <kglobal.h> -#include <kstandarddirs.h> -#include <klocale.h> -#include <kurl.h> -#include <kio/ioslave_defaults.h> -#include <kmimetype.h> -#include <kmimemagic.h> -#include <klargefile.h> -#include <kremoteencoding.h> - -#include "sftp.h" -#include "kio_sftp.h" -#include "atomicio.h" -#include "sftpfileattr.h" -#include "ksshprocess.h" - - -using namespace TDEIO; -extern "C" -{ - int KDE_EXPORT kdemain( int argc, char **argv ) - { - TDEInstance instance( "kio_sftp" ); - - kdDebug(KIO_SFTP_DB) << "*** Starting kio_sftp " << endl; - - if (argc != 4) { - kdDebug(KIO_SFTP_DB) << "Usage: kio_sftp protocol domain-socket1 domain-socket2" << endl; - exit(-1); - } - - sftpProtocol slave(argv[2], argv[3]); - slave.dispatchLoop(); - - kdDebug(KIO_SFTP_DB) << "*** kio_sftp Done" << endl; - return 0; - } -} - - -/* - * This helper handles some special issues (blocking and interrupted - * system call) when writing to a file handle. - * - * @return 0 on success or an error code on failure (ERR_COULD_NOT_WRITE, - * ERR_DISK_FULL, ERR_CONNECTION_BROKEN). - */ -static int writeToFile (int fd, const char *buf, size_t len) -{ - while (len > 0) - { - ssize_t written = ::write(fd, buf, len); - if (written >= 0) - { - buf += written; - len -= written; - continue; - } - - switch(errno) - { - case EINTR: - continue; - case EPIPE: - return ERR_CONNECTION_BROKEN; - case ENOSPC: - return ERR_DISK_FULL; - default: - return ERR_COULD_NOT_WRITE; - } - } - return 0; -} - -sftpProtocol::sftpProtocol(const TQCString &pool_socket, const TQCString &app_socket) - : SlaveBase("kio_sftp", pool_socket, app_socket), - mConnected(false), mPort(-1), mMsgId(0) { - kdDebug(KIO_SFTP_DB) << "sftpProtocol(): pid = " << getpid() << endl; -} - - -sftpProtocol::~sftpProtocol() { - kdDebug(KIO_SFTP_DB) << "~sftpProtocol(): pid = " << getpid() << endl; - closeConnection(); -} - -/** - * Type is a sftp packet type found in .sftp.h'. - * Example: SSH2_FXP_READLINK, SSH2_FXP_RENAME, etc. - * - * Returns true if the type is supported by the sftp protocol - * version negotiated by the client and server (sftpVersion). - */ -bool sftpProtocol::isSupportedOperation(int type) { - switch (type) { - case SSH2_FXP_VERSION: - case SSH2_FXP_STATUS: - case SSH2_FXP_HANDLE: - case SSH2_FXP_DATA: - case SSH2_FXP_NAME: - case SSH2_FXP_ATTRS: - case SSH2_FXP_INIT: - case SSH2_FXP_OPEN: - case SSH2_FXP_CLOSE: - case SSH2_FXP_READ: - case SSH2_FXP_WRITE: - case SSH2_FXP_LSTAT: - case SSH2_FXP_FSTAT: - case SSH2_FXP_SETSTAT: - case SSH2_FXP_FSETSTAT: - case SSH2_FXP_OPENDIR: - case SSH2_FXP_READDIR: - case SSH2_FXP_REMOVE: - case SSH2_FXP_MKDIR: - case SSH2_FXP_RMDIR: - case SSH2_FXP_REALPATH: - case SSH2_FXP_STAT: - return true; - case SSH2_FXP_RENAME: - return sftpVersion >= 2 ? true : false; - case SSH2_FXP_EXTENDED: - case SSH2_FXP_EXTENDED_REPLY: - case SSH2_FXP_READLINK: - case SSH2_FXP_SYMLINK: - return sftpVersion >= 3 ? true : false; - default: - kdDebug(KIO_SFTP_DB) << "isSupportedOperation(type:" - << type << "): unrecognized operation type" << endl; - break; - } - - return false; -} - -void sftpProtocol::copy(const KURL &src, const KURL &dest, int permissions, bool overwrite) -{ - kdDebug(KIO_SFTP_DB) << "copy(): " << src << " -> " << dest << endl; - - bool srcLocal = src.isLocalFile(); - bool destLocal = dest.isLocalFile(); - - if ( srcLocal && !destLocal ) // Copy file -> sftp - sftpCopyPut(src, dest, permissions, overwrite); - else if ( destLocal && !srcLocal ) // Copy sftp -> file - sftpCopyGet(dest, src, permissions, overwrite); - else - error(ERR_UNSUPPORTED_ACTION, TQString::null); -} - -void sftpProtocol::sftpCopyGet(const KURL& dest, const KURL& src, int mode, bool overwrite) -{ - kdDebug(KIO_SFTP_DB) << "sftpCopyGet(): " << src << " -> " << dest << endl; - - // Attempt to establish a connection... - openConnection(); - if( !mConnected ) - return; - - KDE_struct_stat buff_orig; - TQCString dest_orig ( TQFile::encodeName(dest.path()) ); - bool origExists = (KDE_lstat( dest_orig.data(), &buff_orig ) != -1); - - if (origExists) - { - if (S_ISDIR(buff_orig.st_mode)) - { - error(ERR_IS_DIRECTORY, dest.prettyURL()); - return; - } - - if (!overwrite) - { - error(ERR_FILE_ALREADY_EXIST, dest.prettyURL()); - return; - } - } - - TDEIO::filesize_t offset = 0; - TQCString dest_part ( dest_orig + ".part" ); - - int fd = -1; - bool partExists = false; - bool markPartial = config()->readBoolEntry("MarkPartial", true); - - if (markPartial) - { - KDE_struct_stat buff_part; - partExists = (KDE_stat( dest_part.data(), &buff_part ) != -1); - - if (partExists && buff_part.st_size > 0 && S_ISREG(buff_part.st_mode)) - { - if (canResume( buff_part.st_size )) - { - offset = buff_part.st_size; - kdDebug(KIO_SFTP_DB) << "sftpCopyGet: Resuming @ " << offset << endl; - } - } - - if (offset > 0) - { - fd = KDE_open(dest_part.data(), O_RDWR); - offset = KDE_lseek(fd, 0, SEEK_END); - if (offset == 0) - { - error(ERR_CANNOT_RESUME, dest.prettyURL()); - return; - } - } - else - { - // Set up permissions properly, based on what is done in file io-slave - int openFlags = (O_CREAT | O_TRUNC | O_WRONLY); - int initialMode = (mode == -1) ? 0666 : (mode | S_IWUSR); - fd = KDE_open(dest_part.data(), openFlags, initialMode); - } - } - else - { - // Set up permissions properly, based on what is done in file io-slave - int openFlags = (O_CREAT | O_TRUNC | O_WRONLY); - int initialMode = (mode == -1) ? 0666 : (mode | S_IWUSR); - fd = KDE_open(dest_orig.data(), openFlags, initialMode); - } - - if(fd == -1) - { - kdDebug(KIO_SFTP_DB) << "sftpCopyGet: Unable to open (" << fd << ") for writting." << endl; - if (errno == EACCES) - error (ERR_WRITE_ACCESS_DENIED, dest.prettyURL()); - else - error (ERR_CANNOT_OPEN_FOR_WRITING, dest.prettyURL()); - return; - } - - Status info = sftpGet(src, offset, fd); - if ( info.code != 0 ) - { - // Should we keep the partially downloaded file ?? - TDEIO::filesize_t size = config()->readNumEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE); - if (info.size < size) - ::remove(dest_part.data()); - - error(info.code, info.text); - return; - } - - if (::close(fd) != 0) - { - error(ERR_COULD_NOT_WRITE, dest.prettyURL()); - return; - } - - // - if (markPartial) - { - if (::rename(dest_part.data(), dest_orig.data()) != 0) - { - error (ERR_CANNOT_RENAME_PARTIAL, dest_part); - return; - } - } - - data(TQByteArray()); - kdDebug(KIO_SFTP_DB) << "sftpCopyGet(): emit finished()" << endl; - finished(); -} - -sftpProtocol::Status sftpProtocol::sftpGet( const KURL& src, TDEIO::filesize_t offset, int fd ) -{ - int code; - sftpFileAttr attr(remoteEncoding()); - - Status res; - res.code = 0; - res.size = 0; - - kdDebug(KIO_SFTP_DB) << "sftpGet(): " << src << endl; - - // stat the file first to get its size - if( (code = sftpStat(src, attr)) != SSH2_FX_OK ) { - return doProcessStatus(code, src.prettyURL()); - } - - // We cannot get file if it is a directory - if( attr.fileType() == S_IFDIR ) { - res.text = src.prettyURL(); - res.code = ERR_IS_DIRECTORY; - return res; - } - - TDEIO::filesize_t fileSize = attr.fileSize(); - TQ_UINT32 pflags = SSH2_FXF_READ; - attr.clear(); - - TQByteArray handle; - if( (code = sftpOpen(src, pflags, attr, handle)) != SSH2_FX_OK ) { - res.text = src.prettyURL(); - res.code = ERR_CANNOT_OPEN_FOR_READING; - return res; - } - - // needed for determining mimetype - // note: have to emit mimetype before emitting totalsize. - TQByteArray buff; - TQByteArray mimeBuffer; - - unsigned int oldSize; - bool foundMimetype = false; - - // How big should each data packet be? Definitely not bigger than 64kb or - // you will overflow the 2 byte size variable in a sftp packet. - TQ_UINT32 len = 60*1024; - code = SSH2_FX_OK; - - kdDebug(KIO_SFTP_DB) << "sftpGet(): offset = " << offset << endl; - while( code == SSH2_FX_OK ) { - if( (code = sftpRead(handle, offset, len, buff)) == SSH2_FX_OK ) { - offset += buff.size(); - - // save data for mimetype. Pretty much follows what is in the ftp ioslave - if( !foundMimetype ) { - oldSize = mimeBuffer.size(); - mimeBuffer.resize(oldSize + buff.size()); - memcpy(mimeBuffer.data()+oldSize, buff.data(), buff.size()); - - if( mimeBuffer.size() > 1024 || offset == fileSize ) { - // determine mimetype - KMimeMagicResult* result = - KMimeMagic::self()->findBufferFileType(mimeBuffer, src.fileName()); - kdDebug(KIO_SFTP_DB) << "sftpGet(): mimetype is " << - result->mimeType() << endl; - mimeType(result->mimeType()); - - // Always send the total size after emitting mime-type... - totalSize(fileSize); - - if (fd == -1) - data(mimeBuffer); - else - { - if ( (res.code=writeToFile(fd, mimeBuffer.data(), mimeBuffer.size())) != 0 ) - return res; - } - - processedSize(mimeBuffer.size()); - mimeBuffer.resize(0); - foundMimetype = true; - } - } - else { - if (fd == -1) - data(buff); - else - { - if ( (res.code= writeToFile(fd, buff.data(), buff.size())) != 0 ) - return res; - } - processedSize(offset); - } - } - - /* - Check if slave was killed. According to slavebase.h we need to leave - the slave methods as soon as possible if the slave is killed. This - allows the slave to be cleaned up properly. - */ - if( wasKilled() ) { - res.text = i18n("An internal error occurred. Please retry the request again."); - res.code = ERR_UNKNOWN; - return res; - } - } - - if( code != SSH2_FX_EOF ) { - res.text = src.prettyURL(); - res.code = ERR_COULD_NOT_READ; // return here or still send empty array to indicate end of read? - } - - res.size = offset; - sftpClose(handle); - processedSize (offset); - return res; -} - -void sftpProtocol::get(const KURL& url) { - kdDebug(KIO_SFTP_DB) << "get(): " << url << endl ; - - openConnection(); - if( !mConnected ) - return; - - // Get resume offset - TQ_UINT64 offset = config()->readUnsignedLongNumEntry("resume"); - if( offset > 0 ) { - canResume(); - kdDebug(KIO_SFTP_DB) << "get(): canResume(), offset = " << offset << endl; - } - - Status info = sftpGet(url, offset); - - if (info.code != 0) - { - error(info.code, info.text); - return; - } - - data(TQByteArray()); - kdDebug(KIO_SFTP_DB) << "get(): emit finished()" << endl; - finished(); -} - - -void sftpProtocol::setHost (const TQString& h, int port, const TQString& user, const TQString& pass) -{ - kdDebug(KIO_SFTP_DB) << "setHost(): " << user << "@" << h << ":" << port << endl; - - if( mHost != h || mPort != port || user != mUsername || mPassword != pass ) - closeConnection(); - - mHost = h; - - if( port > 0 ) - mPort = port; - else { - mPort = -1; - } - - mUsername = user; - mPassword = pass; - - if (user.isEmpty()) - { - KUser u; - mUsername = u.loginName(); - } -} - - -void sftpProtocol::openConnection() { - - if(mConnected) - return; - - kdDebug(KIO_SFTP_DB) << "openConnection(): " << mUsername << "@" - << mHost << ":" << mPort << endl; - - infoMessage( i18n("Opening SFTP connection to host <b>%1:%2</b>").arg(mHost).arg(mPort)); - - if( mHost.isEmpty() ) { - kdDebug(KIO_SFTP_DB) << "openConnection(): Need hostname..." << endl; - error(ERR_UNKNOWN_HOST, i18n("No hostname specified")); - return; - } - - //////////////////////////////////////////////////////////////////////////// - // Setup AuthInfo for use with password caching and the - // password dialog box. - AuthInfo info; - info.url.setProtocol("sftp"); - info.url.setHost(mHost); - info.url.setPort(mPort); - info.url.setUser(mUsername); - info.caption = i18n("SFTP Login"); - info.comment = "sftp://" + mHost + ":" + TQString::number(mPort); - info.commentLabel = i18n("site:"); - info.username = mUsername; - info.keepPassword = true; - - /////////////////////////////////////////////////////////////////////////// - // Check for cached authentication info if a username AND password were - // not specified in setHost(). - if( mUsername.isEmpty() && mPassword.isEmpty() ) { - kdDebug(KIO_SFTP_DB) << "openConnection(): checking cache " - << "info.username = " << info.username - << ", info.url = " << info.url.prettyURL() << endl; - - if( checkCachedAuthentication(info) ) { - mUsername = info.username; - mPassword = info.password; - } - } - - /////////////////////////////////////////////////////////////////////////// - // Now setup our ssh options. If we found a cached username - // and password we set the SSH_PASSWORD and SSH_USERNAME - // options right away. Otherwise we wait. The other options are - // necessary for running sftp over ssh. - KSshProcess::SshOpt opt; // a ssh option, this can be reused - KSshProcess::SshOptList opts; // list of SshOpts - KSshProcess::SshOptListIterator passwdIt; // points to the opt in opts that specifies the password - KSshProcess::SshOptListIterator usernameIt; - -// opt.opt = KSshProcess::SSH_VERBOSE; -// opts.append(opt); -// opts.append(opt); - - if( mPort != -1 ) { - opt.opt = KSshProcess::SSH_PORT; - opt.num = mPort; - opts.append(opt); - } - - opt.opt = KSshProcess::SSH_SUBSYSTEM; - opt.str = "sftp"; - opts.append(opt); - - opt.opt = KSshProcess::SSH_FORWARDX11; - opt.boolean = false; - opts.append(opt); - - opt.opt = KSshProcess::SSH_FORWARDAGENT; - opt.boolean = false; - opts.append(opt); - - opt.opt = KSshProcess::SSH_PROTOCOL; - opt.num = 2; - opts.append(opt); - - opt.opt = KSshProcess::SSH_HOST; - opt.str = mHost; - opts.append(opt); - - opt.opt = KSshProcess::SSH_ESCAPE_CHAR; - opt.num = -1; // don't use any escape character - opts.append(opt); - - // set the username and password if we have them - if( !mUsername.isEmpty() ) { - opt.opt = KSshProcess::SSH_USERNAME; - opt.str = mUsername; - usernameIt = opts.append(opt); - } - - if( !mPassword.isEmpty() ) { - opt.opt = KSshProcess::SSH_PASSWD; - opt.str = mPassword; - passwdIt = opts.append(opt); - } - - ssh.setOptions(opts); - ssh.printArgs(); - - /////////////////////////////////////////////////////////////////////////// - // Start the ssh connection process. - // - - int err; // error code from KSshProcess - TQString msg; // msg for dialog box - TQString caption; // dialog box caption - bool firstTime = true; - bool dlgResult; - - while( !(mConnected = ssh.connect()) ) { - err = ssh.error(); - kdDebug(KIO_SFTP_DB) << "openConnection(): " - "Got " << err << " from KSshProcess::connect()" << endl; - - switch(err) { - case KSshProcess::ERR_NEED_PASSWD: - case KSshProcess::ERR_NEED_PASSPHRASE: - // At this point we know that either we didn't set - // an username or password in the ssh options list, - // or what we did pass did not work. Therefore we - // must prompt the user. - if( err == KSshProcess::ERR_NEED_PASSPHRASE ) - info.prompt = i18n("Please enter your username and key passphrase."); - else - info.prompt = i18n("Please enter your username and password."); - - kdDebug(KIO_SFTP_DB) << "openConnection(): info.username = " << info.username - << ", info.url = " << info.url.prettyURL() << endl; - - if( firstTime ) - dlgResult = openPassDlg(info); - else - dlgResult = openPassDlg(info, i18n("Incorrect username or password")); - - if( dlgResult ) { - if( info.username.isEmpty() || info.password.isEmpty() ) { - error(ERR_COULD_NOT_AUTHENTICATE, - i18n("Please enter a username and password")); - continue; - } - } - else { - // user canceled or dialog failed to open - error(ERR_USER_CANCELED, TQString::null); - kdDebug(KIO_SFTP_DB) << "openConnection(): user canceled, dlgResult = " << dlgResult << endl; - closeConnection(); - return; - } - - firstTime = false; - - // Check if the username has changed. SSH only accepts - // the username at startup. If the username has changed - // we must disconnect ssh, change the SSH_USERNAME - // option, and reset the option list. We will also set - // the password option so the user is not prompted for - // it again. - if( mUsername != info.username ) { - kdDebug(KIO_SFTP_DB) << "openConnection(): Username changed from " - << mUsername << " to " << info.username << endl; - - ssh.disconnect(); - - // if we haven't yet added the username - // or password option to the ssh options list then - // the iterators will be equal to the empty iterator. - // Create the opts now and add them to the opt list. - if( usernameIt == KSshProcess::SshOptListIterator() ) { - kdDebug(KIO_SFTP_DB) << "openConnection(): " - "Adding username to options list" << endl; - opt.opt = KSshProcess::SSH_USERNAME; - usernameIt = opts.append(opt); - } - - if( passwdIt == KSshProcess::SshOptListIterator() ) { - kdDebug(KIO_SFTP_DB) << "openConnection(): " - "Adding password to options list" << endl; - opt.opt = KSshProcess::SSH_PASSWD; - passwdIt = opts.append(opt); - } - - (*usernameIt).str = info.username; - (*passwdIt).str = info.password; - ssh.setOptions(opts); - ssh.printArgs(); - } - else { // just set the password - ssh.setPassword(info.password); - } - - mUsername = info.username; - mPassword = info.password; - - break; - - case KSshProcess::ERR_NEW_HOST_KEY: - caption = i18n("Warning: Cannot verify host's identity."); - msg = ssh.errorMsg(); - if( KMessageBox::Yes != messageBox(WarningYesNo, msg, caption) ) { - closeConnection(); - error(ERR_USER_CANCELED, TQString::null); - return; - } - ssh.acceptHostKey(true); - break; - - case KSshProcess::ERR_DIFF_HOST_KEY: - caption = i18n("Warning: Host's identity changed."); - msg = ssh.errorMsg(); - if( KMessageBox::Yes != messageBox(WarningYesNo, msg, caption) ) { - closeConnection(); - error(ERR_USER_CANCELED, TQString::null); - return; - } - ssh.acceptHostKey(true); - break; - - case KSshProcess::ERR_AUTH_FAILED: - infoMessage(i18n("Authentication failed.")); - error(ERR_COULD_NOT_LOGIN, i18n("Authentication failed.")); - return; - - case KSshProcess::ERR_AUTH_FAILED_NEW_KEY: - msg = ssh.errorMsg(); - error(ERR_COULD_NOT_LOGIN, msg); - return; - - case KSshProcess::ERR_AUTH_FAILED_DIFF_KEY: - msg = ssh.errorMsg(); - error(ERR_COULD_NOT_LOGIN, msg); - return; - - case KSshProcess::ERR_CLOSED_BY_REMOTE_HOST: - infoMessage(i18n("Connection failed.")); - caption = i18n("Connection closed by remote host."); - msg = ssh.errorMsg(); - messageBox(Information, msg, caption); - closeConnection(); - error(ERR_COULD_NOT_LOGIN, msg); - return; - - case KSshProcess::ERR_INTERACT: - case KSshProcess::ERR_INTERNAL: - case KSshProcess::ERR_UNKNOWN: - case KSshProcess::ERR_INVALID_STATE: - case KSshProcess::ERR_CANNOT_LAUNCH: - case KSshProcess::ERR_HOST_KEY_REJECTED: - default: - infoMessage(i18n("Connection failed.")); - caption = i18n("Unexpected SFTP error: %1").arg(err); - msg = ssh.errorMsg(); - messageBox(Information, msg, caption); - closeConnection(); - error(ERR_UNKNOWN, msg); - return; - } - } - - // catch all in case we did something wrong above - if( !mConnected ) { - error(ERR_INTERNAL, TQString::null); - return; - } - - // Now send init packet. - kdDebug(KIO_SFTP_DB) << "openConnection(): Sending SSH2_FXP_INIT packet." << endl; - TQByteArray p; - TQDataStream packet(p, IO_WriteOnly); - packet << (TQ_UINT32)5; // packet length - packet << (TQ_UINT8) SSH2_FXP_INIT; // packet type - packet << (TQ_UINT32)SSH2_FILEXFER_VERSION; // client version - - putPacket(p); - getPacket(p); - - TQDataStream s(p, IO_ReadOnly); - TQ_UINT32 version; - TQ_UINT8 type; - s >> type; - kdDebug(KIO_SFTP_DB) << "openConnection(): Got type " << type << endl; - - if( type == SSH2_FXP_VERSION ) { - s >> version; - kdDebug(KIO_SFTP_DB) << "openConnection(): Got server version " << version << endl; - - // XXX Get extensions here - sftpVersion = version; - - /* Server should return lowest common version supported by - * client and server, but double check just in case. - */ - if( sftpVersion > SSH2_FILEXFER_VERSION ) { - error(ERR_UNSUPPORTED_PROTOCOL, - i18n("SFTP version %1").arg(version)); - closeConnection(); - return; - } - } - else { - error(ERR_UNKNOWN, i18n("Protocol error.")); - closeConnection(); - return; - } - - // Login succeeded! - infoMessage(i18n("Successfully connected to %1").arg(mHost)); - info.url.setProtocol("sftp"); - info.url.setHost(mHost); - info.url.setPort(mPort); - info.url.setUser(mUsername); - info.username = mUsername; - info.password = mPassword; - kdDebug(KIO_SFTP_DB) << "sftpProtocol(): caching info.username = " << info.username << - ", info.url = " << info.url.prettyURL() << endl; - cacheAuthentication(info); - mConnected = true; - connected(); - - mPassword.fill('x'); - info.password.fill('x'); - - return; -} - -void sftpProtocol::closeConnection() { - kdDebug(KIO_SFTP_DB) << "closeConnection()" << endl; - ssh.disconnect(); - mConnected = false; -} - -void sftpProtocol::sftpCopyPut(const KURL& src, const KURL& dest, int permissions, bool overwrite) { - - KDE_struct_stat buff; - TQCString file (TQFile::encodeName(src.path())); - - if (KDE_lstat(file.data(), &buff) == -1) { - error (ERR_DOES_NOT_EXIST, src.prettyURL()); - return; - } - - if (S_ISDIR (buff.st_mode)) { - error (ERR_IS_DIRECTORY, src.prettyURL()); - return; - } - - int fd = KDE_open (file.data(), O_RDONLY); - if (fd == -1) { - error (ERR_CANNOT_OPEN_FOR_READING, src.prettyURL()); - return; - } - - totalSize (buff.st_size); - - sftpPut (dest, permissions, false, overwrite, fd); - - // Close the file descriptor... - ::close( fd ); -} - -void sftpProtocol::sftpPut( const KURL& dest, int permissions, bool resume, bool overwrite, int fd ) { - - openConnection(); - if( !mConnected ) - return; - - kdDebug(KIO_SFTP_DB) << "sftpPut(): " << dest - << ", resume=" << resume - << ", overwrite=" << overwrite << endl; - - KURL origUrl( dest ); - sftpFileAttr origAttr(remoteEncoding()); - bool origExists = false; - - // Stat original (without part ext) to see if it already exists - int code = sftpStat(origUrl, origAttr); - - if( code == SSH2_FX_OK ) { - kdDebug(KIO_SFTP_DB) << "sftpPut(): <file> already exists" << endl; - - // Delete remote file if its size is zero - if( origAttr.fileSize() == 0 ) { - if( sftpRemove(origUrl, true) != SSH2_FX_OK ) { - error(ERR_CANNOT_DELETE_ORIGINAL, origUrl.prettyURL()); - return; - } - } - else { - origExists = true; - } - } - else if( code != SSH2_FX_NO_SUCH_FILE ) { - processStatus(code, origUrl.prettyURL()); - return; - } - - // Do not waste time/resources with more remote stat calls if the file exists - // and we weren't instructed to overwrite it... - if( origExists && !overwrite ) { - error(ERR_FILE_ALREADY_EXIST, origUrl.prettyURL()); - return; - } - - // Stat file with part ext to see if it already exists... - KURL partUrl( origUrl ); - partUrl.setFileName( partUrl.fileName() + ".part" ); - - TQ_UINT64 offset = 0; - bool partExists = false; - bool markPartial = config()->readBoolEntry("MarkPartial", true); - - if( markPartial ) { - - sftpFileAttr partAttr(remoteEncoding()); - code = sftpStat(partUrl, partAttr); - - if( code == SSH2_FX_OK ) { - kdDebug(KIO_SFTP_DB) << "sftpPut(): .part file already exists" << endl; - partExists = true; - offset = partAttr.fileSize(); - - // If for some reason, both the original and partial files exist, - // skip resumption just like we would if the size of the partial - // file is zero... - if( origExists || offset == 0 ) - { - if( sftpRemove(partUrl, true) != SSH2_FX_OK ) { - error(ERR_CANNOT_DELETE_PARTIAL, partUrl.prettyURL()); - return; - } - - if( sftpRename(origUrl, partUrl) != SSH2_FX_OK ) { - error(ERR_CANNOT_RENAME_ORIGINAL, origUrl.prettyURL()); - return; - } - - offset = 0; - } - else if( !overwrite && !resume ) { - if (fd != -1) - resume = (KDE_lseek(fd, offset, SEEK_SET) != -1); - else - resume = canResume( offset ); - - kdDebug(KIO_SFTP_DB) << "sftpPut(): can resume = " << resume - << ", offset = " << offset; - - if( !resume ) { - error(ERR_FILE_ALREADY_EXIST, partUrl.prettyURL()); - return; - } - } - else { - offset = 0; - } - } - else if( code == SSH2_FX_NO_SUCH_FILE ) { - if( origExists && sftpRename(origUrl, partUrl) != SSH2_FX_OK ) { - error(ERR_CANNOT_RENAME_ORIGINAL, origUrl.prettyURL()); - return; - } - } - else { - processStatus(code, partUrl.prettyURL()); - return; - } - } - - // Determine the url we will actually write to... - KURL writeUrl (markPartial ? partUrl:origUrl); - - TQ_UINT32 pflags = 0; - if( overwrite && !resume ) - pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT | SSH2_FXF_TRUNC; - else if( !overwrite && !resume ) - pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT | SSH2_FXF_EXCL; - else if( overwrite && resume ) - pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT; - else if( !overwrite && resume ) - pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT | SSH2_FXF_APPEND; - - sftpFileAttr attr(remoteEncoding()); - TQByteArray handle; - - // Set the permissions of the file we write to if it didn't already exist - // and the permission info is supplied, i.e it is not -1 - if( !partExists && !origExists && permissions != -1) - attr.setPermissions(permissions); - - code = sftpOpen( writeUrl, pflags, attr, handle ); - if( code != SSH2_FX_OK ) { - - // Rename the file back to its original name if a - // put fails due to permissions problems... - if( markPartial && overwrite ) { - (void) sftpRename(partUrl, origUrl); - writeUrl = origUrl; - } - - if( code == SSH2_FX_FAILURE ) { // assume failure means file exists - error(ERR_FILE_ALREADY_EXIST, writeUrl.prettyURL()); - return; - } - else { - processStatus(code, writeUrl.prettyURL()); - return; - } - } - - long nbytes; - TQByteArray buff; - - do { - - if( fd != -1 ) { - buff.resize( 16*1024 ); - if ( (nbytes = ::read(fd, buff.data(), buff.size())) > -1 ) - buff.resize( nbytes ); - } - else { - dataReq(); - nbytes = readData( buff ); - } - - if( nbytes >= 0 ) { - if( (code = sftpWrite(handle, offset, buff)) != SSH2_FX_OK ) { - error(ERR_COULD_NOT_WRITE, dest.prettyURL()); - return; - } - - offset += nbytes; - processedSize(offset); - - /* Check if slave was killed. According to slavebase.h we - * need to leave the slave methods as soon as possible if - * the slave is killed. This allows the slave to be cleaned - * up properly. - */ - if( wasKilled() ) { - sftpClose(handle); - closeConnection(); - error(ERR_UNKNOWN, i18n("An internal error occurred. Please try again.")); - return; - } - } - - } while( nbytes > 0 ); - - if( nbytes < 0 ) { - sftpClose(handle); - - if( markPartial ) { - // Remove remote file if it smaller than our keep size - uint minKeepSize = config()->readNumEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE); - - if( sftpStat(writeUrl, attr) == SSH2_FX_OK ) { - if( attr.fileSize() < minKeepSize ) { - sftpRemove(writeUrl, true); - } - } - } - - error( ERR_UNKNOWN, i18n("Unknown error was encountered while copying the file " - "to '%1'. Please try again.").arg(dest.host()) ); - return; - } - - if( (code = sftpClose(handle)) != SSH2_FX_OK ) { - error(ERR_COULD_NOT_WRITE, writeUrl.prettyURL()); - return; - } - - // If wrote to a partial file, then remove the part ext - if( markPartial ) { - if( sftpRename(partUrl, origUrl) != SSH2_FX_OK ) { - error(ERR_CANNOT_RENAME_PARTIAL, origUrl.prettyURL()); - return; - } - } - - finished(); -} - -void sftpProtocol::put ( const KURL& url, int permissions, bool overwrite, bool resume ){ - kdDebug(KIO_SFTP_DB) << "put(): " << url << ", overwrite = " << overwrite - << ", resume = " << resume << endl; - - sftpPut( url, permissions, resume, overwrite ); -} - -void sftpProtocol::stat ( const KURL& url ){ - kdDebug(KIO_SFTP_DB) << "stat(): " << url << endl; - - openConnection(); - if( !mConnected ) - return; - - // If the stat URL has no path, do not attempt to determine the real - // path and do a redirect. KRun will simply ignore such requests. - // Instead, simply return the mime-type as a directory... - if( !url.hasPath() ) { - UDSEntry entry; - UDSAtom atom; - - atom.m_uds = TDEIO::UDS_NAME; - atom.m_str = TQString::null; - entry.append( atom ); - - atom.m_uds = TDEIO::UDS_FILE_TYPE; - atom.m_long = S_IFDIR; - entry.append( atom ); - - atom.m_uds = TDEIO::UDS_ACCESS; - atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - entry.append( atom ); - - atom.m_uds = TDEIO::UDS_USER; - atom.m_str = mUsername; - entry.append( atom ); - atom.m_uds = TDEIO::UDS_GROUP; - entry.append( atom ); - - // no size - statEntry( entry ); - finished(); - return; - } - - int code; - sftpFileAttr attr(remoteEncoding()); - if( (code = sftpStat(url, attr)) != SSH2_FX_OK ) { - processStatus(code, url.prettyURL()); - return; - } - else { - //kdDebug() << "We sent and received stat packet ok" << endl; - attr.setFilename(url.fileName()); - statEntry(attr.entry()); - } - - finished(); - - kdDebug(KIO_SFTP_DB) << "stat: END" << endl; - return; -} - - -void sftpProtocol::mimetype ( const KURL& url ){ - kdDebug(KIO_SFTP_DB) << "mimetype(): " << url << endl; - - openConnection(); - if( !mConnected ) - return; - - TQ_UINT32 pflags = SSH2_FXF_READ; - TQByteArray handle, mydata; - sftpFileAttr attr(remoteEncoding()); - int code; - if( (code = sftpOpen(url, pflags, attr, handle)) != SSH2_FX_OK ) { - error(ERR_CANNOT_OPEN_FOR_READING, url.prettyURL()); - return; - } - - TQ_UINT32 len = 1024; // Get first 1k for determining mimetype - TQ_UINT64 offset = 0; - code = SSH2_FX_OK; - while( offset < len && code == SSH2_FX_OK ) { - if( (code = sftpRead(handle, offset, len, mydata)) == SSH2_FX_OK ) { - data(mydata); - offset += mydata.size(); - processedSize(offset); - - kdDebug(KIO_SFTP_DB) << "mimetype(): offset = " << offset << endl; - } - } - - - data(TQByteArray()); - processedSize(offset); - sftpClose(handle); - finished(); - kdDebug(KIO_SFTP_DB) << "mimetype(): END" << endl; -} - - -void sftpProtocol::listDir(const KURL& url) { - kdDebug(KIO_SFTP_DB) << "listDir(): " << url << endl; - - openConnection(); - if( !mConnected ) - return; - - if( !url.hasPath() ) { - KURL newUrl ( url ); - if( sftpRealPath(url, newUrl) == SSH2_FX_OK ) { - kdDebug(KIO_SFTP_DB) << "listDir: Redirecting to " << newUrl << endl; - redirection(newUrl); - finished(); - return; - } - } - - int code; - TQByteArray handle; - - if( (code = sftpOpenDirectory(url, handle)) != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "listDir(): open directory failed" << endl; - processStatus(code, url.prettyURL()); - return; - } - - - code = SSH2_FX_OK; - while( code == SSH2_FX_OK ) { - code = sftpReadDir(handle, url); - if( code != SSH2_FX_OK && code != SSH2_FX_EOF ) - processStatus(code, url.prettyURL()); - kdDebug(KIO_SFTP_DB) << "listDir(): return code = " << code << endl; - } - - if( (code = sftpClose(handle)) != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "listdir(): closing of directory failed" << endl; - processStatus(code, url.prettyURL()); - return; - } - - finished(); - kdDebug(KIO_SFTP_DB) << "listDir(): END" << endl; -} - -/** Make a directory. - OpenSSH does not follow the internet draft for sftp in this case. - The format of the mkdir request expected by OpenSSH sftp server is: - uint32 id - string path - ATTR attr - */ -void sftpProtocol::mkdir(const KURL&url, int permissions){ - - kdDebug(KIO_SFTP_DB) << "mkdir() creating dir: " << url.path() << endl; - - openConnection(); - if( !mConnected ) - return; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - sftpFileAttr attr(remoteEncoding()); - - if (permissions != -1) - attr.setPermissions(permissions); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << TQ_UINT32(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len + attr.size()); - s << (TQ_UINT8)SSH2_FXP_MKDIR; - s << id; - s.writeBytes(path.data(), len); - s << attr; - - kdDebug(KIO_SFTP_DB) << "mkdir(): packet size is " << p.size() << endl; - - putPacket(p); - getPacket(p); - - TQ_UINT8 type; - TQDataStream r(p, IO_ReadOnly); - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "mkdir: sftp packet id mismatch" << endl; - error(ERR_COULD_NOT_MKDIR, path); - finished(); - return; - } - - if( type != SSH2_FXP_STATUS ) { - kdError(KIO_SFTP_DB) << "mkdir(): unexpected packet type of " << type << endl; - error(ERR_COULD_NOT_MKDIR, path); - finished(); - return; - } - - int code; - r >> code; - if( code != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "mkdir(): failed with code " << code << endl; - - // Check if mkdir failed because the directory already exists so that - // we can return the appropriate message... - sftpFileAttr dirAttr(remoteEncoding()); - if ( sftpStat(url, dirAttr) == SSH2_FX_OK ) - { - error( ERR_DIR_ALREADY_EXIST, url.prettyURL() ); - return; - } - - error(ERR_COULD_NOT_MKDIR, path); - } - - finished(); -} - -void sftpProtocol::rename(const KURL& src, const KURL& dest, bool overwrite){ - kdDebug(KIO_SFTP_DB) << "rename(" << src << " -> " << dest << ")" << endl; - - if (!isSupportedOperation(SSH2_FXP_RENAME)) { - error(ERR_UNSUPPORTED_ACTION, - i18n("The remote host does not support renaming files.")); - return; - } - - openConnection(); - if( !mConnected ) - return; - - // Always stat the destination before attempting to rename - // a file or a directory... - sftpFileAttr attr(remoteEncoding()); - int code = sftpStat(dest, attr); - - // If the destination directory, exists tell it to the job - // so it the proper action can be presented to the user... - if( code == SSH2_FX_OK ) - { - if (!overwrite) - { - if ( S_ISDIR(attr.permissions()) ) - error( TDEIO::ERR_DIR_ALREADY_EXIST, dest.url() ); - else - error( TDEIO::ERR_FILE_ALREADY_EXIST, dest.url() ); - return; - } - - // If overwrite is specified, then simply remove the existing file/dir first... - if( (code = sftpRemove( dest, !S_ISDIR(attr.permissions()) )) != SSH2_FX_OK ) - { - processStatus(code); - return; - } - } - - // Do the renaming... - if( (code = sftpRename(src, dest)) != SSH2_FX_OK ) { - processStatus(code); - return; - } - - finished(); - kdDebug(KIO_SFTP_DB) << "rename(): END" << endl; -} - -void sftpProtocol::symlink(const TQString& target, const KURL& dest, bool overwrite){ - kdDebug(KIO_SFTP_DB) << "symlink()" << endl; - - if (!isSupportedOperation(SSH2_FXP_SYMLINK)) { - error(ERR_UNSUPPORTED_ACTION, - i18n("The remote host does not support creating symbolic links.")); - return; - } - - openConnection(); - if( !mConnected ) - return; - - int code; - bool failed = false; - if( (code = sftpSymLink(target, dest)) != SSH2_FX_OK ) { - if( overwrite ) { // try to delete the destination - sftpFileAttr attr(remoteEncoding()); - if( (code = sftpStat(dest, attr)) != SSH2_FX_OK ) { - failed = true; - } - else { - if( (code = sftpRemove(dest, !S_ISDIR(attr.permissions())) ) != SSH2_FX_OK ) { - failed = true; - } - else { - // XXX what if rename fails again? We have lost the file. - // Maybe rename dest to a temporary name first? If rename is - // successful, then delete? - if( (code = sftpSymLink(target, dest)) != SSH2_FX_OK ) - failed = true; - } - } - } - else if( code == SSH2_FX_FAILURE ) { - error(ERR_FILE_ALREADY_EXIST, dest.prettyURL()); - return; - } - else - failed = true; - } - - // What error code do we return? Code for the original symlink command - // or for the last command or for both? The second one is implemented here. - if( failed ) - processStatus(code); - - finished(); -} - -void sftpProtocol::chmod(const KURL& url, int permissions){ - TQString perms; - perms.setNum(permissions, 8); - kdDebug(KIO_SFTP_DB) << "chmod(" << url << ", " << perms << ")" << endl; - - openConnection(); - if( !mConnected ) - return; - - sftpFileAttr attr(remoteEncoding()); - - if (permissions != -1) - attr.setPermissions(permissions); - - int code; - if( (code = sftpSetStat(url, attr)) != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "chmod(): sftpSetStat failed with error " << code << endl; - if( code == SSH2_FX_FAILURE ) - error(ERR_CANNOT_CHMOD, TQString::null); - else - processStatus(code, url.prettyURL()); - } - finished(); -} - - -void sftpProtocol::del(const KURL &url, bool isfile){ - kdDebug(KIO_SFTP_DB) << "del(" << url << ", " << (isfile?"file":"dir") << ")" << endl; - - openConnection(); - if( !mConnected ) - return; - - int code; - if( (code = sftpRemove(url, isfile)) != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "del(): sftpRemove failed with error code " << code << endl; - processStatus(code, url.prettyURL()); - } - finished(); -} - -void sftpProtocol::slave_status() { - kdDebug(KIO_SFTP_DB) << "slave_status(): connected to " - << mHost << "? " << mConnected << endl; - - slaveStatus ((mConnected ? mHost : TQString::null), mConnected); -} - -bool sftpProtocol::getPacket(TQByteArray& msg) { - TQByteArray buf(4096); - - // Get the message length... - ssize_t len = atomicio(ssh.stdioFd(), buf.data(), 4, true /*read*/); - - if( len == 0 || len == -1 ) { - kdDebug(KIO_SFTP_DB) << "getPacket(): read of packet length failed, ret = " - << len << ", error =" << strerror(errno) << endl; - closeConnection(); - error( ERR_CONNECTION_BROKEN, mHost); - msg.resize(0); - return false; - } - - uint msgLen; - TQDataStream s(buf, IO_ReadOnly); - s >> msgLen; - - //kdDebug(KIO_SFTP_DB) << "getPacket(): Message size = " << msgLen << endl; - - msg.resize(0); - - TQBuffer b( msg ); - b.open( IO_WriteOnly ); - - while( msgLen ) { - len = atomicio(ssh.stdioFd(), buf.data(), kMin((uint)buf.size(), msgLen), true /*read*/); - - if( len == 0 || len == -1) { - TQString errmsg; - if (len == 0) - errmsg = i18n("Connection closed"); - else - errmsg = i18n("Could not read SFTP packet"); - kdDebug(KIO_SFTP_DB) << "getPacket(): nothing to read, ret = " << - len << ", error =" << strerror(errno) << endl; - closeConnection(); - error(ERR_CONNECTION_BROKEN, errmsg); - b.close(); - return false; - } - - b.writeBlock(buf.data(), len); - - //kdDebug(KIO_SFTP_DB) << "getPacket(): Read Message size = " << len << endl; - //kdDebug(KIO_SFTP_DB) << "getPacket(): Copy Message size = " << msg.size() << endl; - - msgLen -= len; - } - - b.close(); - - return true; -} - -/** Send an sftp packet to stdin of the ssh process. */ -bool sftpProtocol::putPacket(TQByteArray& p){ -// kdDebug(KIO_SFTP_DB) << "putPacket(): size == " << p.size() << endl; - int ret; - ret = atomicio(ssh.stdioFd(), p.data(), p.size(), false /*write*/); - if( ret <= 0 ) { - kdDebug(KIO_SFTP_DB) << "putPacket(): write failed, ret =" << ret << - ", error = " << strerror(errno) << endl; - return false; - } - - return true; -} - -/** Used to have the server canonicalize any given path name to an absolute path. -This is useful for converting path names containing ".." components or relative -pathnames without a leading slash into absolute paths. -Returns the canonicalized url. */ -int sftpProtocol::sftpRealPath(const KURL& url, KURL& newUrl){ - - kdDebug(KIO_SFTP_DB) << "sftpRealPath(" << url << ", newUrl)" << endl; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << TQ_UINT32(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len); - s << (TQ_UINT8)SSH2_FXP_REALPATH; - s << id; - s.writeBytes(path.data(), len); - - putPacket(p); - getPacket(p); - - TQ_UINT8 type; - TQDataStream r(p, IO_ReadOnly); - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpRealPath: sftp packet id mismatch" << endl; - return -1; - } - - if( type == SSH2_FXP_STATUS ) { - TQ_UINT32 code; - r >> code; - return code; - } - - if( type != SSH2_FXP_NAME ) { - kdError(KIO_SFTP_DB) << "sftpRealPath(): unexpected packet type of " << type << endl; - return -1; - } - - TQ_UINT32 count; - r >> count; - if( count != 1 ) { - kdError(KIO_SFTP_DB) << "sftpRealPath(): Bad number of file attributes for realpath command" << endl; - return -1; - } - - TQCString newPath; - r >> newPath; - - newPath.truncate(newPath.size()); - if (newPath.isEmpty()) - newPath = "/"; - newUrl.setPath(newPath); - - return SSH2_FX_OK; -} - -sftpProtocol::Status sftpProtocol::doProcessStatus(TQ_UINT8 code, const TQString& message) -{ - Status res; - res.code = 0; - res.size = 0; - res.text = message; - - switch(code) - { - case SSH2_FX_OK: - case SSH2_FX_EOF: - break; - case SSH2_FX_NO_SUCH_FILE: - res.code = ERR_DOES_NOT_EXIST; - break; - case SSH2_FX_PERMISSION_DENIED: - res.code = ERR_ACCESS_DENIED; - break; - case SSH2_FX_FAILURE: - res.text = i18n("SFTP command failed for an unknown reason."); - res.code = ERR_UNKNOWN; - break; - case SSH2_FX_BAD_MESSAGE: - res.text = i18n("The SFTP server received a bad message."); - res.code = ERR_UNKNOWN; - break; - case SSH2_FX_OP_UNSUPPORTED: - res.text = i18n("You attempted an operation unsupported by the SFTP server."); - res.code = ERR_UNKNOWN; - break; - default: - res.text = i18n("Error code: %1").arg(code); - res.code = ERR_UNKNOWN; - } - - return res; -} - -/** Process SSH_FXP_STATUS packets. */ -void sftpProtocol::processStatus(TQ_UINT8 code, const TQString& message){ - Status st = doProcessStatus( code, message ); - if( st.code != 0 ) - error( st.code, st.text ); -} - -/** Opens a directory handle for url.path. Returns true if succeeds. */ -int sftpProtocol::sftpOpenDirectory(const KURL& url, TQByteArray& handle){ - - kdDebug(KIO_SFTP_DB) << "sftpOpenDirectory(" << url << ", handle)" << endl; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len); - s << (TQ_UINT8)SSH2_FXP_OPENDIR; - s << (TQ_UINT32)id; - s.writeBytes(path.data(), len); - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpOpenDirectory: sftp packet id mismatch: " << - "expected " << expectedId << ", got " << id << endl; - return -1; - } - - if( type == SSH2_FXP_STATUS ) { - TQ_UINT32 errCode; - r >> errCode; - return errCode; - } - - if( type != SSH2_FXP_HANDLE ) { - kdError(KIO_SFTP_DB) << "sftpOpenDirectory: unexpected message type of " << type << endl; - return -1; - } - - r >> handle; - if( handle.size() > 256 ) { - kdError(KIO_SFTP_DB) << "sftpOpenDirectory: handle exceeds max length" << endl; - return -1; - } - - kdDebug(KIO_SFTP_DB) << "sftpOpenDirectory: handle (" << handle.size() << "): [" << handle << "]" << endl; - return SSH2_FX_OK; -} - -/** Closes a directory or file handle. */ -int sftpProtocol::sftpClose(const TQByteArray& handle){ - - kdDebug(KIO_SFTP_DB) << "sftpClose()" << endl; - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + handle.size()); - s << (TQ_UINT8)SSH2_FXP_CLOSE; - s << (TQ_UINT32)id; - s << handle; - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpClose: sftp packet id mismatch" << endl; - return -1; - } - - if( type != SSH2_FXP_STATUS ) { - kdError(KIO_SFTP_DB) << "sftpClose: unexpected message type of " << type << endl; - return -1; - } - - TQ_UINT32 code; - r >> code; - if( code != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "sftpClose: close failed with err code " << code << endl; - } - - return code; -} - -/** Set a files attributes. */ -int sftpProtocol::sftpSetStat(const KURL& url, const sftpFileAttr& attr){ - - kdDebug(KIO_SFTP_DB) << "sftpSetStat(" << url << ", attr)" << endl; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len + attr.size()); - s << (TQ_UINT8)SSH2_FXP_SETSTAT; - s << (TQ_UINT32)id; - s.writeBytes(path.data(), len); - s << attr; - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpSetStat(): sftp packet id mismatch" << endl; - return -1; - // XXX How do we do a fatal error? - } - - if( type != SSH2_FXP_STATUS ) { - kdError(KIO_SFTP_DB) << "sftpSetStat(): unexpected message type of " << type << endl; - return -1; - } - - TQ_UINT32 code; - r >> code; - if( code != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "sftpSetStat(): set stat failed with err code " << code << endl; - } - - return code; -} - -/** Sends a sftp command to remove a file or directory. */ -int sftpProtocol::sftpRemove(const KURL& url, bool isfile){ - - kdDebug(KIO_SFTP_DB) << "sftpRemove(): " << url << ", isFile ? " << isfile << endl; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len); - s << (TQ_UINT8)(isfile ? SSH2_FXP_REMOVE : SSH2_FXP_RMDIR); - s << (TQ_UINT32)id; - s.writeBytes(path.data(), len); - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "del(): sftp packet id mismatch" << endl; - return -1; - } - - if( type != SSH2_FXP_STATUS ) { - kdError(KIO_SFTP_DB) << "del(): unexpected message type of " << type << endl; - return -1; - } - - TQ_UINT32 code; - r >> code; - if( code != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "del(): del failed with err code " << code << endl; - } - - return code; -} - -/** Send a sftp command to rename a file or directoy. */ -int sftpProtocol::sftpRename(const KURL& src, const KURL& dest){ - - kdDebug(KIO_SFTP_DB) << "sftpRename(" << src << " -> " << dest << ")" << endl; - - TQCString srcPath = remoteEncoding()->encode(src.path()); - TQCString destPath = remoteEncoding()->encode(dest.path()); - - uint slen = srcPath.length(); - uint dlen = destPath.length(); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + - 4 /*str length*/ + slen + - 4 /*str length*/ + dlen); - s << (TQ_UINT8)SSH2_FXP_RENAME; - s << (TQ_UINT32)id; - s.writeBytes(srcPath.data(), slen); - s.writeBytes(destPath.data(), dlen); - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpRename(): sftp packet id mismatch" << endl; - return -1; - } - - if( type != SSH2_FXP_STATUS ) { - kdError(KIO_SFTP_DB) << "sftpRename(): unexpected message type of " << type << endl; - return -1; - } - - int code; - r >> code; - if( code != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "sftpRename(): rename failed with err code " << code << endl; - } - - return code; -} -/** Get directory listings. */ -int sftpProtocol::sftpReadDir(const TQByteArray& handle, const KURL& url){ - // url is needed so we can lookup the link destination - kdDebug(KIO_SFTP_DB) << "sftpReadDir(): " << url << endl; - - TQ_UINT32 id, expectedId, count; - TQ_UINT8 type; - - sftpFileAttr attr (remoteEncoding()); - attr.setDirAttrsFlag(true); - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - id = expectedId = mMsgId++; - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + handle.size()); - s << (TQ_UINT8)SSH2_FXP_READDIR; - s << (TQ_UINT32)id; - s << handle; - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - r >> type >> id; - - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpReadDir(): sftp packet id mismatch" << endl; - return -1; - } - - int code; - if( type == SSH2_FXP_STATUS ) { - r >> code; - return code; - } - - if( type != SSH2_FXP_NAME ) { - kdError(KIO_SFTP_DB) << "kio_sftpProtocl::sftpReadDir(): Unexpected message" << endl; - return -1; - } - - r >> count; - kdDebug(KIO_SFTP_DB) << "sftpReadDir(): got " << count << " entries" << endl; - - while(count--) { - r >> attr; - - if( S_ISLNK(attr.permissions()) ) { - KURL myurl ( url ); - myurl.addPath(attr.filename()); - - // Stat the symlink to find out its type... - sftpFileAttr attr2 (remoteEncoding()); - (void) sftpStat(myurl, attr2); - - attr.setLinkType(attr2.linkType()); - attr.setLinkDestination(attr2.linkDestination()); - } - - listEntry(attr.entry(), false); - } - - listEntry(attr.entry(), true); - - return SSH2_FX_OK; -} - -int sftpProtocol::sftpReadLink(const KURL& url, TQString& target){ - - kdDebug(KIO_SFTP_DB) << "sftpReadLink(): " << url << endl; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - //kdDebug(KIO_SFTP_DB) << "sftpReadLink(): Encoded Path: " << path << endl; - //kdDebug(KIO_SFTP_DB) << "sftpReadLink(): Encoded Size: " << len << endl; - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len); - s << (TQ_UINT8)SSH2_FXP_READLINK; - s << id; - s.writeBytes(path.data(), len); - - - putPacket(p); - getPacket(p); - - TQ_UINT8 type; - TQDataStream r(p, IO_ReadOnly); - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpReadLink(): sftp packet id mismatch" << endl; - return -1; - } - - if( type == SSH2_FXP_STATUS ) { - TQ_UINT32 code; - r >> code; - kdDebug(KIO_SFTP_DB) << "sftpReadLink(): read link failed with code " << code << endl; - return code; - } - - if( type != SSH2_FXP_NAME ) { - kdError(KIO_SFTP_DB) << "sftpReadLink(): unexpected packet type of " << type << endl; - return -1; - } - - TQ_UINT32 count; - r >> count; - if( count != 1 ) { - kdError(KIO_SFTP_DB) << "sftpReadLink(): Bad number of file attributes for realpath command" << endl; - return -1; - } - - TQCString linkAddress; - r >> linkAddress; - - linkAddress.truncate(linkAddress.size()); - kdDebug(KIO_SFTP_DB) << "sftpReadLink(): Link address: " << linkAddress << endl; - - target = remoteEncoding()->decode(linkAddress); - - return SSH2_FX_OK; -} - -int sftpProtocol::sftpSymLink(const TQString& _target, const KURL& dest){ - - TQCString destPath = remoteEncoding()->encode(dest.path()); - TQCString target = remoteEncoding()->encode(_target); - uint dlen = destPath.length(); - uint tlen = target.length(); - - kdDebug(KIO_SFTP_DB) << "sftpSymLink(" << target << " -> " << destPath << ")" << endl; - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + - 4 /*str length*/ + tlen + - 4 /*str length*/ + dlen); - s << (TQ_UINT8)SSH2_FXP_SYMLINK; - s << (TQ_UINT32)id; - s.writeBytes(target.data(), tlen); - s.writeBytes(destPath.data(), dlen); - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpSymLink(): sftp packet id mismatch" << endl; - return -1; - } - - if( type != SSH2_FXP_STATUS ) { - kdError(KIO_SFTP_DB) << "sftpSymLink(): unexpected message type of " << type << endl; - return -1; - } - - TQ_UINT32 code; - r >> code; - if( code != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "sftpSymLink(): rename failed with err code " << code << endl; - } - - return code; -} - -/** Stats a file. */ -int sftpProtocol::sftpStat(const KURL& url, sftpFileAttr& attr) { - - kdDebug(KIO_SFTP_DB) << "sftpStat(): " << url << endl; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len); - s << (TQ_UINT8)SSH2_FXP_LSTAT; - s << (TQ_UINT32)id; - s.writeBytes(path.data(), len); - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpStat(): sftp packet id mismatch" << endl; - return -1; - } - - if( type == SSH2_FXP_STATUS ) { - TQ_UINT32 errCode; - r >> errCode; - kdError(KIO_SFTP_DB) << "sftpStat(): stat failed with code " << errCode << endl; - return errCode; - } - - if( type != SSH2_FXP_ATTRS ) { - kdError(KIO_SFTP_DB) << "sftpStat(): unexpected message type of " << type << endl; - return -1; - } - - r >> attr; - attr.setFilename(url.fileName()); - kdDebug(KIO_SFTP_DB) << "sftpStat(): " << attr << endl; - - // If the stat'ed resource is a symlink, perform a recursive stat - // to determine the actual destination's type (file/dir). - if( S_ISLNK(attr.permissions()) && isSupportedOperation(SSH2_FXP_READLINK) ) { - - TQString target; - int code = sftpReadLink( url, target ); - - if ( code != SSH2_FX_OK ) { - kdError(KIO_SFTP_DB) << "sftpStat(): Unable to stat symlink destination" << endl; - return -1; - } - - kdDebug(KIO_SFTP_DB) << "sftpStat(): Resource is a symlink to -> " << target << endl; - - KURL dest( url ); - if( target[0] == '/' ) - dest.setPath(target); - else - dest.setFileName(target); - - dest.cleanPath(); - - // Ignore symlinks that point to themselves... - if ( dest != url ) { - - sftpFileAttr attr2 (remoteEncoding()); - (void) sftpStat(dest, attr2); - - if (attr2.linkType() == 0) - attr.setLinkType(attr2.fileType()); - else - attr.setLinkType(attr2.linkType()); - - attr.setLinkDestination(target); - - kdDebug(KIO_SFTP_DB) << "sftpStat(): File type: " << attr.fileType() << endl; - } - } - - return SSH2_FX_OK; -} - - -int sftpProtocol::sftpOpen(const KURL& url, const TQ_UINT32 pflags, - const sftpFileAttr& attr, TQByteArray& handle) { - kdDebug(KIO_SFTP_DB) << "sftpOpen(" << url << ", handle" << endl; - - TQCString path = remoteEncoding()->encode(url.path()); - uint len = path.length(); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + - 4 /*str length*/ + len + - 4 /*pflags*/ + attr.size()); - s << (TQ_UINT8)SSH2_FXP_OPEN; - s << (TQ_UINT32)id; - s.writeBytes(path.data(), len); - s << pflags; - s << attr; - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpOpen(): sftp packet id mismatch" << endl; - return -1; - } - - if( type == SSH2_FXP_STATUS ) { - TQ_UINT32 errCode; - r >> errCode; - return errCode; - } - - if( type != SSH2_FXP_HANDLE ) { - kdError(KIO_SFTP_DB) << "sftpOpen(): unexpected message type of " << type << endl; - return -1; - } - - r >> handle; - if( handle.size() > 256 ) { - kdError(KIO_SFTP_DB) << "sftpOpen(): handle exceeds max length" << endl; - return -1; - } - - kdDebug(KIO_SFTP_DB) << "sftpOpen(): handle (" << handle.size() << "): [" << handle << "]" << endl; - return SSH2_FX_OK; -} - - -int sftpProtocol::sftpRead(const TQByteArray& handle, TDEIO::filesize_t offset, TQ_UINT32 len, TQByteArray& data) -{ - // kdDebug(KIO_SFTP_DB) << "sftpRead( offset = " << offset << ", len = " << len << ")" << endl; - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + - 4 /*str length*/ + handle.size() + - 8 /*offset*/ + 4 /*length*/); - s << (TQ_UINT8)SSH2_FXP_READ; - s << (TQ_UINT32)id; - s << handle; - s << offset; // we don't have a convienient 64 bit int so set upper int to zero - s << len; - - putPacket(p); - getPacket(p); - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpRead: sftp packet id mismatch" << endl; - return -1; - } - - if( type == SSH2_FXP_STATUS ) { - TQ_UINT32 errCode; - r >> errCode; - kdError(KIO_SFTP_DB) << "sftpRead: read failed with code " << errCode << endl; - return errCode; - } - - if( type != SSH2_FXP_DATA ) { - kdError(KIO_SFTP_DB) << "sftpRead: unexpected message type of " << type << endl; - return -1; - } - - r >> data; - - return SSH2_FX_OK; -} - - -int sftpProtocol::sftpWrite(const TQByteArray& handle, TDEIO::filesize_t offset, const TQByteArray& data){ -// kdDebug(KIO_SFTP_DB) << "sftpWrite( offset = " << offset << -// ", data sz = " << data.size() << ")" << endl; - TQByteArray p; - TQDataStream s(p, IO_WriteOnly); - - TQ_UINT32 id, expectedId; - id = expectedId = mMsgId++; - s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + - 4 /*str length*/ + handle.size() + - 8 /*offset*/ + - 4 /* data size */ + data.size()); - s << (TQ_UINT8)SSH2_FXP_WRITE; - s << (TQ_UINT32)id; - s << handle; - s << offset; // we don't have a convienient 64 bit int so set upper int to zero - s << data; - -// kdDebug(KIO_SFTP_DB) << "sftpWrite(): SSH2_FXP_WRITE, id:" -// << id << ", handle:" << handle << ", offset:" << offset << ", some data" << endl; - -// kdDebug(KIO_SFTP_DB) << "sftpWrite(): send packet [" << p << "]" << endl; - - putPacket(p); - getPacket(p); - -// kdDebug(KIO_SFTP_DB) << "sftpWrite(): received packet [" << p << "]" << endl; - - TQDataStream r(p, IO_ReadOnly); - TQ_UINT8 type; - - r >> type >> id; - if( id != expectedId ) { - kdError(KIO_SFTP_DB) << "sftpWrite(): sftp packet id mismatch, got " - << id << ", expected " << expectedId << endl; - return -1; - } - - if( type != SSH2_FXP_STATUS ) { - kdError(KIO_SFTP_DB) << "sftpWrite(): unexpected message type of " << type << endl; - return -1; - } - - TQ_UINT32 code; - r >> code; - return code; -} - - diff --git a/kioslave/sftp/kio_sftp.h b/kioslave/sftp/kio_sftp.h deleted file mode 100644 index e9120452b..000000000 --- a/kioslave/sftp/kio_sftp.h +++ /dev/null @@ -1,149 +0,0 @@ -/*************************************************************************** - sftpProtocol.h - description - ------------------- - begin : Sat Jun 30 20:08:47 CDT 2001 - copyright : (C) 2001 by Lucas Fisher - email : ljfisher@purdue.edu -***************************************************************************/ - -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ -#ifndef __kio_sftp_h__ -#define __kio_sftp_h__ - -#include <tqstring.h> -#include <tqcstring.h> -#include <tqobject.h> - -#include <kurl.h> -#include <kio/global.h> -#include <kio/slavebase.h> -#include <kdebug.h> - -#include "process.h" -#include "sftpfileattr.h" -#include "ksshprocess.h" - -#define KIO_SFTP_DB 7120 - - -class sftpProtocol : public TDEIO::SlaveBase -{ - -public: - sftpProtocol(const TQCString &pool_socket, const TQCString &app_socket); - virtual ~sftpProtocol(); - virtual void setHost(const TQString& h, int port, const TQString& user, const TQString& pass); - virtual void get(const KURL& url); - virtual void listDir(const KURL& url) ; - virtual void mimetype(const KURL& url); - virtual void stat(const KURL& url); - virtual void copy(const KURL &src, const KURL &dest, int permissions, bool overwrite); - virtual void put(const KURL& url, int permissions, bool overwrite, bool resume); - virtual void closeConnection(); - virtual void slave_status(); - virtual void del(const KURL &url, bool isfile); - virtual void chmod(const KURL& url, int permissions); - virtual void symlink(const TQString& target, const KURL& dest, bool overwrite); - virtual void rename(const KURL& src, const KURL& dest, bool overwrite); - virtual void mkdir(const KURL&url, int permissions); - virtual void openConnection(); - -private: // Private variables - /** True if ioslave is connected to sftp server. */ - bool mConnected; - - /** Host we are connected to. */ - TQString mHost; - - /** Port we are connected to. */ - int mPort; - - /** Ssh process to which we send the sftp packets. */ - KSshProcess ssh; - - /** Username to use when connecting */ - TQString mUsername; - - /** User's password */ - TQString mPassword; - - /** Message id of the last sftp packet we sent. */ - unsigned int mMsgId; - - /** Type of packet we are expecting to receive next. */ - unsigned char mExpected; - - /** Version of the sftp protocol we are using. */ - int sftpVersion; - - struct Status - { - int code; - TDEIO::filesize_t size; - TQString text; - }; - -private: // private methods - bool getPacket(TQByteArray& msg); - - /* Type is a sftp packet type found in .sftp.h'. - * Example: SSH2_FXP_READLINK, SSH2_FXP_RENAME, etc. - * - * Returns true if the type is supported by the sftp protocol - * version negotiated by the client and server (sftpVersion). - */ - bool isSupportedOperation(int type); - /** Used to have the server canonicalize any given path name to an absolute path. - This is useful for converting path names containing ".." components or relative - pathnames without a leading slash into absolute paths. - Returns the canonicalized url. */ - int sftpRealPath(const KURL& url, KURL& newUrl); - - /** Send an sftp packet to stdin of the ssh process. */ - bool putPacket(TQByteArray& p); - /** Process SSH_FXP_STATUS packets. */ - void processStatus(TQ_UINT8, const TQString& message = TQString::null); - /** Process SSH_FXP_STATUS packes and return the result. */ - Status doProcessStatus(TQ_UINT8, const TQString& message = TQString::null); - /** Opens a directory handle for url.path. Returns true if succeeds. */ - int sftpOpenDirectory(const KURL& url, TQByteArray& handle); - /** Closes a directory or file handle. */ - int sftpClose(const TQByteArray& handle); - /** Send a sftp command to rename a file or directoy. */ - int sftpRename(const KURL& src, const KURL& dest); - /** Set a files attributes. */ - int sftpSetStat(const KURL& url, const sftpFileAttr& attr); - /** Sends a sftp command to remove a file or directory. */ - int sftpRemove(const KURL& url, bool isfile); - /** Creates a symlink named dest to target. */ - int sftpSymLink(const TQString& target, const KURL& dest); - /** Get directory listings. */ - int sftpReadDir(const TQByteArray& handle, const KURL& url); - /** Retrieves the destination of a link. */ - int sftpReadLink(const KURL& url, TQString& target); - /** Stats a file. */ - int sftpStat(const KURL& url, sftpFileAttr& attr); - /** No descriptions */ - int sftpOpen(const KURL& url, const TQ_UINT32 pflags, const sftpFileAttr& attr, TQByteArray& handle); - /** No descriptions */ - int sftpRead(const TQByteArray& handle, TDEIO::filesize_t offset, TQ_UINT32 len, TQByteArray& data); - /** No descriptions */ - int sftpWrite(const TQByteArray& handle, TDEIO::filesize_t offset, const TQByteArray& data); - - /** Performs faster upload when the source is a local file... */ - void sftpCopyPut(const KURL& src, const KURL& dest, int mode, bool overwrite); - /** Performs faster download when the destination is a local file... */ - void sftpCopyGet(const KURL& dest, const KURL& src, int mode, bool overwrite); - - /** */ - Status sftpGet( const KURL& src, TDEIO::filesize_t offset = 0, int fd = -1); - void sftpPut( const KURL& dest, int permissions, bool resume, bool overwrite, int fd = -1); -}; -#endif diff --git a/kioslave/sftp/ksshprocess.cpp b/kioslave/sftp/ksshprocess.cpp deleted file mode 100644 index 3393f8934..000000000 --- a/kioslave/sftp/ksshprocess.cpp +++ /dev/null @@ -1,1114 +0,0 @@ -/*************************************************************************** - ksshprocess.cpp - description - ------------------- - begin : Tue Jul 31 2001 - copyright : (C) 2001 by Lucas Fisher - email : ljfisher@purdue.edu - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ - -/* - * See the KSshProcess header for examples on use. - * - * This class uses a hacked version of the PTYProcess - * class. This was needed because the tdelibs PTYProcess does not provide - * access to the pty file descriptor which we need, because ssh prints the - * password prompt to the pty and reads the password from the pty. I don't - * feel I know enough about ptys to confidently modify the orignial - * PTYProcess class. - * - * To start ssh we take the arguments the user gave us - * in the SshOptList and build the ssh command arguments based on the version - * of ssh we are using. This command and its arguments are passed to - * PTYProcess for execution. Once ssh is started we scan each line of input - * from stdin, stderr, and the pty for recognizable strings. The recognizable - * strings are taken from several string tables. Each table contains a string - * for each specific version of ssh we support and a string for a generic - * version of OpenSSH and commercial SSH incase we don't recognized the - * specific ssh version strings (as when a new SSH version is released after - * a release of KSshProcess). There are tables for ssh version strings, - * password prompts, new host key errors, different host key errors, - * messages than indicate a successful connect, authentication errors, etc. - * If we find user interaction is necessary, for instance to provide a - * password or passphrase, we return a err code to the user who can send - * a message to KSshProcess, using one of several methods, to correct - * the error. - * - * Determining when the ssh connection has successfully authenticationed has - * proved to be the most difficult challenge. OpenSSH does not print a message - * on successful authentication, thus the only way to know is to send data - * and wait for a return. The problem here is sometimes it can take a bit - * to establish the connection (for example, do to DNS lookups). This means - * the user may be sitting there waiting for a connection that failed. - * Instead, ssh is always started with the verbose flag. Then we look for - * a message that indicates auth succeeded. This is hazardous because - * debug messages are more likely to change between OpenSSH releases. - * Thus, we could become incompatible with new OpenSSH releases. - */ - -#include <config.h> - -#include "ksshprocess.h" - -#include <stdio.h> -#include <errno.h> - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#include <kstandarddirs.h> -#include <klocale.h> -#include <tqregexp.h> - -/* - * The following are tables of string and regexps we match - * against the output of ssh. An entry in each array - * corresponds the the version of ssh found in versionStrs[]. - * - * The version strings must be ordered in the array from most - * specific to least specific in cases where the beginning - * of several version strings are the similar. For example, - * consider the openssh version strings. The generic "OpenSSH" - * must be the last of the openssh version strings in the array - * so that is matched last. We use these generic version strings - * so we can do a best effor to support unknown ssh versions. - */ -TQRegExp KSshProcess::versionStrs[] = { - TQRegExp("OpenSSH_3\\.[6-9]|OpenSSH_[1-9]*[4-9]\\.[0-9]"), - TQRegExp("OpenSSH"), - TQRegExp("SSH Secure Shell") -}; - -const char * const KSshProcess::passwordPrompt[] = { - "password:", // OpenSSH - "password:", // OpenSSH - "password:" // SSH -}; - -const char * const KSshProcess::passphrasePrompt[] = { - "Enter passphrase for key", - "Enter passphrase for key", - "Passphrase for key" -}; - -const char * const KSshProcess::authSuccessMsg[] = { - "Authentication succeeded", - "ssh-userauth2 successful", - "Received SSH_CROSS_AUTHENTICATED packet" -}; - -const char* const KSshProcess::authFailedMsg[] = { - "Permission denied (", - "Permission denied (", - "Authentication failed." -}; - -const char* const KSshProcess::tryAgainMsg[] = { - "please try again", - "please try again", - "adjfhjsdhfdsjfsjdfhuefeufeuefe" -}; - -TQRegExp KSshProcess::hostKeyMissingMsg[] = { - TQRegExp("The authenticity of host|No (DSA|RSA) host key is known for"), - TQRegExp("The authenticity of host|No (DSA|RSA) host key is known for"), - TQRegExp("Host key not found from database") -}; - -const char* const KSshProcess::continuePrompt[] = { - "Are you sure you want to continue connecting (yes/no)?", - "Are you sure you want to continue connecting (yes/no)?", - "Are you sure you want to continue connecting (yes/no)?" -}; - -const char* const KSshProcess::hostKeyChangedMsg[] = { - "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!", - "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!", - "WARNING: HOST IDENTIFICATION HAS CHANGED!" -}; - -TQRegExp KSshProcess::keyFingerprintMsg[] = { - TQRegExp("..(:..){15}"), - TQRegExp("..(:..){15}"), - TQRegExp(".....(-.....){10}") -}; - -TQRegExp KSshProcess::knownHostsFileMsg[] = { - TQRegExp("Add correct host key in (.*) to get rid of this message."), - TQRegExp("Add correct host key in (.*) to get rid of this message."), - TQRegExp("Add correct host key to \"(.*)\"") -}; - - -// This prompt only applies to commerical ssh. -const char* const KSshProcess::changeHostKeyOnDiskPrompt[] = { - "as;jf;sajkfdslkfjas;dfjdsa;fj;dsajfdsajf", - "as;jf;sajkfdslkfjas;dfjdsa;fj;dsajfdsajf", - "Do you want to change the host key on disk (yes/no)?" -}; - -// We need this in addition the authFailedMsg because when -// OpenSSH gets a changed host key it will fail to connect -// depending on the StrictHostKeyChecking option. Depending -// how this option is set, it will print "Permission denied" -// and quit, or print "Host key verification failed." and -// quit. The later if StrictHostKeyChecking is "no". -// The former if StrictHostKeyChecking is -// "yes" or explicitly set to "ask". -TQRegExp KSshProcess::hostKeyVerifyFailedMsg[] = { - TQRegExp("Host key verification failed\\."), - TQRegExp("Host key verification failed\\."), - TQRegExp("Disconnected; key exchange or algorithm? negotiation failed \\(Key exchange failed\\.\\)\\.") -}; - -const char * const KSshProcess::connectionClosedMsg[] = { - "Connection closed by remote host", - "Connection closed by remote host", - "Connection closed by remote host" -}; - - -void KSshProcess::SIGCHLD_handler(int) { - while(waitpid(-1, NULL, WNOHANG) > 0); -} - -void KSshProcess::installSignalHandlers() { - struct sigaction act; - memset(&act,0,sizeof(act)); - act.sa_handler = SIGCHLD_handler; - act.sa_flags = 0 -#ifdef SA_NOCLDSTOP - | SA_NOCLDSTOP -#endif -#ifdef SA_RESTART - | SA_RESTART -#endif - ; - sigaction(SIGCHLD,&act,NULL); -} - -void KSshProcess::removeSignalHandlers() { - struct sigaction act; - memset(&act,0,sizeof(act)); - act.sa_handler = SIG_DFL; - sigaction(SIGCHLD,&act,NULL); -} - -KSshProcess::KSshProcess() - : mVersion(UNKNOWN_VER), mConnected(false), - mRunning(false), mConnectState(0) { - mSshPath = KStandardDirs::findExe(TQString::fromLatin1("ssh")); - kdDebug(KSSHPROC) << "KSshProcess::KSshProcess(): ssh path [" << - mSshPath << "]" << endl; - - installSignalHandlers(); -} - -KSshProcess::KSshProcess(TQString pathToSsh) - : mSshPath(pathToSsh), mVersion(UNKNOWN_VER), mConnected(false), - mRunning(false), mConnectState(0) { - installSignalHandlers(); -} - -KSshProcess::~KSshProcess(){ - disconnect(); - removeSignalHandlers(); - while(waitpid(-1, NULL, WNOHANG) > 0); -} - -bool KSshProcess::setSshPath(TQString pathToSsh) { - mSshPath = pathToSsh; - version(); - if( mVersion == UNKNOWN_VER ) - return false; - - return true; -} - -KSshProcess::SshVersion KSshProcess::version() { - TQString cmd; - cmd = mSshPath+" -V 2>&1"; - - // Get version string from ssh client. - FILE *p; - if( (p = popen(cmd.latin1(), "r")) == NULL ) { - kdDebug(KSSHPROC) << "KSshProcess::version(): " - "failed to start ssh: " << strerror(errno) << endl; - return UNKNOWN_VER; - } - - // Determine of the version from the version string. - size_t len; - char buf[128]; - if( (len = fread(buf, sizeof(char), sizeof(buf)-1, p)) == 0 ) { - kdDebug(KSSHPROC) << "KSshProcess::version(): " - "Read of ssh version string failed " << - strerror(ferror(p)) << endl; - return UNKNOWN_VER; - } - if( pclose(p) == -1 ) { - kdError(KSSHPROC) << "KSshProcess::version(): pclose failed." << endl; - } - buf[len] = '\0'; - TQString ver; - ver = buf; - kdDebug(KSSHPROC) << "KSshProcess::version(): " - "got version string [" << ver << "]" << endl; - - mVersion = UNKNOWN_VER; - for(int i = 0; i < SSH_VER_MAX; i++) { - if( ver.find(versionStrs[i]) != -1 ) { - mVersion = (SshVersion)i; - break; - } - } - - kdDebug(KSSHPROC) << "KSshPRocess::version(): version number = " - << mVersion << endl; - - if( mVersion == UNKNOWN_VER ) { - kdDebug(KSSHPROC) << "KSshProcess::version(): " - "Sorry, I don't know about this version of ssh" << endl; - mError = ERR_UNKNOWN_VERSION; - return UNKNOWN_VER; - } - - return mVersion; -} -/* -TQString KSshProcess::versionStr() { - if( mVersion == UNKNOWN_VER ) { - version(); - if( mVersion == UNKNOWN_VER ) - return TQString::null; - } - - return TQString::fromLatin1(versionStrs[mVersion]); -} -*/ - -bool KSshProcess::setOptions(const SshOptList& opts) { - kdDebug(KSSHPROC) << "KSshProcess::setOptions()" << endl; - mArgs.clear(); - SshOptListConstIterator it; - TQString cmd, subsystem; - mPassword = mUsername = mHost = TQString::null; - TQCString tmp; - for(it = opts.begin(); it != opts.end(); ++it) { - //kdDebug(KSSHPROC) << "opt.opt = " << (*it).opt << endl; - //kdDebug(KSSHPROC) << "opt.str = " << (*it).str << endl; - //kdDebug(KSSHPROC) << "opt.num = " << (*it).num << endl; - switch( (*it).opt ) { - case SSH_VERBOSE: - mArgs.append("-v"); - break; - - case SSH_SUBSYSTEM: - subsystem = (*it).str; - break; - - case SSH_PORT: - mArgs.append("-p"); - tmp.setNum((*it).num); - mArgs.append(tmp); - mPort = (*it).num; - break; - - case SSH_HOST: - mHost = (*it).str; - break; - - case SSH_USERNAME: - mArgs.append("-l"); - mArgs.append((*it).str.latin1()); - mUsername = (*it).str; - break; - - case SSH_PASSWD: - mPassword = (*it).str; - break; - - case SSH_PROTOCOL: - if( mVersion <= OPENSSH ) { - tmp = "Protocol="; - tmp += TQString::number((*it).num).latin1(); - mArgs.append("-o"); - mArgs.append(tmp); - } - else if( mVersion <= SSH ) { - if( (*it).num == 1 ) { - mArgs.append("-1"); - } - // else uses version 2 by default - } - break; - - case SSH_FORWARDX11: - tmp = "ForwardX11="; - tmp += (*it).boolean ? "yes" : "no"; - mArgs.append("-o"); - mArgs.append(tmp); - break; - - case SSH_FORWARDAGENT: - tmp = "ForwardAgent="; - tmp += (*it).boolean ? "yes" : "no"; - mArgs.append("-o"); - mArgs.append(tmp); - break; - - case SSH_ESCAPE_CHAR: - if( (*it).num == -1 ) - tmp = "none"; - else - tmp = (char)((*it).num); - mArgs.append("-e"); - mArgs.append(tmp); - break; - - case SSH_OPTION: - // don't allow NumberOfPasswordPrompts or StrictHostKeyChecking - // since KSshProcess depends on specific setting of these for - // preforming authentication correctly. - tmp = (*it).str.latin1(); - if( tmp.contains("NumberOfPasswordPrompts") || - tmp.contains("StrictHostKeyChecking") ) { - mError = ERR_INVALID_OPT; - return false; - } - else { - mArgs.append("-o"); - mArgs.append(tmp); - } - break; - - case SSH_COMMAND: - cmd = (*it).str; - break; - - default: - kdDebug(KSSHPROC) << "KSshProcess::setOptions(): " - "unrecognized ssh opt " << (*it).opt << endl; - } - } - - if( !subsystem.isEmpty() && !cmd.isEmpty() ) { - kdDebug(KSSHPROC) << "KSshProcess::setOptions(): " - "cannot use a subsystem and command at the same time" << endl; - mError = ERR_CMD_SUBSYS_CONFLICT; - mErrorMsg = i18n("Cannot specify a subsystem and command at the same time."); - return false; - } - - // These options govern the behavior of ssh and - // cannot be defined by the user - //mArgs.append("-o"); - //mArgs.append("StrictHostKeyChecking=ask"); - mArgs.append("-v"); // So we get a message that the - // connection was successful - if( mVersion <= OPENSSH ) { - // nothing - } - else if( mVersion <= SSH ) { - mArgs.append("-o"); // So we can check if the connection was successful - mArgs.append("AuthenticationSuccessMsg=yes"); - } - - if( mHost.isEmpty() ) { - kdDebug(KSSHPROC) << "KSshProcess::setOptions(): " - "a host name must be supplied" << endl; - return false; - } - else { - mArgs.append(mHost.latin1()); - } - - if( !subsystem.isEmpty() ) { - mArgs.append("-s"); - mArgs.append(subsystem.latin1()); - } - - if( !cmd.isEmpty() ) { - mArgs.append(cmd.latin1()); - } - - return true; -} - -void KSshProcess::printArgs() { - TQValueListIterator<TQCString> it; - for( it = mArgs.begin(); it != mArgs.end(); ++it) { - kdDebug(KSSHPROC) << "arg: " << *it << endl; - } -} - - -int KSshProcess::error(TQString& msg) { - kdDebug(KSSHPROC) << "KSshProcess::error()" << endl; - kdDebug() << mErrorMsg << endl; - msg = mErrorMsg; - return mError; -} - -void KSshProcess::kill(int signal) { - int pid = ssh.pid(); - - kdDebug(KSSHPROC) << "KSshProcess::kill(signal:" << signal - << "): ssh pid is " << pid << endl; - kdDebug(KSSHPROC) << "KSshPRocess::kill(): we are " - << (mConnected ? "" : "not ") << "connected" << endl; - kdDebug(KSSHPROC) << "KSshProcess::kill(): we are " - << (mRunning ? "" : "not ") << "running a ssh process" << endl; - - if( mRunning && pid > 1 ) { - // Kill the child process... - if ( ::kill(pid, signal) == 0 ) { - // clean up if we tried to kill the process - if( signal == SIGTERM || signal == SIGKILL ) { - while(waitpid(-1, NULL, WNOHANG) > 0); - mConnected = false; - mRunning = false; - } - } - else - kdDebug(KSSHPROC) << "KSshProcess::kill(): kill failed" << endl; - } - else - kdDebug(KSSHPROC) << "KSshProcess::kill(): " - "Refusing to kill ssh process" << endl; -} - - - -/** - * Try to open an ssh connection. - * SSH prints certain messages to certain file descriptiors: - * passwordPrompt - pty - * passphrasePrompt - pty - * authSuccessMsg - stderr (OpenSSH), - * authFailedMsg - stderr - * hostKeyMissing - stderr - * hostKeyChanged - stderr - * continuePrompt - stderr - * - * We will use a select to wait for a line on each descriptor. Then get - * each line that available and take action based on it. The type - * of messages we are looking for and the action we take on each - * message are: - * passwordPrompt - Return false, set error to ERR_NEED_PASSWD. - * On the next call to connect() we expect a password - * to be available. - * - * passpharsePrompt - Return false, set error to ERR_NEED_PASSPHRASE. - * On the next call to connect() we expect a - * passphrase to be available. - * - * authSuccessMsg - Return true, as we have successfully established a - * ssh connection. - * - * authFailedMsg - Return false, set error to ERR_AUTH_FAILED. We - * were unable to authenticate the connection given - * the available authentication information. - * - * hostKeyMissing - Return false, set error to ERR_NEW_HOST_KEY. Caller - * must call KSshProcess.acceptHostKey(bool) to accept - * or reject the key before calling connect() again. - * - * hostKeyChanged - Return false, set error to ERR_DIFF_HOST_KEY. Caller - * must call KSshProcess.acceptHostKey(bool) to accept - * or reject the key before calling connect() again. - * - * continuePrompt - Send 'yes' or 'no' to accept or reject a key, - * respectively. - * - */ - - -void KSshProcess::acceptHostKey(bool accept) { - kdDebug(KSSHPROC) << "KSshProcess::acceptHostKey(accept:" - << accept << ")" << endl; - mAcceptHostKey = accept; -} - -void KSshProcess::setPassword(TQString password) { - kdDebug(KSSHPROC) << "KSshProcess::setPassword(password:xxxxxxxx)" << endl; - mPassword = password; -} - -TQString KSshProcess::getLine() { - static TQStringList buffer; - TQString line = TQString::null; - TQCString ptyLine, errLine; - - if( buffer.empty() ) { - // PtyProcess buffers lines. First check that there - // isn't something on the PtyProces buffer or that there - // is not data ready to be read from the pty or stderr. - ptyLine = ssh.readLineFromPty(false); - errLine = ssh.readLineFromStderr(false); - - // If PtyProcess did have something for us, get it and - // place it in our line buffer. - if( ! ptyLine.isEmpty() ) { - buffer.prepend(TQString(ptyLine)); - } - - if( ! errLine.isEmpty() ) { - buffer.prepend(TQString(errLine)); - } - - // If we still don't have anything in our buffer so there must - // not be anything on the pty or stderr. Setup a select() - // to wait for some data from SSH. - // Hack around select() failure on newer systems - unsigned long milliseconds = 0; - while ((buffer.size() == 0) && (milliseconds < (60*1000))) { - //kdDebug(KSSHPROC) << "KSshProcess::getLine(): " << - // "Line buffer empty, calling select() to wait for data." << endl; - int errfd = ssh.stderrFd(); - int ptyfd = ssh.fd(); - fd_set rfds; - fd_set efds; - struct timeval tv; - - // find max file descriptor - int maxfd = ptyfd > errfd ? ptyfd : errfd; - - FD_ZERO(&rfds); - FD_SET(ptyfd, &rfds); // Add pty file descriptor - FD_SET(errfd, &rfds); // Add std error file descriptor - - FD_ZERO(&efds); - FD_SET(ptyfd, &efds); - FD_SET(errfd, &efds); - - tv.tv_sec = 60; tv.tv_usec = 0; // 60 second timeout - - // Wait for a message from ssh on stderr or the pty. - int ret = -1; - do - ret = ::select(maxfd+1, &rfds, NULL, &efds, &tv); - while( ret == -1 && errno == EINTR ); - - // Handle any errors from select - if( ret == 0 ) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " << - "timed out waiting for a response" << endl; - mError = ERR_TIMED_OUT; - return TQString::null; - } - else if( ret == -1 ) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - << "select error: " << strerror(errno) << endl; - mError = ERR_INTERNAL; - return TQString::null; - } - - // We are not respecting any type of order in which the - // lines were received. Who knows whether pty or stderr - // had data on it first. - if( FD_ISSET(ptyfd, &rfds) ) { - ptyLine = ssh.readLineFromPty(false); - if (ptyLine.size() > 0) { - buffer.prepend(TQString(ptyLine)); - } - //kdDebug(KSSHPROC) << "KSshProcess::getLine(): " - // "line from pty -" << ptyLine << endl; - } - - if( FD_ISSET(errfd, &rfds) ) { - errLine = ssh.readLineFromStderr(false); - if (errLine.size() > 0) { - buffer.prepend(TQString(errLine)); - } - //kdDebug(KSSHPROC) << "KSshProcess::getLine(): " - // "line from err -" << errLine << endl; - } - - if( FD_ISSET(ptyfd, &efds) ) { - kdDebug(KSSHPROC) << "KSshProcess::getLine(): " - "Exception on pty file descriptor." << endl; - } - - if( FD_ISSET(errfd, &efds) ) { - kdDebug(KSSHPROC) << "KSshProcess::getLine(): " - "Exception on std err file descriptor." << endl; - } - - if (buffer.size() == 0) { - milliseconds++; - usleep(1000); - } - } - } - - // We should have something in our buffer now. - // Return the last line. - //it = buffer.end(); - //line = *it; - //buffer.remove(it); - - line = buffer.last(); - buffer.pop_back(); - - if( line.isNull() && buffer.count() > 0 ) { - line = buffer.last(); - buffer.pop_back(); - } - -// kdDebug(KSSHPROC) << "KSshProcess::getLine(): " << -// buffer.count() << " lines in buffer" << endl; - kdDebug(KSSHPROC) << "KSshProcess::getLine(): " - "ssh: " << line << endl; - - - return line; -} - -// All the different states we could go through while trying to connect. -enum sshConnectState { - STATE_START, STATE_TRY_PASSWD, STATE_WAIT_PROMPT, STATE_NEW_KEY_CONTINUE, - STATE_DIFF_KEY_CONTINUE, STATE_FATAL, STATE_WAIT_CONTINUE_PROMPT, - STATE_SEND_CONTINUE, STATE_AUTH_FAILED, STATE_NEW_KEY_WAIT_CONTINUE, - STATE_DIFF_KEY_WAIT_CONTINUE, STATE_TRY_PASSPHRASE -}; - -// Print the state as a string. Good for debugging -const char* stateStr(int state) { - switch(state) { - case STATE_START: - return "STATE_START"; - case STATE_TRY_PASSWD: - return "STATE_TRY_PASSWD"; - case STATE_WAIT_PROMPT: - return "STATE_WAIT_PROMPT"; - case STATE_NEW_KEY_CONTINUE: - return "STATE_NEW_KEY_CONTINUE"; - case STATE_DIFF_KEY_CONTINUE: - return "STATE_DIFF_KEY_CONTINUE"; - case STATE_FATAL: - return "STATE_FATAL"; - case STATE_WAIT_CONTINUE_PROMPT: - return "STATE_WAIT_CONTINUE_PROMPT"; - case STATE_SEND_CONTINUE: - return "STATE_SEND_CONTINE"; - case STATE_AUTH_FAILED: - return "STATE_AUTH_FAILED"; - case STATE_NEW_KEY_WAIT_CONTINUE: - return "STATE_NEW_KEY_WAIT_CONTINUE"; - case STATE_DIFF_KEY_WAIT_CONTINUE: - return "STATE_DIFF_KEY_WAIT_CONTINUE"; - case STATE_TRY_PASSPHRASE: - return "STATE_TRY_PASSPHRASE"; - } - return "UNKNOWN"; -} - -bool KSshProcess::connect() { - if( mVersion == UNKNOWN_VER ) { - // we don't know the ssh version yet, so find out - version(); - if( mVersion == -1 ) { - return false; - } - } - - // We'll put a limit on the number of state transitions - // to ensure we don't go out of control. - int transitionLimit = 500; - - while(--transitionLimit) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - << "Connect state " << stateStr(mConnectState) << endl; - - TQString line; // a line from ssh - TQString msgBuf; // buffer for important messages from ssh - // which are to be returned to the user - - switch(mConnectState) { - // STATE_START: - // Executes the ssh binary with the options provided. If no options - // have been specified, sets error and returns false. Continue to - // state 1 if execution is successful, otherwise set error and - // return false. - case STATE_START: - // reset some key values to safe values - mAcceptHostKey = false; - mKeyFingerprint = TQString::null; - mKnownHostsFile = TQString::null; - - if( mArgs.isEmpty() ) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): ssh options " - "need to be set first using setArgs()" << endl; - mError = ERR_NO_OPTIONS; - mErrorMsg = i18n("No options provided for ssh execution."); - return false; - } - - if( ssh.exec(mSshPath.latin1(), mArgs) ) { - kdDebug(KSSHPROC) << - "KSshProcess::connect(): ssh exec failed" << endl; - mError = ERR_CANNOT_LAUNCH; - mErrorMsg = i18n("Failed to execute ssh process."); - return false; - } - - kdDebug(KSSHPROC) << "KSshPRocess::connect(): ssh pid = " << ssh.pid() << endl; - - // set flag to indicate what have started a ssh process - mRunning = true; - mConnectState = STATE_WAIT_PROMPT; - break; - - // STATE_WAIT_PROMPT: - // Get a line of input from the ssh process. Check the contents - // of the line to determine the next state. Ignore the line - // if we don't recognize its contents. If the line contains - // the continue prompt, we have an error since we should never - // get that line in this state. Set ERR_INVALID_STATE error - // and return false. - case STATE_WAIT_PROMPT: - line = getLine(); - if( line.isNull() ) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - "Got null line in STATE_WAIT_PROMPT." << endl; - mError = ERR_INTERACT; - mErrorMsg = - i18n("Error encountered while talking to ssh."); - mConnectState = STATE_FATAL; - } - else if( line.find(TQString::fromLatin1(passwordPrompt[mVersion]), 0, false) != -1 ) { - mConnectState = STATE_TRY_PASSWD; - } - else if( line.find(passphrasePrompt[mVersion]) != -1 ) { - mConnectState = STATE_TRY_PASSPHRASE; - } - else if( line.find(authSuccessMsg[mVersion]) != -1 ) { - return true; - } - else if( line.find(authFailedMsg[mVersion]) != -1 - && line.find(tryAgainMsg[mVersion]) == -1 ) { - mConnectState = STATE_AUTH_FAILED; - } - else if( line.find(hostKeyMissingMsg[mVersion]) != -1 ) { - mConnectState = STATE_NEW_KEY_WAIT_CONTINUE; - } - else if( line.find(hostKeyChangedMsg[mVersion]) != -1 ) { - mConnectState = STATE_DIFF_KEY_WAIT_CONTINUE; - } - else if( line.find(continuePrompt[mVersion]) != -1 ) { - //mConnectState = STATE_SEND_CONTINUE; - kdDebug(KSSHPROC) << "KSshProcess:connect(): " - "Got continue prompt where we shouldn't (STATE_WAIT_PROMPT)" - << endl; - mError = ERR_INTERACT; - mErrorMsg = - i18n("Error encountered while talking to ssh."); - } - else if( line.find(connectionClosedMsg[mVersion]) != -1 ) { - mConnectState = STATE_FATAL; - mError = ERR_CLOSED_BY_REMOTE_HOST; - mErrorMsg = i18n("Connection closed by remote host."); - } - else if( line.find(changeHostKeyOnDiskPrompt[mVersion]) != -1 ) { - // always say yes to this. It always comes after commerical ssh - // prints a "continue to connect prompt". We assume that if the - // user choose to continue, then they also want to save the - // host key to disk. - ssh.writeLine("yes"); - } - else { - // ignore line - } - break; - - // STATE_TRY_PASSWD: - // If we have password send it to the ssh process, else - // set error ERR_NEED_PASSWD and return false to the caller. - // The caller then must then call KSshProcess::setPassword(TQString) - // before calling KSshProcess::connect() again. - // - // Almost exactly liek STATE_TRY_PASSPHRASE. Check there if you - // make changes here. - case STATE_TRY_PASSWD: - // We have a password prompt waiting for us to supply - // a password. Send that password to ssh. If the caller - // did not supply a password like we asked, then ask - // again. - if( !mPassword.isEmpty() ) { -// ssh.WaitSlave(); - ssh.writeLine(mPassword.latin1()); - - // Overwrite the password so it isn't in memory. - mPassword.fill(TQChar('X')); - - // Set the password to null so we will request another - // password if this one fails. - mPassword = TQString::null; - - mConnectState = STATE_WAIT_PROMPT; - } - else { - kdDebug(KSSHPROC) << "KSshProcess::connect() " - "Need password from caller." << endl; - // The caller needs to supply a password before - // connecting can continue. - mError = ERR_NEED_PASSWD; - mErrorMsg = i18n("Please supply a password."); - mConnectState = STATE_TRY_PASSWD; - return false; - } - break; - - // STATE_TRY_KEY_PASSPHRASE: - // If we have passphrase send it to the ssh process, else - // set error ERR_NEED_PASSPHRASE and return false to the caller. - // The caller then must then call KSshProcess::setPassword(TQString) - // before calling KSshProcess::connect() again. - // - // Almost exactly like STATE_TRY_PASSWD. The only difference is - // the error we set if we don't have a passphrase. We duplicate - // this code to keep in the spirit of the state machine. - case STATE_TRY_PASSPHRASE: - // We have a passphrase prompt waiting for us to supply - // a passphrase. Send that passphrase to ssh. If the caller - // did not supply a passphrase like we asked, then ask - // again. - if( !mPassword.isEmpty() ) { -// ssh.WaitSlave(); - ssh.writeLine(mPassword.latin1()); - - // Overwrite the password so it isn't in memory. - mPassword.fill(TQChar('X')); - - // Set the password to null so we will request another - // password if this one fails. - mPassword = TQString::null; - - mConnectState = STATE_WAIT_PROMPT; - } - else { - kdDebug(KSSHPROC) << "KSshProcess::connect() " - "Need passphrase from caller." << endl; - // The caller needs to supply a passphrase before - // connecting can continue. - mError = ERR_NEED_PASSPHRASE; - mErrorMsg = i18n("Please supply the passphrase for " - "your SSH private key."); - mConnectState = STATE_TRY_PASSPHRASE; - return false; - } - break; - - // STATE_AUTH_FAILED: - // Authentication has failed. Tell the caller by setting the - // ERR_AUTH_FAILED error and returning false. If - // auth has failed then ssh should have exited, but - // we will kill it to make sure. - case STATE_AUTH_FAILED: - mError = ERR_AUTH_FAILED; - mErrorMsg = i18n("Authentication to %1 failed").arg(mHost); - mConnectState = STATE_FATAL; - break; - - // STATE_NEW_KEY_WAIT_CONTINUE: - // Grab lines from ssh until we get a continue prompt or a auth - // denied. We will get the later if StrictHostKeyChecking is set - // to yes. Go to STATE_NEW_KEY_CONTINUE if we get a continue prompt. - case STATE_NEW_KEY_WAIT_CONTINUE: - line = getLine(); - if( line.isNull() ) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - "Got null line in STATE_NEW_KEY_WAIT_CONTINUE." << endl; - mError = ERR_INTERACT; - mErrorMsg = - i18n("Error encountered while talking to ssh."); - mConnectState = STATE_FATAL; - } - else if( (line.find(authFailedMsg[mVersion]) != -1 - && line.find(tryAgainMsg[mVersion]) == -1) - || line.find(hostKeyVerifyFailedMsg[mVersion]) != -1 ) { - mError = ERR_AUTH_FAILED_NEW_KEY; - mErrorMsg = i18n( - "The identity of the remote host '%1' could not be verified " - "because the host's key is not in the \"known hosts\" file." - ).arg(mHost); - - if( mKnownHostsFile.isEmpty() ) { - mErrorMsg += i18n( - " Manually, add the host's key to the \"known hosts\" " - "file or contact your administrator." - ); - } - else { - mErrorMsg += i18n( - " Manually, add the host's key to %1 " - "or contact your administrator." - ).arg(mKnownHostsFile); - } - - mConnectState = STATE_FATAL; - } - else if( line.find(continuePrompt[mVersion]) != -1 ) { - mConnectState = STATE_NEW_KEY_CONTINUE; - } - else if( line.find(connectionClosedMsg[mVersion]) != -1 ) { - mConnectState = STATE_FATAL; - mError = ERR_CLOSED_BY_REMOTE_HOST; - mErrorMsg = i18n("Connection closed by remote host."); - } - else if( line.find(keyFingerprintMsg[mVersion]) != -1 ) { - mKeyFingerprint = keyFingerprintMsg[mVersion].cap(); - kdDebug(KSSHPROC) << "Found key fingerprint: " << mKeyFingerprint << endl; - mConnectState = STATE_NEW_KEY_WAIT_CONTINUE; - } - else { - // ignore line - } - break; - - - // STATE_NEW_KEY_CONTINUE: - // We got a continue prompt for the new key message. Set the error - // message to reflect this, return false and hope for caller response. - case STATE_NEW_KEY_CONTINUE: - mError = ERR_NEW_HOST_KEY; - mErrorMsg = i18n( - "The identity of the remote host '%1' could not be " - "verified. The host's key fingerprint is:\n%2\nYou should " - "verify the fingerprint with the host's administrator before " - "connecting.\n\n" - "Would you like to accept the host's key and connect anyway? " - ).arg(mHost).arg(mKeyFingerprint); - mConnectState = STATE_SEND_CONTINUE; - return false; - - // STATE_DIFF_KEY_WAIT_CONTINUE: - // Grab lines from ssh until we get a continue prompt or a auth - // denied. We will get the later if StrictHostKeyChecking is set - // to yes. Go to STATE_DIFF_KEY_CONTINUE if we get a continue prompt. - case STATE_DIFF_KEY_WAIT_CONTINUE: - line = getLine(); - if( line.isNull() ) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - "Got null line in STATE_DIFF_KEY_WAIT_CONTINUE." << endl; - mError = ERR_INTERACT; - mErrorMsg = - i18n("Error encountered while talking to ssh."); - mConnectState = STATE_FATAL; - } - else if( (line.find(authFailedMsg[mVersion]) != -1 - && line.find(tryAgainMsg[mVersion]) == -1) - || line.find(hostKeyVerifyFailedMsg[mVersion]) != -1 ) { - mError = ERR_AUTH_FAILED_DIFF_KEY; - mErrorMsg = i18n( - "WARNING: The identity of the remote host '%1' has changed!\n\n" - "Someone could be eavesdropping on your connection, or the " - "administrator may have just changed the host's key. " - "Either way, you should verify the host's key fingerprint with the host's " - "administrator. The key fingerprint is:\n%2\n" - "Add the correct host key to \"%3\" to " - "get rid of this message." - ).arg(mHost).arg(mKeyFingerprint).arg(mKnownHostsFile); - mConnectState = STATE_FATAL; - } - else if( line.find(continuePrompt[mVersion]) != -1 ) { - mConnectState = STATE_DIFF_KEY_CONTINUE; - } - else if( line.find(keyFingerprintMsg[mVersion]) != -1 ) { - mKeyFingerprint = keyFingerprintMsg[mVersion].cap(); - kdDebug(KSSHPROC) << "Found key fingerprint: " << mKeyFingerprint << endl; - mConnectState = STATE_DIFF_KEY_WAIT_CONTINUE; - } - else if( line.find(knownHostsFileMsg[mVersion]) != -1 ) { - mKnownHostsFile = (knownHostsFileMsg[mVersion]).cap(1); - kdDebug(KSSHPROC) << "Found known hosts file name: " << mKnownHostsFile << endl; - mConnectState = STATE_DIFF_KEY_WAIT_CONTINUE; - } - else { - // ignore line - } - break; - - // STATE_DIFF_KEY_CONTINUE: - // We got a continue prompt for the different key message. - // Set ERR_DIFF_HOST_KEY error - // and return false to signal need to caller action. - case STATE_DIFF_KEY_CONTINUE: - mError = ERR_DIFF_HOST_KEY; - mErrorMsg = i18n( - "WARNING: The identity of the remote host '%1' has changed!\n\n" - "Someone could be eavesdropping on your connection, or the " - "administrator may have just changed the host's key. " - "Either way, you should verify the host's key fingerprint with the host's " - "administrator before connecting. The key fingerprint is:\n%2\n\n" - "Would you like to accept the host's new key and connect anyway?" - ).arg(mHost).arg(mKeyFingerprint); - mConnectState = STATE_SEND_CONTINUE; - return false; - - // STATE_SEND_CONTINUE: - // We found a continue prompt. Send our answer. - case STATE_SEND_CONTINUE: - if( mAcceptHostKey ) { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - "host key accepted" << endl; - ssh.writeLine("yes"); - mConnectState = STATE_WAIT_PROMPT; - } - else { - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - "host key rejected" << endl; - ssh.writeLine("no"); - mError = ERR_HOST_KEY_REJECTED; - mErrorMsg = i18n("Host key was rejected."); - mConnectState = STATE_FATAL; - } - break; - - // STATE_FATAL: - // Something bad happened that we cannot recover from. - // Kill the ssh process and set flags to show we have - // ended the connection and killed ssh. - // - // mError and mErrorMsg should be set by the immediately - // previous state. - case STATE_FATAL: - kill(); - mConnected = false; - mRunning = false; - mConnectState = STATE_START; - // mError, mErroMsg set by last state - return false; - - default: - kdDebug(KSSHPROC) << "KSshProcess::connect(): " - "Invalid state number - " << mConnectState << endl; - mError = ERR_INVALID_STATE; - mConnectState = STATE_FATAL; - } - } - - // we should never get here - kdDebug(KSSHPROC) << "KSshProcess::connect(): " << - "After switch(). We shouldn't be here." << endl; - mError = ERR_INTERNAL; - return false; -} - -void KSshProcess::disconnect() { - kill(); - mConnected = false; - mRunning = false; - mConnectState = STATE_START; -} - diff --git a/kioslave/sftp/ksshprocess.h b/kioslave/sftp/ksshprocess.h deleted file mode 100644 index 5130628e4..000000000 --- a/kioslave/sftp/ksshprocess.h +++ /dev/null @@ -1,623 +0,0 @@ -/*************************************************************************** - ksshprocess.h - description - ------------------- - begin : Tue Jul 31 2001 - copyright : (C) 2001 by Lucas Fisher - email : ljfisher@purdue.edu - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ - -#ifndef KSSHPROCESS_H -#define KSSHPROCESS_H - -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> -#include <unistd.h> - -#include <tqvaluelist.h> - -#include <kdebug.h> - -#include "process.h" - -#define KSSHPROC 7120 - -/** - * Provides version independent access to ssh. Currently supported - * versions of SSH are: - * OpenSSH 2.9p1 - * OpenSSH 2.9p2 - * OpenSSH 3.0 - * OpenSSH 3.1 - * Commercial SSH 3.0.0 - * Other versions of OpenSSH and commerical SSH will probably work also. - * - * To setup a SSH connection first create a list of options to use and tell - * KSshProcess about your options. Then start the ssh connection. Once the - * connection is setup use the stdin, stdout, stderr, and pty file descriptors - * to communicate with ssh. For a detailed example of how to use, see - * ksshprocesstest.cpp. - * - * @author Lucas Fisher - * - * Example: Connect to ssh server on localhost - * KSshProcess::SshOpt opt; - * KSshProcess::SshOptList options; - * - * opt.opt = KSshProcess::SSH_HOST; - * opt.str = "localhost"; - * options.append(opt); - * - * opt.opt = KSshProcess::SSH_USERNAME; - * opt.str = "me"; - * options.append(opt); - * - * KSshProcess ssh; - * if( !ssh.setOptions(options) ) { - * int err = ssh.error(); - * // process error - * return false; - * } - * - * int err; - * TQString errMsg; - * while( !ssh.connect() ) { - * err = ssh.error(errMsg); - * - * switch( err ) { - * case KSshProcess::ERR_NEW_HOST_KEY: - * case KSshProcess::ERR_DIFF_HOST_KEY: - * // ask user to accept key - * if( acceptHostKey ) { - * ssh.acceptKey(true); - * } - * break; - * - * case KSshProcess::ERR_NEED_PASSWORD: - * // ask user for password - * ssh.password(userPassword); - * break; - * - * case KSshProcess::ERR_NEED_KEY_PASSPHRASE: - * // ask user for their key passphrase - * ssh.keyPassphrase(keyPassphrase); - * break; - * - * default: - * // somethings wrong, alert user - * return; - * } - * } - * // We have an open ssh connection to localhost - * - */ - -class KSshProcess { -public: - /** - * SSH Option - * - * Stores SSH options for use with KSshProcess. - * - * SSH options are configured much like UDS entries. - * Each option is assigned a constant and a string, bool, - * or number is assigned based on the option. - * - * @author Lucas Fisher (ljfisher@iastate.edu) - */ - class SshOpt { - public: - TQ_UINT32 opt; - TQString str; - TQ_INT32 num; - bool boolean; - }; - - /** - * List of SshOptions and associated iterators - */ - typedef TQValueList<SshOpt> SshOptList; - typedef TQValueListIterator<SshOpt> SshOptListIterator; - typedef TQValueListConstIterator<SshOpt> SshOptListConstIterator; - - /** - * Ssh versions supported by KSshProcess. Subject to change - * at any time. - */ - enum SshVersion { - OPENSSH_3_6, - OPENSSH, - SSH, - SSH_VER_MAX, - UNKNOWN_VER - }; - - /** - * SSH options supported by KSshProcess. Set SshOpt::opt to one of these - * values. - */ - // we cannot do this like UDSAtomType (ORing the type with the name) because - // we have too many options for ssh and not enough bits. - enum SshOptType { - /** - * Request server to invoke subsystem. (str) - */ - SSH_SUBSYSTEM, - /** - * Connect to port on the server. (num) - */ - SSH_PORT, - /** - * Connect to host. (str) - */ - SSH_HOST, - /** - * connect using this username. (str) - */ - SSH_USERNAME, - /** - * connect using this password. (str) - */ - SSH_PASSWD, - /** - * connect using this version of the SSH protocol. num == 1 or 2 - */ - SSH_PROTOCOL, - /** - * whether to forward X11 connections. (boolean) - */ - SSH_FORWARDX11, - /** - * whether to do agent forwarding. (boolean) - */ - SSH_FORWARDAGENT, - /** - * use as escape character. 0 for none (num) - */ - SSH_ESCAPE_CHAR, - /** - * command for ssh to perform once it is connected (str) - */ - SSH_COMMAND, - /** - * Set ssh verbosity. This may be added multiple times. It may also cause KSSHProcess - * to fail since we don't understand all the debug messages. - */ - SSH_VERBOSE, - /** - * Set a ssh option as one would find in the ssh_config file - * The str member should be set to 'optName value' - */ - SSH_OPTION, - /** - * Set some other option not supported by KSSHProcess. The option should - * be specified in the str member of SshOpt. Careful with this since - * not all versions of SSH support the same options. - */ - SSH_OTHER, - SSH_OPT_MAX // always last - }; // that's all for now - - /** - * Errors that KSshProcess can encounter. When a member function returns - * false, call error() to retrieve one of these error codes. - */ - enum SshError { - /** - * Don't recognize the ssh version - */ - ERR_UNKNOWN_VERSION, - /** - * Cannot lauch ssh client - */ - ERR_CANNOT_LAUNCH, - /** - * Interaction with the ssh client failed. This happens when we can't - * find the password prompt or something similar - */ - ERR_INTERACT, - /** - * Arguments for both a remotely executed subsystem and command were provide. - * Only one or the other may be used - */ - ERR_CMD_SUBSYS_CONFLICT, - /** - * No password was supplied - */ - ERR_NEED_PASSWD, - /** - * No passphrase was supplied. - */ - ERR_NEED_PASSPHRASE, - /** - * No usename was supplied - */ - ERR_NEED_USERNAME, - /** - * Timed out waiting for a response from ssh or the server - */ - ERR_TIMED_OUT, - /** - * Internal error, probably from a system call - */ - ERR_INTERNAL, - /** - * ssh was disconnect from the host - */ - ERR_DISCONNECTED, - /** - * No ssh options have been set. Call setArgs() before calling connect. - */ - ERR_NO_OPTIONS, - /** - * A host key was received from an unknown host. - * Call connect() with the acceptHostKey argument to accept the key. - */ - ERR_NEW_HOST_KEY, - /** - * A host key different from what is stored in the user's known_hosts file - * has be received. This is an indication of an attack - */ - ERR_DIFF_HOST_KEY, - /** - * A new or different host key was rejected by the caller. The ssh - * connection was terminated and the ssh process killed. - */ - ERR_HOST_KEY_REJECTED, - /** - * An invalid option was found in the SSH option list - */ - ERR_INVALID_OPT, - /** - * SSH accepted host key without prompting user. - */ - ERR_ACCEPTED_KEY, - /** - * Authentication failed - */ - ERR_AUTH_FAILED, - /** - * Authentication failed because a new host key was detected and - * SSH is configured with strict host key checking enabled. - */ - ERR_AUTH_FAILED_NEW_KEY, - /** - * Authentication failed because a changed host key was detected and - * SSH is configured with strict host key checking enabled. - */ - ERR_AUTH_FAILED_DIFF_KEY, - /** - * The remote host closed the connection for unknown reasons. - */ - ERR_CLOSED_BY_REMOTE_HOST, - /** - * We have no idea what happened - */ - ERR_UNKNOWN, - /** - * The connect state machine entered an invalid state. - */ - ERR_INVALID_STATE, - ERR_MAX - }; - - /** - * Initialize a SSH process using the first SSH binary found in the PATH - */ - KSshProcess(); - - /** - * Initialize a SSH process using the specified SSH binary. - * @param pathToSsh The fully qualified path name of the ssh binary - * KSshProcess should use to setup a SSH connection. - */ - KSshProcess(TQString pathToSsh); - ~KSshProcess(); - - /** - * Set the ssh binary KSshProcess should use. This will only affect the - * next ssh connection attempt using this instance. - * - * @param pathToSsh Full path to the ssh binary. - * - * @return True if the ssh binary is found and KSshProcess - * recognizes the version. - * - */ - bool setSshPath(TQString pathToSsh); - - /** - * Get the ssh version. - * - * @return The ssh version or -1 if KSshProcess does not recognize - * the ssh version. The returned value corresponds to the - * member of the SshVersion enum. - */ - SshVersion version(); - - /** - * Get a string describing the ssh version - * - * @return A string describing the ssh version recognized by KSshProcess - */ - //TQString versionStr(); - - /** - * Get the last error encountered by KSshProcess. - * - * @param msg Set to the error message, if any, outputted by ssh when it is run. - * - * @return The error number. See SshError for descriptions. - */ - int error(TQString& msg); - - /** - * Get the last error encountered by KSshProcess. - * @return The error number. See SshError for descriptions. - */ - int error() { return mError; } - - TQString errorMsg() { return mErrorMsg; } - - /** - * Send a signal to the ssh process. Do not use this to end the - * ssh connection as it will not correctly reset the internal - * state of the KSshProcess object. Use KSshProcess::disconnect() - * instead. - * - * @param signal The signal to send to the ssh process. See 'kill -l' - * for a list of possible signals. - * The default signal is SIGKILL which kills ssh. - * - */ - void kill(int signal = SIGKILL); - - /** - * The pid of the ssh process started by this instance of KSshProcess. - * Only valid if KSshProcess::running() returns true; - * - * @return The pid of the running ssh process. - */ - int pid() { return ssh.pid(); } - - /** - * Whether a ssh connection has been established with a - * remote host. A establish connection means ssh has successfully - * authenticated with the remote host and user data can be transfered - * between the local and remote host. This cannot return - * true unless the most recent call to KSshProccess::connect() returned true. - * - * @return True if a ssh connection has been established with a remote - * host. False otherwise. - */ - bool connected() { return mConnected; } - - /** - * Whether a ssh process is currently running. This only indicates - * if a ssh process has been started and is still running. It does not - * tell if authentication has been successful. This may return true - * even if the most recent call to KSshProcess::connect() returned false. - * - * @return True if a ssh process started by this instance of KSshProcess - * is running. False otherwise. - */ - bool running() { return mRunning; } - - /** - * Print the command line arguments ssh is run with using kdDebug. - */ - void printArgs(); - - /** - * Set the SSH options. - * This must be called before connect(). See SshOptType for a list of - * supported ssh options. The required options are SSH_USERNAME - * and SSH_HOST. - * - * To reset the saved options, just recall setOptions() again with - * a different options list. - * - * @param opts A list of SshOpt objects specifying the ssh options. - * - * @return True if all options are valid. False if unrecognized options - * or a required option is missing. Call error() - * for details. - * - */ - bool setOptions(const SshOptList& opts); - - /** - * Create a ssh connection based on the options provided by setOptions(). - * Sets one of the following error codes on failure: - * <ul> - * <li>ERR_NO_OPTIONS</li> - * <li>ERR_CANNOT_LAUNCH</li> - * <li>ERR_INVALID_STATE</li> - * <li>ERR_NEED_PASSWD</li> - * <li>ERR_AUTH_FAILED</li> - * <li>ERR_NEW_HOST_KEY</li> - * <li>ERR_KEY_ACCEPTED</li> - * <li>ERR_DIFF_HOST_KEY</li> - * <li>ERR_INTERNAL</li> - * <li>ERR_INTERACT</li> - * </ul> - * - * @param acceptHostKey When true KSshProcess will automatically accept - * unrecognized or changed host keys. - * - * @return True if the ssh connection is successful. False if the connection - * fails. Call error() to get the reason for the failure. - */ - bool connect(); - - - /** - * Disconnect ssh from the host. This kills the ssh process and - * resets the internal state of this KSshProcess object. After a - * disconnect, the same KSshProcess can be used to connect to a - * host. - */ - void disconnect(); - - /** - * Call to respond to a ERR_NEW_HOST_KEY or ERR_DIFF_HOST_KEY error. - * - * @param accept True to accept the host key, false to not accept the - * host key and kill ssh. - * - */ - void acceptHostKey(bool accept); - - /** - * Call to respond to a ERR_NEED_PASSWD or ERR_NEED_PASSPHRASE error. - * - * @param password The user password to give ssh. - */ - void setPassword(TQString password); - - /** - * Access to standard in and out of the ssh process. - * - * @return The file description for stdin and stdout of the ssh process. - */ - int stdioFd() { return ssh.stdioFd(); } - - /** - * Access to standard error of the ssh process. - * - * @return The file descriptior for stderr of the ssh process. - */ - int stderrFd() { return ssh.stderrFd(); } - - /** - * Access the pty to which the ssh process is attached. - * - * @return The file descriptor of pty to which ssh is attached. - */ - int pty() { return ssh.fd(); } -private: - /** - * Path the the ssh binary. - */ - TQString mSshPath; - - /** - * SSH version. This is an index into the supported SSH - * versions array, and the various messages arrays. - */ - SshVersion mVersion; - - /** - * User's password. Zero this out when it is no longer needed. - */ - TQString mPassword; - - /** - * User's username. - */ - TQString mUsername; - - /** - * Name of host we are connecting to. - */ - TQString mHost; - - /** - * Accept new or changed host keys if true. - */ - bool mAcceptHostKey; - - /** - * Flag to tell use if we have an open, authenticated ssh - * session going. - */ - bool mConnected; - - /** - * Flag to tell us if we have started a ssh process, we use this - * to make sure we kill ssh before going away. - */ - bool mRunning; - - /** - * Save any key fingerprint msg from ssh so we can present - * it to the caller. - */ - TQString mKeyFingerprint; - - /** - * The location of the known host key file. We grab this from - * any error messages ssh prints out. - */ - TQString mKnownHostsFile; - - /** - * The state of our connect state machine. - */ - int mConnectState; - - /** - * Port on on which the target ssh server is listening. - */ - int mPort; - - /** - * The last error number encountered. This is only valid for the - * last error. - */ - SshError mError; - - /** - * An error message that corresponds to the error number set in - * mError. Optional. - */ - TQString mErrorMsg; - - /** - * Interface to the SSH process we ceate. Handles communication - * to and from the SSH process using stdin, stdout, stderr, and - * pty. - */ - MyPtyProcess ssh; - - /** - * List of arguments we start SSH with. - */ - QCStringList mArgs; - void init(); - - /** - * Handler to clean up when ssh process terminates. - */ - static void SIGCHLD_handler(int signo); - void installSignalHandlers(); - void removeSignalHandlers(); - - TQString getLine(); - - static TQRegExp versionStrs[]; - static const char * const passwordPrompt[]; - static const char * const passphrasePrompt[]; - static const char * const authSuccessMsg[]; - static const char * const authFailedMsg[]; - static TQRegExp hostKeyMissingMsg[]; - static const char * const hostKeyChangedMsg[]; - static const char * const continuePrompt[]; - static const char * const hostKeyAcceptedMsg[]; - static const char * const tryAgainMsg[]; - static TQRegExp hostKeyVerifyFailedMsg[]; - static const char * const connectionClosedMsg[]; - static const char * const changeHostKeyOnDiskPrompt[]; - static TQRegExp keyFingerprintMsg[]; - static TQRegExp knownHostsFileMsg[]; -}; -#endif diff --git a/kioslave/sftp/ksshprocesstest.cpp b/kioslave/sftp/ksshprocesstest.cpp deleted file mode 100644 index 59dbf58c7..000000000 --- a/kioslave/sftp/ksshprocesstest.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "ksshprocess.h" -#include <iostream> - -using namespace std; - -int main(int argc, char *argv[]) { - - if( argc < 5 ) { - cout << "Usage: " << argv[0] << - " <ssh path> <host> <username> <password>" << endl; - return 1; - } - - KSshProcess ssh(argv[1]); - cout << ssh.version() << endl; - - KSshProcess::SshOptList opts; - KSshProcess::SshOpt opt; - - opt.opt = KSshProcess::SSH_PORT; - opt.num = 22; - opts.append(opt); - - opt.opt = KSshProcess::SSH_HOST; - opt.str = TQString(argv[2]); - opts.append(opt); - - opt.opt = KSshProcess::SSH_USERNAME; - opt.str = TQString(argv[3]); - opts.append(opt); - -// opt.opt = KSshProcess::SSH_PASSWD; -// opt.str = TQString(argv[4]); -// opts.append(opt); - - if( !ssh.setOptions(opts) ) { - cout << "ksshprocesstest: setOptions failed" << endl; - return -1; - } - - ssh.printArgs(); - - bool stop = false; - bool connected; - char buf[256]; - char c; - while( !stop && !(connected = ssh.connect()) ) { - cout << "ksshprocesstest: Error num - " << ssh.error() << endl; - cout << "ksshprocesstest: Error msg - " << ssh.errorMsg().latin1() << endl; - switch( ssh.error() ) { - case KSshProcess::ERR_NEED_PASSWD: - case KSshProcess::ERR_NEED_PASSPHRASE: - cout << "Password: "; - cin >> buf; - cout << "password is " << buf << endl; - ssh.setPassword(TQString(buf)); - break; - case KSshProcess::ERR_NEW_HOST_KEY: - case KSshProcess::ERR_DIFF_HOST_KEY: - cout << "Accept host key? (y/n): "; - cin >> c; - cout << "Answered " << c << endl; - ssh.acceptHostKey(c == 'y' ? true : false); - break; - case KSshProcess::ERR_AUTH_FAILED: - cout << "ksshprocesstest: auth failed." << endl; - stop = true; - break; - case KSshProcess::ERR_AUTH_FAILED_NEW_KEY: - cout << "ksshprocesstest: auth failed because of new key." << endl; - stop = true; - break; - case KSshProcess::ERR_AUTH_FAILED_DIFF_KEY: - cout << "ksshprocesstest: auth failed because of changed key." << endl; - stop = true; - break; - - case KSshProcess::ERR_INTERACT: - case KSshProcess::ERR_INTERNAL: - case KSshProcess::ERR_UNKNOWN: - case KSshProcess::ERR_INVALID_STATE: - case KSshProcess::ERR_CANNOT_LAUNCH: - case KSshProcess::ERR_HOST_KEY_REJECTED: - cout << "ksshprocesstest: FATAL ERROR" << endl; - stop = true; - break; - - } - } - - if( connected ) { - cout << "ksshprocesstest: Successfully connected to " << argv[2] << endl; - } - else { - cout << "ksshprocesstest: Connect to " << argv[2] << " failed." << endl; - } - -} diff --git a/kioslave/sftp/process.cpp b/kioslave/sftp/process.cpp deleted file mode 100644 index 885fe7636..000000000 --- a/kioslave/sftp/process.cpp +++ /dev/null @@ -1,493 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * - * This file is part of the KDE project, module tdesu. - * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org> - * - * This file contains code from TEShell.C of the KDE konsole. - * Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> - * - * 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. - * - * process.cpp: Functionality to build a front end to password asking - * terminal programs. - */ - -#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 <termios.h> -#include <signal.h> - -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/socket.h> - -#if defined(__SVR4) && defined(sun) -#include <stropts.h> -#include <sys/stream.h> -#endif - -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> // Needed on some systems. -#endif - -#include <tqglobal.h> -#include <tqcstring.h> -#include <tqfile.h> - -#include <kdebug.h> -#include <kstandarddirs.h> - -#include "process.h" -#include <tdesu/tdesu_pty.h> -#include <tdesu/kcookie.h> - - -MyPtyProcess::MyPtyProcess() -{ - m_bTerminal = false; - m_bErase = false; - m_pPTY = 0L; - m_Pid = -1; - m_Fd = -1; -} - - -int MyPtyProcess::init() -{ - delete m_pPTY; - m_pPTY = new PTY(); - m_Fd = m_pPTY->getpt(); - if (m_Fd < 0) - return -1; - if ((m_pPTY->grantpt() < 0) || (m_pPTY->unlockpt() < 0)) - { - kdError(PTYPROC) << k_lineinfo << "Master setup failed.\n" << endl; - m_Fd = -1; - return -1; - } - m_TTY = m_pPTY->ptsname(); - m_stdoutBuf.resize(0); - m_stderrBuf.resize(0); - m_ptyBuf.resize(0); - return 0; -} - - -MyPtyProcess::~MyPtyProcess() -{ - delete m_pPTY; -} - - -/* - * Read one line of input. The terminal is in canonical mode, so you always - * read a line at at time, but it's possible to receive multiple lines in - * one time. - */ - - -TQCString MyPtyProcess::readLineFrom(int fd, TQCString& inbuf, bool block) -{ - int pos; - TQCString ret; - - if (!inbuf.isEmpty()) - { - - pos = inbuf.find('\n'); - - if (pos == -1) - { - ret = inbuf; - inbuf.resize(0); - } else - { - ret = inbuf.left(pos); - inbuf = inbuf.mid(pos+1); - } - return ret; - - } - - int flags = fcntl(fd, F_GETFL); - if (flags < 0) - { - kdError(PTYPROC) << k_lineinfo << "fcntl(F_GETFL): " << perror << "\n"; - return ret; - } - if (block) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, flags) < 0) - { - kdError(PTYPROC) << k_lineinfo << "fcntl(F_SETFL): " << perror << "\n"; - return ret; - } - - int nbytes; - char buf[256]; - while (1) - { - nbytes = read(fd, buf, 255); - if (nbytes == -1) - { - if (errno == EINTR) - continue; - else break; - } - if (nbytes == 0) - break; // eof - - buf[nbytes] = '\000'; - inbuf += buf; - - pos = inbuf.find('\n'); - if (pos == -1) - { - ret = inbuf; - inbuf.resize(0); - } else - { - ret = inbuf.left(pos); - inbuf = inbuf.mid(pos+1); - } - break; - - } - - return ret; -} - -void MyPtyProcess::writeLine(TQCString line, bool addnl) -{ - if (!line.isEmpty()) - write(m_Fd, line, line.length()); - if (addnl) - write(m_Fd, "\n", 1); -} - -void MyPtyProcess::unreadLineFrom(TQCString inbuf, TQCString line, bool addnl) -{ - if (addnl) - line += '\n'; - if (!line.isEmpty()) - inbuf.prepend(line); -} - - -/* - * Fork and execute the command. This returns in the parent. - */ - -int MyPtyProcess::exec(TQCString command, QCStringList args) -{ - kdDebug(PTYPROC) << "MyPtyProcess::exec(): " << command << endl;// << ", args = " << args << endl; - - if (init() < 0) - return -1; - - // Open the pty slave before forking. See SetupTTY() - int slave = open(m_TTY, O_RDWR); - if (slave < 0) - { - kdError(PTYPROC) << k_lineinfo << "Could not open slave pty.\n"; - return -1; - } - - // Also create a socket pair to connect to standard in/out. - // This will allow use to bypass the terminal. - int inout[2]; - int err[2]; - int ok = 1; - ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, inout) >= 0; - ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, err ) >= 0; - if( !ok ) { - kdDebug(PTYPROC) << "Could not create socket" << endl; - return -1; - } - m_stdinout = inout[0]; - m_err = err[0]; - - if ((m_Pid = fork()) == -1) - { - kdError(PTYPROC) << k_lineinfo << "fork(): " << perror << "\n"; - return -1; - } - - // Parent - if (m_Pid) - { - close(slave); - close(inout[1]); - close(err[1]); - return 0; - } - - // Child - - ok = 1; - ok &= dup2(inout[1], STDIN_FILENO) >= 0; - ok &= dup2(inout[1], STDOUT_FILENO) >= 0; - ok &= dup2(err[1], STDERR_FILENO) >= 0; - - if( !ok ) - { - kdError(PTYPROC) << "dup of socket descriptor failed" << endl; - _exit(1); - } - - close(inout[1]); - close(inout[0]); - close(err[1]); - close(err[0]); - - if (SetupTTY(slave) < 0) - _exit(1); - - // From now on, terminal output goes through the tty. - TQCString path; - if (command.contains('/')) - path = command; - else - { - TQString file = KStandardDirs::findExe(command); - if (file.isEmpty()) - { - kdError(PTYPROC) << k_lineinfo << command << " not found\n"; - _exit(1); - } - path = TQFile::encodeName(file); - } - - int i; - const char * argp[32]; - argp[0] = path; - QCStringList::Iterator it; - for (i=1, it=args.begin(); it!=args.end() && i<31; it++) { - argp[i++] = *it; - kdDebug(PTYPROC) << *it << endl; - } - argp[i] = 0L; - execv(path, (char * const *)argp); - kdError(PTYPROC) << k_lineinfo << "execv(\"" << path << "\"): " << perror << "\n"; - _exit(1); - return -1; // Shut up compiler. Never reached. -} - -/* - * Wait until the terminal is set into no echo mode. At least one su - * (RH6 w/ Linux-PAM patches) sets noecho mode AFTER writing the Password: - * prompt, using TCSAFLUSH. This flushes the terminal I/O queues, possibly - * taking the password with it. So we wait until no echo mode is set - * before writing the password. - * Note that this is done on the slave fd. While Linux allows tcgetattr() on - * the master side, Solaris doesn't. - */ - -int MyPtyProcess::WaitSlave() -{ - int slave = open(m_TTY, O_RDWR); - if (slave < 0) - { - kdError(PTYPROC) << k_lineinfo << "Could not open slave tty.\n"; - return -1; - } - - struct termios tio; - struct timeval tv; - while (1) - { - if (tcgetattr(slave, &tio) < 0) - { - kdError(PTYPROC) << k_lineinfo << "tcgetattr(): " << perror << "\n"; - close(slave); - return -1; - } - if (tio.c_lflag & ECHO) - { - kdDebug(PTYPROC) << k_lineinfo << "Echo mode still on." << endl; - // sleep 1/10 sec - tv.tv_sec = 0; tv.tv_usec = 100000; - select(slave, 0L, 0L, 0L, &tv); - continue; - } - break; - } - close(slave); - return 0; -} - - -int MyPtyProcess::enableLocalEcho(bool enable) -{ - int slave = open(m_TTY, O_RDWR); - if (slave < 0) - { - kdError(PTYPROC) << k_lineinfo << "Could not open slave tty.\n"; - return -1; - } - struct termios tio; - if (tcgetattr(slave, &tio) < 0) - { - kdError(PTYPROC) << k_lineinfo << "tcgetattr(): " << perror << "\n"; - close(slave); return -1; - } - if (enable) - tio.c_lflag |= ECHO; - else - tio.c_lflag &= ~ECHO; - if (tcsetattr(slave, TCSANOW, &tio) < 0) - { - kdError(PTYPROC) << k_lineinfo << "tcsetattr(): " << perror << "\n"; - close(slave); return -1; - } - close(slave); - return 0; -} - - -/* - * Copy output to stdout until the child process exists, or a line of output - * matches `m_Exit'. - * We have to use waitpid() to test for exit. Merely waiting for EOF on the - * pty does not work, because the target process may have children still - * attached to the terminal. - */ - -int MyPtyProcess::waitForChild() -{ - int ret, state, retval = 1; - struct timeval tv; - - fd_set fds; - FD_ZERO(&fds); - - while (1) - { - tv.tv_sec = 1; tv.tv_usec = 0; - FD_SET(m_Fd, &fds); - ret = select(m_Fd+1, &fds, 0L, 0L, &tv); - if (ret == -1) - { - if (errno == EINTR) continue; - else - { - kdError(PTYPROC) << k_lineinfo << "select(): " << perror << "\n"; - return -1; - } - } - - if (ret) - { - TQCString line = readLine(false); - while (!line.isNull()) - { - if (!m_Exit.isEmpty() && !tqstrnicmp(line, m_Exit, m_Exit.length())) - kill(m_Pid, SIGTERM); - if (m_bTerminal) - { - fputs(line, stdout); - fputc('\n', stdout); - } - line = readLine(false); - } - } - - // Check if the process is still alive - ret = waitpid(m_Pid, &state, WNOHANG); - if (ret < 0) - { - if (errno == ECHILD) - retval = 0; - else - kdError(PTYPROC) << k_lineinfo << "waitpid(): " << perror << "\n"; - break; - } - if (ret == m_Pid) - { - if (WIFEXITED(state)) - retval = WEXITSTATUS(state); - break; - } - } - - return -retval; -} - -/* - * SetupTTY: Creates a new session. The filedescriptor "fd" should be - * connected to the tty. It is closed after the tty is reopened to make it - * our controlling terminal. This way the tty is always opened at least once - * so we'll never get EIO when reading from it. - */ - -int MyPtyProcess::SetupTTY(int fd) -{ - // Reset signal handlers - for (int sig = 1; sig < NSIG; sig++) - signal(sig, SIG_DFL); - signal(SIGHUP, SIG_IGN); - - // Close all file handles -// struct rlimit rlp; -// getrlimit(RLIMIT_NOFILE, &rlp); -// for (int i = 0; i < (int)rlp.rlim_cur; i++) -// if (i != fd) close(i); - - // Create a new session. - setsid(); - - // Open slave. This will make it our controlling terminal - int slave = open(m_TTY, O_RDWR); - if (slave < 0) - { - kdError(PTYPROC) << k_lineinfo << "Could not open slave side: " << perror << "\n"; - return -1; - } - close(fd); - -#if defined(__SVR4) && defined(sun) - - // Solaris STREAMS environment. - // Push these modules to make the stream look like a terminal. - ioctl(slave, I_PUSH, "ptem"); - ioctl(slave, I_PUSH, "ldterm"); - -#endif - - // Connect stdin, stdout and stderr -// dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); -// if (slave > 2) -// close(slave); - - // Disable OPOST processing. Otherwise, '\n' are (on Linux at least) - // translated to '\r\n'. - struct termios tio; - if (tcgetattr(slave, &tio) < 0) - { - kdError(PTYPROC) << k_lineinfo << "tcgetattr(): " << perror << "\n"; - return -1; - } - tio.c_oflag &= ~OPOST; - if (tcsetattr(slave, TCSANOW, &tio) < 0) - { - kdError(PTYPROC) << k_lineinfo << "tcsetattr(): " << perror << "\n"; - return -1; - } - - return 0; -} diff --git a/kioslave/sftp/process.h b/kioslave/sftp/process.h deleted file mode 100644 index 215c51ea7..000000000 --- a/kioslave/sftp/process.h +++ /dev/null @@ -1,148 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * - * This file is part of the KDE project, module tdesu. - * Copyright (C) 1999,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. - */ - -#ifndef __Process_h_Included__ -#define __Process_h_Included__ - -#include <tqcstring.h> -#include <tqstring.h> -#include <tqstringlist.h> -#include <tqvaluelist.h> - -#define PTYPROC 7120 - -class PTY; -typedef TQValueList<TQCString> QCStringList; - -/** - * Synchronous communication with tty programs. - * - * PtyProcess provides synchronous communication with tty based programs. - * The communications channel used is a pseudo tty (as opposed to a pipe) - * This means that programs which require a terminal will work. - */ - -class MyPtyProcess -{ -public: - MyPtyProcess(); - virtual ~MyPtyProcess(); - - /** - * Fork off and execute a command. The command's standard in and output - * are connected to the pseudo tty. They are accessible with @ref #readLine - * and @ref #writeLine. - * @param command The command to execute. - * @param args The arguments to the command. - */ - int exec(TQCString command, QCStringList args); - - /** - * Read a line from the program's standard out. Depending on the @em block - * parameter, this call blocks until a single, full line is read. - * @param block Block until a full line is read? - * @return The output string. - */ - TQCString readLine(bool block = true) - { return readLineFrom(m_Fd, m_ptyBuf, block); } - - TQCString readLineFromPty(bool block = true) - { return readLineFrom(m_Fd, m_ptyBuf, block); } - - TQCString readLineFromStdout(bool block = true) - { return readLineFrom(m_stdinout, m_stdoutBuf, block); } - - TQCString readLineFromStderr(bool block = true) - { return readLineFrom(m_err, m_stderrBuf, block); } - - /** - * Write a line of text to the program's standard in. - * @param line The text to write. - * @param addNewline Adds a '\n' to the line. - */ - void writeLine(TQCString line, bool addNewline=true); - - /** - * Put back a line of input. - * @param line The line to put back. - * @param addNewline Adds a '\n' to the line. - */ - - void unreadLine(TQCString line, bool addNewline = true) - { unreadLineFrom(m_ptyBuf, line, addNewline); } - - void unreadLineFromPty(TQCString line, bool addNewline = true) - { unreadLineFrom(m_ptyBuf, line, addNewline); } - - void unreadLineFromStderr(TQCString line, bool addNewline = true) - { unreadLineFrom(m_stderrBuf, line, addNewline); } - - void unreadLineFromStdout(TQCString line, bool addNewline = true) - { unreadLineFrom(m_stdoutBuf, line, addNewline); } - - /** - * Set exit string. If a line of program output matches this, - * @ref #waitForChild() will terminate the program and return. - */ - void setExitString(TQCString exit) { m_Exit = exit; } - - /** - * Wait for the child to exit. See also @ref #setExitString. - */ - int waitForChild(); - - /** - * Wait until the pty has cleared the ECHO flag. This is useful - * when programs write a password prompt before they disable ECHO. - * Disabling it might flush any input that was written. - */ - int WaitSlave(); - - /** Enables/disables local echo on the pseudo tty. */ - int enableLocalEcho(bool enable=true); - - /** Enable/disable terminal output. Relevant only to some subclasses. */ - void setTerminal(bool terminal) { m_bTerminal = terminal; } - - /** Overwritte the password as soon as it is used. Relevant only to - * some subclasses. */ - void setErase(bool erase) { m_bErase = erase; } - - /** Return the filedescriptor of the process. */ - int fd() {return m_Fd;} - - /** Return the pid of the process. */ - int pid() {return m_Pid;} - - int stdioFd() {return m_stdinout;} - - int stderrFd() {return m_err;} - -protected: - bool m_bErase, m_bTerminal; - int m_Pid, m_Fd, m_stdinout, m_err; - TQCString m_Command, m_Exit; - -private: - int init(); - int SetupTTY(int fd); - - PTY *m_pPTY; - TQCString m_TTY; - TQCString m_ptyBuf, m_stderrBuf, m_stdoutBuf; - - TQCString readLineFrom(int fd, TQCString& inbuf, bool block); - void unreadLineFrom(TQCString inbuf, TQCString line, bool addnl); - class PtyProcessPrivate; - PtyProcessPrivate *d; -}; - -#endif diff --git a/kioslave/sftp/sftp.h b/kioslave/sftp/sftp.h deleted file mode 100644 index 95518130d..000000000 --- a/kioslave/sftp/sftp.h +++ /dev/null @@ -1,91 +0,0 @@ -/* $OpenBSD: sftp.h,v 1.3 2001/03/07 10:11:23 djm Exp $ */ - -/* - * Copyright (c) 2001 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * draft-ietf-secsh-filexfer-01.txt - */ - -/* version */ -#define SSH2_FILEXFER_VERSION 3 - -/* client to server */ -#define SSH2_FXP_INIT 1 -#define SSH2_FXP_OPEN 3 -#define SSH2_FXP_CLOSE 4 -#define SSH2_FXP_READ 5 -#define SSH2_FXP_WRITE 6 -#define SSH2_FXP_LSTAT 7 -#define SSH2_FXP_FSTAT 8 -#define SSH2_FXP_SETSTAT 9 -#define SSH2_FXP_FSETSTAT 10 -#define SSH2_FXP_OPENDIR 11 -#define SSH2_FXP_READDIR 12 -#define SSH2_FXP_REMOVE 13 -#define SSH2_FXP_MKDIR 14 -#define SSH2_FXP_RMDIR 15 -#define SSH2_FXP_REALPATH 16 -#define SSH2_FXP_STAT 17 -#define SSH2_FXP_RENAME 18 -#define SSH2_FXP_READLINK 19 -#define SSH2_FXP_SYMLINK 20 - -/* server to client */ -#define SSH2_FXP_VERSION 2 -#define SSH2_FXP_STATUS 101 -#define SSH2_FXP_HANDLE 102 -#define SSH2_FXP_DATA 103 -#define SSH2_FXP_NAME 104 -#define SSH2_FXP_ATTRS 105 - -#define SSH2_FXP_EXTENDED 200 -#define SSH2_FXP_EXTENDED_REPLY 201 - -/* attributes */ -#define SSH2_FILEXFER_ATTR_SIZE 0x00000001 -#define SSH2_FILEXFER_ATTR_UIDGID 0x00000002 -#define SSH2_FILEXFER_ATTR_PERMISSIONS 0x00000004 -#define SSH2_FILEXFER_ATTR_ACMODTIME 0x00000008 -#define SSH2_FILEXFER_ATTR_EXTENDED 0x80000000 - -/* portable open modes */ -#define SSH2_FXF_READ 0x00000001 -#define SSH2_FXF_WRITE 0x00000002 -#define SSH2_FXF_APPEND 0x00000004 -#define SSH2_FXF_CREAT 0x00000008 -#define SSH2_FXF_TRUNC 0x00000010 -#define SSH2_FXF_EXCL 0x00000020 - -/* status messages */ -#define SSH2_FX_OK 0 -#define SSH2_FX_EOF 1 -#define SSH2_FX_NO_SUCH_FILE 2 -#define SSH2_FX_PERMISSION_DENIED 3 -#define SSH2_FX_FAILURE 4 -#define SSH2_FX_BAD_MESSAGE 5 -#define SSH2_FX_NO_CONNECTION 6 -#define SSH2_FX_CONNECTION_LOST 7 -#define SSH2_FX_OP_UNSUPPORTED 8 -#define SSH2_FX_MAX 8 diff --git a/kioslave/sftp/sftp.protocol b/kioslave/sftp/sftp.protocol deleted file mode 100644 index 177cd86e9..000000000 --- a/kioslave/sftp/sftp.protocol +++ /dev/null @@ -1,84 +0,0 @@ -[Protocol] -exec=kio_sftp -protocol=sftp -input=none -listing=Name,Type,Size,Date,Access,Owner,Group,Link -output=filesystem -copyToFile=true -copyFromFile=true -reading=true -writing=true -makedir=true -deleting=true -moving=true -Icon=ftp -Description=A kioslave for sftp -Description[af]='n Kioslave vir sftp -Description[be]=Kioslave для sftp -Description[bg]=kioslave за sftp -Description[bn]=এস.এফ.টি.পি-র জন্য একটি kioslave -Description[br]=Ur kioslave evit sftp -Description[bs]=kioslave za SFTP -Description[ca]=Un kioslave per a sftp -Description[cs]=Protokol KDE pro sftp -Description[csb]=Plugins dlô procedurë òbsłużënkù sftp -Description[da]=En kioslave for sftp -Description[de]=Ein-/Ausgabemodul für das sftp-Protokoll -Description[el]=Ένας kioslave για sftp -Description[eo]=kenelsklavo por sftp -Description[es]=Un kioslave para sftp -Description[et]=SFTP IO-moodul -Description[eu]=Sftp-rako kioslave bat -Description[fa]=یک kioslave برای sftp -Description[fi]=Sftp:n liitin -Description[fr]=Un module d'entrées / sorties pour le sftp -Description[fy]=Een kioslave Foar sftp -Description[ga]=kioslave le haghaidh sftp -Description[gl]=Un kioslave para sftp -Description[he]=ממשק kioslave עבור sftp -Description[hi]=एसएफटीपी के लिए केआईओस्लेव -Description[hr]=Kioslave za SFTP -Description[hu]=KDE-protokoll az sftp-hez -Description[is]=kioslave fyrir sftp -Description[it]=Un kioslave per sftp -Description[ja]=sftp のための kioslave -Description[kk]=sftp-ке арналған енгізу-шығару модулі -Description[km]=kioslave របស់ sftp -Description[ko]=SFTP KIO 슬레이브 -Description[lt]=Kiovergas sftp protokolui -Description[lv]=KIO vergs priekš sftp -Description[mk]=kio-служител за sftp -Description[ms]=Kioslave untuk sftp -Description[nb]=En kioslave for sftp -Description[nds]=En In-/Utgaavdeenst för sftpl -Description[ne]=sftp का लागि एउटा किओस्लेभ -Description[nl]=Een kioslave voor sftp -Description[nn]=Ein kioslave for sftp -Description[pa]=sftp ਲਈ kioslave -Description[pl]=Wtyczka protokołu sftp -Description[pt]=Um 'kioslave' para sftp -Description[pt_BR]=Uma implementação para o sftp -Description[ro]=Un dispozitiv de I/E pentru SFTP -Description[ru]=Модуль ввода-вывода для sftp -Description[rw]=kioslave ya sftp -Description[se]=ŠO-šláva sftp-protokolla várás -Description[sk]=kioslave pre sftp -Description[sl]=kioslave za sftp -Description[sr]=Kioslave за SFTP -Description[sr@Latn]=Kioslave za SFTP -Description[sv]=En I/O-slav för SFTP -Description[ta]=sftpக்கான ஒரு க்யோஸ்லேவ் -Description[te]=ఎస్ ఎఫ్ టి పి కొరకు ఐఒ బానిస -Description[th]=ตัวนำข้อมูลเข้า-ออกสำหรับ sftp -Description[tr]=Sftp için kioslave -Description[tt]=sftp öçen kioslave -Description[uk]=Підлеглий В/В для sftp -Description[uz]=SFTP uchun KCH-sleyv -Description[uz@cyrillic]=SFTP учун КЧ-слейв -Description[vi]=A kioslave (đày tớ vào ra KDE) cho sftp -Description[wa]=On kioslave po sftp -Description[zh_CN]=sftp 的 kioslave -Description[zh_TW]=sftp 的 kioslave -DocPath=kioslave/sftp.html -Icon=ftp -Class=:internet diff --git a/kioslave/sftp/sftpfileattr.cpp b/kioslave/sftp/sftpfileattr.cpp deleted file mode 100644 index 95a82677f..000000000 --- a/kioslave/sftp/sftpfileattr.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/*************************************************************************** - sftpfileattr.cpp - description - ------------------- - begin : Sat Jun 30 2001 - copyright : (C) 2001 by Lucas Fisher - email : ljfisher@iastate.edu - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ - -#include "sftpfileattr.h" - -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <tqstring.h> -#include <tqdatastream.h> - -#include <kio/global.h> -#include <kremoteencoding.h> - -using namespace TDEIO; - -sftpFileAttr::sftpFileAttr(){ - clear(); - mDirAttrs = false; -} - -sftpFileAttr::sftpFileAttr(KRemoteEncoding* encoding){ - clear(); - mDirAttrs = false; - mEncoding = encoding; -} - - -/** Constructor to initialize the file attributes on declaration. */ -sftpFileAttr::sftpFileAttr(TQ_ULLONG size, uid_t uid, gid_t gid, - mode_t permissions, time_t atime, - time_t mtime, TQ_UINT32 extendedCount) { - clear(); - mDirAttrs = false; - mSize = size; - mUid = uid; - mGid = gid; - mAtime = atime; - mMtime = mtime; - mPermissions = permissions; - mExtendedCount = extendedCount; -} - -sftpFileAttr::~sftpFileAttr(){ -} - -/** Returns a UDSEntry describing the file. -The UDSEntry is generated from the sftp file attributes. */ -UDSEntry sftpFileAttr::entry() { - UDSEntry entry; - UDSAtom atom; - - atom.m_uds = UDS_NAME; - atom.m_str = mFilename; - entry.append(atom); - - if( mFlags & SSH2_FILEXFER_ATTR_SIZE ) { - atom.m_uds = UDS_SIZE; - atom.m_long = mSize; - entry.append(atom); - } - - if( mFlags & SSH2_FILEXFER_ATTR_ACMODTIME ) { - atom.m_uds = UDS_ACCESS_TIME; - atom.m_long = mAtime; - entry.append(atom); - - atom.m_uds = UDS_MODIFICATION_TIME; - atom.m_long = mMtime; - entry.append(atom); - } - - if( mFlags & SSH2_FILEXFER_ATTR_UIDGID ) { - if( mUserName.isEmpty() || mGroupName.isEmpty() ) - getUserGroupNames(); - - atom.m_uds = UDS_USER; - atom.m_str = mUserName; - entry.append(atom); - - atom.m_uds = UDS_GROUP; - atom.m_str = mGroupName; - entry.append(atom); - } - - if( mFlags & SSH2_FILEXFER_ATTR_PERMISSIONS ) { - atom.m_uds = UDS_ACCESS; - atom.m_long = mPermissions; - entry.append(atom); - - mode_t type = fileType(); - - // Set the type if we know what it is - if( type != 0 ) { - atom.m_uds = UDS_FILE_TYPE; - atom.m_long = (mLinkType ? mLinkType:type); - entry.append(atom); - } - - if( S_ISLNK(type) ) { - atom.m_uds = UDS_LINK_DEST; - atom.m_str = mLinkDestination; - entry.append(atom); - } - } - - return entry; -} - -/** Use to output the file attributes to a sftp packet */ -TQDataStream& operator<< (TQDataStream& s, const sftpFileAttr& fa) { - s << (TQ_UINT32)fa.mFlags; - - if( fa.mFlags & SSH2_FILEXFER_ATTR_SIZE ) - { s << (TQ_ULLONG)fa.mSize; } - - if( fa.mFlags & SSH2_FILEXFER_ATTR_UIDGID ) - { s << (TQ_UINT32)fa.mUid << (TQ_UINT32)fa.mGid; } - - if( fa.mFlags & SSH2_FILEXFER_ATTR_PERMISSIONS ) - { s << (TQ_UINT32)fa.mPermissions; } - - if( fa.mFlags & SSH2_FILEXFER_ATTR_ACMODTIME ) - { s << (TQ_UINT32)fa.mAtime << (TQ_UINT32)fa.mMtime; } - - if( fa.mFlags & SSH2_FILEXFER_ATTR_EXTENDED ) { - s << (TQ_UINT32)fa.mExtendedCount; - // XXX: Write extensions to data stream here - // s.writeBytes(extendedtype).writeBytes(extendeddata); - } - return s; -} - - -/** Use to read a file attribute from a sftp packet */ -TQDataStream& operator>> (TQDataStream& s, sftpFileAttr& fa) { - - // XXX Add some error checking in here in case - // we get a bad sftp packet. - - fa.clear(); - - if( fa.mDirAttrs ) { - TQCString fn; - s >> fn; - fn.truncate( fn.size() ); - - fa.mFilename = fa.mEncoding->decode( fn ); - - s >> fa.mLongname; - fa.mLongname.truncate( fa.mLongname.size() ); - //kdDebug() << ">>: ftpfileattr long filename (" << fa.mLongname.size() << ")= " << fa.mLongname << endl; - } - - s >> fa.mFlags; // get flags - - if( fa.mFlags & SSH2_FILEXFER_ATTR_SIZE ) { - TQ_ULLONG fileSize; - s >> fileSize; - fa.setFileSize(fileSize); - } - - TQ_UINT32 x; - - if( fa.mFlags & SSH2_FILEXFER_ATTR_UIDGID ) { - s >> x; fa.setUid(x); - s >> x; fa.setGid(x); - } - - if( fa.mFlags & SSH2_FILEXFER_ATTR_PERMISSIONS ) { - s >> x; fa.setPermissions(x); - } - - if( fa.mFlags & SSH2_FILEXFER_ATTR_ACMODTIME ) { - s >> x; fa.setAtime(x); - s >> x; fa.setMtime(x); - } - - if( fa.mFlags & SSH2_FILEXFER_ATTR_EXTENDED ) { - s >> x; fa.setExtendedCount(x); - // XXX: Read in extensions from data stream here - // s.readBytes(extendedtype).readBytes(extendeddata); - } - - fa.getUserGroupNames(); - return s; -} -/** Parse longname for the owner and group names. */ -void sftpFileAttr::getUserGroupNames(){ - // Get the name of the owner and group of the file from longname. - TQString user, group; - if( mLongname.isEmpty() ) { - // do not have the user name so use the user id instead - user.setNum(mUid); - group.setNum(mGid); - } - else { - int field = 0; - int i = 0; - int l = mLongname.length(); - - TQString longName = mEncoding->decode( mLongname ); - - kdDebug(7120) << "Decoded: " << longName << endl; - - // Find the beginning of the third field which contains the user name. - while( field != 2 ) { - if( longName[i].isSpace() ) { - field++; i++; - while( i < l && longName[i].isSpace() ) { i++; } - } - else { i++; } - } - // i is the index of the first character of the third field. - while( i < l && !longName[i].isSpace() ) { - user.append(longName[i]); - i++; - } - - // i is the first character of the space between fields 3 and 4 - // user contains the owner's user name - while( i < l && longName[i].isSpace() ) { - i++; - } - - // i is the first character of the fourth field - while( i < l && !longName[i].isSpace() ) { - group.append(longName[i]); - i++; - } - // group contains the name of the group. - } - - mUserName = user; - mGroupName = group; -} - -/** No descriptions */ -kdbgstream& operator<< (kdbgstream& s, sftpFileAttr& a) { - s << "Filename: " << a.mFilename - << ", Uid: " << a.mUid - << ", Gid: " << a.mGid - << ", Username: " << a.mUserName - << ", GroupName: " << a.mGroupName - << ", Permissions: " << a.mPermissions - << ", size: " << a.mSize - << ", atime: " << a.mAtime - << ", mtime: " << a.mMtime - << ", extended cnt: " << a.mExtendedCount; - - if (S_ISLNK(a.mLinkType)) { - s << ", Link Type: " << a.mLinkType; - s << ", Link Destination: " << a.mLinkDestination; - } - - return s; -} - -/** Make sure it builds with NDEBUG */ -kndbgstream& operator<< (kndbgstream& s, sftpFileAttr& ) { - return s; -} - -/** Clear all attributes and flags. */ -void sftpFileAttr::clear(){ - clearAtime(); - clearMtime(); - clearGid(); - clearUid(); - clearFileSize(); - clearPermissions(); - clearExtensions(); - mFilename = TQString::null; - mGroupName = TQString::null; - mUserName = TQString::null; - mLinkDestination = TQString::null; - mFlags = 0; - mLongname = "\0"; - mLinkType = 0; -} - -/** Return the size of the sftp attribute. */ -TQ_UINT32 sftpFileAttr::size() const{ - TQ_UINT32 size = 4; // for the attr flag - if( mFlags & SSH2_FILEXFER_ATTR_SIZE ) - size += 8; - - if( mFlags & SSH2_FILEXFER_ATTR_UIDGID ) - size += 8; - - if( mFlags & SSH2_FILEXFER_ATTR_PERMISSIONS ) - size += 4; - - if( mFlags & SSH2_FILEXFER_ATTR_ACMODTIME ) - size += 8; - - if( mFlags & SSH2_FILEXFER_ATTR_EXTENDED ) { - size += 4; - // add size of extensions - } - return size; -} - -/** Returns the file type as determined from the file permissions */ -mode_t sftpFileAttr::fileType() const{ - mode_t type = 0; - - if( S_ISLNK(mPermissions) ) - type |= S_IFLNK; - - if( S_ISREG(mPermissions) ) - type |= S_IFREG; - else if( S_ISDIR(mPermissions) ) - type |= S_IFDIR; - else if( S_ISCHR(mPermissions) ) - type |= S_IFCHR; - else if( S_ISBLK(mPermissions) ) - type |= S_IFBLK; - else if( S_ISFIFO(mPermissions) ) - type |= S_IFIFO; - else if( S_ISSOCK(mPermissions) ) - type |= S_IFSOCK; - - return type; -} - -void sftpFileAttr::setEncoding( KRemoteEncoding* encoding ) -{ - mEncoding = encoding; -} -// vim:ts=4:sw=4 diff --git a/kioslave/sftp/sftpfileattr.h b/kioslave/sftp/sftpfileattr.h deleted file mode 100644 index 543153b5e..000000000 --- a/kioslave/sftp/sftpfileattr.h +++ /dev/null @@ -1,261 +0,0 @@ -/*************************************************************************** - sftpfileattr.h - description - ------------------- - begin : Sat Jun 30 2001 - copyright : (C) 2001 by Lucas Fisher - email : ljfisher@iastate.edu - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ - -#ifndef SFTPFILEATTR_H -#define SFTPFILEATTR_H - -#include <sys/types.h> - -#include <tqglobal.h> -#include <tqstring.h> -#include <tqdatastream.h> - -#include <kio/global.h> -#include <kdebug.h> - -#include "sftp.h" - -/** - *@author Lucas Fisher - */ - -class KRemoteEncoding; - -class sftpFileAttr { - -private: // Private attributes - /** Name of file. */ - TQString mFilename; - - /** Specifies which fields of the file attribute are available. */ - TQ_UINT32 mFlags; - - /** Size of the file in bytes. Should be 64 bit safe. */ - TQ_ULLONG mSize; - - /** User id of the owner of the file. */ - uid_t mUid; - - /** Group id of the group to which the file belongs. */ - gid_t mGid; - - /** POSIX permissions of the file. */ - mode_t mPermissions; - - /** Last access time of the file in seconds from Jan 1, 1970. */ - time_t mAtime; - - /** Last modification time of file in seconds since Jan. 1, 1970. */ - time_t mMtime; - - /** Number of file attribute extensions. - Not currently implemented */ - TQ_UINT32 mExtendedCount; - - /** Longname of the file as found in a SSH_FXP_NAME sftp packet. - These contents are parse to return the file's owner name and - gr oup name. */ - TQCString mLongname; - - TQString mUserName; - TQString mGroupName; - - /** If file is a link, contains the destination of the link */ - TQString mLinkDestination; - - /** If resource is a link, contains the type the link,e.g. file,dir... */ - mode_t mLinkType; - - /** Whether >> operator should read filename and longname from the stream. */ - bool mDirAttrs; - - /** Holds the encoding of the remote host */ - KRemoteEncoding* mEncoding; - -public: - sftpFileAttr(); - - sftpFileAttr(KRemoteEncoding* encoding); - - ~sftpFileAttr(); - - /** Constructor to initialize the file attributes on declaration. */ - sftpFileAttr(TQ_ULLONG size_, uid_t uid_, gid_t gid_, mode_t permissions_, - time_t atime_, time_t mtime_, TQ_UINT32 extendedCount_ = 0); - - /** Return the size of the sftp attribute not including filename or longname*/ - TQ_UINT32 size() const; - - /** Clear all attributes and flags. */ - void clear(); - - /** Set the size of the file. */ - void setFileSize(TQ_ULLONG s) - { mSize = s; mFlags |= SSH2_FILEXFER_ATTR_SIZE; } - - /** The size file attribute will not be included in the UDSEntry - or when the file attribute is written to the sftp packet. */ - void clearFileSize() - { mSize = 0; mFlags &= ~SSH2_FILEXFER_ATTR_SIZE; } - - /** Returns the size of the file. */ - TQ_ULLONG fileSize() const { return mSize; } - - /** Sets the POSIX permissions of the file. */ - void setPermissions(mode_t p) - { mPermissions = p; mFlags |= SSH2_FILEXFER_ATTR_PERMISSIONS; } - - /** The permissions file attribute will not be included in the UDSEntry - or when the file attribute is written to the sftp packet. */ - void clearPermissions() - { mPermissions = 0; mFlags &= ~SSH2_FILEXFER_ATTR_PERMISSIONS; } - - /** Returns the POSIX permissons of the file. */ - mode_t permissions() const { return mPermissions; } - - /** Sets the group id of the file. */ - void setGid(gid_t id) - { mGid = id; mFlags |= SSH2_FILEXFER_ATTR_UIDGID; } - - /** Neither the gid or uid file attributes will not be included in the UDSEntry - or when the file attribute is written to the sftp packet. This is - equivalent to clearUid() */ - void clearGid() - { mGid = 0; mFlags &= SSH2_FILEXFER_ATTR_UIDGID; } - - /** Returns the group id of the file. */ - gid_t gid() const { return mGid; } - - /** Sets the uid of the file. */ - void setUid(uid_t id) - { mUid = id; mFlags |= SSH2_FILEXFER_ATTR_UIDGID; } - - /** Neither the gid or uid file attributes will not be included in the UDSEntry - or when the file attribute is written to the sftp packet. This is - equivalent to clearGid() */ - void clearUid() - { mUid = 0; mFlags &= SSH2_FILEXFER_ATTR_UIDGID; } - - /** Returns the user id of the file. */ - gid_t uid() const { return mUid; } - - /** Set the modificatoin time of the file in seconds since Jan. 1, 1970. */ - void setMtime(time_t t) - { mMtime = t; mFlags |= SSH2_FILEXFER_ATTR_ACMODTIME; } - - /** Neither the mtime or atime file attributes will not be included in the UDSEntry - or when the file attribute is written to the sftp packet. This is - equivalent to clearAtime() */ - void clearMtime() - { mMtime = 0; mFlags &= SSH2_FILEXFER_ATTR_ACMODTIME; } - - /** Returns the modification time of the file in seconds since Jan. 1, 1970. */ - time_t mtime() const { return mMtime; } - - /** Sets the access time of the file in seconds since Jan. 1, 1970. */ - void setAtime(time_t t) - { mAtime = t; mFlags |= SSH2_FILEXFER_ATTR_ACMODTIME; } - - /** Neither the atime or mtime file attributes will not be included in the UDSEntry - or when the file attribute is written to the sftp packet. This is - equivalent to clearMtime() */ - void clearAtime() - { mAtime = 0; mFlags &= SSH2_FILEXFER_ATTR_ACMODTIME; } - - /** Returns the last access time of the file in seconds since Jan. 1, 1970. */ - time_t atime() const { return mAtime; } - - /** Sets the number of file attribute extensions. */ - void setExtendedCount(unsigned int c) - { mExtendedCount = c; mFlags |= SSH2_FILEXFER_ATTR_EXTENDED; } - - /** No extensions will be included when the file attribute is written - to a sftp packet. */ - void clearExtensions() - { mExtendedCount = 0; mFlags &= ~SSH2_FILEXFER_ATTR_EXTENDED; } - - /** Returns the number of file attribute extentsions. */ - unsigned int extendedCount() const { return mExtendedCount; } - - /** Returns the flags for the sftp file attributes. */ - unsigned int flags() const { return mFlags; } - - /** Sets file's longname. See sftpFileAttr::longname. */ - void setLongname(TQString l) { mLongname = l.latin1(); } - - /** Returns a string describing the file attributes. The format is specific - to the implementation of the sftp server. In most cases (ie OpenSSH) - this is similar to the long output of 'ls'. */ - TQString longname() const { return mLongname; } - - void setLinkDestination(const TQString& target) - { mLinkDestination = target; } - - TQString linkDestination() - { return mLinkDestination; } - - /** Sets the actual type a symbolic link points to. */ - void setLinkType (mode_t type) { mLinkType = type; } - - mode_t linkType() const { return mLinkType; } - - /** No descriptions */ - void setFilename(const TQString& fn) - { mFilename = fn; } - - TQString filename() const - { return mFilename; } - - /** Returns a UDSEntry describing the file. - The UDSEntry is generated from the sftp file attributes. */ - TDEIO::UDSEntry entry(); - - /** Use to output the file attributes to a sftp packet - This will only write the sftp ATTR structure to the stream. - It will never write the filename and longname because the client - never sends those to the server. */ - friend TQDataStream& operator<< (TQDataStream&, const sftpFileAttr&); - - /** Use to read a file attribute from a sftp packet. - Read this carefully! If the DirAttrs flag is true, this will - read the filename, longname, and file attributes from the stream. - This is for use with listing directories. - If the DirAttrs flag is false, this will only read file attributes - from the stream. - BY DEFAULT, A NEW INSTANCE HAS DirAttrs == false */ - friend TQDataStream& operator>> (TQDataStream&, sftpFileAttr&); - - /** Parse longname for the owner and group names. */ - void getUserGroupNames(); - - /** Sets the DirAttrs flag. This flag affects how the >> operator works on data streams. */ - void setDirAttrsFlag(bool flag){ mDirAttrs = flag; } - - /** Gets the DirAttrs flag. */ - bool getDirAttrsFlag() const { return mDirAttrs; } - - friend kdbgstream& operator<< (kdbgstream& s, sftpFileAttr& a); - friend kndbgstream& operator<< (kndbgstream& s, sftpFileAttr& a); - - /** Returns the file type as determined from the file permissions */ - mode_t fileType() const; - - /** Set the encoding of the remote file system */ - void setEncoding( KRemoteEncoding* encoding ); -}; - -#endif |