.fi
.RE
.LP
-for every
+for
.B ldap
and
.B meta
-database.
-This is because operational attributes related to entry creation and
-modification should not be proxied, as they could be mistakenly written
+databases.
+This was required because operational attributes related to entry creation
+and modification should not be proxied, as they could be mistakenly written
to the target server(s), generating an error.
-The current implementation automatically sets lastmod to off, so its use
-is redundant and should be omitted, because the lastmod directive will
-be deprecated in the future.
+The current implementation automatically sets lastmod to \fBoff\fP,
+so its use is redundant and should be omitted.
.TP
.B uri <ldapurl>
-LDAP server to use. Multiple URIs can be set in in a single
+LDAP server to use. Multiple URIs can be set in a single
.B ldapurl
argument, resulting in the underlying library automatically
call the first server of the list that responds, e.g.
\fBuri "ldap://host/ ldap://backup-host/"\fP
The URI list is space- or comma-separated.
-.\"This statement is mandatory.
-.\".TP
-.\".B server <hostport>
-.\"Obsolete option; same as `uri ldap://<hostport>/'.
+Whenever the server that responds is not the first one in the list,
+the list is rearranged and the responsive server is moved to the head,
+so that it will be first contacted the next time a connection
+needs be created.
.HP
.hy 0
.B acl-bind
parameters).
Otherwise, the default
.B proxyauthz
-is used, i.e. the proxyAuthz control is added to all operations.
+is used, i.e. the proxyAuthz control (Proxied Authorization, RFC 4370)
+is added to all operations.
The supported modes are:
Flags can be
-\fBoverride,{prescriptive|non-prescriptive}\fP
+\fBoverride,[non-]prescriptive\fP
When the
.B override
support is detected by reading the remote server's root DSE.
.TP
-.B timeout [{add|delete|modify|modrdn}=]<val> [...]
+.B timeout [<op>=]<val> [...]
This directive allows to set per-operation timeouts.
-If no operation is specified, it affects all.
-Currently, only write operations are addressed, because searches
-can already be limited by means of the
-.B limits
-directive (see
+Operations can be
+
+\fB<op> ::= bind, add, delete, modrdn, modify, compare\fP
+
+The \fBsearch\fP operation is already controlled either
+by the \fBtimelimit\fP parameter or by server-side enforced
+time limits (see \fBtimelimit\fP and \fBlimits\fP in
.BR slapd.conf (5)
-for details), and other operations are not supposed to incur into the
-need for timeouts.
-Note: if the timelimit is exceeded, the operation is abandoned;
-the protocol does not provide any means to rollback the operation,
-so the client will not know if the operation eventually succeeded or not.
+for details).
+Timeout is meaningless for the remaining operations,
+\fBunbind\fP and \fBabandon\fP, which do not imply any response,
+while it is not yet implemented in currently supported \fBextended\fP
+operations.
+If no operation is specified, the timeout \fBval\fP affects all
+supported operations.
+
+Note: if the timelimit is exceeded, the operation is cancelled
+(according to the \fBcancel\fP directive);
+the protocol does not provide any means to rollback operations,
+so the client will not be notified about the result of the operation,
+which may eventually succeeded or not.
+In case the timeout is exceeded during a bind operation, the connection
+is destroyed, according to RFC4511.
+
+Note: in some cases, this backend may issue binds prior
+to other operations (e.g. to bind anonymously or with some prescribed
+identity according to the \fBidassert-bind\fP directive).
+In this case, the timeout of the operation that resulted in the bind
+is used.
.TP
.B tls {[try-]start|[try-]propagate}
\fBpropagate\fP issues the StartTLS operation only if the original
connection did.
The \fBtry-\fP prefix instructs the proxy to continue operations
-if the StartTLS operation failed; its use is highly deprecated.
+if the StartTLS operation failed; its use is \fBnot\fP recommended.
.SH BACKWARD COMPATIBILITY
-The LDAP backend has been heavily reworked between releases 2.2 and 2.3;
-as a side-effect, some of the traditional directives have been
+The LDAP backend has been heavily reworked between releases 2.2 and 2.3,
+and subsequently between 2.3 and 2.4.
+As a side-effect, some of the traditional directives have been
deprecated and should be no longer used, as they might disappear
in future releases.
.TP
.B acl-authcDN "<administrative DN for access control purposes>"
-DN which is used to query the target server for acl checking; it
-is supposed to have read access on the target server to attributes used
+Formerly known as the
+.BR binddn ,
+it is the DN that is used to query the target server for acl checking;
+it is supposed to have read access on the target server to attributes used
on the proxy for acl checking.
There is no risk of giving away such values; they are only used to
check permissions.
+
.B The acl-authcDN identity is by no means implicitly used by the proxy
.B when the client connects anonymously.
-See the
+The
.B idassert-*
-feature instead.
+feature can be used (at own risk) for that purpose instead.
+
This directive is obsoleted by the
.B binddn
arg of
.TP
.B acl-passwd <password>
-Password used with the above
+Formerly known as the
+.BR bindpw ,
+it is the password used with the above
.B acl-authcDN
directive.
This directive is obsoleted by the
-.B binddn
+.B credentials
arg of
.B acl-bind
when \fIbindmethod\fP=\fBsimple\fP, and will be dismissed in the future.
above.
This directive is obsoleted by the
.B crendentials
-of
+arg of
.B idassert-bind
when \fIbindmethod\fP=\fBsimple\fP, and will be dismissed in the future.
.BR idassert-bind ,
and will be dismissed in the future.
+.TP
+.B port <port>
+this directive is no longer supported. Use the
+.B uri
+directive as described above.
+
.TP
.B server <hostname[:port]>
this directive is no longer supported. Use the
rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs,
ctrls, NULL, &msgid );
rs->sr_err = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_ADD ],
+ li->li_timeout[ SLAP_OP_ADD ],
( LDAP_BACK_SENDRESULT | retrying ) );
if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
retrying &= ~LDAP_BACK_RETRYING;
time_t lc_time;
} ldapconn_t;
-/*
- * operation enumeration for timeouts
- */
-enum {
- LDAP_BACK_OP_ADD = 0,
- LDAP_BACK_OP_DELETE,
- LDAP_BACK_OP_MODIFY,
- LDAP_BACK_OP_MODRDN,
- LDAP_BACK_OP_LAST
-};
-
typedef struct ldap_avl_info_t {
ldap_pvt_thread_mutex_t lai_mutex;
Avlnode *lai_tree;
time_t li_network_timeout;
time_t li_conn_ttl;
time_t li_idle_timeout;
- time_t li_timeout[ LDAP_BACK_OP_LAST ];
+ time_t li_timeout[ SLAP_OP_LAST ];
} ldapinfo_t;
typedef enum ldap_back_send_t {
rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
LDAP_SASL_SIMPLE,
&op->orb_cred, op->o_ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
-
+ rc = ldap_back_op_result( lc, op, rs, msgid,
+ li->li_timeout[ SLAP_OP_BIND ],
+ LDAP_BACK_BIND_SERR );
if ( rc == LDAP_SUCCESS ) {
/* If defined, proxyAuthz will be used also when
* back-ldap is the authorizing backend; for this
return 0;
}
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
+ rc = ldap_back_op_result( lc, op, rs, msgid,
+ -1, (sendok|LDAP_BACK_BINDING) );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
}
int rc;
struct timeval tv;
LDAPMessage *res = NULL;
+ time_t stoptime = (time_t)(-1);
+ int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ const char *timeout_text = "Operation timed out";
- if ( timeout ) {
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
+ /* if timeout is not specified, compute and use
+ * the one specific to the ongoing operation */
+ if ( timeout == (time_t)(-1) ) {
+ slap_op_t opidx = slap_req2op( op->o_tag );
- } else {
- LDAP_BACK_TV_SET( &tv );
+ if ( opidx == SLAP_OP_SEARCH ) {
+ if ( op->ors_tlimit <= 0 ) {
+ timeout = 0;
+
+ } else {
+ timeout = op->ors_tlimit;
+ timeout_err = LDAP_TIMELIMIT_EXCEEDED;
+ timeout_text = NULL;
+ }
+
+ } else {
+ timeout = li->li_timeout[ opidx ];
+ }
}
+ /* better than nothing :) */
+ if ( timeout == 0 ) {
+ if ( li->li_idle_timeout ) {
+ timeout = li->li_idle_timeout;
+
+ } else if ( li->li_conn_ttl ) {
+ timeout = li->li_conn_ttl;
+ }
+ }
+
+ if ( timeout ) {
+ stoptime = op->o_time + timeout;
+ }
+
+ LDAP_BACK_TV_SET( &tv );
+
retry:;
/* if result parsing fails, note the failure reason */
rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
switch ( rc ) {
case 0:
- if ( timeout ) {
- (void)ldap_back_cancel( lc, op, rs, msgid, sendok );
- rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
- rs->sr_text = "Operation timed out";
+ if ( timeout && slap_get_time() > stoptime ) {
+ if ( sendok & LDAP_BACK_BINDING ) {
+ ldap_unbind_ext( lc->lc_ld, NULL, NULL );
+ lc->lc_ld = NULL;
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+
+ } else {
+ (void)ldap_back_cancel( lc, op, rs, msgid, sendok );
+ }
+ rs->sr_err = timeout_err;
+ rs->sr_text = timeout_text;
break;
}
+ /* timeout == 0 */
LDAP_BACK_TV_SET( &tv );
ldap_pvt_thread_yield();
goto retry;
rs->sr_err = ldap_sasl_bind( lc->lc_ld,
binddn.bv_val, LDAP_SASL_SIMPLE,
&bindcred, NULL, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
+ rc = ldap_back_op_result( lc, op, rs, msgid,
+ -1, (sendok|LDAP_BACK_BINDING) );
break;
default:
BackendInfo *bi = be->bd_info;
ldapinfo_t *li;
- int t;
+ slap_op_t t;
be->bd_info = lback;
be->be_private = NULL;
li->li_nretries = lc->lc_common_li->li_nretries;
li->li_flags = lc->lc_common_li->li_flags;
li->li_version = lc->lc_common_li->li_version;
- for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
+ for ( t = 0; t < SLAP_OP_LAST; t++ ) {
li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
}
be->bd_info = bi;
op->orc_ava->aa_desc->ad_cname.bv_val,
&op->orc_ava->aa_value,
ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 0,
+ rc = ldap_back_op_result( lc, op, rs, msgid,
+ li->li_timeout[ SLAP_OP_COMPARE ],
( LDAP_BACK_SENDRESULT | retrying ) );
if ( rc == LDAP_UNAVAILABLE && retrying ) {
retrying &= ~LDAP_BACK_RETRYING;
{ BER_BVNULL, 0 }
};
+/* see enum in slap.h */
static slap_cf_aux_table timeout_table[] = {
- { BER_BVC("add="), 0 * sizeof( time_t ), 'u', 0, NULL },
- { BER_BVC("delete="), 1 * sizeof( time_t ), 'u', 0, NULL },
- { BER_BVC("modify="), 2 * sizeof( time_t ), 'u', 0, NULL },
- { BER_BVC("modrdn="), 3 * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("bind="), SLAP_OP_BIND * sizeof( time_t ), 'u', 0, NULL },
+ /* unbind makes no sense */
+ { BER_BVC("add="), SLAP_OP_ADD * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("delete="), SLAP_OP_DELETE * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("modrdn="), SLAP_OP_MODRDN * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("modify="), SLAP_OP_MODIFY * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("compare="), SLAP_OP_COMPARE * sizeof( time_t ), 'u', 0, NULL },
+#if 0 /* uses timelimit instead */
+ { BER_BVC("search="), SLAP_OP_SEARCH * sizeof( time_t ), 'u', 0, NULL },
+#endif
+ /* abandon makes little sense */
+#if 0 /* not implemented yet */
+ { BER_BVC("extended="), SLAP_OP_EXTENDED * sizeof( time_t ), 'u', 0, NULL },
+#endif
{ BER_BVNULL, 0, 0, 0, NULL }
};
case LDAP_BACK_CFG_TIMEOUT:
BER_BVZERO( &bv );
- for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
if ( li->li_timeout[ i ] != 0 ) {
break;
}
}
- if ( i == LDAP_BACK_OP_LAST ) {
+ if ( i == SLAP_OP_LAST ) {
return 1;
}
break;
case LDAP_BACK_CFG_TIMEOUT:
- for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
li->li_timeout[ i ] = 0;
}
break;
unsigned u;
if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) {
+ snprintf( c->msg, sizeof( c->msg),
+ "unable to parse timeout \"%s\"",
+ c->argv[ i ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
return 1;
}
- for ( j = 0; j < LDAP_BACK_OP_LAST; j++ ) {
+ for ( j = 0; j < SLAP_OP_LAST; j++ ) {
li->li_timeout[ j ] = u;
}
}
if ( slap_cf_aux_table_parse( c->argv[ i ], li->li_timeout, timeout_table, "slapd-ldap timeout" ) ) {
+ snprintf( c->msg, sizeof( c->msg),
+ "unable to parse timeout \"%s\"",
+ c->argv[ i ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
return 1;
}
}
rs->sr_err = ldap_delete_ext( lc->lc_ld, op->o_req_dn.bv_val,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_DELETE],
+ li->li_timeout[ SLAP_OP_DELETE ],
( LDAP_BACK_SENDRESULT | retrying ) );
if ( rs->sr_err == LDAP_SERVER_DOWN && retrying ) {
retrying &= ~LDAP_BACK_RETRYING;
BackendInfo *bi = be->bd_info;
ldapinfo_t *li;
- int t;
+ slap_op_t t;
be->bd_info = lback;
be->be_private = NULL;
li->li_nretries = lc->lc_common_li->li_nretries;
li->li_flags = lc->lc_common_li->li_flags;
li->li_version = lc->lc_common_li->li_version;
- for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
+ for ( t = 0; t < SLAP_OP_LAST; t++ ) {
li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
}
be->bd_info = bi;
rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_dn.bv_val, modv,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_MODIFY],
+ li->li_timeout[ SLAP_OP_MODIFY ],
( LDAP_BACK_SENDRESULT | retrying ) );
if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
retrying &= ~LDAP_BACK_RETRYING;
op->orr_newrdn.bv_val, newSup,
op->orr_deleteoldrdn, ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_MODRDN ],
+ li->li_timeout[ SLAP_OP_MODRDN ],
( LDAP_BACK_SENDRESULT | retrying ) );
if ( rs->sr_err == LDAP_SERVER_DOWN && retrying ) {
retrying &= ~LDAP_BACK_RETRYING;
ldapconn_t *lc;
struct timeval tv;
- time_t stoptime = (time_t)-1;
+ time_t stoptime = (time_t)(-1);
LDAPMessage *res,
*e;
int rc = 0,