Some work on the dirmngr

This commit is contained in:
Werner Koch 2010-07-26 14:01:32 +00:00
parent 57a3538555
commit ca279dc707
10 changed files with 180 additions and 99 deletions

View File

@ -1,3 +1,7 @@
2010-07-25 Werner Koch <wk@g10code.com>
* configure.ac (USE_LDAPWRAPPER): AC_DEFINE and AM_CONDITIONAL it.
2010-06-09 Werner Koch <wk@g10code.com>
* configure.ac (GNUPG_DIRMNGR_LDAP_PGM): Add option

View File

@ -1,3 +1,7 @@
2010-07-25 Werner Koch <wk@g10code.com>
* argparse.c (initialize): Use ARGPARSE_PRINT_WARNING constant.
2010-07-24 Werner Koch <wk@g10code.com>
* estream.c (es_set_binary): New.

View File

@ -267,7 +267,7 @@ initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
else
jnlib_log_error (_("invalid option \"%.50s\"\n"), s);
}
if ( arg->err != 1 )
if (arg->err != ARGPARSE_PRINT_WARNING)
exit (2);
arg->err = 0;
}

View File

@ -540,6 +540,7 @@ have_dosish_system=no
have_w32_system=no
have_w32ce_system=no
use_simple_gettext=no
use_ldapwrapper=yes
mmap_needed=yes
case "${host}" in
*-mingw32*)
@ -554,6 +555,7 @@ case "${host}" in
disable_keyserver_path=yes
have_dosish_system=yes
have_w32_system=yes
use_ldapwrapper=no # Fixme: Do this only for CE.
case "${host}" in
*-mingw32ce*)
have_w32ce_system=yes
@ -636,6 +638,11 @@ fi
AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
AM_CONDITIONAL(HAVE_W32CE_SYSTEM, test "$have_w32ce_system" = yes)
if test "$use_ldapwrapper" = yes; then
AC_DEFINE(USE_LDAPWRAPPER,1, [Build dirmngr with LDAP wrapper process])
fi
AM_CONDITIONAL(USE_LDAPWRAPPER, test "$use_ldapwrapper" = yes)
if test "$disable_keyserver_path" = yes; then
AC_DEFINE(DISABLE_KEYSERVER_PATH,1,
[Defined to disable exec-path for keyserver helpers])

View File

@ -1,3 +1,16 @@
2010-07-25 Werner Koch <wk@g10code.com>
* Makefile.am (dirmngr_SOURCES) [!USE_LDAPWRAPPER]: Build
ldap-wrapper-ce.
* ldap-wrapper-ce.c: New.
* dirmngr_ldap.c (opt): Remove global variable ...
(my_opt_t): ... and declare a type instead.
(main): Define a MY_OPT variable and change all references to OPT
to this.
(set_timeout, print_ldap_entries, fetch_ldap, process_url): Pass
MYOPT arg.
2010-07-24 Werner Koch <wk@g10code.com>
* dirmngr_ldap.c (main): Init common subsystems. Call

View File

@ -23,7 +23,9 @@ EXTRA_DIST = OAUTHORS ONEWS ChangeLog.1
bin_PROGRAMS = dirmngr dirmngr-client
if USE_LDAPWRAPPER
libexec_PROGRAMS = dirmngr_ldap
endif
AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
@ -39,7 +41,14 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
ldapserver.h ldapserver.c certcache.c certcache.h \
cdb.h cdblib.c ldap.c misc.c dirmngr-err.h \
ocsp.c ocsp.h validate.c validate.h ldap-wrapper.c ldap-wrapper.h
ocsp.c ocsp.h validate.c validate.h ldap-wrapper.h
if USE_LDAPWRAPPER
dirmngr_SOURCES += ldap-wrapper.c
else
dirmngr_SOURCES += ldap-wrapper-ce.c dirmngr_ldap.c
endif
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
@ -50,11 +59,13 @@ else
ldap_url =
endif
if USE_LDAPWRAPPER
dirmngr_ldap_SOURCES = dirmngr_ldap.c $(ldap_url) no-libgcrypt.c
dirmngr_ldap_CFLAGS = $(GPG_ERROR_CFLAGS)
dirmngr_ldap_LDFLAGS =
dirmngr_ldap_LDADD = $(libcommon) ../gl/libgnu.a $(DNSLIBS) \
$(GPG_ERROR_LIBS) $(LDAPLIBS) $(LIBINTL) $(LIBICONV)
endif
dirmngr_client_SOURCES = dirmngr-client.c no-libgcrypt.c
dirmngr_client_LDADD = $(libcommon) ../gl/libgnu.a $(LIBASSUAN_LIBS) \

