Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34572591
gpgkeys_ldap.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
51 KB
Subscribers
None
gpgkeys_ldap.c
View Options
/* gpgkeys_ldap.c - talk to a LDAP keyserver
* Copyright (C) 2001, 2002, 2004, 2005, 2006
* 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the Free Software Foundation
* gives permission to link the code of the keyserver helper tools:
* gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License
* in all respects for all of the code used other than "OpenSSL". If
* you modify this file, you may extend this exception to your version
* of the file, but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version.
*/
#include
<config.h>
#include
<stdio.h>
#include
<string.h>
#include
<time.h>
#include
<unistd.h>
#ifdef HAVE_GETOPT_H
#include
<getopt.h>
#endif
#include
<stdlib.h>
#include
<errno.h>
#include
<assert.h>
#ifdef _WIN32
#include
<winsock2.h>
#include
<winldap.h>
#else
#ifdef NEED_LBER_H
#include
<lber.h>
#endif
/* For OpenLDAP, to enable the API that we're using. */
#define LDAP_DEPRECATED 1
#include
<ldap.h>
#endif
#include
"util.h"
#include
"keyserver.h"
#include
"ksutil.h"
#ifdef __riscos__
#include
"util.h"
#endif
extern
char
*
optarg
;
extern
int
optind
;
static
int
real_ldap
=
0
;
static
char
*
basekeyspacedn
=
NULL
;
static
char
*
pgpkeystr
=
"pgpKey"
;
static
FILE
*
input
=
NULL
,
*
output
=
NULL
,
*
console
=
NULL
;
static
LDAP
*
ldap
=
NULL
;
static
struct
ks_options
*
opt
;
#ifndef HAVE_TIMEGM
time_t
timegm
(
struct
tm
*
tm
);
#endif
static
int
ldap_err_to_gpg_err
(
int
err
)
{
int
ret
;
switch
(
err
)
{
case
LDAP_ALREADY_EXISTS
:
ret
=
KEYSERVER_KEY_EXISTS
;
break
;
case
LDAP_SERVER_DOWN
:
ret
=
KEYSERVER_UNREACHABLE
;
break
;
default
:
ret
=
KEYSERVER_GENERAL_ERROR
;
break
;
}
return
ret
;
}
static
int
ldap_to_gpg_err
(
LDAP
*
ld
)
{
#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
int
err
;
if
(
ldap_get_option
(
ld
,
LDAP_OPT_ERROR_NUMBER
,
&
err
)
==
0
)
return
ldap_err_to_gpg_err
(
err
);
else
return
KEYSERVER_GENERAL_ERROR
;
#elif defined(HAVE_LDAP_LD_ERRNO)
return
ldap_err_to_gpg_err
(
ld
->
ld_errno
);
#else
/* We should never get here since the LDAP library should always
have either ldap_get_option or ld_errno, but just in case... */
return
KEYSERVER_GENERAL_ERROR
;
#endif
}
static
int
key_in_keylist
(
const
char
*
key
,
struct
keylist
*
list
)
{
struct
keylist
*
keyptr
=
list
;
while
(
keyptr
!=
NULL
)
{
if
(
strcasecmp
(
key
,
keyptr
->
str
)
==
0
)
return
1
;
keyptr
=
keyptr
->
next
;
}
return
0
;
}
static
int
add_key_to_keylist
(
const
char
*
key
,
struct
keylist
**
list
)
{
struct
keylist
*
keyptr
=
malloc
(
sizeof
(
struct
keylist
));
if
(
keyptr
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: out of memory when deduping "
"key list
\n
"
);
return
KEYSERVER_NO_MEMORY
;
}
strncpy
(
keyptr
->
str
,
key
,
MAX_LINE
);
keyptr
->
str
[
MAX_LINE
-1
]
=
'\0'
;
keyptr
->
next
=*
list
;
*
list
=
keyptr
;
return
0
;
}
static
void
free_keylist
(
struct
keylist
*
list
)
{
while
(
list
!=
NULL
)
{
struct
keylist
*
keyptr
=
list
;
list
=
keyptr
->
next
;
free
(
keyptr
);
}
}
static
time_t
ldap2epochtime
(
const
char
*
timestr
)
{
struct
tm
pgptime
;
time_t
answer
;
memset
(
&
pgptime
,
0
,
sizeof
(
pgptime
));
/* YYYYMMDDHHmmssZ */
sscanf
(
timestr
,
"%4d%2d%2d%2d%2d%2d"
,
&
pgptime
.
tm_year
,
&
pgptime
.
tm_mon
,
&
pgptime
.
tm_mday
,
&
pgptime
.
tm_hour
,
&
pgptime
.
tm_min
,
&
pgptime
.
tm_sec
);
pgptime
.
tm_year
-=
1900
;
pgptime
.
tm_isdst
=
-1
;
pgptime
.
tm_mon
--
;
/* mktime() takes the timezone into account, so we use timegm() */
answer
=
timegm
(
&
pgptime
);
return
answer
;
}
/* Caller must free */
static
char
*
epoch2ldaptime
(
time_t
stamp
)
{
struct
tm
*
ldaptime
;
char
buf
[
16
];
ldaptime
=
gmtime
(
&
stamp
);
ldaptime
->
tm_year
+=
1900
;
ldaptime
->
tm_mon
++
;
/* YYYYMMDDHHmmssZ */
sprintf
(
buf
,
"%04d%02d%02d%02d%02d%02dZ"
,
ldaptime
->
tm_year
,
ldaptime
->
tm_mon
,
ldaptime
->
tm_mday
,
ldaptime
->
tm_hour
,
ldaptime
->
tm_min
,
ldaptime
->
tm_sec
);
return
strdup
(
buf
);
}
/* Append two onto the end of one. Two is not freed, but its pointers
are now part of one. Make sure you don't free them both! */
static
int
join_two_modlists
(
LDAPMod
***
one
,
LDAPMod
**
two
)
{
int
i
,
one_count
=
0
,
two_count
=
0
;
LDAPMod
**
grow
;
for
(
grow
=*
one
;
*
grow
;
grow
++
)
one_count
++
;
for
(
grow
=
two
;
*
grow
;
grow
++
)
two_count
++
;
grow
=
realloc
(
*
one
,
sizeof
(
LDAPMod
*
)
*
(
one_count
+
two_count
+
1
));
if
(
!
grow
)
return
0
;
for
(
i
=
0
;
i
<
two_count
;
i
++
)
grow
[
one_count
+
i
]
=
two
[
i
];
grow
[
one_count
+
i
]
=
NULL
;
*
one
=
grow
;
return
1
;
}
/* Passing a NULL for value effectively deletes that attribute. This
doesn't mean "delete" in the sense of removing something from the
modlist, but "delete" in the LDAP sense of adding a modlist item
that specifies LDAP_MOD_REPLACE and a null attribute for the given
attribute. LDAP_MOD_DELETE doesn't work here as we don't know if
the attribute in question exists or not. */
static
int
make_one_attr
(
LDAPMod
***
modlist
,
char
*
attr
,
const
char
*
value
)
{
LDAPMod
**
m
;
int
nummods
=
0
;
/* Search modlist for the attribute we're playing with. */
for
(
m
=*
modlist
;
*
m
;
m
++
)
{
if
(
strcasecmp
((
*
m
)
->
mod_type
,
attr
)
==
0
)
{
char
**
ptr
=
(
*
m
)
->
mod_values
;
int
numvalues
=
0
;
/* We have this attribute already, so when the REPLACE
happens, the server attributes will be replaced
anyway. */
if
(
!
value
)
return
1
;
if
(
ptr
)
for
(
ptr
=
(
*
m
)
->
mod_values
;
*
ptr
;
ptr
++
)
{
/* Duplicate value */
if
(
strcmp
(
*
ptr
,
value
)
==
0
)
return
1
;
numvalues
++
;
}
ptr
=
realloc
((
*
m
)
->
mod_values
,
sizeof
(
char
*
)
*
(
numvalues
+
2
));
if
(
!
ptr
)
return
0
;
(
*
m
)
->
mod_values
=
ptr
;
ptr
[
numvalues
]
=
strdup
(
value
);
if
(
!
ptr
[
numvalues
])
return
0
;
ptr
[
numvalues
+
1
]
=
NULL
;
break
;
}
nummods
++
;
}
/* We didn't find the attr, so make one and add it to the end */
if
(
!*
m
)
{
LDAPMod
**
grow
;
grow
=
realloc
(
*
modlist
,
sizeof
(
LDAPMod
*
)
*
(
nummods
+
2
));
if
(
!
grow
)
return
0
;
*
modlist
=
grow
;
grow
[
nummods
]
=
malloc
(
sizeof
(
LDAPMod
));
if
(
!
grow
[
nummods
])
return
0
;
grow
[
nummods
]
->
mod_op
=
LDAP_MOD_REPLACE
;
grow
[
nummods
]
->
mod_type
=
attr
;
if
(
value
)
{
grow
[
nummods
]
->
mod_values
=
malloc
(
sizeof
(
char
*
)
*
2
);
if
(
!
grow
[
nummods
]
->
mod_values
)
{
grow
[
nummods
]
=
NULL
;
return
0
;
}
/* Is this the right thing? Can a UTF8-encoded user ID have
embedded nulls? */
grow
[
nummods
]
->
mod_values
[
0
]
=
strdup
(
value
);
if
(
!
grow
[
nummods
]
->
mod_values
[
0
])
{
free
(
grow
[
nummods
]
->
mod_values
);
grow
[
nummods
]
=
NULL
;
return
0
;
}
grow
[
nummods
]
->
mod_values
[
1
]
=
NULL
;
}
else
grow
[
nummods
]
->
mod_values
=
NULL
;
grow
[
nummods
+
1
]
=
NULL
;
}
return
1
;
}
static
void
build_attrs
(
LDAPMod
***
modlist
,
char
*
line
)
{
char
*
record
;
int
i
;
/* Remove trailing whitespace */
for
(
i
=
strlen
(
line
);
i
>
0
;
i
--
)
if
(
ascii_isspace
(
line
[
i
-1
]))
line
[
i
-1
]
=
'\0'
;
else
break
;
if
((
record
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
ks_strcasecmp
(
"pub"
,
record
)
==
0
)
{
char
*
tok
;
int
disabled
=
0
,
revoked
=
0
;
/* The long keyid */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
strlen
(
tok
)
==
16
)
{
make_one_attr
(
modlist
,
"pgpCertID"
,
tok
);
make_one_attr
(
modlist
,
"pgpKeyID"
,
&
tok
[
8
]);
}
else
return
;
/* The primary pubkey algo */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
switch
(
atoi
(
tok
))
{
case
1
:
make_one_attr
(
modlist
,
"pgpKeyType"
,
"RSA"
);
break
;
case
17
:
make_one_attr
(
modlist
,
"pgpKeyType"
,
"DSS/DH"
);
break
;
}
/* Size of primary key */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
atoi
(
tok
)
>
0
)
{
char
padded
[
6
];
int
val
=
atoi
(
tok
);
/* We zero pad this on the left to make PGP happy. */
if
(
val
<
99999
&&
val
>
0
)
{
sprintf
(
padded
,
"%05u"
,
atoi
(
tok
));
make_one_attr
(
modlist
,
"pgpKeySize"
,
padded
);
}
}
/* pk timestamp */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
atoi
(
tok
)
>
0
)
{
char
*
stamp
=
epoch2ldaptime
(
atoi
(
tok
));
if
(
stamp
)
{
make_one_attr
(
modlist
,
"pgpKeyCreateTime"
,
stamp
);
free
(
stamp
);
}
}
/* pk expire */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
atoi
(
tok
)
>
0
)
{
char
*
stamp
=
epoch2ldaptime
(
atoi
(
tok
));
if
(
stamp
)
{
make_one_attr
(
modlist
,
"pgpKeyExpireTime"
,
stamp
);
free
(
stamp
);
}
}
/* flags */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
while
(
*
tok
)
switch
(
*
tok
++
)
{
case
'r'
:
case
'R'
:
revoked
=
1
;
break
;
case
'd'
:
case
'D'
:
disabled
=
1
;
break
;
}
/*
Note that we always create the pgpDisabled and pgpRevoked
attributes, regardless of whether the key is disabled/revoked
or not. This is because a very common search is like
"(&(pgpUserID=*isabella*)(pgpDisabled=0))"
*/
make_one_attr
(
modlist
,
"pgpDisabled"
,
disabled
?
"1"
:
"0"
);
make_one_attr
(
modlist
,
"pgpRevoked"
,
revoked
?
"1"
:
"0"
);
}
else
if
(
ks_strcasecmp
(
"sub"
,
record
)
==
0
)
{
char
*
tok
;
/* The long keyid */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
strlen
(
tok
)
==
16
)
make_one_attr
(
modlist
,
"pgpSubKeyID"
,
tok
);
else
return
;
/* The subkey algo */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
/* Size of subkey */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
atoi
(
tok
)
>
0
)
{
char
padded
[
6
];
int
val
=
atoi
(
tok
);
/* We zero pad this on the left to make PGP happy. */
if
(
val
<
99999
&&
val
>
0
)
{
sprintf
(
padded
,
"%05u"
,
atoi
(
tok
));
make_one_attr
(
modlist
,
"pgpKeySize"
,
padded
);
}
}
/* Ignore the rest of the items for subkeys since the LDAP
schema doesn't store them. */
}
else
if
(
ks_strcasecmp
(
"uid"
,
record
)
==
0
)
{
char
*
userid
,
*
tok
;
/* The user ID string */
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
strlen
(
tok
)
==
0
)
return
;
userid
=
tok
;
/* By definition, de-%-encoding is always smaller than the
original string so we can decode in place. */
i
=
0
;
while
(
*
tok
)
if
(
tok
[
0
]
==
'%'
&&
tok
[
1
]
&&
tok
[
2
])
{
int
c
;
userid
[
i
]
=
(
c
=
hextobyte
(
&
tok
[
1
]))
==
-1
?
'?'
:
c
;
i
++
;
tok
+=
3
;
}
else
userid
[
i
++
]
=*
tok
++
;
userid
[
i
]
=
'\0'
;
/* We don't care about the other info provided in the uid: line
since the LDAP schema doesn't need it. */
make_one_attr
(
modlist
,
"pgpUserID"
,
userid
);
}
else
if
(
ks_strcasecmp
(
"sig"
,
record
)
==
0
)
{
char
*
tok
;
if
((
tok
=
strsep
(
&
line
,
":"
))
==
NULL
)
return
;
if
(
strlen
(
tok
)
==
16
)
make_one_attr
(
modlist
,
"pgpSignerID"
,
tok
);
}
}
static
void
free_mod_values
(
LDAPMod
*
mod
)
{
char
**
ptr
;
if
(
!
mod
->
mod_values
)
return
;
for
(
ptr
=
mod
->
mod_values
;
*
ptr
;
ptr
++
)
free
(
*
ptr
);
free
(
mod
->
mod_values
);
}
static
int
send_key
(
int
*
r_eof
)
{
int
err
,
begin
=
0
,
end
=
0
,
keysize
=
1
,
ret
=
KEYSERVER_INTERNAL_ERROR
;
char
*
dn
=
NULL
,
line
[
MAX_LINE
],
*
key
=
NULL
;
char
keyid
[
17
],
state
[
6
];
LDAPMod
**
modlist
,
**
addlist
,
**
ml
;
modlist
=
malloc
(
sizeof
(
LDAPMod
*
));
if
(
!
modlist
)
{
fprintf
(
console
,
"gpgkeys: can't allocate memory for keyserver record
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
*
modlist
=
NULL
;
addlist
=
malloc
(
sizeof
(
LDAPMod
*
));
if
(
!
addlist
)
{
fprintf
(
console
,
"gpgkeys: can't allocate memory for keyserver record
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
*
addlist
=
NULL
;
/* Start by nulling out all attributes. We try and do a modify
operation first, so this ensures that we don't leave old
attributes lying around. */
make_one_attr
(
&
modlist
,
"pgpDisabled"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpKeyID"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpKeyType"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpUserID"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpKeyCreateTime"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpSignerID"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpRevoked"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpSubKeyID"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpKeySize"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpKeyExpireTime"
,
NULL
);
make_one_attr
(
&
modlist
,
"pgpCertID"
,
NULL
);
/* Assemble the INFO stuff into LDAP attributes */
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
)
if
(
sscanf
(
line
,
"INFO%*[ ]%16s%*[ ]%5s
\n
"
,
keyid
,
state
)
==
2
&&
strcmp
(
state
,
"BEGIN"
)
==
0
)
{
begin
=
1
;
break
;
}
if
(
!
begin
)
{
/* i.e. eof before the INFO BEGIN was found. This isn't an
error. */
*
r_eof
=
1
;
ret
=
KEYSERVER_OK
;
goto
fail
;
}
if
(
strlen
(
keyid
)
!=
16
)
{
*
r_eof
=
1
;
ret
=
KEYSERVER_KEY_INCOMPLETE
;
goto
fail
;
}
dn
=
malloc
(
strlen
(
"pgpCertID="
)
+
16
+
1
+
strlen
(
basekeyspacedn
)
+
1
);
if
(
dn
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: can't allocate memory for keyserver record
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
sprintf
(
dn
,
"pgpCertID=%s,%s"
,
keyid
,
basekeyspacedn
);
key
=
malloc
(
1
);
if
(
!
key
)
{
fprintf
(
console
,
"gpgkeys: unable to allocate memory for key
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
key
[
0
]
=
'\0'
;
/* Now parse each line until we see the END */
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
)
if
(
sscanf
(
line
,
"INFO%*[ ]%16s%*[ ]%3s
\n
"
,
keyid
,
state
)
==
2
&&
strcmp
(
state
,
"END"
)
==
0
)
{
end
=
1
;
break
;
}
else
build_attrs
(
&
addlist
,
line
);
if
(
!
end
)
{
fprintf
(
console
,
"gpgkeys: no INFO %s END found
\n
"
,
keyid
);
*
r_eof
=
1
;
ret
=
KEYSERVER_KEY_INCOMPLETE
;
goto
fail
;
}
begin
=
end
=
0
;
/* Read and throw away stdin until we see the BEGIN */
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
)
if
(
sscanf
(
line
,
"KEY%*[ ]%16s%*[ ]%5s
\n
"
,
keyid
,
state
)
==
2
&&
strcmp
(
state
,
"BEGIN"
)
==
0
)
{
begin
=
1
;
break
;
}
if
(
!
begin
)
{
/* i.e. eof before the KEY BEGIN was found. This isn't an
error. */
*
r_eof
=
1
;
ret
=
KEYSERVER_OK
;
goto
fail
;
}
/* Now slurp up everything until we see the END */
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
)
if
(
sscanf
(
line
,
"KEY%*[ ]%16s%*[ ]%3s
\n
"
,
keyid
,
state
)
==
2
&&
strcmp
(
state
,
"END"
)
==
0
)
{
end
=
1
;
break
;
}
else
{
char
*
tempkey
;
keysize
+=
strlen
(
line
);
tempkey
=
realloc
(
key
,
keysize
);
if
(
tempkey
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: unable to reallocate for key
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
else
key
=
tempkey
;
strcat
(
key
,
line
);
}
if
(
!
end
)
{
fprintf
(
console
,
"gpgkeys: no KEY %s END found
\n
"
,
keyid
);
*
r_eof
=
1
;
ret
=
KEYSERVER_KEY_INCOMPLETE
;
goto
fail
;
}
make_one_attr
(
&
addlist
,
"objectClass"
,
"pgpKeyInfo"
);
make_one_attr
(
&
addlist
,
"pgpKey"
,
key
);
/* Now append addlist onto modlist */
if
(
!
join_two_modlists
(
&
modlist
,
addlist
))
{
fprintf
(
console
,
"gpgkeys: unable to merge LDAP modification lists
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
/* Going on the assumption that modify operations are more frequent
than adds, we try a modify first. If it's not there, we just
turn around and send an add command for the same key. Otherwise,
the modify brings the server copy into compliance with our copy.
Note that unlike the LDAP keyserver (and really, any other
keyserver) this does NOT merge signatures, but replaces the whole
key. This should make some people very happy. */
err
=
ldap_modify_s
(
ldap
,
dn
,
modlist
);
if
(
err
==
LDAP_NO_SUCH_OBJECT
)
err
=
ldap_add_s
(
ldap
,
dn
,
addlist
);
if
(
err
!=
LDAP_SUCCESS
)
{
fprintf
(
console
,
"gpgkeys: error adding key %s to keyserver: %s
\n
"
,
keyid
,
ldap_err2string
(
err
));
ret
=
ldap_err_to_gpg_err
(
err
);
goto
fail
;
}
ret
=
KEYSERVER_OK
;
fail
:
if
(
modlist
)
{
/* Unwind and free the whole modlist structure */
for
(
ml
=
modlist
;
*
ml
;
ml
++
)
{
free_mod_values
(
*
ml
);
free
(
*
ml
);
}
free
(
modlist
);
}
free
(
addlist
);
free
(
dn
);
free
(
key
);
if
(
ret
!=
0
&&
begin
)
fprintf
(
output
,
"KEY %s FAILED %d
\n
"
,
keyid
,
ret
);
return
ret
;
}
static
int
send_key_keyserver
(
int
*
r_eof
)
{
int
err
,
begin
=
0
,
end
=
0
,
keysize
=
1
,
ret
=
KEYSERVER_INTERNAL_ERROR
;
char
*
dn
=
NULL
,
line
[
MAX_LINE
],
*
key
[
2
]
=
{
NULL
,
NULL
};
char
keyid
[
17
],
state
[
6
];
LDAPMod
mod
,
*
attrs
[
2
];
memset
(
&
mod
,
0
,
sizeof
(
mod
));
mod
.
mod_op
=
LDAP_MOD_ADD
;
mod
.
mod_type
=
pgpkeystr
;
mod
.
mod_values
=
key
;
attrs
[
0
]
=&
mod
;
attrs
[
1
]
=
NULL
;
dn
=
malloc
(
strlen
(
"pgpCertid=virtual,"
)
+
strlen
(
basekeyspacedn
)
+
1
);
if
(
dn
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: can't allocate memory for keyserver record
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
strcpy
(
dn
,
"pgpCertid=virtual,"
);
strcat
(
dn
,
basekeyspacedn
);
key
[
0
]
=
malloc
(
1
);
if
(
key
[
0
]
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: unable to allocate memory for key
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
key
[
0
][
0
]
=
'\0'
;
/* Read and throw away stdin until we see the BEGIN */
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
)
if
(
sscanf
(
line
,
"KEY%*[ ]%16s%*[ ]%5s
\n
"
,
keyid
,
state
)
==
2
&&
strcmp
(
state
,
"BEGIN"
)
==
0
)
{
begin
=
1
;
break
;
}
if
(
!
begin
)
{
/* i.e. eof before the KEY BEGIN was found. This isn't an
error. */
*
r_eof
=
1
;
ret
=
KEYSERVER_OK
;
goto
fail
;
}
/* Now slurp up everything until we see the END */
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
)
if
(
sscanf
(
line
,
"KEY%*[ ]%16s%*[ ]%3s
\n
"
,
keyid
,
state
)
==
2
&&
strcmp
(
state
,
"END"
)
==
0
)
{
end
=
1
;
break
;
}
else
{
keysize
+=
strlen
(
line
);
key
[
0
]
=
realloc
(
key
[
0
],
keysize
);
if
(
key
[
0
]
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: unable to reallocate for key
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
strcat
(
key
[
0
],
line
);
}
if
(
!
end
)
{
fprintf
(
console
,
"gpgkeys: no KEY %s END found
\n
"
,
keyid
);
*
r_eof
=
1
;
ret
=
KEYSERVER_KEY_INCOMPLETE
;
goto
fail
;
}
err
=
ldap_add_s
(
ldap
,
dn
,
attrs
);
if
(
err
!=
LDAP_SUCCESS
)
{
fprintf
(
console
,
"gpgkeys: error adding key %s to keyserver: %s
\n
"
,
keyid
,
ldap_err2string
(
err
));
ret
=
ldap_err_to_gpg_err
(
err
);
goto
fail
;
}
ret
=
KEYSERVER_OK
;
fail
:
free
(
key
[
0
]);
free
(
dn
);
if
(
ret
!=
0
&&
begin
)
fprintf
(
output
,
"KEY %s FAILED %d
\n
"
,
keyid
,
ret
);
/* Not a fatal error */
if
(
ret
==
KEYSERVER_KEY_EXISTS
)
ret
=
KEYSERVER_OK
;
return
ret
;
}
static
void
build_info
(
const
char
*
certid
,
LDAPMessage
*
each
)
{
char
**
vals
;
fprintf
(
output
,
"INFO %s BEGIN
\n
"
,
certid
);
fprintf
(
output
,
"pub:%s:"
,
certid
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeytype"
);
if
(
vals
!=
NULL
)
{
if
(
strcmp
(
vals
[
0
],
"RSA"
)
==
0
)
fprintf
(
output
,
"1"
);
else
if
(
strcmp
(
vals
[
0
],
"DSS/DH"
)
==
0
)
fprintf
(
output
,
"17"
);
ldap_value_free
(
vals
);
}
fprintf
(
output
,
":"
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeysize"
);
if
(
vals
!=
NULL
)
{
if
(
atoi
(
vals
[
0
])
>
0
)
fprintf
(
output
,
"%d"
,
atoi
(
vals
[
0
]));
ldap_value_free
(
vals
);
}
fprintf
(
output
,
":"
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeycreatetime"
);
if
(
vals
!=
NULL
)
{
if
(
strlen
(
vals
[
0
])
==
15
)
fprintf
(
output
,
"%u"
,(
unsigned
int
)
ldap2epochtime
(
vals
[
0
]));
ldap_value_free
(
vals
);
}
fprintf
(
output
,
":"
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeyexpiretime"
);
if
(
vals
!=
NULL
)
{
if
(
strlen
(
vals
[
0
])
==
15
)
fprintf
(
output
,
"%u"
,(
unsigned
int
)
ldap2epochtime
(
vals
[
0
]));
ldap_value_free
(
vals
);
}
fprintf
(
output
,
":"
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgprevoked"
);
if
(
vals
!=
NULL
)
{
if
(
atoi
(
vals
[
0
])
==
1
)
fprintf
(
output
,
"r"
);
ldap_value_free
(
vals
);
}
fprintf
(
output
,
"
\n
"
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpuserid"
);
if
(
vals
!=
NULL
)
{
int
i
;
for
(
i
=
0
;
vals
[
i
];
i
++
)
fprintf
(
output
,
"uid:%s
\n
"
,
vals
[
i
]);
ldap_value_free
(
vals
);
}
fprintf
(
output
,
"INFO %s END
\n
"
,
certid
);
}
/* Note that key-not-found is not a fatal error */
static
int
get_key
(
char
*
getkey
)
{
LDAPMessage
*
res
,
*
each
;
int
ret
=
KEYSERVER_INTERNAL_ERROR
,
err
,
count
;
struct
keylist
*
dupelist
=
NULL
;
char
search
[
62
];
/* This ordering is significant - specifically, "pgpcertid" needs to
be the second item in the list, since everything after it may be
discarded if the user isn't in verbose mode. */
char
*
attrs
[]
=
{
"replaceme"
,
"pgpcertid"
,
"pgpuserid"
,
"pgpkeyid"
,
"pgprevoked"
,
"pgpdisabled"
,
"pgpkeycreatetime"
,
"modifytimestamp"
,
"pgpkeysize"
,
"pgpkeytype"
,
NULL
};
attrs
[
0
]
=
pgpkeystr
;
/* Some compilers don't like using variables as
array initializers. */
/* Build the search string */
/* GPG can send us a v4 fingerprint, a v3 or v4 long key id, or a v3
or v4 short key id */
if
(
strncmp
(
getkey
,
"0x"
,
2
)
==
0
)
getkey
+=
2
;
if
(
strlen
(
getkey
)
==
32
)
{
fprintf
(
console
,
"gpgkeys: LDAP keyservers do not support v3 fingerprints
\n
"
);
fprintf
(
output
,
"KEY 0x%s BEGIN
\n
"
,
getkey
);
fprintf
(
output
,
"KEY 0x%s FAILED %d
\n
"
,
getkey
,
KEYSERVER_NOT_SUPPORTED
);
return
KEYSERVER_NOT_SUPPORTED
;
}
if
(
strlen
(
getkey
)
>
16
)
{
char
*
offset
=&
getkey
[
strlen
(
getkey
)
-16
];
/* fingerprint. Take the last 16 characters and treat it like a
long key id */
if
(
opt
->
flags
.
include_subkeys
)
sprintf
(
search
,
"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))"
,
offset
,
offset
);
else
sprintf
(
search
,
"(pgpcertid=%.16s)",offset)
;
}
else
if
(
strlen
(
getkey
)
>
8
)
{
/* long key id */
if
(
opt
->
flags
.
include_subkeys
)
sprintf
(
search
,
"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))"
,
getkey
,
getkey
);
else
sprintf
(
search
,
"(pgpcertid=%.16s)",getkey)
;
}
else
{
/* short key id */
sprintf
(
search
,
"(pgpkeyid=%.8s)"
,
getkey
);
}
if
(
opt
->
verbose
>
2
)
fprintf
(
console
,
"gpgkeys: LDAP fetch for: %s
\n
"
,
search
);
if
(
!
opt
->
verbose
)
attrs
[
2
]
=
NULL
;
/* keep only pgpkey(v2) and pgpcertid */
err
=
ldap_search_s
(
ldap
,
basekeyspacedn
,
LDAP_SCOPE_SUBTREE
,
search
,
attrs
,
0
,
&
res
);
if
(
err
!=
0
)
{
int
errtag
=
ldap_err_to_gpg_err
(
err
);
fprintf
(
console
,
"gpgkeys: LDAP search error: %s
\n
"
,
ldap_err2string
(
err
));
fprintf
(
output
,
"KEY 0x%s BEGIN
\n
"
,
getkey
);
fprintf
(
output
,
"KEY 0x%s FAILED %d
\n
"
,
getkey
,
errtag
);
return
errtag
;
}
count
=
ldap_count_entries
(
ldap
,
res
);
if
(
count
<
1
)
{
fprintf
(
console
,
"gpgkeys: key %s not found on keyserver
\n
"
,
getkey
);
fprintf
(
output
,
"KEY 0x%s BEGIN
\n
"
,
getkey
);
fprintf
(
output
,
"KEY 0x%s FAILED %d
\n
"
,
getkey
,
KEYSERVER_KEY_NOT_FOUND
);
}
else
{
/* There may be more than one unique result for a given keyID,
so we should fetch them all (test this by fetching short key
id 0xDEADBEEF). */
each
=
ldap_first_entry
(
ldap
,
res
);
while
(
each
!=
NULL
)
{
char
**
vals
,
**
certid
;
/* Use the long keyid to remove duplicates. The LDAP server
returns the same keyid more than once if there are
multiple user IDs on the key. Note that this does NOT
mean that a keyid that exists multiple times on the
keyserver will not be fetched. It means that each KEY,
no matter how many user IDs share its keyid, will be
fetched only once. If a keyid that belongs to more than
one key is fetched, the server quite properly responds
with all matching keys. -ds */
certid
=
ldap_get_values
(
ldap
,
each
,
"pgpcertid"
);
if
(
certid
!=
NULL
)
{
if
(
!
key_in_keylist
(
certid
[
0
],
dupelist
))
{
/* it's not a duplicate, so add it */
int
rc
=
add_key_to_keylist
(
certid
[
0
],
&
dupelist
);
if
(
rc
)
{
ret
=
rc
;
goto
fail
;
}
build_info
(
certid
[
0
],
each
);
fprintf
(
output
,
"KEY 0x%s BEGIN
\n
"
,
getkey
);
vals
=
ldap_get_values
(
ldap
,
each
,
pgpkeystr
);
if
(
vals
==
NULL
)
{
int
errtag
=
ldap_to_gpg_err
(
ldap
);
fprintf
(
console
,
"gpgkeys: unable to retrieve key %s "
"from keyserver
\n
"
,
getkey
);
fprintf
(
output
,
"KEY 0x%s FAILED %d
\n
"
,
getkey
,
errtag
);
}
else
{
print_nocr
(
output
,
vals
[
0
]);
fprintf
(
output
,
"
\n
KEY 0x%s END
\n
"
,
getkey
);
ldap_value_free
(
vals
);
}
}
ldap_value_free
(
certid
);
}
each
=
ldap_next_entry
(
ldap
,
each
);
}
}
ret
=
KEYSERVER_OK
;
fail
:
ldap_msgfree
(
res
);
free_keylist
(
dupelist
);
return
ret
;
}
#define LDAP_ESCAPE_CHARS "*()\\"
/* Append string to buffer in a LDAP-quoted way */
static
void
ldap_quote
(
char
*
buffer
,
const
char
*
string
)
{
/* Find the end of buffer */
buffer
+=
strlen
(
buffer
);
for
(;
*
string
;
string
++
)
{
if
(
strchr
(
LDAP_ESCAPE_CHARS
,
*
string
))
{
sprintf
(
buffer
,
"
\\
%02X"
,
*
string
);
buffer
+=
3
;
}
else
*
buffer
++=*
string
;
}
*
buffer
=
'\0'
;
}
/* Note that key-not-found is not a fatal error */
static
int
get_name
(
char
*
getkey
)
{
LDAPMessage
*
res
,
*
each
;
int
ret
=
KEYSERVER_INTERNAL_ERROR
,
err
,
count
;
/* The maximum size of the search, including the optional stuff and
the trailing \0 */
char
search
[
2
+
12
+
(
MAX_LINE
*
3
)
+
2
+
15
+
14
+
1
+
1
+
20
];
/* This ordering is significant - specifically, "pgpcertid" needs to
be the second item in the list, since everything after it may be
discarded if the user isn't in verbose mode. */
char
*
attrs
[]
=
{
"replaceme"
,
"pgpcertid"
,
"pgpuserid"
,
"pgpkeyid"
,
"pgprevoked"
,
"pgpdisabled"
,
"pgpkeycreatetime"
,
"modifytimestamp"
,
"pgpkeysize"
,
"pgpkeytype"
,
NULL
};
attrs
[
0
]
=
pgpkeystr
;
/* Some compilers don't like using variables as
array initializers. */
/* Build the search string */
search
[
0
]
=
'\0'
;
if
(
!
opt
->
flags
.
include_disabled
||
!
opt
->
flags
.
include_revoked
)
strcat
(
search
,
"(&"
);
strcat
(
search
,
"(pgpUserID=*"
);
ldap_quote
(
search
,
getkey
);
strcat
(
search
,
"*)"
);
if
(
!
opt
->
flags
.
include_disabled
)
strcat
(
search
,
"(pgpDisabled=0)"
);
if
(
!
opt
->
flags
.
include_revoked
)
strcat
(
search
,
"(pgpRevoked=0)"
);
if
(
!
opt
->
flags
.
include_disabled
||
!
opt
->
flags
.
include_revoked
)
strcat
(
search
,
")"
);
if
(
opt
->
verbose
>
2
)
fprintf
(
console
,
"gpgkeys: LDAP fetch for: %s
\n
"
,
search
);
if
(
!
opt
->
verbose
)
attrs
[
2
]
=
NULL
;
/* keep only pgpkey(v2) and pgpcertid */
err
=
ldap_search_s
(
ldap
,
basekeyspacedn
,
LDAP_SCOPE_SUBTREE
,
search
,
attrs
,
0
,
&
res
);
if
(
err
!=
0
)
{
int
errtag
=
ldap_err_to_gpg_err
(
err
);
fprintf
(
console
,
"gpgkeys: LDAP search error: %s
\n
"
,
ldap_err2string
(
err
));
fprintf
(
output
,
"NAME %s BEGIN
\n
"
,
getkey
);
fprintf
(
output
,
"NAME %s FAILED %d
\n
"
,
getkey
,
errtag
);
return
errtag
;
}
count
=
ldap_count_entries
(
ldap
,
res
);
if
(
count
<
1
)
{
fprintf
(
console
,
"gpgkeys: key %s not found on keyserver
\n
"
,
getkey
);
fprintf
(
output
,
"NAME %s BEGIN
\n
"
,
getkey
);
fprintf
(
output
,
"NAME %s FAILED %d
\n
"
,
getkey
,
KEYSERVER_KEY_NOT_FOUND
);
}
else
{
/* There may be more than one result, but we return them all. */
each
=
ldap_first_entry
(
ldap
,
res
);
while
(
each
!=
NULL
)
{
char
**
vals
,
**
certid
;
certid
=
ldap_get_values
(
ldap
,
each
,
"pgpcertid"
);
if
(
certid
!=
NULL
)
{
build_info
(
certid
[
0
],
each
);
fprintf
(
output
,
"NAME %s BEGIN
\n
"
,
getkey
);
vals
=
ldap_get_values
(
ldap
,
each
,
pgpkeystr
);
if
(
vals
==
NULL
)
{
int
errtag
=
ldap_to_gpg_err
(
ldap
);
fprintf
(
console
,
"gpgkeys: unable to retrieve key %s "
"from keyserver
\n
"
,
getkey
);
fprintf
(
output
,
"NAME %s FAILED %d
\n
"
,
getkey
,
errtag
);
}
else
{
print_nocr
(
output
,
vals
[
0
]);
fprintf
(
output
,
"
\n
NAME %s END
\n
"
,
getkey
);
ldap_value_free
(
vals
);
}
ldap_value_free
(
certid
);
}
each
=
ldap_next_entry
(
ldap
,
each
);
}
}
ret
=
KEYSERVER_OK
;
ldap_msgfree
(
res
);
return
ret
;
}
static
void
printquoted
(
FILE
*
stream
,
char
*
string
,
char
delim
)
{
while
(
*
string
)
{
if
(
*
string
==
delim
||
*
string
==
'%'
)
fprintf
(
stream
,
"%%%02x"
,
*
string
);
else
fputc
(
*
string
,
stream
);
string
++
;
}
}
/* Returns 0 on success and -1 on error. Note that key-not-found is
not an error! */
static
int
search_key
(
const
char
*
searchkey
)
{
char
**
vals
,
*
search
;
LDAPMessage
*
res
,
*
each
;
int
err
,
count
=
0
;
struct
keylist
*
dupelist
=
NULL
;
/* The maximum size of the search, including the optional stuff and
the trailing \0 */
char
*
attrs
[]
=
{
"pgpcertid"
,
"pgpuserid"
,
"pgprevoked"
,
"pgpdisabled"
,
"pgpkeycreatetime"
,
"pgpkeyexpiretime"
,
"modifytimestamp"
,
"pgpkeysize"
,
"pgpkeytype"
,
NULL
};
enum
ks_search_type
search_type
;
search
=
malloc
(
2
+
1
+
9
+
1
+
3
+
strlen
(
searchkey
)
+
3
+
1
+
15
+
14
+
1
+
1
+
20
);
if
(
!
search
)
{
fprintf
(
console
,
"gpgkeys: out of memory when building search list
\n
"
);
fprintf
(
output
,
"SEARCH %s FAILED %d
\n
"
,
searchkey
,
KEYSERVER_NO_MEMORY
);
return
KEYSERVER_NO_MEMORY
;
}
fprintf
(
output
,
"SEARCH %s BEGIN
\n
"
,
searchkey
);
search_type
=
classify_ks_search
(
&
searchkey
);
if
(
opt
->
debug
)
fprintf
(
console
,
"search type is %d, and key is
\"
%s
\"\n
"
,
search_type
,
searchkey
);
/* Build the search string */
search
[
0
]
=
'\0'
;
if
(
!
opt
->
flags
.
include_disabled
||
!
opt
->
flags
.
include_revoked
)
strcat
(
search
,
"(&"
);
strcat
(
search
,
"("
);
switch
(
search_type
)
{
case
KS_SEARCH_KEYID_SHORT
:
strcat
(
search
,
"pgpKeyID"
);
break
;
case
KS_SEARCH_KEYID_LONG
:
strcat
(
search
,
"pgpCertID"
);
break
;
default
:
strcat
(
search
,
"pgpUserID"
);
break
;
}
strcat
(
search
,
"="
);
switch
(
search_type
)
{
case
KS_SEARCH_SUBSTR
:
strcat
(
search
,
"*"
);
break
;
case
KS_SEARCH_MAIL
:
strcat
(
search
,
"*<"
);
break
;
case
KS_SEARCH_MAILSUB
:
strcat
(
search
,
"*<*"
);
break
;
case
KS_SEARCH_EXACT
:
case
KS_SEARCH_KEYID_LONG
:
case
KS_SEARCH_KEYID_SHORT
:
break
;
}
strcat
(
search
,
searchkey
);
switch
(
search_type
)
{
case
KS_SEARCH_SUBSTR
:
strcat
(
search
,
"*"
);
break
;
case
KS_SEARCH_MAIL
:
strcat
(
search
,
">*"
);
break
;
case
KS_SEARCH_MAILSUB
:
strcat
(
search
,
"*>*"
);
break
;
case
KS_SEARCH_EXACT
:
case
KS_SEARCH_KEYID_LONG
:
case
KS_SEARCH_KEYID_SHORT
:
break
;
}
strcat
(
search
,
")"
);
if
(
!
opt
->
flags
.
include_disabled
)
strcat
(
search
,
"(pgpDisabled=0)"
);
if
(
!
opt
->
flags
.
include_revoked
)
strcat
(
search
,
"(pgpRevoked=0)"
);
if
(
!
opt
->
flags
.
include_disabled
||
!
opt
->
flags
.
include_revoked
)
strcat
(
search
,
")"
);
if
(
opt
->
verbose
>
2
)
fprintf
(
console
,
"gpgkeys: LDAP search for: %s
\n
"
,
search
);
err
=
ldap_search_s
(
ldap
,
basekeyspacedn
,
LDAP_SCOPE_SUBTREE
,
search
,
attrs
,
0
,
&
res
);
free
(
search
);
if
(
err
!=
LDAP_SUCCESS
&&
err
!=
LDAP_SIZELIMIT_EXCEEDED
)
{
int
errtag
=
ldap_err_to_gpg_err
(
err
);
fprintf
(
output
,
"SEARCH %s FAILED %d
\n
"
,
searchkey
,
errtag
);
fprintf
(
console
,
"gpgkeys: LDAP search error: %s
\n
"
,
ldap_err2string
(
err
));
return
errtag
;
}
/* The LDAP server doesn't return a real count of unique keys, so we
can't use ldap_count_entries here. */
each
=
ldap_first_entry
(
ldap
,
res
);
while
(
each
!=
NULL
)
{
char
**
certid
=
ldap_get_values
(
ldap
,
each
,
"pgpcertid"
);
if
(
certid
!=
NULL
)
{
if
(
!
key_in_keylist
(
certid
[
0
],
dupelist
))
{
int
rc
=
add_key_to_keylist
(
certid
[
0
],
&
dupelist
);
if
(
rc
!=
0
)
{
fprintf
(
output
,
"SEARCH %s FAILED %d
\n
"
,
searchkey
,
rc
);
free_keylist
(
dupelist
);
return
rc
;
}
count
++
;
}
}
each
=
ldap_next_entry
(
ldap
,
each
);
}
if
(
err
==
LDAP_SIZELIMIT_EXCEEDED
)
{
if
(
count
==
1
)
fprintf
(
console
,
"gpgkeys: search results exceeded server limit."
" First %d result shown.
\n
"
,
count
);
else
fprintf
(
console
,
"gpgkeys: search results exceeded server limit."
" First %d results shown.
\n
"
,
count
);
}
free_keylist
(
dupelist
);
dupelist
=
NULL
;
if
(
count
<
1
)
fprintf
(
output
,
"info:1:0
\n
"
);
else
{
fprintf
(
output
,
"info:1:%d
\n
"
,
count
);
each
=
ldap_first_entry
(
ldap
,
res
);
while
(
each
!=
NULL
)
{
char
**
certid
;
certid
=
ldap_get_values
(
ldap
,
each
,
"pgpcertid"
);
if
(
certid
!=
NULL
)
{
LDAPMessage
*
uids
;
/* Have we seen this certid before? */
if
(
!
key_in_keylist
(
certid
[
0
],
dupelist
))
{
int
rc
=
add_key_to_keylist
(
certid
[
0
],
&
dupelist
);
if
(
rc
)
{
fprintf
(
output
,
"SEARCH %s FAILED %d
\n
"
,
searchkey
,
rc
);
free_keylist
(
dupelist
);
ldap_value_free
(
certid
);
ldap_msgfree
(
res
);
return
rc
;
}
fprintf
(
output
,
"pub:%s:"
,
certid
[
0
]);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeytype"
);
if
(
vals
!=
NULL
)
{
/* The LDAP server doesn't exactly handle this
well. */
if
(
strcasecmp
(
vals
[
0
],
"RSA"
)
==
0
)
fprintf
(
output
,
"1"
);
else
if
(
strcasecmp
(
vals
[
0
],
"DSS/DH"
)
==
0
)
fprintf
(
output
,
"17"
);
ldap_value_free
(
vals
);
}
fputc
(
':'
,
output
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeysize"
);
if
(
vals
!=
NULL
)
{
/* Not sure why, but some keys are listed with a
key size of 0. Treat that like an
unknown. */
if
(
atoi
(
vals
[
0
])
>
0
)
fprintf
(
output
,
"%d"
,
atoi
(
vals
[
0
]));
ldap_value_free
(
vals
);
}
fputc
(
':'
,
output
);
/* YYYYMMDDHHmmssZ */
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeycreatetime"
);
if
(
vals
!=
NULL
&&
strlen
(
vals
[
0
])
==
15
)
{
fprintf
(
output
,
"%u"
,
(
unsigned
int
)
ldap2epochtime
(
vals
[
0
]));
ldap_value_free
(
vals
);
}
fputc
(
':'
,
output
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpkeyexpiretime"
);
if
(
vals
!=
NULL
&&
strlen
(
vals
[
0
])
==
15
)
{
fprintf
(
output
,
"%u"
,
(
unsigned
int
)
ldap2epochtime
(
vals
[
0
]));
ldap_value_free
(
vals
);
}
fputc
(
':'
,
output
);
vals
=
ldap_get_values
(
ldap
,
each
,
"pgprevoked"
);
if
(
vals
!=
NULL
)
{
if
(
atoi
(
vals
[
0
])
==
1
)
fprintf
(
output
,
"r"
);
ldap_value_free
(
vals
);
}
vals
=
ldap_get_values
(
ldap
,
each
,
"pgpdisabled"
);
if
(
vals
!=
NULL
)
{
if
(
atoi
(
vals
[
0
])
==
1
)
fprintf
(
output
,
"d"
);
ldap_value_free
(
vals
);
}
#if 0
/* This is not yet specified in the keyserver
protocol, but may be someday. */
fputc(':',output);
vals=ldap_get_values(ldap,each,"modifytimestamp");
if(vals!=NULL && strlen(vals[0])==15)
{
fprintf(output,"%u",
(unsigned int)ldap2epochtime(vals[0]));
ldap_value_free(vals);
}
#endif
fprintf
(
output
,
"
\n
"
);
/* Now print all the uids that have this certid */
uids
=
ldap_first_entry
(
ldap
,
res
);
while
(
uids
!=
NULL
)
{
vals
=
ldap_get_values
(
ldap
,
uids
,
"pgpcertid"
);
if
(
vals
!=
NULL
)
{
if
(
strcasecmp
(
certid
[
0
],
vals
[
0
])
==
0
)
{
char
**
uidvals
;
fprintf
(
output
,
"uid:"
);
uidvals
=
ldap_get_values
(
ldap
,
uids
,
"pgpuserid"
);
if
(
uidvals
!=
NULL
)
{
/* Need to escape any colons */
printquoted
(
output
,
uidvals
[
0
],
':'
);
ldap_value_free
(
uidvals
);
}
fprintf
(
output
,
"
\n
"
);
}
ldap_value_free
(
vals
);
}
uids
=
ldap_next_entry
(
ldap
,
uids
);
}
}
ldap_value_free
(
certid
);
}
each
=
ldap_next_entry
(
ldap
,
each
);
}
}
ldap_msgfree
(
res
);
free_keylist
(
dupelist
);
fprintf
(
output
,
"SEARCH %s END
\n
"
,
searchkey
);
return
KEYSERVER_OK
;
}
static
void
fail_all
(
struct
keylist
*
keylist
,
int
err
)
{
if
(
!
keylist
)
return
;
if
(
opt
->
action
==
KS_SEARCH
)
{
fprintf
(
output
,
"SEARCH "
);
while
(
keylist
)
{
fprintf
(
output
,
"%s "
,
keylist
->
str
);
keylist
=
keylist
->
next
;
}
fprintf
(
output
,
"FAILED %d
\n
"
,
err
);
}
else
while
(
keylist
)
{
fprintf
(
output
,
"KEY %s FAILED %d
\n
"
,
keylist
->
str
,
err
);
keylist
=
keylist
->
next
;
}
}
static
int
find_basekeyspacedn
(
void
)
{
int
err
,
i
;
char
*
attr
[]
=
{
"namingContexts"
,
NULL
,
NULL
,
NULL
};
LDAPMessage
*
res
;
char
**
context
;
/* Look for namingContexts */
err
=
ldap_search_s
(
ldap
,
""
,
LDAP_SCOPE_BASE
,
"(objectClass=*)"
,
attr
,
0
,
&
res
);
if
(
err
==
LDAP_SUCCESS
)
{
context
=
ldap_get_values
(
ldap
,
res
,
"namingContexts"
);
if
(
context
)
{
attr
[
0
]
=
"pgpBaseKeySpaceDN"
;
attr
[
1
]
=
"pgpVersion"
;
attr
[
2
]
=
"pgpSoftware"
;
real_ldap
=
1
;
/* We found some, so try each namingContext as the search base
and look for pgpBaseKeySpaceDN. Because we found this, we
know we're talking to a regular-ish LDAP server and not a
LDAP keyserver. */
for
(
i
=
0
;
context
[
i
]
&&
!
basekeyspacedn
;
i
++
)
{
char
**
vals
;
LDAPMessage
*
si_res
;
char
*
object
;
object
=
malloc
(
17
+
strlen
(
context
[
i
])
+
1
);
if
(
!
object
)
return
-1
;
strcpy
(
object
,
"cn=pgpServerInfo,"
);
strcat
(
object
,
context
[
i
]);
err
=
ldap_search_s
(
ldap
,
object
,
LDAP_SCOPE_BASE
,
"(objectClass=*)"
,
attr
,
0
,
&
si_res
);
free
(
object
);
if
(
err
==
LDAP_NO_SUCH_OBJECT
)
continue
;
else
if
(
err
!=
LDAP_SUCCESS
)
return
err
;
vals
=
ldap_get_values
(
ldap
,
si_res
,
"pgpBaseKeySpaceDN"
);
if
(
vals
)
{
basekeyspacedn
=
strdup
(
vals
[
0
]);
ldap_value_free
(
vals
);
}
if
(
opt
->
verbose
>
1
)
{
vals
=
ldap_get_values
(
ldap
,
si_res
,
"pgpSoftware"
);
if
(
vals
)
{
fprintf
(
console
,
"Server:
\t
%s
\n
"
,
vals
[
0
]);
ldap_value_free
(
vals
);
}
vals
=
ldap_get_values
(
ldap
,
si_res
,
"pgpVersion"
);
if
(
vals
)
{
fprintf
(
console
,
"Version:
\t
%s
\n
"
,
vals
[
0
]);
ldap_value_free
(
vals
);
}
}
ldap_msgfree
(
si_res
);
}
ldap_value_free
(
context
);
}
ldap_msgfree
(
res
);
}
else
{
/* We don't have an answer yet, which means the server might be
a LDAP keyserver. */
char
**
vals
;
LDAPMessage
*
si_res
;
attr
[
0
]
=
"pgpBaseKeySpaceDN"
;
attr
[
1
]
=
"version"
;
attr
[
2
]
=
"software"
;
err
=
ldap_search_s
(
ldap
,
"cn=pgpServerInfo"
,
LDAP_SCOPE_BASE
,
"(objectClass=*)"
,
attr
,
0
,
&
si_res
);
if
(
err
!=
LDAP_SUCCESS
)
return
err
;
/* For the LDAP keyserver, this is always "OU=ACTIVE,O=PGP
KEYSPACE,C=US", but it might not be in the future. */
vals
=
ldap_get_values
(
ldap
,
si_res
,
"baseKeySpaceDN"
);
if
(
vals
)
{
basekeyspacedn
=
strdup
(
vals
[
0
]);
ldap_value_free
(
vals
);
}
if
(
opt
->
verbose
>
1
)
{
vals
=
ldap_get_values
(
ldap
,
si_res
,
"software"
);
if
(
vals
)
{
fprintf
(
console
,
"Server:
\t
%s
\n
"
,
vals
[
0
]);
ldap_value_free
(
vals
);
}
}
vals
=
ldap_get_values
(
ldap
,
si_res
,
"version"
);
if
(
vals
)
{
if
(
opt
->
verbose
>
1
)
fprintf
(
console
,
"Version:
\t
%s
\n
"
,
vals
[
0
]);
/* If the version is high enough, use the new pgpKeyV2
attribute. This design if iffy at best, but it matches how
PGP does it. I figure the NAI folks assumed that there would
never be a LDAP keyserver vendor with a different numbering
scheme. */
if
(
atoi
(
vals
[
0
])
>
1
)
pgpkeystr
=
"pgpKeyV2"
;
ldap_value_free
(
vals
);
}
ldap_msgfree
(
si_res
);
}
return
LDAP_SUCCESS
;
}
static
void
show_help
(
FILE
*
fp
)
{
fprintf
(
fp
,
"-h, --help
\t
help
\n
"
);
fprintf
(
fp
,
"-V
\t\t
machine readable version
\n
"
);
fprintf
(
fp
,
"--version
\t
human readable version
\n
"
);
fprintf
(
fp
,
"-o
\t\t
output to this file
\n
"
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
int
port
=
0
,
arg
,
err
,
ret
=
KEYSERVER_INTERNAL_ERROR
;
char
line
[
MAX_LINE
],
*
binddn
=
NULL
,
*
bindpw
=
NULL
;
int
failed
=
0
,
use_ssl
=
0
,
use_tls
=
0
,
bound
=
0
;
struct
keylist
*
keylist
=
NULL
,
*
keyptr
=
NULL
;
console
=
stderr
;
/* Kludge to implement standard GNU options. */
if
(
argc
>
1
&&
!
strcmp
(
argv
[
1
],
"--version"
))
{
fputs
(
"gpgkeys_ldap ("
GNUPG_NAME
") "
VERSION
"
\n
"
,
stdout
);
return
0
;
}
else
if
(
argc
>
1
&&
!
strcmp
(
argv
[
1
],
"--help"
))
{
show_help
(
stdout
);
return
0
;
}
while
((
arg
=
getopt
(
argc
,
argv
,
"hVo:"
))
!=
-1
)
switch
(
arg
)
{
default
:
case
'h'
:
show_help
(
console
);
return
KEYSERVER_OK
;
case
'V'
:
fprintf
(
stdout
,
"%d
\n
%s
\n
"
,
KEYSERVER_PROTO_VERSION
,
VERSION
);
return
KEYSERVER_OK
;
case
'o'
:
output
=
fopen
(
optarg
,
"w"
);
if
(
output
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: Cannot open output file '%s': %s
\n
"
,
optarg
,
strerror
(
errno
));
return
KEYSERVER_INTERNAL_ERROR
;
}
break
;
}
if
(
argc
>
optind
)
{
input
=
fopen
(
argv
[
optind
],
"r"
);
if
(
input
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: Cannot open input file '%s': %s
\n
"
,
argv
[
optind
],
strerror
(
errno
));
return
KEYSERVER_INTERNAL_ERROR
;
}
}
if
(
input
==
NULL
)
input
=
stdin
;
if
(
output
==
NULL
)
output
=
stdout
;
opt
=
init_ks_options
();
if
(
!
opt
)
return
KEYSERVER_NO_MEMORY
;
/* Get the command and info block */
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
)
{
char
optionstr
[
MAX_OPTION
+
1
];
if
(
line
[
0
]
==
'\n'
)
break
;
err
=
parse_ks_options
(
line
,
opt
);
if
(
err
>
0
)
{
ret
=
err
;
goto
fail
;
}
else
if
(
err
==
0
)
continue
;
if
(
sscanf
(
line
,
"OPTION %"
MKSTRING
(
MAX_OPTION
)
"[^
\n
]
\n
"
,
optionstr
)
==
1
)
{
int
no
=
0
;
char
*
start
=&
optionstr
[
0
];
optionstr
[
MAX_OPTION
]
=
'\0'
;
if
(
strncasecmp
(
optionstr
,
"no-"
,
3
)
==
0
)
{
no
=
1
;
start
=&
optionstr
[
3
];
}
if
(
strncasecmp
(
start
,
"tls"
,
3
)
==
0
)
{
if
(
no
)
use_tls
=
0
;
else
if
(
start
[
3
]
==
'='
)
{
if
(
strcasecmp
(
&
start
[
4
],
"no"
)
==
0
)
use_tls
=
0
;
else
if
(
strcasecmp
(
&
start
[
4
],
"try"
)
==
0
)
use_tls
=
1
;
else
if
(
strcasecmp
(
&
start
[
4
],
"warn"
)
==
0
)
use_tls
=
2
;
else
if
(
strcasecmp
(
&
start
[
4
],
"require"
)
==
0
)
use_tls
=
3
;
else
use_tls
=
1
;
}
else
if
(
start
[
3
]
==
'\0'
)
use_tls
=
1
;
}
else
if
(
strncasecmp
(
start
,
"basedn"
,
6
)
==
0
)
{
if
(
no
)
{
free
(
basekeyspacedn
);
basekeyspacedn
=
NULL
;
}
else
if
(
start
[
6
]
==
'='
)
{
free
(
basekeyspacedn
);
basekeyspacedn
=
strdup
(
&
start
[
7
]);
if
(
!
basekeyspacedn
)
{
fprintf
(
console
,
"gpgkeys: out of memory while creating "
"base DN
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
real_ldap
=
1
;
}
}
else
if
(
strncasecmp
(
start
,
"binddn"
,
6
)
==
0
)
{
if
(
no
)
{
free
(
binddn
);
binddn
=
NULL
;
}
else
if
(
start
[
6
]
==
'='
)
{
free
(
binddn
);
binddn
=
strdup
(
&
start
[
7
]);
if
(
!
binddn
)
{
fprintf
(
console
,
"gpgkeys: out of memory while creating "
"bind DN
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
real_ldap
=
1
;
}
}
else
if
(
strncasecmp
(
start
,
"bindpw"
,
6
)
==
0
)
{
if
(
no
)
{
free
(
bindpw
);
bindpw
=
NULL
;
}
else
if
(
start
[
6
]
==
'='
)
{
free
(
bindpw
);
bindpw
=
strdup
(
&
start
[
7
]);
if
(
!
bindpw
)
{
fprintf
(
console
,
"gpgkeys: out of memory while creating "
"bind password
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
real_ldap
=
1
;
}
}
continue
;
}
}
if
(
!
opt
->
scheme
)
{
fprintf
(
console
,
"gpgkeys: no scheme supplied!
\n
"
);
ret
=
KEYSERVER_SCHEME_NOT_FOUND
;
goto
fail
;
}
if
(
strcasecmp
(
opt
->
scheme
,
"ldaps"
)
==
0
)
{
port
=
636
;
use_ssl
=
1
;
}
if
(
opt
->
port
)
port
=
atoi
(
opt
->
port
);
if
(
!
opt
->
host
)
{
fprintf
(
console
,
"gpgkeys: no keyserver host provided
\n
"
);
goto
fail
;
}
if
(
opt
->
timeout
&&
register_timeout
()
==
-1
)
{
fprintf
(
console
,
"gpgkeys: unable to register timeout handler
\n
"
);
return
KEYSERVER_INTERNAL_ERROR
;
}
#if defined(LDAP_OPT_X_TLS_CACERTFILE) && defined(HAVE_LDAP_SET_OPTION)
if
(
opt
->
ca_cert_file
)
{
err
=
ldap_set_option
(
NULL
,
LDAP_OPT_X_TLS_CACERTFILE
,
opt
->
ca_cert_file
);
if
(
err
!=
LDAP_SUCCESS
)
{
fprintf
(
console
,
"gpgkeys: unable to set ca-cert-file: %s
\n
"
,
ldap_err2string
(
err
));
ret
=
KEYSERVER_INTERNAL_ERROR
;
goto
fail
;
}
}
#endif
/* LDAP_OPT_X_TLS_CACERTFILE && HAVE_LDAP_SET_OPTION */
/* SSL trumps TLS */
if
(
use_ssl
)
use_tls
=
0
;
/* If it's a GET or a SEARCH, the next thing to come in is the
keyids. If it's a SEND, then there are no keyids. */
if
(
opt
->
action
==
KS_SEND
)
while
(
fgets
(
line
,
MAX_LINE
,
input
)
!=
NULL
&&
line
[
0
]
!=
'\n'
);
else
if
(
opt
->
action
==
KS_GET
||
opt
->
action
==
KS_GETNAME
||
opt
->
action
==
KS_SEARCH
)
{
for
(;;)
{
struct
keylist
*
work
;
if
(
fgets
(
line
,
MAX_LINE
,
input
)
==
NULL
)
break
;
else
{
if
(
line
[
0
]
==
'\n'
||
line
[
0
]
==
'\0'
)
break
;
work
=
malloc
(
sizeof
(
struct
keylist
));
if
(
work
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: out of memory while "
"building key list
\n
"
);
ret
=
KEYSERVER_NO_MEMORY
;
goto
fail
;
}
strcpy
(
work
->
str
,
line
);
/* Trim the trailing \n */
work
->
str
[
strlen
(
line
)
-1
]
=
'\0'
;
work
->
next
=
NULL
;
/* Always attach at the end to keep the list in proper
order for searching */
if
(
keylist
==
NULL
)
keylist
=
work
;
else
keyptr
->
next
=
work
;
keyptr
=
work
;
}
}
}
else
{
fprintf
(
console
,
"gpgkeys: no keyserver command specified
\n
"
);
goto
fail
;
}
/* Send the response */
fprintf
(
output
,
"VERSION %d
\n
"
,
KEYSERVER_PROTO_VERSION
);
fprintf
(
output
,
"PROGRAM %s
\n\n
"
,
VERSION
);
if
(
opt
->
verbose
>
1
)
{
fprintf
(
console
,
"Host:
\t\t
%s
\n
"
,
opt
->
host
);
if
(
port
)
fprintf
(
console
,
"Port:
\t\t
%d
\n
"
,
port
);
fprintf
(
console
,
"Command:
\t
%s
\n
"
,
ks_action_to_string
(
opt
->
action
));
}
if
(
opt
->
debug
)
{
#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(HAVE_LDAP_SET_OPTION)
err
=
ldap_set_option
(
NULL
,
LDAP_OPT_DEBUG_LEVEL
,
&
opt
->
debug
);
if
(
err
!=
LDAP_SUCCESS
)
fprintf
(
console
,
"gpgkeys: unable to set debug mode: %s
\n
"
,
ldap_err2string
(
err
));
else
fprintf
(
console
,
"gpgkeys: debug level %d
\n
"
,
opt
->
debug
);
#else
fprintf
(
console
,
"gpgkeys: not built with debugging support
\n
"
);
#endif
}
/* We have a timeout set for the setup stuff since it could time out
as well. */
set_timeout
(
opt
->
timeout
);
/* Note that this tries all A records on a given host (or at least,
OpenLDAP does). */
ldap
=
ldap_init
(
opt
->
host
,
port
);
if
(
ldap
==
NULL
)
{
fprintf
(
console
,
"gpgkeys: internal LDAP init error: %s
\n
"
,
strerror
(
errno
));
fail_all
(
keylist
,
KEYSERVER_INTERNAL_ERROR
);
goto
fail
;
}
if
(
use_ssl
)
{
#if defined(LDAP_OPT_X_TLS) && defined(HAVE_LDAP_SET_OPTION)
int
ssl
=
LDAP_OPT_X_TLS_HARD
;
err
=
ldap_set_option
(
ldap
,
LDAP_OPT_X_TLS
,
&
ssl
);
if
(
err
!=
LDAP_SUCCESS
)
{
fprintf
(
console
,
"gpgkeys: unable to make SSL connection: %s
\n
"
,
ldap_err2string
(
err
));
fail_all
(
keylist
,
ldap_err_to_gpg_err
(
err
));
goto
fail
;
}
if
(
!
opt
->
flags
.
check_cert
)
ssl
=
LDAP_OPT_X_TLS_NEVER
;
err
=
ldap_set_option
(
NULL
,
LDAP_OPT_X_TLS_REQUIRE_CERT
,
&
ssl
);
if
(
err
!=
LDAP_SUCCESS
)
{
fprintf
(
console
,
"gpgkeys: unable to set certificate validation: %s
\n
"
,
ldap_err2string
(
err
));
fail_all
(
keylist
,
ldap_err_to_gpg_err
(
err
));
goto
fail
;
}
#else
fprintf
(
console
,
"gpgkeys: unable to make SSL connection: %s
\n
"
,
"not built with LDAPS support"
);
fail_all
(
keylist
,
KEYSERVER_INTERNAL_ERROR
);
goto
fail
;
#endif
}
if
(
!
basekeyspacedn
)
if
((
err
=
find_basekeyspacedn
())
||
!
basekeyspacedn
)
{
fprintf
(
console
,
"gpgkeys: unable to retrieve LDAP base: %s
\n
"
,
err
?
ldap_err2string
(
err
)
:
"not found"
);
fail_all
(
keylist
,
ldap_err_to_gpg_err
(
err
));
goto
fail
;
}
/* use_tls: 0=don't use, 1=try silently to use, 2=try loudly to use,
3=force use. */
if
(
use_tls
)
{
if
(
!
real_ldap
)
{
if
(
use_tls
>=
2
)
fprintf
(
console
,
"gpgkeys: unable to start TLS: %s
\n
"
,
"not supported by the NAI LDAP keyserver"
);
if
(
use_tls
==
3
)
{
fail_all
(
keylist
,
KEYSERVER_INTERNAL_ERROR
);
goto
fail
;
}
}
else
{
#if defined(HAVE_LDAP_START_TLS_S) && defined(HAVE_LDAP_SET_OPTION)
int
ver
=
LDAP_VERSION3
;
err
=
ldap_set_option
(
ldap
,
LDAP_OPT_PROTOCOL_VERSION
,
&
ver
);
#ifdef LDAP_OPT_X_TLS
if
(
err
==
LDAP_SUCCESS
)
{
if
(
opt
->
flags
.
check_cert
)
ver
=
LDAP_OPT_X_TLS_HARD
;
else
ver
=
LDAP_OPT_X_TLS_NEVER
;
err
=
ldap_set_option
(
NULL
,
LDAP_OPT_X_TLS_REQUIRE_CERT
,
&
ver
);
}
#endif
if
(
err
==
LDAP_SUCCESS
)
err
=
ldap_start_tls_s
(
ldap
,
NULL
,
NULL
);
if
(
err
!=
LDAP_SUCCESS
)
{
if
(
use_tls
>=
2
||
opt
->
verbose
>
2
)
fprintf
(
console
,
"gpgkeys: unable to start TLS: %s
\n
"
,
ldap_err2string
(
err
));
/* Are we forcing it? */
if
(
use_tls
==
3
)
{
fail_all
(
keylist
,
ldap_err_to_gpg_err
(
err
));
goto
fail
;
}
}
else
if
(
opt
->
verbose
>
1
)
fprintf
(
console
,
"gpgkeys: TLS started successfully.
\n
"
);
#else
if
(
use_tls
>=
2
)
fprintf
(
console
,
"gpgkeys: unable to start TLS: %s
\n
"
,
"not built with TLS support"
);
if
(
use_tls
==
3
)
{
fail_all
(
keylist
,
KEYSERVER_INTERNAL_ERROR
);
goto
fail
;
}
#endif
}
}
/* By default we don't bind as there is usually no need to. For
cases where the server needs some authentication, the user can
use binddn and bindpw for auth. */
if
(
binddn
)
{
#ifdef HAVE_LDAP_SET_OPTION
int
ver
=
LDAP_VERSION3
;
err
=
ldap_set_option
(
ldap
,
LDAP_OPT_PROTOCOL_VERSION
,
&
ver
);
if
(
err
!=
LDAP_SUCCESS
)
{
fprintf
(
console
,
"gpgkeys: unable to go to LDAP 3: %s
\n
"
,
ldap_err2string
(
err
));
fail_all
(
keylist
,
ldap_err_to_gpg_err
(
err
));
goto
fail
;
}
#endif
if
(
opt
->
verbose
>
2
)
fprintf
(
console
,
"gpgkeys: LDAP bind to %s, pw %s
\n
"
,
binddn
,
bindpw
?
">not shown<"
:
">none<"
);
err
=
ldap_simple_bind_s
(
ldap
,
binddn
,
bindpw
);
if
(
err
!=
LDAP_SUCCESS
)
{
fprintf
(
console
,
"gpgkeys: internal LDAP bind error: %s
\n
"
,
ldap_err2string
(
err
));
fail_all
(
keylist
,
ldap_err_to_gpg_err
(
err
));
goto
fail
;
}
else
bound
=
1
;
}
if
(
opt
->
action
==
KS_GET
)
{
keyptr
=
keylist
;
while
(
keyptr
!=
NULL
)
{
set_timeout
(
opt
->
timeout
);
if
(
get_key
(
keyptr
->
str
)
!=
KEYSERVER_OK
)
failed
++
;
keyptr
=
keyptr
->
next
;
}
}
else
if
(
opt
->
action
==
KS_GETNAME
)
{
keyptr
=
keylist
;
while
(
keyptr
!=
NULL
)
{
set_timeout
(
opt
->
timeout
);
if
(
get_name
(
keyptr
->
str
)
!=
KEYSERVER_OK
)
failed
++
;
keyptr
=
keyptr
->
next
;
}
}
else
if
(
opt
->
action
==
KS_SEND
)
{
int
eof_seen
=
0
;
do
{
set_timeout
(
opt
->
timeout
);
if
(
real_ldap
)
{
if
(
send_key
(
&
eof_seen
)
!=
KEYSERVER_OK
)
failed
++
;
}
else
{
if
(
send_key_keyserver
(
&
eof_seen
)
!=
KEYSERVER_OK
)
failed
++
;
}
}
while
(
!
eof_seen
);
}
else
if
(
opt
->
action
==
KS_SEARCH
)
{
char
*
searchkey
=
NULL
;
int
len
=
0
;
set_timeout
(
opt
->
timeout
);
/* To search, we stick a * in between each key to search for.
This means that if the user enters words, they'll get
"enters*words". If the user "enters words", they'll get
"enters words" */
keyptr
=
keylist
;
while
(
keyptr
!=
NULL
)
{
len
+=
strlen
(
keyptr
->
str
)
+
1
;
keyptr
=
keyptr
->
next
;
}
searchkey
=
malloc
((
len
*
3
)
+
1
);
if
(
searchkey
==
NULL
)
{
ret
=
KEYSERVER_NO_MEMORY
;
fail_all
(
keylist
,
KEYSERVER_NO_MEMORY
);
goto
fail
;
}
searchkey
[
0
]
=
'\0'
;
keyptr
=
keylist
;
while
(
keyptr
!=
NULL
)
{
ldap_quote
(
searchkey
,
keyptr
->
str
);
strcat
(
searchkey
,
"*"
);
keyptr
=
keyptr
->
next
;
}
/* Nail that last "*" */
if
(
*
searchkey
)
searchkey
[
strlen
(
searchkey
)
-1
]
=
'\0'
;
if
(
search_key
(
searchkey
)
!=
KEYSERVER_OK
)
failed
++
;
free
(
searchkey
);
}
else
assert
(
!
"bad action"
);
if
(
!
failed
)
ret
=
KEYSERVER_OK
;
fail
:
while
(
keylist
!=
NULL
)
{
struct
keylist
*
current
=
keylist
;
keylist
=
keylist
->
next
;
free
(
current
);
}
if
(
input
!=
stdin
)
fclose
(
input
);
if
(
output
!=
stdout
)
fclose
(
output
);
free_ks_options
(
opt
);
if
(
ldap
!=
NULL
&&
bound
)
ldap_unbind_s
(
ldap
);
free
(
basekeyspacedn
);
return
ret
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Jan 17, 2:55 AM (1 d, 6 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2d/4f/9846d313c65142a249819aca9d02
Attached To
rG GnuPG
Event Timeline
Log In to Comment