• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • pim API Reference
  • KDE Home
  • Contact Us
 

libkleo

  • kde-4.x
  • pim
  • libkleo
  • src
  • kleo
dn.cpp
Go to the documentation of this file.
1 /*
2  dn.cpp
3 
4  This file is part of libkleopatra, the KDE keymanagement library
5  Copyright (c) 2004 Klarälvdalens Datakonsult AB
6 
7  DN parsing:
8  Copyright (c) 2002 g10 Code GmbH
9  Copyright (c) 2004 Klarälvdalens Datakonsult AB
10 
11  Libkleopatra is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 2 of the
14  License, or (at your option) any later version.
15 
16  Libkleopatra is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License along
22  with this program; if not, write to the Free Software Foundation, Inc.,
23  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 
25  In addition, as a special exception, the copyright holders give
26  permission to link the code of this program with any edition of
27  the Qt library by Trolltech AS, Norway (or with modified versions
28  of Qt that use the same license as Qt), and distribute linked
29  combinations including the two. You must obey the GNU General
30  Public License in all respects for all of the code used other than
31  Qt. If you modify this file, you may extend this exception to
32  your version of the file, but you are not obligated to do so. If
33  you do not wish to do so, delete this exception statement from
34  your version.
35 */
36 
37 #include "dn.h"
38 
39 #include "oidmap.h"
40 
41 #include "ui/dnattributeorderconfigwidget.h"
42 
43 #include <KConfig>
44 #include <KLocalizedString>
45 
46 #include <QStringList>
47 
48 #include <iostream>
49 #include <iterator>
50 #include <algorithm>
51 #include <map>
52 
53 #include <string.h>
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <KConfigGroup>
57 #include <KSharedConfig>
58 
59 class Kleo::DN::Private
60 {
61 public:
62  Private() : mRefCount(0) {}
63  Private(const Private &other)
64  : attributes(other.attributes),
65  reorderedAttributes(other.reorderedAttributes),
66  mRefCount(0)
67  {
68 
69  }
70 
71  int ref()
72  {
73  return ++mRefCount;
74  }
75 
76  int unref()
77  {
78  if (--mRefCount <= 0) {
79  delete this;
80  return 0;
81  } else {
82  return mRefCount;
83  }
84  }
85 
86  int refCount() const
87  {
88  return mRefCount;
89  }
90 
91  DN::Attribute::List attributes;
92  DN::Attribute::List reorderedAttributes;
93 private:
94  int mRefCount;
95 };
96 
97 namespace
98 {
99 struct DnPair {
100  char *key;
101  char *value;
102 };
103 }
104 
105 // copied from CryptPlug and adapted to work on DN::Attribute::List:
106 
107 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
108 #define hexdigitp(a) (digitp (a) \
109  || (*(a) >= 'A' && *(a) <= 'F') \
110  || (*(a) >= 'a' && *(a) <= 'f'))
111 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
112  *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
113 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
114 
115 static char *
116 trim_trailing_spaces(char *string)
117 {
118  char *p, *mark;
119 
120  for (mark = nullptr, p = string; *p; p++) {
121  if (isspace(*p)) {
122  if (!mark) {
123  mark = p;
124  }
125  } else {
126  mark = nullptr;
127  }
128  }
129  if (mark) {
130  *mark = '\0';
131  }
132 
133  return string;
134 }
135 
136 /* Parse a DN and return an array-ized one. This is not a validating
137  parser and it does not support any old-stylish syntax; gpgme is
138  expected to return only rfc2253 compatible strings. */
139 static const unsigned char *
140 parse_dn_part(DnPair *array, const unsigned char *string)
141 {
142  const unsigned char *s, *s1;
143  size_t n;
144  char *p;
145 
146  /* parse attributeType */
147  for (s = string + 1; *s && *s != '='; s++)
148  ;
149  if (!*s) {
150  return nullptr; /* error */
151  }
152  n = s - string;
153  if (!n) {
154  return nullptr; /* empty key */
155  }
156  p = (char *)malloc(n + 1);
157 
158  memcpy(p, string, n);
159  p[n] = 0;
160  trim_trailing_spaces((char *)p);
161  // map OIDs to their names:
162  for (unsigned int i = 0; i < numOidMaps; ++i)
163  if (!strcasecmp((char *)p, oidmap[i].oid)) {
164  free(p);
165  p = strdup(oidmap[i].name);
166  break;
167  }
168  array->key = p;
169  string = s + 1;
170 
171  if (*string == '#') {
172  /* hexstring */
173  string++;
174  for (s = string; hexdigitp(s); s++) {
175  s++;
176  }
177  n = s - string;
178  if (!n || (n & 1)) {
179  return nullptr; /* empty or odd number of digits */
180  }
181  n /= 2;
182  array->value = p = (char *)malloc(n + 1);
183 
184  for (s1 = string; n; s1 += 2, n--) {
185  *p++ = xtoi_2(s1);
186  }
187  *p = 0;
188  } else {
189  /* regular v3 quoted string */
190  for (n = 0, s = string; *s; s++) {
191  if (*s == '\\') {
192  /* pair */
193  s++;
194  if (*s == ',' || *s == '=' || *s == '+'
195  || *s == '<' || *s == '>' || *s == '#' || *s == ';'
196  || *s == '\\' || *s == '\"' || *s == ' ') {
197  n++;
198  } else if (hexdigitp(s) && hexdigitp(s + 1)) {
199  s++;
200  n++;
201  } else {
202  return nullptr; /* invalid escape sequence */
203  }
204  } else if (*s == '\"') {
205  return nullptr; /* invalid encoding */
206  } else if (*s == ',' || *s == '=' || *s == '+'
207  || *s == '<' || *s == '>' || *s == '#' || *s == ';') {
208  break;
209  } else {
210  n++;
211  }
212  }
213 
214  array->value = p = (char *)malloc(n + 1);
215 
216  for (s = string; n; s++, n--) {
217  if (*s == '\\') {
218  s++;
219  if (hexdigitp(s)) {
220  *p++ = xtoi_2(s);
221  s++;
222  } else {
223  *p++ = *s;
224  }
225  } else {
226  *p++ = *s;
227  }
228  }
229  *p = 0;
230  }
231  return s;
232 }
233 
234 /* Parse a DN and return an array-ized one. This is not a validating
235  parser and it does not support any old-stylish syntax; gpgme is
236  expected to return only rfc2253 compatible strings. */
237 static Kleo::DN::Attribute::List
238 parse_dn(const unsigned char *string)
239 {
240  if (!string) {
241  return QVector<Kleo::DN::Attribute>();
242  }
243 
244  QVector<Kleo::DN::Attribute> result;
245  while (*string) {
246  while (*string == ' ') {
247  string++;
248  }
249  if (!*string) {
250  break; /* ready */
251  }
252 
253  DnPair pair = { nullptr, nullptr };
254  string = parse_dn_part(&pair, string);
255  if (!string) {
256  goto failure;
257  }
258  if (pair.key && pair.value)
259  result.push_back(Kleo::DN::Attribute(QString::fromUtf8(pair.key),
260  QString::fromUtf8(pair.value)));
261  free(pair.key);
262  free(pair.value);
263 
264  while (*string == ' ') {
265  string++;
266  }
267  if (*string && *string != ',' && *string != ';' && *string != '+') {
268  goto failure; /* invalid delimiter */
269  }
270  if (*string) {
271  string++;
272  }
273  }
274  return result;
275 
276 failure:
277  return QVector<Kleo::DN::Attribute>();
278 }
279 
280 static QVector<Kleo::DN::Attribute>
281 parse_dn(const QString &dn)
282 {
283  return parse_dn((const unsigned char *)dn.toUtf8().data());
284 }
285 
286 static QString dn_escape(const QString &s)
287 {
288  QString result;
289  for (int i = 0, end = s.length(); i != end; ++i) {
290  const QChar ch = s[i];
291  switch (ch.unicode()) {
292  case ',':
293  case '+':
294  case '"':
295  case '\\':
296  case '<':
297  case '>':
298  case ';':
299  result += QLatin1Char('\\');
300  // fall through
301  Q_FALLTHROUGH();
302  default:
303  result += ch;
304  }
305  }
306  return result;
307 }
308 
309 static QString
310 serialise(const QVector<Kleo::DN::Attribute> &dn, const QString &sep)
311 {
312  QStringList result;
313  for (QVector<Kleo::DN::Attribute>::const_iterator it = dn.begin(); it != dn.end(); ++it)
314  if (!(*it).name().isEmpty() && !(*it).value().isEmpty()) {
315  result.push_back((*it).name().trimmed() + QLatin1Char('=') + dn_escape((*it).value().trimmed()));
316  }
317  return result.join(sep);
318 }
319 
320 static Kleo::DN::Attribute::List
321 reorder_dn(const Kleo::DN::Attribute::List &dn)
322 {
323  const QStringList &attrOrder = Kleo::DNAttributeMapper::instance()->attributeOrder();
324 
325  Kleo::DN::Attribute::List unknownEntries;
326  Kleo::DN::Attribute::List result;
327  unknownEntries.reserve(dn.size());
328  result.reserve(dn.size());
329 
330  // find all unknown entries in their order of appearance
331  for (Kleo::DN::const_iterator it = dn.begin(); it != dn.end(); ++it)
332  if (!attrOrder.contains((*it).name())) {
333  unknownEntries.push_back(*it);
334  }
335 
336  // process the known attrs in the desired order
337  for (QStringList::const_iterator oit = attrOrder.begin(); oit != attrOrder.end(); ++oit)
338  if (*oit == QLatin1String("_X_")) {
339  // insert the unknown attrs
340  std::copy(unknownEntries.begin(), unknownEntries.end(),
341  std::back_inserter(result));
342  unknownEntries.clear(); // don't produce dup's
343  } else {
344  for (Kleo::DN::const_iterator dnit = dn.begin(); dnit != dn.end(); ++dnit)
345  if ((*dnit).name() == *oit) {
346  result.push_back(*dnit);
347  }
348  }
349 
350  return result;
351 }
352 
353 //
354 //
355 // class DN
356 //
357 //
358 
359 Kleo::DN::DN()
360 {
361  d = new Private();
362  d->ref();
363 }
364 
365 Kleo::DN::DN(const QString &dn)
366 {
367  d = new Private();
368  d->ref();
369  d->attributes = parse_dn(dn);
370 }
371 
372 Kleo::DN::DN(const char *utf8DN)
373 {
374  d = new Private();
375  d->ref();
376  if (utf8DN) {
377  d->attributes = parse_dn((const unsigned char *)utf8DN);
378  }
379 }
380 
381 Kleo::DN::DN(const DN &other)
382  : d(other.d)
383 {
384  if (d) {
385  d->ref();
386  }
387 }
388 
389 Kleo::DN::~DN()
390 {
391  if (d) {
392  d->unref();
393  }
394 }
395 
396 const Kleo::DN &Kleo::DN::operator=(const DN &that)
397 {
398  if (this->d == that.d) {
399  return *this;
400  }
401 
402  if (that.d) {
403  that.d->ref();
404  }
405  if (this->d) {
406  this->d->unref();
407  }
408 
409  this->d = that.d;
410 
411  return *this;
412 }
413 
414 QString Kleo::DN::prettyDN() const
415 {
416  if (!d) {
417  return QString();
418  }
419  if (d->reorderedAttributes.empty()) {
420  d->reorderedAttributes = reorder_dn(d->attributes);
421  }
422  return serialise(d->reorderedAttributes, QStringLiteral(","));
423 }
424 
425 QString Kleo::DN::dn() const
426 {
427  return d ? serialise(d->attributes, QStringLiteral(",")) : QString();
428 }
429 
430 QString Kleo::DN::dn(const QString &sep) const
431 {
432  return d ? serialise(d->attributes, sep) : QString();
433 }
434 
435 // static
436 QString Kleo::DN::escape(const QString &value)
437 {
438  return dn_escape(value);
439 }
440 
441 void Kleo::DN::detach()
442 {
443  if (!d) {
444  d = new Kleo::DN::Private();
445  d->ref();
446  } else if (d->refCount() > 1) {
447  Kleo::DN::Private *d_save = d;
448  d = new Kleo::DN::Private(*d);
449  d->ref();
450  d_save->unref();
451  }
452 }
453 
454 void Kleo::DN::append(const Attribute &attr)
455 {
456  detach();
457  d->attributes.push_back(attr);
458  d->reorderedAttributes.clear();
459 }
460 
461 QString Kleo::DN::operator[](const QString &attr) const
462 {
463  if (!d) {
464  return QString();
465  }
466  const QString attrUpper = attr.toUpper();
467  for (QVector<Attribute>::const_iterator it = d->attributes.constBegin();
468  it != d->attributes.constEnd(); ++it)
469  if ((*it).name() == attrUpper) {
470  return (*it).value();
471  }
472  return QString();
473 }
474 
475 static QVector<Kleo::DN::Attribute> empty;
476 
477 Kleo::DN::const_iterator Kleo::DN::begin() const
478 {
479  return d ? d->attributes.constBegin() : empty.constBegin();
480 }
481 
482 Kleo::DN::const_iterator Kleo::DN::end() const
483 {
484  return d ? d->attributes.constEnd() : empty.constEnd();
485 }
486 
488 
489 namespace
490 {
491 struct ltstr {
492  bool operator()(const char *s1, const char *s2) const
493  {
494  return qstrcmp(s1, s2) < 0;
495  }
496 };
497 }
498 
499 static const char *const defaultOrder[] = {
500  "CN", "L", "_X_", "OU", "O", "C"
501 };
502 
503 static std::pair<const char *, const char *> const attributeLabels[] = {
504 #define MAKE_PAIR(x,y) std::pair<const char*,const char*>( x, y )
505  MAKE_PAIR("CN", I18N_NOOP("Common name")),
506  MAKE_PAIR("SN", I18N_NOOP("Surname")),
507  MAKE_PAIR("GN", I18N_NOOP("Given name")),
508  MAKE_PAIR("L", I18N_NOOP("Location")),
509  MAKE_PAIR("T", I18N_NOOP("Title")),
510  MAKE_PAIR("OU", I18N_NOOP("Organizational unit")),
511  MAKE_PAIR("O", I18N_NOOP("Organization")),
512  MAKE_PAIR("PC", I18N_NOOP("Postal code")),
513  MAKE_PAIR("C", I18N_NOOP("Country code")),
514  MAKE_PAIR("SP", I18N_NOOP("State or province")),
515  MAKE_PAIR("DC", I18N_NOOP("Domain component")),
516  MAKE_PAIR("BC", I18N_NOOP("Business category")),
517  MAKE_PAIR("EMAIL", I18N_NOOP("Email address")),
518  MAKE_PAIR("MAIL", I18N_NOOP("Mail address")),
519  MAKE_PAIR("MOBILE", I18N_NOOP("Mobile phone number")),
520  MAKE_PAIR("TEL", I18N_NOOP("Telephone number")),
521  MAKE_PAIR("FAX", I18N_NOOP("Fax number")),
522  MAKE_PAIR("STREET", I18N_NOOP("Street address")),
523  MAKE_PAIR("UID", I18N_NOOP("Unique ID"))
524 #undef MAKE_PAIR
525 };
526 static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof * attributeLabels;
527 
528 class Kleo::DNAttributeMapper::Private
529 {
530 public:
531  Private();
532  std::map<const char *, const char *, ltstr> map;
533  QStringList attributeOrder;
534 };
535 
536 Kleo::DNAttributeMapper::Private::Private()
537  : map(attributeLabels, attributeLabels + numAttributeLabels) {}
538 
539 Kleo::DNAttributeMapper::DNAttributeMapper()
540 {
541  d = new Private();
542  const KConfigGroup config(KSharedConfig::openConfig(), "DN");
543  d->attributeOrder = config.readEntry("AttributeOrder", QStringList());
544  if (d->attributeOrder.empty())
545  std::copy(defaultOrder, defaultOrder + sizeof defaultOrder / sizeof * defaultOrder,
546  std::back_inserter(d->attributeOrder));
547  mSelf = this;
548 }
549 
550 Kleo::DNAttributeMapper::~DNAttributeMapper()
551 {
552  mSelf = nullptr;
553  delete d; d = nullptr;
554 }
555 
556 Kleo::DNAttributeMapper *Kleo::DNAttributeMapper::mSelf = nullptr;
557 
558 const Kleo::DNAttributeMapper *Kleo::DNAttributeMapper::instance()
559 {
560  if (!mSelf) {
561  (void)new DNAttributeMapper();
562  }
563  return mSelf;
564 }
565 
566 QString Kleo::DNAttributeMapper::name2label(const QString &s) const
567 {
568  const std::map<const char *, const char *, ltstr>::const_iterator it
569  = d->map.find(s.trimmed().toUpper().toLatin1().constData());
570  if (it == d->map.end()) {
571  return QString();
572  }
573  return i18n(it->second);
574 }
575 
576 QStringList Kleo::DNAttributeMapper::names() const
577 {
578  QStringList result;
579  for (std::map<const char *, const char *, ltstr>::const_iterator it = d->map.begin(); it != d->map.end(); ++it) {
580  result.push_back(QLatin1String(it->first));
581  }
582  return result;
583 }
584 
585 const QStringList &Kleo::DNAttributeMapper::attributeOrder() const
586 {
587  return d->attributeOrder;
588 }
589 
590 void Kleo::DNAttributeMapper::setAttributeOrder(const QStringList &order)
591 {
592  d->attributeOrder = order;
593  if (order.empty())
594  std::copy(defaultOrder, defaultOrder + sizeof defaultOrder / sizeof * defaultOrder,
595  std::back_inserter(d->attributeOrder));
596  KConfigGroup config(KSharedConfig::openConfig(), "DN");
597  config.writeEntry("AttributeOrder", order);
598 }
599 
600 Kleo::DNAttributeOrderConfigWidget *Kleo::DNAttributeMapper::configWidget(QWidget *parent) const
601 {
602  return new DNAttributeOrderConfigWidget(mSelf, parent);
603 }
QWidget
trim_trailing_spaces
static char * trim_trailing_spaces(char *string)
Definition: dn.cpp:116
QString::toUpper
QString toUpper() const
empty
static QVector< Kleo::DN::Attribute > empty
Definition: dn.cpp:475
name
const char * name
Definition: kconfigbasedkeyfilter.cpp:127
Kleo::DNAttributeMapper::name2label
QString name2label(const QString &s) const
Definition: dn.cpp:566
oid
const char * oid
Definition: oidmap.h:38
Kleo::DNAttributeMapper::setAttributeOrder
void setAttributeOrder(const QStringList &order)
Definition: dn.cpp:590
numOidMaps
static const unsigned int numOidMaps
Definition: oidmap.h:55
QVector::begin
iterator begin()
QList::push_back
void push_back(const T &value)
Attribute
oidmap
static const struct @2 oidmap[]
QChar
QList::reserve
void reserve(int alloc)
QVector::constEnd
const_iterator constEnd() const
defaultOrder
static const char *const defaultOrder[]
Definition: dn.cpp:499
Kleo::DN::DN
DN()
Definition: dn.cpp:359
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
numAttributeLabels
static const unsigned int numAttributeLabels
Definition: dn.cpp:526
Kleo::DN::prettyDN
QString prettyDN() const
Definition: dn.cpp:414
QStringList::join
QString join(const QString &separator) const
Kleo::DNAttributeMapper::attributeOrder
const QStringList & attributeOrder() const
Definition: dn.cpp:585
QList::const_iterator
dn.h
Kleo::DN::escape
static QString escape(const QString &value)
Definition: dn.cpp:436
Kleo::DNAttributeMapper
DN Attribute mapper.
Definition: dn.h:55
xtoi_2
#define xtoi_2(p)
Definition: dn.cpp:113
reorder_dn
static Kleo::DN::Attribute::List reorder_dn(const Kleo::DN::Attribute::List &dn)
Definition: dn.cpp:321
QString::fromUtf8
QString fromUtf8(const char *str, int size)
QList::empty
bool empty() const
dnattributeorderconfigwidget.h
Kleo::DNAttributeMapper::names
QStringList names() const
Definition: dn.cpp:576
oidmap.h
QString::trimmed
QString trimmed() const
Kleo::DNAttributeOrderConfigWidget
Definition: dnattributeorderconfigwidget.h:50
QByteArray::constData
const char * constData() const
Kleo::DN::append
void append(const Attribute &attr)
Definition: dn.cpp:454
parse_dn_part
static const unsigned char * parse_dn_part(DnPair *array, const unsigned char *string)
Definition: dn.cpp:140
QString
QtConcurrent::map
QFuture< void > map(Sequence &sequence, MapFunction function)
QChar::unicode
ushort unicode() const
QStringList
Kleo::DN
DN parser and reorderer.
Definition: dn.h:80
QList::end
iterator end()
QLatin1Char
hexdigitp
#define hexdigitp(a)
Definition: dn.cpp:108
Kleo::DN::operator[]
QString operator[](const QString &attr) const
Definition: dn.cpp:461
QVector::constBegin
const_iterator constBegin() const
QString::toLatin1
QByteArray toLatin1() const
QVector
QLatin1String
parse_dn
static Kleo::DN::Attribute::List parse_dn(const unsigned char *string)
Definition: dn.cpp:238
Kleo::DN::~DN
~DN()
Definition: dn.cpp:389
Kleo::DN::end
const_iterator end() const
Definition: dn.cpp:482
serialise
static QString serialise(const QVector< Kleo::DN::Attribute > &dn, const QString &sep)
Definition: dn.cpp:310
QString::length
int length() const
QByteArray::data
char * data()
attributeLabels
static std::pair< const char *, const char * > const attributeLabels[]
Definition: dn.cpp:503
QVector::push_back
void push_back(const T &value)
QString::find
int find(QChar c, int i, bool cs) const
dn_escape
static QString dn_escape(const QString &s)
Definition: dn.cpp:286
Kleo::DN::begin
const_iterator begin() const
Definition: dn.cpp:477
MAKE_PAIR
#define MAKE_PAIR(x, y)
QVector::end
iterator end()
QList::begin
iterator begin()
Kleo::DNAttributeMapper::instance
static const DNAttributeMapper * instance()
Definition: dn.cpp:558
Kleo::DN::Attribute
Attribute(const QString &name=QString(), const QString &value=QString())
Definition: dn.h:128
Kleo::DNAttributeMapper::configWidget
DNAttributeOrderConfigWidget * configWidget(QWidget *parent=nullptr) const
Definition: dn.cpp:600
Kleo::DN::dn
QString dn() const
Definition: dn.cpp:425
Kleo::DN::operator=
const DN & operator=(const DN &other)
Definition: dn.cpp:396
QString::toUtf8
QByteArray toUtf8() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Wed Dec 11 2019 06:52:29 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libkleo

Skip menu "libkleo"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

pim API Reference

Skip menu "pim API Reference"
  • akonadi-calendar-tools
  •   konsolekalendar
  • akregator
  •   src
  • kalarmcal
  •   src
  •     lib
  • kdepim-runtime
  •   agents
  •   src
  • kleopatra
  •   src
  • kmailtransport
  • knotes
  • kontact
  • kontactinterface
  • kpimtextedit
  • ksmtp
  • ktnef
  • libkgapi
  • libkleo
  •   src
  •     src
  •     src

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal