certmanager/lib

dn.cpp
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
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 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 TQt library by Trolltech AS, Norway (or with modified versions
28  of TQt that use the same license as TQt), 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  TQt. 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 #include "ui/dnattributeorderconfigwidget.h"
41 
42 #include <tdeapplication.h>
43 #include <tdeconfig.h>
44 #include <tdelocale.h>
45 
46 #include <tqstringlist.h>
47 #include <tqvaluevector.h>
48 
49 #include <iostream>
50 #include <iterator>
51 #include <algorithm>
52 #include <map>
53 
54 #include <string.h>
55 #include <ctype.h>
56 #include <stdlib.h>
57 
58 struct Kleo::DN::Private {
59  Private() : mRefCount( 0 ) {}
60  Private( const Private & other )
61  : attributes( other.attributes ),
62  reorderedAttributes( other.reorderedAttributes ),
63  mRefCount( 0 )
64  {
65 
66  }
67 
68  int ref() {
69  return ++mRefCount;
70  }
71 
72  int unref() {
73  if ( --mRefCount <= 0 ) {
74  delete this;
75  return 0;
76  } else
77  return mRefCount;
78  }
79 
80  int refCount() const { return mRefCount; }
81 
82  DN::Attribute::List attributes;
83  DN::Attribute::List reorderedAttributes;
84 private:
85  int mRefCount;
86 };
87 
88 namespace {
89  struct DnPair {
90  char * key;
91  char * value;
92  };
93 }
94 
95 // copied from CryptPlug and adapted to work on DN::Attribute::List:
96 
97 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
98 #define hexdigitp(a) (digitp (a) \
99  || (*(a) >= 'A' && *(a) <= 'F') \
100  || (*(a) >= 'a' && *(a) <= 'f'))
101 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
102  *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
103 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
104 
105 static char *
106 trim_trailing_spaces( char *string )
107 {
108  char *p, *mark;
109 
110  for( mark = NULL, p = string; *p; p++ ) {
111  if( isspace( *p ) ) {
112  if( !mark )
113  mark = p;
114  }
115  else
116  mark = NULL;
117  }
118  if( mark )
119  *mark = '\0' ;
120 
121  return string ;
122 }
123 
124 /* Parse a DN and return an array-ized one. This is not a validating
125  parser and it does not support any old-stylish syntax; gpgme is
126  expected to return only rfc2253 compatible strings. */
127 static const unsigned char *
128 parse_dn_part (DnPair *array, const unsigned char *string)
129 {
130  const unsigned char *s, *s1;
131  size_t n;
132  char *p;
133 
134  /* parse attributeType */
135  for (s = string+1; *s && *s != '='; s++)
136  ;
137  if (!*s)
138  return NULL; /* error */
139  n = s - string;
140  if (!n)
141  return NULL; /* empty key */
142  p = (char*)malloc (n+1);
143 
144 
145  memcpy (p, string, n);
146  p[n] = 0;
147  trim_trailing_spaces ((char*)p);
148  // map OIDs to their names:
149  for ( unsigned int i = 0 ; i < numOidMaps ; ++i )
150  if ( !strcasecmp ((char*)p, oidmap[i].oid) ) {
151  free( p );
152  p = strdup( oidmap[i].name );
153  break;
154  }
155  array->key = p;
156  string = s + 1;
157 
158  if (*string == '#')
159  { /* hexstring */
160  string++;
161  for (s=string; hexdigitp (s); s++)
162  s++;
163  n = s - string;
164  if (!n || (n & 1))
165  return NULL; /* empty or odd number of digits */
166  n /= 2;
167  array->value = p = (char*)malloc (n+1);
168 
169 
170  for (s1=string; n; s1 += 2, n--)
171  *p++ = xtoi_2 (s1);
172  *p = 0;
173  }
174  else
175  { /* regular v3 quoted string */
176  for (n=0, s=string; *s; s++)
177  {
178  if (*s == '\\')
179  { /* pair */
180  s++;
181  if (*s == ',' || *s == '=' || *s == '+'
182  || *s == '<' || *s == '>' || *s == '#' || *s == ';'
183  || *s == '\\' || *s == '\"' || *s == ' ')
184  n++;
185  else if (hexdigitp (s) && hexdigitp (s+1))
186  {
187  s++;
188  n++;
189  }
190  else
191  return NULL; /* invalid escape sequence */
192  }
193  else if (*s == '\"')
194  return NULL; /* invalid encoding */
195  else if (*s == ',' || *s == '=' || *s == '+'
196  || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
197  break;
198  else
199  n++;
200  }
201 
202  array->value = p = (char*)malloc (n+1);
203 
204 
205  for (s=string; n; s++, n--)
206  {
207  if (*s == '\\')
208  {
209  s++;
210  if (hexdigitp (s))
211  {
212  *p++ = xtoi_2 (s);
213  s++;
214  }
215  else
216  *p++ = *s;
217  }
218  else
219  *p++ = *s;
220  }
221  *p = 0;
222  }
223  return s;
224 }
225 
226 
227 /* Parse a DN and return an array-ized one. This is not a validating
228  parser and it does not support any old-stylish syntax; gpgme is
229  expected to return only rfc2253 compatible strings. */
230 static Kleo::DN::Attribute::List
231 parse_dn( const unsigned char * string ) {
232  if ( !string )
233  return TQValueVector<Kleo::DN::Attribute>();
234 
235  TQValueVector<Kleo::DN::Attribute> result;
236  while (*string)
237  {
238  while (*string == ' ')
239  string++;
240  if (!*string)
241  break; /* ready */
242 
243  DnPair pair = { 0, 0 };
244  string = parse_dn_part (&pair, string);
245  if (!string)
246  goto failure;
247  if ( pair.key && pair.value )
248  result.push_back( Kleo::DN::Attribute( TQString::fromUtf8( pair.key ),
249  TQString::fromUtf8( pair.value ) ) );
250  free( pair.key );
251  free( pair.value );
252 
253  while (*string == ' ')
254  string++;
255  if (*string && *string != ',' && *string != ';' && *string != '+')
256  goto failure; /* invalid delimiter */
257  if (*string)
258  string++;
259  }
260  return result;
261 
262 failure:
263  return TQValueVector<Kleo::DN::Attribute>();
264 }
265 
266 static TQValueVector<Kleo::DN::Attribute>
267 parse_dn( const TQString & dn ) {
268  return parse_dn( (const unsigned char*)dn.utf8().data() );
269 }
270 
271 static TQString dn_escape( const TQString & s ) {
272  TQString result;
273  for ( unsigned int i = 0, end = s.length() ; i != end ; ++i ) {
274  const TQChar ch = s[i];
275  switch ( ch.unicode() ) {
276  case ',':
277  case '+':
278  case '"':
279  case '\\':
280  case '<':
281  case '>':
282  case ';':
283  result += '\\';
284  // fall through
285  default:
286  result += ch;
287  }
288  }
289  return result;
290 }
291 
292 static TQString
293 serialise( const TQValueVector<Kleo::DN::Attribute> & dn ) {
294  TQStringList result;
295  for ( TQValueVector<Kleo::DN::Attribute>::const_iterator it = dn.begin() ; it != dn.end() ; ++it )
296  if ( !(*it).name().isEmpty() && !(*it).value().isEmpty() )
297  result.push_back( (*it).name().stripWhiteSpace() + '=' + dn_escape( (*it).value().stripWhiteSpace() ) );
298  return result.join( "," );
299 }
300 
301 static Kleo::DN::Attribute::List
302 reorder_dn( const Kleo::DN::Attribute::List & dn ) {
303  const TQStringList & attrOrder = Kleo::DNAttributeMapper::instance()->attributeOrder();
304 
305  Kleo::DN::Attribute::List unknownEntries;
306  Kleo::DN::Attribute::List result;
307  unknownEntries.reserve( dn.size() );
308  result.reserve( dn.size() );
309 
310  // find all unknown entries in their order of appearance
311  for ( Kleo::DN::const_iterator it = dn.begin(); it != dn.end(); ++it )
312  if ( attrOrder.find( (*it).name() ) == attrOrder.end() )
313  unknownEntries.push_back( *it );
314 
315  // process the known attrs in the desired order
316  for ( TQStringList::const_iterator oit = attrOrder.begin() ; oit != attrOrder.end() ; ++oit )
317  if ( *oit == "_X_" ) {
318  // insert the unknown attrs
319  std::copy( unknownEntries.begin(), unknownEntries.end(),
320  std::back_inserter( result ) );
321  unknownEntries.clear(); // don't produce dup's
322  } else {
323  for ( Kleo::DN::const_iterator dnit = dn.begin() ; dnit != dn.end() ; ++dnit )
324  if ( (*dnit).name() == *oit )
325  result.push_back( *dnit );
326  }
327 
328  return result;
329 }
330 
331 //
332 //
333 // class DN
334 //
335 //
336 
337 Kleo::DN::DN() {
338  d = new Private();
339  d->ref();
340 }
341 
342 Kleo::DN::DN( const TQString & dn ) {
343  d = new Private();
344  d->ref();
345  d->attributes = parse_dn( dn );
346 }
347 
348 Kleo::DN::DN( const char * utf8DN ) {
349  d = new Private();
350  d->ref();
351  if ( utf8DN )
352  d->attributes = parse_dn( (const unsigned char*)utf8DN );
353 }
354 
355 Kleo::DN::DN( const DN & other )
356  : d( other.d )
357 {
358  if ( d ) d->ref();
359 }
360 
361 Kleo::DN::~DN() {
362  if ( d ) d->unref();
363 }
364 
365 const Kleo::DN & Kleo::DN::operator=( const DN & that ) {
366  if ( this->d == that.d )
367  return *this;
368 
369  if ( that.d )
370  that.d->ref();
371  if ( this->d )
372  this->d->unref();
373 
374  this->d = that.d;
375 
376  return *this;
377 }
378 
379 TQString Kleo::DN::prettyDN() const {
380  if ( !d )
381  return TQString();
382  if ( d->reorderedAttributes.empty() )
383  d->reorderedAttributes = reorder_dn( d->attributes );
384  return serialise( d->reorderedAttributes );
385 }
386 
387 TQString Kleo::DN::dn() const {
388  return d ? serialise( d->attributes ) : TQString() ;
389 }
390 
391 // static
392 TQString Kleo::DN::escape( const TQString & value ) {
393  return dn_escape( value );
394 }
395 
396 void Kleo::DN::detach() {
397  if ( !d ) {
398  d = new Kleo::DN::Private();
399  d->ref();
400  } else if ( d->refCount() > 1 ) {
401  Kleo::DN::Private * d_save = d;
402  d = new Kleo::DN::Private( *d );
403  d->ref();
404  d_save->unref();
405  }
406 }
407 
408 void Kleo::DN::append( const Attribute & attr ) {
409  detach();
410  d->attributes.push_back( attr );
411  d->reorderedAttributes.clear();
412 }
413 
414 TQString Kleo::DN::operator[]( const TQString & attr ) const {
415  if ( !d )
416  return TQString();
417  const TQString attrUpper = attr.upper();
418  for ( TQValueVector<Attribute>::const_iterator it = d->attributes.begin() ;
419  it != d->attributes.end() ; ++it )
420  if ( (*it).name() == attrUpper )
421  return (*it).value();
422  return TQString();
423 }
424 
425 static TQValueVector<Kleo::DN::Attribute> empty;
426 
427 Kleo::DN::const_iterator Kleo::DN::begin() const {
428  return d ? d->attributes.begin() : empty.begin() ;
429 }
430 
431 Kleo::DN::const_iterator Kleo::DN::end() const {
432  return d ? d->attributes.end() : empty.end() ;
433 }
434 
435 
437 
438 namespace {
439  struct ltstr {
440  bool operator()( const char * s1, const char * s2 ) const {
441  return qstrcmp( s1, s2 ) < 0 ;
442  }
443  };
444 }
445 
446 static const char * defaultOrder[] = {
447  "CN", "L", "_X_", "OU", "O", "C"
448 };
449 
450 std::pair<const char*,const char*> attributeLabels[] = {
451 #define MAKE_PAIR(x,y) std::pair<const char*,const char*>( x, y )
452  MAKE_PAIR( "CN", I18N_NOOP("Common name") ),
453  MAKE_PAIR( "SN", I18N_NOOP("Surname") ),
454  MAKE_PAIR( "GN", I18N_NOOP("Given name") ),
455  MAKE_PAIR( "L", I18N_NOOP("Location") ),
456  MAKE_PAIR( "T", I18N_NOOP("Title") ),
457  MAKE_PAIR( "OU", I18N_NOOP("Organizational unit") ),
458  MAKE_PAIR( "O", I18N_NOOP("Organization") ),
459  MAKE_PAIR( "PC", I18N_NOOP("Postal code") ),
460  MAKE_PAIR( "C", I18N_NOOP("Country code") ),
461  MAKE_PAIR( "SP", I18N_NOOP("State or province") ),
462  MAKE_PAIR( "DC", I18N_NOOP("Domain component") ),
463  MAKE_PAIR( "BC", I18N_NOOP("Business category") ),
464  MAKE_PAIR( "EMAIL", I18N_NOOP("Email address") ),
465  MAKE_PAIR( "MAIL", I18N_NOOP("Mail address") ),
466  MAKE_PAIR( "MOBILE", I18N_NOOP("Mobile phone number") ),
467  MAKE_PAIR( "TEL", I18N_NOOP("Telephone number") ),
468  MAKE_PAIR( "FAX", I18N_NOOP("Fax number") ),
469  MAKE_PAIR( "STREET", I18N_NOOP("Street address") ),
470  MAKE_PAIR( "UID", I18N_NOOP("Unique ID") )
471 #undef MAKE_PAIR
472 };
473 static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof *attributeLabels ;
474 
475 class Kleo::DNAttributeMapper::Private {
476 public:
477  Private();
478  std::map<const char*,const char*,ltstr> map;
479  TQStringList attributeOrder;
480 };
481 
482 Kleo::DNAttributeMapper::Private::Private()
483  : map( attributeLabels, attributeLabels + numAttributeLabels ) {}
484 
485 Kleo::DNAttributeMapper::DNAttributeMapper() {
486  d = new Private();
487  const TDEConfigGroup config( kapp->config(), "DN" );
488  d->attributeOrder = config.readListEntry( "AttributeOrder" );
489  if ( d->attributeOrder.empty() )
490  std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
491  std::back_inserter( d->attributeOrder ) );
492  mSelf = this;
493 }
494 
495 Kleo::DNAttributeMapper::~DNAttributeMapper() {
496  mSelf = 0;
497  delete d; d = 0;
498 }
499 
500 Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::mSelf = 0;
501 
502 const Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::instance() {
503  if ( !mSelf )
504  (void)new DNAttributeMapper();
505  return mSelf;
506 }
507 
508 TQString Kleo::DNAttributeMapper::name2label( const TQString & s ) const {
509  const std::map<const char*,const char*,ltstr>::const_iterator it
510  = d->map.find( s.stripWhiteSpace().upper().latin1() );
511  if ( it == d->map.end() )
512  return TQString();
513  return i18n( it->second );
514 }
515 
516 TQStringList Kleo::DNAttributeMapper::names() const {
517  TQStringList result;
518  for ( std::map<const char*,const char*,ltstr>::const_iterator it = d->map.begin() ; it != d->map.end() ; ++it )
519  result.push_back( it->first );
520  return result;
521 }
522 
523 const TQStringList & Kleo::DNAttributeMapper::attributeOrder() const {
524  return d->attributeOrder;
525 }
526 
527 void Kleo::DNAttributeMapper::setAttributeOrder( const TQStringList & order ) {
528  d->attributeOrder = order;
529  if ( order.empty() )
530  std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
531  std::back_inserter( d->attributeOrder ) );
532  TDEConfigGroup config( kapp->config(), "DN" );
533  config.writeEntry( "AttributeOrder", order );
534 }
535 
536 Kleo::DNAttributeOrderConfigWidget * Kleo::DNAttributeMapper::configWidget( TQWidget * parent, const char * name ) const {
537  return new DNAttributeOrderConfigWidget( mSelf, parent, name );
538 }
DN Attribute mapper.
Definition: dn.h:52
DN parser and reorderer.
Definition: dn.h:76
static TQString escape(const TQString &value)
Definition: dn.cpp:392
TQString prettyDN() const
Definition: dn.cpp:379
TQString dn() const
Definition: dn.cpp:387