/* * Authors: Petr Spacek * * Copyright (C) 2013 Red Hat * see file 'COPYING' for use and warranty information * * This program 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; version 2 or later * * This program 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define LDAP_DEPRECATED 1 #include #include #include #include #include #include #define INDENT " " /** * The cookie value needn't be printable value. Don't this at home! */ void print_cookie(ldap_sync_t *ls) { printf(INDENT "cookie "); if (ls->ls_cookie.bv_len == 0) printf("is not present\n"); else printf("'%2$.*1$s' (length %1$u bytes)\n", (int)ls->ls_cookie.bv_len, ls->ls_cookie.bv_val); } void print_dn(LDAP *ld, LDAPMessage *entry) { char *dn = ldap_get_dn(ld, entry); printf(INDENT "DN: %s\n", dn); ldap_memfree(dn); } void print_values(LDAP *ld, LDAPMessage *entry) { BerElement *attr_ptr = NULL; struct berval **val_array = NULL; struct berval *val = NULL; char *attr_name = NULL; entry = ldap_first_entry(ld, entry); for ( attr_name = ldap_first_attribute(ld, entry, &attr_ptr); attr_name != NULL; attr_name = ldap_next_attribute(ld, entry, attr_ptr)) { val_array = ldap_get_values_len(ld, entry, attr_name); for (val = *val_array; val != NULL; val = *(++val_array)) { printf(INDENT INDENT "attribute %1$s: '%3$.*2$s' (length %2$d byte%4$s)\n", attr_name, (int)val->bv_len, val->bv_val, ((int)val->bv_len == 1) ? "": "s"); } } } #define PRINT_ENUM(name) { case name: txt = __STRING(name); break; } void print_phase(ldap_sync_refresh_t phase) { char *txt = NULL; printf(INDENT "phase: "); switch (phase) { PRINT_ENUM(LDAP_SYNC_CAPI_NONE); PRINT_ENUM(LDAP_SYNC_CAPI_IDSET_FLAG); PRINT_ENUM(LDAP_SYNC_CAPI_DONE_FLAG); PRINT_ENUM(LDAP_SYNC_CAPI_PRESENT); PRINT_ENUM(LDAP_SYNC_CAPI_ADD); PRINT_ENUM(LDAP_SYNC_CAPI_MODIFY); PRINT_ENUM(LDAP_SYNC_CAPI_DELETE); PRINT_ENUM(LDAP_SYNC_CAPI_PRESENTS); PRINT_ENUM(LDAP_SYNC_CAPI_DELETES); PRINT_ENUM(LDAP_SYNC_CAPI_PRESENTS_IDSET); PRINT_ENUM(LDAP_SYNC_CAPI_DELETES_IDSET); PRINT_ENUM(LDAP_SYNC_CAPI_DONE); } printf("%s (0x%X)\n", txt, phase); } void print_uuid(struct berval *entryUUID) { for (ber_len_t i = 0; i < entryUUID->bv_len; i++) { if (i == 4 || i == 6 || i == 8 || i == 10) printf("-"); printf("%02x", (unsigned char)entryUUID->bv_val[i]); } printf(" (length %d bytes = %d bits)", (int)entryUUID->bv_len, (int)entryUUID->bv_len*8); } void assert_entry(LDAP *ld, LDAPMessage *result, int expected) { int count = ldap_count_entries(ld, result); if (count != expected) { printf("expected %d entries\n", expected); assert("ldap_count_entries() != expected" == NULL); } } void print_entry_count(LDAP *ld, LDAPMessage *msg) { printf(INDENT "entry count: %u\n", ldap_count_entries(ld, msg)); } /* * 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. */ int ldap_sync_search_entry ( ldap_sync_t *ls, LDAPMessage *msg, struct berval *entryUUID, ldap_sync_refresh_t phase ) { printf("ldap_sync_search_entry:\n"); print_cookie(ls); print_phase(phase); print_entry_count(ls->ls_ld, msg); assert_entry(ls->ls_ld, msg, 1); printf(INDENT "entryUUID: "); print_uuid(entryUUID); printf("\n"); print_dn(ls->ls_ld, msg); print_values(ls->ls_ld, msg); printf("\n"); return 0; } /* * Called when a reference is returned. */ int ldap_sync_search_reference ( ldap_sync_t *ls, LDAPMessage *msg ) { printf("ldap_sync_search_reference\n"); print_entry_count(ls->ls_ld, msg); assert_entry(ls->ls_ld, msg, 1); printf("\n"); return 0; } /* * 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. */ int ldap_sync_intermediate ( ldap_sync_t *ls, LDAPMessage *msg, BerVarray syncUUIDs, ldap_sync_refresh_t phase ) { printf("ldap_sync_intermediate:\n"); print_cookie(ls); print_phase(phase); if (phase == LDAP_SYNC_CAPI_DONE) printf(INDENT INDENT "=> refresh phase is complete\n"); else if (phase == LDAP_SYNC_CAPI_PRESENTS_IDSET) printf(INDENT INDENT "=> only entries with following UUIDs are present:\n"); else if (phase == LDAP_SYNC_CAPI_DELETES_IDSET) printf(INDENT INDENT "=> entries with following UUIDs were deleted:\n"); else assert("unsupported code" == NULL); if (phase != LDAP_SYNC_CAPI_DONE) while ((*syncUUIDs).bv_len != 0) { printf(INDENT INDENT); print_uuid(syncUUIDs); printf("\n"); syncUUIDs++; } print_entry_count(ls->ls_ld, msg); assert_entry(ls->ls_ld, msg, 0); printf("\n"); return 0; } /* * Called when a searchResultDone is returned. In refreshAndPersist, * this can only occur if the search for any reason is being terminated * by the server. */ int ldap_sync_search_result ( ldap_sync_t *ls, LDAPMessage *msg, int refreshDeletes ) { printf("ldap_sync_search_result:\n"); printf(INDENT "refreshDeletes: %u\n", refreshDeletes); print_entry_count(ls->ls_ld, msg); assert_entry(ls->ls_ld, msg, 0); print_cookie(ls); printf("\n"); return 0; } int main( int argc, char *argv[] ) { LDAP *ld; int result; int auth_method = LDAP_AUTH_SIMPLE; int desired_version = LDAP_VERSION3; char *ldap_url = "ldap://localhost"; char *root_dn = "uid=admin,cn=users,cn=accounts,dc=ipa,dc=test"; char *root_pw = "root4lab"; ldap_sync_t sync_ctx; /* Initialize LDAP connection */ if (ldap_initialize(&ld, ldap_url) != LDAP_OPT_SUCCESS) { ldap_perror(ld, "ldap_initialize"); exit(EXIT_FAILURE); } if (ldap_sync_initialize(&sync_ctx) == NULL) { ldap_perror(ld, "ldap_sync_initialize"); exit(EXIT_FAILURE); } sync_ctx.ls_base = "cn=dns-short,dc=ipa,dc=test"; sync_ctx.ls_ld = ld; sync_ctx.ls_search_entry = ldap_sync_search_entry; sync_ctx.ls_search_reference = ldap_sync_search_reference; sync_ctx.ls_intermediate = ldap_sync_intermediate; sync_ctx.ls_search_result = ldap_sync_search_result; #define INITIAL_SYNC_COOKIE "rid=000,csn=20130710145447.752775Z#000000#000#000000" /* comment out following line if you want to start without cookie */ sync_ctx.ls_cookie = *ber_bvstrdup(INITIAL_SYNC_COOKIE); /* set the LDAP version to be 3 */ if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &desired_version) != LDAP_OPT_SUCCESS) { ldap_perror(ld, "ldap_set_option"); exit(EXIT_FAILURE); } if (ldap_bind_s(ld, root_dn, root_pw, auth_method) != LDAP_SUCCESS ) { ldap_perror( ld, "ldap_bind" ); exit(EXIT_FAILURE); } /* the other option is LDAP_SYNC_REFRESH_ONLY */ if (ldap_sync_init(&sync_ctx, LDAP_SYNC_REFRESH_AND_PERSIST) != LDAP_SUCCESS) { ldap_perror(ld, "ldap_sync_init"); exit(EXIT_FAILURE); } /* comment following line out if you want to use LDAP_SYNC_REFRESH_ONLY */ while ((result = ldap_sync_poll(&sync_ctx)) == LDAP_SUCCESS) ; ldap_perror(ld, "ldap_sync_poll"); result = ldap_unbind_s(ld); if (result != LDAP_SUCCESS) { fprintf(stderr, "ldap_unbind_s: %s\n", ldap_err2string(result)); exit(EXIT_FAILURE); } // this crashes because ls_base is not allocated by ldap_mem* // ldap_sync_destroy(&sync_ctx, 0); return EXIT_SUCCESS; }