View File

@ -55,6 +55,12 @@
#include "i18n.h"
#include "util.h"
/* If we are not using the ldap wrapper process we need to include the
prototype for our module's main function. */
#ifndef USE_LDAPWRAPPER
#include "./ldap-wrapper.h"
#endif
#define DEFAULT_LDAP_TIMEOUT 100 /* Arbitrary long timeout. */
@ -105,8 +111,10 @@ static ARGPARSE_OPTS opts[] = {
};
/* The usual structure for the program flags. */
static struct
/* A structure with module options. This is not a static variable
because if we are not build as a standalone binary, each thread
using this module needs to handle its own values. */
struct my_opt_s
{
int quiet;
int verbose;
@ -114,6 +122,8 @@ static struct
unsigned int alarm_timeout; /* And for the alarm based timeout. */
int multi;
estream_t outstream; /* Send output to thsi stream. */
/* Note that we can't use const for the strings because ldap_* are
not defined that way. */
char *proxy; /* Host and Port override. */
@ -124,12 +134,13 @@ static struct
char *dn; /* Override DN. */
char *filter;/* Override filter. */
char *attr; /* Override attribute. */
} opt;
};
typedef struct my_opt_s my_opt_t;
/* Prototypes. */
static void catch_alarm (int dummy);
static int process_url (const char *url);
static int process_url (my_opt_t myopt, const char *url);
@ -164,13 +175,25 @@ my_strusage (int level)
int
main (int argc, char **argv )
#ifdef USE_LDAPWRAPPER
main (int argc, char **argv)
#else
ldap_wrapper_main (char **argv, estream_t outstream)
#endif
{
#ifndef USE_LDAPWRAPPER
int argc;
#endif
ARGPARSE_ARGS pargs;
int any_err = 0;
char *p;
int only_search_timeout = 0;
struct my_opt_s my_opt_buffer;
my_opt_t myopt = &my_opt_buffer;
memset (&my_opt_buffer, 0, sizeof my_opt_buffer);
#ifdef USE_LDAPWRAPPER
set_strusage (my_strusage);
log_set_prefix ("dirmngr_ldap", JNLIB_LOG_WITH_PREFIX);
@ -180,12 +203,17 @@ main (int argc, char **argv )
init_common_subsystems (&argc, &argv);
es_set_binary (es_stdout);
myopt->outstream = es_stdout;
#else /*!USE_LDAPWRAPPER*/
myopt->outstream = outstream;
for (argc=0; argv[argc]; argc++)
;
#endif /*!USE_LDAPWRAPPER*/
/* LDAP defaults */
opt.timeout.tv_sec = DEFAULT_LDAP_TIMEOUT;
opt.timeout.tv_usec = 0;
opt.alarm_timeout = 0;
myopt->timeout.tv_sec = DEFAULT_LDAP_TIMEOUT;
myopt->timeout.tv_usec = 0;
myopt->alarm_timeout = 0;
/* Parse the command line. */
pargs.argc = &argc;
@ -195,26 +223,26 @@ main (int argc, char **argv )
{
switch (pargs.r_opt)
{
case oVerbose: opt.verbose++; break;
case oQuiet: opt.quiet++; break;
case oVerbose: myopt->verbose++; break;
case oQuiet: myopt->quiet++; break;
case oTimeout:
opt.timeout.tv_sec = pargs.r.ret_int;
opt.timeout.tv_usec = 0;
opt.alarm_timeout = pargs.r.ret_int;
myopt->timeout.tv_sec = pargs.r.ret_int;
myopt->timeout.tv_usec = 0;
myopt->alarm_timeout = pargs.r.ret_int;
break;
case oOnlySearchTimeout: only_search_timeout = 1; break;
case oMulti: opt.multi = 1; break;
case oUser: opt.user = pargs.r.ret_str; break;
case oPass: opt.pass = pargs.r.ret_str; break;
case oMulti: myopt->multi = 1; break;
case oUser: myopt->user = pargs.r.ret_str; break;
case oPass: myopt->pass = pargs.r.ret_str; break;
case oEnvPass:
opt.pass = getenv ("DIRMNGR_LDAP_PASS");
myopt->pass = getenv ("DIRMNGR_LDAP_PASS");
break;
case oProxy: opt.proxy = pargs.r.ret_str; break;
case oHost: opt.host = pargs.r.ret_str; break;
case oPort: opt.port = pargs.r.ret_int; break;
case oDN: opt.dn = pargs.r.ret_str; break;
case oFilter: opt.filter = pargs.r.ret_str; break;
case oAttr: opt.attr = pargs.r.ret_str; break;
case oProxy: myopt->proxy = pargs.r.ret_str; break;
case oHost: myopt->host = pargs.r.ret_str; break;
case oPort: myopt->port = pargs.r.ret_int; break;
case oDN: myopt->dn = pargs.r.ret_str; break;
case oFilter: myopt->filter = pargs.r.ret_str; break;
case oAttr: myopt->attr = pargs.r.ret_str; break;
case oLogWithPID:
{
unsigned int oldflags;
@ -223,36 +251,47 @@ main (int argc, char **argv )
}
break;
default : pargs.err = 2; break;
default :
#ifdef USE_LDAPWRAPPER
pargs.err = ARGPARSE_PRINT_ERROR;
#else
pargs.err = ARGPARSE_PRINT_WARNING; /* No exit() please. */
#endif
break;
}
}
if (only_search_timeout)
opt.alarm_timeout = 0;
myopt->alarm_timeout = 0;
if (opt.proxy)
if (myopt->proxy)
{
opt.host = xstrdup (opt.proxy);
p = strchr (opt.host, ':');
myopt->host = xstrdup (myopt->proxy);
p = strchr (myopt->host, ':');
if (p)
{
*p++ = 0;
opt.port = atoi (p);
myopt->port = atoi (p);
}
if (!opt.port)
opt.port = 389; /* make sure ports gets overridden. */
if (!myopt->port)
myopt->port = 389; /* make sure ports gets overridden. */
}
if (opt.port < 0 || opt.port > 65535)
log_error (_("invalid port number %d\n"), opt.port);
if (myopt->port < 0 || myopt->port > 65535)
log_error (_("invalid port number %d\n"), myopt->port);
#ifdef USE_LDAPWRAPPER
if (log_get_errorcount (0))
exit (2);
if (argc < 1)
usage (1);
#else
/* All passed arguments should be fine in this case. */
assert (argc);
#endif
if (opt.alarm_timeout)
#ifdef USE_LDAPWRAPPER
if (myopt->alarm_timeout)
{
#ifndef HAVE_W32_SYSTEM
# if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
@ -268,11 +307,14 @@ main (int argc, char **argv )
log_fatal ("unable to register timeout handler\n");
#endif
}
#endif /*USE_LDAPWRAPPER*/
for (; argc; argc--, argv++)
if (process_url (*argv))
if (process_url (myopt, *argv))
any_err = 1;
/* FIXME: Do we need to release stuff? */
return any_err;
}
@ -286,19 +328,19 @@ catch_alarm (int dummy)
static void
set_timeout (void)
set_timeout (my_opt_t myopt)
{
#ifndef HAVE_W32_SYSTEM
/* FIXME for W32. */
if (opt.alarm_timeout)
alarm (opt.alarm_timeout);
if (myopt->alarm_timeout)
alarm (myopt->alarm_timeout);
#endif
}
/* Helper for fetch_ldap(). */
static int
print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
print_ldap_entries (my_opt_t myopt, LDAP *ld, LDAPMessage *msg, char *want_attr)
{
LDAPMessage *item;
int any = 0;
@ -309,13 +351,13 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
BerElement *berctx;
char *attr;
if (opt.verbose > 1)
if (myopt->verbose > 1)
log_info (_("scanning result for attribute `%s'\n"),
want_attr? want_attr : "[all]");
if (opt.multi)
if (myopt->multi)
{ /* Write item marker. */
if (es_fwrite ("I\0\0\0\0", 5, 1, es_stdout) != 1)
if (es_fwrite ("I\0\0\0\0", 5, 1, myopt->oustream) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
@ -330,10 +372,10 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
struct berval **values;
int idx;
if (opt.verbose > 1)
if (myopt->verbose > 1)
log_info (_(" available attribute `%s'\n"), attr);
set_timeout ();
set_timeout (myopt);
/* I case we want only one attribute we do a case
insensitive compare without the optional extension
@ -366,23 +408,23 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
if (!values)
{
if (opt.verbose)
if (myopt->verbose)
log_info (_("attribute `%s' not found\n"), attr);
ldap_memfree (attr);
continue;
}
if (opt.verbose)
if (myopt->verbose)
{
log_info (_("found attribute `%s'\n"), attr);
if (opt.verbose > 1)
if (myopt->verbose > 1)
for (idx=0; values[idx]; idx++)
log_info (" length[%d]=%d\n",
idx, (int)values[0]->bv_len);
}
if (opt.multi)
if (myopt->multi)
{ /* Write attribute marker. */
unsigned char tmp[5];
size_t n = strlen (attr);
@ -392,8 +434,8 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
tmp[2] = (n >> 16);
tmp[3] = (n >> 8);
tmp[4] = (n);
if (es_fwrite (tmp, 5, 1, es_stdout) != 1
|| es_fwrite (attr, n, 1, es_stdout) != 1)
if (es_fwrite (tmp, 5, 1, myopt->oustream) != 1
|| es_fwrite (attr, n, 1, myopt->oustream) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
@ -406,7 +448,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
for (idx=0; values[idx]; idx++)
{
if (opt.multi)
if (myopt->multi)
{ /* Write value marker. */
unsigned char tmp[5];
size_t n = values[0]->bv_len;
@ -417,7 +459,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
tmp[3] = (n >> 8);
tmp[4] = (n);
if (es_fwrite (tmp, 5, 1, es_stdout) != 1)
if (es_fwrite (tmp, 5, 1, myopt->oustream) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
@ -433,7 +475,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
CRLs which are 52 KB or larger. */
#warning still true - implement in estream
if (es_fwrite (values[0]->bv_val, values[0]->bv_len,
1, es_stdout) != 1)
1, myopt->oustream) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
@ -456,7 +498,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
cnt = MAX_CNT;
if (es_fwrite (((char *) values[0]->bv_val) + n, cnt, 1,
es_stdout) != 1)
myopt->oustream) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
@ -470,18 +512,18 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
}
#endif
any = 1;
if (!opt.multi)
if (!myopt->multi)
break; /* Print only the first value. */
}
ldap_value_free_len (values);
ldap_memfree (attr);
if (want_attr || !opt.multi)
if (want_attr || !myopt->multi)
break; /* We only want to return the first attribute. */
}
ber_free (berctx, 0);
}
if (opt.verbose > 1 && any)
if (myopt->verbose > 1 && any)
log_info ("result has been printed\n");
return any?0:-1;
@ -491,7 +533,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
/* Helper for the URL based LDAP query. */
static int
fetch_ldap (const char *url, const LDAPURLDesc *ludp)
fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp)
{
LDAP *ld;
LDAPMessage *msg;
@ -499,24 +541,24 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
char *host, *dn, *filter, *attrs[2], *attr;
int port;
host = opt.host? opt.host : ludp->lud_host;
port = opt.port? opt.port : ludp->lud_port;
dn = opt.dn? opt.dn : ludp->lud_dn;
filter = opt.filter? opt.filter : ludp->lud_filter;
attrs[0] = opt.attr? opt.attr : ludp->lud_attrs? ludp->lud_attrs[0]:NULL;
host = myopt->host? myopt->host : ludp->lud_host;
port = myopt->port? myopt->port : ludp->lud_port;
dn = myopt->dn? myopt->dn : ludp->lud_dn;
filter = myopt->filter? myopt->filter : ludp->lud_filter;
attrs[0] = myopt->attr? myopt->attr : ludp->lud_attrs? ludp->lud_attrs[0]:NULL;
attrs[1] = NULL;
attr = attrs[0];
if (!port)
port = (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))? 636:389;
if (opt.verbose)
if (myopt->verbose)
{
log_info (_("processing url `%s'\n"), url);
if (opt.user)
log_info (_(" user `%s'\n"), opt.user);
if (opt.pass)
log_info (_(" pass `%s'\n"), *opt.pass?"*****":"");
if (myopt->user)
log_info (_(" user `%s'\n"), myopt->user);
if (myopt->pass)
log_info (_(" pass `%s'\n"), *myopt->pass?"*****":"");
if (host)
log_info (_(" host `%s'\n"), host);
log_info (_(" port %d\n"), port);
@ -524,7 +566,7 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
log_info (_(" DN `%s'\n"), dn);
if (filter)
log_info (_(" filter `%s'\n"), filter);
if (opt.multi && !opt.attr && ludp->lud_attrs)
if (myopt->multi && !myopt->attr && ludp->lud_attrs)
{
int i;
for (i=0; ludp->lud_attrs[i]; i++)
@ -540,18 +582,18 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
log_error (_("no host name in `%s'\n"), url);
return -1;
}
if (!opt.multi && !attr)
if (!myopt->multi && !attr)
{
log_error (_("no attribute given for query `%s'\n"), url);
return -1;
}
if (!opt.multi && !opt.attr
if (!myopt->multi && !myopt->attr
&& ludp->lud_attrs && ludp->lud_attrs[0] && ludp->lud_attrs[1])
log_info (_("WARNING: using first attribute only\n"));
set_timeout ();
set_timeout (myopt);
ld = ldap_init (host, port);
if (!ld)
{
@ -559,7 +601,7 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
host, port, strerror (errno));
return -1;
}
if (ldap_simple_bind_s (ld, opt.user, opt.pass))
if (ldap_simple_bind_s (ld, myopt->user, myopt->pass))
{
log_error (_("binding to `%s:%d' failed: %s\n"),
host, port, strerror (errno));
@ -567,18 +609,17 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
return -1;
}
set_timeout ();
set_timeout (myopt);
rc = ldap_search_st (ld, dn, ludp->lud_scope, filter,
opt.multi && !opt.attr && ludp->lud_attrs?
myopt->multi && !myopt->attr && ludp->lud_attrs?
ludp->lud_attrs:attrs,
0,
&opt.timeout, &msg);
if (rc == LDAP_SIZELIMIT_EXCEEDED && opt.multi)
&myopt->timeout, &msg);
if (rc == LDAP_SIZELIMIT_EXCEEDED && myopt->multi)
{
if (es_fwrite ("E\0\0\0\x09truncated", 14, 1, es_stdout) != 1)
if (es_fwrite ("E\0\0\0\x09truncated", 14, 1, myopt->oustream) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
log_error (_("error writing to stdout: %s\n"), strerror (errno));
return -1;
}
}
@ -594,7 +635,7 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
}
}
rc = print_ldap_entries (ld, msg, opt.multi? NULL:attr);
rc = print_ldap_entries (myopt, ld, msg, myopt->multi? NULL:attr);
ldap_msgfree (msg);
/* FIXME: Need deinit (ld)? */
@ -607,7 +648,7 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
/* Main processing. Take the URL and run the LDAP query. The result
is printed to stdout, errors are logged to the log stream. */
static int
process_url (const char *url)
process_url (my_opt_t myopt, const char *url)
{
int rc;
LDAPURLDesc *ludp = NULL;
@ -625,7 +666,7 @@ process_url (const char *url)
return -1;
}
rc = fetch_ldap (url, ludp);
rc = fetch_ldap (myopt, url, ludp);
ldap_free_urldesc (ludp);
return rc;

