+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 0:
+ mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
+ break;
+
+ case 1:
+ mi->mi_flags |= META_BACK_F_DEFER_ROOTDN_BIND;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"[pseudo]root-bind-defer {TRUE|false}\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ /* single-conn? */
+ } else if ( strcasecmp( argv[ 0 ], "single-conn" ) == 0 ) {
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"single-conn {FALSE|true}\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( mi->mi_ntargets > 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"single-conn\" must appear before target definitions\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 0:
+ mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN;
+ break;
+
+ case 1:
+ mi->mi_flags |= LDAP_BACK_F_SINGLECONN;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"single-conn {FALSE|true}\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ /* use-temporaries? */
+ } else if ( strcasecmp( argv[ 0 ], "use-temporary-conn" ) == 0 ) {
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"use-temporary-conn {FALSE|true}\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( mi->mi_ntargets > 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"use-temporary-conn\" must appear before target definitions\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 0:
+ mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
+ break;
+
+ case 1:
+ mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"use-temporary-conn {FALSE|true}\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ /* privileged connections pool max size ? */
+ } else if ( strcasecmp( argv[ 0 ], "conn-pool-max" ) == 0 ) {
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max <n>\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( mi->mi_ntargets > 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max\" must appear before target definitions\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( lutil_atoi( &mi->mi_conn_priv_max, argv[1] )
+ || mi->mi_conn_priv_max < LDAP_BACK_CONN_PRIV_MIN
+ || mi->mi_conn_priv_max > LDAP_BACK_CONN_PRIV_MAX )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max <n>\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ } else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) {
+ unsigned flag = 0;
+ unsigned *flagsp = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
+ : &mi->mi_flags;
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"cancel {abandon|ignore|exop}\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( strcasecmp( argv[ 1 ], "abandon" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_ABANDON;
+
+ } else if ( strcasecmp( argv[ 1 ], "ignore" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_IGNORE;
+
+ } else if ( strcasecmp( argv[ 1 ], "exop" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_EXOP;
+
+ } else if ( strcasecmp( argv[ 1 ], "exop-discover" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_EXOP_DISCOVER;
+
+ } else {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"cancel {abandon|ignore|exop[-discover]}\": unknown mode \"%s\" \n",
+ fname, lineno, argv[ 1 ] );
+ return( 1 );
+ }
+
+ *flagsp &= ~LDAP_BACK_F_CANCEL_MASK2;
+ *flagsp |= flag;
+
+ } else if ( strcasecmp( argv[ 0 ], "timeout" ) == 0 ) {
+ char *sep;
+ time_t *tv = mi->mi_ntargets ?
+ mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_timeout
+ : mi->mi_timeout;
+ int c;
+
+ if ( argc < 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"timeout [{add|bind|delete|modify|modrdn}=]<val> [...]\" takes at least 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ for ( c = 1; c < argc; c++ ) {
+ time_t *t = NULL;
+ unsigned long val;
+
+ sep = strchr( argv[ c ], '=' );
+ if ( sep != NULL ) {
+ size_t len = sep - argv[ c ];
+
+ if ( strncasecmp( argv[ c ], "bind", len ) == 0 ) {
+ t = &tv[ SLAP_OP_BIND ];
+ /* unbind makes little sense */
+ } else if ( strncasecmp( argv[ c ], "add", len ) == 0 ) {
+ t = &tv[ SLAP_OP_ADD ];
+ } else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) {
+ t = &tv[ SLAP_OP_DELETE ];
+ } else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) {
+ t = &tv[ SLAP_OP_MODRDN ];
+ } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) {
+ t = &tv[ SLAP_OP_MODIFY ];
+ } else if ( strncasecmp( argv[ c ], "compare", len ) == 0 ) {
+ t = &tv[ SLAP_OP_COMPARE ];
+ } else if ( strncasecmp( argv[ c ], "search", len ) == 0 ) {
+ t = &tv[ SLAP_OP_SEARCH ];
+ /* abandon makes little sense */
+#if 0 /* not implemented yet */
+ } else if ( strncasecmp( argv[ c ], "extended", len ) == 0 ) {
+ t = &tv[ SLAP_OP_EXTENDED ];
+#endif
+ } else {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ snprintf( buf, sizeof( buf ),
+ "unknown/unhandled operation \"%s\" for timeout #%d",
+ argv[ c ], c - 1 );
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: %s.\n",
+ fname, lineno, buf );
+ return 1;
+ }
+ sep++;
+
+ } else {
+ sep = argv[ c ];
+ }
+
+ if ( lutil_parse_time( sep, &val ) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: unable to parse value \"%s\" for timeout.\n",
+ fname, lineno, sep );
+ return 1;
+ }
+
+ if ( t ) {
+ *t = (time_t)val;
+
+ } else {
+ int i;
+
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
+ tv[ i ] = (time_t)val;
+ }
+ }
+ }
+
+ /* name to use as pseudo-root dn */
+ } else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) {
+ int i = mi->mi_ntargets - 1;
+
+ if ( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing name in \"pseudorootdn <name>\" line\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ /*
+ * exact replacement:
+ *
+
+idassert-bind bindmethod=simple
+ binddn=<pseudorootdn>
+ credentials=<pseudorootpw>
+ mode=none
+ flags=non-prescriptive
+idassert-authzFrom "dn:<rootdn>"
+
+ * so that only when authc'd as <rootdn> the proxying occurs
+ * rebinding as the <pseudorootdn> without proxyAuthz.
+ */
+
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
+ "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
+ fname, lineno, 0 );
+
+ {
+ char binddn[ SLAP_TEXT_BUFLEN ];
+ char *cargv[] = {
+ "idassert-bind",
+ "bindmethod=simple",
+ NULL,
+ "mode=none",
+ "flags=non-prescriptive",
+ NULL
+ };
+ int cargc = 5;
+ int rc;
+
+ if ( BER_BVISNULL( &be->be_rootndn ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"rootdn\" must be defined first.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( sizeof( binddn ) <= (unsigned) snprintf( binddn,
+ sizeof( binddn ), "binddn=%s", argv[ 1 ] ))
+ {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootdn\" too long.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+ cargv[ 2 ] = binddn;
+
+ rc = mi->mi_ldap_extra->idassert_parse_cf( fname, lineno, cargc, cargv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
+ if ( rc == 0 ) {
+ struct berval bv;
+
+ if ( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz != NULL ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"idassert-authzFrom\" already defined (discarded).\n",
+ fname, lineno, 0 );
+ ber_bvarray_free( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz );
+ mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz = NULL;
+ }
+
+ assert( !BER_BVISNULL( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authcDN ) );
+
+ bv.bv_len = STRLENOF( "dn:" ) + be->be_rootndn.bv_len;
+ bv.bv_val = ber_memalloc( bv.bv_len + 1 );
+ AC_MEMCPY( bv.bv_val, "dn:", STRLENOF( "dn:" ) );
+ AC_MEMCPY( &bv.bv_val[ STRLENOF( "dn:" ) ], be->be_rootndn.bv_val, be->be_rootndn.bv_len + 1 );
+
+ ber_bvarray_add( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz, &bv );
+ }
+
+ return rc;
+ }
+
+ /* password to use as pseudo-root */
+ } else if ( strcasecmp( argv[ 0 ], "pseudorootpw" ) == 0 ) {
+ int i = mi->mi_ntargets - 1;
+
+ if ( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing password in \"pseudorootpw <password>\" line\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
+ "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
+ fname, lineno, 0 );
+
+ if ( BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_authcDN ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"pseudorootdn\" must be defined first.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( !BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_passwd ) ) {
+ memset( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val, 0,
+ mi->mi_targets[ i ]->mt_idassert_passwd.bv_len );
+ ber_memfree( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val );
+ }
+ ber_str2bv( argv[ 1 ], 0, 1, &mi->mi_targets[ i ]->mt_idassert_passwd );
+
+ /* idassert-bind */
+ } else if ( strcasecmp( argv[ 0 ], "idassert-bind" ) == 0 ) {
+ if ( mi->mi_ntargets == 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"idassert-bind\" "
+ "must appear inside a target specification.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ return mi->mi_ldap_extra->idassert_parse_cf( fname, lineno, argc, argv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
+
+ /* idassert-authzFrom */
+ } else if ( strcasecmp( argv[ 0 ], "idassert-authzFrom" ) == 0 ) {
+ if ( mi->mi_ntargets == 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"idassert-bind\" "
+ "must appear inside a target specification.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ switch ( argc ) {
+ case 2:
+ break;
+
+ case 1:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing <id> in \"idassert-authzFrom <id>\".\n",
+ fname, lineno, 0 );
+ return 1;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: extra cruft after <id> in \"idassert-authzFrom <id>\".\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ return mi->mi_ldap_extra->idassert_authzfrom_parse_cf( fname, lineno, argv[ 1 ], &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
+
+ /* quarantine */
+ } else if ( strcasecmp( argv[ 0 ], "quarantine" ) == 0 ) {
+ char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
+ slap_retry_info_t *ri = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine
+ : &mi->mi_quarantine;
+
+ if ( ( mi->mi_ntargets == 0 && META_BACK_QUARANTINE( mi ) )
+ || ( mi->mi_ntargets > 0 && META_BACK_TGT_QUARANTINE( mi->mi_targets[ mi->mi_ntargets - 1 ] ) ) )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: quarantine already defined.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ switch ( argc ) {
+ case 2:
+ break;
+
+ case 1:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing arg in \"quarantine <pattern list>\".\n",
+ fname, lineno, 0 );
+ return 1;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: extra cruft after \"quarantine <pattern list>\".\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( ri != &mi->mi_quarantine ) {
+ ri->ri_interval = NULL;
+ ri->ri_num = NULL;
+ }
+
+ if ( mi->mi_ntargets > 0 && !META_BACK_QUARANTINE( mi ) ) {
+ ldap_pvt_thread_mutex_init( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine_mutex );
+ }
+
+ if ( mi->mi_ldap_extra->retry_info_parse( argv[ 1 ], ri, buf, sizeof( buf ) ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s line %d: %s.\n",
+ fname, lineno, buf );
+ return 1;
+ }
+
+ if ( mi->mi_ntargets == 0 ) {
+ mi->mi_flags |= LDAP_BACK_F_QUARANTINE;
+
+ } else {
+ mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags |= LDAP_BACK_F_QUARANTINE;
+ }
+
+#ifdef SLAP_CONTROL_X_SESSION_TRACKING
+ /* session tracking request */
+ } else if ( strcasecmp( argv[ 0 ], "session-tracking-request" ) == 0 ) {
+ unsigned *flagsp = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
+ : &mi->mi_flags;
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"session-tracking-request {TRUE|false}\" needs 1 argument.\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ /* this is the default; we add it because the default might change... */
+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 1:
+ *flagsp |= LDAP_BACK_F_ST_REQUEST;
+ break;
+
+ case 0:
+ *flagsp &= ~LDAP_BACK_F_ST_REQUEST;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"session-tracking-request {TRUE|false}\": unknown argument \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return( 1 );
+ }
+#endif /* SLAP_CONTROL_X_SESSION_TRACKING */
+
+ /* dn massaging */
+ } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) {
+ BackendDB *tmp_bd;
+ int i = mi->mi_ntargets - 1, c, rc;
+ struct berval dn, nvnc, pvnc, nrnc, prnc;
+
+ if ( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ /*
+ * syntax:
+ *
+ * suffixmassage <suffix> <massaged suffix>
+ *
+ * the <suffix> field must be defined as a valid suffix
+ * (or suffixAlias?) for the current database;
+ * the <massaged suffix> shouldn't have already been
+ * defined as a valid suffix or suffixAlias for the
+ * current server
+ */
+ if ( argc != 3 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ ber_str2bv( argv[ 1 ], 0, 0, &dn );
+ if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+ "suffix \"%s\" is invalid\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ for ( c = 0; !BER_BVISNULL( &be->be_nsuffix[ c ] ); c++ ) {
+ if ( dnIsSuffix( &nvnc, &be->be_nsuffix[ 0 ] ) ) {
+ break;
+ }
+ }
+
+ if ( BER_BVISNULL( &be->be_nsuffix[ c ] ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+ "<suffix> \"%s\" must be within the database naming context, in "
+ "\"suffixMassage <suffix> <massaged suffix>\"\n",
+ fname, lineno, pvnc.bv_val );
+ free( pvnc.bv_val );
+ free( nvnc.bv_val );
+ return 1;
+ }
+
+ ber_str2bv( argv[ 2 ], 0, 0, &dn );
+ if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+ "massaged suffix \"%s\" is invalid\n",
+ fname, lineno, argv[ 2 ] );
+ free( pvnc.bv_val );
+ free( nvnc.bv_val );
+ return 1;
+ }
+
+ tmp_bd = select_backend( &nrnc, 0 );
+ if ( tmp_bd != NULL && tmp_bd->be_private == be->be_private ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: warning: <massaged suffix> \"%s\" resolves to this database, in "
+ "\"suffixMassage <suffix> <massaged suffix>\"\n",
+ fname, lineno, prnc.bv_val );
+ }
+
+ /*
+ * The suffix massaging is emulated by means of the
+ * rewrite capabilities
+ */
+ rc = suffix_massage_config( mi->mi_targets[ i ]->mt_rwmap.rwm_rw,
+ &pvnc, &nvnc, &prnc, &nrnc );
+
+ free( pvnc.bv_val );
+ free( nvnc.bv_val );
+ free( prnc.bv_val );
+ free( nrnc.bv_val );
+
+ return rc;
+
+ /* rewrite stuff ... */
+ } else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) {
+ int i = mi->mi_ntargets - 1;
+
+ if ( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"rewrite\" "
+ "statement outside target definition.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ return rewrite_parse( mi->mi_targets[ i ]->mt_rwmap.rwm_rw,
+ fname, lineno, argc, argv );
+
+ /* objectclass/attribute mapping */
+ } else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) {
+ int i = mi->mi_ntargets - 1;
+
+ if ( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ return ldap_back_map_config( &mi->mi_targets[ i ]->mt_rwmap.rwm_oc,
+ &mi->mi_targets[ i ]->mt_rwmap.rwm_at,
+ fname, lineno, argc, argv );
+
+ } else if ( strcasecmp( argv[ 0 ], "nretries" ) == 0 ) {
+ int i = mi->mi_ntargets - 1;
+ int nretries = META_RETRY_UNDEFINED;
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: need value in \"nretries <value>\"\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
+ nretries = META_RETRY_FOREVER;
+
+ } else if ( strcasecmp( argv[ 1 ], "never" ) == 0 ) {
+ nretries = META_RETRY_NEVER;
+
+ } else {
+ if ( lutil_atoi( &nretries, argv[ 1 ] ) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: unable to parse value \"%s\" in \"nretries <value>\"\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+ }
+
+ if ( i < 0 ) {
+ mi->mi_nretries = nretries;
+
+ } else {
+ mi->mi_targets[ i ]->mt_nretries = nretries;
+ }
+
+ } else if ( strcasecmp( argv[ 0 ], "protocol-version" ) == 0 ) {
+ int *version = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_version
+ : &mi->mi_version;
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: need value in \"protocol-version <version>\"\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( lutil_atoi( version, argv[ 1 ] ) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: unable to parse version \"%s\" in \"protocol-version <version>\"\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ if ( *version != 0 && ( *version < LDAP_VERSION_MIN || *version > LDAP_VERSION_MAX ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: unsupported version \"%s\" in \"protocol-version <version>\"\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ /* do not return search references */
+ } else if ( strcasecmp( argv[ 0 ], "norefs" ) == 0 ) {
+ unsigned *flagsp = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
+ : &mi->mi_flags;
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"norefs {TRUE|false}\" needs 1 argument.\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ /* this is the default; we add it because the default might change... */
+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 1:
+ *flagsp |= LDAP_BACK_F_NOREFS;
+ break;
+
+ case 0:
+ *flagsp &= ~LDAP_BACK_F_NOREFS;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"norefs {TRUE|false}\": unknown argument \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return( 1 );
+ }
+
+ /* do not propagate undefined search filters */
+ } else if ( strcasecmp( argv[ 0 ], "noundeffilter" ) == 0 ) {
+ unsigned *flagsp = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
+ : &mi->mi_flags;
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"noundeffilter {TRUE|false}\" needs 1 argument.\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ /* this is the default; we add it because the default might change... */
+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 1:
+ *flagsp |= LDAP_BACK_F_NOUNDEFFILTER;
+ break;
+
+ case 0:
+ *flagsp &= ~LDAP_BACK_F_NOUNDEFFILTER;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"noundeffilter {TRUE|false}\": unknown argument \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return( 1 );
+ }