LCOV - code coverage report
Current view: top level - lang/qt/src - dn.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2 217 0.9 %
Date: 2016-11-29 15:07:43 Functions: 2 34 5.9 %

          Line data    Source code
       1             : /*
       2             :     dn.cpp
       3             : 
       4             :     This file is part of qgpgme, the Qt API binding for gpgme
       5             :     Copyright (c) 2004 Klarälvdalens Datakonsult AB
       6             :     Copyright (c) 2016 Intevation GmbH
       7             : 
       8             :     QGpgME is free software; you can redistribute it and/or
       9             :     modify it under the terms of the GNU General Public License as
      10             :     published by the Free Software Foundation; either version 2 of the
      11             :     License, or (at your option) any later version.
      12             : 
      13             :     QGpgME is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :     General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU General Public License
      19             :     along with this program; if not, write to the Free Software
      20             :     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      21             : 
      22             :     In addition, as a special exception, the copyright holders give
      23             :     permission to link the code of this program with any edition of
      24             :     the Qt library by Trolltech AS, Norway (or with modified versions
      25             :     of Qt that use the same license as Qt), and distribute linked
      26             :     combinations including the two.  You must obey the GNU General
      27             :     Public License in all respects for all of the code used other than
      28             :     Qt.  If you modify this file, you may extend this exception to
      29             :     your version of the file, but you are not obligated to do so.  If
      30             :     you do not wish to do so, delete this exception statement from
      31             :     your version.
      32             : */
      33             : 
      34             : #ifdef HAVE_CONFIG_H
      35             :  #include "config.h"
      36             : #endif
      37             : 
      38             : #include "dn.h"
      39             : 
      40             : static const struct {
      41             :     const char *name;
      42             :     const char *oid;
      43             : } oidmap[] = {
      44             :     // keep them ordered by oid:
      45             :     { "SP", "ST" }, // hack to show the Sphinx-required/desired SP for
      46             :     // StateOrProvince, otherwise known as ST or even S
      47             :     { "NameDistinguisher", "0.2.262.1.10.7.20" },
      48             :     { "EMAIL", "1.2.840.113549.1.9.1" },
      49             :     { "SN", "2.5.4.4" },
      50             :     { "SerialNumber", "2.5.4.5" },
      51             :     { "T", "2.5.4.12" },
      52             :     { "D", "2.5.4.13" },
      53             :     { "BC", "2.5.4.15" },
      54             :     { "ADDR", "2.5.4.16" },
      55             :     { "PC", "2.5.4.17" },
      56             :     { "GN", "2.5.4.42" },
      57             :     { "Pseudo", "2.5.4.65" },
      58             : };
      59             : static const unsigned int numOidMaps = sizeof oidmap / sizeof * oidmap;
      60             : 
      61           0 : class QGpgME::DN::Private
      62             : {
      63             : public:
      64           0 :     Private() : mRefCount(0) {}
      65           0 :     Private(const Private &other)
      66             :         : attributes(other.attributes),
      67             :           reorderedAttributes(other.reorderedAttributes),
      68             :           order{"CN", "L", "_X_", "OU", "O", "C"},
      69           0 :           mRefCount(0)
      70             :     {
      71           0 :     }
      72             : 
      73           0 :     int ref()
      74             :     {
      75           0 :         return ++mRefCount;
      76             :     }
      77             : 
      78           0 :     int unref()
      79             :     {
      80           0 :         if (--mRefCount <= 0) {
      81           0 :             delete this;
      82           0 :             return 0;
      83             :         } else {
      84           0 :             return mRefCount;
      85             :         }
      86             :     }
      87             : 
      88           0 :     int refCount() const
      89             :     {
      90           0 :         return mRefCount;
      91             :     }
      92             : 
      93             :     DN::Attribute::List attributes;
      94             :     DN::Attribute::List reorderedAttributes;
      95             :     QStringList order;
      96             : private:
      97             :     int mRefCount;
      98             : };
      99             : 
     100             : namespace
     101             : {
     102             : struct DnPair {
     103             :     char *key;
     104             :     char *value;
     105             : };
     106             : }
     107             : 
     108             : // copied from CryptPlug and adapted to work on DN::Attribute::List:
     109             : 
     110             : #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
     111             : #define hexdigitp(a) (digitp (a)                     \
     112             :                       || (*(a) >= 'A' && *(a) <= 'F')  \
     113             :                       || (*(a) >= 'a' && *(a) <= 'f'))
     114             : #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
     115             :                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
     116             : #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
     117             : 
     118             : static char *
     119           0 : trim_trailing_spaces(char *string)
     120             : {
     121             :     char *p, *mark;
     122             : 
     123           0 :     for (mark = NULL, p = string; *p; p++) {
     124           0 :         if (isspace(*p)) {
     125           0 :             if (!mark) {
     126           0 :                 mark = p;
     127             :             }
     128             :         } else {
     129           0 :             mark = NULL;
     130             :         }
     131             :     }
     132           0 :     if (mark) {
     133           0 :         *mark = '\0';
     134             :     }
     135             : 
     136           0 :     return string;
     137             : }
     138             : 
     139             : /* Parse a DN and return an array-ized one.  This is not a validating
     140             :    parser and it does not support any old-stylish syntax; gpgme is
     141             :    expected to return only rfc2253 compatible strings. */
     142             : static const unsigned char *
     143           0 : parse_dn_part(DnPair *array, const unsigned char *string)
     144             : {
     145             :     const unsigned char *s, *s1;
     146             :     size_t n;
     147             :     char *p;
     148             : 
     149             :     /* parse attributeType */
     150           0 :     for (s = string + 1; *s && *s != '='; s++)
     151             :         ;
     152           0 :     if (!*s) {
     153           0 :         return NULL;    /* error */
     154             :     }
     155           0 :     n = s - string;
     156           0 :     if (!n) {
     157           0 :         return NULL;    /* empty key */
     158             :     }
     159           0 :     p = (char *)malloc(n + 1);
     160             : 
     161           0 :     memcpy(p, string, n);
     162           0 :     p[n] = 0;
     163           0 :     trim_trailing_spaces((char *)p);
     164             :     // map OIDs to their names:
     165           0 :     for (unsigned int i = 0; i < numOidMaps; ++i)
     166           0 :         if (!strcasecmp((char *)p, oidmap[i].oid)) {
     167           0 :             free(p);
     168           0 :             p = strdup(oidmap[i].name);
     169           0 :             break;
     170             :         }
     171           0 :     array->key = p;
     172           0 :     string = s + 1;
     173             : 
     174           0 :     if (*string == '#') {
     175             :         /* hexstring */
     176           0 :         string++;
     177           0 :         for (s = string; hexdigitp(s); s++) {
     178           0 :             s++;
     179             :         }
     180           0 :         n = s - string;
     181           0 :         if (!n || (n & 1)) {
     182           0 :             return NULL;    /* empty or odd number of digits */
     183             :         }
     184           0 :         n /= 2;
     185           0 :         array->value = p = (char *)malloc(n + 1);
     186             : 
     187           0 :         for (s1 = string; n; s1 += 2, n--) {
     188           0 :             *p++ = xtoi_2(s1);
     189             :         }
     190           0 :         *p = 0;
     191             :     } else {
     192             :         /* regular v3 quoted string */
     193           0 :         for (n = 0, s = string; *s; s++) {
     194           0 :             if (*s == '\\') {
     195             :                 /* pair */
     196           0 :                 s++;
     197           0 :                 if (*s == ',' || *s == '=' || *s == '+'
     198           0 :                         || *s == '<' || *s == '>' || *s == '#' || *s == ';'
     199           0 :                         || *s == '\\' || *s == '\"' || *s == ' ') {
     200           0 :                     n++;
     201           0 :                 } else if (hexdigitp(s) && hexdigitp(s + 1)) {
     202           0 :                     s++;
     203           0 :                     n++;
     204             :                 } else {
     205           0 :                     return NULL;    /* invalid escape sequence */
     206             :                 }
     207           0 :             } else if (*s == '\"') {
     208           0 :                 return NULL;    /* invalid encoding */
     209           0 :             } else if (*s == ',' || *s == '=' || *s == '+'
     210           0 :                        || *s == '<' || *s == '>' || *s == '#' || *s == ';') {
     211             :                 break;
     212             :             } else {
     213           0 :                 n++;
     214             :             }
     215             :         }
     216             : 
     217           0 :         array->value = p = (char *)malloc(n + 1);
     218             : 
     219           0 :         for (s = string; n; s++, n--) {
     220           0 :             if (*s == '\\') {
     221           0 :                 s++;
     222           0 :                 if (hexdigitp(s)) {
     223           0 :                     *p++ = xtoi_2(s);
     224           0 :                     s++;
     225             :                 } else {
     226           0 :                     *p++ = *s;
     227             :                 }
     228             :             } else {
     229           0 :                 *p++ = *s;
     230             :             }
     231             :         }
     232           0 :         *p = 0;
     233             :     }
     234           0 :     return s;
     235             : }
     236             : 
     237             : /* Parse a DN and return an array-ized one.  This is not a validating
     238             :    parser and it does not support any old-stylish syntax; gpgme is
     239             :    expected to return only rfc2253 compatible strings. */
     240             : static QGpgME::DN::Attribute::List
     241           0 : parse_dn(const unsigned char *string)
     242             : {
     243           0 :     if (!string) {
     244           0 :         return QVector<QGpgME::DN::Attribute>();
     245             :     }
     246             : 
     247           0 :     QVector<QGpgME::DN::Attribute> result;
     248           0 :     while (*string) {
     249           0 :         while (*string == ' ') {
     250           0 :             string++;
     251             :         }
     252           0 :         if (!*string) {
     253           0 :             break;    /* ready */
     254             :         }
     255             : 
     256           0 :         DnPair pair = { 0, 0 };
     257           0 :         string = parse_dn_part(&pair, string);
     258           0 :         if (!string) {
     259           0 :             goto failure;
     260             :         }
     261           0 :         if (pair.key && pair.value)
     262             :             result.push_back(QGpgME::DN::Attribute(QString::fromUtf8(pair.key),
     263           0 :                                                  QString::fromUtf8(pair.value)));
     264           0 :         free(pair.key);
     265           0 :         free(pair.value);
     266             : 
     267           0 :         while (*string == ' ') {
     268           0 :             string++;
     269             :         }
     270           0 :         if (*string && *string != ',' && *string != ';' && *string != '+') {
     271           0 :             goto failure;    /* invalid delimiter */
     272             :         }
     273           0 :         if (*string) {
     274           0 :             string++;
     275             :         }
     276             :     }
     277           0 :     return result;
     278             : 
     279             : failure:
     280           0 :     return QVector<QGpgME::DN::Attribute>();
     281             : }
     282             : 
     283             : static QVector<QGpgME::DN::Attribute>
     284           0 : parse_dn(const QString &dn)
     285             : {
     286           0 :     return parse_dn((const unsigned char *)dn.toUtf8().data());
     287             : }
     288             : 
     289           0 : static QString dn_escape(const QString &s)
     290             : {
     291           0 :     QString result;
     292           0 :     for (unsigned int i = 0, end = s.length(); i != end; ++i) {
     293           0 :         const QChar ch = s[i];
     294           0 :         switch (ch.unicode()) {
     295             :         case ',':
     296             :         case '+':
     297             :         case '"':
     298             :         case '\\':
     299             :         case '<':
     300             :         case '>':
     301             :         case ';':
     302           0 :             result += QLatin1Char('\\');
     303             :         // fall through
     304             :         default:
     305           0 :             result += ch;
     306             :         }
     307             :     }
     308           0 :     return result;
     309             : }
     310             : 
     311             : static QString
     312           0 : serialise(const QVector<QGpgME::DN::Attribute> &dn, const QString &sep)
     313             : {
     314           0 :     QStringList result;
     315           0 :     for (QVector<QGpgME::DN::Attribute>::const_iterator it = dn.begin(); it != dn.end(); ++it)
     316           0 :         if (!(*it).name().isEmpty() && !(*it).value().isEmpty()) {
     317           0 :             result.push_back((*it).name().trimmed() + QLatin1Char('=') + dn_escape((*it).value().trimmed()));
     318             :         }
     319           0 :     return result.join(sep);
     320             : }
     321             : 
     322             : static QGpgME::DN::Attribute::List
     323           0 : reorder_dn(const QGpgME::DN::Attribute::List &dn, const QStringList &attrOrder)
     324             : {
     325           0 :     QGpgME::DN::Attribute::List unknownEntries;
     326           0 :     QGpgME::DN::Attribute::List result;
     327           0 :     unknownEntries.reserve(dn.size());
     328           0 :     result.reserve(dn.size());
     329             : 
     330             :     // find all unknown entries in their order of appearance
     331           0 :     for (QGpgME::DN::const_iterator it = dn.begin(); it != dn.end(); ++it)
     332           0 :         if (!attrOrder.contains((*it).name())) {
     333           0 :             unknownEntries.push_back(*it);
     334             :         }
     335             : 
     336             :     // process the known attrs in the desired order
     337           0 :     for (QStringList::const_iterator oit = attrOrder.begin(); oit != attrOrder.end(); ++oit)
     338           0 :         if (*oit == QLatin1String("_X_")) {
     339             :             // insert the unknown attrs
     340             :             std::copy(unknownEntries.begin(), unknownEntries.end(),
     341           0 :                       std::back_inserter(result));
     342           0 :             unknownEntries.clear(); // don't produce dup's
     343             :         } else {
     344           0 :             for (QGpgME::DN::const_iterator dnit = dn.begin(); dnit != dn.end(); ++dnit)
     345           0 :                 if ((*dnit).name() == *oit) {
     346           0 :                     result.push_back(*dnit);
     347             :                 }
     348             :         }
     349             : 
     350           0 :     return result;
     351             : }
     352             : 
     353             : //
     354             : //
     355             : // class DN
     356             : //
     357             : //
     358             : 
     359           0 : QGpgME::DN::DN()
     360             : {
     361           0 :     d = new Private();
     362           0 :     d->ref();
     363           0 : }
     364             : 
     365           0 : QGpgME::DN::DN(const QString &dn)
     366             : {
     367           0 :     d = new Private();
     368           0 :     d->ref();
     369           0 :     d->attributes = parse_dn(dn);
     370           0 : }
     371             : 
     372           0 : QGpgME::DN::DN(const char *utf8DN)
     373             : {
     374           0 :     d = new Private();
     375           0 :     d->ref();
     376           0 :     if (utf8DN) {
     377           0 :         d->attributes = parse_dn((const unsigned char *)utf8DN);
     378             :     }
     379           0 : }
     380             : 
     381           0 : QGpgME::DN::DN(const DN &other)
     382           0 :     : d(other.d)
     383             : {
     384           0 :     if (d) {
     385           0 :         d->ref();
     386             :     }
     387           0 : }
     388             : 
     389           0 : QGpgME::DN::~DN()
     390             : {
     391           0 :     if (d) {
     392           0 :         d->unref();
     393             :     }
     394           0 : }
     395             : 
     396           0 : const QGpgME::DN &QGpgME::DN::operator=(const DN &that)
     397             : {
     398           0 :     if (this->d == that.d) {
     399           0 :         return *this;
     400             :     }
     401             : 
     402           0 :     if (that.d) {
     403           0 :         that.d->ref();
     404             :     }
     405           0 :     if (this->d) {
     406           0 :         this->d->unref();
     407             :     }
     408             : 
     409           0 :     this->d = that.d;
     410             : 
     411           0 :     return *this;
     412             : }
     413             : 
     414           0 : QString QGpgME::DN::prettyDN() const
     415             : {
     416           0 :     if (!d) {
     417           0 :         return QString();
     418             :     }
     419           0 :     if (d->reorderedAttributes.empty()) {
     420           0 :         d->reorderedAttributes = reorder_dn(d->attributes, d->order);
     421             :     }
     422           0 :     return serialise(d->reorderedAttributes, QStringLiteral(","));
     423             : }
     424             : 
     425           0 : QString QGpgME::DN::dn() const
     426             : {
     427           0 :     return d ? serialise(d->attributes, QStringLiteral(",")) : QString();
     428             : }
     429             : 
     430           0 : QString QGpgME::DN::dn(const QString &sep) const
     431             : {
     432           0 :     return d ? serialise(d->attributes, sep) : QString();
     433             : }
     434             : 
     435             : // static
     436           0 : QString QGpgME::DN::escape(const QString &value)
     437             : {
     438           0 :     return dn_escape(value);
     439             : }
     440             : 
     441           0 : void QGpgME::DN::detach()
     442             : {
     443           0 :     if (!d) {
     444           0 :         d = new QGpgME::DN::Private();
     445           0 :         d->ref();
     446           0 :     } else if (d->refCount() > 1) {
     447           0 :         QGpgME::DN::Private *d_save = d;
     448           0 :         d = new QGpgME::DN::Private(*d);
     449           0 :         d->ref();
     450           0 :         d_save->unref();
     451             :     }
     452           0 : }
     453             : 
     454           0 : void QGpgME::DN::append(const Attribute &attr)
     455             : {
     456           0 :     detach();
     457           0 :     d->attributes.push_back(attr);
     458           0 :     d->reorderedAttributes.clear();
     459           0 : }
     460             : 
     461           0 : QString QGpgME::DN::operator[](const QString &attr) const
     462             : {
     463           0 :     if (!d) {
     464           0 :         return QString();
     465             :     }
     466           0 :     const QString attrUpper = attr.toUpper();
     467           0 :     for (QVector<Attribute>::const_iterator it = d->attributes.constBegin();
     468           0 :             it != d->attributes.constEnd(); ++it)
     469           0 :         if ((*it).name() == attrUpper) {
     470           0 :             return (*it).value();
     471             :         }
     472           0 :     return QString();
     473             : }
     474             : 
     475           6 : static QVector<QGpgME::DN::Attribute> empty;
     476             : 
     477           0 : QGpgME::DN::const_iterator QGpgME::DN::begin() const
     478             : {
     479           0 :     return d ? d->attributes.constBegin() : empty.constBegin();
     480             : }
     481             : 
     482           0 : QGpgME::DN::const_iterator QGpgME::DN::end() const
     483             : {
     484           0 :     return d ? d->attributes.constEnd() : empty.constEnd();
     485             : }
     486             : 
     487           0 : void QGpgME::DN::setAttributeOrder (const QStringList &order) const
     488             : {
     489           0 :     d->order = order;
     490           0 : }
     491             : 
     492           0 : const QStringList & QGpgME::DN::attributeOrder () const
     493             : {
     494           0 :     return d->order;
     495          18 : }

Generated by: LCOV version 1.11