]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/syncprov.c
a02ca2e8c5d8209d74b1ce407e7164006af87584
[openldap] / servers / slapd / overlays / syncprov.c
1 /* syncprov.c - syncrepl provider */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2004 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 work was initially developed by Howard Chu for inclusion in
17  * OpenLDAP Software.
18  */
19
20 #include "portable.h"
21
22 #ifdef SLAPD_OVER_SYNCPROV
23
24 #include "slap.h"
25
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 */
32 } syncops;
33
34 /* Record of which searches matched at premodify step */
35 typedef struct syncmatches {
36         struct syncmatches *sm_next;
37         syncops *sm_op;
38 } syncmatches;
39
40 typedef struct syncprov_info_t {
41         Entry           *si_e;  /* cached ldapsync context */
42         syncops         *si_ops;
43         int             si_chkops;      /* checkpointing */
44         int             si_chktime;
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;
50 } syncprov_info_t;
51
52 typedef struct opcookie {
53         slap_overinst *son;
54         syncmatches *smatches;
55 } opcookie;
56
57 /* Refresh - find entries between cookie CSN and current CSN at start
58  * of operation.
59  */
60
61 static void
62 syncprov_matchops( Operation *op, opcookie *opc )
63 {
64         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
65         syncprov_info_t         *si = on->on_bi.bi_private;
66
67         syncops *ss;
68
69         for (ss = si->si_ops; ss; ss=ss->s_next)
70         {
71                 /* validate base */
72                 /* check if current o_req_dn is in scope and matches filter */
73         }
74 }
75
76 static int
77 syncprov_op_response( Operation *op, SlapReply *rs )
78 {
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;
83
84         if ( rs->sr_err == LDAP_SUCCESS )
85         {
86                 switch(op->o_tag) {
87                 case LDAP_REQ_ADD:
88                         /* for each op in si->si_ops:
89                          *   validate base
90                          *   check for scope and filter
91                          *   send ADD msg if matched
92                          */
93                          break;
94                 case LDAP_REQ_DELETE:
95                         /* for each match in opc->smatches:
96                          *   send DELETE msg
97                          */
98                          break;
99                 case LDAP_REQ_MODIFY:
100                 case LDAP_REQ_MODRDN:
101                         /* for each op in si->si_ops:
102                          *   validate base
103                          *   check for scope and filter
104                          *   if match
105                          *     if match in opc->smatches, send UPDATE
106                          *     else send ADD
107                          *   else
108                          *     if match in opc->smatches, send DELETE
109                          */
110                          break;
111                 case LDAP_REQ_EXTENDED:
112                         /* for each op in si->si_ops:
113                          *   validate base
114                          *   check for scope and filter
115                          *   send UPDATE msg if matched
116                          */
117                          break;
118                 }
119         }
120         op->o_callback = cb->sc_next;
121         op->o_tmpfree(cb, op->o_tmpmemctx);
122         return SLAP_CB_CONTINUE;
123 }
124
125 static int
126 syncprov_op_compare( Operation *op, SlapReply *rs )
127 {
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;
131
132         if ( dn_match( &op->o_req_ndn, &si->si_e->e_nname ) )
133         {
134                 
135                 ldap_pvt_thread_mutex_lock( &si->si_e_mutex );
136
137                 if ( get_assert( op ) &&
138                         ( test_filter( op, si->si_e, get_assertion( op ) ) != LDAP_COMPARE_TRUE ) )
139                 {
140                         rs->sr_err = LDAP_ASSERTION_FAILED;
141                         goto return_results;
142                 }
143
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;
148                         goto return_results;
149                 }
150
151                 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
152
153                 for ( a = attr_find( si->si_e->e_attrs, op->oq_compare.rs_ava->aa_desc );
154                         a != NULL;
155                         a = attr_find( a->a_next, op->oq_compare.rs_ava->aa_desc ) )
156                 {
157                         rs->sr_err = LDAP_COMPARE_FALSE;
158
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 )
163                         {
164                                 rs->sr_err = LDAP_COMPARE_TRUE;
165                                 break;
166                         }
167                 }
168
169 return_results:;
170
171                 ldap_pvt_thread_mutex_unlock( &si->si_entry_mutex );
172
173                 send_ldap_result( op, rs );
174
175                 if( rs->sr_err == LDAP_COMPARE_FALSE || rs->sr_err == LDAP_COMPARE_TRUE ) {
176                         rs->sr_err = LDAP_SUCCESS;
177                 }
178                 rc = rs->sr_err;
179         }
180
181         return SLAP_CB_CONTINUE;
182 }
183         
184 static int
185 syncprov_op_add( Operation *op, SlapReply *rs )
186 {
187         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
188         syncprov_info_t         *si = on->on_bi.bi_private;
189
190         if ( si->si_ops )
191         {
192                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
193                 opcookie *opc = (opcookie *)(cb+1);
194                 opc->son = on;
195                 cb->sc_response = syncprov_op_response;
196                 cb->sc_private = opc;
197                 cb->sc_next = op->o_callback;
198                 op->o_callback = cb;
199         }
200
201         return SLAP_CB_CONTINUE;
202 }
203
204 static int
205 syncprov_op_delete( Operation *op, SlapReply *rs )
206 {
207         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
208         syncprov_info_t         *si = on->on_bi.bi_private;
209
210         if ( si->si_ops )
211         {
212                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
213                 opcookie *opc = (opcookie *)(cb+1);
214                 opc->son = on;
215                 cb->sc_response = syncprov_op_response;
216                 cb->sc_private = opc;
217                 cb->sc_next = op->o_callback;
218                 op->o_callback = cb;
219
220                 syncprov_matchops( op, opc );
221         }
222
223         return SLAP_CB_CONTINUE;
224 }
225
226 static int
227 syncprov_op_modify( Operation *op, SlapReply *rs )
228 {
229         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
230         syncprov_info_t         *si = on->on_bi.bi_private;
231
232         if ( si->si_ops )
233         {
234                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
235                 opcookie *opc = (opcookie *)(cb+1);
236                 opc->son = on;
237                 cb->sc_response = syncprov_op_response;
238                 cb->sc_private = opc;
239                 cb->sc_next = op->o_callback;
240                 op->o_callback = cb;
241
242                 syncprov_matchops( op, opc );
243         }
244
245         return SLAP_CB_CONTINUE;
246 }
247
248 static int
249 syncprov_op_modrdn( Operation *op, SlapReply *rs )
250 {
251         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
252         syncprov_info_t         *si = on->on_bi.bi_private;
253
254         if ( si->si_ops )
255         {
256                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
257                 opcookie *opc = (opcookie *)(cb+1);
258                 opc->son = on;
259                 cb->sc_response = syncprov_op_response;
260                 cb->sc_private = opc;
261                 cb->sc_next = op->o_callback;
262                 op->o_callback = cb;
263
264                 syncprov_matchops( op, opc );
265         }
266
267         return SLAP_CB_CONTINUE;
268 }
269
270 static int
271 syncprov_op_extended( Operation *op, SlapReply *rs )
272 {
273         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
274         syncprov_info_t         *si = on->on_bi.bi_private;
275
276         if ( si->si_ops )
277         {
278                 int i, doit = 0;
279
280                 for ( i=0; write_exop[i]; i++ )
281                 {
282                         if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid ))
283                         {
284                                 doit = 1;
285                                 break;
286                         }
287                 }
288                 if ( doit )
289                 {
290                         slap_callback *cb = op->o_tmpcalloc(1,
291                                 sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
292                         opcookie *opc = (opcookie *)(cb+1);
293                         opc->son = on;
294                         cb->sc_response = syncprov_op_response;
295                         cb->sc_private = opc;
296                         cb->sc_next = op->o_callback;
297                         op->o_callback = cb;
298                 }
299         }
300
301         return SLAP_CB_CONTINUE;
302 }
303
304 static int
305 syncprov_response( Operation *op, SlapReply *rs )
306 {
307         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
308         syncprov_info_t         *si = (syncprov_info_t *)on->on_bi.bi_private;
309
310         /* If the operation succeeded and we're checkpointing */
311         if ( rs->sr_err == LDAP_SUCCESS && ( si->si_chkops || si->si_chktime ))
312         {
313                 int do_check = 0;
314
315                 switch ( op->o_tag ) {
316                 case LDAP_REQ_EXTENDED:
317                         /* if not PASSWD_MODIFY, break */
318                         /* else fallthru */
319                 case LDAP_REQ_ADD:
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 );
324                         if ( si->si_chkops )
325                         {
326                                 si->si_numops++;
327                                 if ( si->si_numops >= si->si_chkops )
328                                 {
329                                         do_check = 1;
330                                         si->si_numops = 0;
331                                 }
332                         }
333                         if ( si->si_chktime )
334                         {
335                                 if ( op->o_time - si->si_chklast >= si->si_chktime )
336                                 {
337                                         do_check = 1;
338                                         si->si_chklast = op->o_time;
339                                 }
340                         }
341                         ldap_pvt_thread_mutex_unlock( &si->si_chk_mutex );
342                         if ( do_check )
343                         {
344                                 /* write cn=ldapsync to underlying db */
345                         }
346                         break;
347                 }
348         }
349         return SLAP_CB_CONTINUE;
350 }
351
352 static int
353 syncprov_db_config(
354         BackendDB       *be,
355         const char      *fname,
356         int             lineno,
357         int             argc,
358         char    **argv
359 )
360 {
361         slap_overinst           *on = (slap_overinst *)be->bd_info;
362         syncprov_info_t         *si = (syncprov_info_t *)on->on_bi.bi_private;
363
364         if ( strcasecmp( argv[ 0 ], "syncprov-checkpoint" ) == 0 ) {
365                 if ( argc != 3 ) {
366                         fprintf( stderr, "%s: line %d: wrong number of arguments in "
367                                 "\"syncprov-checkpint <ops> <minutes>\"\n", fname, lineno );
368                         return -1;
369                 }
370                 si->si_chkops = atoi( argv[1] );
371                 si->si_chktime = atoi( argv[2] ) * 60;
372
373         } else {
374                 return SLAP_CONF_UNKNOWN;
375         }
376
377         return 0;
378 }
379
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.
383  */
384 static int
385 syncprov_db_open(
386         BackendDB *be
387 )
388 {
389         slap_overinst   *on = (slap_overinst *) be->bd_info;
390         syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
391
392         return 0;
393 }
394
395 /* Write the current cn=ldapsync context into the underlying db.
396  */
397 static int
398 syncprov_db_close(
399         BackendDB *be
400 )
401 {
402         slap_overinst   *on = (slap_overinst *) be->bd_info;
403         syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
404
405         /* for si->si_ops:
406          *   send DONE messages
407          *   free si_ops
408          */
409         return 0;
410 }
411
412 static int
413 syncprov_db_init(
414         BackendDB *be
415 )
416 {
417         slap_overinst   *on = (slap_overinst *)be->bd_info;
418         syncprov_info_t *si;
419
420         si = ch_calloc(1, sizeof(syncprov_info_t));
421         on->on_bi.bi_private = si;
422
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 );
426
427         return 0;
428 }
429
430 static int
431 syncprov_db_destroy(
432         BackendDB *be
433 )
434 {
435         slap_overinst   *on = (slap_overinst *)be->bd_info;
436         syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
437
438         if ( si ) {
439                 if ( si->si_e ) {
440                         entry_free( si->si_e );
441
442                 }
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 );
446
447                 ch_free( si );
448         }
449
450         return 0;
451 }
452
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.
456  */
457
458 static slap_overinst            syncprov;
459
460 int
461 syncprov_init()
462 {
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;
469
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;
477
478         syncprov.on_response = syncprov_response;
479
480         return overlay_register( &syncprov );
481 }
482
483 #if SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC
484 int
485 init_module( int argc, char *argv[] )
486 {
487         return syncprov_init();
488 }
489 #endif /* SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC */
490
491 #endif /* defined(SLAPD_OVER_SYNCPROV) */