certmanager/lib Library API Documentation

dn.cpp

00001 /* 00002 dn.cpp 00003 00004 This file is part of libkleopatra, the KDE keymanagement library 00005 Copyright (c) 2004 Klarälvdalens Datakonsult AB 00006 00007 DN parsing: 00008 Copyright (c) 2002 g10 Code GmbH 00009 Copyright (c) 2004 Klarälvdalens Datakonsult AB 00010 00011 Libkleopatra is free software; you can redistribute it and/or 00012 modify it under the terms of the GNU General Public License as 00013 published by the Free Software Foundation; either version 2 of the 00014 License, or (at your option) any later version. 00015 00016 Libkleopatra is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 General Public License for more details. 00020 00021 You should have received a copy of the GNU General Public License 00022 along with this program; if not, write to the Free Software 00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 00025 In addition, as a special exception, the copyright holders give 00026 permission to link the code of this program with any edition of 00027 the Qt library by Trolltech AS, Norway (or with modified versions 00028 of Qt that use the same license as Qt), and distribute linked 00029 combinations including the two. You must obey the GNU General 00030 Public License in all respects for all of the code used other than 00031 Qt. If you modify this file, you may extend this exception to 00032 your version of the file, but you are not obligated to do so. If 00033 you do not wish to do so, delete this exception statement from 00034 your version. 00035 */ 00036 00037 #include "dn.h" 00038 00039 #include "oidmap.h" 00040 #include "ui/dnattributeorderconfigwidget.h" 00041 00042 #include <kapplication.h> 00043 #include <kconfig.h> 00044 #include <klocale.h> 00045 00046 #include <qstringlist.h> 00047 #include <qvaluevector.h> 00048 00049 #include <iostream> 00050 #include <iterator> 00051 #include <algorithm> 00052 #include <map> 00053 00054 #include <string.h> 00055 #include <ctype.h> 00056 #include <stdlib.h> 00057 00058 struct Kleo::DN::Private { 00059 Private() : mRefCount( 0 ) {} 00060 Private( const Private & other ) 00061 : attributes( other.attributes ), 00062 reorderedAttributes( other.reorderedAttributes ), 00063 mRefCount( 0 ) 00064 { 00065 00066 } 00067 00068 int ref() { 00069 return ++mRefCount; 00070 } 00071 00072 int unref() { 00073 if ( --mRefCount <= 0 ) { 00074 delete this; 00075 return 0; 00076 } else 00077 return mRefCount; 00078 } 00079 00080 int refCount() const { return mRefCount; } 00081 00082 DN::Attribute::List attributes; 00083 DN::Attribute::List reorderedAttributes; 00084 private: 00085 int mRefCount; 00086 }; 00087 00088 namespace { 00089 struct DnPair { 00090 char * key; 00091 char * value; 00092 }; 00093 } 00094 00095 // copied from CryptPlug and adapted to work on DN::Attribute::List: 00096 00097 #define digitp(p) (*(p) >= '0' && *(p) <= '9') 00098 #define hexdigitp(a) (digitp (a) \ 00099 || (*(a) >= 'A' && *(a) <= 'F') \ 00100 || (*(a) >= 'a' && *(a) <= 'f')) 00101 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ 00102 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) 00103 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) 00104 00105 static char * 00106 trim_trailing_spaces( char *string ) 00107 { 00108 char *p, *mark; 00109 00110 for( mark = NULL, p = string; *p; p++ ) { 00111 if( isspace( *p ) ) { 00112 if( !mark ) 00113 mark = p; 00114 } 00115 else 00116 mark = NULL; 00117 } 00118 if( mark ) 00119 *mark = '\0' ; 00120 00121 return string ; 00122 } 00123 00124 /* Parse a DN and return an array-ized one. This is not a validating 00125 parser and it does not support any old-stylish syntax; gpgme is 00126 expected to return only rfc2253 compatible strings. */ 00127 static const unsigned char * 00128 parse_dn_part (DnPair *array, const unsigned char *string) 00129 { 00130 const unsigned char *s, *s1; 00131 size_t n; 00132 char *p; 00133 00134 /* parse attributeType */ 00135 for (s = string+1; *s && *s != '='; s++) 00136 ; 00137 if (!*s) 00138 return NULL; /* error */ 00139 n = s - string; 00140 if (!n) 00141 return NULL; /* empty key */ 00142 p = (char*)malloc (n+1); 00143 00144 00145 memcpy (p, string, n); 00146 p[n] = 0; 00147 trim_trailing_spaces ((char*)p); 00148 // map OIDs to their names: 00149 for ( unsigned int i = 0 ; i < numOidMaps ; ++i ) 00150 if ( !strcasecmp ((char*)p, oidmap[i].oid) ) { 00151 free( p ); 00152 p = strdup( oidmap[i].name ); 00153 break; 00154 } 00155 array->key = p; 00156 string = s + 1; 00157 00158 if (*string == '#') 00159 { /* hexstring */ 00160 string++; 00161 for (s=string; hexdigitp (s); s++) 00162 s++; 00163 n = s - string; 00164 if (!n || (n & 1)) 00165 return NULL; /* empty or odd number of digits */ 00166 n /= 2; 00167 array->value = p = (char*)malloc (n+1); 00168 00169 00170 for (s1=string; n; s1 += 2, n--) 00171 *p++ = xtoi_2 (s1); 00172 *p = 0; 00173 } 00174 else 00175 { /* regular v3 quoted string */ 00176 for (n=0, s=string; *s; s++) 00177 { 00178 if (*s == '\\') 00179 { /* pair */ 00180 s++; 00181 if (*s == ',' || *s == '=' || *s == '+' 00182 || *s == '<' || *s == '>' || *s == '#' || *s == ';' 00183 || *s == '\\' || *s == '\"' || *s == ' ') 00184 n++; 00185 else if (hexdigitp (s) && hexdigitp (s+1)) 00186 { 00187 s++; 00188 n++; 00189 } 00190 else 00191 return NULL; /* invalid escape sequence */ 00192 } 00193 else if (*s == '\"') 00194 return NULL; /* invalid encoding */ 00195 else if (*s == ',' || *s == '=' || *s == '+' 00196 || *s == '<' || *s == '>' || *s == '#' || *s == ';' ) 00197 break; 00198 else 00199 n++; 00200 } 00201 00202 array->value = p = (char*)malloc (n+1); 00203 00204 00205 for (s=string; n; s++, n--) 00206 { 00207 if (*s == '\\') 00208 { 00209 s++; 00210 if (hexdigitp (s)) 00211 { 00212 *p++ = xtoi_2 (s); 00213 s++; 00214 } 00215 else 00216 *p++ = *s; 00217 } 00218 else 00219 *p++ = *s; 00220 } 00221 *p = 0; 00222 } 00223 return s; 00224 } 00225 00226 00227 /* Parse a DN and return an array-ized one. This is not a validating 00228 parser and it does not support any old-stylish syntax; gpgme is 00229 expected to return only rfc2253 compatible strings. */ 00230 static Kleo::DN::Attribute::List 00231 parse_dn( const unsigned char * string ) { 00232 if ( !string ) 00233 return QValueVector<Kleo::DN::Attribute>(); 00234 00235 QValueVector<Kleo::DN::Attribute> result; 00236 while (*string) 00237 { 00238 while (*string == ' ') 00239 string++; 00240 if (!*string) 00241 break; /* ready */ 00242 00243 DnPair pair = { 0, 0 }; 00244 string = parse_dn_part (&pair, string); 00245 if (!string) 00246 goto failure; 00247 if ( pair.key && pair.value ) 00248 result.push_back( Kleo::DN::Attribute( QString::fromUtf8( pair.key ), 00249 QString::fromUtf8( pair.value ) ) ); 00250 free( pair.key ); 00251 free( pair.value ); 00252 00253 while (*string == ' ') 00254 string++; 00255 if (*string && *string != ',' && *string != ';' && *string != '+') 00256 goto failure; /* invalid delimiter */ 00257 if (*string) 00258 string++; 00259 } 00260 return result; 00261 00262 failure: 00263 return QValueVector<Kleo::DN::Attribute>(); 00264 } 00265 00266 static QValueVector<Kleo::DN::Attribute> 00267 parse_dn( const QString & dn ) { 00268 return parse_dn( (const unsigned char*)dn.utf8().data() ); 00269 } 00270 00271 static QString 00272 serialise( const QValueVector<Kleo::DN::Attribute> & dn ) { 00273 QStringList result; 00274 for ( QValueVector<Kleo::DN::Attribute>::const_iterator it = dn.begin() ; it != dn.end() ; ++it ) 00275 if ( !(*it).name().isEmpty() && !(*it).value().isEmpty() ) 00276 result.push_back( (*it).name().stripWhiteSpace() + '=' + (*it).value().stripWhiteSpace() ); 00277 return result.join( "," ); 00278 } 00279 00280 static Kleo::DN::Attribute::List 00281 reorder_dn( const Kleo::DN::Attribute::List & dn ) { 00282 const QStringList & attrOrder = Kleo::DNAttributeMapper::instance()->attributeOrder(); 00283 00284 Kleo::DN::Attribute::List unknownEntries; 00285 Kleo::DN::Attribute::List result; 00286 unknownEntries.reserve( dn.size() ); 00287 result.reserve( dn.size() ); 00288 00289 // find all unknown entries in their order of appearance 00290 for ( Kleo::DN::const_iterator it = dn.begin(); it != dn.end(); ++it ) 00291 if ( attrOrder.find( (*it).name() ) == attrOrder.end() ) 00292 unknownEntries.push_back( *it ); 00293 00294 // process the known attrs in the desired order 00295 for ( QStringList::const_iterator oit = attrOrder.begin() ; oit != attrOrder.end() ; ++oit ) 00296 if ( *oit == "_X_" ) { 00297 // insert the unknown attrs 00298 std::copy( unknownEntries.begin(), unknownEntries.end(), 00299 std::back_inserter( result ) ); 00300 unknownEntries.clear(); // don't produce dup's 00301 } else { 00302 for ( Kleo::DN::const_iterator dnit = dn.begin() ; dnit != dn.end() ; ++dnit ) 00303 if ( (*dnit).name() == *oit ) 00304 result.push_back( *dnit ); 00305 } 00306 00307 return result; 00308 } 00309 00310 // 00311 // 00312 // class DN 00313 // 00314 // 00315 00316 Kleo::DN::DN() { 00317 d = new Private(); 00318 d->ref(); 00319 } 00320 00321 Kleo::DN::DN( const QString & dn ) { 00322 d = new Private(); 00323 d->ref(); 00324 d->attributes = parse_dn( dn ); 00325 } 00326 00327 Kleo::DN::DN( const char * utf8DN ) { 00328 d = new Private(); 00329 d->ref(); 00330 if ( utf8DN ) 00331 d->attributes = parse_dn( (const unsigned char*)utf8DN ); 00332 } 00333 00334 Kleo::DN::DN( const DN & other ) 00335 : d( other.d ) 00336 { 00337 if ( d ) d->ref(); 00338 } 00339 00340 Kleo::DN::~DN() { 00341 if ( d ) d->unref(); 00342 } 00343 00344 const Kleo::DN & Kleo::DN::operator=( const DN & that ) { 00345 if ( this->d == that.d ) 00346 return *this; 00347 00348 if ( that.d ) 00349 that.d->ref(); 00350 if ( this->d ) 00351 this->d->unref(); 00352 00353 this->d = that.d; 00354 00355 return *this; 00356 } 00357 00358 QString Kleo::DN::prettyDN() const { 00359 if ( !d ) 00360 return QString::null; 00361 if ( d->reorderedAttributes.empty() ) 00362 d->reorderedAttributes = reorder_dn( d->attributes ); 00363 return serialise( d->reorderedAttributes ); 00364 } 00365 00366 QString Kleo::DN::dn() const { 00367 return d ? serialise( d->attributes ) : QString::null ; 00368 } 00369 00370 void Kleo::DN::detach() { 00371 if ( !d ) { 00372 d = new Kleo::DN::Private(); 00373 d->ref(); 00374 } else if ( d->refCount() > 1 ) { 00375 Kleo::DN::Private * d_save = d; 00376 d = new Kleo::DN::Private( *d ); 00377 d->ref(); 00378 d_save->unref(); 00379 } 00380 } 00381 00382 void Kleo::DN::append( const Attribute & attr ) { 00383 detach(); 00384 d->attributes.push_back( attr ); 00385 d->reorderedAttributes.clear(); 00386 } 00387 00388 QString Kleo::DN::operator[]( const QString & attr ) const { 00389 if ( !d ) 00390 return QString::null; 00391 const QString attrUpper = attr.upper(); 00392 for ( QValueVector<Attribute>::const_iterator it = d->attributes.begin() ; 00393 it != d->attributes.end() ; ++it ) 00394 if ( (*it).name() == attrUpper ) 00395 return (*it).value(); 00396 return QString::null; 00397 } 00398 00399 static QValueVector<Kleo::DN::Attribute> empty; 00400 00401 Kleo::DN::const_iterator Kleo::DN::begin() const { 00402 return d ? d->attributes.begin() : empty.begin() ; 00403 } 00404 00405 Kleo::DN::const_iterator Kleo::DN::end() const { 00406 return d ? d->attributes.end() : empty.end() ; 00407 } 00408 00409 00411 00412 namespace { 00413 struct ltstr { 00414 bool operator()( const char * s1, const char * s2 ) const { 00415 return qstrcmp( s1, s2 ) < 0 ; 00416 } 00417 }; 00418 } 00419 00420 static const char * defaultOrder[] = { 00421 "CN", "L", "_X_", "OU", "O", "C" 00422 }; 00423 00424 std::pair<const char*,const char*> attributeLabels[] = { 00425 #define MAKE_PAIR(x,y) std::pair<const char*,const char*>( x, y ) 00426 MAKE_PAIR( "CN", I18N_NOOP("Common name") ), 00427 MAKE_PAIR( "SN", I18N_NOOP("Surname") ), 00428 MAKE_PAIR( "GN", I18N_NOOP("Given name") ), 00429 MAKE_PAIR( "L", I18N_NOOP("Location") ), 00430 MAKE_PAIR( "T", I18N_NOOP("Title") ), 00431 MAKE_PAIR( "OU", I18N_NOOP("Organizational unit") ), 00432 MAKE_PAIR( "O", I18N_NOOP("Organization") ), 00433 MAKE_PAIR( "PC", I18N_NOOP("Postal code") ), 00434 MAKE_PAIR( "C", I18N_NOOP("Country code") ), 00435 MAKE_PAIR( "SP", I18N_NOOP("State or province") ), 00436 MAKE_PAIR( "DC", I18N_NOOP("Domain component") ), 00437 MAKE_PAIR( "BC", I18N_NOOP("Business category") ), 00438 MAKE_PAIR( "EMAIL", I18N_NOOP("Email address") ), 00439 MAKE_PAIR( "MAIL", I18N_NOOP("Mail address") ), 00440 MAKE_PAIR( "MOBILE", I18N_NOOP("Mobile phone number") ), 00441 MAKE_PAIR( "TEL", I18N_NOOP("Telephone number") ), 00442 MAKE_PAIR( "FAX", I18N_NOOP("Fax number") ), 00443 MAKE_PAIR( "STREET", I18N_NOOP("Street address") ), 00444 MAKE_PAIR( "UID", I18N_NOOP("Unique ID") ) 00445 #undef MAKE_PAIR 00446 }; 00447 static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof *attributeLabels ; 00448 00449 class Kleo::DNAttributeMapper::Private { 00450 public: 00451 Private(); 00452 std::map<const char*,const char*,ltstr> map; 00453 QStringList attributeOrder; 00454 }; 00455 00456 Kleo::DNAttributeMapper::Private::Private() 00457 : map( attributeLabels, attributeLabels + numAttributeLabels ) {} 00458 00459 Kleo::DNAttributeMapper::DNAttributeMapper() { 00460 d = new Private(); 00461 const KConfigGroup config( kapp->config(), "DN" ); 00462 d->attributeOrder = config.readListEntry( "AttributeOrder" ); 00463 if ( d->attributeOrder.empty() ) 00464 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder, 00465 std::back_inserter( d->attributeOrder ) ); 00466 mSelf = this; 00467 } 00468 00469 Kleo::DNAttributeMapper::~DNAttributeMapper() { 00470 mSelf = 0; 00471 delete d; d = 0; 00472 } 00473 00474 Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::mSelf = 0; 00475 00476 const Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::instance() { 00477 if ( !mSelf ) 00478 (void)new DNAttributeMapper(); 00479 return mSelf; 00480 } 00481 00482 QString Kleo::DNAttributeMapper::name2label( const QString & s ) const { 00483 const std::map<const char*,const char*,ltstr>::const_iterator it 00484 = d->map.find( s.stripWhiteSpace().upper().latin1() ); 00485 if ( it == d->map.end() ) 00486 return QString::null; 00487 return i18n( it->second ); 00488 } 00489 00490 QStringList Kleo::DNAttributeMapper::names() const { 00491 QStringList result; 00492 for ( std::map<const char*,const char*,ltstr>::const_iterator it = d->map.begin() ; it != d->map.end() ; ++it ) 00493 result.push_back( it->first ); 00494 return result; 00495 } 00496 00497 const QStringList & Kleo::DNAttributeMapper::attributeOrder() const { 00498 return d->attributeOrder; 00499 } 00500 00501 void Kleo::DNAttributeMapper::setAttributeOrder( const QStringList & order ) { 00502 d->attributeOrder = order; 00503 if ( order.empty() ) 00504 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder, 00505 std::back_inserter( d->attributeOrder ) ); 00506 KConfigGroup config( kapp->config(), "DN" ); 00507 config.writeEntry( "AttributeOrder", order ); 00508 } 00509 00510 Kleo::DNAttributeOrderConfigWidget * Kleo::DNAttributeMapper::configWidget( QWidget * parent, const char * name ) const { 00511 return new DNAttributeOrderConfigWidget( mSelf, parent, name ); 00512 }
KDE Logo
This file is part of the documentation for certmanager/lib Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:50:04 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003