]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/syncprov.c
disable referral rewrite in default suffix massage
[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 #define SLAPD_OVER_SYNCPROV     SLAPD_MOD_STATIC
23
24 #ifdef SLAPD_OVER_SYNCPROV
25
26 #include "slap.h"
27
28 /* Record of a persistent search */
29 typedef struct syncops {
30         struct syncops *s_next;
31         struct berval   s_base;         /* ndn of search base */
32         ID              s_eid;          /* entryID of search base */
33         Operation       *s_op;          /* search op */
34 } syncops;
35
36 /* Record of which searches matched at premodify step */
37 typedef struct syncmatches {
38         struct syncmatches *sm_next;
39         syncops *sm_op;
40 } syncmatches;
41
42 typedef struct syncprov_info_t {
43         Entry           *si_e;  /* cached ldapsync context */
44         syncops         *si_ops;
45         int             si_chkops;      /* checkpointing */
46         int             si_chktime;
47         int             si_numops;      /* number of ops since last checkpoint */
48         time_t  si_chklast;     /* time of last checkpoint */
49         ldap_pvt_thread_mutex_t si_e_mutex;
50         ldap_pvt_thread_mutex_t si_ops_mutex;
51         ldap_pvt_thread_mutex_t si_chk_mutex;
52 } syncprov_info_t;
53
54 typedef struct opcookie {
55         slap_overinst *son;
56         syncmatches *smatches;
57         struct berval suuid;
58 } opcookie;
59
60 typedef struct findcookie {
61         ID fid;
62         struct berval fdn;
63 } findcookie;
64
65 static int
66 findbase_cb( Operation *op, SlapReply *rs )
67 {
68         slap_callback *sc = op->o_callback;
69
70         if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) {
71                 findcookie *fc = sc->sc_private;
72                 fc->fid = rs->sr_entry->e_id;
73                 ber_dupbv_x( &fc->fdn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
74         }
75         return LDAP_SUCCESS;
76 }
77
78 static int
79 syncprov_findbase( Operation *op, syncops *ss, findcookie *fc )
80 {
81         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
82         syncprov_info_t         *si = on->on_bi.bi_private;
83
84         slap_callback cb;
85         Operation fop;
86         SlapReply frs = { REP_RESULT };
87         int rc;
88
89         fop = *op;
90
91         cb.sc_response = findbase_cb;
92         cb.sc_private = fc;
93
94         fop.o_callback = &cb;
95         fop.o_tag = LDAP_REQ_SEARCH;
96         fop.ors_scope = LDAP_SCOPE_BASE;
97         fop.ors_deref = ss->s_op->ors_deref;
98         fop.ors_slimit = 1;
99         fop.ors_tlimit = SLAP_NO_LIMIT;
100         fop.ors_attrs = slap_anlist_no_attrs;
101         fop.ors_attrsonly = 1;
102         fop.ors_filter = ss->s_op->ors_filter;
103         fop.ors_filterstr = ss->s_op->ors_filterstr;
104
105         fop.o_req_ndn = ss->s_op->o_req_ndn;
106
107         rc = fop.o_bd->be_search( &fop, &frs );
108
109         if ( fc->fid == ss->s_eid ) return LDAP_SUCCESS;
110
111         /* If entryID has changed, then the base of this search has
112          * changed. Invalidate the psearch.
113          */
114         return LDAP_NO_SUCH_OBJECT;
115 }
116
117 static void
118 syncprov_matchops( Operation *op, opcookie *opc )
119 {
120         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
121         syncprov_info_t         *si = on->on_bi.bi_private;
122
123         findcookie fc = { NOID };
124         syncops *ss;
125         Entry *e;
126         Attribute *a;
127         int rc;
128
129         rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
130         if ( rc ) return;
131
132         a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
133         if ( a )
134                 ber_dupbv_x( &opc->suuid, &a->a_vals[0], op->o_tmpmemctx );
135
136         ldap_pvt_thread_mutex_lock( &si->si_ops_mutex );
137         for (ss = si->si_ops; ss; ss=ss->s_next)
138         {
139                 /* validate base */
140                 rc = syncprov_findbase( op, ss, &fc );
141                 if ( rc != LDAP_SUCCESS ) continue;
142
143                 /* check if current o_req_dn is in scope and matches filter */
144                 if ( dnIsSuffix( &op->o_req_ndn, &fc.fdn ) && test_filter( op, e,
145                          ss->s_op->ors_filter ) == LDAP_COMPARE_TRUE ) {
146                         syncmatches *sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx );
147                         sm->sm_next = opc->smatches;
148                         sm->sm_op = ss;
149                         opc->smatches = sm;
150                 }
151         }
152         ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex );
153         be_entry_release_r( op, e );
154 }
155
156 static int
157 syncprov_op_response( Operation *op, SlapReply *rs )
158 {
159         slap_callback *cb = op->o_callback;
160         opcookie *opc = (opcookie *)(cb+1);
161         slap_overinst *on = opc->son;
162         syncprov_info_t         *si = on->on_bi.bi_private;
163
164         if ( rs->sr_err == LDAP_SUCCESS )
165         {
166                 switch(op->o_tag) {
167                 case LDAP_REQ_ADD:
168                         /* for each op in si->si_ops:
169                          *   validate base
170                          *   check for scope and filter
171                          *   send ADD msg if matched
172                          */
173                          break;
174                 case LDAP_REQ_DELETE:
175                         /* for each match in opc->smatches:
176                          *   send DELETE msg
177                          */
178                          break;
179                 case LDAP_REQ_MODIFY:
180                 case LDAP_REQ_MODRDN:
181                         /* for each op in si->si_ops:
182                          *   validate base
183                          *   check for scope and filter
184                          *   if match
185                          *     if match in opc->smatches, send UPDATE
186                          *     else send ADD
187                          *   else
188                          *     if match in opc->smatches, send DELETE
189                          */
190                          break;
191                 case LDAP_REQ_EXTENDED:
192                         /* for each op in si->si_ops:
193                          *   validate base
194                          *   check for scope and filter
195                          *   send UPDATE msg if matched
196                          */
197                          break;
198                 }
199         }
200         op->o_callback = cb->sc_next;
201         op->o_tmpfree(cb, op->o_tmpmemctx);
202         return SLAP_CB_CONTINUE;
203 }
204
205 static int
206 syncprov_op_compare( Operation *op, SlapReply *rs )
207 {
208         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
209         syncprov_info_t         *si = on->on_bi.bi_private;
210         int rc = SLAP_CB_CONTINUE;
211
212         if ( dn_match( &op->o_req_ndn, &si->si_e->e_nname ) )
213         {
214                 Attribute *a;
215
216                 ldap_pvt_thread_mutex_lock( &si->si_e_mutex );
217
218                 if ( get_assert( op ) &&
219                         ( test_filter( op, si->si_e, get_assertion( op ) ) != LDAP_COMPARE_TRUE ) )
220                 {
221                         rs->sr_err = LDAP_ASSERTION_FAILED;
222                         goto return_results;
223                 }
224
225                 rs->sr_err = access_allowed( op, si->si_e, op->oq_compare.rs_ava->aa_desc,
226                         &op->oq_compare.rs_ava->aa_value, ACL_COMPARE, NULL );
227                 if ( ! rs->sr_err ) {
228                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
229                         goto return_results;
230                 }
231
232                 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
233
234                 for ( a = attr_find( si->si_e->e_attrs, op->oq_compare.rs_ava->aa_desc );
235                         a != NULL;
236                         a = attr_find( a->a_next, op->oq_compare.rs_ava->aa_desc ) )
237                 {
238                         rs->sr_err = LDAP_COMPARE_FALSE;
239
240                         if ( value_find_ex( op->oq_compare.rs_ava->aa_desc,
241                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
242                                         SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
243                                 a->a_nvals, &op->oq_compare.rs_ava->aa_value, op->o_tmpmemctx ) == 0 )
244                         {
245                                 rs->sr_err = LDAP_COMPARE_TRUE;
246                                 break;
247                         }
248                 }
249
250 return_results:;
251
252                 ldap_pvt_thread_mutex_unlock( &si->si_e_mutex );
253
254                 send_ldap_result( op, rs );
255
256                 if( rs->sr_err == LDAP_COMPARE_FALSE || rs->sr_err == LDAP_COMPARE_TRUE ) {
257                         rs->sr_err = LDAP_SUCCESS;
258                 }
259                 rc = rs->sr_err;
260         }
261
262         return SLAP_CB_CONTINUE;
263 }
264         
265 static int
266 syncprov_op_add( Operation *op, SlapReply *rs )
267 {
268         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
269         syncprov_info_t         *si = on->on_bi.bi_private;
270
271         if ( si->si_ops )
272         {
273                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
274                 opcookie *opc = (opcookie *)(cb+1);
275                 opc->son = on;
276                 cb->sc_response = syncprov_op_response;
277                 cb->sc_private = opc;
278                 cb->sc_next = op->o_callback;
279                 op->o_callback = cb;
280         }
281
282         return SLAP_CB_CONTINUE;
283 }
284
285 static int
286 syncprov_op_delete( Operation *op, SlapReply *rs )
287 {
288         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
289         syncprov_info_t         *si = on->on_bi.bi_private;
290
291         if ( si->si_ops )
292         {
293                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
294                 opcookie *opc = (opcookie *)(cb+1);
295                 opc->son = on;
296                 cb->sc_response = syncprov_op_response;
297                 cb->sc_private = opc;
298                 cb->sc_next = op->o_callback;
299                 op->o_callback = cb;
300
301                 syncprov_matchops( op, opc );
302         }
303
304         return SLAP_CB_CONTINUE;
305 }
306
307 static int
308 syncprov_op_modify( Operation *op, SlapReply *rs )
309 {
310         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
311         syncprov_info_t         *si = on->on_bi.bi_private;
312
313         if ( si->si_ops )
314         {
315                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
316                 opcookie *opc = (opcookie *)(cb+1);
317                 opc->son = on;
318                 cb->sc_response = syncprov_op_response;
319                 cb->sc_private = opc;
320                 cb->sc_next = op->o_callback;
321                 op->o_callback = cb;
322
323                 syncprov_matchops( op, opc );
324         }
325
326         return SLAP_CB_CONTINUE;
327 }
328
329 static int
330 syncprov_op_modrdn( Operation *op, SlapReply *rs )
331 {
332         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
333         syncprov_info_t         *si = on->on_bi.bi_private;
334
335         if ( si->si_ops )
336         {
337                 slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
338                 opcookie *opc = (opcookie *)(cb+1);
339                 opc->son = on;
340                 cb->sc_response = syncprov_op_response;
341                 cb->sc_private = opc;
342                 cb->sc_next = op->o_callback;
343                 op->o_callback = cb;
344
345                 syncprov_matchops( op, opc );
346         }
347
348         return SLAP_CB_CONTINUE;
349 }
350
351 static const struct berval * write_exop[] = {
352         &slap_EXOP_MODIFY_PASSWD,
353         NULL
354 };
355
356 static int
357 syncprov_op_extended( Operation *op, SlapReply *rs )
358 {
359         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
360         syncprov_info_t         *si = on->on_bi.bi_private;
361
362         if ( si->si_ops )
363         {
364                 int i, doit = 0;
365
366                 for ( i=0; write_exop[i]; i++ )
367                 {
368                         if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid ))
369                         {
370                                 doit = 1;
371                                 break;
372                         }
373                 }
374                 if ( doit )
375                 {
376                         slap_callback *cb = op->o_tmpcalloc(1,
377                                 sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
378                         opcookie *opc = (opcookie *)(cb+1);
379                         opc->son = on;
380                         cb->sc_response = syncprov_op_response;
381                         cb->sc_private = opc;
382                         cb->sc_next = op->o_callback;
383                         op->o_callback = cb;
384
385                         syncprov_matchops( op, opc );
386                 }
387         }
388
389         return SLAP_CB_CONTINUE;
390 }
391
392 static int
393 syncprov_op_search( Operation *op, SlapReply *rs )
394 {
395 }
396
397 static int
398 syncprov_response( Operation *op, SlapReply *rs )
399 {
400         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
401         syncprov_info_t         *si = (syncprov_info_t *)on->on_bi.bi_private;
402
403         /* If the operation succeeded and we're checkpointing */
404         if ( rs->sr_err == LDAP_SUCCESS && ( si->si_chkops || si->si_chktime ))
405         {
406                 int do_check = 0;
407
408                 switch ( op->o_tag ) {
409                 case LDAP_REQ_EXTENDED:
410                         { int i, doit = 0;
411
412                         /* if not PASSWD_MODIFY, break */
413                         for ( i=0; write_exop[i]; i++ )
414                         {
415                                 if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid ))
416                                 {
417                                         doit = 1;
418                                         break;
419                                 }
420                         }
421                         if ( !doit ) break;
422                         }
423                         /* else fallthru */
424                 case LDAP_REQ_ADD:
425                 case LDAP_REQ_MODIFY:
426                 case LDAP_REQ_MODRDN:
427                 case LDAP_REQ_DELETE:
428                         ldap_pvt_thread_mutex_lock( &si->si_chk_mutex );
429                         if ( si->si_chkops )
430                         {
431                                 si->si_numops++;
432                                 if ( si->si_numops >= si->si_chkops )
433                                 {
434                                         do_check = 1;
435                                         si->si_numops = 0;
436                                 }
437                         }
438                         if ( si->si_chktime )
439                         {
440                                 if ( op->o_time - si->si_chklast >= si->si_chktime )
441                                 {
442                                         do_check = 1;
443                                         si->si_chklast = op->o_time;
444                                 }
445                         }
446                         ldap_pvt_thread_mutex_unlock( &si->si_chk_mutex );
447                         if ( do_check )
448                         {
449                                 /* write cn=ldapsync to underlying db */
450                         }
451                         break;
452                 }
453         }
454         return SLAP_CB_CONTINUE;
455 }
456
457 static int
458 syncprov_db_config(
459         BackendDB       *be,
460         const char      *fname,
461         int             lineno,
462         int             argc,
463         char    **argv
464 )
465 {
466         slap_overinst           *on = (slap_overinst *)be->bd_info;
467         syncprov_info_t         *si = (syncprov_info_t *)on->on_bi.bi_private;
468
469         if ( strcasecmp( argv[ 0 ], "syncprov-checkpoint" ) == 0 ) {
470                 if ( argc != 3 ) {
471                         fprintf( stderr, "%s: line %d: wrong number of arguments in "
472                                 "\"syncprov-checkpint <ops> <minutes>\"\n", fname, lineno );
473                         return -1;
474                 }
475                 si->si_chkops = atoi( argv[1] );
476                 si->si_chktime = atoi( argv[2] ) * 60;
477
478         } else {
479                 return SLAP_CONF_UNKNOWN;
480         }
481
482         return 0;
483 }
484
485 /* Read any existing cn=ldapsync context from the underlying db.
486  * Then search for any entries newer than that. If no value exists,
487  * just generate it. Cache whatever result.
488  */
489 static int
490 syncprov_db_open(
491         BackendDB *be
492 )
493 {
494         slap_overinst   *on = (slap_overinst *) be->bd_info;
495         syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
496
497         return 0;
498 }
499
500 /* Write the current cn=ldapsync context into the underlying db.
501  */
502 static int
503 syncprov_db_close(
504         BackendDB *be
505 )
506 {
507         slap_overinst   *on = (slap_overinst *) be->bd_info;
508         syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
509
510         /* for si->si_ops:
511          *   send DONE messages
512          *   free si_ops
513          */
514         return 0;
515 }
516
517 static int
518 syncprov_db_init(
519         BackendDB *be
520 )
521 {
522         slap_overinst   *on = (slap_overinst *)be->bd_info;
523         syncprov_info_t *si;
524
525         si = ch_calloc(1, sizeof(syncprov_info_t));
526         on->on_bi.bi_private = si;
527
528         ldap_pvt_thread_mutex_init( &si->si_e_mutex );
529         ldap_pvt_thread_mutex_init( &si->si_ops_mutex );
530         ldap_pvt_thread_mutex_init( &si->si_chk_mutex );
531
532         return 0;
533 }
534
535 static int
536 syncprov_db_destroy(
537         BackendDB *be
538 )
539 {
540         slap_overinst   *on = (slap_overinst *)be->bd_info;
541         syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
542
543         if ( si ) {
544                 if ( si->si_e ) {
545                         entry_free( si->si_e );
546
547                 }
548                 ldap_pvt_thread_mutex_destroy( &si->si_chk_mutex );
549                 ldap_pvt_thread_mutex_destroy( &si->si_ops_mutex );
550                 ldap_pvt_thread_mutex_destroy( &si->si_e_mutex );
551
552                 ch_free( si );
553         }
554
555         return 0;
556 }
557
558 /* This overlay is set up for dynamic loading via moduleload. For static
559  * configuration, you'll need to arrange for the slap_overinst to be
560  * initialized and registered by some other function inside slapd.
561  */
562
563 static slap_overinst            syncprov;
564
565 int
566 syncprov_init()
567 {
568         syncprov.on_bi.bi_type = "syncprov";
569         syncprov.on_bi.bi_db_init = syncprov_db_init;
570         syncprov.on_bi.bi_db_config = syncprov_db_config;
571         syncprov.on_bi.bi_db_destroy = syncprov_db_destroy;
572         syncprov.on_bi.bi_db_open = syncprov_db_open;
573         syncprov.on_bi.bi_db_close = syncprov_db_close;
574
575         syncprov.on_bi.bi_op_add = syncprov_op_add;
576         syncprov.on_bi.bi_op_compare = syncprov_op_compare;
577         syncprov.on_bi.bi_op_delete = syncprov_op_delete;
578         syncprov.on_bi.bi_op_modify = syncprov_op_modify;
579         syncprov.on_bi.bi_op_modrdn = syncprov_op_modrdn;
580         syncprov.on_bi.bi_op_search = syncprov_op_search;
581         syncprov.on_bi.bi_extended = syncprov_op_extended;
582
583         syncprov.on_response = syncprov_response;
584
585         return overlay_register( &syncprov );
586 }
587
588 #if SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC
589 int
590 init_module( int argc, char *argv[] )
591 {
592         return syncprov_init();
593 }
594 #endif /* SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC */
595
596 #endif /* defined(SLAPD_OVER_SYNCPROV) */