+
+
+
+/* NOTE: used & documented in slapd.conf(5) */
+#define IDSTR "rid"
+#define PROVIDERSTR "provider"
+#define SCHEMASTR "schemachecking"
+#define FILTERSTR "filter"
+#define SEARCHBASESTR "searchbase"
+#define SCOPESTR "scope"
+#define ATTRSONLYSTR "attrsonly"
+#define ATTRSSTR "attrs"
+#define TYPESTR "type"
+#define INTERVALSTR "interval"
+#define RETRYSTR "retry"
+#define SLIMITSTR "sizelimit"
+#define TLIMITSTR "timelimit"
+#define SYNCDATASTR "syncdata"
+
+/* FIXME: undocumented */
+#define LOGBASESTR "logbase"
+#define LOGFILTERSTR "logfilter"
+#define OLDAUTHCSTR "bindprincipal"
+#define EXATTRSSTR "exattrs"
+#define MANAGEDSAITSTR "manageDSAit"
+
+/* FIXME: unused */
+#define LASTMODSTR "lastmod"
+#define LMGENSTR "gen"
+#define LMNOSTR "no"
+#define LMREQSTR "req"
+#define SRVTABSTR "srvtab"
+#define SUFFIXSTR "suffix"
+
+/* mandatory */
+#define GOT_ID 0x0001
+#define GOT_PROVIDER 0x0002
+
+/* check */
+#define GOT_ALL (GOT_ID|GOT_PROVIDER)
+
+static struct {
+ struct berval key;
+ int val;
+} scopes[] = {
+ { BER_BVC("base"), LDAP_SCOPE_BASE },
+ { BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
+ { BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL }, /* OpenLDAP extension */
+ { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
+ { BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE },
+ { BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
+ { BER_BVC("subtree"), LDAP_SCOPE_SUBTREE }, /* OpenLDAP extension */
+ { BER_BVNULL, 0 }
+};
+
+static slap_verbmasks datamodes[] = {
+ { BER_BVC("default"), SYNCDATA_DEFAULT },
+ { BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
+ { BER_BVC("changelog"), SYNCDATA_CHANGELOG },
+ { BER_BVNULL, 0 }
+};
+
+static int
+parse_syncrepl_line(
+ ConfigArgs *c,
+ syncinfo_t *si )
+{
+ int gots = 0;
+ int i;
+ char *val;
+
+ for ( i = 1; i < c->argc; i++ ) {
+ if ( !strncasecmp( c->argv[ i ], IDSTR "=",
+ STRLENOF( IDSTR "=" ) ) )
+ {
+ int tmp;
+ /* '\0' string terminator accounts for '=' */
+ val = c->argv[ i ] + STRLENOF( IDSTR "=" );
+ if ( lutil_atoi( &tmp, val ) != 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "unable to parse syncrepl id \"%s\"", val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ if ( tmp >= 1000 || tmp < 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "syncrepl id %d is out of range [0..999]", tmp );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ si->si_rid = tmp;
+ gots |= GOT_ID;
+ } else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
+ STRLENOF( PROVIDERSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
+ ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
+ gots |= GOT_PROVIDER;
+ } else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
+ STRLENOF( SCHEMASTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( SCHEMASTR "=" );
+ if ( !strncasecmp( val, "on", STRLENOF( "on" ) )) {
+ si->si_schemachecking = 1;
+ } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
+ si->si_schemachecking = 0;
+ } else {
+ si->si_schemachecking = 1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=",
+ STRLENOF( FILTERSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( FILTERSTR "=" );
+ if ( si->si_filterstr.bv_val )
+ ch_free( si->si_filterstr.bv_val );
+ ber_str2bv( val, 0, 1, &si->si_filterstr );
+ } else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=",
+ STRLENOF( LOGFILTERSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( LOGFILTERSTR "=" );
+ if ( si->si_logfilterstr.bv_val )
+ ch_free( si->si_logfilterstr.bv_val );
+ ber_str2bv( val, 0, 1, &si->si_logfilterstr );
+ } else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=",
+ STRLENOF( SEARCHBASESTR "=" ) ) )
+ {
+ struct berval bv;
+ int rc;
+
+ val = c->argv[ i ] + STRLENOF( SEARCHBASESTR "=" );
+ if ( si->si_base.bv_val ) {
+ ch_free( si->si_base.bv_val );
+ }
+ ber_str2bv( val, 0, 0, &bv );
+ rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Invalid base DN \"%s\": %d (%s)",
+ val, rc, ldap_err2string( rc ) );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
+ STRLENOF( LOGBASESTR "=" ) ) )
+ {
+ struct berval bv;
+ int rc;
+
+ val = c->argv[ i ] + STRLENOF( LOGBASESTR "=" );
+ if ( si->si_logbase.bv_val ) {
+ ch_free( si->si_logbase.bv_val );
+ }
+ ber_str2bv( val, 0, 0, &bv );
+ rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_logbase, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Invalid logbase DN \"%s\": %d (%s)",
+ val, rc, ldap_err2string( rc ) );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=",
+ STRLENOF( SCOPESTR "=" ) ) )
+ {
+ int j;
+ val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
+ for ( j=0; !BER_BVISNULL(&scopes[j].key); j++ ) {
+ if (!strcasecmp( val, scopes[j].key.bv_val )) {
+ si->si_scope = scopes[j].val;
+ break;
+ }
+ }
+ if ( BER_BVISNULL(&scopes[j].key) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "unknown scope \"%s\"", val);
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
+ STRLENOF( ATTRSONLYSTR ) ) )
+ {
+ si->si_attrsonly = 1;
+ } else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=",
+ STRLENOF( ATTRSSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( ATTRSSTR "=" );
+ if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
+ char *attr_fname;
+ attr_fname = ch_strdup( val + STRLENOF(":include:") );
+ si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
+ if ( si->si_anlist == NULL ) {
+ ch_free( attr_fname );
+ return -1;
+ }
+ si->si_anfile = attr_fname;
+ } else {
+ char *str, *s, *next;
+ char delimstr[] = " ,\t";
+ str = ch_strdup( val );
+ for ( s = ldap_pvt_strtok( str, delimstr, &next );
+ s != NULL;
+ s = ldap_pvt_strtok( NULL, delimstr, &next ) )
+ {
+ if ( strlen(s) == 1 && *s == '*' ) {
+ si->si_allattrs = 1;
+ *(val + ( s - str )) = delimstr[0];
+ }
+ if ( strlen(s) == 1 && *s == '+' ) {
+ si->si_allopattrs = 1;
+ *(val + ( s - str )) = delimstr[0];
+ }
+ }
+ ch_free( str );
+ si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
+ if ( si->si_anlist == NULL ) {
+ return -1;
+ }
+ }
+ } else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=",
+ STRLENOF( EXATTRSSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( EXATTRSSTR "=" );
+ if ( !strncasecmp( val, ":include:", STRLENOF(":include:") )) {
+ char *attr_fname;
+ attr_fname = ch_strdup( val + STRLENOF(":include:") );
+ si->si_exanlist = file2anlist(
+ si->si_exanlist, attr_fname, " ,\t" );
+ if ( si->si_exanlist == NULL ) {
+ ch_free( attr_fname );
+ return -1;
+ }
+ ch_free( attr_fname );
+ } else {
+ si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
+ if ( si->si_exanlist == NULL ) {
+ return -1;
+ }
+ }
+ } else if ( !strncasecmp( c->argv[ i ], TYPESTR "=",
+ STRLENOF( TYPESTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( TYPESTR "=" );
+ if ( !strncasecmp( val, "refreshOnly",
+ STRLENOF("refreshOnly") ) )
+ {
+ si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
+ } else if ( !strncasecmp( val, "refreshAndPersist",
+ STRLENOF("refreshAndPersist") ) )
+ {
+ si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_AND_PERSIST;
+ si->si_interval = 60;
+ } else {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "unknown sync type \"%s\"", val);
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=",
+ STRLENOF( INTERVALSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( INTERVALSTR "=" );
+ if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+ si->si_interval = 0;
+ } else if ( strchr( val, ':' ) != NULL ) {
+ char *next, *ptr = val;
+ unsigned dd, hh, mm, ss;
+ dd = strtoul( ptr, &next, 10 );
+ if ( next == ptr || next[0] != ':' ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\", unable to parse days", val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ ptr = next + 1;
+ hh = strtoul( ptr, &next, 10 );
+ if ( next == ptr || next[0] != ':' || hh > 24 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\", unable to parse hours", val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ ptr = next + 1;
+ mm = strtoul( ptr, &next, 10 );
+ if ( next == ptr || next[0] != ':' || mm > 60 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\", unable to parse minutes", val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ ptr = next + 1;
+ ss = strtoul( ptr, &next, 10 );
+ if ( next == ptr || next[0] != '\0' || ss > 60 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\", unable to parse seconds", val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
+ } else {
+ unsigned long t;
+
+ if ( lutil_parse_time( val, &t ) != 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\"", val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ si->si_interval = (time_t)t;
+ }
+ if ( si->si_interval < 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "invalid interval \"%ld\"",
+ (long) si->si_interval);
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=",
+ STRLENOF( RETRYSTR "=" ) ) )
+ {
+ char **retry_list;
+ int j, k, n;
+
+ val = c->argv[ i ] + STRLENOF( RETRYSTR "=" );
+ retry_list = (char **) ch_calloc( 1, sizeof( char * ));
+ retry_list[0] = NULL;
+
+ slap_str2clist( &retry_list, val, " ,\t" );
+
+ for ( k = 0; retry_list && retry_list[k]; k++ ) ;
+ n = k / 2;
+ if ( k % 2 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: incomplete syncrepl retry list" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ for ( k = 0; retry_list && retry_list[k]; k++ ) {
+ ch_free( retry_list[k] );
+ }
+ ch_free( retry_list );
+ return 1;
+ }
+ si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ));
+ si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ));
+ si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ));
+ for ( j = 0; j < n; j++ ) {
+ unsigned long t;
+ if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: invalid retry interval \"%s\" (#%d)",
+ retry_list[j*2], j );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ /* do some cleanup */
+ return 1;
+ }
+ si->si_retryinterval[j] = (time_t)t;
+ if ( *retry_list[j*2+1] == '+' ) {
+ si->si_retrynum_init[j] = RETRYNUM_FOREVER;
+ si->si_retrynum[j] = RETRYNUM_FOREVER;
+ j++;
+ break;
+ } else {
+ if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
+ || si->si_retrynum_init[j] <= 0 )
+ {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: invalid initial retry number \"%s\" (#%d)",
+ retry_list[j*2+1], j );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ /* do some cleanup */
+ return 1;
+ }
+ if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
+ || si->si_retrynum[j] <= 0 )
+ {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: invalid retry number \"%s\" (#%d)",
+ retry_list[j*2+1], j );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ /* do some cleanup */
+ return 1;
+ }
+ }
+ }
+ si->si_retrynum_init[j] = RETRYNUM_TAIL;
+ si->si_retrynum[j] = RETRYNUM_TAIL;
+ si->si_retryinterval[j] = 0;
+
+ for ( k = 0; retry_list && retry_list[k]; k++ ) {
+ ch_free( retry_list[k] );
+ }
+ ch_free( retry_list );
+ } else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=",
+ STRLENOF( MANAGEDSAITSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
+ if ( lutil_atoi( &si->si_manageDSAit, val ) != 0
+ || si->si_manageDSAit < 0 || si->si_manageDSAit > 1 )
+ {
+ snprintf( c->msg, sizeof( c->msg ),
+ "invalid manageDSAit value \"%s\".\n",
+ val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=",
+ STRLENOF( SLIMITSTR "=") ) )
+ {
+ val = c->argv[ i ] + STRLENOF( SLIMITSTR "=" );
+ if ( strcasecmp( val, "unlimited" ) == 0 ) {
+ si->si_slimit = 0;
+
+ } else if ( lutil_atoi( &si->si_slimit, val ) != 0 || si->si_slimit < 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "invalid size limit value \"%s\".\n",
+ val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=",
+ STRLENOF( TLIMITSTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( TLIMITSTR "=" );
+ if ( strcasecmp( val, "unlimited" ) == 0 ) {
+ si->si_tlimit = 0;
+
+ } else if ( lutil_atoi( &si->si_tlimit, val ) != 0 || si->si_tlimit < 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "invalid time limit value \"%s\".\n",
+ val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ } else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=",
+ STRLENOF( SYNCDATASTR "=" ) ) )
+ {
+ val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
+ si->si_syncdata = verb_to_mask( val, datamodes );
+ } else if ( bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: parse_syncrepl_line: "
+ "unknown keyword \"%s\"\n", c->argv[ i ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+ }
+
+ if ( gots != GOT_ALL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "Error: Malformed \"syncrepl\" line in slapd config file" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+add_syncrepl(
+ ConfigArgs *c )
+{
+ syncinfo_t *si;
+ int rc = 0;
+
+ if ( !( c->be->be_search && c->be->be_add && c->be->be_modify && c->be->be_delete ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: database %s does not support operations "
+ "required for syncrepl\n", c->log, c->be->be_type, 0 );
+ return 1;
+ }
+ si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
+
+ if ( si == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
+ return 1;
+ }
+
+ si->si_bindconf.sb_tls = SB_TLS_OFF;
+ si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
+ si->si_schemachecking = 0;
+ ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
+ &si->si_filterstr );
+ si->si_base.bv_val = NULL;
+ si->si_scope = LDAP_SCOPE_SUBTREE;
+ si->si_attrsonly = 0;
+ si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
+ si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
+ si->si_attrs = NULL;
+ si->si_allattrs = 0;
+ si->si_allopattrs = 0;
+ si->si_exattrs = NULL;
+ si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
+ si->si_interval = 86400;
+ si->si_retryinterval = NULL;
+ si->si_retrynum_init = NULL;
+ si->si_retrynum = NULL;
+ si->si_manageDSAit = 0;
+ si->si_tlimit = 0;
+ si->si_slimit = 0;
+ si->si_conn_setup = 0;
+
+ si->si_presentlist = NULL;
+ LDAP_LIST_INIT( &si->si_nonpresentlist );
+ ldap_pvt_thread_mutex_init( &si->si_mutex );
+
+ rc = parse_syncrepl_line( c, si );
+
+ if ( rc == 0 ) {
+ si->si_be = c->be;
+ init_syncrepl( si );
+ si->si_re = ldap_pvt_runqueue_insert( &slapd_rq, si->si_interval,
+ do_syncrepl, si, "do_syncrepl", c->be->be_suffix[0].bv_val );
+ if ( !si->si_re )
+ rc = -1;
+ }
+ if ( rc < 0 ) {
+ Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
+ syncinfo_free( si );
+ return 1;
+ } else {
+ Debug( LDAP_DEBUG_CONFIG,
+ "Config: ** successfully added syncrepl \"%s\"\n",
+ BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
+ "(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 );
+ if ( !si->si_schemachecking ) {
+ SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
+ }
+ c->be->be_syncinfo = si;
+ return 0;
+ }
+}
+
+static void
+syncrepl_unparse( syncinfo_t *si, struct berval *bv )
+{
+ struct berval bc, uri;
+ char buf[BUFSIZ*2], *ptr;
+ int i;
+
+#define WHATSLEFT ( sizeof( buf ) - ( ptr - buf ) )
+
+ BER_BVZERO( bv );
+
+ /* temporarily inhibit bindconf from printing URI */
+ uri = si->si_bindconf.sb_uri;
+ BER_BVZERO( &si->si_bindconf.sb_uri );
+ bindconf_unparse( &si->si_bindconf, &bc );
+ si->si_bindconf.sb_uri = uri;
+
+ ptr = buf;
+ ptr += snprintf( ptr, WHATSLEFT, IDSTR "=%03ld " PROVIDERSTR "=%s",
+ si->si_rid, si->si_bindconf.sb_uri.bv_val );
+ if ( ptr - buf >= sizeof( buf ) ) return;
+ if ( !BER_BVISNULL( &bc )) {
+ if ( WHATSLEFT <= bc.bv_len ) {
+ free( bc.bv_val );
+ return;
+ }
+ ptr = lutil_strcopy( ptr, bc.bv_val );
+ free( bc.bv_val );
+ }
+ if ( !BER_BVISEMPTY( &si->si_filterstr )) {
+ if ( WHATSLEFT <= STRLENOF( " " FILTERSTR "=\"" "\"" ) + si->si_filterstr.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
+ ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
+ *ptr++ = '"';
+ }
+ if ( !BER_BVISNULL( &si->si_base )) {
+ if ( WHATSLEFT <= STRLENOF( " " SEARCHBASESTR "=\"" "\"" ) + si->si_base.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
+ ptr = lutil_strcopy( ptr, si->si_base.bv_val );
+ *ptr++ = '"';
+ }
+ if ( !BER_BVISEMPTY( &si->si_logfilterstr )) {
+ if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
+ ptr = lutil_strcopy( ptr, si->si_logfilterstr.bv_val );
+ *ptr++ = '"';
+ }
+ if ( !BER_BVISNULL( &si->si_logbase )) {
+ if ( WHATSLEFT <= STRLENOF( " " LOGBASESTR "=\"" "\"" ) + si->si_logbase.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " LOGBASESTR "=\"" );
+ ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
+ *ptr++ = '"';
+ }
+ for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
+ if ( si->si_scope == scopes[i].val ) {
+ if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + scopes[i].key.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
+ ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
+ break;
+ }
+ }
+ if ( si->si_attrsonly ) {
+ if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
+ ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR );
+ }
+ if ( si->si_anfile ) {
+ if ( WHATSLEFT <= STRLENOF( " " ATTRSSTR "=\":include:" "\"" ) + strlen( si->si_anfile ) ) return;
+ ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:\"" );
+ ptr = lutil_strcopy( ptr, si->si_anfile );
+ *ptr++ = '"';
+ } else if ( si->si_allattrs || si->si_allopattrs ||
+ ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) ))
+ {
+ char *old;
+
+ if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
+ ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
+ old = ptr;
+ /* FIXME: add check for overflow */
+ ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
+ if ( si->si_allattrs ) {
+ if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
+ if ( old != ptr ) *ptr++ = ',';
+ *ptr++ = '*';
+ }
+ if ( si->si_allopattrs ) {
+ if ( WHATSLEFT <= STRLENOF( ",+\"" ) ) return;
+ if ( old != ptr ) *ptr++ = ',';
+ *ptr++ = '+';
+ }
+ *ptr++ = '"';
+ }
+ if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
+ if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
+ ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
+ /* FIXME: add check for overflow */
+ ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
+ }
+ if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
+ ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
+ ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
+
+ if ( WHATSLEFT <= STRLENOF( " " TYPESTR "=" ) + STRLENOF( "refreshAndPersist" ) ) return;
+ ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
+ ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
+ "refreshAndPersist" : "refreshOnly" );
+
+ if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
+ int dd, hh, mm, ss;
+
+ dd = si->si_interval;
+ ss = dd % 60;
+ dd /= 60;
+ mm = dd % 60;
+ dd /= 60;
+ hh = dd % 24;
+ dd /= 24;
+ ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
+ ptr += snprintf( ptr, WHATSLEFT, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
+ if ( ptr - buf >= sizeof( buf ) ) return;
+ } else if ( si->si_retryinterval ) {
+ int space=0;
+ if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
+ ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
+ for (i=0; si->si_retryinterval[i]; i++) {
+ if ( space ) *ptr++ = ' ';
+ space = 1;
+ ptr += snprintf( ptr, WHATSLEFT, "%ld ", (long) si->si_retryinterval[i] );
+ if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
+ *ptr++ = '+';
+ else
+ ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+ }
+ if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
+ *ptr++ = '"';
+ }
+
+ if ( si->si_slimit ) {
+ if ( WHATSLEFT <= STRLENOF( " " SLIMITSTR "=" ) ) return;
+ ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
+ ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_slimit );
+ }
+
+ if ( si->si_tlimit ) {
+ if ( WHATSLEFT <= STRLENOF( " " TLIMITSTR "=" ) ) return;
+ ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
+ ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_tlimit );
+ }
+
+ if ( si->si_syncdata ) {
+ if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) {
+ if ( WHATSLEFT <= STRLENOF( " " SYNCDATASTR "=" ) + bc.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" );
+ ptr = lutil_strcopy( ptr, bc.bv_val );
+ }
+ }
+ bc.bv_len = ptr - buf;
+ bc.bv_val = buf;
+ ber_dupbv( bv, &bc );
+}
+
+int
+syncrepl_config( ConfigArgs *c )
+{
+ if (c->op == SLAP_CONFIG_EMIT) {
+ if ( c->be->be_syncinfo ) {
+ struct berval bv;
+ syncrepl_unparse( c->be->be_syncinfo, &bv );
+ ber_bvarray_add( &c->rvalue_vals, &bv );
+ return 0;
+ }
+ return 1;
+ } else if ( c->op == LDAP_MOD_DELETE ) {
+ struct re_s *re;
+
+ if ( c->be->be_syncinfo ) {
+ syncinfo_free( c->be->be_syncinfo );
+ c->be->be_syncinfo = NULL;
+ }
+ SLAP_DBFLAGS( c->be ) &= ~(SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SYNC_SHADOW);
+ return 0;
+ }
+ if ( SLAP_SHADOW( c->be ) ) {
+ Debug(LDAP_DEBUG_ANY, "%s: "
+ "syncrepl: database already shadowed.\n",
+ c->log, 0, 0);
+ return(1);
+ } else if ( add_syncrepl( c ) ) {
+ return(1);
+ }
+ return config_sync_shadow( c );
+}