From 150a4f106ce06829466562db3edcec9a719209ab Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Mon, 4 Sep 2006 08:24:05 +0000 Subject: [PATCH] improve timeout support (ITS#4157, ITS#4663); manpage cleanup --- doc/man/man5/slapd-ldap.5 | 101 ++++++++++++++++++---------- servers/slapd/back-ldap/add.c | 2 +- servers/slapd/back-ldap/back-ldap.h | 13 +--- servers/slapd/back-ldap/bind.c | 70 +++++++++++++++---- servers/slapd/back-ldap/chain.c | 4 +- servers/slapd/back-ldap/compare.c | 3 +- servers/slapd/back-ldap/config.c | 35 +++++++--- servers/slapd/back-ldap/delete.c | 2 +- servers/slapd/back-ldap/distproc.c | 4 +- servers/slapd/back-ldap/modify.c | 2 +- servers/slapd/back-ldap/modrdn.c | 2 +- servers/slapd/back-ldap/search.c | 2 +- 12 files changed, 161 insertions(+), 79 deletions(-) diff --git a/doc/man/man5/slapd-ldap.5 b/doc/man/man5/slapd-ldap.5 index 79eb9349e3..6ead6fa1c9 100644 --- a/doc/man/man5/slapd-ldap.5 +++ b/doc/man/man5/slapd-ldap.5 @@ -64,21 +64,20 @@ lastmod off .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 -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. @@ -86,10 +85,10 @@ 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 -.\"Obsolete option; same as `uri ldap:///'. +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 @@ -226,7 +225,8 @@ or 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: @@ -297,7 +297,7 @@ useful when the asserted identities do not exist on the remote server. Flags can be -\fBoverride,{prescriptive|non-prescriptive}\fP +\fBoverride,[non-]prescriptive\fP When the .B override @@ -389,19 +389,37 @@ If set to support is detected by reading the remote server's root DSE. .TP -.B timeout [{add|delete|modify|modrdn}=] [...] +.B timeout [=] [...] 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 ::= 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} @@ -410,26 +428,31 @@ only works if the URI directive protocol scheme is not \fBldaps://\fP. \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 "" -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 @@ -438,11 +461,13 @@ when \fIbindmethod\fP=\fBsimple\fP, and will be dismissed in the future. .TP .B acl-passwd -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. @@ -465,7 +490,7 @@ Password used with the 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. @@ -488,6 +513,12 @@ arg of .BR idassert-bind , and will be dismissed in the future. +.TP +.B port +this directive is no longer supported. Use the +.B uri +directive as described above. + .TP .B server this directive is no longer supported. Use the diff --git a/servers/slapd/back-ldap/add.c b/servers/slapd/back-ldap/add.c index 1989a5b608..9a8ba0518b 100644 --- a/servers/slapd/back-ldap/add.c +++ b/servers/slapd/back-ldap/add.c @@ -104,7 +104,7 @@ retry: 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; diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index a1fb091f31..e1ede3506f 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -101,17 +101,6 @@ typedef struct ldapconn_t { 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; @@ -279,7 +268,7 @@ typedef struct ldapinfo_t { 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 { diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 2d3527e239..1557de1e0a 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -117,8 +117,9 @@ ldap_back_bind( Operation *op, SlapReply *rs ) 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 @@ -1116,7 +1117,8 @@ retry:; 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 ); } @@ -1270,28 +1272,67 @@ ldap_back_op_result( 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; @@ -1690,7 +1731,8 @@ ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_b 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: diff --git a/servers/slapd/back-ldap/chain.c b/servers/slapd/back-ldap/chain.c index c0707c16a2..6bf0deac50 100644 --- a/servers/slapd/back-ldap/chain.c +++ b/servers/slapd/back-ldap/chain.c @@ -1741,7 +1741,7 @@ ldap_chain_db_init_one( BackendInfo *bi = be->bd_info; ldapinfo_t *li; - int t; + slap_op_t t; be->bd_info = lback; be->be_private = NULL; @@ -1757,7 +1757,7 @@ ldap_chain_db_init_one( 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; diff --git a/servers/slapd/back-ldap/compare.c b/servers/slapd/back-ldap/compare.c index 11fd3eb9c3..f58a4e3731 100644 --- a/servers/slapd/back-ldap/compare.c +++ b/servers/slapd/back-ldap/compare.c @@ -63,7 +63,8 @@ retry: 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; diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 154f4c305a..cd93d834c5 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -351,11 +351,22 @@ static slap_verbmasks cancel_mode[] = { { 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 } }; @@ -921,13 +932,13 @@ ldap_back_cf_gen( ConfigArgs *c ) 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; } @@ -1099,7 +1110,7 @@ ldap_back_cf_gen( ConfigArgs *c ) 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; @@ -1578,10 +1589,14 @@ done_url:; 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; } @@ -1589,6 +1604,10 @@ done_url:; } 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; } } diff --git a/servers/slapd/back-ldap/delete.c b/servers/slapd/back-ldap/delete.c index f95660cace..a46616f02d 100644 --- a/servers/slapd/back-ldap/delete.c +++ b/servers/slapd/back-ldap/delete.c @@ -63,7 +63,7 @@ retry: 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; diff --git a/servers/slapd/back-ldap/distproc.c b/servers/slapd/back-ldap/distproc.c index b67cb1d7a2..95c7dfcfbb 100644 --- a/servers/slapd/back-ldap/distproc.c +++ b/servers/slapd/back-ldap/distproc.c @@ -831,7 +831,7 @@ ldap_distproc_db_init_one( BackendInfo *bi = be->bd_info; ldapinfo_t *li; - int t; + slap_op_t t; be->bd_info = lback; be->be_private = NULL; @@ -845,7 +845,7 @@ ldap_distproc_db_init_one( 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; diff --git a/servers/slapd/back-ldap/modify.c b/servers/slapd/back-ldap/modify.c index 648dc18a0d..9e53ac2b8e 100644 --- a/servers/slapd/back-ldap/modify.c +++ b/servers/slapd/back-ldap/modify.c @@ -111,7 +111,7 @@ retry: 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; diff --git a/servers/slapd/back-ldap/modrdn.c b/servers/slapd/back-ldap/modrdn.c index 37e1afe7e8..e2b3b405e8 100644 --- a/servers/slapd/back-ldap/modrdn.c +++ b/servers/slapd/back-ldap/modrdn.c @@ -87,7 +87,7 @@ retry: 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; diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index b5647e5dc9..48a4a6179d 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -145,7 +145,7 @@ ldap_back_search( ldapconn_t *lc; struct timeval tv; - time_t stoptime = (time_t)-1; + time_t stoptime = (time_t)(-1); LDAPMessage *res, *e; int rc = 0, -- 2.39.5