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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 TQt library by Trolltech AS, Norway (or with modified versions 00028 of TQt that use the same license as TQt), 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 TQt. 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 <tqstringlist.h> 00047 #include <tqvaluevector.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 TQValueVector<Kleo::DN::Attribute>(); 00234 00235 TQValueVector<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( TQString::fromUtf8( pair.key ), 00249 TQString::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 TQValueVector<Kleo::DN::Attribute>(); 00264 } 00265 00266 static TQValueVector<Kleo::DN::Attribute> 00267 parse_dn( const TQString & dn ) { 00268 return parse_dn( (const unsigned char*)dn.utf8().data() ); 00269 } 00270 00271 static TQString dn_escape( const TQString & s ) { 00272 TQString result; 00273 for ( unsigned int i = 0, end = s.length() ; i != end ; ++i ) { 00274 const TQChar ch = s[i]; 00275 switch ( ch.unicode() ) { 00276 case ',': 00277 case '+': 00278 case '"': 00279 case '\\': 00280 case '<': 00281 case '>': 00282 case ';': 00283 result += '\\'; 00284 // fall through 00285 default: 00286 result += ch; 00287 } 00288 } 00289 return result; 00290 } 00291 00292 static TQString 00293 serialise( const TQValueVector<Kleo::DN::Attribute> & dn ) { 00294 TQStringList result; 00295 for ( TQValueVector<Kleo::DN::Attribute>::const_iterator it = dn.begin() ; it != dn.end() ; ++it ) 00296 if ( !(*it).name().isEmpty() && !(*it).value().isEmpty() ) 00297 result.push_back( (*it).name().stripWhiteSpace() + '=' + dn_escape( (*it).value().stripWhiteSpace() ) ); 00298 return result.join( "," ); 00299 } 00300 00301 static Kleo::DN::Attribute::List 00302 reorder_dn( const Kleo::DN::Attribute::List & dn ) { 00303 const TQStringList & attrOrder = Kleo::DNAttributeMapper::instance()->attributeOrder(); 00304 00305 Kleo::DN::Attribute::List unknownEntries; 00306 Kleo::DN::Attribute::List result; 00307 unknownEntries.reserve( dn.size() ); 00308 result.reserve( dn.size() ); 00309 00310 // find all unknown entries in their order of appearance 00311 for ( Kleo::DN::const_iterator it = dn.begin(); it != dn.end(); ++it ) 00312 if ( attrOrder.find( (*it).name() ) == attrOrder.end() ) 00313 unknownEntries.push_back( *it ); 00314 00315 // process the known attrs in the desired order 00316 for ( TQStringList::const_iterator oit = attrOrder.begin() ; oit != attrOrder.end() ; ++oit ) 00317 if ( *oit == "_X_" ) { 00318 // insert the unknown attrs 00319 std::copy( unknownEntries.begin(), unknownEntries.end(), 00320 std::back_inserter( result ) ); 00321 unknownEntries.clear(); // don't produce dup's 00322 } else { 00323 for ( Kleo::DN::const_iterator dnit = dn.begin() ; dnit != dn.end() ; ++dnit ) 00324 if ( (*dnit).name() == *oit ) 00325 result.push_back( *dnit ); 00326 } 00327 00328 return result; 00329 } 00330 00331 // 00332 // 00333 // class DN 00334 // 00335 // 00336 00337 Kleo::DN::DN() { 00338 d = new Private(); 00339 d->ref(); 00340 } 00341 00342 Kleo::DN::DN( const TQString & dn ) { 00343 d = new Private(); 00344 d->ref(); 00345 d->attributes = parse_dn( dn ); 00346 } 00347 00348 Kleo::DN::DN( const char * utf8DN ) { 00349 d = new Private(); 00350 d->ref(); 00351 if ( utf8DN ) 00352 d->attributes = parse_dn( (const unsigned char*)utf8DN ); 00353 } 00354 00355 Kleo::DN::DN( const DN & other ) 00356 : d( other.d ) 00357 { 00358 if ( d ) d->ref(); 00359 } 00360 00361 Kleo::DN::~DN() { 00362 if ( d ) d->unref(); 00363 } 00364 00365 const Kleo::DN & Kleo::DN::operator=( const DN & that ) { 00366 if ( this->d == that.d ) 00367 return *this; 00368 00369 if ( that.d ) 00370 that.d->ref(); 00371 if ( this->d ) 00372 this->d->unref(); 00373 00374 this->d = that.d; 00375 00376 return *this; 00377 } 00378 00379 TQString Kleo::DN::prettyDN() const { 00380 if ( !d ) 00381 return TQString(); 00382 if ( d->reorderedAttributes.empty() ) 00383 d->reorderedAttributes = reorder_dn( d->attributes ); 00384 return serialise( d->reorderedAttributes ); 00385 } 00386 00387 TQString Kleo::DN::dn() const { 00388 return d ? serialise( d->attributes ) : TQString() ; 00389 } 00390 00391 // static 00392 TQString Kleo::DN::escape( const TQString & value ) { 00393 return dn_escape( value ); 00394 } 00395 00396 void Kleo::DN::detach() { 00397 if ( !d ) { 00398 d = new Kleo::DN::Private(); 00399 d->ref(); 00400 } else if ( d->refCount() > 1 ) { 00401 Kleo::DN::Private * d_save = d; 00402 d = new Kleo::DN::Private( *d ); 00403 d->ref(); 00404 d_save->unref(); 00405 } 00406 } 00407 00408 void Kleo::DN::append( const Attribute & attr ) { 00409 detach(); 00410 d->attributes.push_back( attr ); 00411 d->reorderedAttributes.clear(); 00412 } 00413 00414 TQString Kleo::DN::operator[]( const TQString & attr ) const { 00415 if ( !d ) 00416 return TQString(); 00417 const TQString attrUpper = attr.upper(); 00418 for ( TQValueVector<Attribute>::const_iterator it = d->attributes.begin() ; 00419 it != d->attributes.end() ; ++it ) 00420 if ( (*it).name() == attrUpper ) 00421 return (*it).value(); 00422 return TQString(); 00423 } 00424 00425 static TQValueVector<Kleo::DN::Attribute> empty; 00426 00427 Kleo::DN::const_iterator Kleo::DN::begin() const { 00428 return d ? d->attributes.begin() : empty.begin() ; 00429 } 00430 00431 Kleo::DN::const_iterator Kleo::DN::end() const { 00432 return d ? d->attributes.end() : empty.end() ; 00433 } 00434 00435 00437 00438 namespace { 00439 struct ltstr { 00440 bool operator()( const char * s1, const char * s2 ) const { 00441 return qstrcmp( s1, s2 ) < 0 ; 00442 } 00443 }; 00444 } 00445 00446 static const char * defaultOrder[] = { 00447 "CN", "L", "_X_", "OU", "O", "C" 00448 }; 00449 00450 std::pair<const char*,const char*> attributeLabels[] = { 00451 #define MAKE_PAIR(x,y) std::pair<const char*,const char*>( x, y ) 00452 MAKE_PAIR( "CN", I18N_NOOP("Common name") ), 00453 MAKE_PAIR( "SN", I18N_NOOP("Surname") ), 00454 MAKE_PAIR( "GN", I18N_NOOP("Given name") ), 00455 MAKE_PAIR( "L", I18N_NOOP("Location") ), 00456 MAKE_PAIR( "T", I18N_NOOP("Title") ), 00457 MAKE_PAIR( "OU", I18N_NOOP("Organizational unit") ), 00458 MAKE_PAIR( "O", I18N_NOOP("Organization") ), 00459 MAKE_PAIR( "PC", I18N_NOOP("Postal code") ), 00460 MAKE_PAIR( "C", I18N_NOOP("Country code") ), 00461 MAKE_PAIR( "SP", I18N_NOOP("State or province") ), 00462 MAKE_PAIR( "DC", I18N_NOOP("Domain component") ), 00463 MAKE_PAIR( "BC", I18N_NOOP("Business category") ), 00464 MAKE_PAIR( "EMAIL", I18N_NOOP("Email address") ), 00465 MAKE_PAIR( "MAIL", I18N_NOOP("Mail address") ), 00466 MAKE_PAIR( "MOBILE", I18N_NOOP("Mobile phone number") ), 00467 MAKE_PAIR( "TEL", I18N_NOOP("Telephone number") ), 00468 MAKE_PAIR( "FAX", I18N_NOOP("Fax number") ), 00469 MAKE_PAIR( "STREET", I18N_NOOP("Street address") ), 00470 MAKE_PAIR( "UID", I18N_NOOP("Unique ID") ) 00471 #undef MAKE_PAIR 00472 }; 00473 static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof *attributeLabels ; 00474 00475 class Kleo::DNAttributeMapper::Private { 00476 public: 00477 Private(); 00478 std::map<const char*,const char*,ltstr> map; 00479 TQStringList attributeOrder; 00480 }; 00481 00482 Kleo::DNAttributeMapper::Private::Private() 00483 : map( attributeLabels, attributeLabels + numAttributeLabels ) {} 00484 00485 Kleo::DNAttributeMapper::DNAttributeMapper() { 00486 d = new Private(); 00487 const KConfigGroup config( kapp->config(), "DN" ); 00488 d->attributeOrder = config.readListEntry( "AttributeOrder" ); 00489 if ( d->attributeOrder.empty() ) 00490 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder, 00491 std::back_inserter( d->attributeOrder ) ); 00492 mSelf = this; 00493 } 00494 00495 Kleo::DNAttributeMapper::~DNAttributeMapper() { 00496 mSelf = 0; 00497 delete d; d = 0; 00498 } 00499 00500 Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::mSelf = 0; 00501 00502 const Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::instance() { 00503 if ( !mSelf ) 00504 (void)new DNAttributeMapper(); 00505 return mSelf; 00506 } 00507 00508 TQString Kleo::DNAttributeMapper::name2label( const TQString & s ) const { 00509 const std::map<const char*,const char*,ltstr>::const_iterator it 00510 = d->map.find( s.stripWhiteSpace().upper().latin1() ); 00511 if ( it == d->map.end() ) 00512 return TQString(); 00513 return i18n( it->second ); 00514 } 00515 00516 TQStringList Kleo::DNAttributeMapper::names() const { 00517 TQStringList result; 00518 for ( std::map<const char*,const char*,ltstr>::const_iterator it = d->map.begin() ; it != d->map.end() ; ++it ) 00519 result.push_back( it->first ); 00520 return result; 00521 } 00522 00523 const TQStringList & Kleo::DNAttributeMapper::attributeOrder() const { 00524 return d->attributeOrder; 00525 } 00526 00527 void Kleo::DNAttributeMapper::setAttributeOrder( const TQStringList & order ) { 00528 d->attributeOrder = order; 00529 if ( order.empty() ) 00530 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder, 00531 std::back_inserter( d->attributeOrder ) ); 00532 KConfigGroup config( kapp->config(), "DN" ); 00533 config.writeEntry( "AttributeOrder", order ); 00534 } 00535 00536 Kleo::DNAttributeOrderConfigWidget * Kleo::DNAttributeMapper::configWidget( TQWidget * parent, const char * name ) const { 00537 return new DNAttributeOrderConfigWidget( mSelf, parent, name ); 00538 }