Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F37526745
dn.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
13 KB
Subscribers
None
dn.cpp
View Options
/*
dn.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
DN parsing:
SPDX-FileCopyrightText: 2002 g10 Code GmbH
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include
<config-libkleo.h>
#include
"dn.h"
#include
"libkleo_debug.h"
#include
"oidmap.h"
#include
<KLazyLocalizedString>
#include
<algorithm>
#ifdef _MSC_VER
#include
<string.h>
#define strcasecmp _stricmp
#endif
namespace
{
static
const
QStringList
defaultOrder
=
{
QStringLiteral
(
"CN"
),
QStringLiteral
(
"L"
),
QStringLiteral
(
"_X_"
),
QStringLiteral
(
"OU"
),
QStringLiteral
(
"O"
),
QStringLiteral
(
"C"
),
};
class
DNAttributeOrderStore
{
DNAttributeOrderStore
()
:
mAttributeOrder
{
defaultOrder
}
{
}
public
:
static
DNAttributeOrderStore
*
instance
()
{
static
DNAttributeOrderStore
*
self
=
new
DNAttributeOrderStore
();
return
self
;
}
const
QStringList
&
attributeOrder
()
const
{
return
mAttributeOrder
.
empty
()
?
defaultOrder
:
mAttributeOrder
;
}
void
setAttributeOrder
(
const
QStringList
&
order
)
{
mAttributeOrder
=
order
;
}
private
:
QStringList
mAttributeOrder
;
};
}
class
Kleo
::
DN
::
Private
{
public
:
Private
()
:
mRefCount
(
0
)
{
}
Private
(
const
Private
&
other
)
:
attributes
(
other
.
attributes
)
,
reorderedAttributes
(
other
.
reorderedAttributes
)
,
mRefCount
(
0
)
{
}
int
ref
()
{
return
++
mRefCount
;
}
int
unref
()
{
if
(
--
mRefCount
<=
0
)
{
delete
this
;
return
0
;
}
else
{
return
mRefCount
;
}
}
int
refCount
()
const
{
return
mRefCount
;
}
DN
::
Attribute
::
List
attributes
;
DN
::
Attribute
::
List
reorderedAttributes
;
private
:
int
mRefCount
;
};
namespace
{
struct
DnPair
{
char
*
key
;
char
*
value
;
};
}
// copied from CryptPlug and adapted to work on DN::Attribute::List:
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define hexdigitp(a) (digitp(a) || (*(a) >= 'A' && *(a) <= 'F') || (*(a) >= 'a' && *(a) <= 'f'))
#define xtoi_1(p) (*(p) <= '9' ? (*(p) - '0') : *(p) <= 'F' ? (*(p) - 'A' + 10) : (*(p) - 'a' + 10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p) + 1))
static
char
*
trim_trailing_spaces
(
char
*
string
)
{
char
*
p
;
char
*
mark
;
for
(
mark
=
nullptr
,
p
=
string
;
*
p
;
p
++
)
{
if
(
isspace
(
*
p
))
{
if
(
!
mark
)
{
mark
=
p
;
}
}
else
{
mark
=
nullptr
;
}
}
if
(
mark
)
{
*
mark
=
'\0'
;
}
return
string
;
}
/* Parse a DN and return an array-ized one. This is not a validating
parser and it does not support any old-stylish syntax; gpgme is
expected to return only rfc2253 compatible strings. */
static
const
unsigned
char
*
parse_dn_part
(
DnPair
*
array
,
const
unsigned
char
*
string
)
{
const
unsigned
char
*
s
;
const
unsigned
char
*
s1
;
size_t
n
;
char
*
p
;
/* parse attributeType */
for
(
s
=
string
+
1
;
*
s
&&
*
s
!=
'='
;
s
++
)
{
;
}
if
(
!*
s
)
{
return
nullptr
;
/* error */
}
n
=
s
-
string
;
if
(
!
n
)
{
return
nullptr
;
/* empty key */
}
p
=
(
char
*
)
malloc
(
n
+
1
);
memcpy
(
p
,
string
,
n
);
p
[
n
]
=
0
;
trim_trailing_spaces
((
char
*
)
p
);
// map OIDs to their names:
if
(
const
char
*
name
=
Kleo
::
attributeNameForOID
(
p
))
{
free
(
p
);
p
=
strdup
(
name
);
}
array
->
key
=
p
;
string
=
s
+
1
;
if
(
*
string
==
'#'
)
{
/* hexstring */
string
++
;
for
(
s
=
string
;
hexdigitp
(
s
);
s
++
)
;
n
=
s
-
string
;
if
(
!
n
||
(
n
&
1
))
{
return
nullptr
;
/* empty or odd number of digits */
}
n
/=
2
;
array
->
value
=
p
=
(
char
*
)
malloc
(
n
+
1
);
for
(
s1
=
string
;
n
;
s1
+=
2
,
n
--
)
{
*
p
++
=
xtoi_2
(
s1
);
}
*
p
=
0
;
}
else
{
/* regular v3 quoted string */
for
(
n
=
0
,
s
=
string
;
*
s
;
s
++
)
{
if
(
*
s
==
'\\'
)
{
/* pair */
s
++
;
if
(
*
s
==
','
||
*
s
==
'='
||
*
s
==
'+'
||
*
s
==
'<'
||
*
s
==
'>'
||
*
s
==
'#'
||
*
s
==
';'
||
*
s
==
'\\'
||
*
s
==
'\"'
||
*
s
==
' '
)
{
n
++
;
}
else
if
(
hexdigitp
(
s
)
&&
hexdigitp
(
s
+
1
))
{
s
++
;
n
++
;
}
else
{
return
nullptr
;
/* invalid escape sequence */
}
}
else
if
(
*
s
==
'\"'
)
{
return
nullptr
;
/* invalid encoding */
}
else
if
(
*
s
==
','
||
*
s
==
'='
||
*
s
==
'+'
||
*
s
==
'<'
||
*
s
==
'>'
||
*
s
==
'#'
||
*
s
==
';'
)
{
break
;
}
else
{
n
++
;
}
}
array
->
value
=
p
=
(
char
*
)
malloc
(
n
+
1
);
for
(
s
=
string
;
n
;
s
++
,
n
--
)
{
if
(
*
s
==
'\\'
)
{
s
++
;
if
(
hexdigitp
(
s
))
{
*
p
++
=
xtoi_2
(
s
);
s
++
;
}
else
{
*
p
++
=
*
s
;
}
}
else
{
*
p
++
=
*
s
;
}
}
*
p
=
0
;
}
return
s
;
}
/* Parse a DN and return an array-ized one. This is not a validating
parser and it does not support any old-stylish syntax; gpgme is
expected to return only rfc2253 compatible strings. */
static
Kleo
::
DN
::
Attribute
::
List
parse_dn
(
const
unsigned
char
*
string
)
{
if
(
!
string
)
{
return
QList
<
Kleo
::
DN
::
Attribute
>
();
}
QList
<
Kleo
::
DN
::
Attribute
>
result
;
while
(
*
string
)
{
while
(
*
string
==
' '
)
{
string
++
;
}
if
(
!*
string
)
{
break
;
/* ready */
}
DnPair
pair
=
{
nullptr
,
nullptr
};
string
=
parse_dn_part
(
&
pair
,
string
);
if
(
!
string
)
{
goto
failure
;
}
if
(
pair
.
key
&&
pair
.
value
)
{
result
.
push_back
(
Kleo
::
DN
::
Attribute
(
QString
::
fromUtf8
(
pair
.
key
),
QString
::
fromUtf8
(
pair
.
value
)));
}
free
(
pair
.
key
);
free
(
pair
.
value
);
while
(
*
string
==
' '
)
{
string
++
;
}
if
(
*
string
&&
*
string
!=
','
&&
*
string
!=
';'
&&
*
string
!=
'+'
)
{
goto
failure
;
/* invalid delimiter */
}
if
(
*
string
)
{
string
++
;
}
}
return
result
;
failure
:
return
QList
<
Kleo
::
DN
::
Attribute
>
();
}
static
QList
<
Kleo
::
DN
::
Attribute
>
parse_dn
(
const
QString
&
dn
)
{
return
parse_dn
((
const
unsigned
char
*
)
dn
.
toUtf8
().
data
());
}
static
QString
dn_escape
(
const
QString
&
s
)
{
QString
result
;
for
(
int
i
=
0
,
end
=
s
.
length
();
i
!=
end
;
++
i
)
{
const
QChar
ch
=
s
[
i
];
switch
(
ch
.
unicode
())
{
case
','
:
case
'+'
:
case
'"'
:
case
'\\'
:
case
'<'
:
case
'>'
:
case
';'
:
result
+=
QLatin1Char
(
'\\'
);
// fall through
[[
fallthrough
]];
default
:
result
+=
ch
;
}
}
return
result
;
}
static
QString
serialise
(
const
QList
<
Kleo
::
DN
::
Attribute
>
&
dn
,
const
QString
&
sep
)
{
QStringList
result
;
for
(
QList
<
Kleo
::
DN
::
Attribute
>::
const_iterator
it
=
dn
.
begin
();
it
!=
dn
.
end
();
++
it
)
{
if
(
!
(
*
it
).
name
().
isEmpty
()
&&
!
(
*
it
).
value
().
isEmpty
())
{
result
.
push_back
((
*
it
).
name
().
trimmed
()
+
QLatin1Char
(
'='
)
+
dn_escape
((
*
it
).
value
().
trimmed
()));
}
}
return
result
.
join
(
sep
);
}
static
Kleo
::
DN
::
Attribute
::
List
reorder_dn
(
const
Kleo
::
DN
::
Attribute
::
List
&
dn
)
{
const
QStringList
&
attrOrder
=
Kleo
::
DN
::
attributeOrder
();
Kleo
::
DN
::
Attribute
::
List
unknownEntries
;
Kleo
::
DN
::
Attribute
::
List
result
;
unknownEntries
.
reserve
(
dn
.
size
());
result
.
reserve
(
dn
.
size
());
// find all unknown entries in their order of appearance
for
(
Kleo
::
DN
::
const_iterator
it
=
dn
.
begin
();
it
!=
dn
.
end
();
++
it
)
{
if
(
!
attrOrder
.
contains
((
*
it
).
name
()))
{
unknownEntries
.
push_back
(
*
it
);
}
}
// process the known attrs in the desired order
for
(
QStringList
::
const_iterator
oit
=
attrOrder
.
begin
();
oit
!=
attrOrder
.
end
();
++
oit
)
{
if
(
*
oit
==
QLatin1StringView
(
"_X_"
))
{
// insert the unknown attrs
std
::
copy
(
unknownEntries
.
begin
(),
unknownEntries
.
end
(),
std
::
back_inserter
(
result
));
unknownEntries
.
clear
();
// don't produce dup's
}
else
{
for
(
Kleo
::
DN
::
const_iterator
dnit
=
dn
.
begin
();
dnit
!=
dn
.
end
();
++
dnit
)
{
if
((
*
dnit
).
name
()
==
*
oit
)
{
result
.
push_back
(
*
dnit
);
}
}
}
}
return
result
;
}
//
//
// class DN
//
//
Kleo
::
DN
::
DN
()
{
d
=
new
Private
();
d
->
ref
();
}
Kleo
::
DN
::
DN
(
const
QString
&
dn
)
{
d
=
new
Private
();
d
->
ref
();
d
->
attributes
=
parse_dn
(
dn
);
}
Kleo
::
DN
::
DN
(
const
char
*
utf8DN
)
{
d
=
new
Private
();
d
->
ref
();
if
(
utf8DN
)
{
d
->
attributes
=
parse_dn
((
const
unsigned
char
*
)
utf8DN
);
}
}
Kleo
::
DN
::
DN
(
const
DN
&
other
)
:
d
(
other
.
d
)
{
if
(
d
)
{
d
->
ref
();
}
}
Kleo
::
DN
::~
DN
()
{
if
(
d
)
{
d
->
unref
();
}
}
const
Kleo
::
DN
&
Kleo
::
DN
::
operator
=
(
const
DN
&
that
)
{
if
(
this
->
d
==
that
.
d
)
{
return
*
this
;
}
if
(
that
.
d
)
{
that
.
d
->
ref
();
}
if
(
this
->
d
)
{
this
->
d
->
unref
();
}
this
->
d
=
that
.
d
;
return
*
this
;
}
// static
QStringList
Kleo
::
DN
::
attributeOrder
()
{
return
DNAttributeOrderStore
::
instance
()
->
attributeOrder
();
}
// static
void
Kleo
::
DN
::
setAttributeOrder
(
const
QStringList
&
order
)
{
DNAttributeOrderStore
::
instance
()
->
setAttributeOrder
(
order
);
}
// static
QStringList
Kleo
::
DN
::
defaultAttributeOrder
()
{
return
defaultOrder
;
}
QString
Kleo
::
DN
::
prettyDN
()
const
{
if
(
!
d
)
{
return
QString
();
}
if
(
d
->
reorderedAttributes
.
empty
())
{
d
->
reorderedAttributes
=
reorder_dn
(
d
->
attributes
);
}
return
serialise
(
d
->
reorderedAttributes
,
QStringLiteral
(
","
));
}
QString
Kleo
::
DN
::
dn
()
const
{
return
d
?
serialise
(
d
->
attributes
,
QStringLiteral
(
","
))
:
QString
();
}
QString
Kleo
::
DN
::
dn
(
const
QString
&
sep
)
const
{
return
d
?
serialise
(
d
->
attributes
,
sep
)
:
QString
();
}
// static
QString
Kleo
::
DN
::
escape
(
const
QString
&
value
)
{
return
dn_escape
(
value
);
}
void
Kleo
::
DN
::
detach
()
{
if
(
!
d
)
{
d
=
new
Kleo
::
DN
::
Private
();
d
->
ref
();
}
else
if
(
d
->
refCount
()
>
1
)
{
Kleo
::
DN
::
Private
*
d_save
=
d
;
d
=
new
Kleo
::
DN
::
Private
(
*
d
);
d
->
ref
();
d_save
->
unref
();
}
}
void
Kleo
::
DN
::
append
(
const
Attribute
&
attr
)
{
detach
();
d
->
attributes
.
push_back
(
attr
);
d
->
reorderedAttributes
.
clear
();
}
QString
Kleo
::
DN
::
operator
[](
const
QString
&
attr
)
const
{
if
(
!
d
)
{
return
QString
();
}
const
QString
attrUpper
=
attr
.
toUpper
();
for
(
QList
<
Attribute
>::
const_iterator
it
=
d
->
attributes
.
constBegin
();
it
!=
d
->
attributes
.
constEnd
();
++
it
)
{
if
((
*
it
).
name
()
==
attrUpper
)
{
return
(
*
it
).
value
();
}
}
return
QString
();
}
static
QList
<
Kleo
::
DN
::
Attribute
>
empty
;
Kleo
::
DN
::
const_iterator
Kleo
::
DN
::
begin
()
const
{
return
d
?
d
->
attributes
.
constBegin
()
:
empty
.
constBegin
();
}
Kleo
::
DN
::
const_iterator
Kleo
::
DN
::
end
()
const
{
return
d
?
d
->
attributes
.
constEnd
()
:
empty
.
constEnd
();
}
/////////////////////
namespace
{
static
const
QMap
<
QString
,
KLazyLocalizedString
>
attributeNamesAndLabels
=
{
// clang-format off
{
QStringLiteral
(
"CN"
),
kli18n
(
"Common name"
)
},
{
QStringLiteral
(
"SN"
),
kli18n
(
"Surname"
)
},
{
QStringLiteral
(
"GN"
),
kli18n
(
"Given name"
)
},
{
QStringLiteral
(
"L"
),
kli18n
(
"Location"
)
},
{
QStringLiteral
(
"T"
),
kli18n
(
"Title"
)
},
{
QStringLiteral
(
"OU"
),
kli18n
(
"Organizational unit"
)},
{
QStringLiteral
(
"O"
),
kli18n
(
"Organization"
)
},
{
QStringLiteral
(
"PC"
),
kli18n
(
"Postal code"
)
},
{
QStringLiteral
(
"C"
),
kli18n
(
"Country code"
)
},
{
QStringLiteral
(
"SP"
),
kli18n
(
"State or province"
)
},
{
QStringLiteral
(
"DC"
),
kli18n
(
"Domain component"
)
},
{
QStringLiteral
(
"BC"
),
kli18n
(
"Business category"
)
},
{
QStringLiteral
(
"EMAIL"
),
kli18n
(
"Email address"
)
},
{
QStringLiteral
(
"MAIL"
),
kli18n
(
"Mail address"
)
},
{
QStringLiteral
(
"MOBILE"
),
kli18n
(
"Mobile phone number"
)},
{
QStringLiteral
(
"TEL"
),
kli18n
(
"Telephone number"
)
},
{
QStringLiteral
(
"FAX"
),
kli18n
(
"Fax number"
)
},
{
QStringLiteral
(
"STREET"
),
kli18n
(
"Street address"
)
},
{
QStringLiteral
(
"UID"
),
kli18n
(
"Unique ID"
)
},
// clang-format on
};
}
// static
QStringList
Kleo
::
DN
::
attributeNames
()
{
return
attributeNamesAndLabels
.
keys
();
}
// static
QString
Kleo
::
DN
::
attributeNameToLabel
(
const
QString
&
name
)
{
const
QString
key
{
name
.
trimmed
().
toUpper
()};
if
(
attributeNames
().
contains
(
key
))
{
return
attributeNamesAndLabels
.
value
(
key
).
toString
();
}
qCWarning
(
LIBKLEO_LOG
)
<<
"Attribute "
<<
key
<<
" doesn't exit. Bug ?"
;
return
{};
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Fri, Mar 13, 8:34 AM (1 d, 16 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
0a/89/cd312fae8ad10d2f16d4caf370c1
Attached To
rLIBKLEO Libkleo
Event Timeline
Log In to Comment