1 /* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/syncrepl.c,v 1.254.2.37 2008/07/10 00:52:39 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2003 by IBM Corporation.
7 * Portions Copyright 2003 by Howard Chu, Symas Corporation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
23 #include <ac/string.h>
24 #include <ac/socket.h>
28 #include "lutil_ldap.h"
34 struct nonpresent_entry
{
35 struct berval
*npe_name
;
36 struct berval
*npe_nname
;
37 LDAP_LIST_ENTRY(nonpresent_entry
) npe_link
;
40 typedef struct cookie_state
{
41 ldap_pvt_thread_mutex_t cs_mutex
;
44 struct berval
*cs_vals
;
48 #define SYNCDATA_DEFAULT 0 /* entries are plain LDAP entries */
49 #define SYNCDATA_ACCESSLOG 1 /* entries are accesslog format */
50 #define SYNCDATA_CHANGELOG 2 /* entries are changelog format */
52 #define SYNCLOG_LOGGING 0 /* doing a log-based update */
53 #define SYNCLOG_FALLBACK 1 /* doing a full refresh */
55 #define RETRYNUM_FOREVER (-1) /* retry forever */
56 #define RETRYNUM_TAIL (-2) /* end of retrynum array */
57 #define RETRYNUM_VALID(n) ((n) >= RETRYNUM_FOREVER) /* valid retrynum */
58 #define RETRYNUM_FINITE(n) ((n) > RETRYNUM_FOREVER) /* not forever */
60 typedef struct syncinfo_s
{
61 struct syncinfo_s
*si_next
;
66 char si_ridtxt
[ STRLENOF("rid=999") + 1 ];
67 slap_bindconf si_bindconf
;
68 struct berval si_base
;
69 struct berval si_logbase
;
70 struct berval si_filterstr
;
71 struct berval si_logfilterstr
;
75 AttributeName
*si_anlist
;
76 AttributeName
*si_exanlist
;
81 int si_schemachecking
;
82 int si_type
; /* the active type */
83 int si_ctype
; /* the configured type */
85 time_t *si_retryinterval
;
86 int *si_retrynum_init
;
88 struct sync_cookie si_syncCookie
;
89 cookie_state
*si_cookieState
;
95 int si_refreshPresent
;
100 Avlnode
*si_presentlist
;
103 LDAP_LIST_HEAD(np
, nonpresent_entry
) si_nonpresentlist
;
104 ldap_pvt_thread_mutex_t si_mutex
;
107 static int syncuuid_cmp( const void *, const void * );
108 static int avl_presentlist_insert( syncinfo_t
* si
, struct berval
*syncUUID
);
109 static void syncrepl_del_nonpresent( Operation
*, syncinfo_t
*, BerVarray
, struct sync_cookie
*, int );
110 static int syncrepl_message_to_op(
111 syncinfo_t
*, Operation
*, LDAPMessage
* );
112 static int syncrepl_message_to_entry(
113 syncinfo_t
*, Operation
*, LDAPMessage
*,
114 Modifications
**, Entry
**, int );
115 static int syncrepl_entry(
116 syncinfo_t
*, Operation
*, Entry
*,
117 Modifications
**,int, struct berval
*,
118 struct berval
*cookieCSN
);
119 static int syncrepl_updateCookie(
120 syncinfo_t
*, Operation
*, struct berval
*,
121 struct sync_cookie
* );
122 static struct berval
* slap_uuidstr_from_normalized(
123 struct berval
*, struct berval
*, void * );
125 /* callback functions */
126 static int dn_callback( Operation
*, SlapReply
* );
127 static int nonpresent_callback( Operation
*, SlapReply
* );
128 static int null_callback( Operation
*, SlapReply
* );
130 static AttributeDescription
*sync_descs
[4];
133 syncrepl_state2str( int state
)
136 case LDAP_SYNC_PRESENT
:
142 case LDAP_SYNC_MODIFY
:
145 case LDAP_SYNC_DELETE
:
153 init_syncrepl(syncinfo_t
*si
)
156 char **attrs
, **exattrs
;
158 if ( !sync_descs
[0] ) {
159 sync_descs
[0] = slap_schema
.si_ad_objectClass
;
160 sync_descs
[1] = slap_schema
.si_ad_structuralObjectClass
;
161 sync_descs
[2] = slap_schema
.si_ad_entryCSN
;
162 sync_descs
[3] = NULL
;
165 if ( si
->si_allattrs
&& si
->si_allopattrs
)
168 attrs
= anlist2attrs( si
->si_anlist
);
171 if ( si
->si_allattrs
) {
174 if ( !is_at_operational( at_find( attrs
[i
] ) ) ) {
175 for ( j
= i
; attrs
[j
] != NULL
; j
++ ) {
178 attrs
[j
] = attrs
[j
+1];
184 attrs
= ( char ** ) ch_realloc( attrs
, (i
+ 2)*sizeof( char * ) );
185 attrs
[i
] = ch_strdup("*");
188 } else if ( si
->si_allopattrs
) {
191 if ( is_at_operational( at_find( attrs
[i
] ) ) ) {
192 for ( j
= i
; attrs
[j
] != NULL
; j
++ ) {
195 attrs
[j
] = attrs
[j
+1];
201 attrs
= ( char ** ) ch_realloc( attrs
, (i
+ 2)*sizeof( char * ) );
202 attrs
[i
] = ch_strdup("+");
206 for ( i
= 0; sync_descs
[i
] != NULL
; i
++ ) {
209 if ( !strcmp( attrs
[j
], sync_descs
[i
]->ad_cname
.bv_val
) ) {
210 for ( k
= j
; attrs
[k
] != NULL
; k
++ ) {
213 attrs
[k
] = attrs
[k
+1];
221 for ( n
= 0; attrs
[ n
] != NULL
; n
++ ) /* empty */;
223 if ( si
->si_allopattrs
) {
224 attrs
= ( char ** ) ch_realloc( attrs
, (n
+ 2)*sizeof( char * ) );
226 attrs
= ( char ** ) ch_realloc( attrs
, (n
+ 4)*sizeof( char * ) );
230 if ( si
->si_allopattrs
) {
231 attrs
[n
++] = ch_strdup( sync_descs
[0]->ad_cname
.bv_val
);
233 for ( i
= 0; sync_descs
[ i
] != NULL
; i
++ ) {
234 attrs
[ n
++ ] = ch_strdup ( sync_descs
[i
]->ad_cname
.bv_val
);
242 if ( si
->si_allattrs
== si
->si_allopattrs
) {
243 attrs
= (char**) ch_malloc( 3 * sizeof(char*) );
244 attrs
[i
++] = ch_strdup( "*" );
245 attrs
[i
++] = ch_strdup( "+" );
246 } else if ( si
->si_allattrs
&& !si
->si_allopattrs
) {
247 for ( n
= 0; sync_descs
[ n
] != NULL
; n
++ ) ;
248 attrs
= (char**) ch_malloc( (n
+1)* sizeof(char*) );
249 attrs
[i
++] = ch_strdup( "*" );
250 for ( j
= 1; sync_descs
[ j
] != NULL
; j
++ ) {
251 attrs
[i
++] = ch_strdup ( sync_descs
[j
]->ad_cname
.bv_val
);
253 } else if ( !si
->si_allattrs
&& si
->si_allopattrs
) {
254 attrs
= (char**) ch_malloc( 3 * sizeof(char*) );
255 attrs
[i
++] = ch_strdup( "+" );
256 attrs
[i
++] = ch_strdup( sync_descs
[0]->ad_cname
.bv_val
);
261 si
->si_attrs
= attrs
;
263 exattrs
= anlist2attrs( si
->si_exanlist
);
266 for ( n
= 0; exattrs
[n
] != NULL
; n
++ ) ;
268 for ( i
= 0; sync_descs
[i
] != NULL
; i
++ ) {
270 while ( exattrs
[j
] != NULL
) {
271 if ( !strcmp( exattrs
[j
], sync_descs
[i
]->ad_cname
.bv_val
) ) {
272 ch_free( exattrs
[j
] );
273 for ( k
= j
; exattrs
[k
] != NULL
; k
++ ) {
274 exattrs
[k
] = exattrs
[k
+1];
282 for ( i
= 0; exattrs
[i
] != NULL
; i
++ ) {
283 for ( j
= 0; si
->si_anlist
[j
].an_name
.bv_val
; j
++ ) {
285 if ( ( oc
= si
->si_anlist
[j
].an_oc
) ) {
287 while ( oc
->soc_required
[k
] ) {
288 if ( !strcmp( exattrs
[i
],
289 oc
->soc_required
[k
]->sat_cname
.bv_val
) ) {
290 ch_free( exattrs
[i
] );
291 for ( l
= i
; exattrs
[l
]; l
++ ) {
292 exattrs
[l
] = exattrs
[l
+1];
302 for ( i
= 0; exattrs
[i
] != NULL
; i
++ ) ;
305 exattrs
= (char **) ch_realloc( exattrs
, (i
+ 1)*sizeof(char *) );
308 si
->si_exattrs
= exattrs
;
311 typedef struct logschema
{
313 struct berval ls_req
;
314 struct berval ls_mod
;
315 struct berval ls_newRdn
;
316 struct berval ls_delRdn
;
317 struct berval ls_newSup
;
320 static logschema changelog_sc
= {
322 BER_BVC("changeType"),
325 BER_BVC("deleteOldRDN"),
326 BER_BVC("newSuperior")
329 static logschema accesslog_sc
= {
333 BER_BVC("reqNewRDN"),
334 BER_BVC("reqDeleteOldRDN"),
335 BER_BVC("reqNewSuperior")
343 BerElementBuffer berbuf
;
344 BerElement
*ber
= (BerElement
*)&berbuf
;
345 LDAPControl c
[2], *ctrls
[3];
349 char **attrs
, *lattrs
[8];
354 /* setup LDAP SYNC control */
355 ber_init2( ber
, NULL
, LBER_USE_DER
);
356 ber_set_option( ber
, LBER_OPT_BER_MEMCTX
, &ctx
);
358 /* If we're using a log but we have no state, then fallback to
359 * normal mode for a full refresh.
361 if ( si
->si_syncdata
&& !si
->si_syncCookie
.numcsns
) {
362 si
->si_logstate
= SYNCLOG_FALLBACK
;
365 /* Use the log parameters if we're in log mode */
366 if ( si
->si_syncdata
&& si
->si_logstate
== SYNCLOG_LOGGING
) {
368 if ( si
->si_syncdata
== SYNCDATA_ACCESSLOG
)
372 lattrs
[0] = ls
->ls_dn
.bv_val
;
373 lattrs
[1] = ls
->ls_req
.bv_val
;
374 lattrs
[2] = ls
->ls_mod
.bv_val
;
375 lattrs
[3] = ls
->ls_newRdn
.bv_val
;
376 lattrs
[4] = ls
->ls_delRdn
.bv_val
;
377 lattrs
[5] = ls
->ls_newSup
.bv_val
;
378 lattrs
[6] = slap_schema
.si_ad_entryCSN
->ad_cname
.bv_val
;
382 base
= si
->si_logbase
.bv_val
;
383 filter
= si
->si_logfilterstr
.bv_val
;
386 scope
= LDAP_SCOPE_SUBTREE
;
389 base
= si
->si_base
.bv_val
;
390 filter
= si
->si_filterstr
.bv_val
;
391 attrs
= si
->si_attrs
;
392 attrsonly
= si
->si_attrsonly
;
393 scope
= si
->si_scope
;
395 if ( si
->si_syncdata
&& si
->si_logstate
== SYNCLOG_FALLBACK
) {
396 si
->si_type
= LDAP_SYNC_REFRESH_ONLY
;
398 si
->si_type
= si
->si_ctype
;
401 if ( !BER_BVISNULL( &si
->si_syncCookie
.octet_str
) )
403 ber_printf( ber
, "{eOb}",
404 abs(si
->si_type
), &si
->si_syncCookie
.octet_str
, rhint
);
406 ber_printf( ber
, "{eb}",
407 abs(si
->si_type
), rhint
);
410 if ( (rc
= ber_flatten2( ber
, &c
[0].ldctl_value
, 0 ) ) == LBER_ERROR
) {
415 c
[0].ldctl_oid
= LDAP_CONTROL_SYNC
;
416 c
[0].ldctl_iscritical
= si
->si_type
< 0;
419 if ( !BER_BVISNULL( &si
->si_bindconf
.sb_authzId
) ) {
420 c
[1].ldctl_oid
= LDAP_CONTROL_PROXY_AUTHZ
;
421 c
[1].ldctl_value
= si
->si_bindconf
.sb_authzId
;
422 c
[1].ldctl_iscritical
= 1;
429 rc
= ldap_search_ext( si
->si_ld
, base
, scope
, filter
, attrs
, attrsonly
,
430 ctrls
, NULL
, NULL
, si
->si_slimit
, &si
->si_msgid
);
444 int i
, j
, changed
= 0;
446 /* Look for contextCSN from syncprov overlay. If
447 * there's no overlay, this will be a no-op. That means
448 * this is a pure consumer, so local changes will not be
449 * allowed, and all changes will already be reflected in
452 a
.a_desc
= slap_schema
.si_ad_contextCSN
;
454 e
.e_name
= op
->o_bd
->be_suffix
[0];
455 e
.e_nname
= op
->o_bd
->be_nsuffix
[0];
456 at
[0].an_name
= a
.a_desc
->ad_cname
;
457 at
[0].an_desc
= a
.a_desc
;
458 BER_BVZERO( &at
[1].an_name
);
460 rs
.sr_flags
= REP_ENTRY_MODIFIABLE
;
462 op
->o_req_dn
= e
.e_name
;
463 op
->o_req_ndn
= e
.e_nname
;
465 ldap_pvt_thread_mutex_lock( &si
->si_cookieState
->cs_mutex
);
466 i
= backend_operational( op
, &rs
);
467 if ( i
== LDAP_SUCCESS
&& a
.a_nvals
) {
468 int num
= a
.a_numvals
;
469 /* check for differences */
470 if ( num
!= si
->si_cookieState
->cs_num
) {
473 for ( i
=0; i
<num
; i
++ ) {
474 if ( ber_bvcmp( &a
.a_nvals
[i
],
475 &si
->si_cookieState
->cs_vals
[i
] )) {
482 ber_bvarray_free( si
->si_cookieState
->cs_vals
);
483 ch_free( si
->si_cookieState
->cs_sids
);
484 si
->si_cookieState
->cs_num
= num
;
485 si
->si_cookieState
->cs_vals
= a
.a_nvals
;
486 si
->si_cookieState
->cs_sids
= slap_parse_csn_sids( a
.a_nvals
,
488 si
->si_cookieState
->cs_age
++;
490 ber_bvarray_free( a
.a_nvals
);
492 ber_bvarray_free( a
.a_vals
);
494 /* See if the cookieState has changed due to anything outside
495 * this particular consumer. That includes other consumers in
496 * the same context, or local changes detected above.
498 if ( si
->si_cookieState
->cs_num
> 0 && si
->si_cookieAge
!=
499 si
->si_cookieState
->cs_age
) {
500 if ( !si
->si_syncCookie
.numcsns
) {
501 ber_bvarray_free( si
->si_syncCookie
.ctxcsn
);
502 ber_bvarray_dup_x( &si
->si_syncCookie
.ctxcsn
,
503 si
->si_cookieState
->cs_vals
, NULL
);
506 for (i
=0; !BER_BVISNULL( &si
->si_syncCookie
.ctxcsn
[i
] ); i
++) {
507 /* bogus, just dup everything */
508 if ( si
->si_syncCookie
.sids
[i
] == -1 ) {
509 ber_bvarray_free( si
->si_syncCookie
.ctxcsn
);
510 ber_bvarray_dup_x( &si
->si_syncCookie
.ctxcsn
,
511 si
->si_cookieState
->cs_vals
, NULL
);
515 for (j
=0; j
<si
->si_cookieState
->cs_num
; j
++) {
516 if ( si
->si_syncCookie
.sids
[i
] !=
517 si
->si_cookieState
->cs_sids
[j
] )
519 if ( bvmatch( &si
->si_syncCookie
.ctxcsn
[i
],
520 &si
->si_cookieState
->cs_vals
[j
] ))
522 ber_bvreplace( &si
->si_syncCookie
.ctxcsn
[i
],
523 &si
->si_cookieState
->cs_vals
[j
] );
531 si
->si_cookieAge
= si
->si_cookieState
->cs_age
;
532 ch_free( si
->si_syncCookie
.octet_str
.bv_val
);
533 slap_compose_sync_cookie( NULL
, &si
->si_syncCookie
.octet_str
,
534 si
->si_syncCookie
.ctxcsn
, si
->si_syncCookie
.rid
,
535 si
->si_syncCookie
.sid
);
537 ldap_pvt_thread_mutex_unlock( &si
->si_cookieState
->cs_mutex
);
547 int cmdline_cookie_found
= 0;
549 struct sync_cookie
*sc
= NULL
;
554 rc
= slap_client_connect( &si
->si_ld
, &si
->si_bindconf
);
555 if ( rc
!= LDAP_SUCCESS
) {
558 op
->o_protocol
= LDAP_VERSION3
;
560 /* Set SSF to strongest of TLS, SASL SSFs */
563 op
->o_transport_ssf
= 0;
565 if ( ldap_get_option( si
->si_ld
, LDAP_OPT_X_TLS_SSL_CTX
, &ssl
)
566 == LDAP_SUCCESS
&& ssl
!= NULL
)
568 op
->o_tls_ssf
= ldap_pvt_tls_get_strength( ssl
);
570 #endif /* HAVE_TLS */
572 ber_len_t ssf
; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
573 to use sasl_ssf_t but currently uses ber_len_t */
574 ldap_get_option( si
->si_ld
, LDAP_OPT_X_SASL_SSF
, &ssf
);
575 op
->o_sasl_ssf
= ssf
;
577 op
->o_ssf
= ( op
->o_sasl_ssf
> op
->o_tls_ssf
)
578 ? op
->o_sasl_ssf
: op
->o_tls_ssf
;
580 ldap_set_option( si
->si_ld
, LDAP_OPT_TIMELIMIT
, &si
->si_tlimit
);
582 si
->si_syncCookie
.rid
= si
->si_rid
;
584 /* whenever there are multiple data sources possible, advertise sid */
585 si
->si_syncCookie
.sid
= ( SLAP_MULTIMASTER( si
->si_be
) || si
->si_be
!= si
->si_wbe
) ?
588 /* We've just started up, or the remote server hasn't sent us
589 * any meaningful state.
591 if ( BER_BVISNULL( &si
->si_syncCookie
.octet_str
) ) {
594 LDAP_STAILQ_FOREACH( sc
, &slap_sync_cookie
, sc_next
) {
595 if ( si
->si_rid
== sc
->rid
) {
596 cmdline_cookie_found
= 1;
601 if ( cmdline_cookie_found
) {
602 /* cookie is supplied in the command line */
604 LDAP_STAILQ_REMOVE( &slap_sync_cookie
, sc
, sync_cookie
, sc_next
);
606 /* ctxcsn wasn't parsed yet, do it now */
607 slap_parse_sync_cookie( sc
, op
->o_tmpmemctx
);
608 slap_sync_cookie_free( &si
->si_syncCookie
, 0 );
609 slap_dup_sync_cookie( &si
->si_syncCookie
, sc
);
610 slap_sync_cookie_free( sc
, 1 );
612 ldap_pvt_thread_mutex_lock( &si
->si_cookieState
->cs_mutex
);
613 if ( !si
->si_cookieState
->cs_num
) {
614 /* get contextCSN shadow replica from database */
615 BerVarray csn
= NULL
;
616 void *ctx
= op
->o_tmpmemctx
;
618 op
->o_req_ndn
= op
->o_bd
->be_nsuffix
[0];
619 op
->o_req_dn
= op
->o_req_ndn
;
621 /* try to read stored contextCSN */
622 op
->o_tmpmemctx
= NULL
;
623 backend_attribute( op
, NULL
, &op
->o_req_ndn
,
624 slap_schema
.si_ad_contextCSN
, &csn
, ACL_READ
);
625 op
->o_tmpmemctx
= ctx
;
627 si
->si_cookieState
->cs_vals
= csn
;
628 for (i
=0; !BER_BVISNULL( &csn
[i
] ); i
++);
629 si
->si_cookieState
->cs_num
= i
;
630 si
->si_cookieState
->cs_sids
= slap_parse_csn_sids( csn
, i
, NULL
);
633 if ( si
->si_cookieState
->cs_num
) {
634 ber_bvarray_free( si
->si_syncCookie
.ctxcsn
);
635 if ( ber_bvarray_dup_x( &si
->si_syncCookie
.ctxcsn
,
636 si
->si_cookieState
->cs_vals
, NULL
)) {
638 ldap_pvt_thread_mutex_unlock( &si
->si_cookieState
->cs_mutex
);
641 si
->si_syncCookie
.numcsns
= si
->si_cookieState
->cs_num
;
642 si
->si_syncCookie
.sids
= ch_malloc( si
->si_cookieState
->cs_num
*
644 for ( i
=0; i
<si
->si_syncCookie
.numcsns
; i
++ )
645 si
->si_syncCookie
.sids
[i
] = si
->si_cookieState
->cs_sids
[i
];
647 ldap_pvt_thread_mutex_unlock( &si
->si_cookieState
->cs_mutex
);
650 slap_compose_sync_cookie( NULL
, &si
->si_syncCookie
.octet_str
,
651 si
->si_syncCookie
.ctxcsn
, si
->si_syncCookie
.rid
,
652 si
->si_syncCookie
.sid
);
654 /* Look for contextCSN from syncprov overlay. */
655 check_syncprov( op
, si
);
658 si
->si_refreshDone
= 0;
660 rc
= ldap_sync_search( si
, op
->o_tmpmemctx
);
662 if( rc
!= LDAP_SUCCESS
) {
663 Debug( LDAP_DEBUG_ANY
, "do_syncrep1: %s "
664 "ldap_search_ext: %s (%d)\n",
665 si
->si_ridtxt
, ldap_err2string( rc
), rc
);
671 ldap_unbind_ext( si
->si_ld
, NULL
, NULL
);
680 compare_csns( struct sync_cookie
*sc1
, struct sync_cookie
*sc2
, int *which
)
687 if ( sc1
->numcsns
< sc2
->numcsns
) {
688 *which
= sc1
->numcsns
;
692 for (j
=0; j
<sc2
->numcsns
; j
++) {
693 for (i
=0; i
<sc1
->numcsns
; i
++) {
694 if ( sc1
->sids
[i
] != sc2
->sids
[j
] )
696 value_match( &match
, slap_schema
.si_ad_entryCSN
,
697 slap_schema
.si_ad_entryCSN
->ad_type
->sat_ordering
,
698 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX
,
699 &sc1
->ctxcsn
[i
], &sc2
->ctxcsn
[j
], &text
);
706 if ( i
== sc1
->numcsns
) {
707 /* sc2 has a sid sc1 lacks */
715 #define SYNC_PAUSED -3
722 LDAPControl
**rctrls
= NULL
;
725 BerElementBuffer berbuf
;
726 BerElement
*ber
= (BerElement
*)&berbuf
;
728 LDAPMessage
*msg
= NULL
;
731 struct berval
*retdata
= NULL
;
736 struct berval syncUUID
= BER_BVNULL
;
737 struct sync_cookie syncCookie
= { NULL
};
738 struct sync_cookie syncCookie_req
= { NULL
};
739 struct berval cookie
= BER_BVNULL
;
746 Modifications
*modlist
= NULL
;
750 struct timeval
*tout_p
= NULL
;
751 struct timeval tout
= { 0, 0 };
753 int refreshDeletes
= 0;
754 BerVarray syncUUIDs
= NULL
;
757 if ( slapd_shutdown
) {
762 ber_init2( ber
, NULL
, LBER_USE_DER
);
763 ber_set_option( ber
, LBER_OPT_BER_MEMCTX
, &op
->o_tmpmemctx
);
765 Debug( LDAP_DEBUG_TRACE
, "=>do_syncrep2 %s\n", si
->si_ridtxt
, 0, 0 );
767 psub
= &si
->si_be
->be_nsuffix
[0];
769 slap_dup_sync_cookie( &syncCookie_req
, &si
->si_syncCookie
);
771 if ( abs(si
->si_type
) == LDAP_SYNC_REFRESH_AND_PERSIST
) {
777 while ( ( rc
= ldap_result( si
->si_ld
, si
->si_msgid
, LDAP_MSG_ONE
,
778 tout_p
, &msg
) ) > 0 )
780 if ( slapd_shutdown
) {
784 switch( ldap_msgtype( msg
) ) {
785 case LDAP_RES_SEARCH_ENTRY
:
786 ldap_get_entry_controls( si
->si_ld
, msg
, &rctrls
);
787 /* we can't work without the control */
791 /* NOTE: make sure we use the right one;
792 * a better approach would be to run thru
793 * the whole list and take care of all */
794 rctrlp
= ldap_control_find( LDAP_CONTROL_SYNC_STATE
, rctrls
, &next
);
795 if ( next
&& ldap_control_find( LDAP_CONTROL_SYNC_STATE
, next
, NULL
) )
797 Debug( LDAP_DEBUG_ANY
, "do_syncrep2: %s "
798 "got search entry with multiple "
799 "Sync State control\n", si
->si_ridtxt
, 0, 0 );
804 if ( rctrlp
== NULL
) {
805 Debug( LDAP_DEBUG_ANY
, "do_syncrep2: %s "
806 "got search entry without "
807 "Sync State control\n", si
->si_ridtxt
, 0, 0 );
811 ber_init2( ber
, &rctrlp
->ldctl_value
, LBER_USE_DER
);
812 ber_scanf( ber
, "{em" /*"}"*/, &syncstate
, &syncUUID
);
813 /* FIXME: what if syncUUID is NULL or empty?
814 * (happens with back-sql...) */
815 if ( BER_BVISEMPTY( &syncUUID
) ) {
816 Debug( LDAP_DEBUG_ANY
, "do_syncrep2: %s "
817 "got empty syncUUID with LDAP_SYNC_%s\n",
819 syncrepl_state2str( syncstate
), 0 );
820 ldap_controls_free( rctrls
);
824 if ( ber_peek_tag( ber
, &len
) == LDAP_TAG_SYNC_COOKIE
) {
825 ber_scanf( ber
, /*"{"*/ "m}", &cookie
);
827 Debug( LDAP_DEBUG_SYNC
, "do_syncrep2: cookie=%s\n",
828 BER_BVISNULL( &cookie
) ? "" : cookie
.bv_val
, 0, 0 );
830 if ( !BER_BVISNULL( &cookie
) ) {
831 ch_free( syncCookie
.octet_str
.bv_val
);
832 ber_dupbv( &syncCookie
.octet_str
, &cookie
);
834 if ( !BER_BVISNULL( &syncCookie
.octet_str
) )
836 slap_parse_sync_cookie( &syncCookie
, NULL
);
837 if ( syncCookie
.ctxcsn
) {
838 int i
, sid
= slap_parse_csn_sid( syncCookie
.ctxcsn
);
839 for ( i
=0; i
<si
->si_cookieState
->cs_num
; i
++ ) {
840 if ( si
->si_cookieState
->cs_sids
[i
] == sid
&&
841 ber_bvcmp( syncCookie
.ctxcsn
, &si
->si_cookieState
->cs_vals
[i
] ) <= 0 ) {
842 Debug( LDAP_DEBUG_SYNC
, "do_syncrep2: %s CSN too old, ignoring %s\n",
843 si
->si_ridtxt
, syncCookie
.ctxcsn
->bv_val
, 0 );
844 ldap_controls_free( rctrls
);
853 if ( si
->si_syncdata
&& si
->si_logstate
== SYNCLOG_LOGGING
) {
855 if ( ( rc
= syncrepl_message_to_op( si
, op
, msg
) ) == LDAP_SUCCESS
&&
858 rc
= syncrepl_updateCookie( si
, op
, psub
, &syncCookie
);
859 } else switch ( rc
) {
860 case LDAP_ALREADY_EXISTS
:
861 case LDAP_NO_SUCH_OBJECT
:
862 case LDAP_NO_SUCH_ATTRIBUTE
:
863 case LDAP_TYPE_OR_VALUE_EXISTS
:
864 rc
= LDAP_SYNC_REFRESH_REQUIRED
;
865 si
->si_logstate
= SYNCLOG_FALLBACK
;
866 ldap_abandon_ext( si
->si_ld
, si
->si_msgid
, NULL
, NULL
);
871 } else if ( ( rc
= syncrepl_message_to_entry( si
, op
, msg
,
872 &modlist
, &entry
, syncstate
) ) == LDAP_SUCCESS
)
874 if ( ( rc
= syncrepl_entry( si
, op
, entry
, &modlist
,
875 syncstate
, &syncUUID
, syncCookie
.ctxcsn
) ) == LDAP_SUCCESS
&&
878 rc
= syncrepl_updateCookie( si
, op
, psub
, &syncCookie
);
881 ldap_controls_free( rctrls
);
883 slap_mods_free( modlist
, 1 );
889 case LDAP_RES_SEARCH_REFERENCE
:
890 Debug( LDAP_DEBUG_ANY
,
891 "do_syncrep2: %s reference received error\n",
892 si
->si_ridtxt
, 0, 0 );
895 case LDAP_RES_SEARCH_RESULT
:
896 Debug( LDAP_DEBUG_SYNC
,
897 "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
898 si
->si_ridtxt
, 0, 0 );
899 ldap_parse_result( si
->si_ld
, msg
, &err
, NULL
, NULL
, NULL
,
901 #ifdef LDAP_X_SYNC_REFRESH_REQUIRED
902 if ( err
== LDAP_X_SYNC_REFRESH_REQUIRED
) {
903 /* map old result code to registered code */
904 err
= LDAP_SYNC_REFRESH_REQUIRED
;
907 if ( err
== LDAP_SYNC_REFRESH_REQUIRED
) {
908 if ( si
->si_logstate
== SYNCLOG_LOGGING
) {
909 si
->si_logstate
= SYNCLOG_FALLBACK
;
916 ber_init2( ber
, &rctrlp
->ldctl_value
, LBER_USE_DER
);
918 ber_scanf( ber
, "{" /*"}"*/);
919 if ( ber_peek_tag( ber
, &len
) == LDAP_TAG_SYNC_COOKIE
) {
920 ber_scanf( ber
, "m", &cookie
);
922 Debug( LDAP_DEBUG_SYNC
, "do_syncrep2: cookie=%s\n",
923 BER_BVISNULL( &cookie
) ? "" : cookie
.bv_val
, 0, 0 );
925 if ( !BER_BVISNULL( &cookie
) ) {
926 ch_free( syncCookie
.octet_str
.bv_val
);
927 ber_dupbv( &syncCookie
.octet_str
, &cookie
);
929 if ( !BER_BVISNULL( &syncCookie
.octet_str
) )
931 slap_parse_sync_cookie( &syncCookie
, NULL
);
934 if ( ber_peek_tag( ber
, &len
) == LDAP_TAG_REFRESHDELETES
)
936 ber_scanf( ber
, "b", &refreshDeletes
);
938 ber_scanf( ber
, /*"{"*/ "}" );
940 if ( SLAP_MULTIMASTER( op
->o_bd
) && check_syncprov( op
, si
)) {
941 slap_sync_cookie_free( &syncCookie_req
, 0 );
942 slap_dup_sync_cookie( &syncCookie_req
, &si
->si_syncCookie
);
944 if ( !syncCookie
.ctxcsn
) {
946 } else if ( !syncCookie_req
.ctxcsn
) {
950 match
= compare_csns( &syncCookie_req
, &syncCookie
, &m
);
953 ldap_controls_free( rctrls
);
955 if (si
->si_type
!= LDAP_SYNC_REFRESH_AND_PERSIST
) {
956 /* FIXME : different error behaviors according to
957 * 1) err code : LDAP_BUSY ...
958 * 2) on err policy : stop service, stop sync, retry
960 if ( refreshDeletes
== 0 && match
< 0 &&
961 err
== LDAP_SUCCESS
&&
962 syncCookie_req
.numcsns
== syncCookie
.numcsns
)
964 syncrepl_del_nonpresent( op
, si
, NULL
,
967 avl_free( si
->si_presentlist
, ch_free
);
968 si
->si_presentlist
= NULL
;
971 if ( syncCookie
.ctxcsn
&& match
< 0 && err
== LDAP_SUCCESS
)
973 rc
= syncrepl_updateCookie( si
, op
, psub
, &syncCookie
);
975 if ( err
== LDAP_SUCCESS
976 && si
->si_logstate
== SYNCLOG_FALLBACK
) {
977 si
->si_logstate
= SYNCLOG_LOGGING
;
978 rc
= LDAP_SYNC_REFRESH_REQUIRED
;
985 case LDAP_RES_INTERMEDIATE
:
986 rc
= ldap_parse_intermediate( si
->si_ld
, msg
,
987 &retoid
, &retdata
, NULL
, 0 );
988 if ( !rc
&& !strcmp( retoid
, LDAP_SYNC_INFO
) ) {
989 ber_init2( ber
, retdata
, LBER_USE_DER
);
991 switch ( si_tag
= ber_peek_tag( ber
, &len
) ) {
993 case LDAP_TAG_SYNC_NEW_COOKIE
:
994 Debug( LDAP_DEBUG_SYNC
,
995 "do_syncrep2: %s %s - %s\n",
997 "LDAP_RES_INTERMEDIATE",
999 ber_scanf( ber
, "tm", &tag
, &cookie
);
1001 case LDAP_TAG_SYNC_REFRESH_DELETE
:
1002 case LDAP_TAG_SYNC_REFRESH_PRESENT
:
1003 Debug( LDAP_DEBUG_SYNC
,
1004 "do_syncrep2: %s %s - %s\n",
1006 "LDAP_RES_INTERMEDIATE",
1007 si_tag
== LDAP_TAG_SYNC_REFRESH_PRESENT
?
1008 "REFRESH_PRESENT" : "REFRESH_DELETE" );
1009 if ( si_tag
== LDAP_TAG_SYNC_REFRESH_DELETE
) {
1010 si
->si_refreshDelete
= 1;
1012 si
->si_refreshPresent
= 1;
1014 ber_scanf( ber
, "t{" /*"}"*/, &tag
);
1015 if ( ber_peek_tag( ber
, &len
) == LDAP_TAG_SYNC_COOKIE
)
1017 ber_scanf( ber
, "m", &cookie
);
1019 Debug( LDAP_DEBUG_SYNC
, "do_syncrep2: cookie=%s\n",
1020 BER_BVISNULL( &cookie
) ? "" : cookie
.bv_val
, 0, 0 );
1022 if ( !BER_BVISNULL( &cookie
) ) {
1023 ch_free( syncCookie
.octet_str
.bv_val
);
1024 ber_dupbv( &syncCookie
.octet_str
, &cookie
);
1026 if ( !BER_BVISNULL( &syncCookie
.octet_str
) )
1028 slap_parse_sync_cookie( &syncCookie
, NULL
);
1031 /* Defaults to TRUE */
1032 if ( ber_peek_tag( ber
, &len
) ==
1033 LDAP_TAG_REFRESHDONE
)
1035 ber_scanf( ber
, "b", &si
->si_refreshDone
);
1038 si
->si_refreshDone
= 1;
1040 ber_scanf( ber
, /*"{"*/ "}" );
1042 case LDAP_TAG_SYNC_ID_SET
:
1043 Debug( LDAP_DEBUG_SYNC
,
1044 "do_syncrep2: %s %s - %s\n",
1046 "LDAP_RES_INTERMEDIATE",
1048 ber_scanf( ber
, "t{" /*"}"*/, &tag
);
1049 if ( ber_peek_tag( ber
, &len
) ==
1050 LDAP_TAG_SYNC_COOKIE
)
1052 ber_scanf( ber
, "m", &cookie
);
1054 Debug( LDAP_DEBUG_SYNC
, "do_syncrep2: cookie=%s\n",
1055 BER_BVISNULL( &cookie
) ? "" : cookie
.bv_val
, 0, 0 );
1057 if ( !BER_BVISNULL( &cookie
) ) {
1058 ch_free( syncCookie
.octet_str
.bv_val
);
1059 ber_dupbv( &syncCookie
.octet_str
, &cookie
);
1061 if ( !BER_BVISNULL( &syncCookie
.octet_str
) )
1063 slap_parse_sync_cookie( &syncCookie
, NULL
);
1064 compare_csns( &syncCookie_req
, &syncCookie
, &m
);
1067 if ( ber_peek_tag( ber
, &len
) ==
1068 LDAP_TAG_REFRESHDELETES
)
1070 ber_scanf( ber
, "b", &refreshDeletes
);
1072 ber_scanf( ber
, "[W]", &syncUUIDs
);
1073 ber_scanf( ber
, /*"{"*/ "}" );
1074 if ( refreshDeletes
) {
1075 syncrepl_del_nonpresent( op
, si
, syncUUIDs
,
1077 ber_bvarray_free_x( syncUUIDs
, op
->o_tmpmemctx
);
1080 for ( i
= 0; !BER_BVISNULL( &syncUUIDs
[i
] ); i
++ ) {
1081 (void)avl_presentlist_insert( si
, &syncUUIDs
[i
] );
1082 slap_sl_free( syncUUIDs
[i
].bv_val
, op
->o_tmpmemctx
);
1084 slap_sl_free( syncUUIDs
, op
->o_tmpmemctx
);
1086 slap_sync_cookie_free( &syncCookie
, 0 );
1089 Debug( LDAP_DEBUG_ANY
,
1090 "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
1091 si
->si_ridtxt
, (long) si_tag
, 0 );
1092 ldap_memfree( retoid
);
1093 ber_bvfree( retdata
);
1097 if ( SLAP_MULTIMASTER( op
->o_bd
) && check_syncprov( op
, si
)) {
1098 slap_sync_cookie_free( &syncCookie_req
, 0 );
1099 slap_dup_sync_cookie( &syncCookie_req
, &si
->si_syncCookie
);
1101 if ( !syncCookie
.ctxcsn
) {
1103 } else if ( !syncCookie_req
.ctxcsn
) {
1107 match
= compare_csns( &syncCookie_req
, &syncCookie
, &m
);
1111 if ( si
->si_refreshPresent
== 1 &&
1112 syncCookie_req
.numcsns
== syncCookie
.numcsns
) {
1113 syncrepl_del_nonpresent( op
, si
, NULL
,
1117 if ( syncCookie
.ctxcsn
)
1119 rc
= syncrepl_updateCookie( si
, op
, psub
, &syncCookie
);
1123 ldap_memfree( retoid
);
1124 ber_bvfree( retdata
);
1128 Debug( LDAP_DEBUG_ANY
, "do_syncrep2: %s "
1129 "unknown intermediate response (%d)\n",
1130 si
->si_ridtxt
, rc
, 0 );
1131 ldap_memfree( retoid
);
1132 ber_bvfree( retdata
);
1138 Debug( LDAP_DEBUG_ANY
, "do_syncrep2: %s "
1139 "unknown message (0x%02lx)\n",
1141 (unsigned long)ldap_msgtype( msg
), 0 );
1145 if ( !BER_BVISNULL( &syncCookie
.octet_str
) ) {
1146 slap_sync_cookie_free( &syncCookie_req
, 0 );
1147 slap_dup_sync_cookie( &syncCookie_req
, &syncCookie
);
1148 slap_sync_cookie_free( &syncCookie
, 0 );
1150 ldap_msgfree( msg
);
1152 if ( ldap_pvt_thread_pool_pausing( &connection_pool
)) {
1153 slap_sync_cookie_free( &syncCookie
, 0 );
1154 slap_sync_cookie_free( &syncCookie_req
, 0 );
1160 ldap_get_option( si
->si_ld
, LDAP_OPT_ERROR_NUMBER
, &rc
);
1165 if ( err
!= LDAP_SUCCESS
) {
1166 Debug( LDAP_DEBUG_ANY
,
1167 "do_syncrep2: %s (%d) %s\n",
1168 si
->si_ridtxt
, err
, ldap_err2string( err
) );
1171 slap_sync_cookie_free( &syncCookie
, 0 );
1172 slap_sync_cookie_free( &syncCookie_req
, 0 );
1174 if ( msg
) ldap_msgfree( msg
);
1176 if ( rc
&& rc
!= LDAP_SYNC_REFRESH_REQUIRED
&& si
->si_ld
) {
1177 if ( si
->si_conn
) {
1178 connection_client_stop( si
->si_conn
);
1181 ldap_unbind_ext( si
->si_ld
, NULL
, NULL
);
1193 struct re_s
* rtask
= arg
;
1194 syncinfo_t
*si
= ( syncinfo_t
* ) rtask
->arg
;
1195 Connection conn
= {0};
1196 OperationBuffer opbuf
;
1198 int rc
= LDAP_SUCCESS
;
1199 int dostop
= 0, do_setup
= 0;
1201 int i
, defer
= 1, fail
= 0;
1204 Debug( LDAP_DEBUG_TRACE
, "=>do_syncrepl %s\n", si
->si_ridtxt
, 0, 0 );
1209 /* There will never be more than one instance active */
1210 ldap_pvt_thread_mutex_lock( &si
->si_mutex
);
1212 switch( abs( si
->si_type
) ) {
1213 case LDAP_SYNC_REFRESH_ONLY
:
1214 case LDAP_SYNC_REFRESH_AND_PERSIST
:
1217 ldap_pvt_thread_mutex_unlock( &si
->si_mutex
);
1221 if ( slapd_shutdown
) {
1223 if ( si
->si_conn
) {
1224 connection_client_stop( si
->si_conn
);
1227 ldap_unbind_ext( si
->si_ld
, NULL
, NULL
);
1230 ldap_pvt_thread_mutex_unlock( &si
->si_mutex
);
1234 connection_fake_init( &conn
, &opbuf
, ctx
);
1237 /* use global malloc for now */
1238 op
->o_tmpmemctx
= NULL
;
1239 op
->o_tmpmfuncs
= &ch_mfuncs
;
1241 op
->o_managedsait
= SLAP_CONTROL_NONCRITICAL
;
1244 /* Coordinate contextCSN updates with any syncprov overlays
1245 * in use. This may be complicated by the use of the glue
1248 * Typically there is a single syncprov mastering the entire
1249 * glued tree. In that case, our contextCSN updates should
1250 * go to the master DB. But if there is no syncprov on the
1251 * master DB, then nothing special is needed here.
1253 * Alternatively, there may be individual syncprov overlays
1254 * on each glued branch. In that case, each syncprov only
1255 * knows about changes within its own branch. And so our
1256 * contextCSN updates should only go to the local DB.
1258 if ( !si
->si_wbe
) {
1259 if ( SLAP_GLUE_SUBORDINATE( be
) && !overlay_is_inst( be
, "syncprov" )) {
1260 BackendDB
* top_be
= select_backend( &be
->be_nsuffix
[0], 1 );
1261 if ( overlay_is_inst( top_be
, "syncprov" ))
1262 si
->si_wbe
= select_backend( &be
->be_nsuffix
[0], 1 );
1269 if ( !si
->si_schemachecking
)
1270 op
->o_no_schema_check
= 1;
1272 /* Establish session, do search */
1274 si
->si_refreshDelete
= 0;
1275 si
->si_refreshPresent
= 0;
1277 /* use main DB when retrieving contextCSN */
1278 op
->o_bd
= si
->si_wbe
;
1279 op
->o_dn
= op
->o_bd
->be_rootdn
;
1280 op
->o_ndn
= op
->o_bd
->be_rootndn
;
1281 rc
= do_syncrep1( op
, si
);
1285 /* Process results */
1286 if ( rc
== LDAP_SUCCESS
) {
1287 ldap_get_option( si
->si_ld
, LDAP_OPT_DESC
, &s
);
1289 /* use current DB */
1291 op
->o_dn
= op
->o_bd
->be_rootdn
;
1292 op
->o_ndn
= op
->o_bd
->be_rootndn
;
1293 rc
= do_syncrep2( op
, si
);
1294 if ( rc
== LDAP_SYNC_REFRESH_REQUIRED
) {
1295 rc
= ldap_sync_search( si
, op
->o_tmpmemctx
);
1299 /* We got deleted while running on cn=config */
1300 if ( !si
->si_ctype
) {
1306 if ( rc
!= SYNC_PAUSED
) {
1307 if ( abs(si
->si_type
) == LDAP_SYNC_REFRESH_AND_PERSIST
) {
1308 /* If we succeeded, enable the connection for further listening.
1309 * If we failed, tear down the connection and reschedule.
1311 if ( rc
== LDAP_SUCCESS
) {
1312 if ( si
->si_conn
) {
1313 connection_client_enable( si
->si_conn
);
1318 } else if ( si
->si_conn
) {
1322 if ( rc
== -2 ) rc
= 0;
1327 /* At this point, we have 5 cases:
1328 * 1) for any hard failure, give up and remove this task
1329 * 2) for ServerDown, reschedule this task to run later
1330 * 3) for threadpool pause, reschedule to run immediately
1331 * 4) for Refresh and Success, reschedule to run
1332 * 5) for Persist and Success, reschedule to defer
1334 ldap_pvt_thread_mutex_lock( &slapd_rq
.rq_mutex
);
1336 if ( ldap_pvt_runqueue_isrunning( &slapd_rq
, rtask
) ) {
1337 ldap_pvt_runqueue_stoptask( &slapd_rq
, rtask
);
1341 connection_client_stop( si
->si_conn
);
1345 if ( rc
== SYNC_PAUSED
) {
1346 rtask
->interval
.tv_sec
= 0;
1347 ldap_pvt_runqueue_resched( &slapd_rq
, rtask
, 0 );
1349 } else if ( rc
== LDAP_SUCCESS
) {
1350 if ( si
->si_type
== LDAP_SYNC_REFRESH_ONLY
) {
1353 rtask
->interval
.tv_sec
= si
->si_interval
;
1354 ldap_pvt_runqueue_resched( &slapd_rq
, rtask
, defer
);
1355 if ( si
->si_retrynum
) {
1356 for ( i
= 0; si
->si_retrynum_init
[i
] != RETRYNUM_TAIL
; i
++ ) {
1357 si
->si_retrynum
[i
] = si
->si_retrynum_init
[i
];
1359 si
->si_retrynum
[i
] = RETRYNUM_TAIL
;
1362 for ( i
= 0; si
->si_retrynum
&& si
->si_retrynum
[i
] <= 0; i
++ ) {
1363 if ( si
->si_retrynum
[i
] == RETRYNUM_FOREVER
|| si
->si_retrynum
[i
] == RETRYNUM_TAIL
)
1368 || !si
->si_retrynum
|| si
->si_retrynum
[i
] == RETRYNUM_TAIL
) {
1369 ldap_pvt_runqueue_remove( &slapd_rq
, rtask
);
1370 fail
= RETRYNUM_TAIL
;
1371 } else if ( RETRYNUM_VALID( si
->si_retrynum
[i
] ) ) {
1372 if ( si
->si_retrynum
[i
] > 0 )
1373 si
->si_retrynum
[i
]--;
1374 fail
= si
->si_retrynum
[i
];
1375 rtask
->interval
.tv_sec
= si
->si_retryinterval
[i
];
1376 ldap_pvt_runqueue_resched( &slapd_rq
, rtask
, 0 );
1377 slap_wake_listener();
1381 ldap_pvt_thread_mutex_unlock( &slapd_rq
.rq_mutex
);
1384 si
->si_conn
= connection_client_setup( s
, do_syncrepl
, arg
);
1387 ldap_pvt_thread_mutex_unlock( &si
->si_mutex
);
1390 if ( fail
== RETRYNUM_TAIL
) {
1391 Debug( LDAP_DEBUG_ANY
,
1392 "do_syncrepl: %s quitting\n",
1393 si
->si_ridtxt
, 0, 0 );
1394 } else if ( fail
> 0 ) {
1395 Debug( LDAP_DEBUG_ANY
,
1396 "do_syncrepl: %s retrying (%d retries left)\n",
1397 si
->si_ridtxt
, fail
, 0 );
1399 Debug( LDAP_DEBUG_ANY
,
1400 "do_syncrepl: %s retrying\n",
1401 si
->si_ridtxt
, 0, 0 );
1405 /* Do final delete cleanup */
1406 if ( !si
->si_ctype
) {
1407 cookie_state
*cs
= NULL
;
1410 cs
= be
->be_syncinfo
->si_cookieState
;
1411 for ( sip
= &be
->be_syncinfo
; *sip
!= si
; sip
= &(*sip
)->si_next
);
1413 syncinfo_free( si
, 0 );
1414 if ( !be
->be_syncinfo
) {
1415 SLAP_DBFLAGS( be
) &= ~(SLAP_DBFLAG_SHADOW
|SLAP_DBFLAG_SYNC_SHADOW
);
1417 ch_free( cs
->cs_sids
);
1418 ber_bvarray_free( cs
->cs_vals
);
1419 ldap_pvt_thread_mutex_destroy( &cs
->cs_mutex
);
1427 static slap_verbmasks modops
[] = {
1428 { BER_BVC("add"), LDAP_REQ_ADD
},
1429 { BER_BVC("delete"), LDAP_REQ_DELETE
},
1430 { BER_BVC("modify"), LDAP_REQ_MODIFY
},
1431 { BER_BVC("modrdn"), LDAP_REQ_MODRDN
},
1435 static Modifications
*
1436 syncrepl_accesslog_mods(
1443 AttributeDescription
*ad
;
1444 struct berval bv
, bv2
;
1446 Modifications
*mod
= NULL
, *modlist
= NULL
, **modtail
;
1451 for (i
=0; !BER_BVISNULL( &vals
[i
] ); i
++) {
1455 colon
= ber_bvchr( &bv
, ':' );
1461 bv
.bv_len
= colon
- bv
.bv_val
;
1462 if ( slap_bv2ad( &bv
, &ad
, &text
) ) {
1467 /* Ignore dynamically generated attrs */
1468 if ( ad
->ad_type
->sat_flags
& SLAP_AT_DYNAMIC
) {
1472 /* Ignore excluded attrs */
1473 if ( ldap_charray_inlist( si
->si_exattrs
,
1474 ad
->ad_type
->sat_cname
.bv_val
) )
1480 case '+': op
= LDAP_MOD_ADD
; break;
1481 case '-': op
= LDAP_MOD_DELETE
; break;
1482 case '=': op
= LDAP_MOD_REPLACE
; break;
1483 case '#': op
= LDAP_MOD_INCREMENT
; break;
1487 if ( !mod
|| ad
!= mod
->sml_desc
|| op
!= mod
->sml_op
) {
1488 mod
= (Modifications
*) ch_malloc( sizeof( Modifications
) );
1491 mod
->sml_next
= NULL
;
1493 mod
->sml_type
= ad
->ad_cname
;
1494 mod
->sml_values
= NULL
;
1495 mod
->sml_nvalues
= NULL
;
1496 mod
->sml_numvals
= 0;
1499 modtail
= &mod
->sml_next
;
1501 if ( colon
[2] == ' ' ) {
1502 bv
.bv_val
= colon
+ 3;
1503 bv
.bv_len
= vals
[i
].bv_len
- ( bv
.bv_val
- vals
[i
].bv_val
);
1504 ber_dupbv( &bv2
, &bv
);
1505 ber_bvarray_add( &mod
->sml_values
, &bv2
);
1512 static Modifications
*
1513 syncrepl_changelog_mods(
1518 return NULL
; /* FIXME */
1522 syncrepl_message_to_op(
1528 BerElement
*ber
= NULL
;
1529 Modifications
*modlist
= NULL
;
1531 SlapReply rs
= { REP_RESULT
};
1532 slap_callback cb
= { NULL
, null_callback
, NULL
, NULL
};
1535 char txtbuf
[SLAP_TEXT_BUFLEN
];
1536 size_t textlen
= sizeof txtbuf
;
1538 struct berval bdn
, dn
= BER_BVNULL
, ndn
;
1539 struct berval bv
, *bvals
= NULL
;
1540 struct berval rdn
= BER_BVNULL
, sup
= BER_BVNULL
,
1541 prdn
= BER_BVNULL
, nrdn
= BER_BVNULL
,
1542 psup
= BER_BVNULL
, nsup
= BER_BVNULL
;
1543 int rc
, deleteOldRdn
= 0, freeReqDn
= 0;
1545 if ( ldap_msgtype( msg
) != LDAP_RES_SEARCH_ENTRY
) {
1546 Debug( LDAP_DEBUG_ANY
, "syncrepl_message_to_op: %s "
1547 "Message type should be entry (%d)",
1548 si
->si_ridtxt
, ldap_msgtype( msg
), 0 );
1552 if ( si
->si_syncdata
== SYNCDATA_ACCESSLOG
)
1557 rc
= ldap_get_dn_ber( si
->si_ld
, msg
, &ber
, &bdn
);
1559 if ( rc
!= LDAP_SUCCESS
) {
1560 Debug( LDAP_DEBUG_ANY
,
1561 "syncrepl_message_to_op: %s dn get failed (%d)",
1562 si
->si_ridtxt
, rc
, 0 );
1566 op
->o_tag
= LBER_DEFAULT
;
1567 op
->o_bd
= si
->si_wbe
;
1569 while (( rc
= ldap_get_attribute_ber( si
->si_ld
, msg
, ber
, &bv
, &bvals
) )
1571 if ( bv
.bv_val
== NULL
)
1574 if ( !ber_bvstrcasecmp( &bv
, &ls
->ls_dn
) ) {
1576 dnPrettyNormal( NULL
, &bdn
, &dn
, &ndn
, op
->o_tmpmemctx
);
1577 ber_dupbv( &op
->o_req_dn
, &dn
);
1578 ber_dupbv( &op
->o_req_ndn
, &ndn
);
1579 slap_sl_free( ndn
.bv_val
, op
->o_tmpmemctx
);
1580 slap_sl_free( dn
.bv_val
, op
->o_tmpmemctx
);
1582 } else if ( !ber_bvstrcasecmp( &bv
, &ls
->ls_req
) ) {
1583 int i
= verb_to_mask( bvals
[0].bv_val
, modops
);
1585 Debug( LDAP_DEBUG_ANY
,
1586 "syncrepl_message_to_op: %s unknown op %s",
1587 si
->si_ridtxt
, bvals
[0].bv_val
, 0 );
1592 op
->o_tag
= modops
[i
].mask
;
1593 } else if ( !ber_bvstrcasecmp( &bv
, &ls
->ls_mod
) ) {
1594 /* Parse attribute into modlist */
1595 if ( si
->si_syncdata
== SYNCDATA_ACCESSLOG
) {
1596 modlist
= syncrepl_accesslog_mods( si
, bvals
);
1598 modlist
= syncrepl_changelog_mods( si
, bvals
);
1600 } else if ( !ber_bvstrcasecmp( &bv
, &ls
->ls_newRdn
) ) {
1602 } else if ( !ber_bvstrcasecmp( &bv
, &ls
->ls_delRdn
) ) {
1603 if ( !ber_bvstrcasecmp( &slap_true_bv
, bvals
) ) {
1606 } else if ( !ber_bvstrcasecmp( &bv
, &ls
->ls_newSup
) ) {
1608 } else if ( !ber_bvstrcasecmp( &bv
,
1609 &slap_schema
.si_ad_entryCSN
->ad_cname
) )
1611 slap_queue_csn( op
, bvals
);
1616 /* If we didn't get a mod type or a target DN, bail out */
1617 if ( op
->o_tag
== LBER_DEFAULT
|| BER_BVISNULL( &dn
) ) {
1622 op
->o_callback
= &cb
;
1623 slap_op_time( &op
->o_time
, &op
->o_tincr
);
1625 switch( op
->o_tag
) {
1627 case LDAP_REQ_MODIFY
:
1628 /* If we didn't get required data, bail */
1629 if ( !modlist
) goto done
;
1631 rc
= slap_mods_check( op
, modlist
, &text
, txtbuf
, textlen
, NULL
);
1633 if ( rc
!= LDAP_SUCCESS
) {
1634 Debug( LDAP_DEBUG_ANY
, "syncrepl_message_to_op: %s "
1635 "mods check (%s)\n",
1636 si
->si_ridtxt
, text
, 0 );
1640 if ( op
->o_tag
== LDAP_REQ_ADD
) {
1641 Entry
*e
= entry_alloc();
1643 op
->ora_e
->e_name
= op
->o_req_dn
;
1644 op
->ora_e
->e_nname
= op
->o_req_ndn
;
1646 rc
= slap_mods2entry( modlist
, &op
->ora_e
, 1, 0, &text
, txtbuf
, textlen
);
1647 if( rc
!= LDAP_SUCCESS
) {
1648 Debug( LDAP_DEBUG_ANY
, "syncrepl_message_to_op: %s "
1649 "mods2entry (%s)\n",
1650 si
->si_ridtxt
, text
, 0 );
1652 rc
= op
->o_bd
->be_add( op
, &rs
);
1653 Debug( LDAP_DEBUG_SYNC
,
1654 "syncrepl_message_to_op: %s be_add %s (%d)\n",
1655 si
->si_ridtxt
, op
->o_req_dn
.bv_val
, rc
);
1657 if ( e
== op
->ora_e
)
1658 be_entry_release_w( op
, op
->ora_e
);
1660 op
->orm_modlist
= modlist
;
1661 op
->o_bd
= si
->si_wbe
;
1662 rc
= op
->o_bd
->be_modify( op
, &rs
);
1663 modlist
= op
->orm_modlist
;
1664 Debug( rc
? LDAP_DEBUG_ANY
: LDAP_DEBUG_SYNC
,
1665 "syncrepl_message_to_op: %s be_modify %s (%d)\n",
1666 si
->si_ridtxt
, op
->o_req_dn
.bv_val
, rc
);
1667 op
->o_bd
= si
->si_be
;
1670 case LDAP_REQ_MODRDN
:
1671 if ( BER_BVISNULL( &rdn
) ) goto done
;
1673 if ( rdnPretty( NULL
, &rdn
, &prdn
, NULL
) ) {
1676 if ( rdnNormalize( 0, NULL
, NULL
, &rdn
, &nrdn
, NULL
) ) {
1679 if ( !BER_BVISNULL( &sup
) ) {
1680 if ( dnPrettyNormal( NULL
, &sup
, &psup
, &nsup
, NULL
) ) {
1683 op
->orr_newSup
= &psup
;
1684 op
->orr_nnewSup
= &nsup
;
1686 op
->orr_newSup
= NULL
;
1687 op
->orr_nnewSup
= NULL
;
1689 op
->orr_newrdn
= prdn
;
1690 op
->orr_nnewrdn
= nrdn
;
1691 op
->orr_deleteoldrdn
= deleteOldRdn
;
1692 op
->orr_modlist
= NULL
;
1693 if ( slap_modrdn2mods( op
, &rs
) ) {
1697 /* Append modlist for operational attrs */
1701 for ( m
= op
->orr_modlist
; m
->sml_next
; m
= m
->sml_next
)
1703 m
->sml_next
= modlist
;
1706 rc
= op
->o_bd
->be_modrdn( op
, &rs
);
1707 slap_mods_free( op
->orr_modlist
, 1 );
1708 Debug( rc
? LDAP_DEBUG_ANY
: LDAP_DEBUG_SYNC
,
1709 "syncrepl_message_to_op: %s be_modrdn %s (%d)\n",
1710 si
->si_ridtxt
, op
->o_req_dn
.bv_val
, rc
);
1712 case LDAP_REQ_DELETE
:
1713 rc
= op
->o_bd
->be_delete( op
, &rs
);
1714 Debug( rc
? LDAP_DEBUG_ANY
: LDAP_DEBUG_SYNC
,
1715 "syncrepl_message_to_op: %s be_delete %s (%d)\n",
1716 si
->si_ridtxt
, op
->o_req_dn
.bv_val
, rc
);
1720 slap_graduate_commit_csn( op
);
1721 op
->o_bd
= si
->si_be
;
1722 op
->o_tmpfree( op
->o_csn
.bv_val
, op
->o_tmpmemctx
);
1723 BER_BVZERO( &op
->o_csn
);
1725 slap_mods_free( modlist
, op
->o_tag
!= LDAP_REQ_ADD
);
1727 if ( !BER_BVISNULL( &rdn
) ) {
1728 if ( !BER_BVISNULL( &nsup
) ) {
1729 ch_free( nsup
.bv_val
);
1731 if ( !BER_BVISNULL( &psup
) ) {
1732 ch_free( psup
.bv_val
);
1734 if ( !BER_BVISNULL( &nrdn
) ) {
1735 ch_free( nrdn
.bv_val
);
1737 if ( !BER_BVISNULL( &prdn
) ) {
1738 ch_free( prdn
.bv_val
);
1742 ch_free( op
->o_req_ndn
.bv_val
);
1743 ch_free( op
->o_req_dn
.bv_val
);
1750 syncrepl_message_to_entry(
1754 Modifications
**modlist
,
1760 BerElement
*ber
= NULL
;
1763 Modifications
**modtail
= modlist
;
1766 char txtbuf
[SLAP_TEXT_BUFLEN
];
1767 size_t textlen
= sizeof txtbuf
;
1769 struct berval bdn
= BER_BVNULL
, dn
, ndn
;
1774 if ( ldap_msgtype( msg
) != LDAP_RES_SEARCH_ENTRY
) {
1775 Debug( LDAP_DEBUG_ANY
, "syncrepl_message_to_entry: %s "
1776 "Message type should be entry (%d)",
1777 si
->si_ridtxt
, ldap_msgtype( msg
), 0 );
1781 op
->o_tag
= LDAP_REQ_ADD
;
1783 rc
= ldap_get_dn_ber( si
->si_ld
, msg
, &ber
, &bdn
);
1784 if ( rc
!= LDAP_SUCCESS
) {
1785 Debug( LDAP_DEBUG_ANY
,
1786 "syncrepl_message_to_entry: %s dn get failed (%d)",
1787 si
->si_ridtxt
, rc
, 0 );
1791 if ( syncstate
== LDAP_SYNC_PRESENT
|| syncstate
== LDAP_SYNC_DELETE
) {
1792 /* NOTE: this could be done even before decoding the DN,
1793 * although encoding errors wouldn't be detected */
1798 if ( entry
== NULL
) {
1802 dnPrettyNormal( NULL
, &bdn
, &dn
, &ndn
, op
->o_tmpmemctx
);
1803 ber_dupbv( &op
->o_req_dn
, &dn
);
1804 ber_dupbv( &op
->o_req_ndn
, &ndn
);
1805 slap_sl_free( ndn
.bv_val
, op
->o_tmpmemctx
);
1806 slap_sl_free( dn
.bv_val
, op
->o_tmpmemctx
);
1808 is_ctx
= dn_match( &op
->o_req_ndn
, &op
->o_bd
->be_nsuffix
[0] );
1811 e
->e_name
= op
->o_req_dn
;
1812 e
->e_nname
= op
->o_req_ndn
;
1814 while ( ber_remaining( ber
) ) {
1815 if ( (ber_scanf( ber
, "{mW}", &tmp
.sml_type
, &tmp
.sml_values
) ==
1816 LBER_ERROR
) || BER_BVISNULL( &tmp
.sml_type
) )
1821 /* Drop all updates to the contextCSN of the context entry
1824 if ( is_ctx
&& !strcasecmp( tmp
.sml_type
.bv_val
,
1825 slap_schema
.si_ad_contextCSN
->ad_cname
.bv_val
)) {
1826 ber_bvarray_free( tmp
.sml_values
);
1830 mod
= (Modifications
*) ch_malloc( sizeof( Modifications
) );
1832 mod
->sml_op
= LDAP_MOD_REPLACE
;
1834 mod
->sml_next
= NULL
;
1835 mod
->sml_desc
= NULL
;
1836 mod
->sml_type
= tmp
.sml_type
;
1837 mod
->sml_values
= tmp
.sml_values
;
1838 mod
->sml_nvalues
= NULL
;
1839 mod
->sml_numvals
= 0; /* slap_mods_check will set this */
1842 modtail
= &mod
->sml_next
;
1845 if ( *modlist
== NULL
) {
1846 Debug( LDAP_DEBUG_ANY
, "syncrepl_message_to_entry: %s no attributes\n",
1847 si
->si_ridtxt
, 0, 0 );
1852 rc
= slap_mods_check( op
, *modlist
, &text
, txtbuf
, textlen
, NULL
);
1854 if ( rc
!= LDAP_SUCCESS
) {
1855 Debug( LDAP_DEBUG_ANY
, "syncrepl_message_to_entry: %s mods check (%s)\n",
1856 si
->si_ridtxt
, text
, 0 );
1860 /* Strip out dynamically generated attrs */
1861 for ( modtail
= modlist
; *modtail
; ) {
1863 if ( mod
->sml_desc
->ad_type
->sat_flags
& SLAP_AT_DYNAMIC
) {
1864 *modtail
= mod
->sml_next
;
1865 slap_mod_free( &mod
->sml_mod
, 0 );
1868 modtail
= &mod
->sml_next
;
1872 /* Strip out attrs in exattrs list */
1873 for ( modtail
= modlist
; *modtail
; ) {
1875 if ( ldap_charray_inlist( si
->si_exattrs
,
1876 mod
->sml_desc
->ad_type
->sat_cname
.bv_val
) )
1878 *modtail
= mod
->sml_next
;
1879 slap_mod_free( &mod
->sml_mod
, 0 );
1882 modtail
= &mod
->sml_next
;
1886 rc
= slap_mods2entry( *modlist
, &e
, 1, 1, &text
, txtbuf
, textlen
);
1887 if( rc
!= LDAP_SUCCESS
) {
1888 Debug( LDAP_DEBUG_ANY
, "syncrepl_message_to_entry: %s mods2entry (%s)\n",
1889 si
->si_ridtxt
, text
, 0 );
1894 if ( rc
!= LDAP_SUCCESS
) {
1906 static struct berval generic_filterstr
= BER_BVC("(objectclass=*)");
1908 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
1909 * entry if a previous refresh was interrupted before sending us a new
1910 * context state. We try to compare the new entry to the existing entry
1911 * and ignore the new entry if they are the same.
1913 * Also, we may get an update where the entryDN has changed, due to
1914 * a ModDn on the provider. We detect this as well, so we can issue
1915 * the corresponding operation locally.
1917 * In the case of a modify, we get a list of all the attributes
1918 * in the original entry. Rather than deleting the entry and re-adding it,
1919 * we issue a Modify request that deletes all the attributes and adds all
1920 * the new ones. This avoids the issue of trying to delete/add a non-leaf
1923 * We otherwise distinguish ModDN from Modify; in the case of
1924 * a ModDN we just use the CSN, modifyTimestamp and modifiersName
1925 * operational attributes from the entry, and do a regular ModDN.
1927 typedef struct dninfo
{
1931 int renamed
; /* Was an existing entry renamed? */
1932 int delOldRDN
; /* Was old RDN deleted? */
1933 Modifications
**modlist
; /* the modlist we received */
1934 Modifications
*mods
; /* the modlist we compared */
1937 /* return 1 if inserted, 0 otherwise */
1939 avl_presentlist_insert(
1941 struct berval
*syncUUID
)
1943 struct berval
*syncuuid_bv
= ch_malloc( sizeof( struct berval
) + syncUUID
->bv_len
+ 1 );
1945 syncuuid_bv
->bv_len
= syncUUID
->bv_len
;
1946 syncuuid_bv
->bv_val
= (char *)&syncuuid_bv
[1];
1947 AC_MEMCPY( syncuuid_bv
->bv_val
, syncUUID
->bv_val
, syncUUID
->bv_len
);
1948 syncuuid_bv
->bv_val
[ syncuuid_bv
->bv_len
] = '\0';
1950 if ( avl_insert( &si
->si_presentlist
, (caddr_t
) syncuuid_bv
,
1951 syncuuid_cmp
, avl_dup_error
) )
1953 ch_free( syncuuid_bv
);
1965 Modifications
** modlist
,
1967 struct berval
* syncUUID
,
1968 struct berval
* syncCSN
)
1970 Backend
*be
= op
->o_bd
;
1971 slap_callback cb
= { NULL
, NULL
, NULL
, NULL
};
1972 int syncuuid_inserted
= 0;
1973 struct berval syncUUID_strrep
= BER_BVNULL
;
1975 SlapReply rs_search
= {REP_RESULT
};
1976 SlapReply rs_delete
= {REP_RESULT
};
1977 SlapReply rs_add
= {REP_RESULT
};
1978 SlapReply rs_modify
= {REP_RESULT
};
1980 AttributeAssertion ava
= ATTRIBUTEASSERTION_INIT
;
1981 int rc
= LDAP_SUCCESS
;
1983 struct berval pdn
= BER_BVNULL
;
1988 Debug( LDAP_DEBUG_SYNC
,
1989 "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s)\n",
1990 si
->si_ridtxt
, syncrepl_state2str( syncstate
), 0 );
1992 if (( syncstate
== LDAP_SYNC_PRESENT
|| syncstate
== LDAP_SYNC_ADD
) ) {
1993 if ( !si
->si_refreshPresent
&& !si
->si_refreshDone
) {
1994 syncuuid_inserted
= avl_presentlist_insert( si
, syncUUID
);
1998 if ( syncstate
== LDAP_SYNC_PRESENT
) {
2000 } else if ( syncstate
!= LDAP_SYNC_DELETE
) {
2001 if ( entry
== NULL
) {
2006 (void)slap_uuidstr_from_normalized( &syncUUID_strrep
, syncUUID
, op
->o_tmpmemctx
);
2007 if ( syncstate
!= LDAP_SYNC_DELETE
) {
2008 Attribute
*a
= attr_find( entry
->e_attrs
, slap_schema
.si_ad_entryUUID
);
2011 /* add if missing */
2012 attr_merge_one( entry
, slap_schema
.si_ad_entryUUID
,
2013 &syncUUID_strrep
, syncUUID
);
2015 } else if ( !bvmatch( &a
->a_nvals
[0], syncUUID
) ) {
2016 /* replace only if necessary */
2017 if ( a
->a_nvals
!= a
->a_vals
) {
2018 ber_memfree( a
->a_nvals
[0].bv_val
);
2019 ber_dupbv( &a
->a_nvals
[0], syncUUID
);
2021 ber_memfree( a
->a_vals
[0].bv_val
);
2022 ber_dupbv( &a
->a_vals
[0], &syncUUID_strrep
);
2026 f
.f_choice
= LDAP_FILTER_EQUALITY
;
2028 ava
.aa_desc
= slap_schema
.si_ad_entryUUID
;
2029 ava
.aa_value
= *syncUUID
;
2031 if ( syncuuid_inserted
) {
2032 Debug( LDAP_DEBUG_SYNC
, "syncrepl_entry: %s inserted UUID %s\n",
2033 si
->si_ridtxt
, syncUUID_strrep
.bv_val
, 0 );
2035 op
->ors_filter
= &f
;
2037 op
->ors_filterstr
.bv_len
= STRLENOF( "(entryUUID=)" ) + syncUUID_strrep
.bv_len
;
2038 op
->ors_filterstr
.bv_val
= (char *) slap_sl_malloc(
2039 op
->ors_filterstr
.bv_len
+ 1, op
->o_tmpmemctx
);
2040 AC_MEMCPY( op
->ors_filterstr
.bv_val
, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
2041 AC_MEMCPY( &op
->ors_filterstr
.bv_val
[STRLENOF( "(entryUUID=" )],
2042 syncUUID_strrep
.bv_val
, syncUUID_strrep
.bv_len
);
2043 op
->ors_filterstr
.bv_val
[op
->ors_filterstr
.bv_len
- 1] = ')';
2044 op
->ors_filterstr
.bv_val
[op
->ors_filterstr
.bv_len
] = '\0';
2046 op
->o_tag
= LDAP_REQ_SEARCH
;
2047 op
->ors_scope
= LDAP_SCOPE_SUBTREE
;
2048 op
->ors_deref
= LDAP_DEREF_NEVER
;
2050 /* get the entry for this UUID */
2051 op
->o_req_dn
= si
->si_base
;
2052 op
->o_req_ndn
= si
->si_base
;
2054 op
->o_time
= slap_get_time();
2055 op
->ors_tlimit
= SLAP_NO_LIMIT
;
2058 op
->ors_attrs
= slap_anlist_all_attributes
;
2059 op
->ors_attrsonly
= 0;
2061 /* set callback function */
2062 op
->o_callback
= &cb
;
2063 cb
.sc_response
= dn_callback
;
2064 cb
.sc_private
= &dni
;
2065 dni
.new_entry
= entry
;
2066 dni
.modlist
= modlist
;
2068 if ( limits_check( op
, &rs_search
) == 0 ) {
2069 rc
= be
->be_search( op
, &rs_search
);
2070 Debug( LDAP_DEBUG_SYNC
,
2071 "syncrepl_entry: %s be_search (%d)\n",
2072 si
->si_ridtxt
, rc
, 0 );
2075 if ( !BER_BVISNULL( &op
->ors_filterstr
) ) {
2076 slap_sl_free( op
->ors_filterstr
.bv_val
, op
->o_tmpmemctx
);
2079 cb
.sc_response
= null_callback
;
2082 if ( entry
&& !BER_BVISNULL( &entry
->e_name
) ) {
2083 Debug( LDAP_DEBUG_SYNC
,
2084 "syncrepl_entry: %s %s\n",
2085 si
->si_ridtxt
, entry
->e_name
.bv_val
, 0 );
2087 Debug( LDAP_DEBUG_SYNC
,
2088 "syncrepl_entry: %s %s\n",
2089 si
->si_ridtxt
, dni
.dn
.bv_val
? dni
.dn
.bv_val
: "(null)", 0 );
2092 assert( BER_BVISNULL( &op
->o_csn
) );
2094 slap_queue_csn( op
, syncCSN
);
2097 slap_op_time( &op
->o_time
, &op
->o_tincr
);
2098 switch ( syncstate
) {
2100 case LDAP_SYNC_MODIFY
:
2101 if ( BER_BVISNULL( &op
->o_csn
))
2104 Attribute
*a
= attr_find( entry
->e_attrs
, slap_schema
.si_ad_entryCSN
);
2106 /* FIXME: op->o_csn is assumed to be
2107 * on the thread's slab; this needs
2108 * to be cleared ASAP.
2109 * What happens if already present?
2111 assert( BER_BVISNULL( &op
->o_csn
) );
2112 op
->o_csn
= a
->a_vals
[0];
2117 if ( BER_BVISNULL( &dni
.dn
) ) {
2119 op
->o_req_dn
= entry
->e_name
;
2120 op
->o_req_ndn
= entry
->e_nname
;
2121 op
->o_tag
= LDAP_REQ_ADD
;
2123 op
->o_bd
= si
->si_wbe
;
2125 rc
= op
->o_bd
->be_add( op
, &rs_add
);
2126 Debug( LDAP_DEBUG_SYNC
,
2127 "syncrepl_entry: %s be_add (%d)\n",
2128 si
->si_ridtxt
, rc
, 0 );
2129 switch ( rs_add
.sr_err
) {
2131 if ( op
->ora_e
== entry
) {
2132 be_entry_release_w( op
, entry
);
2138 /* we assume that LDAP_NO_SUCH_OBJECT is returned
2139 * only if the suffix entry is not present */
2140 case LDAP_NO_SUCH_OBJECT
:
2141 rc
= syncrepl_add_glue( op
, entry
);
2145 /* if an entry was added via syncrepl_add_glue(),
2146 * it likely has no entryUUID, so the previous
2147 * be_search() doesn't find it. In this case,
2148 * give syncrepl a chance to modify it. Also
2149 * allow for entries that were recreated with the
2150 * same DN but a different entryUUID.
2152 case LDAP_ALREADY_EXISTS
:
2154 Operation op2
= *op
;
2155 SlapReply rs2
= { 0 };
2156 slap_callback cb2
= { 0 };
2159 op2
.o_tag
= LDAP_REQ_SEARCH
;
2160 op2
.o_req_dn
= entry
->e_name
;
2161 op2
.o_req_ndn
= entry
->e_nname
;
2162 op2
.ors_scope
= LDAP_SCOPE_BASE
;
2163 op2
.ors_deref
= LDAP_DEREF_NEVER
;
2164 op2
.ors_attrs
= slap_anlist_all_attributes
;
2165 op2
.ors_attrsonly
= 0;
2166 op2
.ors_limit
= NULL
;
2168 op2
.ors_tlimit
= SLAP_NO_LIMIT
;
2170 f
.f_choice
= LDAP_FILTER_PRESENT
;
2171 f
.f_desc
= slap_schema
.si_ad_objectClass
;
2172 op2
.ors_filter
= &f
;
2173 op2
.ors_filterstr
= generic_filterstr
;
2175 op2
.o_callback
= &cb2
;
2176 cb2
.sc_response
= dn_callback
;
2177 cb2
.sc_private
= &dni
;
2179 rc
= be
->be_search( &op2
, &rs2
);
2180 if ( rc
) goto done
;
2183 slap_op_time( &op
->o_time
, &op
->o_tincr
);
2189 Debug( LDAP_DEBUG_ANY
,
2190 "syncrepl_entry: %s be_add failed (%d)\n",
2191 si
->si_ridtxt
, rs_add
.sr_err
, 0 );
2198 op
->o_req_dn
= dni
.dn
;
2199 op
->o_req_ndn
= dni
.ndn
;
2200 if ( dni
.renamed
) {
2201 struct berval noldp
, newp
, nnewp
;
2203 op
->o_tag
= LDAP_REQ_MODRDN
;
2204 dnRdn( &entry
->e_name
, &op
->orr_newrdn
);
2205 dnRdn( &entry
->e_nname
, &op
->orr_nnewrdn
);
2207 dnParent( &dni
.ndn
, &noldp
);
2208 dnParent( &entry
->e_nname
, &nnewp
);
2209 if ( !dn_match( &noldp
, &nnewp
) ) {
2210 dnParent( &entry
->e_name
, &newp
);
2211 op
->orr_newSup
= &newp
;
2212 op
->orr_nnewSup
= &nnewp
;
2214 op
->orr_newSup
= NULL
;
2215 op
->orr_nnewSup
= NULL
;
2217 op
->orr_deleteoldrdn
= dni
.delOldRDN
;
2218 op
->orr_modlist
= NULL
;
2219 if ( ( rc
= slap_modrdn2mods( op
, &rs_modify
) ) ) {
2223 /* RDNs must be NUL-terminated for back-ldap */
2224 noldp
= op
->orr_newrdn
;
2225 ber_dupbv_x( &op
->orr_newrdn
, &noldp
, op
->o_tmpmemctx
);
2226 noldp
= op
->orr_nnewrdn
;
2227 ber_dupbv_x( &op
->orr_nnewrdn
, &noldp
, op
->o_tmpmemctx
);
2229 /* Setup opattrs too */
2231 static AttributeDescription
*nullattr
= NULL
;
2232 static AttributeDescription
**const opattrs
[] = {
2233 &slap_schema
.si_ad_entryCSN
,
2234 &slap_schema
.si_ad_modifiersName
,
2235 &slap_schema
.si_ad_modifyTimestamp
,
2238 AttributeDescription
*opattr
;
2239 Modifications
*mod
, **modtail
, **ml
;
2242 for ( mod
= op
->orr_modlist
;
2244 mod
= mod
->sml_next
)
2246 modtail
= &mod
->sml_next
;
2248 /* pull mod off incoming modlist, append to orr_modlist */
2249 for ( i
= 0; (opattr
= *opattrs
[i
]) != NULL
; i
++ ) {
2250 for ( ml
= modlist
; *ml
; ml
= &(*ml
)->sml_next
)
2252 if ( (*ml
)->sml_desc
== opattr
) {
2254 *ml
= mod
->sml_next
;
2255 mod
->sml_next
= NULL
;
2257 modtail
= &mod
->sml_next
;
2263 op
->o_bd
= si
->si_wbe
;
2264 rc
= op
->o_bd
->be_modrdn( op
, &rs_modify
);
2265 op
->o_tmpfree( op
->orr_nnewrdn
.bv_val
, op
->o_tmpmemctx
);
2266 op
->o_tmpfree( op
->orr_newrdn
.bv_val
, op
->o_tmpmemctx
);
2268 slap_mods_free( op
->orr_modlist
, 1 );
2269 Debug( LDAP_DEBUG_SYNC
,
2270 "syncrepl_entry: %s be_modrdn (%d)\n",
2271 si
->si_ridtxt
, rc
, 0 );
2276 op
->o_tag
= LDAP_REQ_MODIFY
;
2277 op
->orm_modlist
= dni
.mods
;
2278 op
->orm_no_opattrs
= 1;
2279 op
->o_bd
= si
->si_wbe
;
2281 rc
= op
->o_bd
->be_modify( op
, &rs_modify
);
2282 slap_mods_free( op
->orm_modlist
, 1 );
2283 op
->orm_no_opattrs
= 0;
2284 Debug( LDAP_DEBUG_SYNC
,
2285 "syncrepl_entry: %s be_modify (%d)\n",
2286 si
->si_ridtxt
, rc
, 0 );
2287 if ( rs_modify
.sr_err
!= LDAP_SUCCESS
) {
2288 Debug( LDAP_DEBUG_ANY
,
2289 "syncrepl_entry: %s be_modify failed (%d)\n",
2290 si
->si_ridtxt
, rs_modify
.sr_err
, 0 );
2294 Debug( LDAP_DEBUG_SYNC
,
2295 "syncrepl_entry: %s entry unchanged, ignored (%s)\n",
2296 si
->si_ridtxt
, op
->o_req_dn
.bv_val
, 0 );
2299 case LDAP_SYNC_DELETE
:
2300 if ( !BER_BVISNULL( &dni
.dn
) ) {
2301 op
->o_req_dn
= dni
.dn
;
2302 op
->o_req_ndn
= dni
.ndn
;
2303 op
->o_tag
= LDAP_REQ_DELETE
;
2304 op
->o_bd
= si
->si_wbe
;
2305 rc
= op
->o_bd
->be_delete( op
, &rs_delete
);
2306 Debug( LDAP_DEBUG_SYNC
,
2307 "syncrepl_entry: %s be_delete (%d)\n",
2308 si
->si_ridtxt
, rc
, 0 );
2310 while ( rs_delete
.sr_err
== LDAP_SUCCESS
2311 && op
->o_delete_glue_parent
) {
2312 op
->o_delete_glue_parent
= 0;
2313 if ( !be_issuffix( be
, &op
->o_req_ndn
) ) {
2314 slap_callback cb
= { NULL
};
2315 cb
.sc_response
= slap_null_cb
;
2316 dnParent( &op
->o_req_ndn
, &pdn
);
2318 op
->o_req_ndn
= pdn
;
2319 op
->o_callback
= &cb
;
2320 op
->o_bd
->be_delete( op
, &rs_delete
);
2330 Debug( LDAP_DEBUG_ANY
,
2331 "syncrepl_entry: %s unknown syncstate\n", si
->si_ridtxt
, 0, 0 );
2336 if ( !BER_BVISNULL( &syncUUID_strrep
) ) {
2337 slap_sl_free( syncUUID_strrep
.bv_val
, op
->o_tmpmemctx
);
2338 BER_BVZERO( &syncUUID_strrep
);
2340 if ( !BER_BVISNULL( &dni
.ndn
) ) {
2341 op
->o_tmpfree( dni
.ndn
.bv_val
, op
->o_tmpmemctx
);
2343 if ( !BER_BVISNULL( &dni
.dn
) ) {
2344 op
->o_tmpfree( dni
.dn
.bv_val
, op
->o_tmpmemctx
);
2347 entry_free( entry
);
2350 slap_graduate_commit_csn( op
);
2352 if ( !BER_BVISNULL( &op
->o_csn
) && freecsn
) {
2353 op
->o_tmpfree( op
->o_csn
.bv_val
, op
->o_tmpmemctx
);
2355 BER_BVZERO( &op
->o_csn
);
2359 static struct berval gcbva
[] = {
2365 #define NP_DELETE_ONE 2
2368 syncrepl_del_nonpresent(
2372 struct sync_cookie
*sc
,
2375 Backend
* be
= op
->o_bd
;
2376 slap_callback cb
= { NULL
};
2377 SlapReply rs_search
= {REP_RESULT
};
2378 SlapReply rs_delete
= {REP_RESULT
};
2379 SlapReply rs_modify
= {REP_RESULT
};
2380 struct nonpresent_entry
*np_list
, *np_prev
;
2382 AttributeName an
[2];
2384 struct berval pdn
= BER_BVNULL
;
2387 op
->o_req_dn
= si
->si_base
;
2388 op
->o_req_ndn
= si
->si_base
;
2390 cb
.sc_response
= nonpresent_callback
;
2393 op
->o_callback
= &cb
;
2394 op
->o_tag
= LDAP_REQ_SEARCH
;
2395 op
->ors_scope
= si
->si_scope
;
2396 op
->ors_deref
= LDAP_DEREF_NEVER
;
2397 op
->o_time
= slap_get_time();
2398 op
->ors_tlimit
= SLAP_NO_LIMIT
;
2403 AttributeAssertion eq
= ATTRIBUTEASSERTION_INIT
;
2406 op
->ors_attrsonly
= 1;
2407 op
->ors_attrs
= slap_anlist_no_attrs
;
2408 op
->ors_limit
= NULL
;
2409 op
->ors_filter
= &uf
;
2412 uf
.f_av_desc
= slap_schema
.si_ad_entryUUID
;
2414 uf
.f_choice
= LDAP_FILTER_EQUALITY
;
2415 si
->si_refreshDelete
|= NP_DELETE_ONE
;
2417 for (i
=0; uuids
[i
].bv_val
; i
++) {
2419 uf
.f_av_value
= uuids
[i
];
2420 filter2bv_x( op
, op
->ors_filter
, &op
->ors_filterstr
);
2421 rc
= be
->be_search( op
, &rs_search
);
2422 op
->o_tmpfree( op
->ors_filterstr
.bv_val
, op
->o_tmpmemctx
);
2424 si
->si_refreshDelete
^= NP_DELETE_ONE
;
2428 memset( &an
[0], 0, 2 * sizeof( AttributeName
) );
2429 an
[0].an_name
= slap_schema
.si_ad_entryUUID
->ad_cname
;
2430 an
[0].an_desc
= slap_schema
.si_ad_entryUUID
;
2432 op
->ors_slimit
= SLAP_NO_LIMIT
;
2433 op
->ors_attrsonly
= 0;
2434 op
->ors_filter
= str2filter_x( op
, si
->si_filterstr
.bv_val
);
2435 /* In multimaster, updates can continue to arrive while
2436 * we're searching. Limit the search result to entries
2437 * older than all of our cookie CSNs.
2439 if ( SLAP_MULTIMASTER( op
->o_bd
)) {
2442 cf
= op
->o_tmpalloc( (sc
->numcsns
+1) * sizeof(Filter
) +
2443 sc
->numcsns
* sizeof(AttributeAssertion
), op
->o_tmpmemctx
);
2445 f
->f_choice
= LDAP_FILTER_AND
;
2449 for ( i
=0; i
<sc
->numcsns
; i
++ ) {
2451 f
->f_choice
= LDAP_FILTER_LE
;
2452 f
->f_ava
= (AttributeAssertion
*)(f
+1);
2453 f
->f_av_desc
= slap_schema
.si_ad_entryCSN
;
2454 f
->f_av_value
= sc
->ctxcsn
[i
];
2455 f
->f_next
= (Filter
*)(f
->f_ava
+1);
2458 f
->f_next
= op
->ors_filter
;
2459 of
= op
->ors_filter
;
2460 op
->ors_filter
= cf
;
2461 filter2bv_x( op
, op
->ors_filter
, &op
->ors_filterstr
);
2464 op
->ors_filterstr
= si
->si_filterstr
;
2466 op
->o_nocaching
= 1;
2468 if ( limits_check( op
, &rs_search
) == 0 ) {
2469 rc
= be
->be_search( op
, &rs_search
);
2471 if ( SLAP_MULTIMASTER( op
->o_bd
)) {
2472 op
->o_tmpfree( cf
, op
->o_tmpmemctx
);
2473 op
->ors_filter
= of
;
2475 if ( op
->ors_filter
) filter_free_x( op
, op
->ors_filter
);
2479 op
->o_nocaching
= 0;
2481 if ( !LDAP_LIST_EMPTY( &si
->si_nonpresentlist
) ) {
2483 if ( sc
->ctxcsn
&& !BER_BVISNULL( &sc
->ctxcsn
[m
] ) ) {
2484 csn
= sc
->ctxcsn
[m
];
2486 csn
= si
->si_syncCookie
.ctxcsn
[0];
2489 op
->o_bd
= si
->si_wbe
;
2490 slap_queue_csn( op
, &csn
);
2492 np_list
= LDAP_LIST_FIRST( &si
->si_nonpresentlist
);
2493 while ( np_list
!= NULL
) {
2494 LDAP_LIST_REMOVE( np_list
, npe_link
);
2496 np_list
= LDAP_LIST_NEXT( np_list
, npe_link
);
2497 op
->o_tag
= LDAP_REQ_DELETE
;
2498 op
->o_callback
= &cb
;
2499 cb
.sc_response
= null_callback
;
2501 op
->o_req_dn
= *np_prev
->npe_name
;
2502 op
->o_req_ndn
= *np_prev
->npe_nname
;
2503 rc
= op
->o_bd
->be_delete( op
, &rs_delete
);
2504 Debug( LDAP_DEBUG_SYNC
,
2505 "syncrepl_del_nonpresent: %s be_delete %s (%d)\n",
2506 si
->si_ridtxt
, op
->o_req_dn
.bv_val
, rc
);
2508 if ( rs_delete
.sr_err
== LDAP_NOT_ALLOWED_ON_NONLEAF
) {
2509 Modifications mod1
, mod2
;
2510 mod1
.sml_op
= LDAP_MOD_REPLACE
;
2512 mod1
.sml_desc
= slap_schema
.si_ad_objectClass
;
2513 mod1
.sml_type
= mod1
.sml_desc
->ad_cname
;
2514 mod1
.sml_numvals
= 2;
2515 mod1
.sml_values
= &gcbva
[0];
2516 mod1
.sml_nvalues
= NULL
;
2517 mod1
.sml_next
= &mod2
;
2519 mod2
.sml_op
= LDAP_MOD_REPLACE
;
2521 mod2
.sml_desc
= slap_schema
.si_ad_structuralObjectClass
;
2522 mod2
.sml_type
= mod2
.sml_desc
->ad_cname
;
2523 mod2
.sml_numvals
= 1;
2524 mod2
.sml_values
= &gcbva
[1];
2525 mod2
.sml_nvalues
= NULL
;
2526 mod2
.sml_next
= NULL
;
2528 op
->o_tag
= LDAP_REQ_MODIFY
;
2529 op
->orm_modlist
= &mod1
;
2531 rc
= op
->o_bd
->be_modify( op
, &rs_modify
);
2532 if ( mod2
.sml_next
) slap_mods_free( mod2
.sml_next
, 1 );
2535 while ( rs_delete
.sr_err
== LDAP_SUCCESS
&&
2536 op
->o_delete_glue_parent
) {
2537 op
->o_delete_glue_parent
= 0;
2538 if ( !be_issuffix( be
, &op
->o_req_ndn
) ) {
2539 slap_callback cb
= { NULL
};
2540 cb
.sc_response
= slap_null_cb
;
2541 dnParent( &op
->o_req_ndn
, &pdn
);
2543 op
->o_req_ndn
= pdn
;
2544 op
->o_callback
= &cb
;
2545 /* give it a root privil ? */
2546 op
->o_bd
->be_delete( op
, &rs_delete
);
2552 op
->o_delete_glue_parent
= 0;
2554 ber_bvfree( np_prev
->npe_name
);
2555 ber_bvfree( np_prev
->npe_nname
);
2558 if ( slapd_shutdown
) {
2563 slap_graduate_commit_csn( op
);
2566 op
->o_tmpfree( op
->o_csn
.bv_val
, op
->o_tmpmemctx
);
2567 BER_BVZERO( &op
->o_csn
);
2578 Backend
*be
= op
->o_bd
;
2579 slap_callback cb
= { NULL
};
2584 struct berval dn
= BER_BVNULL
;
2585 struct berval ndn
= BER_BVNULL
;
2587 SlapReply rs_add
= {REP_RESULT
};
2588 struct berval ptr
, nptr
;
2591 op
->o_tag
= LDAP_REQ_ADD
;
2592 op
->o_callback
= &cb
;
2593 cb
.sc_response
= null_callback
;
2594 cb
.sc_private
= NULL
;
2599 /* count RDNs in suffix */
2600 if ( !BER_BVISEMPTY( &be
->be_nsuffix
[0] ) ) {
2601 for ( i
= 0, ptr
= be
->be_nsuffix
[0], comma
= ptr
.bv_val
; comma
!= NULL
; comma
= ber_bvchr( &ptr
, ',' ) ) {
2603 ptr
.bv_len
-= comma
- ptr
.bv_val
;
2613 /* Start with BE suffix */
2615 for ( i
= 0; i
< suffrdns
; i
++ ) {
2616 comma
= ber_bvrchr( &ptr
, ',' );
2617 if ( comma
!= NULL
) {
2618 ptr
.bv_len
= comma
- ptr
.bv_val
;
2625 if ( !BER_BVISEMPTY( &ptr
) ) {
2626 dn
.bv_len
-= ptr
.bv_len
+ 1;
2627 dn
.bv_val
+= ptr
.bv_len
+ 1;
2630 /* the normalizedDNs are always the same length, no counting
2634 if ( ndn
.bv_len
> be
->be_nsuffix
[0].bv_len
) {
2635 ndn
.bv_val
+= ndn
.bv_len
- be
->be_nsuffix
[0].bv_len
;
2636 ndn
.bv_len
= be
->be_nsuffix
[0].bv_len
;
2638 nptr
.bv_len
= ndn
.bv_val
- nptr
.bv_val
- 1;
2644 while ( ndn
.bv_val
> e
->e_nname
.bv_val
) {
2645 glue
= entry_alloc();
2646 ber_dupbv( &glue
->e_name
, &dn
);
2647 ber_dupbv( &glue
->e_nname
, &ndn
);
2649 a
= attr_alloc( slap_schema
.si_ad_objectClass
);
2652 a
->a_vals
= ch_calloc( 3, sizeof( struct berval
) );
2653 ber_dupbv( &a
->a_vals
[0], &gcbva
[0] );
2654 ber_dupbv( &a
->a_vals
[1], &gcbva
[1] );
2655 ber_dupbv( &a
->a_vals
[2], &gcbva
[2] );
2657 a
->a_nvals
= a
->a_vals
;
2659 a
->a_next
= glue
->e_attrs
;
2662 a
= attr_alloc( slap_schema
.si_ad_structuralObjectClass
);
2665 a
->a_vals
= ch_calloc( 2, sizeof( struct berval
) );
2666 ber_dupbv( &a
->a_vals
[0], &gcbva
[1] );
2667 ber_dupbv( &a
->a_vals
[1], &gcbva
[2] );
2669 a
->a_nvals
= a
->a_vals
;
2671 a
->a_next
= glue
->e_attrs
;
2674 op
->o_req_dn
= glue
->e_name
;
2675 op
->o_req_ndn
= glue
->e_nname
;
2677 rc
= be
->be_add ( op
, &rs_add
);
2678 if ( rs_add
.sr_err
== LDAP_SUCCESS
) {
2679 if ( op
->ora_e
== glue
)
2680 be_entry_release_w( op
, glue
);
2682 /* incl. ALREADY EXIST */
2684 if ( rs_add
.sr_err
!= LDAP_ALREADY_EXISTS
) {
2690 /* Move to next child */
2691 comma
= ber_bvrchr( &ptr
, ',' );
2692 if ( comma
== NULL
) {
2695 ptr
.bv_len
= comma
- ptr
.bv_val
;
2697 dn
.bv_val
= ++comma
;
2698 dn
.bv_len
= e
->e_name
.bv_len
- (dn
.bv_val
- e
->e_name
.bv_val
);
2700 comma
= ber_bvrchr( &nptr
, ',' );
2701 assert( comma
!= NULL
);
2702 nptr
.bv_len
= comma
- nptr
.bv_val
;
2704 ndn
.bv_val
= ++comma
;
2705 ndn
.bv_len
= e
->e_nname
.bv_len
- (ndn
.bv_val
- e
->e_nname
.bv_val
);
2708 op
->o_req_dn
= e
->e_name
;
2709 op
->o_req_ndn
= e
->e_nname
;
2711 rc
= be
->be_add ( op
, &rs_add
);
2712 if ( rs_add
.sr_err
== LDAP_SUCCESS
) {
2713 if ( op
->ora_e
== e
)
2714 be_entry_release_w( op
, e
);
2723 syncrepl_updateCookie(
2727 struct sync_cookie
*syncCookie
)
2729 Backend
*be
= op
->o_bd
;
2731 struct berval first
= BER_BVNULL
;
2735 slap_callback cb
= { NULL
};
2736 SlapReply rs_modify
= {REP_RESULT
};
2738 mod
.sml_op
= LDAP_MOD_REPLACE
;
2739 mod
.sml_desc
= slap_schema
.si_ad_contextCSN
;
2740 mod
.sml_type
= mod
.sml_desc
->ad_cname
;
2741 mod
.sml_flags
= SLAP_MOD_INTERNAL
;
2742 mod
.sml_nvalues
= NULL
;
2743 mod
.sml_next
= NULL
;
2745 ldap_pvt_thread_mutex_lock( &si
->si_cookieState
->cs_mutex
);
2747 /* clone the cookieState CSNs so we can Replace the whole thing */
2748 mod
.sml_numvals
= si
->si_cookieState
->cs_num
;
2749 mod
.sml_values
= op
->o_tmpalloc(( mod
.sml_numvals
+1 )*sizeof(struct berval
), op
->o_tmpmemctx
);
2750 for ( i
=0; i
<mod
.sml_numvals
; i
++ )
2751 mod
.sml_values
[i
] = si
->si_cookieState
->cs_vals
[i
];
2752 BER_BVZERO( &mod
.sml_values
[i
] );
2754 /* find any CSNs in the syncCookie that are newer than the cookieState */
2755 for ( i
=0; i
<syncCookie
->numcsns
; i
++ ) {
2756 for ( j
=0; j
<si
->si_cookieState
->cs_num
; j
++ ) {
2757 if ( syncCookie
->sids
[i
] != si
->si_cookieState
->cs_sids
[j
] )
2759 len
= syncCookie
->ctxcsn
[i
].bv_len
;
2760 if ( len
> si
->si_cookieState
->cs_vals
[j
].bv_len
)
2761 len
= si
->si_cookieState
->cs_vals
[j
].bv_len
;
2762 if ( memcmp( syncCookie
->ctxcsn
[i
].bv_val
,
2763 si
->si_cookieState
->cs_vals
[j
].bv_val
, len
) > 0 ) {
2764 mod
.sml_values
[j
] = syncCookie
->ctxcsn
[i
];
2765 if ( BER_BVISNULL( &first
))
2766 first
= syncCookie
->ctxcsn
[i
];
2770 /* there was no match for this SID, it's a new CSN */
2771 if ( j
== si
->si_cookieState
->cs_num
) {
2772 mod
.sml_values
= op
->o_tmprealloc( mod
.sml_values
,
2773 ( mod
.sml_numvals
+2 )*sizeof(struct berval
), op
->o_tmpmemctx
);
2774 mod
.sml_values
[mod
.sml_numvals
++] = syncCookie
->ctxcsn
[i
];
2775 BER_BVZERO( &mod
.sml_values
[mod
.sml_numvals
] );
2776 if ( BER_BVISNULL( &first
))
2777 first
= syncCookie
->ctxcsn
[i
];
2780 /* Should never happen, ITS#5065 */
2781 if ( BER_BVISNULL( &first
)) {
2782 ldap_pvt_thread_mutex_unlock( &si
->si_cookieState
->cs_mutex
);
2783 op
->o_tmpfree( mod
.sml_values
, op
->o_tmpmemctx
);
2786 op
->o_bd
= si
->si_wbe
;
2787 slap_queue_csn( op
, &first
);
2789 op
->o_tag
= LDAP_REQ_MODIFY
;
2791 cb
.sc_response
= null_callback
;
2794 op
->o_callback
= &cb
;
2795 op
->o_req_dn
= op
->o_bd
->be_suffix
[0];
2796 op
->o_req_ndn
= op
->o_bd
->be_nsuffix
[0];
2798 /* update contextCSN */
2799 op
->o_msgid
= SLAP_SYNC_UPDATE_MSGID
;
2801 op
->orm_modlist
= &mod
;
2802 op
->orm_no_opattrs
= 1;
2803 rc
= op
->o_bd
->be_modify( op
, &rs_modify
);
2804 op
->orm_no_opattrs
= 0;
2807 if ( rs_modify
.sr_err
== LDAP_SUCCESS
) {
2808 slap_sync_cookie_free( &si
->si_syncCookie
, 0 );
2809 slap_dup_sync_cookie( &si
->si_syncCookie
, syncCookie
);
2810 /* If we replaced any old values */
2811 for ( i
=0; i
<si
->si_cookieState
->cs_num
; i
++ ) {
2812 if ( mod
.sml_values
[i
].bv_val
!= si
->si_cookieState
->cs_vals
[i
].bv_val
)
2813 ber_bvreplace( &si
->si_cookieState
->cs_vals
[i
],
2814 &mod
.sml_values
[i
] );
2816 /* Handle any added values */
2817 if ( i
< mod
.sml_numvals
) {
2818 si
->si_cookieState
->cs_num
= mod
.sml_numvals
;
2819 value_add( &si
->si_cookieState
->cs_vals
, &mod
.sml_values
[i
] );
2820 free( si
->si_cookieState
->cs_sids
);
2821 si
->si_cookieState
->cs_sids
= slap_parse_csn_sids(
2822 si
->si_cookieState
->cs_vals
, si
->si_cookieState
->cs_num
, NULL
);
2825 si
->si_cookieState
->cs_age
++;
2826 si
->si_cookieAge
= si
->si_cookieState
->cs_age
;
2828 Debug( LDAP_DEBUG_ANY
,
2829 "syncrepl_updateCookie: %s be_modify failed (%d)\n",
2830 si
->si_ridtxt
, rs_modify
.sr_err
, 0 );
2832 ldap_pvt_thread_mutex_unlock( &si
->si_cookieState
->cs_mutex
);
2835 op
->o_tmpfree( op
->o_csn
.bv_val
, op
->o_tmpmemctx
);
2836 BER_BVZERO( &op
->o_csn
);
2837 if ( mod
.sml_next
) slap_mods_free( mod
.sml_next
, 1 );
2838 op
->o_tmpfree( mod
.sml_values
, op
->o_tmpmemctx
);
2844 attr_cmp( Operation
*op
, Attribute
*old
, Attribute
*new,
2845 Modifications
***mret
, Modifications
***mcur
)
2848 Modifications
*mod
, **modtail
;
2854 struct berval
**adds
, **dels
;
2855 /* count old and new */
2856 for ( o
=0; old
->a_vals
[o
].bv_val
; o
++ ) ;
2857 for ( n
=0; new->a_vals
[n
].bv_val
; n
++ ) ;
2859 /* there MUST be both old and new values */
2864 adds
= op
->o_tmpalloc( sizeof(struct berval
*) * n
, op
->o_tmpmemctx
);
2865 dels
= op
->o_tmpalloc( sizeof(struct berval
*) * o
, op
->o_tmpmemctx
);
2867 for ( i
=0; i
<o
; i
++ ) dels
[i
] = &old
->a_vals
[i
];
2868 for ( i
=0; i
<n
; i
++ ) adds
[i
] = &new->a_vals
[i
];
2872 for ( i
=0; i
<o
; i
++ ) {
2873 for ( j
=0; j
<n
; j
++ ) {
2876 if ( bvmatch( dels
[i
], adds
[j
] ) ) {
2886 /* Don't delete/add an objectClass, always use the replace op.
2887 * Modify would fail if provider has replaced entry with a new,
2888 * and the new explicitly includes a superior of a class that was
2889 * only included implicitly in the old entry. Ref ITS#5517.
2891 if ( nn
&& no
< o
&& old
->a_desc
== slap_schema
.si_ad_objectClass
)
2895 /* all old values were deleted, just use the replace op */
2899 /* delete some values */
2900 mod
= ch_malloc( sizeof( Modifications
) );
2901 mod
->sml_op
= LDAP_MOD_DELETE
;
2903 mod
->sml_desc
= old
->a_desc
;
2904 mod
->sml_type
= mod
->sml_desc
->ad_cname
;
2905 mod
->sml_numvals
= no
;
2906 mod
->sml_values
= ch_malloc( ( no
+ 1 ) * sizeof(struct berval
) );
2907 if ( old
->a_vals
!= old
->a_nvals
) {
2908 mod
->sml_nvalues
= ch_malloc( ( no
+ 1 ) * sizeof(struct berval
) );
2910 mod
->sml_nvalues
= NULL
;
2913 for ( i
= 0; i
< o
; i
++ ) {
2914 if ( !dels
[i
] ) continue;
2915 ber_dupbv( &mod
->sml_values
[j
], &old
->a_vals
[i
] );
2916 if ( mod
->sml_nvalues
) {
2917 ber_dupbv( &mod
->sml_nvalues
[j
], &old
->a_nvals
[i
] );
2921 BER_BVZERO( &mod
->sml_values
[j
] );
2922 if ( mod
->sml_nvalues
) {
2923 BER_BVZERO( &mod
->sml_nvalues
[j
] );
2926 modtail
= &mod
->sml_next
;
2929 op
->o_tmpfree( dels
, op
->o_tmpmemctx
);
2930 /* some values were added */
2931 if ( nn
&& no
< o
) {
2932 mod
= ch_malloc( sizeof( Modifications
) );
2933 mod
->sml_op
= LDAP_MOD_ADD
;
2935 mod
->sml_desc
= old
->a_desc
;
2936 mod
->sml_type
= mod
->sml_desc
->ad_cname
;
2937 mod
->sml_numvals
= nn
;
2938 mod
->sml_values
= ch_malloc( ( nn
+ 1 ) * sizeof(struct berval
) );
2939 if ( old
->a_vals
!= old
->a_nvals
) {
2940 mod
->sml_nvalues
= ch_malloc( ( nn
+ 1 ) * sizeof(struct berval
) );
2942 mod
->sml_nvalues
= NULL
;
2945 for ( i
= 0; i
< n
; i
++ ) {
2946 if ( !adds
[i
] ) continue;
2947 ber_dupbv( &mod
->sml_values
[j
], &new->a_vals
[i
] );
2948 if ( mod
->sml_nvalues
) {
2949 ber_dupbv( &mod
->sml_nvalues
[j
], &new->a_nvals
[i
] );
2953 BER_BVZERO( &mod
->sml_values
[j
] );
2954 if ( mod
->sml_nvalues
) {
2955 BER_BVZERO( &mod
->sml_nvalues
[j
] );
2958 modtail
= &mod
->sml_next
;
2961 op
->o_tmpfree( adds
, op
->o_tmpmemctx
);
2963 /* new attr, just use the new mod */
2967 /* advance to next element */
2971 **mcur
= mod
->sml_next
;
2973 modtail
= &mod
->sml_next
;
2975 *mcur
= &mod
->sml_next
;
2986 dninfo
*dni
= op
->o_callback
->sc_private
;
2988 if ( rs
->sr_type
== REP_SEARCH
) {
2989 if ( !BER_BVISNULL( &dni
->dn
) ) {
2990 Debug( LDAP_DEBUG_ANY
,
2991 "dn_callback : consistency error - "
2992 "entryUUID is not unique\n", 0, 0, 0 );
2994 ber_dupbv_x( &dni
->dn
, &rs
->sr_entry
->e_name
, op
->o_tmpmemctx
);
2995 ber_dupbv_x( &dni
->ndn
, &rs
->sr_entry
->e_nname
, op
->o_tmpmemctx
);
2996 /* If there is a new entry, see if it differs from the old.
2997 * We compare the non-normalized values so that cosmetic changes
2998 * in the provider are always propagated.
3000 if ( dni
->new_entry
) {
3001 Modifications
**modtail
, **ml
;
3002 Attribute
*old
, *new;
3005 is_ctx
= dn_match( &rs
->sr_entry
->e_nname
,
3006 &op
->o_bd
->be_nsuffix
[0] );
3008 /* Did the DN change?
3010 if ( !dn_match( &rs
->sr_entry
->e_name
,
3011 &dni
->new_entry
->e_name
) )
3013 struct berval oldRDN
, oldVal
;
3014 AttributeDescription
*ad
= NULL
;
3018 /* See if the oldRDN was deleted */
3019 dnRdn( &rs
->sr_entry
->e_nname
, &oldRDN
);
3020 oldVal
.bv_val
= strchr(oldRDN
.bv_val
, '=') + 1;
3021 oldVal
.bv_len
= oldRDN
.bv_len
- ( oldVal
.bv_val
-
3023 oldRDN
.bv_len
-= oldVal
.bv_len
+ 2;
3024 slap_bv2ad( &oldRDN
, &ad
, &rs
->sr_text
);
3025 a
= attr_find( dni
->new_entry
->e_attrs
, ad
);
3026 if ( !a
|| attr_valfind( a
,
3027 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
|
3028 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH
|
3029 SLAP_MR_VALUE_OF_SYNTAX
,
3030 &oldVal
, NULL
, op
->o_tmpmemctx
) != LDAP_SUCCESS
)
3034 /* OK, this was just a modDN, we're done */
3035 return LDAP_SUCCESS
;
3038 modtail
= &dni
->mods
;
3041 /* Make sure new entry is actually newer than old entry */
3042 old
= attr_find( rs
->sr_entry
->e_attrs
,
3043 slap_schema
.si_ad_entryCSN
);
3044 new = attr_find( dni
->new_entry
->e_attrs
,
3045 slap_schema
.si_ad_entryCSN
);
3047 int rc
, len
= old
->a_vals
[0].bv_len
;
3048 if ( len
> new->a_vals
[0].bv_len
)
3049 len
= new->a_vals
[0].bv_len
;
3050 rc
= memcmp( old
->a_vals
[0].bv_val
,
3051 new->a_vals
[0].bv_val
, len
);
3053 Debug( LDAP_DEBUG_SYNC
,
3054 "dn_callback : new entry is older than ours "
3055 "%s ours %s, new %s\n",
3056 rs
->sr_entry
->e_name
.bv_val
,
3057 old
->a_vals
[0].bv_val
,
3058 new->a_vals
[0].bv_val
);
3059 return LDAP_SUCCESS
;
3060 } else if ( rc
== 0 ) {
3061 Debug( LDAP_DEBUG_SYNC
,
3062 "dn_callback : entries have identical CSN "
3064 rs
->sr_entry
->e_name
.bv_val
,
3065 old
->a_vals
[0].bv_val
, 0 );
3066 return LDAP_SUCCESS
;
3070 /* We assume that attributes are saved in the same order
3071 * in the remote and local databases. So if we walk through
3072 * the attributeDescriptions one by one they should match in
3073 * lock step. If not, look for an add or delete.
3075 for ( old
= rs
->sr_entry
->e_attrs
, new = dni
->new_entry
->e_attrs
;
3078 /* If we've seen this before, use its mod now */
3079 if ( new->a_flags
& SLAP_ATTR_IXADD
) {
3080 attr_cmp( op
, NULL
, new, &modtail
, &ml
);
3084 /* Skip contextCSN */
3085 if ( is_ctx
&& old
->a_desc
==
3086 slap_schema
.si_ad_contextCSN
) {
3091 if ( old
->a_desc
!= new->a_desc
) {
3095 /* If it's just been re-added later,
3096 * remember that we've seen it.
3098 tmp
= attr_find( new, old
->a_desc
);
3100 tmp
->a_flags
|= SLAP_ATTR_IXADD
;
3102 /* If it's a new attribute, pull it in.
3104 tmp
= attr_find( old
, new->a_desc
);
3106 attr_cmp( op
, NULL
, new, &modtail
, &ml
);
3110 /* Delete old attr */
3111 mod
= ch_malloc( sizeof( Modifications
) );
3112 mod
->sml_op
= LDAP_MOD_DELETE
;
3114 mod
->sml_desc
= old
->a_desc
;
3115 mod
->sml_type
= mod
->sml_desc
->ad_cname
;
3116 mod
->sml_numvals
= 0;
3117 mod
->sml_values
= NULL
;
3118 mod
->sml_nvalues
= NULL
;
3120 modtail
= &mod
->sml_next
;
3125 /* kludge - always update modifiersName so that it
3126 * stays co-located with the other mod opattrs. But only
3127 * if we know there are other valid mods.
3129 if ( old
->a_desc
== slap_schema
.si_ad_modifiersName
&&
3131 attr_cmp( op
, NULL
, new, &modtail
, &ml
);
3133 attr_cmp( op
, old
, new, &modtail
, &ml
);
3141 } else if ( rs
->sr_type
== REP_RESULT
) {
3142 if ( rs
->sr_err
== LDAP_SIZELIMIT_EXCEEDED
) {
3143 Debug( LDAP_DEBUG_ANY
,
3144 "dn_callback : consistency error - "
3145 "entryUUID is not unique\n", 0, 0, 0 );
3149 return LDAP_SUCCESS
;
3153 nonpresent_callback(
3157 syncinfo_t
*si
= op
->o_callback
->sc_private
;
3160 struct berval
* present_uuid
= NULL
;
3161 struct nonpresent_entry
*np_entry
;
3163 if ( rs
->sr_type
== REP_RESULT
) {
3164 count
= avl_free( si
->si_presentlist
, ch_free
);
3165 si
->si_presentlist
= NULL
;
3167 } else if ( rs
->sr_type
== REP_SEARCH
) {
3168 if ( !( si
->si_refreshDelete
& NP_DELETE_ONE
) ) {
3169 a
= attr_find( rs
->sr_entry
->e_attrs
, slap_schema
.si_ad_entryUUID
);
3172 present_uuid
= avl_find( si
->si_presentlist
, &a
->a_nvals
[0],
3176 if ( LogTest( LDAP_DEBUG_SYNC
) ) {
3177 char buf
[sizeof("rid=999 not")];
3179 snprintf( buf
, sizeof(buf
), "%s %s", si
->si_ridtxt
,
3180 present_uuid
? "got" : "not" );
3182 Debug( LDAP_DEBUG_SYNC
, "nonpresent_callback: %s UUID %s, dn %s\n",
3183 buf
, a
? a
->a_vals
[0].bv_val
: "<missing>", rs
->sr_entry
->e_name
.bv_val
);
3186 if ( a
== NULL
) return 0;
3189 if ( present_uuid
== NULL
) {
3190 np_entry
= (struct nonpresent_entry
*)
3191 ch_calloc( 1, sizeof( struct nonpresent_entry
) );
3192 np_entry
->npe_name
= ber_dupbv( NULL
, &rs
->sr_entry
->e_name
);
3193 np_entry
->npe_nname
= ber_dupbv( NULL
, &rs
->sr_entry
->e_nname
);
3194 LDAP_LIST_INSERT_HEAD( &si
->si_nonpresentlist
, np_entry
, npe_link
);
3197 avl_delete( &si
->si_presentlist
,
3198 &a
->a_nvals
[0], syncuuid_cmp
);
3199 ch_free( present_uuid
);
3202 return LDAP_SUCCESS
;
3210 if ( rs
->sr_err
!= LDAP_SUCCESS
&&
3211 rs
->sr_err
!= LDAP_REFERRAL
&&
3212 rs
->sr_err
!= LDAP_ALREADY_EXISTS
&&
3213 rs
->sr_err
!= LDAP_NO_SUCH_OBJECT
&&
3214 rs
->sr_err
!= LDAP_NOT_ALLOWED_ON_NONLEAF
)
3216 Debug( LDAP_DEBUG_ANY
,
3217 "null_callback : error code 0x%x\n",
3220 return LDAP_SUCCESS
;
3223 static struct berval
*
3224 slap_uuidstr_from_normalized(
3225 struct berval
* uuidstr
,
3226 struct berval
* normalized
,
3231 unsigned char nibble
;
3234 if ( normalized
== NULL
) return NULL
;
3235 if ( normalized
->bv_len
!= 16 ) return NULL
;
3240 new = (struct berval
*)slap_sl_malloc( sizeof(struct berval
), ctx
);
3241 if ( new == NULL
) {
3248 if ( ( new->bv_val
= slap_sl_malloc( new->bv_len
+ 1, ctx
) ) == NULL
) {
3249 if ( new != uuidstr
) {
3250 slap_sl_free( new, ctx
);
3255 for ( i
= 0; i
< 16; i
++ ) {
3256 if ( i
== 4 || i
== 6 || i
== 8 || i
== 10 ) {
3257 new->bv_val
[(i
<<1)+d
] = '-';
3261 nibble
= (normalized
->bv_val
[i
] >> 4) & 0xF;
3262 if ( nibble
< 10 ) {
3263 new->bv_val
[(i
<<1)+d
] = nibble
+ '0';
3265 new->bv_val
[(i
<<1)+d
] = nibble
- 10 + 'a';
3268 nibble
= (normalized
->bv_val
[i
]) & 0xF;
3269 if ( nibble
< 10 ) {
3270 new->bv_val
[(i
<<1)+d
+1] = nibble
+ '0';
3272 new->bv_val
[(i
<<1)+d
+1] = nibble
- 10 + 'a';
3276 new->bv_val
[new->bv_len
] = '\0';
3283 if ( normalized
== NULL
) return NULL
;
3284 if ( normalized
->bv_len
!= 16 ) return NULL
;
3290 new = (struct berval
*)slap_sl_malloc( sizeof(struct berval
), ctx
);
3291 if ( new == NULL
) {
3298 if ( ( new->bv_val
= slap_sl_malloc( new->bv_len
+ 1, ctx
) ) == NULL
) {
3303 rc
= lutil_uuidstr_from_normalized( normalized
->bv_val
,
3304 normalized
->bv_len
, new->bv_val
, new->bv_len
+ 1 );
3308 if ( new != NULL
) {
3309 if ( new->bv_val
!= NULL
) {
3310 slap_sl_free( new->bv_val
, ctx
);
3313 if ( new != uuidstr
) {
3314 slap_sl_free( new, ctx
);
3327 syncuuid_cmp( const void* v_uuid1
, const void* v_uuid2
)
3329 const struct berval
*uuid1
= v_uuid1
;
3330 const struct berval
*uuid2
= v_uuid2
;
3331 int rc
= uuid1
->bv_len
- uuid2
->bv_len
;
3332 if ( rc
) return rc
;
3333 return ( memcmp( uuid1
->bv_val
, uuid2
->bv_val
, uuid1
->bv_len
) );
3337 syncinfo_free( syncinfo_t
*sie
, int free_all
)
3339 syncinfo_t
*si_next
;
3341 if ( free_all
&& sie
->si_cookieState
) {
3342 ch_free( sie
->si_cookieState
->cs_sids
);
3343 ber_bvarray_free( sie
->si_cookieState
->cs_vals
);
3344 ldap_pvt_thread_mutex_destroy( &sie
->si_cookieState
->cs_mutex
);
3345 ch_free( sie
->si_cookieState
);
3348 si_next
= sie
->si_next
;
3351 if ( sie
->si_conn
) {
3352 connection_client_stop( sie
->si_conn
);
3353 sie
->si_conn
= NULL
;
3355 ldap_unbind_ext( sie
->si_ld
, NULL
, NULL
);
3358 /* re-fetch it, in case it was already removed */
3359 ldap_pvt_thread_mutex_lock( &slapd_rq
.rq_mutex
);
3360 sie
->si_re
= ldap_pvt_runqueue_find( &slapd_rq
, do_syncrepl
, sie
);
3362 if ( ldap_pvt_runqueue_isrunning( &slapd_rq
, sie
->si_re
) )
3363 ldap_pvt_runqueue_stoptask( &slapd_rq
, sie
->si_re
);
3364 ldap_pvt_runqueue_remove( &slapd_rq
, sie
->si_re
);
3367 ldap_pvt_thread_mutex_unlock( &slapd_rq
.rq_mutex
);
3368 ldap_pvt_thread_mutex_destroy( &sie
->si_mutex
);
3370 bindconf_free( &sie
->si_bindconf
);
3372 if ( sie
->si_filterstr
.bv_val
) {
3373 ch_free( sie
->si_filterstr
.bv_val
);
3375 if ( sie
->si_logfilterstr
.bv_val
) {
3376 ch_free( sie
->si_logfilterstr
.bv_val
);
3378 if ( sie
->si_base
.bv_val
) {
3379 ch_free( sie
->si_base
.bv_val
);
3381 if ( sie
->si_logbase
.bv_val
) {
3382 ch_free( sie
->si_logbase
.bv_val
);
3384 if ( sie
->si_attrs
) {
3386 while ( sie
->si_attrs
[i
] != NULL
) {
3387 ch_free( sie
->si_attrs
[i
] );
3390 ch_free( sie
->si_attrs
);
3392 if ( sie
->si_exattrs
) {
3394 while ( sie
->si_exattrs
[i
] != NULL
) {
3395 ch_free( sie
->si_exattrs
[i
] );
3398 ch_free( sie
->si_exattrs
);
3400 if ( sie
->si_anlist
) {
3402 while ( sie
->si_anlist
[i
].an_name
.bv_val
!= NULL
) {
3403 ch_free( sie
->si_anlist
[i
].an_name
.bv_val
);
3406 ch_free( sie
->si_anlist
);
3408 if ( sie
->si_exanlist
) {
3410 while ( sie
->si_exanlist
[i
].an_name
.bv_val
!= NULL
) {
3411 ch_free( sie
->si_exanlist
[i
].an_name
.bv_val
);
3414 ch_free( sie
->si_exanlist
);
3416 if ( sie
->si_retryinterval
) {
3417 ch_free( sie
->si_retryinterval
);
3419 if ( sie
->si_retrynum
) {
3420 ch_free( sie
->si_retrynum
);
3422 if ( sie
->si_retrynum_init
) {
3423 ch_free( sie
->si_retrynum_init
);
3425 slap_sync_cookie_free( &sie
->si_syncCookie
, 0 );
3426 if ( sie
->si_presentlist
) {
3427 avl_free( sie
->si_presentlist
, ch_free
);
3429 while ( !LDAP_LIST_EMPTY( &sie
->si_nonpresentlist
) ) {
3430 struct nonpresent_entry
* npe
;
3431 npe
= LDAP_LIST_FIRST( &sie
->si_nonpresentlist
);
3432 LDAP_LIST_REMOVE( npe
, npe_link
);
3433 if ( npe
->npe_name
) {
3434 if ( npe
->npe_name
->bv_val
) {
3435 ch_free( npe
->npe_name
->bv_val
);
3437 ch_free( npe
->npe_name
);
3439 if ( npe
->npe_nname
) {
3440 if ( npe
->npe_nname
->bv_val
) {
3441 ch_free( npe
->npe_nname
->bv_val
);
3443 ch_free( npe
->npe_nname
);
3449 } while ( free_all
&& si_next
);
3454 /* NOTE: used & documented in slapd.conf(5) */
3456 #define PROVIDERSTR "provider"
3457 #define SCHEMASTR "schemachecking"
3458 #define FILTERSTR "filter"
3459 #define SEARCHBASESTR "searchbase"
3460 #define SCOPESTR "scope"
3461 #define ATTRSONLYSTR "attrsonly"
3462 #define ATTRSSTR "attrs"
3463 #define TYPESTR "type"
3464 #define INTERVALSTR "interval"
3465 #define RETRYSTR "retry"
3466 #define SLIMITSTR "sizelimit"
3467 #define TLIMITSTR "timelimit"
3468 #define SYNCDATASTR "syncdata"
3469 #define LOGBASESTR "logbase"
3470 #define LOGFILTERSTR "logfilter"
3472 /* FIXME: undocumented */
3473 #define EXATTRSSTR "exattrs"
3474 #define MANAGEDSAITSTR "manageDSAit"
3477 #define GOT_ID 0x0001
3478 #define GOT_PROVIDER 0x0002
3479 #define GOT_BASE 0x0004
3482 #define GOT_ALL (GOT_ID|GOT_PROVIDER|GOT_BASE)
3488 { BER_BVC("base"), LDAP_SCOPE_BASE
},
3489 { BER_BVC("one"), LDAP_SCOPE_ONELEVEL
},
3490 { BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL
}, /* OpenLDAP extension */
3491 { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE
},
3492 { BER_BVC("subord"), LDAP_SCOPE_SUBORDINATE
},
3493 { BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE
},
3494 { BER_BVC("sub"), LDAP_SCOPE_SUBTREE
},
3495 { BER_BVC("subtree"), LDAP_SCOPE_SUBTREE
}, /* OpenLDAP extension */
3499 static slap_verbmasks datamodes
[] = {
3500 { BER_BVC("default"), SYNCDATA_DEFAULT
},
3501 { BER_BVC("accesslog"), SYNCDATA_ACCESSLOG
},
3502 { BER_BVC("changelog"), SYNCDATA_CHANGELOG
},
3507 parse_syncrepl_line(
3515 for ( i
= 1; i
< c
->argc
; i
++ ) {
3516 if ( !strncasecmp( c
->argv
[ i
], IDSTR
"=",
3517 STRLENOF( IDSTR
"=" ) ) )
3520 /* '\0' string terminator accounts for '=' */
3521 val
= c
->argv
[ i
] + STRLENOF( IDSTR
"=" );
3522 if ( lutil_atoi( &tmp
, val
) != 0 ) {
3523 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3524 "Error: parse_syncrepl_line: "
3525 "unable to parse syncrepl id \"%s\"", val
);
3526 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3529 if ( tmp
> SLAP_SYNC_SID_MAX
|| tmp
< 0 ) {
3530 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3531 "Error: parse_syncrepl_line: "
3532 "syncrepl id %d is out of range [0..4095]", tmp
);
3533 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3537 sprintf( si
->si_ridtxt
, IDSTR
"=%03d", si
->si_rid
);
3539 } else if ( !strncasecmp( c
->argv
[ i
], PROVIDERSTR
"=",
3540 STRLENOF( PROVIDERSTR
"=" ) ) )
3542 val
= c
->argv
[ i
] + STRLENOF( PROVIDERSTR
"=" );
3543 ber_str2bv( val
, 0, 1, &si
->si_bindconf
.sb_uri
);
3544 gots
|= GOT_PROVIDER
;
3545 } else if ( !strncasecmp( c
->argv
[ i
], SCHEMASTR
"=",
3546 STRLENOF( SCHEMASTR
"=" ) ) )
3548 val
= c
->argv
[ i
] + STRLENOF( SCHEMASTR
"=" );
3549 if ( !strncasecmp( val
, "on", STRLENOF( "on" ) ) ) {
3550 si
->si_schemachecking
= 1;
3551 } else if ( !strncasecmp( val
, "off", STRLENOF( "off" ) ) ) {
3552 si
->si_schemachecking
= 0;
3554 si
->si_schemachecking
= 1;
3556 } else if ( !strncasecmp( c
->argv
[ i
], FILTERSTR
"=",
3557 STRLENOF( FILTERSTR
"=" ) ) )
3559 val
= c
->argv
[ i
] + STRLENOF( FILTERSTR
"=" );
3560 if ( si
->si_filterstr
.bv_val
)
3561 ch_free( si
->si_filterstr
.bv_val
);
3562 ber_str2bv( val
, 0, 1, &si
->si_filterstr
);
3563 } else if ( !strncasecmp( c
->argv
[ i
], LOGFILTERSTR
"=",
3564 STRLENOF( LOGFILTERSTR
"=" ) ) )
3566 val
= c
->argv
[ i
] + STRLENOF( LOGFILTERSTR
"=" );
3567 if ( si
->si_logfilterstr
.bv_val
)
3568 ch_free( si
->si_logfilterstr
.bv_val
);
3569 ber_str2bv( val
, 0, 1, &si
->si_logfilterstr
);
3570 } else if ( !strncasecmp( c
->argv
[ i
], SEARCHBASESTR
"=",
3571 STRLENOF( SEARCHBASESTR
"=" ) ) )
3576 val
= c
->argv
[ i
] + STRLENOF( SEARCHBASESTR
"=" );
3577 if ( si
->si_base
.bv_val
) {
3578 ch_free( si
->si_base
.bv_val
);
3580 ber_str2bv( val
, 0, 0, &bv
);
3581 rc
= dnNormalize( 0, NULL
, NULL
, &bv
, &si
->si_base
, NULL
);
3582 if ( rc
!= LDAP_SUCCESS
) {
3583 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3584 "Invalid base DN \"%s\": %d (%s)",
3585 val
, rc
, ldap_err2string( rc
) );
3586 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3589 if ( !be_issubordinate( c
->be
, &si
->si_base
) ) {
3590 ch_free( si
->si_base
.bv_val
);
3591 BER_BVZERO( &si
->si_base
);
3592 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3593 "Base DN \"%s\" is not within the database naming context",
3595 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3599 } else if ( !strncasecmp( c
->argv
[ i
], LOGBASESTR
"=",
3600 STRLENOF( LOGBASESTR
"=" ) ) )
3605 val
= c
->argv
[ i
] + STRLENOF( LOGBASESTR
"=" );
3606 if ( si
->si_logbase
.bv_val
) {
3607 ch_free( si
->si_logbase
.bv_val
);
3609 ber_str2bv( val
, 0, 0, &bv
);
3610 rc
= dnNormalize( 0, NULL
, NULL
, &bv
, &si
->si_logbase
, NULL
);
3611 if ( rc
!= LDAP_SUCCESS
) {
3612 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3613 "Invalid logbase DN \"%s\": %d (%s)",
3614 val
, rc
, ldap_err2string( rc
) );
3615 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3618 } else if ( !strncasecmp( c
->argv
[ i
], SCOPESTR
"=",
3619 STRLENOF( SCOPESTR
"=" ) ) )
3622 val
= c
->argv
[ i
] + STRLENOF( SCOPESTR
"=" );
3623 for ( j
= 0; !BER_BVISNULL(&scopes
[j
].key
); j
++ ) {
3624 if (!strcasecmp( val
, scopes
[j
].key
.bv_val
) ) {
3625 si
->si_scope
= scopes
[j
].val
;
3629 if ( BER_BVISNULL(&scopes
[j
].key
) ) {
3630 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3631 "Error: parse_syncrepl_line: "
3632 "unknown scope \"%s\"", val
);
3633 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3636 } else if ( !strncasecmp( c
->argv
[ i
], ATTRSONLYSTR
,
3637 STRLENOF( ATTRSONLYSTR
) ) )
3639 si
->si_attrsonly
= 1;
3640 } else if ( !strncasecmp( c
->argv
[ i
], ATTRSSTR
"=",
3641 STRLENOF( ATTRSSTR
"=" ) ) )
3643 val
= c
->argv
[ i
] + STRLENOF( ATTRSSTR
"=" );
3644 if ( !strncasecmp( val
, ":include:", STRLENOF(":include:") ) ) {
3646 attr_fname
= ch_strdup( val
+ STRLENOF(":include:") );
3647 si
->si_anlist
= file2anlist( si
->si_anlist
, attr_fname
, " ,\t" );
3648 if ( si
->si_anlist
== NULL
) {
3649 ch_free( attr_fname
);
3652 si
->si_anfile
= attr_fname
;
3654 char *str
, *s
, *next
;
3655 const char *delimstr
= " ,\t";
3656 str
= ch_strdup( val
);
3657 for ( s
= ldap_pvt_strtok( str
, delimstr
, &next
);
3659 s
= ldap_pvt_strtok( NULL
, delimstr
, &next
) )
3661 if ( strlen(s
) == 1 && *s
== '*' ) {
3662 si
->si_allattrs
= 1;
3663 val
[ s
- str
] = delimstr
[0];
3665 if ( strlen(s
) == 1 && *s
== '+' ) {
3666 si
->si_allopattrs
= 1;
3667 val
[ s
- str
] = delimstr
[0];
3671 si
->si_anlist
= str2anlist( si
->si_anlist
, val
, " ,\t" );
3672 if ( si
->si_anlist
== NULL
) {
3676 } else if ( !strncasecmp( c
->argv
[ i
], EXATTRSSTR
"=",
3677 STRLENOF( EXATTRSSTR
"=" ) ) )
3679 val
= c
->argv
[ i
] + STRLENOF( EXATTRSSTR
"=" );
3680 if ( !strncasecmp( val
, ":include:", STRLENOF(":include:") ) ) {
3682 attr_fname
= ch_strdup( val
+ STRLENOF(":include:") );
3683 si
->si_exanlist
= file2anlist(
3684 si
->si_exanlist
, attr_fname
, " ,\t" );
3685 if ( si
->si_exanlist
== NULL
) {
3686 ch_free( attr_fname
);
3689 ch_free( attr_fname
);
3691 si
->si_exanlist
= str2anlist( si
->si_exanlist
, val
, " ,\t" );
3692 if ( si
->si_exanlist
== NULL
) {
3696 } else if ( !strncasecmp( c
->argv
[ i
], TYPESTR
"=",
3697 STRLENOF( TYPESTR
"=" ) ) )
3699 val
= c
->argv
[ i
] + STRLENOF( TYPESTR
"=" );
3700 if ( !strncasecmp( val
, "refreshOnly",
3701 STRLENOF("refreshOnly") ) )
3703 si
->si_type
= si
->si_ctype
= LDAP_SYNC_REFRESH_ONLY
;
3704 } else if ( !strncasecmp( val
, "refreshAndPersist",
3705 STRLENOF("refreshAndPersist") ) )
3707 si
->si_type
= si
->si_ctype
= LDAP_SYNC_REFRESH_AND_PERSIST
;
3708 si
->si_interval
= 60;
3710 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3711 "Error: parse_syncrepl_line: "
3712 "unknown sync type \"%s\"", val
);
3713 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3716 } else if ( !strncasecmp( c
->argv
[ i
], INTERVALSTR
"=",
3717 STRLENOF( INTERVALSTR
"=" ) ) )
3719 val
= c
->argv
[ i
] + STRLENOF( INTERVALSTR
"=" );
3720 if ( si
->si_type
== LDAP_SYNC_REFRESH_AND_PERSIST
) {
3721 si
->si_interval
= 0;
3722 } else if ( strchr( val
, ':' ) != NULL
) {
3723 char *next
, *ptr
= val
;
3726 dd
= strtol( ptr
, &next
, 10 );
3727 if ( next
== ptr
|| next
[0] != ':' || dd
< 0 ) {
3728 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3729 "Error: parse_syncrepl_line: "
3730 "invalid interval \"%s\", unable to parse days", val
);
3731 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3735 hh
= strtol( ptr
, &next
, 10 );
3736 if ( next
== ptr
|| next
[0] != ':' || hh
< 0 || hh
> 24 ) {
3737 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3738 "Error: parse_syncrepl_line: "
3739 "invalid interval \"%s\", unable to parse hours", val
);
3740 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3744 mm
= strtol( ptr
, &next
, 10 );
3745 if ( next
== ptr
|| next
[0] != ':' || mm
< 0 || mm
> 60 ) {
3746 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3747 "Error: parse_syncrepl_line: "
3748 "invalid interval \"%s\", unable to parse minutes", val
);
3749 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3753 ss
= strtol( ptr
, &next
, 10 );
3754 if ( next
== ptr
|| next
[0] != '\0' || ss
< 0 || ss
> 60 ) {
3755 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3756 "Error: parse_syncrepl_line: "
3757 "invalid interval \"%s\", unable to parse seconds", val
);
3758 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3761 si
->si_interval
= (( dd
* 24 + hh
) * 60 + mm
) * 60 + ss
;
3765 if ( lutil_parse_time( val
, &t
) != 0 ) {
3766 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3767 "Error: parse_syncrepl_line: "
3768 "invalid interval \"%s\"", val
);
3769 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3772 si
->si_interval
= (time_t)t
;
3774 if ( si
->si_interval
< 0 ) {
3775 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3776 "Error: parse_syncrepl_line: "
3777 "invalid interval \"%ld\"",
3778 (long) si
->si_interval
);
3779 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3782 } else if ( !strncasecmp( c
->argv
[ i
], RETRYSTR
"=",
3783 STRLENOF( RETRYSTR
"=" ) ) )
3788 val
= c
->argv
[ i
] + STRLENOF( RETRYSTR
"=" );
3789 retry_list
= (char **) ch_calloc( 1, sizeof( char * ) );
3790 retry_list
[0] = NULL
;
3792 slap_str2clist( &retry_list
, val
, " ,\t" );
3794 for ( k
= 0; retry_list
&& retry_list
[k
]; k
++ ) ;
3797 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3798 "Error: incomplete syncrepl retry list" );
3799 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3800 for ( k
= 0; retry_list
&& retry_list
[k
]; k
++ ) {
3801 ch_free( retry_list
[k
] );
3803 ch_free( retry_list
);
3806 si
->si_retryinterval
= (time_t *) ch_calloc( n
+ 1, sizeof( time_t ) );
3807 si
->si_retrynum
= (int *) ch_calloc( n
+ 1, sizeof( int ) );
3808 si
->si_retrynum_init
= (int *) ch_calloc( n
+ 1, sizeof( int ) );
3809 for ( j
= 0; j
< n
; j
++ ) {
3811 if ( lutil_atoul( &t
, retry_list
[j
*2] ) != 0 ) {
3812 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3813 "Error: invalid retry interval \"%s\" (#%d)",
3814 retry_list
[j
*2], j
);
3815 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3816 /* do some cleanup */
3819 si
->si_retryinterval
[j
] = (time_t)t
;
3820 if ( *retry_list
[j
*2+1] == '+' ) {
3821 si
->si_retrynum_init
[j
] = RETRYNUM_FOREVER
;
3822 si
->si_retrynum
[j
] = RETRYNUM_FOREVER
;
3826 if ( lutil_atoi( &si
->si_retrynum_init
[j
], retry_list
[j
*2+1] ) != 0
3827 || si
->si_retrynum_init
[j
] <= 0 )
3829 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3830 "Error: invalid initial retry number \"%s\" (#%d)",
3831 retry_list
[j
*2+1], j
);
3832 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3833 /* do some cleanup */
3836 if ( lutil_atoi( &si
->si_retrynum
[j
], retry_list
[j
*2+1] ) != 0
3837 || si
->si_retrynum
[j
] <= 0 )
3839 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3840 "Error: invalid retry number \"%s\" (#%d)",
3841 retry_list
[j
*2+1], j
);
3842 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3843 /* do some cleanup */
3848 si
->si_retrynum_init
[j
] = RETRYNUM_TAIL
;
3849 si
->si_retrynum
[j
] = RETRYNUM_TAIL
;
3850 si
->si_retryinterval
[j
] = 0;
3852 for ( k
= 0; retry_list
&& retry_list
[k
]; k
++ ) {
3853 ch_free( retry_list
[k
] );
3855 ch_free( retry_list
);
3856 } else if ( !strncasecmp( c
->argv
[ i
], MANAGEDSAITSTR
"=",
3857 STRLENOF( MANAGEDSAITSTR
"=" ) ) )
3859 val
= c
->argv
[ i
] + STRLENOF( MANAGEDSAITSTR
"=" );
3860 if ( lutil_atoi( &si
->si_manageDSAit
, val
) != 0
3861 || si
->si_manageDSAit
< 0 || si
->si_manageDSAit
> 1 )
3863 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3864 "invalid manageDSAit value \"%s\".\n",
3866 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3869 } else if ( !strncasecmp( c
->argv
[ i
], SLIMITSTR
"=",
3870 STRLENOF( SLIMITSTR
"=") ) )
3872 val
= c
->argv
[ i
] + STRLENOF( SLIMITSTR
"=" );
3873 if ( strcasecmp( val
, "unlimited" ) == 0 ) {
3876 } else if ( lutil_atoi( &si
->si_slimit
, val
) != 0 || si
->si_slimit
< 0 ) {
3877 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3878 "invalid size limit value \"%s\".\n",
3880 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3883 } else if ( !strncasecmp( c
->argv
[ i
], TLIMITSTR
"=",
3884 STRLENOF( TLIMITSTR
"=" ) ) )
3886 val
= c
->argv
[ i
] + STRLENOF( TLIMITSTR
"=" );
3887 if ( strcasecmp( val
, "unlimited" ) == 0 ) {
3890 } else if ( lutil_atoi( &si
->si_tlimit
, val
) != 0 || si
->si_tlimit
< 0 ) {
3891 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3892 "invalid time limit value \"%s\".\n",
3894 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3897 } else if ( !strncasecmp( c
->argv
[ i
], SYNCDATASTR
"=",
3898 STRLENOF( SYNCDATASTR
"=" ) ) )
3900 val
= c
->argv
[ i
] + STRLENOF( SYNCDATASTR
"=" );
3901 si
->si_syncdata
= verb_to_mask( val
, datamodes
);
3902 } else if ( bindconf_parse( c
->argv
[i
], &si
->si_bindconf
) ) {
3903 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3904 "Error: parse_syncrepl_line: "
3905 "unable to parse \"%s\"\n", c
->argv
[ i
] );
3906 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3911 if ( gots
!= GOT_ALL
) {
3912 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
3913 "Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s",
3914 gots
& GOT_ID
? "" : " "IDSTR
,
3915 gots
& GOT_PROVIDER
? "" : " "PROVIDERSTR
,
3916 gots
& GOT_BASE
? "" : " "SEARCHBASESTR
);
3917 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
, 0 );
3931 if ( !( c
->be
->be_search
&& c
->be
->be_add
&& c
->be
->be_modify
&& c
->be
->be_delete
) ) {
3932 snprintf( c
->cr_msg
, sizeof(c
->cr_msg
), "database %s does not support "
3933 "operations required for syncrepl", c
->be
->be_type
);
3934 Debug( LDAP_DEBUG_ANY
, "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
3937 if ( BER_BVISEMPTY( &c
->be
->be_rootdn
) ) {
3938 strcpy( c
->cr_msg
, "rootDN must be defined before syncrepl may be used" );
3939 Debug( LDAP_DEBUG_ANY
, "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
3942 si
= (syncinfo_t
*) ch_calloc( 1, sizeof( syncinfo_t
) );
3945 Debug( LDAP_DEBUG_ANY
, "out of memory in add_syncrepl\n", 0, 0, 0 );
3949 si
->si_bindconf
.sb_tls
= SB_TLS_OFF
;
3950 si
->si_bindconf
.sb_method
= LDAP_AUTH_SIMPLE
;
3951 si
->si_schemachecking
= 0;
3952 ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
3953 &si
->si_filterstr
);
3954 si
->si_base
.bv_val
= NULL
;
3955 si
->si_scope
= LDAP_SCOPE_SUBTREE
;
3956 si
->si_attrsonly
= 0;
3957 si
->si_anlist
= (AttributeName
*) ch_calloc( 1, sizeof( AttributeName
) );
3958 si
->si_exanlist
= (AttributeName
*) ch_calloc( 1, sizeof( AttributeName
) );
3959 si
->si_attrs
= NULL
;
3960 si
->si_allattrs
= 0;
3961 si
->si_allopattrs
= 0;
3962 si
->si_exattrs
= NULL
;
3963 si
->si_type
= si
->si_ctype
= LDAP_SYNC_REFRESH_ONLY
;
3964 si
->si_interval
= 86400;
3965 si
->si_retryinterval
= NULL
;
3966 si
->si_retrynum_init
= NULL
;
3967 si
->si_retrynum
= NULL
;
3968 si
->si_manageDSAit
= 0;
3972 si
->si_presentlist
= NULL
;
3973 LDAP_LIST_INIT( &si
->si_nonpresentlist
);
3974 ldap_pvt_thread_mutex_init( &si
->si_mutex
);
3976 rc
= parse_syncrepl_line( c
, si
);
3979 /* Must be LDAPv3 because we need controls */
3980 switch ( si
->si_bindconf
.sb_version
) {
3982 /* not explicitly set */
3983 si
->si_bindconf
.sb_version
= LDAP_VERSION3
;
3986 /* explicitly set */
3989 Debug( LDAP_DEBUG_ANY
,
3990 "version %d incompatible with syncrepl\n",
3991 si
->si_bindconf
.sb_version
, 0, 0 );
3992 syncinfo_free( si
, 0 );
3997 if ( slapMode
& SLAP_SERVER_MODE
) {
3998 Listener
**l
= slapd_get_listeners();
4001 /* check if URL points to current server. If so, ignore
4002 * this configuration. We require an exact match. Just
4003 * in case they really want to do this, they can vary
4004 * the case of the URL to allow it.
4006 if ( l
&& !SLAP_DBHIDDEN( c
->be
) ) {
4008 for ( i
=0; l
[i
]; i
++ ) {
4009 if ( bvmatch( &l
[i
]->sl_url
, &si
->si_bindconf
.sb_uri
) ) {
4017 init_syncrepl( si
);
4018 ldap_pvt_thread_mutex_lock( &slapd_rq
.rq_mutex
);
4019 si
->si_re
= ldap_pvt_runqueue_insert( &slapd_rq
,
4020 si
->si_interval
, do_syncrepl
, si
, "do_syncrepl",
4022 ldap_pvt_thread_mutex_unlock( &slapd_rq
.rq_mutex
);
4024 rc
= config_sync_shadow( c
) ? -1 : 0;
4029 /* mirrormode still needs to see this flag in tool mode */
4030 rc
= config_sync_shadow( c
) ? -1 : 0;
4035 /* Use main slapd defaults */
4036 bindconf_tls_defaults( &si
->si_bindconf
);
4039 Debug( LDAP_DEBUG_ANY
, "failed to add syncinfo\n", 0, 0, 0 );
4040 syncinfo_free( si
, 0 );
4043 Debug( LDAP_DEBUG_CONFIG
,
4044 "Config: ** successfully added syncrepl \"%s\"\n",
4045 BER_BVISNULL( &si
->si_bindconf
.sb_uri
) ?
4046 "(null)" : si
->si_bindconf
.sb_uri
.bv_val
, 0, 0 );
4047 if ( !si
->si_schemachecking
) {
4048 SLAP_DBFLAGS(c
->be
) |= SLAP_DBFLAG_NO_SCHEMA_CHECK
;
4050 if ( c
->be
->be_syncinfo
) {
4051 si
->si_cookieState
= c
->be
->be_syncinfo
->si_cookieState
;
4053 si
->si_cookieState
= ch_calloc( 1, sizeof( cookie_state
));
4054 ldap_pvt_thread_mutex_init( &si
->si_cookieState
->cs_mutex
);
4056 si
->si_next
= c
->be
->be_syncinfo
;
4057 c
->be
->be_syncinfo
= si
;
4063 syncrepl_unparse( syncinfo_t
*si
, struct berval
*bv
)
4065 struct berval bc
, uri
;
4066 char buf
[BUFSIZ
*2], *ptr
;
4069 #define WHATSLEFT ( sizeof( buf ) - ( ptr - buf ) )
4073 /* temporarily inhibit bindconf from printing URI */
4074 uri
= si
->si_bindconf
.sb_uri
;
4075 BER_BVZERO( &si
->si_bindconf
.sb_uri
);
4076 si
->si_bindconf
.sb_version
= 0;
4077 bindconf_unparse( &si
->si_bindconf
, &bc
);
4078 si
->si_bindconf
.sb_uri
= uri
;
4079 si
->si_bindconf
.sb_version
= LDAP_VERSION3
;
4082 assert( si
->si_rid
>= 0 && si
->si_rid
<= SLAP_SYNC_SID_MAX
);
4083 ptr
+= snprintf( ptr
, WHATSLEFT
, IDSTR
"=%03d " PROVIDERSTR
"=%s",
4084 si
->si_rid
, si
->si_bindconf
.sb_uri
.bv_val
);
4085 if ( ptr
- buf
>= sizeof( buf
) ) return;
4086 if ( !BER_BVISNULL( &bc
) ) {
4087 if ( WHATSLEFT
<= bc
.bv_len
) {
4091 ptr
= lutil_strcopy( ptr
, bc
.bv_val
);
4094 if ( !BER_BVISEMPTY( &si
->si_filterstr
) ) {
4095 if ( WHATSLEFT
<= STRLENOF( " " FILTERSTR
"=\"" "\"" ) + si
->si_filterstr
.bv_len
) return;
4096 ptr
= lutil_strcopy( ptr
, " " FILTERSTR
"=\"" );
4097 ptr
= lutil_strcopy( ptr
, si
->si_filterstr
.bv_val
);
4100 if ( !BER_BVISNULL( &si
->si_base
) ) {
4101 if ( WHATSLEFT
<= STRLENOF( " " SEARCHBASESTR
"=\"" "\"" ) + si
->si_base
.bv_len
) return;
4102 ptr
= lutil_strcopy( ptr
, " " SEARCHBASESTR
"=\"" );
4103 ptr
= lutil_strcopy( ptr
, si
->si_base
.bv_val
);
4106 if ( !BER_BVISEMPTY( &si
->si_logfilterstr
) ) {
4107 if ( WHATSLEFT
<= STRLENOF( " " LOGFILTERSTR
"=\"" "\"" ) + si
->si_logfilterstr
.bv_len
) return;
4108 ptr
= lutil_strcopy( ptr
, " " LOGFILTERSTR
"=\"" );
4109 ptr
= lutil_strcopy( ptr
, si
->si_logfilterstr
.bv_val
);
4112 if ( !BER_BVISNULL( &si
->si_logbase
) ) {
4113 if ( WHATSLEFT
<= STRLENOF( " " LOGBASESTR
"=\"" "\"" ) + si
->si_logbase
.bv_len
) return;
4114 ptr
= lutil_strcopy( ptr
, " " LOGBASESTR
"=\"" );
4115 ptr
= lutil_strcopy( ptr
, si
->si_logbase
.bv_val
);
4118 for (i
=0; !BER_BVISNULL(&scopes
[i
].key
);i
++) {
4119 if ( si
->si_scope
== scopes
[i
].val
) {
4120 if ( WHATSLEFT
<= STRLENOF( " " SCOPESTR
"=" ) + scopes
[i
].key
.bv_len
) return;
4121 ptr
= lutil_strcopy( ptr
, " " SCOPESTR
"=" );
4122 ptr
= lutil_strcopy( ptr
, scopes
[i
].key
.bv_val
);
4126 if ( si
->si_attrsonly
) {
4127 if ( WHATSLEFT
<= STRLENOF( " " ATTRSONLYSTR
"=\"" "\"" ) ) return;
4128 ptr
= lutil_strcopy( ptr
, " " ATTRSONLYSTR
);
4130 if ( si
->si_anfile
) {
4131 if ( WHATSLEFT
<= STRLENOF( " " ATTRSSTR
"=\":include:" "\"" ) + strlen( si
->si_anfile
) ) return;
4132 ptr
= lutil_strcopy( ptr
, " " ATTRSSTR
"=:include:\"" );
4133 ptr
= lutil_strcopy( ptr
, si
->si_anfile
);
4135 } else if ( si
->si_allattrs
|| si
->si_allopattrs
||
4136 ( si
->si_anlist
&& !BER_BVISNULL(&si
->si_anlist
[0].an_name
) ) )
4140 if ( WHATSLEFT
<= STRLENOF( " " ATTRSONLYSTR
"=\"" "\"" ) ) return;
4141 ptr
= lutil_strcopy( ptr
, " " ATTRSSTR
"=\"" );
4143 /* FIXME: add check for overflow */
4144 ptr
= anlist_unparse( si
->si_anlist
, ptr
, WHATSLEFT
);
4145 if ( si
->si_allattrs
) {
4146 if ( WHATSLEFT
<= STRLENOF( ",*\"" ) ) return;
4147 if ( old
!= ptr
) *ptr
++ = ',';
4150 if ( si
->si_allopattrs
) {
4151 if ( WHATSLEFT
<= STRLENOF( ",+\"" ) ) return;
4152 if ( old
!= ptr
) *ptr
++ = ',';
4157 if ( si
->si_exanlist
&& !BER_BVISNULL(&si
->si_exanlist
[0].an_name
) ) {
4158 if ( WHATSLEFT
<= STRLENOF( " " EXATTRSSTR
"=" ) ) return;
4159 ptr
= lutil_strcopy( ptr
, " " EXATTRSSTR
"=" );
4160 /* FIXME: add check for overflow */
4161 ptr
= anlist_unparse( si
->si_exanlist
, ptr
, WHATSLEFT
);
4163 if ( WHATSLEFT
<= STRLENOF( " " SCHEMASTR
"=" ) + STRLENOF( "off" ) ) return;
4164 ptr
= lutil_strcopy( ptr
, " " SCHEMASTR
"=" );
4165 ptr
= lutil_strcopy( ptr
, si
->si_schemachecking
? "on" : "off" );
4167 if ( WHATSLEFT
<= STRLENOF( " " TYPESTR
"=" ) + STRLENOF( "refreshAndPersist" ) ) return;
4168 ptr
= lutil_strcopy( ptr
, " " TYPESTR
"=" );
4169 ptr
= lutil_strcopy( ptr
, si
->si_type
== LDAP_SYNC_REFRESH_AND_PERSIST
?
4170 "refreshAndPersist" : "refreshOnly" );
4172 if ( si
->si_type
== LDAP_SYNC_REFRESH_ONLY
) {
4175 dd
= si
->si_interval
;
4182 ptr
= lutil_strcopy( ptr
, " " INTERVALSTR
"=" );
4183 ptr
+= snprintf( ptr
, WHATSLEFT
, "%02d:%02d:%02d:%02d", dd
, hh
, mm
, ss
);
4184 if ( ptr
- buf
>= sizeof( buf
) ) return;
4185 } else if ( si
->si_retryinterval
) {
4187 if ( WHATSLEFT
<= STRLENOF( " " RETRYSTR
"=\"" "\"" ) ) return;
4188 ptr
= lutil_strcopy( ptr
, " " RETRYSTR
"=\"" );
4189 for (i
=0; si
->si_retryinterval
[i
]; i
++) {
4190 if ( space
) *ptr
++ = ' ';
4192 ptr
+= snprintf( ptr
, WHATSLEFT
, "%ld ", (long) si
->si_retryinterval
[i
] );
4193 if ( si
->si_retrynum_init
[i
] == RETRYNUM_FOREVER
)
4196 ptr
+= snprintf( ptr
, WHATSLEFT
, "%d", si
->si_retrynum_init
[i
] );
4198 if ( WHATSLEFT
<= STRLENOF( "\"" ) ) return;
4202 if ( si
->si_slimit
) {
4203 if ( WHATSLEFT
<= STRLENOF( " " SLIMITSTR
"=" ) ) return;
4204 ptr
= lutil_strcopy( ptr
, " " SLIMITSTR
"=" );
4205 ptr
+= snprintf( ptr
, WHATSLEFT
, "%d", si
->si_slimit
);
4208 if ( si
->si_tlimit
) {
4209 if ( WHATSLEFT
<= STRLENOF( " " TLIMITSTR
"=" ) ) return;
4210 ptr
= lutil_strcopy( ptr
, " " TLIMITSTR
"=" );
4211 ptr
+= snprintf( ptr
, WHATSLEFT
, "%d", si
->si_tlimit
);
4214 if ( si
->si_syncdata
) {
4215 if ( enum_to_verb( datamodes
, si
->si_syncdata
, &bc
) >= 0 ) {
4216 if ( WHATSLEFT
<= STRLENOF( " " SYNCDATASTR
"=" ) + bc
.bv_len
) return;
4217 ptr
= lutil_strcopy( ptr
, " " SYNCDATASTR
"=" );
4218 ptr
= lutil_strcopy( ptr
, bc
.bv_val
);
4221 bc
.bv_len
= ptr
- buf
;
4223 ber_dupbv( bv
, &bc
);
4227 syncrepl_config( ConfigArgs
*c
)
4229 if (c
->op
== SLAP_CONFIG_EMIT
) {
4230 if ( c
->be
->be_syncinfo
) {
4234 for ( si
= c
->be
->be_syncinfo
; si
; si
=si
->si_next
) {
4235 syncrepl_unparse( si
, &bv
);
4236 ber_bvarray_add( &c
->rvalue_vals
, &bv
);
4241 } else if ( c
->op
== LDAP_MOD_DELETE
) {
4242 cookie_state
*cs
= NULL
;
4243 if ( c
->be
->be_syncinfo
) {
4244 syncinfo_t
*si
, **sip
;
4247 cs
= c
->be
->be_syncinfo
->si_cookieState
;
4248 for ( sip
= &c
->be
->be_syncinfo
, i
=0; *sip
; i
++ ) {
4250 if ( c
->valx
== -1 || i
== c
->valx
) {
4253 /* If the task is currently active, we have to leave
4254 * it running. It will exit on its own. This will only
4255 * happen when running on the cn=config DB.
4258 ldap_pvt_thread_mutex_lock( &slapd_rq
.rq_mutex
);
4259 isrunning
= ldap_pvt_runqueue_isrunning( &slapd_rq
, si
->si_re
);
4260 ldap_pvt_thread_mutex_unlock( &slapd_rq
.rq_mutex
);
4262 if ( si
->si_re
&& isrunning
) {
4265 syncinfo_free( si
, 0 );
4274 if ( !c
->be
->be_syncinfo
) {
4275 SLAP_DBFLAGS( c
->be
) &= ~(SLAP_DBFLAG_SHADOW
|SLAP_DBFLAG_SYNC_SHADOW
);
4277 ber_bvarray_free( cs
->cs_vals
);
4278 ldap_pvt_thread_mutex_destroy( &cs
->cs_mutex
);
4284 if ( SLAP_SLURP_SHADOW( c
->be
) ) {
4285 Debug(LDAP_DEBUG_ANY
, "%s: "
4286 "syncrepl: database already shadowed.\n",
4290 return add_syncrepl( c
);