+
+static int
+add_syncrepl(
+ Backend *be,
+ char **cargv,
+ int cargc
+)
+{
+ syncinfo_t *si;
+ syncinfo_t *si_entry;
+ int rc = 0;
+ int duplicated_replica_id = 0;
+
+ si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
+
+ if ( si == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ERR, "out of memory in add_syncrepl\n", 0, 0,0 );
+#else
+ Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
+#endif
+ return 1;
+ }
+
+ si->si_tls = SYNCINFO_TLS_OFF;
+ if ( be->be_rootndn.bv_val ) {
+ ber_dupbv( &si->si_updatedn, &be->be_rootndn );
+ }
+ si->si_bindmethod = LDAP_AUTH_SIMPLE;
+ si->si_schemachecking = 0;
+ ber_str2bv( "(objectclass=*)", sizeof("(objectclass=*)")-1, 0,
+ &si->si_filterstr );
+ si->si_base.bv_val = NULL;
+ si->si_scope = LDAP_SCOPE_SUBTREE;
+ si->si_attrsonly = 0;
+ si->si_attrs = (char **) ch_calloc( 1, sizeof( char * ));
+ si->si_attrs[0] = NULL;
+ si->si_type = LDAP_SYNC_REFRESH_ONLY;
+ si->si_interval = 86400;
+ si->si_syncCookie.ctxcsn = NULL;
+ si->si_syncCookie.octet_str = NULL;
+ si->si_syncCookie.sid = -1;
+ si->si_manageDSAit = 0;
+ si->si_tlimit = -1;
+ si->si_slimit = -1;
+ si->si_syncUUID_ndn.bv_val = NULL;
+ si->si_syncUUID_ndn.bv_len = 0;
+
+ si->si_presentlist = NULL;
+ LDAP_LIST_INIT( &si->si_nonpresentlist );
+
+ rc = parse_syncrepl_line( cargv, cargc, si );
+
+ LDAP_STAILQ_FOREACH( si_entry, &be->be_syncinfo, si_next ) {
+ if ( si->si_rid == si_entry->si_rid ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ERR,
+ "add_syncrepl: duplicaetd replica id\n", 0, 0,0 );
+#else
+ Debug( LDAP_DEBUG_ANY,
+ "add_syncrepl: duplicated replica id\n",0, 0, 0 );
+#endif
+ duplicated_replica_id = 1;
+ break;
+ }
+ }
+
+ if ( rc < 0 || duplicated_replica_id ) {
+ syncinfo_t *si_entry;
+ /* Something bad happened - back out */
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ERR, "failed to add syncinfo\n", 0, 0,0 );
+#else
+ Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
+#endif
+
+ /* If error, remove all syncinfo */
+ LDAP_STAILQ_FOREACH( si_entry, &be->be_syncinfo, si_next ) {
+ if ( si_entry->si_updatedn.bv_val ) {
+ ch_free( si->si_updatedn.bv_val );
+ }
+ if ( si_entry->si_filterstr.bv_val ) {
+ ch_free( si->si_filterstr.bv_val );
+ }
+ if ( si_entry->si_attrs ) {
+ int i = 0;
+ while ( si_entry->si_attrs[i] != NULL ) {
+ ch_free( si_entry->si_attrs[i] );
+ i++;
+ }
+ ch_free( si_entry->si_attrs );
+ }
+ }
+
+ while ( !LDAP_STAILQ_EMPTY( &be->be_syncinfo )) {
+ si_entry = LDAP_STAILQ_FIRST( &be->be_syncinfo );
+ LDAP_STAILQ_REMOVE_HEAD( &be->be_syncinfo, si_next );
+ ch_free( si_entry );
+ }
+ LDAP_STAILQ_INIT( &be->be_syncinfo );
+ return 1;
+ } else {
+#ifdef NEW_LOGGING
+ LDAP_LOG ( CONFIG, RESULTS,
+ "add_syncrepl: Config: ** successfully added syncrepl \"%s\"\n",
+ si->si_provideruri == NULL ? "(null)" : si->si_provideruri, 0, 0 );
+#else
+ Debug( LDAP_DEBUG_CONFIG,
+ "Config: ** successfully added syncrepl \"%s\"\n",
+ si->si_provideruri == NULL ? "(null)" : si->si_provideruri, 0, 0 );
+#endif
+ if ( !si->si_schemachecking ) {
+ be->be_flags |= SLAP_BFLAG_NO_SCHEMA_CHECK;
+ }
+ si->si_be = be;
+ LDAP_STAILQ_INSERT_TAIL( &be->be_syncinfo, si, si_next );
+ return 0;
+ }
+}
+
+#define IDSTR "rid"
+#define PROVIDERSTR "provider"
+#define SUFFIXSTR "suffix"
+#define UPDATEDNSTR "updatedn"
+#define BINDMETHSTR "bindmethod"
+#define SIMPLESTR "simple"
+#define SASLSTR "sasl"
+#define BINDDNSTR "binddn"
+#define CREDSTR "credentials"
+#define OLDAUTHCSTR "bindprincipal"
+#define AUTHCSTR "authcID"
+#define AUTHZSTR "authzID"
+#define SRVTABSTR "srvtab"
+#define SASLMECHSTR "saslmech"
+#define REALMSTR "realm"
+#define SECPROPSSTR "secprops"
+#define STARTTLSSTR "starttls"
+#define CRITICALSTR "critical"
+
+#define SCHEMASTR "schemachecking"
+#define FILTERSTR "filter"
+#define SEARCHBASESTR "searchbase"
+#define SCOPESTR "scope"
+#define ATTRSSTR "attrs"
+#define ATTRSONLYSTR "attrsonly"
+#define TYPESTR "type"
+#define INTERVALSTR "interval"
+#define LASTMODSTR "lastmod"
+#define LMREQSTR "req"
+#define LMGENSTR "gen"
+#define LMNOSTR "no"
+#define MANAGEDSAITSTR "manageDSAit"
+#define SLIMITSTR "sizelimit"
+#define TLIMITSTR "timelimit"
+
+#define GOT_ID 0x0001
+#define GOT_PROVIDER 0x0002
+#define GOT_METHOD 0x0004
+#define GOT_ALL 0x0007
+
+static int
+parse_syncrepl_line(
+ char **cargv,
+ int cargc,
+ syncinfo_t *si
+)
+{
+ int gots = 0;
+ int i, j;
+ char *hp, *val;
+ int nr_attr = 0;
+
+ for ( i = 1; i < cargc; i++ ) {
+ if ( !strncasecmp( cargv[ i ], IDSTR, sizeof( IDSTR ) - 1 )) {
+ int tmp;
+ /* '\0' string terminator accounts for '=' */
+ val = cargv[ i ] + sizeof( IDSTR );
+ tmp= atoi( val );
+ if ( tmp >= 1000 || tmp < 0 ) {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "syncrepl id %d is out of range [0..999]\n", tmp );
+ return -1;
+ }
+ si->si_rid = tmp;
+ gots |= GOT_ID;
+ } else if ( !strncasecmp( cargv[ i ], PROVIDERSTR,
+ sizeof( PROVIDERSTR ) - 1 )) {
+ val = cargv[ i ] + sizeof( PROVIDERSTR );
+ si->si_provideruri = ch_strdup( val );
+ si->si_provideruri_bv = (BerVarray)
+ ch_calloc( 2, sizeof( struct berval ));
+ ber_str2bv( si->si_provideruri, strlen( si->si_provideruri ),
+ 0, &si->si_provideruri_bv[0] );
+ si->si_provideruri_bv[1].bv_len = 0;
+ si->si_provideruri_bv[1].bv_val = NULL;
+ gots |= GOT_PROVIDER;
+ } else if ( !strncasecmp( cargv[ i ], STARTTLSSTR,
+ sizeof(STARTTLSSTR) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( STARTTLSSTR );
+ if( !strcasecmp( val, CRITICALSTR ) ) {
+ si->si_tls = SYNCINFO_TLS_CRITICAL;
+ } else {
+ si->si_tls = SYNCINFO_TLS_ON;
+ }
+ } else if ( !strncasecmp( cargv[ i ],
+ UPDATEDNSTR, sizeof( UPDATEDNSTR ) - 1 ) )
+ {
+ struct berval updatedn = {0, NULL};
+ val = cargv[ i ] + sizeof( UPDATEDNSTR );
+ ber_str2bv( val, 0, 0, &updatedn );
+ ch_free( si->si_updatedn.bv_val );
+ dnNormalize( 0, NULL, NULL, &updatedn, &si->si_updatedn, NULL );
+ } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
+ sizeof( BINDMETHSTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( BINDMETHSTR );
+ if ( !strcasecmp( val, SIMPLESTR )) {
+ si->si_bindmethod = LDAP_AUTH_SIMPLE;
+ gots |= GOT_METHOD;
+ } else if ( !strcasecmp( val, SASLSTR )) {
+#ifdef HAVE_CYRUS_SASL
+ si->si_bindmethod = LDAP_AUTH_SASL;
+ gots |= GOT_METHOD;
+#else /* HAVE_CYRUS_SASL */
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "not compiled with SASL support\n" );
+ return 1;
+#endif /* HAVE_CYRUS_SASL */
+ } else {
+ si->si_bindmethod = -1;
+ }
+ } else if ( !strncasecmp( cargv[ i ],
+ BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( BINDDNSTR );
+ si->si_binddn = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( CREDSTR );
+ si->si_passwd = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( SASLMECHSTR );
+ si->si_saslmech = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( SECPROPSSTR );
+ si->si_secprops = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( REALMSTR );
+ si->si_realm = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( AUTHCSTR );
+ si->si_authcId = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
+ /* Old authcID is provided for some backwards compatibility */
+ val = cargv[ i ] + sizeof( OLDAUTHCSTR );
+ si->si_authcId = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( AUTHZSTR );
+ si->si_authzId = ch_strdup( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ SCHEMASTR, sizeof( SCHEMASTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( SCHEMASTR );
+ if ( !strncasecmp( val, "on", sizeof( "on" ) - 1 )) {
+ si->si_schemachecking = 1;
+ } else if ( !strncasecmp( val, "off", sizeof( "off" ) - 1 ) ) {
+ si->si_schemachecking = 0;
+ } else {
+ si->si_schemachecking = 1;
+ }
+ } else if ( !strncasecmp( cargv[ i ],
+ FILTERSTR, sizeof( FILTERSTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( FILTERSTR );
+ ber_str2bv( val, 0, 1, &si->si_filterstr );
+ } else if ( !strncasecmp( cargv[ i ],
+ SEARCHBASESTR, sizeof( SEARCHBASESTR ) - 1 ) )
+ {
+ struct berval bv;
+ val = cargv[ i ] + sizeof( SEARCHBASESTR );
+ if ( si->si_base.bv_val ) {
+ ch_free( si->si_base.bv_val );
+ }
+ ber_str2bv( val, 0, 0, &bv );
+ if ( dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL )) {
+ fprintf( stderr, "Invalid base DN \"%s\"\n", val );
+ return 1;
+ }
+ } else if ( !strncasecmp( cargv[ i ],
+ SCOPESTR, sizeof( SCOPESTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( SCOPESTR );
+ if ( !strncasecmp( val, "base", sizeof( "base" ) - 1 )) {
+ si->si_scope = LDAP_SCOPE_BASE;
+ } else if ( !strncasecmp( val, "one", sizeof( "one" ) - 1 )) {
+ si->si_scope = LDAP_SCOPE_ONELEVEL;
+ } else if ( !strncasecmp( val, "sub", sizeof( "sub" ) - 1 )) {
+ si->si_scope = LDAP_SCOPE_SUBTREE;
+ } else {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "unknown scope \"%s\"\n", val);
+ return 1;
+ }
+ } else if ( !strncasecmp( cargv[ i ],
+ ATTRSONLYSTR, sizeof( ATTRSONLYSTR ) - 1 ) )
+ {
+ si->si_attrsonly = 1;
+ } else if ( !strncasecmp( cargv[ i ],
+ ATTRSSTR, sizeof( ATTRSSTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( ATTRSSTR );
+ str2clist( &si->si_attrs, val, "," );
+ } else if ( !strncasecmp( cargv[ i ],
+ TYPESTR, sizeof( TYPESTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( TYPESTR );
+ if ( !strncasecmp( val, "refreshOnly", sizeof("refreshOnly")-1 )) {
+ si->si_type = LDAP_SYNC_REFRESH_ONLY;
+ } else if ( !strncasecmp( val, "refreshAndPersist",
+ sizeof("refreshAndPersist")-1 ))
+ {
+ si->si_type = LDAP_SYNC_REFRESH_AND_PERSIST;
+ si->si_interval = 60;
+ } else {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "unknown sync type \"%s\"\n", val);
+ return 1;
+ }
+ } else if ( !strncasecmp( cargv[ i ],
+ INTERVALSTR, sizeof( INTERVALSTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( INTERVALSTR );
+ if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+ si->si_interval = 0;
+ } else {
+ char *hstr;
+ char *mstr;
+ char *dstr;
+ char *sstr;
+ int dd, hh, mm, ss;
+ dstr = val;
+ hstr = strchr( dstr, ':' );
+ if ( hstr == NULL ) {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\"\n", val );
+ return 1;
+ }
+ *hstr++ = '\0';
+ mstr = strchr( hstr, ':' );
+ if ( mstr == NULL ) {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\"\n", val );
+ return 1;
+ }
+ *mstr++ = '\0';
+ sstr = strchr( mstr, ':' );
+ if ( sstr == NULL ) {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\"\n", val );
+ return 1;
+ }
+ *sstr++ = '\0';
+
+ dd = atoi( dstr );
+ hh = atoi( hstr );
+ mm = atoi( mstr );
+ ss = atoi( sstr );
+ if (( hh > 24 ) || ( hh < 0 ) ||
+ ( mm > 60 ) || ( mm < 0 ) ||
+ ( ss > 60 ) || ( ss < 0 ) || ( dd < 0 )) {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "invalid interval \"%s\"\n", val );
+ return 1;
+ }
+ si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
+ }
+ if ( si->si_interval < 0 ) {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "invalid interval \"%ld\"\n",
+ (long) si->si_interval);
+ return 1;
+ }
+ } else if ( !strncasecmp( cargv[ i ],
+ MANAGEDSAITSTR, sizeof( MANAGEDSAITSTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( MANAGEDSAITSTR );
+ si->si_manageDSAit = atoi( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ SLIMITSTR, sizeof( SLIMITSTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( SLIMITSTR );
+ si->si_slimit = atoi( val );
+ } else if ( !strncasecmp( cargv[ i ],
+ TLIMITSTR, sizeof( TLIMITSTR ) - 1 ) )
+ {
+ val = cargv[ i ] + sizeof( TLIMITSTR );
+ si->si_tlimit = atoi( val );
+ } else {
+ fprintf( stderr, "Error: parse_syncrepl_line: "
+ "unknown keyword \"%s\"\n", cargv[ i ] );
+ }
+ }
+
+ if ( gots != GOT_ALL ) {
+ fprintf( stderr,
+ "Error: Malformed \"syncrepl\" line in slapd config file" );
+ return -1;
+ }
+
+ return 0;
+}
+
+char **
+str2clist( char ***out, char *in, const char *brkstr )
+{
+ char *str;
+ char *s;
+ char *lasts;
+ int i, j;
+ const char *text;
+ char **new;
+
+ /* find last element in list */
+ for (i = 0; *out && *out[i]; i++);
+
+ /* protect the input string from strtok */
+ str = ch_strdup( in );
+
+ if ( *str == '\0' ) {
+ free( str );
+ return( *out );
+ }
+
+ /* Count words in string */
+ j=1;
+ for ( s = str; *s; s++ ) {
+ if ( strchr( brkstr, *s ) != NULL ) {
+ j++;
+ }
+ }
+
+ *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
+ new = *out + i;
+ for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
+ s != NULL;
+ s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
+ {
+ *new = ch_strdup( s );
+ new++;
+ }
+
+ *new = NULL;
+ free( str );
+ return( *out );
+}