ldap_sync.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. /* $OpenLDAP$ */
  2. /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  3. *
  4. * Copyright 2006-2022 The OpenLDAP Foundation.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted only as authorized by the OpenLDAP
  9. * Public License.
  10. *
  11. * A copy of this license is available in the file LICENSE in the
  12. * top-level directory of the distribution or, alternatively, at
  13. * <http://www.OpenLDAP.org/license.html>.
  14. */
  15. /* ACKNOWLEDGEMENTS:
  16. * This program was originally developed by Pierangelo Masarati
  17. * for inclusion in OpenLDAP Software.
  18. */
  19. /*
  20. * Proof-of-concept API that implement the client-side
  21. * of the "LDAP Content Sync Operation" (RFC 4533)
  22. */
  23. #include "portable.h"
  24. #include <ac/time.h>
  25. #include "ldap-int.h"
  26. #ifdef LDAP_SYNC_TRACE
  27. static const char *
  28. ldap_sync_state2str( int state )
  29. {
  30. switch ( state ) {
  31. case LDAP_SYNC_PRESENT:
  32. return "LDAP_SYNC_PRESENT";
  33. case LDAP_SYNC_ADD:
  34. return "LDAP_SYNC_ADD";
  35. case LDAP_SYNC_MODIFY:
  36. return "LDAP_SYNC_MODIFY";
  37. case LDAP_SYNC_DELETE:
  38. return "LDAP_SYNC_DELETE";
  39. default:
  40. return "(unknown)";
  41. }
  42. }
  43. #endif
  44. /*
  45. * initialize the persistent search structure
  46. */
  47. ldap_sync_t *
  48. ldap_sync_initialize( ldap_sync_t *ls_in )
  49. {
  50. ldap_sync_t *ls = ls_in;
  51. if ( ls == NULL ) {
  52. ls = ldap_memalloc( sizeof( ldap_sync_t ) );
  53. if ( ls == NULL ) {
  54. return NULL;
  55. }
  56. }
  57. memset( ls, 0, sizeof( ldap_sync_t ) );
  58. ls->ls_scope = LDAP_SCOPE_SUBTREE;
  59. ls->ls_timeout = -1;
  60. return ls;
  61. }
  62. /*
  63. * destroy the persistent search structure
  64. */
  65. void
  66. ldap_sync_destroy( ldap_sync_t *ls, int freeit )
  67. {
  68. assert( ls != NULL );
  69. if ( ls->ls_base != NULL ) {
  70. ldap_memfree( ls->ls_base );
  71. ls->ls_base = NULL;
  72. }
  73. if ( ls->ls_filter != NULL ) {
  74. ldap_memfree( ls->ls_filter );
  75. ls->ls_filter = NULL;
  76. }
  77. if ( ls->ls_attrs != NULL ) {
  78. int i;
  79. for ( i = 0; ls->ls_attrs[ i ] != NULL; i++ ) {
  80. ldap_memfree( ls->ls_attrs[ i ] );
  81. }
  82. ldap_memfree( ls->ls_attrs );
  83. ls->ls_attrs = NULL;
  84. }
  85. if ( ls->ls_ld != NULL ) {
  86. (void)ldap_unbind_ext( ls->ls_ld, NULL, NULL );
  87. #ifdef LDAP_SYNC_TRACE
  88. fprintf( stderr, "ldap_unbind_ext()\n" );
  89. #endif /* LDAP_SYNC_TRACE */
  90. ls->ls_ld = NULL;
  91. }
  92. if ( ls->ls_cookie.bv_val != NULL ) {
  93. ldap_memfree( ls->ls_cookie.bv_val );
  94. ls->ls_cookie.bv_val = NULL;
  95. }
  96. if ( freeit ) {
  97. ldap_memfree( ls );
  98. }
  99. }
  100. /*
  101. * handle the LDAP_RES_SEARCH_ENTRY response
  102. */
  103. static int
  104. ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res )
  105. {
  106. LDAPControl **ctrls = NULL;
  107. int rc = LDAP_OTHER,
  108. i;
  109. BerElement *ber = NULL;
  110. struct berval entryUUID = { 0 },
  111. cookie = { 0 };
  112. int state = -1;
  113. ber_len_t len;
  114. ldap_sync_refresh_t phase;
  115. #ifdef LDAP_SYNC_TRACE
  116. fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" );
  117. #endif /* LDAP_SYNC_TRACE */
  118. assert( ls != NULL );
  119. assert( res != NULL );
  120. phase = ls->ls_refreshPhase;
  121. /* OK */
  122. /* extract:
  123. * - data
  124. * - entryUUID
  125. *
  126. * check that:
  127. * - Sync State Control is "add"
  128. */
  129. /* the control MUST be present */
  130. /* extract controls */
  131. ldap_get_entry_controls( ls->ls_ld, res, &ctrls );
  132. if ( ctrls == NULL ) {
  133. goto done;
  134. }
  135. /* lookup the sync state control */
  136. for ( i = 0; ctrls[ i ] != NULL; i++ ) {
  137. if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) {
  138. break;
  139. }
  140. }
  141. /* control must be present; there might be other... */
  142. if ( ctrls[ i ] == NULL ) {
  143. goto done;
  144. }
  145. /* extract data */
  146. ber = ber_init( &ctrls[ i ]->ldctl_value );
  147. if ( ber == NULL ) {
  148. goto done;
  149. }
  150. /* scan entryUUID in-place ("m") */
  151. if ( ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID ) == LBER_ERROR
  152. || entryUUID.bv_len == 0 )
  153. {
  154. goto done;
  155. }
  156. if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
  157. /* scan cookie in-place ("m") */
  158. if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) == LBER_ERROR ) {
  159. goto done;
  160. }
  161. if ( cookie.bv_val != NULL ) {
  162. ber_bvreplace( &ls->ls_cookie, &cookie );
  163. }
  164. #ifdef LDAP_SYNC_TRACE
  165. fprintf( stderr, "\t\tgot cookie=%s\n",
  166. cookie.bv_val ? cookie.bv_val : "(null)" );
  167. #endif /* LDAP_SYNC_TRACE */
  168. }
  169. switch ( state ) {
  170. case LDAP_SYNC_PRESENT:
  171. case LDAP_SYNC_DELETE:
  172. case LDAP_SYNC_ADD:
  173. case LDAP_SYNC_MODIFY:
  174. /* NOTE: ldap_sync_refresh_t is defined
  175. * as the corresponding LDAP_SYNC_*
  176. * for the 4 above cases */
  177. phase = state;
  178. #ifdef LDAP_SYNC_TRACE
  179. fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) );
  180. #endif /* LDAP_SYNC_TRACE */
  181. break;
  182. default:
  183. #ifdef LDAP_SYNC_TRACE
  184. fprintf( stderr, "\t\tgot unknown syncState=%d\n", state );
  185. #endif /* LDAP_SYNC_TRACE */
  186. goto done;
  187. }
  188. rc = ls->ls_search_entry
  189. ? ls->ls_search_entry( ls, res, &entryUUID, phase )
  190. : LDAP_SUCCESS;
  191. done:;
  192. if ( ber != NULL ) {
  193. ber_free( ber, 1 );
  194. }
  195. if ( ctrls != NULL ) {
  196. ldap_controls_free( ctrls );
  197. }
  198. return rc;
  199. }
  200. /*
  201. * handle the LDAP_RES_SEARCH_REFERENCE response
  202. * (to be implemented yet)
  203. */
  204. static int
  205. ldap_sync_search_reference( ldap_sync_t *ls, LDAPMessage *res )
  206. {
  207. int rc = 0;
  208. #ifdef LDAP_SYNC_TRACE
  209. fprintf( stderr, "\tgot LDAP_RES_SEARCH_REFERENCE\n" );
  210. #endif /* LDAP_SYNC_TRACE */
  211. assert( ls != NULL );
  212. assert( res != NULL );
  213. if ( ls->ls_search_reference ) {
  214. rc = ls->ls_search_reference( ls, res );
  215. }
  216. return rc;
  217. }
  218. /*
  219. * handle the LDAP_RES_SEARCH_RESULT response
  220. */
  221. static int
  222. ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res )
  223. {
  224. int err;
  225. char *matched = NULL,
  226. *msg = NULL;
  227. LDAPControl **ctrls = NULL;
  228. int rc;
  229. int refreshDeletes = -1;
  230. #ifdef LDAP_SYNC_TRACE
  231. fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" );
  232. #endif /* LDAP_SYNC_TRACE */
  233. assert( ls != NULL );
  234. assert( res != NULL );
  235. /* should not happen in refreshAndPersist... */
  236. rc = ldap_parse_result( ls->ls_ld,
  237. res, &err, &matched, &msg, NULL, &ctrls, 0 );
  238. #ifdef LDAP_SYNC_TRACE
  239. fprintf( stderr,
  240. "\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n",
  241. err,
  242. matched ? matched : "",
  243. msg ? msg : "",
  244. rc );
  245. #endif /* LDAP_SYNC_TRACE */
  246. if ( rc == LDAP_SUCCESS ) {
  247. rc = err;
  248. }
  249. ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
  250. switch ( rc ) {
  251. case LDAP_SUCCESS: {
  252. int i;
  253. BerElement *ber = NULL;
  254. ber_len_t len;
  255. struct berval cookie = { 0 };
  256. rc = LDAP_OTHER;
  257. /* deal with control; then fallthru to handler */
  258. if ( ctrls == NULL ) {
  259. goto done;
  260. }
  261. /* lookup the sync state control */
  262. for ( i = 0; ctrls[ i ] != NULL; i++ ) {
  263. if ( strcmp( ctrls[ i ]->ldctl_oid,
  264. LDAP_CONTROL_SYNC_DONE ) == 0 )
  265. {
  266. break;
  267. }
  268. }
  269. /* control must be present; there might be other... */
  270. if ( ctrls[ i ] == NULL ) {
  271. goto done;
  272. }
  273. /* extract data */
  274. ber = ber_init( &ctrls[ i ]->ldctl_value );
  275. if ( ber == NULL ) {
  276. goto done;
  277. }
  278. if ( ber_scanf( ber, "{" /*"}"*/) == LBER_ERROR ) {
  279. goto ber_done;
  280. }
  281. if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
  282. if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
  283. goto ber_done;
  284. }
  285. if ( cookie.bv_val != NULL ) {
  286. ber_bvreplace( &ls->ls_cookie, &cookie );
  287. }
  288. #ifdef LDAP_SYNC_TRACE
  289. fprintf( stderr, "\t\tgot cookie=%s\n",
  290. cookie.bv_val ? cookie.bv_val : "(null)" );
  291. #endif /* LDAP_SYNC_TRACE */
  292. }
  293. refreshDeletes = 0;
  294. if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
  295. if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) {
  296. goto ber_done;
  297. }
  298. if ( refreshDeletes ) {
  299. refreshDeletes = 1;
  300. }
  301. }
  302. if ( ber_scanf( ber, /*"{"*/ "}" ) != LBER_ERROR ) {
  303. rc = LDAP_SUCCESS;
  304. }
  305. ber_done:;
  306. ber_free( ber, 1 );
  307. if ( rc != LDAP_SUCCESS ) {
  308. break;
  309. }
  310. #ifdef LDAP_SYNC_TRACE
  311. fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
  312. refreshDeletes ? "TRUE" : "FALSE" );
  313. #endif /* LDAP_SYNC_TRACE */
  314. /* FIXME: what should we do with the refreshDelete? */
  315. switch ( refreshDeletes ) {
  316. case 0:
  317. ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
  318. break;
  319. default:
  320. ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
  321. break;
  322. }
  323. } /* fallthru */
  324. case LDAP_SYNC_REFRESH_REQUIRED:
  325. /* TODO: check for Sync Done Control */
  326. /* FIXME: perhaps the handler should be called
  327. * also in case of failure; we'll deal with this
  328. * later when implementing refreshOnly */
  329. if ( ls->ls_search_result ) {
  330. err = ls->ls_search_result( ls, res, refreshDeletes );
  331. }
  332. break;
  333. }
  334. done:;
  335. if ( matched != NULL ) {
  336. ldap_memfree( matched );
  337. }
  338. if ( msg != NULL ) {
  339. ldap_memfree( msg );
  340. }
  341. if ( ctrls != NULL ) {
  342. ldap_controls_free( ctrls );
  343. }
  344. ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
  345. return rc;
  346. }
  347. /*
  348. * handle the LDAP_RES_INTERMEDIATE response
  349. */
  350. static int
  351. ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone )
  352. {
  353. int rc;
  354. char *retoid = NULL;
  355. struct berval *retdata = NULL;
  356. BerElement *ber = NULL;
  357. ber_len_t len;
  358. ber_tag_t syncinfo_tag;
  359. struct berval cookie;
  360. int refreshDeletes = 0;
  361. BerVarray syncUUIDs = NULL;
  362. ldap_sync_refresh_t phase;
  363. #ifdef LDAP_SYNC_TRACE
  364. fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" );
  365. #endif /* LDAP_SYNC_TRACE */
  366. assert( ls != NULL );
  367. assert( res != NULL );
  368. assert( refreshDone != NULL );
  369. *refreshDone = 0;
  370. rc = ldap_parse_intermediate( ls->ls_ld, res,
  371. &retoid, &retdata, NULL, 0 );
  372. #ifdef LDAP_SYNC_TRACE
  373. fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n",
  374. rc != LDAP_SUCCESS ? "!!! " : "",
  375. retoid == NULL ? "\"\"" : retoid,
  376. rc );
  377. #endif /* LDAP_SYNC_TRACE */
  378. /* parsing must be successful, and yield the OID
  379. * of the sync info intermediate response */
  380. if ( rc != LDAP_SUCCESS ) {
  381. goto done;
  382. }
  383. rc = LDAP_OTHER;
  384. if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) {
  385. goto done;
  386. }
  387. /* init ber using the value in the response */
  388. ber = ber_init( retdata );
  389. if ( ber == NULL ) {
  390. goto done;
  391. }
  392. syncinfo_tag = ber_peek_tag( ber, &len );
  393. switch ( syncinfo_tag ) {
  394. case LDAP_TAG_SYNC_NEW_COOKIE:
  395. if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
  396. goto done;
  397. }
  398. if ( cookie.bv_val != NULL ) {
  399. ber_bvreplace( &ls->ls_cookie, &cookie );
  400. }
  401. #ifdef LDAP_SYNC_TRACE
  402. fprintf( stderr, "\t\tgot cookie=%s\n",
  403. cookie.bv_val ? cookie.bv_val : "(null)" );
  404. #endif /* LDAP_SYNC_TRACE */
  405. break;
  406. case LDAP_TAG_SYNC_REFRESH_DELETE:
  407. case LDAP_TAG_SYNC_REFRESH_PRESENT:
  408. if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
  409. #ifdef LDAP_SYNC_TRACE
  410. fprintf( stderr, "\t\tgot refreshDelete\n" );
  411. #endif /* LDAP_SYNC_TRACE */
  412. switch ( ls->ls_refreshPhase ) {
  413. case LDAP_SYNC_CAPI_NONE:
  414. case LDAP_SYNC_CAPI_PRESENTS:
  415. ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
  416. break;
  417. default:
  418. /* TODO: impossible; handle */
  419. goto done;
  420. }
  421. } else {
  422. #ifdef LDAP_SYNC_TRACE
  423. fprintf( stderr, "\t\tgot refreshPresent\n" );
  424. #endif /* LDAP_SYNC_TRACE */
  425. switch ( ls->ls_refreshPhase ) {
  426. case LDAP_SYNC_CAPI_NONE:
  427. ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
  428. break;
  429. default:
  430. /* TODO: impossible; handle */
  431. goto done;
  432. }
  433. }
  434. if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) {
  435. goto done;
  436. }
  437. if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
  438. if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
  439. goto done;
  440. }
  441. if ( cookie.bv_val != NULL ) {
  442. ber_bvreplace( &ls->ls_cookie, &cookie );
  443. }
  444. #ifdef LDAP_SYNC_TRACE
  445. fprintf( stderr, "\t\tgot cookie=%s\n",
  446. cookie.bv_val ? cookie.bv_val : "(null)" );
  447. #endif /* LDAP_SYNC_TRACE */
  448. }
  449. *refreshDone = 1;
  450. if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) {
  451. if ( ber_scanf( ber, "b", refreshDone ) == LBER_ERROR ) {
  452. goto done;
  453. }
  454. }
  455. #ifdef LDAP_SYNC_TRACE
  456. fprintf( stderr, "\t\tgot refreshDone=%s\n",
  457. *refreshDone ? "TRUE" : "FALSE" );
  458. #endif /* LDAP_SYNC_TRACE */
  459. if ( ber_scanf( ber, /*"{"*/ "}" ) == LBER_ERROR ) {
  460. goto done;
  461. }
  462. if ( *refreshDone ) {
  463. ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
  464. }
  465. if ( ls->ls_intermediate ) {
  466. ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase );
  467. }
  468. break;
  469. case LDAP_TAG_SYNC_ID_SET:
  470. #ifdef LDAP_SYNC_TRACE
  471. fprintf( stderr, "\t\tgot syncIdSet\n" );
  472. #endif /* LDAP_SYNC_TRACE */
  473. if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) {
  474. goto done;
  475. }
  476. if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
  477. if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
  478. goto done;
  479. }
  480. if ( cookie.bv_val != NULL ) {
  481. ber_bvreplace( &ls->ls_cookie, &cookie );
  482. }
  483. #ifdef LDAP_SYNC_TRACE
  484. fprintf( stderr, "\t\tgot cookie=%s\n",
  485. cookie.bv_val ? cookie.bv_val : "(null)" );
  486. #endif /* LDAP_SYNC_TRACE */
  487. }
  488. if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
  489. if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) {
  490. goto done;
  491. }
  492. }
  493. if ( ber_scanf( ber, /*"{"*/ "[W]}", &syncUUIDs ) == LBER_ERROR
  494. || syncUUIDs == NULL )
  495. {
  496. goto done;
  497. }
  498. #ifdef LDAP_SYNC_TRACE
  499. {
  500. int i;
  501. fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
  502. refreshDeletes ? "TRUE" : "FALSE" );
  503. for ( i = 0; syncUUIDs[ i ].bv_val != NULL; i++ ) {
  504. char buf[ BUFSIZ ];
  505. fprintf( stderr, "\t\t%s\n",
  506. lutil_uuidstr_from_normalized(
  507. syncUUIDs[ i ].bv_val, syncUUIDs[ i ].bv_len,
  508. buf, sizeof( buf ) ) );
  509. }
  510. }
  511. #endif /* LDAP_SYNC_TRACE */
  512. if ( refreshDeletes ) {
  513. phase = LDAP_SYNC_CAPI_DELETES_IDSET;
  514. } else {
  515. phase = LDAP_SYNC_CAPI_PRESENTS_IDSET;
  516. }
  517. /* FIXME: should touch ls->ls_refreshPhase? */
  518. if ( ls->ls_intermediate ) {
  519. ls->ls_intermediate( ls, res, syncUUIDs, phase );
  520. }
  521. ber_bvarray_free( syncUUIDs );
  522. break;
  523. default:
  524. #ifdef LDAP_SYNC_TRACE
  525. fprintf( stderr, "\t\tunknown tag!\n" );
  526. #endif /* LDAP_SYNC_TRACE */
  527. goto done;
  528. }
  529. rc = LDAP_SUCCESS;
  530. done:;
  531. if ( ber != NULL ) {
  532. ber_free( ber, 1 );
  533. }
  534. if ( retoid != NULL ) {
  535. ldap_memfree( retoid );
  536. }
  537. if ( retdata != NULL ) {
  538. ber_bvfree( retdata );
  539. }
  540. return rc;
  541. }
  542. /*
  543. * initialize the sync
  544. */
  545. int
  546. ldap_sync_init( ldap_sync_t *ls, int mode )
  547. {
  548. LDAPControl ctrl = { 0 },
  549. *ctrls[ 2 ];
  550. BerElement *ber = NULL;
  551. int rc;
  552. struct timeval tv = { 0 },
  553. *tvp = NULL;
  554. LDAPMessage *res = NULL;
  555. #ifdef LDAP_SYNC_TRACE
  556. fprintf( stderr, "ldap_sync_init(%s)...\n",
  557. mode == LDAP_SYNC_REFRESH_AND_PERSIST ?
  558. "LDAP_SYNC_REFRESH_AND_PERSIST" :
  559. ( mode == LDAP_SYNC_REFRESH_ONLY ?
  560. "LDAP_SYNC_REFRESH_ONLY" : "unknown" ) );
  561. #endif /* LDAP_SYNC_TRACE */
  562. assert( ls != NULL );
  563. assert( ls->ls_ld != NULL );
  564. /* support both refreshOnly and refreshAndPersist */
  565. switch ( mode ) {
  566. case LDAP_SYNC_REFRESH_AND_PERSIST:
  567. case LDAP_SYNC_REFRESH_ONLY:
  568. break;
  569. default:
  570. fprintf( stderr, "ldap_sync_init: unknown mode=%d\n", mode );
  571. return LDAP_PARAM_ERROR;
  572. }
  573. /* check consistency of cookie and reloadHint at initial refresh */
  574. if ( ls->ls_cookie.bv_val == NULL && ls->ls_reloadHint != 0 ) {
  575. fprintf( stderr, "ldap_sync_init: inconsistent cookie/rhint\n" );
  576. return LDAP_PARAM_ERROR;
  577. }
  578. ctrls[ 0 ] = &ctrl;
  579. ctrls[ 1 ] = NULL;
  580. /* prepare the Sync Request control */
  581. ber = ber_alloc_t( LBER_USE_DER );
  582. #ifdef LDAP_SYNC_TRACE
  583. fprintf( stderr, "%sber_alloc_t() %s= NULL\n",
  584. ber == NULL ? "!!! " : "",
  585. ber == NULL ? "=" : "!" );
  586. #endif /* LDAP_SYNC_TRACE */
  587. if ( ber == NULL ) {
  588. rc = LDAP_NO_MEMORY;
  589. goto done;
  590. }
  591. ls->ls_refreshPhase = LDAP_SYNC_CAPI_NONE;
  592. if ( ls->ls_cookie.bv_val != NULL ) {
  593. ber_printf( ber, "{eOb}", mode,
  594. &ls->ls_cookie, ls->ls_reloadHint );
  595. } else {
  596. ber_printf( ber, "{eb}", mode, ls->ls_reloadHint );
  597. }
  598. rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 );
  599. #ifdef LDAP_SYNC_TRACE
  600. fprintf( stderr,
  601. "%sber_flatten2() == %d\n",
  602. rc ? "!!! " : "",
  603. rc );
  604. #endif /* LDAP_SYNC_TRACE */
  605. if ( rc < 0 ) {
  606. rc = LDAP_OTHER;
  607. goto done;
  608. }
  609. /* make the control critical, as we cannot proceed without */
  610. ctrl.ldctl_oid = LDAP_CONTROL_SYNC;
  611. ctrl.ldctl_iscritical = 1;
  612. /* timelimit? */
  613. if ( ls->ls_timelimit ) {
  614. tv.tv_sec = ls->ls_timelimit;
  615. tvp = &tv;
  616. }
  617. /* actually run the search */
  618. rc = ldap_search_ext( ls->ls_ld,
  619. ls->ls_base, ls->ls_scope, ls->ls_filter,
  620. ls->ls_attrs, 0, ctrls, NULL,
  621. tvp, ls->ls_sizelimit, &ls->ls_msgid );
  622. #ifdef LDAP_SYNC_TRACE
  623. fprintf( stderr,
  624. "%sldap_search_ext(\"%s\", %d, \"%s\") == %d\n",
  625. rc ? "!!! " : "",
  626. ls->ls_base, ls->ls_scope, ls->ls_filter, rc );
  627. #endif /* LDAP_SYNC_TRACE */
  628. if ( rc != LDAP_SUCCESS ) {
  629. goto done;
  630. }
  631. /* initial content/content update phase */
  632. for ( ; ; ) {
  633. LDAPMessage *msg = NULL;
  634. /* NOTE: this very short timeout is just to let
  635. * ldap_result() yield long enough to get something */
  636. tv.tv_sec = 0;
  637. tv.tv_usec = 100000;
  638. rc = ldap_result( ls->ls_ld, ls->ls_msgid,
  639. LDAP_MSG_RECEIVED, &tv, &res );
  640. #ifdef LDAP_SYNC_TRACE
  641. fprintf( stderr,
  642. "\t%sldap_result(%d) == %d\n",
  643. rc == -1 ? "!!! " : "",
  644. ls->ls_msgid, rc );
  645. #endif /* LDAP_SYNC_TRACE */
  646. switch ( rc ) {
  647. case 0:
  648. /*
  649. * timeout
  650. *
  651. * TODO: can do something else in the meanwhile)
  652. */
  653. break;
  654. case -1:
  655. /* smtg bad! */
  656. goto done;
  657. default:
  658. for ( msg = ldap_first_message( ls->ls_ld, res );
  659. msg != NULL;
  660. msg = ldap_next_message( ls->ls_ld, msg ) )
  661. {
  662. int refreshDone;
  663. switch ( ldap_msgtype( msg ) ) {
  664. case LDAP_RES_SEARCH_ENTRY:
  665. rc = ldap_sync_search_entry( ls, res );
  666. break;
  667. case LDAP_RES_SEARCH_REFERENCE:
  668. rc = ldap_sync_search_reference( ls, res );
  669. break;
  670. case LDAP_RES_SEARCH_RESULT:
  671. rc = ldap_sync_search_result( ls, res );
  672. goto done_search;
  673. case LDAP_RES_INTERMEDIATE:
  674. rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
  675. if ( rc != LDAP_SUCCESS || refreshDone ) {
  676. goto done_search;
  677. }
  678. break;
  679. default:
  680. #ifdef LDAP_SYNC_TRACE
  681. fprintf( stderr, "\tgot something unexpected...\n" );
  682. #endif /* LDAP_SYNC_TRACE */
  683. ldap_msgfree( res );
  684. rc = LDAP_OTHER;
  685. goto done;
  686. }
  687. }
  688. ldap_msgfree( res );
  689. res = NULL;
  690. break;
  691. }
  692. }
  693. done_search:;
  694. ldap_msgfree( res );
  695. done:;
  696. if ( ber != NULL ) {
  697. ber_free( ber, 1 );
  698. }
  699. return rc;
  700. }
  701. /*
  702. * initialize the refreshOnly sync
  703. */
  704. int
  705. ldap_sync_init_refresh_only( ldap_sync_t *ls )
  706. {
  707. return ldap_sync_init( ls, LDAP_SYNC_REFRESH_ONLY );
  708. }
  709. /*
  710. * initialize the refreshAndPersist sync
  711. */
  712. int
  713. ldap_sync_init_refresh_and_persist( ldap_sync_t *ls )
  714. {
  715. return ldap_sync_init( ls, LDAP_SYNC_REFRESH_AND_PERSIST );
  716. }
  717. /*
  718. * poll for new responses
  719. */
  720. int
  721. ldap_sync_poll( ldap_sync_t *ls )
  722. {
  723. struct timeval tv,
  724. *tvp = NULL;
  725. LDAPMessage *res = NULL,
  726. *msg;
  727. int rc = 0;
  728. #ifdef LDAP_SYNC_TRACE
  729. fprintf( stderr, "ldap_sync_poll...\n" );
  730. #endif /* LDAP_SYNC_TRACE */
  731. assert( ls != NULL );
  732. assert( ls->ls_ld != NULL );
  733. if ( ls->ls_timeout != -1 ) {
  734. tv.tv_sec = ls->ls_timeout;
  735. tv.tv_usec = 0;
  736. tvp = &tv;
  737. }
  738. rc = ldap_result( ls->ls_ld, ls->ls_msgid,
  739. LDAP_MSG_RECEIVED, tvp, &res );
  740. if ( rc <= 0 ) {
  741. return rc;
  742. }
  743. for ( msg = ldap_first_message( ls->ls_ld, res );
  744. msg;
  745. msg = ldap_next_message( ls->ls_ld, msg ) )
  746. {
  747. int refreshDone;
  748. switch ( ldap_msgtype( msg ) ) {
  749. case LDAP_RES_SEARCH_ENTRY:
  750. rc = ldap_sync_search_entry( ls, res );
  751. break;
  752. case LDAP_RES_SEARCH_REFERENCE:
  753. rc = ldap_sync_search_reference( ls, res );
  754. break;
  755. case LDAP_RES_SEARCH_RESULT:
  756. rc = ldap_sync_search_result( ls, res );
  757. goto done_search;
  758. case LDAP_RES_INTERMEDIATE:
  759. rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
  760. if ( rc != LDAP_SUCCESS || refreshDone ) {
  761. goto done_search;
  762. }
  763. break;
  764. default:
  765. #ifdef LDAP_SYNC_TRACE
  766. fprintf( stderr, "\tgot something unexpected...\n" );
  767. #endif /* LDAP_SYNC_TRACE */
  768. ldap_msgfree( res );
  769. rc = LDAP_OTHER;
  770. goto done;
  771. }
  772. }
  773. done_search:;
  774. ldap_msgfree( res );
  775. done:;
  776. return rc;
  777. }