File indexing completed on 2024-12-15 04:50:15
0001 /* 0002 This file is part of libkldap. 0003 SPDX-FileCopyrightText: 2006 Sean Harmer <sh@theharmers.co.uk> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "ldapdn.h" 0009 0010 #include "ldap_core_debug.h" 0011 #include <algorithm> 0012 0013 using namespace KLDAPCore; 0014 0015 class Q_DECL_HIDDEN LdapDN::LdapDNPrivate 0016 { 0017 public: 0018 LdapDNPrivate() = default; 0019 0020 ~LdapDNPrivate() = default; 0021 0022 [[nodiscard]] bool isValidRDNString(const QString &rdn) const; 0023 [[nodiscard]] QStringList splitOnNonEscapedChar(const QString &rdn, QChar ch) const; 0024 0025 QString m_dn; 0026 }; 0027 0028 bool LdapDN::LdapDNPrivate::isValidRDNString(const QString &rdn) const 0029 { 0030 qCDebug(LDAP_LOG) << "Testing rdn:" << rdn; 0031 0032 // If it is a muli-valued rdn, split it into its constituent parts 0033 const QStringList rdnParts = splitOnNonEscapedChar(rdn, QLatin1Char('+')); 0034 const int rdnPartsSize(rdnParts.size()); 0035 if (rdnPartsSize > 1) { 0036 for (int i = 0; i < rdnPartsSize; i++) { 0037 if (!isValidRDNString(rdnParts.at(i))) { 0038 return false; 0039 } 0040 } 0041 return true; 0042 } 0043 // Split the rdn into the attribute name and value parts 0044 const auto components = QStringView(rdn).split(QLatin1Char('=')); 0045 // We should have exactly two parts 0046 if (components.size() != 2) { 0047 return false; 0048 } 0049 0050 return true; 0051 } 0052 0053 QStringList LdapDN::LdapDNPrivate::splitOnNonEscapedChar(const QString &str, QChar ch) const 0054 { 0055 QStringList strParts; 0056 int index = 0; 0057 int searchFrom = 0; 0058 int strPartStartIndex = 0; 0059 while ((index = str.indexOf(ch, searchFrom)) != -1) { 0060 const QChar prev = str[std::max(0, index - 1)]; 0061 if (prev != QLatin1Char('\\')) { 0062 // Found a component of a multi-valued RDN 0063 // qCDebug(LDAP_LOG) << "Found" << ch << "at index" << index; 0064 QString tmp = str.mid(strPartStartIndex, index - strPartStartIndex); 0065 // qCDebug(LDAP_LOG) << "Adding part:" << tmp; 0066 strParts.append(tmp); 0067 strPartStartIndex = index + 1; 0068 } 0069 0070 searchFrom = index + 1; 0071 } 0072 0073 // Add on the part after the last found delimiter 0074 QString tmp = str.mid(strPartStartIndex); 0075 // qCDebug(LDAP_LOG) << "Adding part:" << tmp; 0076 strParts.append(tmp); 0077 0078 return strParts; 0079 } 0080 0081 LdapDN::LdapDN() 0082 : d(new LdapDNPrivate) 0083 { 0084 } 0085 0086 LdapDN::LdapDN(const QString &dn) 0087 : d(new LdapDNPrivate) 0088 { 0089 d->m_dn = dn; 0090 } 0091 0092 LdapDN::LdapDN(const LdapDN &that) 0093 : d(new LdapDNPrivate) 0094 { 0095 *d = *that.d; 0096 } 0097 0098 LdapDN &LdapDN::operator=(const LdapDN &that) 0099 { 0100 if (this == &that) { 0101 return *this; 0102 } 0103 0104 *d = *that.d; 0105 return *this; 0106 } 0107 0108 LdapDN::~LdapDN() = default; 0109 0110 void LdapDN::clear() 0111 { 0112 d->m_dn.clear(); 0113 } 0114 0115 bool LdapDN::isEmpty() const 0116 { 0117 return d->m_dn.isEmpty(); 0118 } 0119 0120 QString LdapDN::toString() const 0121 { 0122 return d->m_dn; 0123 } 0124 0125 QString LdapDN::toString(int depth) const 0126 { 0127 const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); 0128 if (depth >= rdns.size()) { 0129 return {}; 0130 } 0131 0132 // Construct a DN down to the requested depth 0133 QString dn; 0134 for (int i = depth; i >= 0; i--) { 0135 dn += rdns.at(rdns.size() - 1 - i) + QLatin1Char(','); 0136 qCDebug(LDAP_LOG) << "dn =" << dn; 0137 } 0138 dn.chop(1); // Strip off the extraneous comma 0139 0140 return dn; 0141 } 0142 0143 QString LdapDN::rdnString() const 0144 { 0145 /** \TODO We should move this into the d pointer as we calculate rdns quite a lot */ 0146 const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); 0147 return rdns.at(0); 0148 } 0149 0150 QString LdapDN::rdnString(int depth) const 0151 { 0152 const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); 0153 if (depth >= rdns.size()) { 0154 return {}; 0155 } 0156 return rdns.at(rdns.size() - 1 - depth); 0157 } 0158 0159 bool LdapDN::isValid() const 0160 { 0161 qCDebug(LDAP_LOG) << "Testing dn:" << d->m_dn; 0162 0163 // Break the string into rdn's 0164 const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); 0165 0166 // Test to see if each rdn is valid 0167 const int rdnsSize(rdns.size()); 0168 for (int i = 0; i < rdnsSize; i++) { 0169 if (!d->isValidRDNString(rdns.at(i))) { 0170 return false; 0171 } 0172 } 0173 0174 return true; 0175 } 0176 0177 int LdapDN::depth() const 0178 { 0179 const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); 0180 return rdns.size(); 0181 } 0182 0183 bool LdapDN::operator==(const LdapDN &rhs) const 0184 { 0185 return d->m_dn == rhs.d->m_dn; 0186 } 0187 0188 bool LdapDN::operator!=(const LdapDN &rhs) const 0189 { 0190 return d->m_dn != rhs.d->m_dn; 0191 }