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
58struct 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;
84private:
85 int mRefCount;
86};
87
88namespace {
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
105static char *
106trim_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. */
127static const unsigned char *
128parse_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. */
230static Kleo::DN::Attribute::List
231parse_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
262failure:
263 return TQValueVector<Kleo::DN::Attribute>();
264}
265
266static TQValueVector<Kleo::DN::Attribute>
267parse_dn( const TQString & dn ) {
268 return parse_dn( (const unsigned char*)dn.utf8().data() );
269}
270
271static 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
292static TQString
293serialise( 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
301static Kleo::DN::Attribute::List
302reorder_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
337Kleo::DN::DN() {
338 d = new Private();
339 d->ref();
340}
341
342Kleo::DN::DN( const TQString & dn ) {
343 d = new Private();
344 d->ref();
345 d->attributes = parse_dn( dn );
346}
347
348Kleo::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
355Kleo::DN::DN( const DN & other )
356 : d( other.d )
357{
358 if ( d ) d->ref();
359}
360
361Kleo::DN::~DN() {
362 if ( d ) d->unref();
363}
364
365const 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
379TQString 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
387TQString Kleo::DN::dn() const {
388 return d ? serialise( d->attributes ) : TQString() ;
389}
390
391// static
392TQString Kleo::DN::escape( const TQString & value ) {
393 return dn_escape( value );
394}
395
396void 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
408void Kleo::DN::append( const Attribute & attr ) {
409 detach();
410 d->attributes.push_back( attr );
411 d->reorderedAttributes.clear();
412}
413
414TQString 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
425static TQValueVector<Kleo::DN::Attribute> empty;
426
427Kleo::DN::const_iterator Kleo::DN::begin() const {
428 return d ? d->attributes.begin() : empty.begin() ;
429}
430
431Kleo::DN::const_iterator Kleo::DN::end() const {
432 return d ? d->attributes.end() : empty.end() ;
433}
434
435
437
438namespace {
439 struct ltstr {
440 bool operator()( const char * s1, const char * s2 ) const {
441 return qstrcmp( s1, s2 ) < 0 ;
442 }
443 };
444}
445
446static const char * defaultOrder[] = {
447 "CN", "L", "_X_", "OU", "O", "C"
448};
449
450std::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};
473static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof *attributeLabels ;
474
475class Kleo::DNAttributeMapper::Private {
476public:
477 Private();
478 std::map<const char*,const char*,ltstr> map;
479 TQStringList attributeOrder;
480};
481
482Kleo::DNAttributeMapper::Private::Private()
483 : map( attributeLabels, attributeLabels + numAttributeLabels ) {}
484
485Kleo::DNAttributeMapper::DNAttributeMapper() {
486 d = new Private();
487 const TDEConfigGroup config( tdeApp->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
495Kleo::DNAttributeMapper::~DNAttributeMapper() {
496 mSelf = 0;
497 delete d; d = 0;
498}
499
500Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::mSelf = 0;
501
502const Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::instance() {
503 if ( !mSelf )
504 (void)new DNAttributeMapper();
505 return mSelf;
506}
507
508TQString 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
516TQStringList 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
523const TQStringList & Kleo::DNAttributeMapper::attributeOrder() const {
524 return d->attributeOrder;
525}
526
527void 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( tdeApp->config(), "DN" );
533 config.writeEntry( "AttributeOrder", order );
534}
535
536Kleo::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