[network/kio-extras/release/26.08] smb: smb: fix DFS namespace authentication
Harald Sitter <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 753c547b35ab6b2cec8d65ca90f316c3c5aa486e by Harald Sitter. Committed on 27/07/2026 at 17:36. Pushed by sitter into branch 'release/26.08'. smb: fix DFS namespace authentication split and send the username and workgroup on our end while upstream is not doing this reliably for the DFS scenario. should get revisited once upstream has a fix out. https://bugzilla.samba.org/show_bug.cgi?id=16149 BUG: 510902 (cherry picked from commit daa6a64cc4889bfbb03f4b41b08143506bfbdde7) Co-authored-by: Clemens Brunner <[email protected]> M +24 -0 smb/autotests/smburltest.cpp M +11 -0 smb/smbauthenticator.cpp M +16 -0 smb/smburl.cpp M +7 -0 smb/smburl.h https://invent.kde.org/network/kio-extras/-/commit/753c547b35ab6b2cec8d65ca90f316c3c5aa486e diff --git a/smb/autotests/smburltest.cpp b/smb/autotests/smburltest.cpp index 8d642231a..e8d6c996f 100644 --- a/smb/autotests/smburltest.cpp +++ b/smb/autotests/smburltest.cpp @@ -137,6 +137,30 @@ private Q_SLOTS: // We tag printers as such cause otherwise we have no way of knowing it was a printer. QCOMPARE(SMBUrl(QUrl("smb://host/printer?kio-printer=true")).getType(), SMBURLTYPE_PRINTER); } + + void testSplitDomainUser() + { + // No separator: domain is empty, user is the whole string + QCOMPARE(SMBUrl::splitDomainUser("user"), std::make_pair(QString(), QString("user"))); + + // Forward slash separator + QCOMPARE(SMBUrl::splitDomainUser("DOMAIN/user"), std::make_pair(QString("DOMAIN"), QString("user"))); + + // Backslash separator + QCOMPARE(SMBUrl::splitDomainUser("DOMAIN\\user"), std::make_pair(QString("DOMAIN"), QString("user"))); + + // Both separators present: first one wins (forward slash before backslash) + QCOMPARE(SMBUrl::splitDomainUser("DOM/AIN\\user"), std::make_pair(QString("DOM"), QString("AIN\\user"))); + + // Both separators present: first one wins (backslash before forward slash) + QCOMPARE(SMBUrl::splitDomainUser("DOM\\AIN/user"), std::make_pair(QString("DOM"), QString("AIN/user"))); + + // Empty string + QCOMPARE(SMBUrl::splitDomainUser(QString()), std::make_pair(QString(), QString())); + + // Separator at position 0: domain part is empty, falls back to no-domain path + QCOMPARE(SMBUrl::splitDomainUser("/user"), std::make_pair(QString(), QString("/user"))); + } }; QTEST_GUILESS_MAIN(SMBUrlTest) diff --git a/smb/smbauthenticator.cpp b/smb/smbauthenticator.cpp index 6afd08ed9..cc7e77301 100644 --- a/smb/smbauthenticator.cpp +++ b/smb/smbauthenticator.cpp @@ -74,6 +74,17 @@ void SMBAuthenticator::auth(SMBCCTX *context, if (m_frontend.checkCachedAuthentication(info)) { qCDebug(KIO_SMB_LOG) << "got password through cache" << info.username; + // Split "DOMAIN/user" or "DOMAIN\user" so the domain goes into the + // workgroup buffer and only the bare username into the username buffer. + // KIO encodes domain-qualified usernames as "DOMAIN/user" in the URL. + // TODO: revisit when https://bugzilla.samba.org/show_bug.cgi?id=16149 gets fixed properly + auto [domain, bareUser] = SMBUrl::splitDomainUser(info.username); + if (!domain.isEmpty()) { + strncpy(workgroup, domain.toUtf8().constData(), static_cast<size_t>(wgmaxlen - 1)); + workgroup[wgmaxlen - 1] = '\0'; + } + info.username = bareUser; + qCDebug(KIO_SMB_LOG) << "got password through cache: user=" << info.username << " domain=" << workgroup; } else if (!m_defaultUser.isEmpty()) { // user defined a default username/password in kcontrol; try this info.username = m_defaultUser; diff --git a/smb/smburl.cpp b/smb/smburl.cpp index 4436d28dd..42b2f7d1f 100644 --- a/smb/smburl.cpp +++ b/smb/smburl.cpp @@ -14,6 +14,22 @@ #include <QHostAddress> #include <QUrlQuery> +std::pair<QString, QString> SMBUrl::splitDomainUser(const QString &combined) +{ + const qsizetype slashPos = combined.indexOf(QLatin1Char('/')); + const qsizetype backslashPos = combined.indexOf(QLatin1Char('\\')); + qsizetype separatorPos = -1; + if (slashPos >= 0 && backslashPos >= 0) { + separatorPos = qMin(slashPos, backslashPos); + } else if (slashPos >= 0 || backslashPos >= 0) { + separatorPos = qMax(slashPos, backslashPos); + } + if (separatorPos > 0) { + return {combined.left(separatorPos), combined.mid(separatorPos + 1)}; + } + return {{}, combined}; +} + SMBUrl::SMBUrl(const QUrl &kurl) : QUrl(kurl) { diff --git a/smb/smburl.h b/smb/smburl.h index 14a0bf1a5..ad861c367 100644 --- a/smb/smburl.h +++ b/smb/smburl.h @@ -32,6 +32,7 @@ #define KIO_SMB_INTERNAL_H_INCLUDED #include <QByteArray> +#include <QString> #include <QUrl> /** @@ -117,6 +118,12 @@ public: */ SMBUrl partUrl() const; + /** + * Splits "DOMAIN/user" or "DOMAIN\user" into {domain, user}. + * domain is empty if there is no separator. + */ + static std::pair<QString, QString> splitDomainUser(const QString &combined); + private: void updateCache(); QByteArray m_surl;