+int
+slap_retry_info_parse(
+ char *in,
+ slap_retry_info_t *ri,
+ char *buf,
+ ber_len_t buflen )
+{
+ char **retrylist = NULL;
+ int rc = 0;
+ int i;
+
+ slap_str2clist( &retrylist, in, " ;" );
+ if ( retrylist == NULL ) {
+ return 1;
+ }
+
+ for ( i = 0; retrylist[ i ] != NULL; i++ )
+ /* count */ ;
+
+ ri->ri_interval = ch_calloc( sizeof( time_t ), i + 1 );
+ ri->ri_num = ch_calloc( sizeof( int ), i + 1 );
+
+ for ( i = 0; retrylist[ i ] != NULL; i++ ) {
+ unsigned long t;
+ char *sep = strchr( retrylist[ i ], ',' );
+
+ if ( sep == NULL ) {
+ snprintf( buf, buflen,
+ "missing comma in retry pattern #%d \"%s\"",
+ i, retrylist[ i ] );
+ rc = 1;
+ goto done;
+ }
+
+ *sep++ = '\0';
+
+ if ( lutil_parse_time( retrylist[ i ], &t ) ) {
+ snprintf( buf, buflen,
+ "unable to parse interval #%d \"%s\"",
+ i, retrylist[ i ] );
+ rc = 1;
+ goto done;
+ }
+ ri->ri_interval[ i ] = (time_t)t;
+
+ if ( strcmp( sep, "+" ) == 0 ) {
+ if ( retrylist[ i + 1 ] != NULL ) {
+ snprintf( buf, buflen,
+ "extra cruft after retry pattern "
+ "#%d \"%s,+\" with \"forever\" mark",
+ i, retrylist[ i ] );
+ rc = 1;
+ goto done;
+ }
+ ri->ri_num[ i ] = SLAP_RETRYNUM_FOREVER;
+
+ } else if ( lutil_atoi( &ri->ri_num[ i ], sep ) ) {
+ snprintf( buf, buflen,
+ "unable to parse retry num #%d \"%s\"",
+ i, sep );
+ rc = 1;
+ goto done;
+ }
+ }
+
+ ri->ri_num[ i ] = SLAP_RETRYNUM_TAIL;
+
+ ri->ri_idx = 0;
+ ri->ri_count = 0;
+ ri->ri_last = (time_t)(-1);
+
+done:;
+ ldap_charray_free( retrylist );
+
+ if ( rc ) {
+ slap_retry_info_destroy( ri );
+ }
+
+ return rc;
+}
+
+int
+slap_retry_info_unparse(
+ slap_retry_info_t *ri,
+ struct berval *bvout )
+{
+ int i;
+ char buf[ BUFSIZ * 2 ],
+ *ptr = buf;
+ struct berval bv = BER_BVNULL;
+
+ assert( ri != NULL );
+ assert( bvout != NULL );
+
+ BER_BVZERO( bvout );
+
+#define WHATSLEFT ( sizeof( buf ) - ( ptr - buf ) )
+
+ for ( i = 0; ri->ri_num[ i ] != SLAP_RETRYNUM_TAIL; i++ ) {
+ if ( i > 0 ) {
+ if ( WHATSLEFT <= 1 ) {
+ return 1;
+ }
+ *ptr++ = ';';
+ }
+
+ if ( lutil_unparse_time( ptr, WHATSLEFT, (long)ri->ri_interval[i] ) ) {
+ return 1;
+ }
+ ptr += strlen( ptr );
+
+ if ( WHATSLEFT <= 1 ) {
+ return 1;
+ }
+ *ptr++ = ',';
+
+ if ( ri->ri_num[i] == SLAP_RETRYNUM_FOREVER ) {
+ if ( WHATSLEFT <= 1 ) {
+ return 1;
+ }
+ *ptr++ = '+';
+
+ } else {
+ ptr += snprintf( ptr, WHATSLEFT, "%d", ri->ri_num[i] );
+ if ( WHATSLEFT <= 0 ) {
+ return 1;
+ }
+ }
+ }
+
+ bv.bv_val = buf;
+ bv.bv_len = ptr - buf;
+
+ ber_dupbv( bvout, &bv );
+
+ return 0;
+}
+
+void
+slap_retry_info_destroy(
+ slap_retry_info_t *ri )
+{
+ assert( ri != NULL );
+
+ assert( ri->ri_interval != NULL );
+ ch_free( ri->ri_interval );
+ ri->ri_interval = NULL;
+
+ assert( ri->ri_num != NULL );
+ ch_free( ri->ri_num );
+ ri->ri_num = NULL;
+}
+
+static int
+slap_idassert_authzfrom_parse( ConfigArgs *c, slap_idassert_t *si )
+{
+ struct berval bv;
+ struct berval in;
+ int rc;
+
+ if ( strcmp( c->argv[ 1 ], "*" ) == 0
+ || strcmp( c->argv[ 1 ], "dn:*" ) == 0
+ || strcasecmp( c->argv[ 1 ], "dn.regex:.*" ) == 0 )
+ {
+ if ( si->si_authz != NULL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-authzFrom <authz>\": "
+ "\"%s\" conflicts with existing authz rules",
+ c->argv[ 1 ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ si->si_flags |= LDAP_BACK_AUTH_AUTHZ_ALL;
+
+ return 0;
+
+ } else if ( ( si->si_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-authzFrom <authz>\": "
+ "\"<authz>\" conflicts with \"*\"" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ ber_str2bv( c->argv[ 1 ], 0, 0, &in );
+ rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-authzFrom <authz>\": "
+ "invalid syntax" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ ber_bvarray_add( &si->si_authz, &bv );
+
+ return 0;
+}
+
+static int
+slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si )
+{
+ int i;
+
+ for ( i = 1; i < c->argc; i++ ) {
+ if ( strncasecmp( c->argv[ i ], "mode=", STRLENOF( "mode=" ) ) == 0 ) {
+ char *argvi = c->argv[ i ] + STRLENOF( "mode=" );
+ int j;
+
+ j = verb_to_mask( argvi, idassert_mode );
+ if ( BER_BVISNULL( &idassert_mode[ j ].word ) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unknown mode \"%s\"",
+ argvi );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ si->si_mode = idassert_mode[ j ].mask;
+
+ } else if ( strncasecmp( c->argv[ i ], "authz=", STRLENOF( "authz=" ) ) == 0 ) {
+ char *argvi = c->argv[ i ] + STRLENOF( "authz=" );
+
+ if ( strcasecmp( argvi, "native" ) == 0 ) {
+ if ( si->si_bc.sb_method != LDAP_AUTH_SASL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "authz=\"native\" incompatible "
+ "with auth method" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ si->si_flags |= LDAP_BACK_AUTH_NATIVE_AUTHZ;
+
+ } else if ( strcasecmp( argvi, "proxyAuthz" ) == 0 ) {
+ si->si_flags &= ~LDAP_BACK_AUTH_NATIVE_AUTHZ;
+
+ } else {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unknown authz \"%s\"",
+ argvi );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ } else if ( strncasecmp( c->argv[ i ], "flags=", STRLENOF( "flags=" ) ) == 0 ) {
+ char *argvi = c->argv[ i ] + STRLENOF( "flags=" );
+ char **flags = ldap_str2charray( argvi, "," );
+ int j, err = 0;
+
+ if ( flags == NULL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unable to parse flags \"%s\"",
+ argvi );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ for ( j = 0; flags[ j ] != NULL; j++ ) {
+
+ if ( strcasecmp( flags[ j ], "override" ) == 0 ) {
+ si->si_flags |= LDAP_BACK_AUTH_OVERRIDE;
+
+ } else if ( strcasecmp( flags[ j ], "prescriptive" ) == 0 ) {
+ si->si_flags |= LDAP_BACK_AUTH_PRESCRIPTIVE;
+
+ } else if ( strcasecmp( flags[ j ], "non-prescriptive" ) == 0 ) {
+ si->si_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
+
+ } else if ( strcasecmp( flags[ j ], "obsolete-proxy-authz" ) == 0 ) {
+ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: \"obsolete-proxy-authz\" flag "
+ "in \"idassert-mode <args>\" "
+ "incompatible with previously issued \"obsolete-encoding-workaround\" flag.\n",
+ c->log, 0, 0 );
+ err = 1;
+ break;
+
+ } else {
+ si->si_flags |= LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ;
+ }
+
+ } else if ( strcasecmp( flags[ j ], "obsolete-encoding-workaround" ) == 0 ) {
+ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: \"obsolete-encoding-workaround\" flag "
+ "in \"idassert-mode <args>\" "
+ "incompatible with previously issued \"obsolete-proxy-authz\" flag.\n",
+ c->log, 0, 0 );
+ err = 1;
+ break;
+
+ } else {
+ si->si_flags |= LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND;
+ }
+
+ } else {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unknown flag \"%s\"",
+ flags[ j ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ err = 1;
+ break;
+ }
+ }
+
+ ldap_charray_free( flags );
+ if ( err ) {
+ return 1;
+ }
+
+ } else if ( bindconf_parse( c->argv[ i ], &si->si_bc ) ) {
+ return 1;
+ }
+ }
+ bindconf_tls_defaults( &si->si_bc );
+
+ return 0;
+}
+
+/* NOTE: temporary, until back-meta is ported to back-config */
+int
+slap_idassert_authzfrom_parse_cf( const char *fname, int lineno, const char *arg, slap_idassert_t *si )
+{
+ ConfigArgs c = { 0 };
+ char *argv[ 3 ];
+
+ snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
+ c.argc = 2;
+ c.argv = argv;
+ argv[ 0 ] = "idassert-authzFrom";
+ argv[ 1 ] = (char *)arg;
+ argv[ 2 ] = NULL;
+
+ return slap_idassert_authzfrom_parse( &c, si );
+}
+
+int
+slap_idassert_parse_cf( const char *fname, int lineno, int argc, char *argv[], slap_idassert_t *si )
+{
+ ConfigArgs c = { 0 };
+
+ snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
+ c.argc = argc;
+ c.argv = argv;
+
+ return slap_idassert_parse( &c, si );
+}
+