mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-05 22:50:51 -05:00
import of LDAP Sync client API
This commit is contained in:
parent
c310cfd837
commit
5513ac6335
4 changed files with 1112 additions and 4 deletions
180
include/ldap.h
180
include/ldap.h
|
|
@ -735,6 +735,138 @@ typedef struct ldap_url_desc {
|
|||
#define LDAP_URL_ERR_BADFILTER 0x09 /* bad or missing filter */
|
||||
#define LDAP_URL_ERR_BADEXTS 0x0a /* bad or missing extensions */
|
||||
|
||||
/*
|
||||
* LDAP sync (RFC4533) API
|
||||
*/
|
||||
|
||||
typedef struct ldap_sync_t ldap_sync_t;
|
||||
|
||||
typedef enum {
|
||||
/* these are private - the client should never see them */
|
||||
LDAP_SYNC_CAPI_NONE = -1,
|
||||
|
||||
LDAP_SYNC_CAPI_PHASE_FLAG = 0x10U,
|
||||
LDAP_SYNC_CAPI_IDSET_FLAG = 0x20U,
|
||||
LDAP_SYNC_CAPI_DONE_FLAG = 0x40U,
|
||||
|
||||
/* these are passed to ls_search_entry() */
|
||||
LDAP_SYNC_CAPI_PRESENT = LDAP_SYNC_PRESENT,
|
||||
LDAP_SYNC_CAPI_ADD = LDAP_SYNC_ADD,
|
||||
LDAP_SYNC_CAPI_MODIFY = LDAP_SYNC_MODIFY,
|
||||
LDAP_SYNC_CAPI_DELETE = LDAP_SYNC_DELETE,
|
||||
|
||||
/* these are passed to ls_intermediate() */
|
||||
LDAP_SYNC_CAPI_PRESENTS = ( LDAP_SYNC_CAPI_PHASE_FLAG | LDAP_SYNC_CAPI_PRESENT ),
|
||||
LDAP_SYNC_CAPI_DELETES = ( LDAP_SYNC_CAPI_PHASE_FLAG | LDAP_SYNC_CAPI_DELETE ),
|
||||
|
||||
LDAP_SYNC_CAPI_PRESENTS_IDSET = ( LDAP_SYNC_CAPI_PRESENTS | LDAP_SYNC_CAPI_IDSET_FLAG ),
|
||||
LDAP_SYNC_CAPI_DELETES_IDSET = ( LDAP_SYNC_CAPI_DELETES | LDAP_SYNC_CAPI_IDSET_FLAG ),
|
||||
|
||||
LDAP_SYNC_CAPI_DONE = ( LDAP_SYNC_CAPI_DONE_FLAG | LDAP_SYNC_CAPI_PRESENTS )
|
||||
} ldap_sync_refresh_t;
|
||||
|
||||
/*
|
||||
* Called when an entry is returned by ldap_result().
|
||||
* If phase is LDAP_SYNC_CAPI_ADD or LDAP_SYNC_CAPI_MODIFY,
|
||||
* the entry has been either added or modified, and thus
|
||||
* the complete view of the entry should be in the LDAPMessage.
|
||||
* If phase is LDAP_SYNC_CAPI_PRESENT or LDAP_SYNC_CAPI_DELETE,
|
||||
* only the DN should be in the LDAPMessage.
|
||||
*/
|
||||
typedef int (*ldap_sync_search_entry_f) LDAP_P((
|
||||
ldap_sync_t *ls,
|
||||
LDAPMessage *msg,
|
||||
struct berval *entryUUID,
|
||||
ldap_sync_refresh_t phase ));
|
||||
|
||||
/*
|
||||
* Called when a reference is returned; the client should know
|
||||
* what to do with it.
|
||||
*/
|
||||
typedef int (*ldap_sync_search_reference_f) LDAP_P((
|
||||
ldap_sync_t *ls,
|
||||
LDAPMessage *msg ));
|
||||
|
||||
/*
|
||||
* Called when specific intermediate/final messages are returned.
|
||||
* If phase is LDAP_SYNC_CAPI_PRESENTS or LDAP_SYNC_CAPI_DELETES,
|
||||
* a "presents" or "deletes" phase begins.
|
||||
* If phase is LDAP_SYNC_CAPI_DONE, a special "presents" phase
|
||||
* with refreshDone set to "TRUE" has been returned, to indicate
|
||||
* that the refresh phase of a refreshAndPersist is complete.
|
||||
* In the above cases, syncUUIDs is NULL.
|
||||
*
|
||||
* If phase is LDAP_SYNC_CAPI_PRESENTS_IDSET or
|
||||
* LDAP_SYNC_CAPI_DELETES_IDSET, syncUUIDs is an array of UUIDs
|
||||
* that are either present or have been deleted.
|
||||
*/
|
||||
typedef int (*ldap_sync_intermediate_f) LDAP_P((
|
||||
ldap_sync_t *ls,
|
||||
LDAPMessage *msg,
|
||||
BerVarray syncUUIDs,
|
||||
ldap_sync_refresh_t phase ));
|
||||
|
||||
/*
|
||||
* Called when a searchResultDone is returned. In refreshAndPersist,
|
||||
* this can only occur if the search for any reason is being terminated
|
||||
* by the server.
|
||||
*/
|
||||
typedef int (*ldap_sync_search_result_f) LDAP_P((
|
||||
ldap_sync_t *ls,
|
||||
LDAPMessage *msg,
|
||||
int refreshDeletes ));
|
||||
|
||||
/*
|
||||
* This structure contains all information about the persistent search;
|
||||
* the caller is responsible for connecting, setting version, binding, tls...
|
||||
*/
|
||||
struct ldap_sync_t {
|
||||
/* conf search params */
|
||||
char *ls_base;
|
||||
int ls_scope;
|
||||
char *ls_filter;
|
||||
char **ls_attrs;
|
||||
int ls_timelimit;
|
||||
int ls_sizelimit;
|
||||
|
||||
/* poll timeout */
|
||||
int ls_timeout;
|
||||
|
||||
/* helpers - add as appropriate */
|
||||
ldap_sync_search_entry_f ls_search_entry;
|
||||
ldap_sync_search_reference_f ls_search_reference;
|
||||
ldap_sync_intermediate_f ls_intermediate;
|
||||
ldap_sync_search_result_f ls_search_result;
|
||||
|
||||
/* set by the caller as appropriate */
|
||||
void *ls_private;
|
||||
|
||||
/* conn stuff */
|
||||
LDAP *ls_ld;
|
||||
|
||||
/* --- the parameters below are private - do not modify --- */
|
||||
|
||||
/* FIXME: make the structure opaque, and provide an interface
|
||||
* to modify the public values? */
|
||||
|
||||
/* result stuff */
|
||||
int ls_msgid;
|
||||
|
||||
/* sync stuff */
|
||||
/* needed by refreshOnly */
|
||||
int ls_reloadHint;
|
||||
|
||||
/* opaque - need to pass between sessions, updated by the API */
|
||||
struct berval ls_cookie;
|
||||
|
||||
/* state variable - do not modify */
|
||||
ldap_sync_refresh_t ls_refreshPhase;
|
||||
};
|
||||
|
||||
/*
|
||||
* End of LDAP sync (RFC4533) API
|
||||
*/
|
||||
|
||||
/*
|
||||
* The API draft spec says we should declare (or cause to be declared)
|
||||
* 'struct timeval'. We don't. See IETF LDAPext discussions.
|
||||
|
|
@ -2120,5 +2252,53 @@ ldap_txn_end_s LDAP_P(( LDAP *ld,
|
|||
int *retidp ));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* in ldap_sync.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* initialize the persistent search structure
|
||||
*/
|
||||
LDAP_F( ldap_sync_t * )
|
||||
ldap_sync_initialize LDAP_P((
|
||||
ldap_sync_t *ls ));
|
||||
|
||||
/*
|
||||
* destroy the persistent search structure
|
||||
*/
|
||||
LDAP_F( void )
|
||||
ldap_sync_destroy LDAP_P((
|
||||
ldap_sync_t *ls,
|
||||
int freeit ));
|
||||
|
||||
/*
|
||||
* initialize a refreshOnly sync
|
||||
*/
|
||||
LDAP_F( int )
|
||||
ldap_sync_init LDAP_P((
|
||||
ldap_sync_t *ls,
|
||||
int mode ));
|
||||
|
||||
/*
|
||||
* initialize a refreshOnly sync
|
||||
*/
|
||||
LDAP_F( int )
|
||||
ldap_sync_init_refresh_only LDAP_P((
|
||||
ldap_sync_t *ls ));
|
||||
|
||||
/*
|
||||
* initialize a refreshAndPersist sync
|
||||
*/
|
||||
LDAP_F( int )
|
||||
ldap_sync_init_refresh_and_persist LDAP_P((
|
||||
ldap_sync_t *ls ));
|
||||
|
||||
/*
|
||||
* poll for new responses
|
||||
*/
|
||||
LDAP_F( int )
|
||||
ldap_sync_poll LDAP_P((
|
||||
ldap_sync_t *ls ));
|
||||
|
||||
LDAP_END_DECL
|
||||
#endif /* _LDAP_H */
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ SRCS = bind.c open.c result.c error.c compare.c search.c \
|
|||
request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
|
||||
init.c options.c print.c string.c util-int.c schema.c \
|
||||
charray.c tls.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
|
||||
turn.c ppolicy.c dds.c txn.c
|
||||
turn.c ppolicy.c dds.c txn.c ldap_sync.c
|
||||
|
||||
OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \
|
||||
controls.lo messages.lo references.lo extended.lo cyrus.lo \
|
||||
|
|
@ -37,7 +37,7 @@ OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \
|
|||
request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \
|
||||
init.lo options.lo print.lo string.lo util-int.lo schema.lo \
|
||||
charray.lo tls.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
|
||||
turn.lo ppolicy.lo dds.lo txn.lo
|
||||
turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo
|
||||
|
||||
LDAP_INCDIR= ../../include
|
||||
LDAP_LIBDIR= ../../libraries
|
||||
|
|
|
|||
928
libraries/libldap/ldap_sync.c
Normal file
928
libraries/libldap/ldap_sync.c
Normal file
|
|
@ -0,0 +1,928 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2006-2007 The OpenLDAP Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This program was originally developed by Pierangelo Masarati
|
||||
* for inclusion in OpenLDAP Software.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Proof-of-concept API that implement the client-side
|
||||
* of the "LDAP Content Sync Operation" (RFC 4533)
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <ac/time.h>
|
||||
|
||||
#include "ldap-int.h"
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
/*
|
||||
* used for debug purposes
|
||||
*/
|
||||
static char *
|
||||
print_UUID( char *buf, size_t len, unsigned char *UUID )
|
||||
{
|
||||
snprintf( buf, len,
|
||||
"%02x%02x%02x%02x-%02x%02x-%02x%02x-"
|
||||
"%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
UUID[0],
|
||||
UUID[1],
|
||||
UUID[2],
|
||||
UUID[3],
|
||||
UUID[4],
|
||||
UUID[5],
|
||||
UUID[6],
|
||||
UUID[7],
|
||||
UUID[8],
|
||||
UUID[9],
|
||||
UUID[10],
|
||||
UUID[11],
|
||||
UUID[12],
|
||||
UUID[13],
|
||||
UUID[14],
|
||||
UUID[15] );
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *
|
||||
ldap_sync_state2str( int state )
|
||||
{
|
||||
switch ( state ) {
|
||||
case LDAP_SYNC_PRESENT:
|
||||
return "LDAP_SYNC_PRESENT";
|
||||
|
||||
case LDAP_SYNC_ADD:
|
||||
return "LDAP_SYNC_ADD";
|
||||
|
||||
case LDAP_SYNC_MODIFY:
|
||||
return "LDAP_SYNC_MODIFY";
|
||||
|
||||
case LDAP_SYNC_DELETE:
|
||||
return "LDAP_SYNC_DELETE";
|
||||
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* initialize the persistent search structure
|
||||
*/
|
||||
ldap_sync_t *
|
||||
ldap_sync_initialize( ldap_sync_t *ls_in )
|
||||
{
|
||||
ldap_sync_t *ls = ls_in;
|
||||
|
||||
if ( ls == NULL ) {
|
||||
ls = ldap_memalloc( sizeof( ldap_sync_t ) );
|
||||
if ( ls == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
memset( ls, 0, sizeof( ldap_sync_t ) );
|
||||
}
|
||||
|
||||
ls->ls_scope = LDAP_SCOPE_SUBTREE;
|
||||
ls->ls_timeout = -1;
|
||||
|
||||
return ls;
|
||||
}
|
||||
|
||||
/*
|
||||
* destroy the persistent search structure
|
||||
*/
|
||||
void
|
||||
ldap_sync_destroy( ldap_sync_t *ls, int freeit )
|
||||
{
|
||||
assert( ls != NULL );
|
||||
|
||||
if ( ls->ls_base != NULL ) {
|
||||
ldap_memfree( ls->ls_base );
|
||||
ls->ls_base = NULL;
|
||||
}
|
||||
|
||||
if ( ls->ls_filter != NULL ) {
|
||||
ldap_memfree( ls->ls_filter );
|
||||
ls->ls_filter = NULL;
|
||||
}
|
||||
|
||||
if ( ls->ls_attrs != NULL ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0; ls->ls_attrs[ i ] != NULL; i++ ) {
|
||||
ldap_memfree( ls->ls_attrs[ i ] );
|
||||
}
|
||||
ldap_memfree( ls->ls_attrs );
|
||||
ls->ls_attrs = NULL;
|
||||
}
|
||||
|
||||
if ( ls->ls_ld != NULL ) {
|
||||
(void)ldap_unbind_ext( ls->ls_ld, NULL, NULL );
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "ldap_unbind_ext()\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
ls->ls_ld = NULL;
|
||||
}
|
||||
|
||||
if ( ls->ls_cookie.bv_val != NULL ) {
|
||||
ldap_memfree( ls->ls_cookie.bv_val );
|
||||
ls->ls_cookie.bv_val = NULL;
|
||||
}
|
||||
|
||||
if ( freeit ) {
|
||||
ldap_memfree( ls );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* handle the LDAP_RES_SEARCH_ENTRY response
|
||||
*/
|
||||
static int
|
||||
ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res )
|
||||
{
|
||||
LDAPControl **ctrls = NULL;
|
||||
int rc = LDAP_SUCCESS,
|
||||
i;
|
||||
BerElement *ber = NULL;
|
||||
struct berval entryUUID = { 0 },
|
||||
cookie = { 0 };
|
||||
int state = -1;
|
||||
ber_len_t len;
|
||||
ldap_sync_refresh_t phase = ls->ls_refreshPhase;
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
assert( ls != NULL );
|
||||
assert( res != NULL );
|
||||
|
||||
/* OK */
|
||||
|
||||
/* extract:
|
||||
* - data
|
||||
* - entryUUID
|
||||
*
|
||||
* check that:
|
||||
* - Sync State Control is "add"
|
||||
*/
|
||||
|
||||
/* the control MUST be present */
|
||||
|
||||
/* extract controls */
|
||||
ldap_get_entry_controls( ls->ls_ld, res, &ctrls );
|
||||
if ( ctrls == NULL ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* lookup the sync state control */
|
||||
for ( i = 0; ctrls[ i ] != NULL; i++ ) {
|
||||
if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* control must be present; there might be other... */
|
||||
if ( ctrls[ i ] == NULL ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* extract data */
|
||||
ber = ber_init( &ctrls[ i ]->ldctl_value );
|
||||
/* scan entryUUID in-place ("m") */
|
||||
ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID );
|
||||
if ( entryUUID.bv_len == 0 ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
|
||||
/* scan cookie in-place ("m") */
|
||||
ber_scanf( ber, /*"{"*/ "m}", &cookie );
|
||||
if ( cookie.bv_val != NULL ) {
|
||||
ber_bvreplace( &ls->ls_cookie, &cookie );
|
||||
}
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot cookie=%s\n",
|
||||
cookie.bv_val ? cookie.bv_val : "(null)" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
}
|
||||
|
||||
switch ( state ) {
|
||||
case LDAP_SYNC_PRESENT:
|
||||
case LDAP_SYNC_DELETE:
|
||||
case LDAP_SYNC_ADD:
|
||||
case LDAP_SYNC_MODIFY:
|
||||
/* NOTE: ldap_sync_refresh_t is defined
|
||||
* as the corresponding LDAP_SYNC_*
|
||||
* for the 4 above cases */
|
||||
phase = state;
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = LDAP_OTHER;
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot unknown syncState=%d\n", state );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( ls->ls_search_entry ) {
|
||||
rc = ls->ls_search_entry( ls, res, &entryUUID, phase );
|
||||
}
|
||||
|
||||
done:;
|
||||
if ( ber != NULL ) {
|
||||
ber_free( ber, 1 );
|
||||
}
|
||||
|
||||
if ( ctrls != NULL ) {
|
||||
ldap_controls_free( ctrls );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle the LDAP_RES_SEARCH_REFERENCE response
|
||||
* (to be implemented yet)
|
||||
*/
|
||||
static int
|
||||
ldap_sync_search_reference( ldap_sync_t *ls, LDAPMessage *res )
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\tgot LDAP_RES_SEARCH_REFERENCE\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
assert( ls != NULL );
|
||||
assert( res != NULL );
|
||||
|
||||
if ( ls->ls_search_reference ) {
|
||||
rc = ls->ls_search_reference( ls, res );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle the LDAP_RES_SEARCH_RESULT response
|
||||
*/
|
||||
static int
|
||||
ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res )
|
||||
{
|
||||
int err;
|
||||
char *matched = NULL,
|
||||
*msg = NULL;
|
||||
LDAPControl **ctrls = NULL;
|
||||
int rc;
|
||||
int refreshDeletes = -1;
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
assert( ls != NULL );
|
||||
assert( res != NULL );
|
||||
|
||||
/* should not happen in refreshAndPersist... */
|
||||
rc = ldap_parse_result( ls->ls_ld,
|
||||
res, &err, &matched, &msg, NULL, &ctrls, 0 );
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr,
|
||||
"\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n",
|
||||
err,
|
||||
matched ? matched : "",
|
||||
msg ? msg : "",
|
||||
rc );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
if ( rc == LDAP_SUCCESS ) {
|
||||
rc = err;
|
||||
}
|
||||
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
|
||||
|
||||
switch ( rc ) {
|
||||
case LDAP_SUCCESS: {
|
||||
int i;
|
||||
BerElement *ber = NULL;
|
||||
ber_len_t len;
|
||||
struct berval cookie = { 0 };
|
||||
|
||||
/* deal with control; then fallthru to handler */
|
||||
if ( ctrls == NULL ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* lookup the sync state control */
|
||||
for ( i = 0; ctrls[ i ] != NULL; i++ ) {
|
||||
if ( strcmp( ctrls[ i ]->ldctl_oid,
|
||||
LDAP_CONTROL_SYNC_DONE ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* control must be present; there might be other... */
|
||||
if ( ctrls[ i ] == NULL ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* extract data */
|
||||
ber = ber_init( &ctrls[ i ]->ldctl_value );
|
||||
|
||||
ber_scanf( ber, "{" /*"}"*/);
|
||||
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
|
||||
ber_scanf( ber, "m", &cookie );
|
||||
if ( cookie.bv_val != NULL ) {
|
||||
ber_bvreplace( &ls->ls_cookie, &cookie );
|
||||
}
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot cookie=%s\n",
|
||||
cookie.bv_val ? cookie.bv_val : "(null)" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
}
|
||||
|
||||
refreshDeletes = 0;
|
||||
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
|
||||
ber_scanf( ber, "b", &refreshDeletes );
|
||||
if ( refreshDeletes ) {
|
||||
refreshDeletes = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ber_scanf( ber, /*"{"*/ "}" );
|
||||
|
||||
/* NOTE: if any goto/return between ber_init() and here
|
||||
* is introduced, don't forget to ber_free() */
|
||||
ber_free( ber, 1 );
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
|
||||
refreshDeletes ? "TRUE" : "FALSE" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
/* FIXME: what should we do with the refreshDelete? */
|
||||
switch ( refreshDeletes ) {
|
||||
case 0:
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
|
||||
break;
|
||||
|
||||
default:
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
|
||||
break;
|
||||
}
|
||||
|
||||
} /* fallthru */
|
||||
|
||||
case LDAP_SYNC_REFRESH_REQUIRED:
|
||||
/* TODO: check for Sync Done Control */
|
||||
/* FIXME: perhaps the handler should be called
|
||||
* also in case of failure; we'll deal with this
|
||||
* later when implementing refreshOnly */
|
||||
if ( ls->ls_search_result ) {
|
||||
err = ls->ls_search_result( ls, res, refreshDeletes );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
done:;
|
||||
if ( matched != NULL ) {
|
||||
ldap_memfree( matched );
|
||||
}
|
||||
|
||||
if ( msg != NULL ) {
|
||||
ldap_memfree( msg );
|
||||
}
|
||||
|
||||
if ( ctrls != NULL ) {
|
||||
ldap_controls_free( ctrls );
|
||||
}
|
||||
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle the LDAP_RES_INTERMEDIATE response
|
||||
*/
|
||||
static int
|
||||
ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone )
|
||||
{
|
||||
int rc;
|
||||
char *retoid = NULL;
|
||||
struct berval *retdata = NULL;
|
||||
BerElement *ber = NULL;
|
||||
ber_len_t len;
|
||||
ber_tag_t tag,
|
||||
syncinfo_tag;
|
||||
struct berval cookie;
|
||||
int refreshDeletes = 0;
|
||||
BerVarray syncUUIDs = NULL;
|
||||
ldap_sync_refresh_t phase;
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
assert( ls != NULL );
|
||||
assert( res != NULL );
|
||||
assert( refreshDone != NULL );
|
||||
|
||||
*refreshDone = 0;
|
||||
|
||||
rc = ldap_parse_intermediate( ls->ls_ld, res,
|
||||
&retoid, &retdata, NULL, 0 );
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n",
|
||||
rc != LDAP_SUCCESS ? "!!! " : "",
|
||||
retoid == NULL ? "\"\"" : retoid,
|
||||
rc );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
/* parsing must be successful, and yield the OID
|
||||
* of the sync info intermediate response */
|
||||
if ( rc != LDAP_SUCCESS ) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* init ber using the value in the response */
|
||||
ber = ber_init( retdata );
|
||||
if ( ber == NULL ) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
syncinfo_tag = ber_peek_tag( ber, &len );
|
||||
switch ( syncinfo_tag ) {
|
||||
case LDAP_TAG_SYNC_NEW_COOKIE:
|
||||
ber_scanf( ber, "tm", &tag, &cookie );
|
||||
if ( cookie.bv_val != NULL ) {
|
||||
ber_bvreplace( &ls->ls_cookie, &cookie );
|
||||
}
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot cookie=%s\n",
|
||||
cookie.bv_val ? cookie.bv_val : "(null)" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
break;
|
||||
|
||||
case LDAP_TAG_SYNC_REFRESH_DELETE:
|
||||
case LDAP_TAG_SYNC_REFRESH_PRESENT:
|
||||
if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot refreshDelete\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
switch ( ls->ls_refreshPhase ) {
|
||||
case LDAP_SYNC_CAPI_NONE:
|
||||
case LDAP_SYNC_CAPI_PRESENTS:
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* TODO: impossible; handle */
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
} else {
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot refreshPresent\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
switch ( ls->ls_refreshPhase ) {
|
||||
case LDAP_SYNC_CAPI_NONE:
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* TODO: impossible; handle */
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ber_scanf( ber, "t{" /*"}"*/, &tag );
|
||||
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
|
||||
ber_scanf( ber, "m", &cookie );
|
||||
if ( cookie.bv_val != NULL ) {
|
||||
ber_bvreplace( &ls->ls_cookie, &cookie );
|
||||
}
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot cookie=%s\n",
|
||||
cookie.bv_val ? cookie.bv_val : "(null)" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
}
|
||||
|
||||
*refreshDone = 1;
|
||||
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) {
|
||||
ber_scanf( ber, "b", refreshDone );
|
||||
}
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot refreshDone=%s\n",
|
||||
*refreshDone ? "TRUE" : "FALSE" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
ber_scanf( ber, /*"{"*/ "}" );
|
||||
|
||||
if ( *refreshDone ) {
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
|
||||
}
|
||||
|
||||
if ( ls->ls_intermediate ) {
|
||||
ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LDAP_TAG_SYNC_ID_SET:
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot syncIdSet\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
ber_scanf( ber, "t{" /*"}"*/, &tag );
|
||||
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
|
||||
ber_scanf( ber, "m", &cookie );
|
||||
if ( cookie.bv_val != NULL ) {
|
||||
ber_bvreplace( &ls->ls_cookie, &cookie );
|
||||
}
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tgot cookie=%s\n",
|
||||
cookie.bv_val ? cookie.bv_val : "(null)" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
}
|
||||
|
||||
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
|
||||
ber_scanf( ber, "b", &refreshDeletes );
|
||||
}
|
||||
|
||||
ber_scanf( ber, "[W]", &syncUUIDs );
|
||||
ber_scanf( ber, /*"{"*/ "}" );
|
||||
if ( syncUUIDs == NULL ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
|
||||
refreshDeletes ? "TRUE" : "FALSE" );
|
||||
for ( i = 0; syncUUIDs[ i ].bv_val != NULL; i++ ) {
|
||||
char buf[ BUFSIZ ];
|
||||
fprintf( stderr, "\t\t%s\n",
|
||||
print_UUID( buf, sizeof( buf ),
|
||||
(unsigned char *)syncUUIDs[ i ].bv_val ) );
|
||||
}
|
||||
}
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
if ( refreshDeletes ) {
|
||||
phase = LDAP_SYNC_CAPI_DELETES_IDSET;
|
||||
|
||||
} else {
|
||||
phase = LDAP_SYNC_CAPI_PRESENTS_IDSET;
|
||||
}
|
||||
|
||||
/* FIXME: should touch ls->ls_refreshPhase? */
|
||||
if ( ls->ls_intermediate ) {
|
||||
ls->ls_intermediate( ls, res, syncUUIDs, phase );
|
||||
}
|
||||
|
||||
ber_bvarray_free( syncUUIDs );
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\t\tunknown tag!\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:;
|
||||
if ( ber != NULL ) {
|
||||
ber_free( ber, 1 );
|
||||
}
|
||||
|
||||
if ( retoid != NULL ) {
|
||||
ldap_memfree( retoid );
|
||||
}
|
||||
|
||||
if ( retdata != NULL ) {
|
||||
ber_bvfree( retdata );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the sync
|
||||
*/
|
||||
int
|
||||
ldap_sync_init( ldap_sync_t *ls, int mode )
|
||||
{
|
||||
LDAPControl ctrl = { 0 },
|
||||
*ctrls[ 2 ];
|
||||
BerElement *ber = NULL;
|
||||
int rc;
|
||||
struct timeval tv = { 0 },
|
||||
*tvp = NULL;
|
||||
LDAPMessage *res = NULL;
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "ldap_sync_init(%s)...\n",
|
||||
mode == LDAP_SYNC_REFRESH_AND_PERSIST ?
|
||||
"LDAP_SYNC_REFRESH_AND_PERSIST" :
|
||||
( mode == LDAP_SYNC_REFRESH_ONLY ?
|
||||
"LDAP_SYNC_REFRESH_ONLY" : "unknown" ) );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
assert( ls != NULL );
|
||||
assert( ls->ls_ld != NULL );
|
||||
|
||||
/* support both refreshOnly and refreshAndPersist */
|
||||
switch ( mode ) {
|
||||
case LDAP_SYNC_REFRESH_AND_PERSIST:
|
||||
case LDAP_SYNC_REFRESH_ONLY:
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf( stderr, "ldap_sync_init: unknown mode=%d\n", mode );
|
||||
return LDAP_PARAM_ERROR;
|
||||
}
|
||||
|
||||
/* check consistency of cookie and reloadHint at initial refresh */
|
||||
if ( ls->ls_cookie.bv_val == NULL && ls->ls_reloadHint != 0 ) {
|
||||
fprintf( stderr, "ldap_sync_init: inconsistent cookie/rhint\n" );
|
||||
return LDAP_PARAM_ERROR;
|
||||
}
|
||||
|
||||
ctrls[ 0 ] = &ctrl;
|
||||
ctrls[ 1 ] = NULL;
|
||||
|
||||
/* prepare the Sync Request control */
|
||||
ber = ber_alloc_t( LBER_USE_DER );
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "%sber_alloc_t() %s= NULL\n",
|
||||
ber == NULL ? "!!! " : "",
|
||||
ber == NULL ? "=" : "!" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
if ( ber == NULL ) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ls->ls_refreshPhase = LDAP_SYNC_CAPI_NONE;
|
||||
|
||||
if ( ls->ls_cookie.bv_val != NULL ) {
|
||||
ber_printf( ber, "{eOb}", mode,
|
||||
&ls->ls_cookie, ls->ls_reloadHint );
|
||||
|
||||
} else {
|
||||
ber_printf( ber, "{eb}", mode, ls->ls_reloadHint );
|
||||
}
|
||||
|
||||
rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 );
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr,
|
||||
"%sber_flatten2() == %d\n",
|
||||
rc ? "!!! " : "",
|
||||
rc );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
if ( rc == LBER_ERROR ) {
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* make the control critical, as we cannot proceed without */
|
||||
ctrl.ldctl_oid = LDAP_CONTROL_SYNC;
|
||||
ctrl.ldctl_iscritical = 1;
|
||||
|
||||
/* timelimit? */
|
||||
if ( ls->ls_timelimit ) {
|
||||
tv.tv_sec = ls->ls_timelimit;
|
||||
tvp = &tv;
|
||||
}
|
||||
|
||||
/* actually run the search */
|
||||
rc = ldap_search_ext( ls->ls_ld,
|
||||
ls->ls_base, ls->ls_scope, ls->ls_filter,
|
||||
ls->ls_attrs, 0, ctrls, NULL,
|
||||
tvp, ls->ls_sizelimit, &ls->ls_msgid );
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr,
|
||||
"%sldap_search_ext(\"%s\", %d, \"%s\") == %d\n",
|
||||
rc ? "!!! " : "",
|
||||
ls->ls_base, ls->ls_scope, ls->ls_filter, rc );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
if ( rc != LDAP_SUCCESS ) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* initial content/content update phase */
|
||||
for ( ; ; ) {
|
||||
LDAPMessage *msg = NULL;
|
||||
|
||||
/* NOTE: this very short timeout is just to let
|
||||
* ldap_result() yield long enough to get something */
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100000;
|
||||
|
||||
rc = ldap_result( ls->ls_ld, ls->ls_msgid,
|
||||
LDAP_MSG_RECEIVED, &tv, &res );
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr,
|
||||
"\t%sldap_result(%d) == %d\n",
|
||||
rc == -1 ? "!!! " : "",
|
||||
ls->ls_msgid, rc );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
switch ( rc ) {
|
||||
case 0:
|
||||
/*
|
||||
* timeout
|
||||
*
|
||||
* TODO: can do something else in the meanwhile)
|
||||
*/
|
||||
break;
|
||||
|
||||
case -1:
|
||||
/* smtg bad! */
|
||||
goto done;
|
||||
|
||||
default:
|
||||
for ( msg = ldap_first_message( ls->ls_ld, res );
|
||||
msg != NULL;
|
||||
msg = ldap_next_message( ls->ls_ld, msg ) )
|
||||
{
|
||||
int refreshDone;
|
||||
|
||||
switch ( ldap_msgtype( msg ) ) {
|
||||
case LDAP_RES_SEARCH_ENTRY:
|
||||
rc = ldap_sync_search_entry( ls, res );
|
||||
break;
|
||||
|
||||
case LDAP_RES_SEARCH_REFERENCE:
|
||||
rc = ldap_sync_search_reference( ls, res );
|
||||
break;
|
||||
|
||||
case LDAP_RES_SEARCH_RESULT:
|
||||
rc = ldap_sync_search_result( ls, res );
|
||||
goto done_search;
|
||||
|
||||
case LDAP_RES_INTERMEDIATE:
|
||||
rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
|
||||
if ( rc != LDAP_SUCCESS || refreshDone ) {
|
||||
goto done_search;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\tgot something unexpected...\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
ldap_msgfree( res );
|
||||
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ldap_msgfree( res );
|
||||
res = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done_search:;
|
||||
ldap_msgfree( res );
|
||||
|
||||
done:;
|
||||
if ( ber != NULL ) {
|
||||
ber_free( ber, 1 );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the refreshOnly sync
|
||||
*/
|
||||
int
|
||||
ldap_sync_init_refresh_only( ldap_sync_t *ls )
|
||||
{
|
||||
return ldap_sync_init( ls, LDAP_SYNC_REFRESH_ONLY );
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the refreshAndPersist sync
|
||||
*/
|
||||
int
|
||||
ldap_sync_init_refresh_and_persist( ldap_sync_t *ls )
|
||||
{
|
||||
return ldap_sync_init( ls, LDAP_SYNC_REFRESH_AND_PERSIST );
|
||||
}
|
||||
|
||||
/*
|
||||
* poll for new responses
|
||||
*/
|
||||
int
|
||||
ldap_sync_poll( ldap_sync_t *ls )
|
||||
{
|
||||
struct timeval tv,
|
||||
*tvp = NULL;
|
||||
LDAPMessage *res = NULL,
|
||||
*msg;
|
||||
int rc = 0;
|
||||
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "ldap_sync_poll...\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
assert( ls != NULL );
|
||||
assert( ls->ls_ld != NULL );
|
||||
|
||||
if ( ls->ls_timeout != -1 ) {
|
||||
tv.tv_sec = ls->ls_timeout;
|
||||
tv.tv_usec = 0;
|
||||
tvp = &tv;
|
||||
}
|
||||
|
||||
rc = ldap_result( ls->ls_ld, ls->ls_msgid,
|
||||
LDAP_MSG_RECEIVED, tvp, &res );
|
||||
if ( rc <= 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
for ( msg = ldap_first_message( ls->ls_ld, res );
|
||||
msg;
|
||||
msg = ldap_next_message( ls->ls_ld, msg ) )
|
||||
{
|
||||
int refreshDone;
|
||||
|
||||
switch ( ldap_msgtype( msg ) ) {
|
||||
case LDAP_RES_SEARCH_ENTRY:
|
||||
rc = ldap_sync_search_entry( ls, res );
|
||||
break;
|
||||
|
||||
case LDAP_RES_SEARCH_REFERENCE:
|
||||
rc = ldap_sync_search_reference( ls, res );
|
||||
break;
|
||||
|
||||
case LDAP_RES_SEARCH_RESULT:
|
||||
rc = ldap_sync_search_result( ls, res );
|
||||
goto done_search;
|
||||
|
||||
case LDAP_RES_INTERMEDIATE:
|
||||
rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
|
||||
if ( rc != LDAP_SUCCESS || refreshDone ) {
|
||||
goto done_search;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef LDAP_SYNC_TRACE
|
||||
fprintf( stderr, "\tgot something unexpected...\n" );
|
||||
#endif /* LDAP_SYNC_TRACE */
|
||||
|
||||
ldap_msgfree( res );
|
||||
|
||||
rc = LDAP_OTHER;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done_search:;
|
||||
ldap_msgfree( res );
|
||||
|
||||
done:;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ XXSRCS = apitest.c test.c \
|
|||
request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
|
||||
init.c options.c print.c string.c util-int.c schema.c \
|
||||
charray.c tls.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
|
||||
turn.c ppolicy.c dds.c txn.c
|
||||
turn.c ppolicy.c dds.c txn.c ldap_sync.c
|
||||
SRCS = threads.c rdwr.c rmutex.c tpool.c rq.c \
|
||||
thr_posix.c thr_cthreads.c thr_thr.c thr_lwp.c thr_nt.c \
|
||||
thr_pth.c thr_stub.c thr_debug.c
|
||||
|
|
@ -44,7 +44,7 @@ OBJS = threads.lo rdwr.lo rmutex.lo tpool.lo rq.lo \
|
|||
request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \
|
||||
init.lo options.lo print.lo string.lo util-int.lo schema.lo \
|
||||
charray.lo tls.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
|
||||
turn.lo ppolicy.lo dds.lo txn.lo
|
||||
turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo
|
||||
|
||||
LDAP_INCDIR= ../../include
|
||||
LDAP_LIBDIR= ../../libraries
|
||||
|
|
|
|||
Loading…
Reference in a new issue