View File

@ -41,6 +41,9 @@
#include "misc.h"
#include "ldap-wrapper.h"
#ifdef USE_LDAPWRAPPER
# error This module is not expected to be build.
#endif
/* To keep track of the LDAP wrapper state we use this structure. */
@ -169,19 +172,9 @@ ldap_wrapper_connection_cleanup (ctrl_t ctrl)
}
}
/* Fork and exec the LDAP wrapper and returns a new libksba reader
/* Start a new LDAP thread and returns a new libksba reader
object at READER. ARGV is a NULL terminated list of arguments for
the wrapper. The function returns 0 on success or an error code.
Special hack to avoid passing a password through the command line
which is globally visible: If the first element of ARGV is "--pass"
it will be removed and instead the environment variable
DIRMNGR_LDAP_PASS will be set to the next value of ARGV. On modern
OSes the environment is not visible to other users. For those old
systems where it can't be avoided, we don't want to go into the
hassle of passing the password via stdin; it's just too complicated
and an LDAP password used for public directory lookups should not
be that confidential. */
the wrapper. The function returns 0 on success or an error code. */
gpg_error_t
ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
{

View File

@ -69,6 +69,9 @@
#define pth_close(fd) close(fd)
#endif
#ifndef USE_LDAPWRAPPER
# error This module is not expected to be build.
#endif
/* In case sysconf does not return a value we need to have a limit. */
#ifdef _POSIX_OPEN_MAX

View File

@ -20,6 +20,7 @@
#ifndef LDAP_WRAPPER_H
#define LDAP_WRAPPER_H
/* ldap-wrapper.c or ldap-wrapper-ce.c */
void ldap_wrapper_launch_thread (void);
void ldap_wrapper_wait_connections (void);
void ldap_wrapper_release_context (ksba_reader_t reader);
@ -28,6 +29,10 @@ gpg_error_t ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader,
const char *argv[]);
/* dirmngr_ldap.c */
#ifndef USE_LDAPWRAPPER
int ldap_wrapper_main (int argc, char **argv, estream_t outstream);
#endif
#endif /*LDAP_WRAPPER_H*/