diff --git a/smb/kio_smb.h b/smb/kio_smb.h index 44979154..93773ee0 100644 --- a/smb/kio_smb.h +++ b/smb/kio_smb.h @@ -1,323 +1,323 @@ ///////////////////////////////////////////////////////////////////////////// // // Project: SMB kioslave for KDE // // File: kio_smb.h // // Abstract: The main kio slave class declaration. For convenience, // in concurrent devlopment, the implementation for this class // is separated into several .cpp files -- the file containing // the implementation should be noted in the comments for each // member function. // // Author(s): Matthew Peterson // //--------------------------------------------------------------------------- // // Copyright (c) 2000 Caldera Systems, Inc. // // 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.1 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, please obtain // a copy from http://www.gnu.org/copyleft/gpl.html // ///////////////////////////////////////////////////////////////////////////// #ifndef KIO_SMB_H_INCLUDED #define KIO_SMB_H_INCLUDED #include //-------------- // KDE includes //-------------- #include #include //----------------------------- // Standard C library includes //----------------------------- #include #include #include #include #include #include #include #include #include #include //----------------------------- // Qt includes //----------------------------- #include #include #include //------------------------------- // Samba client library includes //------------------------------- extern "C" { #include } //--------------------------- // kio_smb internal includes //--------------------------- #include "kio_smb_internal.h" #define MAX_XFER_BUF_SIZE 65534 // Categorized logger Q_DECLARE_LOGGING_CATEGORY(KIO_SMB) using namespace KIO; //=========================================================================== class SMBSlave : public QObject, public KIO::SlaveBase { Q_OBJECT private: class SMBError { public: int kioErrorId; QString errorString; }; //--------------------------------------------------------------------- // please make sure your private data does not duplicate existing data //--------------------------------------------------------------------- bool m_initialized_smbc; /** * From Controlcenter */ QString m_default_user; -// QString m_default_workgroup; //currently unused, Alex + QString m_default_workgroup = QStringLiteral("WORKGROUP"); // overwritten with value from smbc QString m_default_password; QString m_default_encoding; /** * we store the current url, it's needed for * callback authorization method */ SMBUrl m_current_url; /** * From Controlcenter, show SHARE$ or not */ // bool m_showHiddenShares; //currently unused, Alex /** * libsmbclient need global variables to store in, * else it crashes on exit next method after use cache_stat, * looks like gcc (C/C++) failure */ struct stat st; protected: //--------------------------------------------- // Authentication functions (kio_smb_auth.cpp) //--------------------------------------------- // (please prefix functions with auth) /** * Description : Initializes the libsmbclient * Return : true on success false with errno set on error */ bool auth_initialize_smbc(); int checkPassword(SMBUrl &url); //--------------------------------------------- // Cache functions (kio_smb_auth.cpp) //--------------------------------------------- //Stat methods //----------------------------------------- // Browsing functions (kio_smb_browse.cpp) //----------------------------------------- // (please prefix functions with browse) /** * Description : Return a stat of given SMBUrl. Calls cache_stat and * pack it in UDSEntry. UDSEntry will not be cleared * Parameter : SMBUrl the url to stat * Return : cache_stat() return code */ int browse_stat_path(const SMBUrl& url, UDSEntry& udsentry); /** * Description : call smbc_stat and return stats of the url * Parameter : SMBUrl the url to stat * Return : stat* of the url * Note : it has some problems with stat in method, looks like * something leave(or removed) on the stack. If your * method segfault on returning try to change the stat* * variable */ int cache_stat( const SMBUrl& url, struct stat* st ); //--------------------------------------------- // Configuration functions (kio_smb_config.cpp) //--------------------------------------------- // (please prefix functions with config) //--------------------------------------- // Directory functions (kio_smb_dir.cpp) //--------------------------------------- // (please prefix functions with dir) //-------------------------------------- // File IO functions (kio_smb_file.cpp) //-------------------------------------- // (please prefix functions with file) //---------------------------- // Misc functions (this file) //---------------------------- /** * Description : correct a given URL * valid URL's are * * smb://[[domain;]user[:password]@]server[:port][/share[/path[/file]]] * smb:/[[domain;]user[:password]@][group/[server[/share[/path[/file]]]]] * domain = workgroup(domain) of the user * user = username * password = password of useraccount * group = workgroup(domain) of server * server = host to connect * share = a share of the server (host) * path = a path of the share * Parameter : QUrl the url to check * Return : new QUrl if it is corrected. else the same QUrl */ QUrl checkURL(const QUrl& kurl) const; void reportError(const SMBUrl& url, const int errNum); void reportWarning(const SMBUrl& url, const int errNum); public: //----------------------------------------------------------------------- // smbclient authentication callback (note that this is called by the // global ::auth_smbc_get_data() call. void auth_smbc_get_data(const char *server,const char *share, char *workgroup, int wgmaxlen, char *username, int unmaxlen, char *password, int pwmaxlen); //----------------------------------------------------------------------- // Overwritten functions from the base class that define the operation of // this slave. (See the base class headerfile slavebase.h for more // details) //----------------------------------------------------------------------- // Functions overwritten in kio_smb.cpp SMBSlave(const QByteArray& pool, const QByteArray& app); ~SMBSlave() override; // Functions overwritten in kio_smb_browse.cpp void listDir( const QUrl& url ) override; void stat( const QUrl& url ) override; // Functions overwritten in kio_smb_config.cpp void reparseConfiguration() override; // Functions overwritten in kio_smb_dir.cpp void copy( const QUrl& src, const QUrl &dest, int permissions, KIO::JobFlags flags ) override; void del( const QUrl& kurl, bool isfile) override; void mkdir( const QUrl& kurl, int permissions ) override; void rename( const QUrl& src, const QUrl& dest, KIO::JobFlags flags ) override; // Functions overwritten in kio_smb_file.cpp void get( const QUrl& kurl ) override; void put( const QUrl& kurl, int permissions, KIO::JobFlags flags ) override; void open( const QUrl& kurl, QIODevice::OpenMode mode ) override; void read( KIO::filesize_t bytesRequested ) override; void write( const QByteArray &fileData ) override; void seek( KIO::filesize_t offset ) override; void close() override; // Functions not implemented (yet) //virtual void setHost(const QString& host, int port, const QString& user, const QString& pass); //virtual void openConnection(); //virtual void closeConnection(); //virtual void slave_status(); void special( const QByteArray & ) override; protected: void virtual_hook(int id, void *data) override; private: SMBError errnumToKioError(const SMBUrl& url, const int errNum); void smbCopy(const QUrl& src, const QUrl &dest, int permissions, KIO::JobFlags flags); void smbCopyGet(const QUrl& src, const QUrl& dest, int permissions, KIO::JobFlags flags); void smbCopyPut(const QUrl& src, const QUrl& dest, int permissions, KIO::JobFlags flags); bool workaroundEEXIST(const int errNum) const; void listDNSSD(UDSEntry &udsentry, const QUrl &url, const uint direntCount); void fileSystemFreeSpace(const QUrl &url); /** * Used in open(), read(), write(), and close() * FIXME Placing these in the private section above causes m_openUrl = kurl * to fail in SMBSlave::open. Need to find out why this is. */ int m_openFd; SMBUrl m_openUrl; const bool m_enableEEXISTWorkaround; /* Enables a workaround for some broken libsmbclient versions */ // Close without calling finish(). Use this to close after error. void closeWithoutFinish(); }; //========================================================================== // the global libsmbclient authentication callback function extern "C" { void auth_smbc_get_data(SMBCCTX * context, const char *server,const char *share, char *workgroup, int wgmaxlen, char *username, int unmaxlen, char *password, int pwmaxlen); } //=========================================================================== // Main slave entrypoint (see kio_smb.cpp) extern "C" { int kdemain( int argc, char **argv ); } #endif //#endif KIO_SMB_H_INCLUDED diff --git a/smb/kio_smb_auth.cpp b/smb/kio_smb_auth.cpp index e1a68e03..4f7778f3 100644 --- a/smb/kio_smb_auth.cpp +++ b/smb/kio_smb_auth.cpp @@ -1,228 +1,253 @@ ///////////////////////////////////////////////////////////////////////////// // // Project: SMB kioslave for KDE2 // // File: kio_smb_auth.cpp // // Abstract: member function implementations for SMBSlave that deal with // SMB directory access // // Author(s): Matthew Peterson // //--------------------------------------------------------------------------- // // Copyright (c) 2000 Caldera Systems, Inc. // // 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.1 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, please obtain // a copy from http://www.gnu.org/copyleft/gpl.html // ///////////////////////////////////////////////////////////////////////////// #include "kio_smb.h" #include "kio_smb_internal.h" #include #include #include #include // call for libsmbclient //========================================================================== void auth_smbc_get_data(SMBCCTX * context, const char *server,const char *share, char *workgroup, int wgmaxlen, char *username, int unmaxlen, char *password, int pwmaxlen) //========================================================================== { if (context != nullptr) { #ifdef DEPRECATED_SMBC_INTERFACE SMBSlave *theSlave = (SMBSlave*) smbc_getOptionUserData(context); #else SMBSlave *theSlave = (SMBSlave*)smbc_option_get(context, "user_data"); #endif theSlave->auth_smbc_get_data(server, share, workgroup,wgmaxlen, username, unmaxlen, password, pwmaxlen); } } //-------------------------------------------------------------------------- void SMBSlave::auth_smbc_get_data(const char *server,const char *share, char *workgroup, int wgmaxlen, char *username, int unmaxlen, char *password, int pwmaxlen) //-------------------------------------------------------------------------- { //check this to see if we "really" need to authenticate... SMBUrlType t = m_current_url.getType(); if( t == SMBURLTYPE_ENTIRE_NETWORK ) { qCDebug(KIO_SMB) << "we don't really need to authenticate for this top level url, returning"; return; } qCDebug(KIO_SMB) << "auth_smbc_get_dat: set user=" << username << ", workgroup=" << workgroup << " server=" << server << ", share=" << share << endl; QString s_server = QString::fromUtf8(server); QString s_share = QString::fromUtf8(share); workgroup[wgmaxlen - 1] = 0; QString s_workgroup = QString::fromUtf8(workgroup); username[unmaxlen - 1] = 0; QString s_username = QString::fromUtf8(username); password[pwmaxlen - 1] = 0; QString s_password = QString::fromUtf8(password); KIO::AuthInfo info; info.url = QUrl("smb:///"); info.url.setHost(s_server); info.url.setPath('/' + s_share); info.username = s_username; info.password = s_password; info.verifyPath = true; + info.setExtraField("domain", s_workgroup); + qCDebug(KIO_SMB) << "libsmb-auth-callback URL:" << info.url; if ( !checkCachedAuthentication( info ) ) { if ( m_default_user.isEmpty() ) { // ok, we do not know the password. Let's try anonymous before we try for real info.username = "anonymous"; info.password.clear(); } else { // user defined a default username/password in kcontrol; try this info.username = m_default_user; info.password = m_default_password; } } else qCDebug(KIO_SMB) << "got password through cache"; - strncpy(username, info.username.toUtf8(), unmaxlen - 1); - strncpy(password, info.password.toUtf8(), pwmaxlen - 1); + // Make sure it'll be safe to cast to size_t (unsigned) + Q_ASSERT(unmaxlen > 0); + Q_ASSERT(pwmaxlen > 0); + Q_ASSERT(wgmaxlen > 0); + + strncpy(username, info.username.toUtf8(), static_cast(unmaxlen - 1)); + strncpy(password, info.password.toUtf8(), static_cast(pwmaxlen - 1)); + // TODO: isEmpty guard can be removed in 20.08+ + // It is only here to prevent us setting an empty work group if a user updates + // but doesn't restart so kiod5 could hold an old cache without domain + // field. In that event we'll leave the input workgroup as-is. + const QString domain = info.getExtraField("domain").toString(); + if (!domain.isEmpty()) { + strncpy(workgroup, domain.toUtf8(), static_cast(wgmaxlen - 1)); + } } int SMBSlave::checkPassword(SMBUrl &url) { qCDebug(KIO_SMB) << "checkPassword for " << url; KIO::AuthInfo info; info.url = QUrl("smb:///"); info.url.setHost(url.host()); QString share = url.path(); int index = share.indexOf('/', 1); if (index > 1) share = share.left(index); if (share.at(0) == '/') share = share.mid(1); info.url.setPath('/' + share); info.verifyPath = true; info.keepPassword = true; + info.setExtraField("anonymous", true); // arbitrary default for dialog + info.setExtraField("domain", m_default_workgroup); + if ( share.isEmpty() ) info.prompt = i18n( "Please enter authentication information for %1" , url.host() ); else info.prompt = i18n( "Please enter authentication information for:\n" "Server = %1\n" "Share = %2" , url.host() , share ); info.username = url.userName(); qCDebug(KIO_SMB) << "call openPasswordDialog for " << info.url; const int passwordDialogErrorCode = openPasswordDialogV2(info); if (passwordDialogErrorCode == KJob::NoError) { qCDebug(KIO_SMB) << "openPasswordDialog returned " << info.username; url.setUser(info.username); if (info.keepPassword) { qCDebug(KIO_SMB) << "Caching info.username = " << info.username << ", info.url = " << info.url.toDisplayString(); cacheAuthentication(info); } return KJob::NoError; } qCDebug(KIO_SMB) << "no value from openPasswordDialog; error:" << passwordDialogErrorCode; return passwordDialogErrorCode; } //-------------------------------------------------------------------------- // Initializes the smbclient library // // Returns: 0 on success -1 with errno set on error bool SMBSlave::auth_initialize_smbc() { SMBCCTX *smb_context = nullptr; qCDebug(KIO_SMB) << "auth_initialize_smbc "; if(m_initialized_smbc == false) { qCDebug(KIO_SMB) << "smbc_init call"; KConfig cfg( "kioslaverc", KConfig::SimpleConfig); int debug_level = cfg.group( "SMB" ).readEntry( "DebugLevel", 0 ); smb_context = smbc_new_context(); if (smb_context == nullptr) { SlaveBase::error(ERR_INTERNAL, i18n("libsmbclient failed to create context")); return false; } #ifdef DEPRECATED_SMBC_INTERFACE // defined by libsmbclient.h of Samba 3.2 /* New libsmbclient interface of Samba 3.2 */ smbc_setDebug(smb_context, debug_level); smbc_setFunctionAuthDataWithContext(smb_context, ::auth_smbc_get_data); smbc_setOptionUserData(smb_context, this); /* Enable Kerberos support */ smbc_setOptionUseKerberos(smb_context, 1); smbc_setOptionFallbackAfterKerberos(smb_context, 1); #else smb_context->debug = debug_level; smb_context->callbacks.auth_fn = NULL; smbc_option_set(smb_context, "auth_function", (void*)::auth_smbc_get_data); smbc_option_set(smb_context, "user_data", this); #if defined(SMB_CTX_FLAG_USE_KERBEROS) && defined(SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) smb_context->flags |= SMB_CTX_FLAG_USE_KERBEROS | SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; #endif #endif /* DEPRECATED_SMBC_INTERFACE */ if (!smbc_init_context(smb_context)) { smbc_free_context(smb_context, 0); smb_context = nullptr; SlaveBase::error(ERR_INTERNAL, i18n("libsmbclient failed to initialize context")); return false; } smbc_set_context(smb_context); + // TODO: refactor; checkPassword should query this on + // demand to not run into situations where we may have cached + // the workgroup early on and it changed since. Needs context + // being held in the slave though, which opens us up to nullptr + // problems should checkPassword be called without init first. + m_default_workgroup = smbc_getWorkgroup(smb_context); + m_initialized_smbc = true; } return true; }