1 /* syncprov.c - syncrepl provider */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2004 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 * This work was initially developed by Howard Chu for inclusion in
22 #ifdef SLAPD_OVER_SYNCPROV
26 /* Record of a persistent search */
27 typedef struct syncops {
28 struct syncops *s_next;
29 struct berval s_base; /* ndn of search base */
30 ID s_eid; /* entryID of search base */
31 Operation *s_op; /* search op */
34 /* Record of which searches matched at premodify step */
35 typedef struct syncmatches {
36 struct syncmatches *sm_next;
40 typedef struct syncprov_info_t {
41 Entry *si_e; /* cached ldapsync context */
43 int si_chkops; /* checkpointing */
45 int si_numops; /* number of ops since last checkpoint */
46 time_t si_chklast; /* time of last checkpoint */
47 ldap_pvt_thread_mutext_t si_e_mutex;
48 ldap_pvt_thread_mutext_t si_ops_mutex;
49 ldap_pvt_thread_mutext_t si_chk_mutex;
52 typedef struct opcookie {
54 syncmatches *smatches;
57 /* Refresh - find entries between cookie CSN and current CSN at start
62 syncprov_matchops( Operation *op, opcookie *opc )
64 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
65 syncprov_info_t *si = on->on_bi.bi_private;
69 for (ss = si->si_ops; ss; ss=ss->s_next)
72 /* check if current o_req_dn is in scope and matches filter */
77 syncprov_op_response( Operation *op, SlapReply *rs )
79 slap_callback *sc = op->o_callback;
80 opcookie *opc = (opcookie *)(cb+1);
81 slap_overinst *on = opc->son;
82 syncprov_info_t *si = on->on_bi.bi_private;
84 if ( rs->sr_err == LDAP_SUCCESS )
88 /* for each op in si->si_ops:
90 * check for scope and filter
91 * send ADD msg if matched
95 /* for each match in opc->smatches:
100 case LDAP_REQ_MODRDN:
101 /* for each op in si->si_ops:
103 * check for scope and filter
105 * if match in opc->smatches, send UPDATE
108 * if match in opc->smatches, send DELETE
111 case LDAP_REQ_EXTENDED:
112 /* for each op in si->si_ops:
114 * check for scope and filter
115 * send UPDATE msg if matched
120 op->o_callback = cb->sc_next;
121 op->o_tmpfree(cb, op->o_tmpmemctx);
122 return SLAP_CB_CONTINUE;
126 syncprov_op_compare( Operation *op, SlapReply *rs )
128 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
129 syncprov_info_t *si = on->on_bi.bi_private;
130 int rc = SLAP_CB_CONTINUE;
132 if ( dn_match( &op->o_req_ndn, &si->si_e->e_nname ) )
135 ldap_pvt_thread_mutex_lock( &si->si_e_mutex );
137 if ( get_assert( op ) &&
138 ( test_filter( op, si->si_e, get_assertion( op ) ) != LDAP_COMPARE_TRUE ) )
140 rs->sr_err = LDAP_ASSERTION_FAILED;
144 rs->sr_err = access_allowed( op, si->si_e, op->oq_compare.rs_ava->aa_desc,
145 &op->oq_compare.rs_ava->aa_value, ACL_COMPARE, NULL );
146 if ( ! rs->sr_err ) {
147 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
151 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
153 for ( a = attr_find( si->si_e->e_attrs, op->oq_compare.rs_ava->aa_desc );
155 a = attr_find( a->a_next, op->oq_compare.rs_ava->aa_desc ) )
157 rs->sr_err = LDAP_COMPARE_FALSE;
159 if ( value_find_ex( op->oq_compare.rs_ava->aa_desc,
160 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
161 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
162 a->a_nvals, &op->oq_compare.rs_ava->aa_value, op->o_tmpmemctx ) == 0 )
164 rs->sr_err = LDAP_COMPARE_TRUE;
171 ldap_pvt_thread_mutex_unlock( &si->si_entry_mutex );
173 send_ldap_result( op, rs );
175 if( rs->sr_err == LDAP_COMPARE_FALSE || rs->sr_err == LDAP_COMPARE_TRUE ) {
176 rs->sr_err = LDAP_SUCCESS;
181 return SLAP_CB_CONTINUE;
185 syncprov_op_add( Operation *op, SlapReply *rs )
187 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
188 syncprov_info_t *si = on->on_bi.bi_private;
192 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
193 opcookie *opc = (opcookie *)(cb+1);
195 cb->sc_response = syncprov_op_response;
196 cb->sc_private = opc;
197 cb->sc_next = op->o_callback;
201 return SLAP_CB_CONTINUE;
205 syncprov_op_delete( Operation *op, SlapReply *rs )
207 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
208 syncprov_info_t *si = on->on_bi.bi_private;
212 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
213 opcookie *opc = (opcookie *)(cb+1);
215 cb->sc_response = syncprov_op_response;
216 cb->sc_private = opc;
217 cb->sc_next = op->o_callback;
220 syncprov_matchops( op, opc );
223 return SLAP_CB_CONTINUE;
227 syncprov_op_modify( Operation *op, SlapReply *rs )
229 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
230 syncprov_info_t *si = on->on_bi.bi_private;
234 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
235 opcookie *opc = (opcookie *)(cb+1);
237 cb->sc_response = syncprov_op_response;
238 cb->sc_private = opc;
239 cb->sc_next = op->o_callback;
242 syncprov_matchops( op, opc );
245 return SLAP_CB_CONTINUE;
249 syncprov_op_modrdn( Operation *op, SlapReply *rs )
251 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
252 syncprov_info_t *si = on->on_bi.bi_private;
256 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
257 opcookie *opc = (opcookie *)(cb+1);
259 cb->sc_response = syncprov_op_response;
260 cb->sc_private = opc;
261 cb->sc_next = op->o_callback;
264 syncprov_matchops( op, opc );
267 return SLAP_CB_CONTINUE;
271 syncprov_op_extended( Operation *op, SlapReply *rs )
273 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
274 syncprov_info_t *si = on->on_bi.bi_private;
280 for ( i=0; write_exop[i]; i++ )
282 if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid ))
290 slap_callback *cb = op->o_tmpcalloc(1,
291 sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
292 opcookie *opc = (opcookie *)(cb+1);
294 cb->sc_response = syncprov_op_response;
295 cb->sc_private = opc;
296 cb->sc_next = op->o_callback;
301 return SLAP_CB_CONTINUE;
305 syncprov_response( Operation *op, SlapReply *rs )
307 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
308 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
310 /* If the operation succeeded and we're checkpointing */
311 if ( rs->sr_err == LDAP_SUCCESS && ( si->si_chkops || si->si_chktime ))
315 switch ( op->o_tag ) {
316 case LDAP_REQ_EXTENDED:
317 /* if not PASSWD_MODIFY, break */
320 case LDAP_REQ_MODIFY:
321 case LDAP_REQ_MODRDN:
322 case LDAP_REQ_DELETE:
323 ldap_pvt_thread_mutex_lock( &si->si_chk_mutex );
327 if ( si->si_numops >= si->si_chkops )
333 if ( si->si_chktime )
335 if ( op->o_time - si->si_chklast >= si->si_chktime )
338 si->si_chklast = op->o_time;
341 ldap_pvt_thread_mutex_unlock( &si->si_chk_mutex );
344 /* write cn=ldapsync to underlying db */
349 return SLAP_CB_CONTINUE;
361 slap_overinst *on = (slap_overinst *)be->bd_info;
362 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
364 if ( strcasecmp( argv[ 0 ], "syncprov-checkpoint" ) == 0 ) {
366 fprintf( stderr, "%s: line %d: wrong number of arguments in "
367 "\"syncprov-checkpint <ops> <minutes>\"\n", fname, lineno );
370 si->si_chkops = atoi( argv[1] );
371 si->si_chktime = atoi( argv[2] ) * 60;
374 return SLAP_CONF_UNKNOWN;
380 /* Read any existing cn=ldapsync context from the underlying db.
381 * Then search for any entries newer than that. If no value exists,
382 * just generate it. Cache whatever result.
389 slap_overinst *on = (slap_overinst *) be->bd_info;
390 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
395 /* Write the current cn=ldapsync context into the underlying db.
402 slap_overinst *on = (slap_overinst *) be->bd_info;
403 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
417 slap_overinst *on = (slap_overinst *)be->bd_info;
420 si = ch_calloc(1, sizeof(syncprov_info_t));
421 on->on_bi.bi_private = si;
423 ldap_pvt_thread_mutex_init( &si->si_e_mutex );
424 ldap_pvt_thread_mutex_init( &si->si_ops_mutex );
425 ldap_pvt_thread_mutex_init( &si->si_chk_mutex );
435 slap_overinst *on = (slap_overinst *)be->bd_info;
436 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
440 entry_free( si->si_e );
443 ldap_pvt_thread_mutex_destroy( &si->si_chk_mutex );
444 ldap_pvt_thread_mutex_destroy( &si->si_ops_mutex );
445 ldap_pvt_thread_mutex_destroy( &si->si_e_mutex );
453 /* This overlay is set up for dynamic loading via moduleload. For static
454 * configuration, you'll need to arrange for the slap_overinst to be
455 * initialized and registered by some other function inside slapd.
458 static slap_overinst syncprov;
463 syncprov.on_bi.bi_type = "syncprov";
464 syncprov.on_bi.bi_db_init = syncprov_db_init;
465 syncprov.on_bi.bi_db_config = syncprov_db_config;
466 syncprov.on_bi.bi_db_destroy = syncprov_db_destroy;
467 syncprov.on_bi.bi_db_open = syncprov_db_open;
468 syncprov.on_bi.bi_db_close = syncprov_db_close;
470 syncprov.on_bi.bi_op_add = syncprov_op_add;
471 syncprov.on_bi.bi_op_compare = syncprov_op_compare;
472 syncprov.on_bi.bi_op_delete = syncprov_op_delete;
473 syncprov.on_bi.bi_op_modify = syncprov_op_modify;
474 syncprov.on_bi.bi_op_modrdn = syncprov_op_modrdn;
475 syncprov.on_bi.bi_op_search = syncprov_op_search;
476 syncprov.on_bi.bi_extended = syncprov_op_extended;
478 syncprov.on_response = syncprov_response;
480 return overlay_register( &syncprov );
483 #if SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC
485 init_module( int argc, char *argv[] )
487 return syncprov_init();
489 #endif /* SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC */
491 #endif /* defined(SLAPD_OVER_SYNCPROV) */