00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifdef ENABLE_SSH
00016
00017 #include <globalsearch/sshconnection_libssh.h>
00018
00019 #include <globalsearch/sshmanager_libssh.h>
00020 #include <globalsearch/macros.h>
00021
00022 #include <QtCore/QDebug>
00023 #include <QtCore/QDir>
00024
00025 #include <fstream>
00026 #include <sstream>
00027 #include <fcntl.h>
00028
00029 using namespace std;
00030
00031 namespace GlobalSearch {
00032
00033 #define START //qDebug() << __PRETTY_FUNCTION__ << " called...";
00034 #define END //qDebug() << __PRETTY_FUNCTION__ << " finished...";
00035
00036 SSHConnectionLibSSH::SSHConnectionLibSSH(SSHManagerLibSSH *parent)
00037 : SSHConnection(parent),
00038 m_session(0),
00039 m_shell(0),
00040 m_isValid(false),
00041 m_inUse(false)
00042 {
00043 if (parent) {
00044
00045 connect(this, SIGNAL(unknownHostKey(const QString &)),
00046 parent, SLOT(setServerKey(const QString &)),
00047 Qt::BlockingQueuedConnection);
00048 }
00049 }
00050
00051 SSHConnectionLibSSH::~SSHConnectionLibSSH()
00052 {
00053 START;
00054 disconnectSession();
00055 END;
00056 }
00057
00058 bool SSHConnectionLibSSH::isConnected()
00059 {
00060 if (!m_session || !m_shell ||
00061 channel_is_closed(m_shell) || channel_is_eof(m_shell) ) {
00062 qWarning() << "SSHConnectionLibSSH is not connected: one or more required "
00063 "channels are not initialized.";
00064 return false;
00065 };
00066
00067 QMutexLocker locker (&m_lock);
00068 START;
00069
00070
00071
00072 const char *command = "echo ok\n";
00073 if (channel_write(m_shell, command, sizeof(command)) == SSH_ERROR) {
00074 qWarning() << "SSHConnectionLibSSH is not connected: cannot write to shell; "
00075 << ssh_get_error(m_session);
00076 return false;
00077 }
00078
00079
00080 int bytesAvail;
00081 int timeout = 3000;
00082 do {
00083
00084 bytesAvail = channel_poll(m_shell, 0);
00085 if (bytesAvail == SSH_ERROR) {
00086 qWarning() << "SSHConnectionLibSSH::isConnected(): server returns an error; "
00087 << ssh_get_error(m_session);
00088 return false;
00089 }
00090
00091 if (bytesAvail <= 0) {
00092 GS_MSLEEP(50);
00093 timeout -= 50;
00094 }
00095 }
00096 while (timeout >= 0 && bytesAvail <= 0);
00097
00098 if (timeout < 0 && bytesAvail == 0) {
00099 qWarning() << "SSHConnectionLibSSH::isConnected(): server timeout.";
00100 return false;
00101 }
00102
00103 else if (bytesAvail != 3) {
00104 qWarning() << "SSHConnectionLibSSH::isConnected(): server returns a bizarre poll value: "
00105 << bytesAvail << "; " << ssh_get_error(m_session);
00106 return false;
00107 }
00108
00109
00110 ostringstream ossout;
00111 char buffer[LIBSSH_BUFFER_SIZE];
00112 int len;
00113 while ((len = channel_read(m_shell,
00114 buffer,
00115 (bytesAvail < LIBSSH_BUFFER_SIZE) ? bytesAvail : LIBSSH_BUFFER_SIZE,
00116 0)) > 0) {
00117 ossout.write(buffer,len);
00118
00119 timeout = 1000;
00120 do {
00121 bytesAvail = channel_poll(m_shell, 0);
00122 if (bytesAvail == SSH_ERROR) {
00123 qWarning() << "SSHConnectionLibSSH::_isConnected: server returns an error; "
00124 << ssh_get_error(m_session);
00125 return false;
00126 }
00127 if (bytesAvail <= 0) {
00128 GS_MSLEEP(50);
00129 timeout -= 50;
00130 }
00131 }
00132 while (timeout >= 0 && bytesAvail <= 0);
00133 }
00134
00135
00136 if (!strcmp(ossout.str().c_str(), "ok")) {
00137 qWarning() << "SSH error: 'echo ok' on the host returned: "
00138 << ossout.str().c_str();
00139 return false;
00140 }
00141
00142 END;
00143 return true;
00144 }
00145
00146 bool SSHConnectionLibSSH::disconnectSession()
00147 {
00148 QMutexLocker locker (&m_lock);
00149 START;
00150
00151 if (m_shell)
00152 channel_free(m_shell);
00153 m_shell = 0;
00154
00155 if (m_session)
00156 ssh_free(m_session);
00157 m_session = 0;
00158
00159 m_isValid = false;
00160 END;
00161 return true;
00162 }
00163
00164 bool SSHConnectionLibSSH::reconnectSession(bool throwExceptions)
00165 {
00166 START;
00167 if (!disconnectSession()) return false;
00168 if (!connectSession(throwExceptions)) return false;
00169 END;
00170 return true;
00171 }
00172
00173 bool SSHConnectionLibSSH::connectSession(bool throwExceptions)
00174 {
00175 QMutexLocker locker (&m_lock);
00176
00177 m_session = ssh_new();
00178 if (!m_session) {
00179 if (throwExceptions) {
00180 throw SSH_UNKNOWN_ERROR;
00181 }
00182 else {
00183 return false;
00184 }
00185 }
00186
00187
00188 int verbosity = SSH_LOG_NOLOG;
00189
00190
00191 int timeout = 5;
00192
00193 ssh_options_set(m_session, SSH_OPTIONS_HOST, m_host.toStdString().c_str());
00194 ssh_options_set(m_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
00195 ssh_options_set(m_session, SSH_OPTIONS_TIMEOUT, &timeout);
00196
00197 if (!m_user.isEmpty()) {
00198 ssh_options_set(m_session, SSH_OPTIONS_USER, m_user.toStdString().c_str());
00199 }
00200 ssh_options_set(m_session, SSH_OPTIONS_PORT, &m_port);
00201
00202
00203 if (ssh_connect(m_session) != SSH_OK) {
00204 qWarning() << "SSH error: " << ssh_get_error(m_session);
00205 if (throwExceptions) {
00206 throw SSH_CONNECTION_ERROR;
00207 }
00208 else {
00209 return false;
00210 }
00211 }
00212
00213
00214 int state = ssh_is_server_known(m_session);
00215 switch (state) {
00216 case SSH_SERVER_KNOWN_OK:
00217 break;
00218 case SSH_SERVER_KNOWN_CHANGED:
00219 case SSH_SERVER_FOUND_OTHER:
00220 case SSH_SERVER_FILE_NOT_FOUND:
00221 case SSH_SERVER_NOT_KNOWN: {
00222 int hlen;
00223 unsigned char *hash = 0;
00224 char *hexa;
00225 hlen = ssh_get_pubkey_hash(m_session, &hash);
00226 hexa = ssh_get_hexa(hash, hlen);
00227 emit unknownHostKey(QString(hexa));
00228 if (throwExceptions) {
00229 throw SSH_UNKNOWN_HOST_ERROR;
00230 }
00231 else {
00232 return false;
00233 }
00234 }
00235 case SSH_SERVER_ERROR:
00236 qWarning() << "SSH error: " << ssh_get_error(m_session);
00237 if (throwExceptions) {
00238 throw SSH_UNKNOWN_ERROR;
00239 }
00240 else {
00241 return false;
00242 }
00243 }
00244
00245
00246 int rc;
00247 int method;
00248
00249
00250 rc = ssh_userauth_none(m_session, NULL);
00251 if (rc == SSH_AUTH_ERROR) {
00252 qWarning() << "SSH error: " << ssh_get_error(m_session);
00253 if (throwExceptions) {
00254 throw SSH_UNKNOWN_ERROR;
00255 }
00256 else {
00257 return false;
00258 }
00259 }
00260
00261 method = ssh_auth_list(m_session);
00262
00263
00264 while (rc != SSH_AUTH_SUCCESS) {
00265
00266
00267 if (method & SSH_AUTH_METHOD_PUBLICKEY) {
00268 rc = ssh_userauth_autopubkey(m_session,
00269 m_user.toStdString().c_str());
00270 if (rc == SSH_AUTH_ERROR) {
00271 qWarning() << "Error during auth (pubkey)";
00272 qWarning() << "Error: " << ssh_get_error(m_session);
00273 if (throwExceptions) {
00274 throw SSH_UNKNOWN_ERROR;
00275 }
00276 else {
00277 return false;
00278 }
00279 } else if (rc == SSH_AUTH_SUCCESS) {
00280 break;
00281 }
00282 }
00283
00284
00285 if (method & SSH_AUTH_METHOD_PASSWORD) {
00286 rc = ssh_userauth_password(m_session,
00287 m_user.toStdString().c_str(),
00288 m_pass.toStdString().c_str());
00289 if (rc == SSH_AUTH_ERROR) {
00290 qWarning() << "Error during auth (passwd)";
00291 qWarning() << "Error: " << ssh_get_error(m_session);
00292 if (throwExceptions) {
00293 throw SSH_UNKNOWN_ERROR;
00294 }
00295 else {
00296 return false;
00297 }
00298 } else if (rc == SSH_AUTH_SUCCESS) {
00299 break;
00300 }
00301 }
00302
00303
00304 if (throwExceptions) {
00305 throw SSH_BAD_PASSWORD_ERROR;
00306 }
00307 else {
00308 return false;
00309 }
00310 }
00311
00312
00313 if (m_shell) {
00314 channel_free(m_shell);
00315 m_shell = 0;
00316 }
00317
00318 m_shell = channel_new(m_session);
00319 if (!m_shell) {
00320 qWarning() << "SSH error initializing shell: "
00321 << ssh_get_error(m_session);
00322 if (throwExceptions) {
00323 throw SSH_UNKNOWN_ERROR;
00324 }
00325 else {
00326 return false;
00327 }
00328 }
00329 if (channel_open_session(m_shell) != SSH_OK) {
00330 qWarning() << "SSH error opening shell: "
00331 << ssh_get_error(m_session);
00332 if (throwExceptions) {
00333 throw SSH_UNKNOWN_ERROR;
00334 }
00335 else {
00336 return false;
00337 }
00338
00339 }
00340 if (channel_request_shell(m_shell) != SSH_OK) {
00341 qWarning() << "SSH error requesting shell: "
00342 << ssh_get_error(m_session);
00343 if (throwExceptions) {
00344 throw SSH_UNKNOWN_ERROR;
00345 }
00346 else {
00347 return false;
00348 }
00349 }
00350
00351 m_isValid = true;
00352 END;
00353 return true;
00354 }
00355
00356 bool SSHConnectionLibSSH::execute(const QString &command,
00357 QString &stdout_str,
00358 QString &stderr_str,
00359 int &exitcode) {
00360 QMutexLocker locker (&m_lock);
00361 return _execute(command, stdout_str, stderr_str, exitcode);
00362 }
00363
00364
00366 bool SSHConnectionLibSSH::_execute(const QString &command,
00367 QString &stdout_str,
00368 QString &stderr_str,
00369 int &exitcode)
00370 {
00371 START;
00372
00373 ssh_channel channel = channel_new(m_session);
00374 if (!channel) {
00375 qWarning() << "SSH error: " << ssh_get_error(m_session);
00376 return false;
00377 }
00378 if (channel_open_session(channel) != SSH_OK) {
00379 qWarning() << "SSH error: " << ssh_get_error(m_session);
00380 return false;
00381 }
00382
00383
00384 int ssh_exit = channel_request_exec(channel, command.toStdString().c_str());
00385 channel_send_eof(channel);
00386
00387 if (ssh_exit == SSH_ERROR) {
00388 channel_close(channel);
00389 return false;
00390 }
00391
00392
00393 ostringstream ossout, osserr;
00394
00395
00396 char buffer[LIBSSH_BUFFER_SIZE];
00397 int len;
00398 while ((len = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
00399 ossout.write(buffer,len);
00400 }
00401 stdout_str = QString(ossout.str().c_str());
00402 while ((len = channel_read(channel, buffer, sizeof(buffer), 1)) > 0) {
00403 osserr.write(buffer,len);
00404 }
00405 stderr_str = QString(osserr.str().c_str());
00406
00407 exitcode = channel_get_exit_status(channel);
00408
00409 channel_close(channel);
00410 channel_free(channel);
00411 END;
00412 return true;
00413 }
00415
00416
00418 sftp_session SSHConnectionLibSSH::_openSFTP()
00419 {
00420 sftp_session sftp = sftp_new(m_session);
00421 if(!sftp){
00422 qWarning() << "sftp error initialising channel" << endl
00423 << ssh_get_error(m_session);
00424 return 0;
00425 }
00426 if(sftp_init(sftp) != SSH_OK){
00427 qWarning() << "error initialising sftp" << endl
00428 << ssh_get_error(m_session);
00429 return 0;
00430 }
00431 return sftp;
00432 }
00434
00435 bool SSHConnectionLibSSH::copyFileToServer(const QString & localpath,
00436 const QString & remotepath)
00437 {
00438 QMutexLocker locker (&m_lock);
00439 if (localpath.trimmed().isEmpty() || remotepath.trimmed().isEmpty()) {
00440 qWarning() << QString("Refusing to copy to/from empty path: '%1' to '%2'")
00441 .arg(localpath, remotepath);
00442 return false;
00443 }
00444 return _copyFileToServer(localpath, remotepath);
00445 }
00446
00447
00449 bool SSHConnectionLibSSH::_copyFileToServer(const QString & localpath,
00450 const QString & remotepath)
00451 {
00452 START;
00453
00454 sftp_session sftp = _openSFTP();
00455 if (!sftp) {
00456 qWarning() << "Could not create sftp channel.";
00457 return false;
00458 }
00459
00460
00461 ifstream from (localpath.toStdString().c_str());
00462 if (!from.is_open()) {
00463 qWarning() << "Error opening file " << localpath << " for reading.";
00464 sftp_free(sftp);
00465 return false;
00466 }
00467
00468
00469 sftp_file to = sftp_open(sftp,
00470 remotepath.toStdString().c_str(),
00471 O_WRONLY | O_CREAT | O_TRUNC,
00472 0750);
00473 if (!to) {
00474 qWarning() << "Error opening file " << remotepath << " for writing.";
00475 sftp_free(sftp);
00476 return false;
00477 }
00478
00479
00480 int size = LIBSSH_BUFFER_SIZE;
00481 char *buffer = new char [size];
00482
00483 int readBytes;
00484 while (!from.eof()) {
00485 from.read(buffer, size);
00486 readBytes = from.gcount();
00487 if (sftp_write(to, buffer, readBytes) != readBytes) {
00488 qWarning() << "Error writing to " << remotepath;
00489 from.close();
00490 sftp_close(to);
00491 sftp_free(sftp);
00492 delete[] buffer;
00493 return false;
00494 }
00495 }
00496 from.close();
00497 sftp_close(to);
00498 sftp_free(sftp);
00499 delete[] buffer;
00500 END;
00501 return true;
00502 }
00504
00505 bool SSHConnectionLibSSH::copyFileFromServer(const QString & remotepath,
00506 const QString & localpath)
00507 {
00508 QMutexLocker locker (&m_lock);
00509 if (localpath.trimmed().isEmpty() || remotepath.trimmed().isEmpty()) {
00510 qWarning() << QString("Refusing to copy to/from empty path: '%2' to '%1'")
00511 .arg(localpath, remotepath);
00512 return false;
00513 }
00514 return _copyFileFromServer(remotepath, localpath);
00515 }
00516
00517
00519 bool SSHConnectionLibSSH::_copyFileFromServer(const QString & remotepath,
00520 const QString & localpath)
00521 {
00522 START;
00523 sftp_session sftp = _openSFTP();
00524 if (!sftp) {
00525 qWarning() << "Could not create sftp channel.";
00526 return false;
00527 }
00528
00529
00530 sftp_file from = sftp_open(sftp,
00531 remotepath.toStdString().c_str(),
00532 O_RDONLY,
00533 0);
00534 if(!from){
00535 qWarning() << "Error opening file " << remotepath << " for reading.";
00536 sftp_free(sftp);
00537 return false;
00538 }
00539
00540
00541 ofstream to (localpath.toStdString().c_str());
00542 if (!to.is_open()) {
00543 qWarning() << "Error opening file " << localpath << " for writing.";
00544 sftp_close(from);
00545 sftp_free(sftp);
00546 return false;
00547 }
00548
00549
00550 char *buffer = new char [LIBSSH_BUFFER_SIZE];
00551
00552 int readBytes;
00553 while ((readBytes = sftp_read(from, buffer, LIBSSH_BUFFER_SIZE)) > 0) {
00554 to.write(buffer,readBytes);
00555 if (to.bad()) {
00556 qWarning() << "Error writing to " << localpath;
00557 to.close();
00558 sftp_close(from);
00559 sftp_free(sftp);
00560 delete[] buffer;
00561 return false;
00562 }
00563 }
00564 to.close();
00565 sftp_close(from);
00566 sftp_free(sftp);
00567 delete[] buffer;
00568 END;
00569 return true;
00570 }
00572
00573 bool SSHConnectionLibSSH::readRemoteFile(const QString &filename,
00574 QString &contents)
00575 {
00576 QMutexLocker locker (&m_lock);
00577 if (filename.trimmed().isEmpty()) {
00578 qWarning() << QString("Refusing to read empty filename: '%1'")
00579 .arg(filename);
00580 return false;
00581 }
00582 return _readRemoteFile(filename, contents);
00583 }
00584
00585
00587 bool SSHConnectionLibSSH::_readRemoteFile(const QString &filename,
00588 QString &contents)
00589 {
00590 START;
00591
00592 sftp_session sftp = _openSFTP();
00593 if (!sftp) {
00594 qWarning() << "Could not create sftp channel.";
00595 return false;
00596 }
00597
00598
00599 sftp_file from = sftp_open(sftp,
00600 filename.toStdString().c_str(),
00601 O_RDONLY,
00602 0);
00603 if(!from){
00604 qWarning() << "Error opening file " << filename << " for reading.";
00605 sftp_free(sftp);
00606 return false;
00607 }
00608
00609
00610 char *buffer = new char [LIBSSH_BUFFER_SIZE];
00611
00612
00613 ostringstream oss;
00614
00615 int readBytes;
00616 while ((readBytes = sftp_read(from, buffer, LIBSSH_BUFFER_SIZE)) > 0) {
00617 oss.write(buffer,readBytes);
00618 }
00619 sftp_close(from);
00620 contents = QString(oss.str().c_str());
00621 sftp_free(sftp);
00622 delete[] buffer;
00623 END;
00624 return true;
00625 }
00627
00628 bool SSHConnectionLibSSH::removeRemoteFile(const QString &filename)
00629 {
00630 QMutexLocker locker (&m_lock);
00631 if (filename.trimmed().isEmpty()) {
00632 qWarning() << QString("Refusing to remove empty filename: '%1'")
00633 .arg(filename);
00634 return false;
00635 }
00636 return _removeRemoteFile(filename);
00637 }
00638
00639
00641 bool SSHConnectionLibSSH::_removeRemoteFile(const QString &filename)
00642 {
00643 START;
00644
00645 sftp_session sftp = _openSFTP();
00646 if (!sftp) {
00647 qWarning() << "Could not create sftp channel.";
00648 return false;
00649 }
00650
00651 if (sftp_unlink(sftp,
00652 filename.toStdString().c_str())
00653 != 0) {
00654 qWarning() << "Error removing remote file " << filename;
00655 sftp_free(sftp);
00656 return false;
00657 }
00658 END;
00659 sftp_free(sftp);
00660 return true;
00661 }
00663
00664 bool SSHConnectionLibSSH::copyDirectoryToServer(const QString & local,
00665 const QString & remote)
00666 {
00667 QMutexLocker locker (&m_lock);
00668 if (local.trimmed().isEmpty() || remote.trimmed().isEmpty()) {
00669 qWarning() << QString("Refusing to copy to/from empty path: '%1' to '%2'")
00670 .arg(local, remote);
00671 return false;
00672 }
00673 return _copyDirectoryToServer(local, remote);
00674 }
00675
00676
00678 bool SSHConnectionLibSSH::_copyDirectoryToServer(const QString & local,
00679 const QString & remote)
00680 {
00681 START;
00682
00683
00684 QString localpath = local + "/";
00685 QString remotepath = remote + "/";
00686
00687
00688 QDir locdir (localpath);
00689 if (!locdir.exists()) {
00690 qWarning() << "Could not open local directory " << localpath;
00691 return false;
00692 }
00693
00694
00695 QStringList directories = locdir.entryList(QDir::AllDirs |
00696 QDir::NoDotAndDotDot,
00697 QDir::Name);
00698 QStringList files = locdir.entryList(QDir::Files, QDir::Name);
00699
00700 sftp_session sftp = _openSFTP();
00701 if (!sftp) {
00702 qWarning() << "Could not create sftp channel.";
00703 return false;
00704 }
00705
00706
00707 sftp_mkdir(sftp,
00708 remotepath.toStdString().c_str(),
00709 0750);
00710
00711
00712 QStringList::const_iterator dir, file;
00713 for (dir = directories.begin(); dir != directories.end(); dir++) {
00714
00715
00716 if (!_copyDirectoryToServer(localpath + (*dir),
00717 remotepath + (*dir))) {
00718 qWarning() << "Error copying " << localpath + (*dir) << " to "
00719 << remotepath + (*dir);
00720 sftp_free(sftp);
00721 return false;
00722 }
00723 }
00724 for (file = files.begin(); file != files.end(); file++) {
00725
00726
00727 if (!_copyFileToServer(localpath + (*file),
00728 remotepath + (*file))) {
00729 qWarning() << "Error copying " << localpath + (*file) << " to "
00730 << remotepath + (*file);
00731 sftp_free(sftp);
00732 return false;
00733 }
00734 }
00735 sftp_free(sftp);
00736 END;
00737 return true;
00738 }
00740
00741 bool SSHConnectionLibSSH::copyDirectoryFromServer(const QString & remote,
00742 const QString & local)
00743 {
00744 QMutexLocker locker (&m_lock);
00745 if (local.trimmed().isEmpty() || remote.trimmed().isEmpty()) {
00746 qWarning() << QString("Refusing to copy to/from empty path: '%2' to '%1'")
00747 .arg(local, remote);
00748 return false;
00749 }
00750 return _copyDirectoryFromServer(remote, local);
00751 }
00752
00753
00755 bool SSHConnectionLibSSH::_copyDirectoryFromServer(const QString & remote,
00756 const QString & local)
00757 {
00758 START;
00759
00760 QString localpath = local + "/";
00761 QString remotepath = remote + "/";
00762
00763 sftp_dir dir;
00764 sftp_attributes file;
00765 sftp_session sftp = _openSFTP();
00766 if (!sftp) {
00767 qWarning() << "Could not create sftp channel.";
00768 return false;
00769 }
00770
00771
00772 dir = sftp_opendir(sftp, remotepath.toStdString().c_str());
00773 if (!dir) {
00774 qWarning() << "Could not open remote directory " << remotepath
00775 << ":\n\t" << ssh_get_error(m_session);
00776 sftp_free(sftp);
00777 return false;
00778 }
00779
00780
00781 QDir locdir;
00782 if (!locdir.mkpath(localpath)) {
00783 qWarning() << "Could not create local directory " << localpath;
00784 sftp_free(sftp);
00785 return false;
00786 }
00787
00788
00789 while ((file = sftp_readdir(sftp,dir))) {
00790 if (strcmp(file->name, ".") == 0 ||
00791 strcmp(file->name, "..") == 0 ) {
00792 continue;
00793 }
00794
00795 switch (file->type) {
00796 case SSH_FILEXFER_TYPE_DIRECTORY:
00797 if (!_copyDirectoryFromServer(remotepath + file->name,
00798 localpath + file->name)) {
00799 sftp_attributes_free(file);
00800 sftp_free(sftp);
00801 return false;
00802 }
00803 break;
00804 default:
00805 if (!_copyFileFromServer(remotepath + file->name,
00806 localpath + file->name)) {
00807 sftp_attributes_free(file);
00808 sftp_free(sftp);
00809 return false;
00810 }
00811 break;
00812 }
00813 sftp_attributes_free(file);
00814 }
00815
00816
00817 if ( !sftp_dir_eof(dir) && sftp_closedir(dir) == SSH_ERROR ) {
00818 qWarning() << "Error copying \'" << remotepath << "\' to \'" << localpath
00819 << "\': " << ssh_get_error(m_session);
00820 sftp_free(sftp);
00821 return false;
00822 }
00823 END;
00824 sftp_free(sftp);
00825 return true;
00826 }
00828
00829 bool SSHConnectionLibSSH::readRemoteDirectoryContents(const QString & path,
00830 QStringList & contents)
00831 {
00832 QMutexLocker locker (&m_lock);
00833 if (path.trimmed().isEmpty()) {
00834 qWarning() << QString("Refusing to read empty path contents: '%1'")
00835 .arg(path);
00836 return false;
00837 }
00838 return _readRemoteDirectoryContents(path, contents);
00839 }
00840
00841
00843 bool SSHConnectionLibSSH::_readRemoteDirectoryContents(const QString & path,
00844 QStringList & contents)
00845 {
00846 START;
00847
00848 QString remotepath = path + "/";
00849 sftp_dir dir;
00850 sftp_attributes file;
00851 contents.clear();
00852
00853 sftp_session sftp = _openSFTP();
00854 if (!sftp) {
00855 qWarning() << "Could not create sftp channel.";
00856 return false;
00857 }
00858
00859
00860 dir = sftp_opendir(sftp, remotepath.toStdString().c_str());
00861 if (!dir) {
00862 qWarning() << "Could not open remote directory " << remotepath
00863 << ":\n\t" << ssh_get_error(m_session);
00864 sftp_free(sftp);
00865 return false;
00866 }
00867
00868
00869 QStringList tmp;
00870 while ((file = sftp_readdir(sftp,dir))) {
00871 if (strcmp(file->name, ".") == 0 ||
00872 strcmp(file->name, "..") == 0 ) {
00873 continue;
00874 }
00875 switch (file->type) {
00876 case SSH_FILEXFER_TYPE_DIRECTORY:
00877 contents << remotepath + file->name + "/";
00878 if (!_readRemoteDirectoryContents(remotepath + file->name,
00879 tmp)) {
00880 sftp_attributes_free(file);
00881 sftp_free(sftp);
00882 return false;
00883 }
00884 contents << tmp;
00885 break;
00886 default:
00887 contents << remotepath + file->name;
00888 break;
00889 }
00890 sftp_attributes_free(file);
00891 }
00892
00893
00894 if ( !sftp_dir_eof(dir) && sftp_closedir(dir) == SSH_ERROR ) {
00895 qWarning() << "Error reading contents of \'" << remotepath
00896 << "\': " << ssh_get_error(m_session);
00897 sftp_free(sftp);
00898 return false;
00899 }
00900 END;
00901 sftp_free(sftp);
00902 return true;
00903 }
00905
00906 bool SSHConnectionLibSSH::removeRemoteDirectory(const QString & path,
00907 bool onlyDeleteContents)
00908 {
00909 QMutexLocker locker (&m_lock);
00910 if (path.trimmed().isEmpty()) {
00911 qWarning() << QString("Refusing to remove empty path: '%1'")
00912 .arg(path);
00913 return false;
00914 }
00915 return _removeRemoteDirectory(path, onlyDeleteContents);
00916 }
00917
00918
00920 bool SSHConnectionLibSSH::_removeRemoteDirectory(const QString & path,
00921 bool onlyDeleteContents)
00922 {
00923 START;
00924
00925 QString remotepath = path + "/";
00926 sftp_dir dir;
00927 sftp_attributes file;
00928 bool ok = true;
00929
00930 sftp_session sftp = _openSFTP();
00931 if (!sftp) {
00932 qWarning() << "Could not create sftp channel.";
00933 return false;
00934 }
00935
00936
00937 dir = sftp_opendir(sftp, remotepath.toStdString().c_str());
00938 if (!dir) {
00939 qWarning() << "Could not open remote directory " << remotepath
00940 << ":\n\t" << ssh_get_error(m_session);
00941 sftp_free(sftp);
00942 return false;
00943 }
00944
00945
00946 while ((file = sftp_readdir(sftp,dir))) {
00947 if (strcmp(file->name, ".") == 0 ||
00948 strcmp(file->name, "..") == 0 ) {
00949 continue;
00950 }
00951 switch (file->type) {
00952 case SSH_FILEXFER_TYPE_DIRECTORY:
00953 if (!_removeRemoteDirectory(remotepath + file->name, false)) {
00954 qWarning() << "Could not remove remote directory"
00955 << remotepath + file->name;
00956 ok = false;
00957 }
00958 break;
00959 default:
00960 if (!_removeRemoteFile(remotepath + file->name)) {
00961 qWarning() << "Could not remove remote file: "
00962 << remotepath + file->name;
00963 ok = false;
00964 }
00965 break;
00966 }
00967 sftp_attributes_free(file);
00968 }
00969
00970
00971 if ( !sftp_dir_eof(dir) && sftp_closedir(dir) == SSH_ERROR ) {
00972 qWarning() << "Error reading contents of \'" << remotepath
00973 << "\': " << ssh_get_error(m_session);
00974 sftp_free(sftp);
00975 return false;
00976 }
00977 if ( !ok ) {
00978 qWarning() << "Some files could not be removed from "
00979 << remotepath;
00980 sftp_free(sftp);
00981 return false;
00982 }
00983
00984
00985 if (!onlyDeleteContents) {
00986 if (sftp_rmdir(sftp,
00987 remotepath.toStdString().c_str())
00988 == SSH_ERROR) {
00989 qWarning() << "Error removing remote directory " << remotepath
00990 << ": " << ssh_get_error(m_session);
00991 sftp_free(sftp);
00992 return false;
00993 }
00994 }
00995 sftp_free(sftp);
00996 END;
00997 return true;
00998 }
01000
01001 bool SSHConnectionLibSSH::addKeyToKnownHosts(const QString &host, unsigned int port)
01002 {
01003
01004 ssh_session session = ssh_new();
01005 if (!session) {
01006 return false;
01007 }
01008
01009
01010 int verbosity = SSH_LOG_NOLOG;
01011 int timeout = 5;
01012
01013 ssh_options_set(session, SSH_OPTIONS_HOST, host.toStdString().c_str());
01014 ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
01015 ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &timeout);
01016 ssh_options_set(session, SSH_OPTIONS_PORT, &port);
01017
01018
01019 if (ssh_connect(session) != SSH_OK) {
01020 qWarning() << "SSH error: " << ssh_get_error(session);
01021 ssh_free(session);
01022 return false;
01023 }
01024
01025 if (ssh_write_knownhost(session) < 0) {
01026 ssh_free(session);
01027 return false;
01028 }
01029
01030 ssh_free(session);
01031 return true;
01032 }
01033
01034 }
01035
01036 #endif // ENABLE_SSH