diff --git a/clients/tools/common.c b/clients/tools/common.c index b1edffdaf6..23829eada0 100644 --- a/clients/tools/common.c +++ b/clients/tools/common.c @@ -153,6 +153,8 @@ static int print_deref( LDAP *ld, LDAPControl *ctrl ); #ifdef LDAP_CONTROL_X_WHATFAILED static int print_whatfailed( LDAP *ld, LDAPControl *ctrl ); #endif +static int print_syncstate( LDAP *ld, LDAPControl *ctrl ); +static int print_syncdone( LDAP *ld, LDAPControl *ctrl ); static struct tool_ctrls_t { const char *oid; @@ -177,6 +179,8 @@ static struct tool_ctrls_t { #ifdef LDAP_CONTROL_X_WHATFAILED { LDAP_CONTROL_X_WHATFAILED, TOOL_ALL, print_whatfailed }, #endif + { LDAP_CONTROL_SYNC_STATE, TOOL_SEARCH, print_syncstate }, + { LDAP_CONTROL_SYNC_DONE, TOOL_SEARCH, print_syncdone }, { NULL, 0, NULL } }; @@ -2335,6 +2339,135 @@ print_whatfailed( LDAP *ld, LDAPControl *ctrl ) } #endif +static int +print_syncstate( LDAP *ld, LDAPControl *ctrl ) +{ + struct berval syncUUID, syncCookie = BER_BVNULL; + char buf[LDAP_LUTIL_UUIDSTR_BUFSIZE], *uuidstr = "(UUID malformed)"; + BerElement *ber; + ber_tag_t tag; + ber_len_t len; + ber_int_t state; + int rc; + + if ( ldif ) { + return 0; + } + + /* Create a BerElement from the berval returned in the control. */ + ber = ber_init( &ctrl->ldctl_value ); + + if ( ber == NULL ) { + return LDAP_NO_MEMORY; + } + + if ( ber_scanf( ber, "{em", &state, &syncUUID ) == LBER_ERROR ) { + ber_free( ber, 1 ); + return 1; + } + + tag = ber_get_stringbv( ber, &syncCookie, 0 ); + + rc = lutil_uuidstr_from_normalized( + syncUUID.bv_val, syncUUID.bv_len, + buf, LDAP_LUTIL_UUIDSTR_BUFSIZE ); + + if ( rc > 0 && rc < LDAP_LUTIL_UUIDSTR_BUFSIZE ) { + uuidstr = buf; + } + + switch ( state ) { + case LDAP_SYNC_PRESENT: + printf(_("# SyncState control, UUID %s present\n"), uuidstr); + break; + case LDAP_SYNC_ADD: + printf(_("# SyncState control, UUID %s added\n"), uuidstr); + break; + case LDAP_SYNC_MODIFY: + printf(_("# SyncState control, UUID %s modified\n"), uuidstr); + break; + case LDAP_SYNC_DELETE: + printf(_("# SyncState control, UUID %s deleted\n"), uuidstr); + break; + default: + ber_free( ber, 1 ); + return 1; + } + + if ( tag != LBER_ERROR ) { + if ( ldif_is_not_printable( syncCookie.bv_val, syncCookie.bv_len ) ) { + struct berval bv; + + bv.bv_len = LUTIL_BASE64_ENCODE_LEN( syncCookie.bv_len ) + 1; + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + bv.bv_len = lutil_b64_ntop( + (unsigned char *) syncCookie.bv_val, syncCookie.bv_len, + bv.bv_val, bv.bv_len ); + + printf(_("# cookie:: %s\n"), bv.bv_val ); + ber_memfree( bv.bv_val ); + } else { + printf(_("# cookie: %s\n"), syncCookie.bv_val ); + } + } + + ber_free( ber, 1 ); + return 0; +} + +static int +print_syncdone( LDAP *ld, LDAPControl *ctrl ) +{ + BerElement *ber; + struct berval cookie = BER_BVNULL; + ber_tag_t tag; + ber_len_t len; + ber_int_t refreshDeletes = 0; + + if ( ldif ) { + return 0; + } + + /* Create a BerElement from the berval returned in the control. */ + ber = ber_init( &ctrl->ldctl_value ); + + if ( ber == NULL ) { + return LDAP_NO_MEMORY; + } + + ber_skip_tag( ber, &len ); + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { + ber_scanf( ber, "m", &cookie ); + } + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) { + ber_scanf( ber, "b", &refreshDeletes ); + } + + printf(_("# SyncDone control refreshDeletes=%d\n"), refreshDeletes ? 1 : 0 ); + + if ( !BER_BVISNULL( &cookie ) ) { + if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) { + struct berval bv; + + bv.bv_len = LUTIL_BASE64_ENCODE_LEN( cookie.bv_len ) + 1; + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + bv.bv_len = lutil_b64_ntop( + (unsigned char *) cookie.bv_val, cookie.bv_len, + bv.bv_val, bv.bv_len ); + + printf(_("# cookie:: %s\n"), bv.bv_val ); + ber_memfree( bv.bv_val ); + } else { + printf(_("# cookie: %s\n"), cookie.bv_val ); + } + } + + ber_free( ber, 1 ); + return 0; +} + #ifdef LDAP_CONTROL_AUTHZID_RESPONSE static int print_authzid( LDAP *ld, LDAPControl *ctrl ) diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c index ed44ada74c..4fd08f1728 100644 --- a/clients/tools/ldapsearch.c +++ b/clients/tools/ldapsearch.c @@ -173,6 +173,9 @@ static void print_extended( LDAP *ld, LDAPMessage *extended ); +static void print_syncinfo( + BerValue *info ); + static void print_partial( LDAP *ld, LDAPMessage *partial ); @@ -1521,7 +1524,11 @@ static int dosearch( nresponses_psearch = 0; if ( strcmp( retoid, LDAP_SYNC_INFO ) == 0 ) { - printf(_("SyncInfo Received\n")); + if ( ldif < 1 ) { + print_syncinfo( retdata ); + } else if ( ldif < 2 ) { + printf(_("# SyncInfo Received\n")); + } ldap_memfree( retoid ); ber_bvfree( retdata ); break; @@ -1776,6 +1783,167 @@ static void print_extended( print_result( ld, extended, 0 ); } +static void print_syncinfo( + BerValue *data ) +{ + BerElement *syncinfo; + struct berval bv, cookie; + ber_tag_t tag; + ber_len_t len; + + if ( (syncinfo = ber_alloc()) == NULL ) { + return; + } + ber_init2( syncinfo, data, 0 ); + + printf(_("# SyncInfo Received: ")); + tag = ber_skip_tag( syncinfo, &len ); + switch (tag) { + case LDAP_TAG_SYNC_NEW_COOKIE: { + printf(_("new cookie\n")); + ber_scanf( syncinfo, "m", &cookie ); + + if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) { + bv.bv_len = LUTIL_BASE64_ENCODE_LEN( + cookie.bv_len ) + 1; + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + bv.bv_len = lutil_b64_ntop( + (unsigned char *) cookie.bv_val, + cookie.bv_len, + bv.bv_val, bv.bv_len ); + + printf(_("# cookie:: %s\n"), bv.bv_val ); + ber_memfree( bv.bv_val ); + } else { + printf(_("# cookie: %s\n"), cookie.bv_val ); + } + } break; + case LDAP_TAG_SYNC_REFRESH_DELETE: { + ber_int_t done = 1; + printf(_("refresh delete\n")); + tag = ber_peek_tag( syncinfo, &len ); + if ( tag == LDAP_TAG_SYNC_COOKIE ) { + ber_scanf( syncinfo, "m", &cookie ); + + if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) { + bv.bv_len = LUTIL_BASE64_ENCODE_LEN( + cookie.bv_len ) + 1; + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + bv.bv_len = lutil_b64_ntop( + (unsigned char *) cookie.bv_val, + cookie.bv_len, + bv.bv_val, bv.bv_len ); + + printf(_("# cookie:: %s\n"), bv.bv_val ); + ber_memfree( bv.bv_val ); + } else { + printf(_("# cookie: %s\n"), cookie.bv_val ); + } + + tag = ber_peek_tag( syncinfo, &len ); + } + if ( tag == LDAP_TAG_REFRESHDONE ) { + ber_get_boolean( syncinfo, &done ); + } + if ( done ) + printf(_("# refresh done, switching to persist stage\n")); + } break; + case LDAP_TAG_SYNC_REFRESH_PRESENT: { + ber_int_t done = 1; + printf(_("refresh present\n")); + tag = ber_peek_tag( syncinfo, &len ); + if ( tag == LDAP_TAG_SYNC_COOKIE ) { + ber_scanf( syncinfo, "m", &cookie ); + + if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) { + bv.bv_len = LUTIL_BASE64_ENCODE_LEN( + cookie.bv_len ) + 1; + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + bv.bv_len = lutil_b64_ntop( + (unsigned char *) cookie.bv_val, + cookie.bv_len, + bv.bv_val, bv.bv_len ); + + printf(_("# cookie:: %s\n"), bv.bv_val ); + ber_memfree( bv.bv_val ); + } else { + printf(_("# cookie: %s\n"), cookie.bv_val ); + } + + tag = ber_peek_tag( syncinfo, &len ); + } + if ( tag == LDAP_TAG_REFRESHDONE ) { + ber_get_boolean( syncinfo, &done ); + } + if ( done ) + printf(_("# refresh done, switching to persist stage\n")); + } break; + case LDAP_TAG_SYNC_ID_SET: { + ber_int_t refreshDeletes = 0; + BerVarray uuids; + + printf(_("ID Set\n")); + tag = ber_peek_tag( syncinfo, &len ); + if ( tag == LDAP_TAG_SYNC_COOKIE ) { + ber_scanf( syncinfo, "m", &cookie ); + + if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) { + bv.bv_len = LUTIL_BASE64_ENCODE_LEN( + cookie.bv_len ) + 1; + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + bv.bv_len = lutil_b64_ntop( + (unsigned char *) cookie.bv_val, + cookie.bv_len, + bv.bv_val, bv.bv_len ); + + printf(_("# cookie:: %s\n"), bv.bv_val ); + ber_memfree( bv.bv_val ); + } else { + printf(_("# cookie: %s\n"), cookie.bv_val ); + } + + tag = ber_peek_tag( syncinfo, &len ); + } + if ( tag == LDAP_TAG_REFRESHDELETES ) { + ber_get_boolean( syncinfo, &refreshDeletes ); + tag = ber_peek_tag( syncinfo, &len ); + } + if ( refreshDeletes ) { + printf(_("# following UUIDs no longer match the search\n")); + } + + printf(_("# syncUUIDs:\n")); + ber_scanf( syncinfo, "[W]", &uuids ); + if ( uuids ) { + char buf[LDAP_LUTIL_UUIDSTR_BUFSIZE]; + int i; + + for ( i=0; !BER_BVISNULL( &uuids[i] ); i++ ) { + int rc = lutil_uuidstr_from_normalized( + uuids[i].bv_val, uuids[i].bv_len, + buf, LDAP_LUTIL_UUIDSTR_BUFSIZE ); + if ( rc <= 0 || rc >= LDAP_LUTIL_UUIDSTR_BUFSIZE ) { + printf(_("#\t(UUID malformed)\n")); + } else { + printf(_("#\t%s\n"), buf); + } + } + ber_bvarray_free( uuids ); + } + } break; + case LBER_DEFAULT: + printf(_("empty SyncInfoValue\n")); + default: + printf(_("SyncInfoValue unknown\n")); + break; + } + ber_free( syncinfo, 0 ); +} + static void print_partial( LDAP *ld, LDAPMessage *partial )