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

Generated by: LCOV version 1.13