Branch '389-ds-base-1.3.1' - ldap/servers
by Mark Reynolds
ldap/servers/slapd/bind.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
New commits:
commit 088dbaf22712a2b5422d87a4715ede5d0b6c14ac
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri May 3 15:42:01 2013 -0400
Ticket 580 - Wrong error code return when using EXTERNAL SASL and no client certificate
Bug Description: When doing a SASL EXTERNAL bind, and no client certificate is provided,
the bind succeeds(as anonymous). However, the bind should fail with
an error 48.
Fix Description: Check for the missing client certificate and return the appropriate
error.
https://fedorahosted.org/389/ticket/580
Reviewed by: Noriko(Thanks!)
(cherry picked from commit 2a81336e582c68fe0326a76a2f156b469688cc9b)
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
index d4d3b49..e92add5 100644
--- a/ldap/servers/slapd/bind.c
+++ b/ldap/servers/slapd/bind.c
@@ -403,10 +403,12 @@ do_bind( Slapi_PBlock *pb )
supported = slapi_get_supported_saslmechanisms_copy();
if ( (pmech = supported) != NULL ) while (1) {
if (*pmech == NULL) {
- /* As we call the safe function, we receive a strdup'd saslmechanisms
- charray. Therefore, we need to remove it instead of NULLing it */
- charray_free(supported);
- pmech = supported = NULL;
+ /*
+ * As we call the safe function, we receive a strdup'd saslmechanisms
+ * charray. Therefore, we need to remove it instead of NULLing it
+ */
+ charray_free(supported);
+ pmech = supported = NULL;
break;
}
if (!strcasecmp (saslmech, *pmech)) break;
@@ -450,11 +452,21 @@ do_bind( Slapi_PBlock *pb )
}
/*
+ * Check for the client certificate.
+ */
+ if( NULL == pb->pb_conn->c_client_cert){
+ send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
+ "missing client certificate", 0, NULL );
+ /* call postop plugins */
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
+ goto free_and_return;
+ }
+
+ /*
* if the client sent us a certificate but we could not map it
* to an LDAP DN, fail and return an invalidCredentials error.
*/
- if ( NULL != pb->pb_conn->c_client_cert &&
- NULL == pb->pb_conn->c_external_dn ) {
+ if ( NULL == pb->pb_conn->c_external_dn ) {
send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
"client certificate mapping failed", 0, NULL );
/* call postop plugins */
@@ -463,7 +475,7 @@ do_bind( Slapi_PBlock *pb )
}
if (!isroot ) {
- /* check if the account is locked */
+ /* check if the account is locked */
bind_target_entry = get_entry(pb, pb->pb_conn->c_external_dn);
if ( bind_target_entry != NULL && slapi_check_account_lock(pb, bind_target_entry,
pw_response_requested, 1 /*check password policy*/, 1 /*send ldap result*/) == 1) {
10 years, 4 months
Branch '389-ds-base-1.3.0' - ldap/servers
by Mark Reynolds
ldap/servers/slapd/bind.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
New commits:
commit 47a8402cf826fd3ecd7b6f05e0e0691ffae62ccc
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri May 3 15:42:01 2013 -0400
Ticket 580 - Wrong error code return when using EXTERNAL SASL and no client certificate
Bug Description: When doing a SASL EXTERNAL bind, and no client certificate is provided,
the bind succeeds(as anonymous). However, the bind should fail with
an error 48.
Fix Description: Check for the missing client certificate and return the appropriate
error.
https://fedorahosted.org/389/ticket/580
Reviewed by: Noriko(Thanks!)
(cherry picked from commit 2a81336e582c68fe0326a76a2f156b469688cc9b)
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
index d4d3b49..e92add5 100644
--- a/ldap/servers/slapd/bind.c
+++ b/ldap/servers/slapd/bind.c
@@ -403,10 +403,12 @@ do_bind( Slapi_PBlock *pb )
supported = slapi_get_supported_saslmechanisms_copy();
if ( (pmech = supported) != NULL ) while (1) {
if (*pmech == NULL) {
- /* As we call the safe function, we receive a strdup'd saslmechanisms
- charray. Therefore, we need to remove it instead of NULLing it */
- charray_free(supported);
- pmech = supported = NULL;
+ /*
+ * As we call the safe function, we receive a strdup'd saslmechanisms
+ * charray. Therefore, we need to remove it instead of NULLing it
+ */
+ charray_free(supported);
+ pmech = supported = NULL;
break;
}
if (!strcasecmp (saslmech, *pmech)) break;
@@ -450,11 +452,21 @@ do_bind( Slapi_PBlock *pb )
}
/*
+ * Check for the client certificate.
+ */
+ if( NULL == pb->pb_conn->c_client_cert){
+ send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
+ "missing client certificate", 0, NULL );
+ /* call postop plugins */
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
+ goto free_and_return;
+ }
+
+ /*
* if the client sent us a certificate but we could not map it
* to an LDAP DN, fail and return an invalidCredentials error.
*/
- if ( NULL != pb->pb_conn->c_client_cert &&
- NULL == pb->pb_conn->c_external_dn ) {
+ if ( NULL == pb->pb_conn->c_external_dn ) {
send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
"client certificate mapping failed", 0, NULL );
/* call postop plugins */
@@ -463,7 +475,7 @@ do_bind( Slapi_PBlock *pb )
}
if (!isroot ) {
- /* check if the account is locked */
+ /* check if the account is locked */
bind_target_entry = get_entry(pb, pb->pb_conn->c_external_dn);
if ( bind_target_entry != NULL && slapi_check_account_lock(pb, bind_target_entry,
pw_response_requested, 1 /*check password policy*/, 1 /*send ldap result*/) == 1) {
10 years, 4 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Mark Reynolds
ldap/servers/slapd/bind.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
New commits:
commit 9bea04c9578f0e1fc48bc2b316b1daf1cf384d42
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri May 3 15:42:01 2013 -0400
Ticket 580 - Wrong error code return when using EXTERNAL SASL and no client certificate
Bug Description: When doing a SASL EXTERNAL bind, and no client certificate is provided,
the bind succeeds(as anonymous). However, the bind should fail with
an error 48.
Fix Description: Check for the missing client certificate and return the appropriate
error.
https://fedorahosted.org/389/ticket/580
Reviewed by: Noriko(Thanks!)
(cherry picked from commit 2a81336e582c68fe0326a76a2f156b469688cc9b)
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
index d4d3b49..e92add5 100644
--- a/ldap/servers/slapd/bind.c
+++ b/ldap/servers/slapd/bind.c
@@ -403,10 +403,12 @@ do_bind( Slapi_PBlock *pb )
supported = slapi_get_supported_saslmechanisms_copy();
if ( (pmech = supported) != NULL ) while (1) {
if (*pmech == NULL) {
- /* As we call the safe function, we receive a strdup'd saslmechanisms
- charray. Therefore, we need to remove it instead of NULLing it */
- charray_free(supported);
- pmech = supported = NULL;
+ /*
+ * As we call the safe function, we receive a strdup'd saslmechanisms
+ * charray. Therefore, we need to remove it instead of NULLing it
+ */
+ charray_free(supported);
+ pmech = supported = NULL;
break;
}
if (!strcasecmp (saslmech, *pmech)) break;
@@ -450,11 +452,21 @@ do_bind( Slapi_PBlock *pb )
}
/*
+ * Check for the client certificate.
+ */
+ if( NULL == pb->pb_conn->c_client_cert){
+ send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
+ "missing client certificate", 0, NULL );
+ /* call postop plugins */
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
+ goto free_and_return;
+ }
+
+ /*
* if the client sent us a certificate but we could not map it
* to an LDAP DN, fail and return an invalidCredentials error.
*/
- if ( NULL != pb->pb_conn->c_client_cert &&
- NULL == pb->pb_conn->c_external_dn ) {
+ if ( NULL == pb->pb_conn->c_external_dn ) {
send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
"client certificate mapping failed", 0, NULL );
/* call postop plugins */
@@ -463,7 +475,7 @@ do_bind( Slapi_PBlock *pb )
}
if (!isroot ) {
- /* check if the account is locked */
+ /* check if the account is locked */
bind_target_entry = get_entry(pb, pb->pb_conn->c_external_dn);
if ( bind_target_entry != NULL && slapi_check_account_lock(pb, bind_target_entry,
pw_response_requested, 1 /*check password policy*/, 1 /*send ldap result*/) == 1) {
10 years, 4 months
ldap/servers
by Mark Reynolds
ldap/servers/slapd/control.c | 8 -
ldap/servers/slapd/result.c | 304 +++++++++++++++++++++++++++++++++++++-
ldap/servers/slapd/slapi-plugin.h | 8 +
3 files changed, 316 insertions(+), 4 deletions(-)
New commits:
commit 63f6db7bc8c61877b9f666c0efe0c7cbcccc9303
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Thu May 30 16:05:36 2013 -0400
Ticket 589 - RFE - Support RFC 4527 Read Entry Controls
Description: Add support for read entry controls. The pre-read control
returns a copy of the entry before it was modifed, and the
post-read control returns the entry after the modify. Both
controls can be used for the same operation. The control
is added just before the result is returned to the client.
https://fedorahosted.org/389/ticket/589
Reviewed by: Noriko & Rich(Thanks!!)
diff --git a/ldap/servers/slapd/control.c b/ldap/servers/slapd/control.c
index e614d50..dbbf5b0 100644
--- a/ldap/servers/slapd/control.c
+++ b/ldap/servers/slapd/control.c
@@ -95,6 +95,12 @@ init_controls( void )
SLAPI_OPERATION_SEARCH );
slapi_register_supported_control( LDAP_CONTROL_VIRT_ATTRS_ONLY,
SLAPI_OPERATION_SEARCH );
+ slapi_register_supported_control( LDAP_CONTROL_PRE_READ_ENTRY,
+ SLAPI_OPERATION_DELETE | SLAPI_OPERATION_MODIFY |
+ SLAPI_OPERATION_MODDN );
+ slapi_register_supported_control( LDAP_CONTROL_POST_READ_ENTRY,
+ SLAPI_OPERATION_ADD | SLAPI_OPERATION_MODIFY |
+ SLAPI_OPERATION_MODDN );
slapi_register_supported_control( LDAP_X_CONTROL_PWPOLICY_REQUEST,
SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
| SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
@@ -361,7 +367,7 @@ get_ldapmessage_controls_ext(
slapi_pblock_set(pb, SLAPI_MANAGEDSAIT, &ctrl_not_found);
slapi_pblock_set(pb, SLAPI_PWPOLICY, &ctrl_not_found);
slapi_log_error(SLAPI_LOG_CONNS, "connection", "Warning: conn=%d op=%d contains an empty list of controls\n",
- pb->pb_conn->c_connid, pb->pb_op->o_opid);
+ (int)pb->pb_conn->c_connid, pb->pb_op->o_opid);
} else {
if ((tag != LBER_END_OF_SEQORSET) && (len != -1)) {
goto free_and_return;
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
index 8f64dd7..7ad584e 100644
--- a/ldap/servers/slapd/result.c
+++ b/ldap/servers/slapd/result.c
@@ -73,6 +73,11 @@ static void log_result( Slapi_PBlock *pb, Operation *op, int err,
ber_tag_t tag, int nentries );
static void log_entry( Operation *op, Slapi_Entry *e );
static void log_referral( Operation *op );
+static int process_read_entry_controls(Slapi_PBlock *pb, char *oid);
+static struct berval * encode_read_entry(Slapi_PBlock *pb, Slapi_Entry *e,
+ char **attrs, int alluserattrs,
+ int some_named_attrs);
+static char * op_to_string(int tag);
#define _LDAP_SEND_RESULT 0
#define _LDAP_SEND_REFERRAL 1
@@ -484,7 +489,7 @@ send_ldap_result_ext(
/*
* there are v3 referrals to add to the result
*/
- /* count the referral */
+ /* count the referral */
if (! config_check_referral_mode())
slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsReferrals);
rc = ber_printf( ber, "{it{esst{s", operation->o_msgid, tag, err,
@@ -521,6 +526,19 @@ send_ldap_result_ext(
rc = ber_printf( ber, "}" ); /* one more } to come */
}
}
+ if(err == LDAP_SUCCESS){
+ /*
+ * Process the Read Entry Controls (if any)
+ */
+ if(process_read_entry_controls(pb, LDAP_CONTROL_PRE_READ_ENTRY)){
+ err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ goto log_and_return;
+ }
+ if(process_read_entry_controls(pb, LDAP_CONTROL_POST_READ_ENTRY)){
+ err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ goto log_and_return;
+ }
+ }
if ( operation->o_results.result_controls != NULL
&& conn->c_ldapversion >= LDAP_VERSION3
&& write_controls( ber, operation->o_results.result_controls ) != 0 ) {
@@ -558,6 +576,168 @@ log_and_return:
LDAPDebug( LDAP_DEBUG_TRACE, "<= send_ldap_result\n", 0, 0, 0 );
}
+/*
+ * For RFC 4527 - Read Entry Controls
+ *
+ * If this is the correct operation for the control, then retrieve the
+ * requested attributes. Then start building the ber-encoded string
+ * value of the entry. We also need to check access control for the
+ * requested attributes. Then an octet string containing a BER-encoded
+ * SearchResultEntry is added to the response control.
+ */
+static int
+process_read_entry_controls(Slapi_PBlock *pb, char *oid)
+{
+ struct berval *req_value = NULL;
+ struct berval *res_value = NULL;
+ LDAPControl **req_ctls = NULL;
+ Slapi_Entry *e = NULL;
+ char **attrs = NULL;
+ int attr_count = 0;
+ int iscritical = 0;
+ int all_attrs = 0;
+ int no_attrs = 0;
+ int rc = 0;
+
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &req_ctls);
+
+ /*
+ * Check for the PRE Read Entry Control, and return the pre-modified entry
+ */
+ if (slapi_control_present(req_ctls, oid, &req_value, &iscritical))
+ {
+ BerElement *req_ber = NULL;
+ Operation *op = pb->pb_op;
+
+ if(strcmp(oid,LDAP_CONTROL_PRE_READ_ENTRY) == 0){
+ /* first verify this is the correct operation for a pre-read entry control */
+ if(op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_DELETE ||
+ op->o_tag == LDAP_REQ_MODDN){
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
+ } else {
+ /* Ok, read control not used for this type of operation */
+ LDAPDebug( LDAP_DEBUG_ANY, "process_read_entry_controls: Read Entry Controls "
+ "can not be used for a %s operation.\n", op_to_string(op->o_tag), 0, 0);
+ rc = -1;
+ goto done;
+ }
+ } else {
+ /* first verify this is the correct operation for a post-read entry control */
+ if(op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD ||
+ op->o_tag == LDAP_REQ_MODDN){
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
+ } else {
+ /* Ok, read control not used for this type of operation */
+ LDAPDebug( LDAP_DEBUG_ANY, "process_read_entry_controls: Read Entry Controls "
+ "can not be used for a %s operation.\n", op_to_string(op->o_tag), 0, 0);
+ rc = -1;
+ goto done;
+ }
+ }
+ if(e == NULL){
+ LDAPDebug( LDAP_DEBUG_ANY, "process_read_entry_controls: unable to retrieve entry\n",0,0,0);
+ rc = -1;
+ goto done;
+ }
+
+#if !defined(DISABLE_ACL_CHECK)
+ /* even though we can modify the entry, that doesn't mean we can read it */
+ if ( plugin_call_acl_plugin (pb, e, attrs, NULL, SLAPI_ACL_READ,
+ ACLPLUGIN_ACCESS_READ_ON_ENTRY, NULL ) != LDAP_SUCCESS )
+ {
+ LDAPDebug( LDAP_DEBUG_ACL, "process_read_entry_controls: access to entry not allowed (%s)\n",
+ slapi_entry_get_dn_const(e), 0, 0 );
+ rc = -1;
+ goto done;
+ }
+#endif
+ /*
+ * Check the ctl_value for any requested attributes
+ */
+ if( req_value && req_value->bv_len != 0 && req_value->bv_val){
+ if ((req_ber = ber_init(req_value)) == NULL){
+ rc = -1;
+ goto free;
+ }
+ if (ber_scanf(req_ber, "{") == LBER_ERROR){
+ rc = -1;
+ goto free;
+ }
+ /* process the attributes */
+ while(1){
+ char *payload = NULL;
+
+ if (ber_get_stringa(req_ber, &payload) != LBER_ERROR){
+ if(strcmp(payload, LDAP_ALL_USER_ATTRS) == 0){
+ all_attrs = 1;
+ slapi_ch_free_string(&payload);
+ } else if(strcmp(payload, LDAP_NO_ATTRS) == 0){
+ no_attrs = 1;
+ slapi_ch_free_string(&payload);
+ } else {
+ charray_add(&attrs, payload);
+ attr_count++;
+ }
+ } else {
+ /* we're done */
+ break;
+ }
+ }
+ if(no_attrs && (all_attrs || attr_count)){
+ /* Can't have both no attrs and some attributes */
+ LDAPDebug( LDAP_DEBUG_ANY, "process_read_entry_controls: Error, both no attributes \"1.1\" and "
+ "specific attributes were requeseted.\n", 0, 0, 0 );
+ rc = -1;
+ goto free;
+ }
+
+ if (ber_scanf(req_ber, "}") == LBER_ERROR){
+ rc = -1;
+ goto free;
+ }
+ } else {
+ /* this is a problem, malformed request control value */
+ LDAPDebug( LDAP_DEBUG_ANY, "process_read_entry_controls: invalid control value.\n",0,0,0);
+ rc = -1;
+ goto free;
+ }
+
+ /*
+ * Get the ber encoded string, and add it to the response control
+ */
+ res_value = encode_read_entry(pb, e, attrs, all_attrs, attr_count);
+ if(res_value && res_value->bv_len > 0){
+ LDAPControl new_ctrl = {0};
+
+ new_ctrl.ldctl_oid = oid;
+ new_ctrl.ldctl_value = *res_value;
+ new_ctrl.ldctl_iscritical = iscritical;
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &new_ctrl );
+ ber_bvfree(res_value);
+ } else {
+ /* failed to encode the result entry */
+ LDAPDebug( LDAP_DEBUG_ANY, "Failed to process READ ENTRY Control (%s), error encoding result entry\n",
+ oid, 0, 0 );
+ rc = -1;
+ }
+
+free:
+ if (NULL != req_ber){
+ ber_free(req_ber, 1);
+ }
+ if(rc != 0){
+ /* log an error */
+ LDAPDebug( LDAP_DEBUG_ANY, "Failed to process READ ENTRY Control (%s) ber decoding error\n",
+ oid, 0, 0 );
+ }
+ }
+done:
+ if(iscritical){
+ return rc;
+ } else {
+ return 0;
+ }
+}
void
send_nobackend_ldap_result( Slapi_PBlock *pb )
@@ -1239,7 +1419,7 @@ send_ldap_search_entry_ext(
slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
LDAPDebug( LDAP_DEBUG_TRACE, "=> send_ldap_search_entry (%s)\n",
- e?slapi_entry_get_dn_const(e):"null", 0, 0 );
+ e ? slapi_entry_get_dn_const(e) : "null", 0, 0 );
/* set current entry */
slapi_pblock_set(pb, SLAPI_SEARCH_ENTRY_ORIG, e);
@@ -1345,7 +1525,7 @@ send_ldap_search_entry_ext(
* We maintain a flag array so that we can remove requests
* for duplicate attributes.
*/
- dontsendattr= (int*) slapi_ch_calloc( i+1, sizeof(int) );
+ dontsendattr = (int*) slapi_ch_calloc( i+1, sizeof(int) );
}
@@ -1852,3 +2032,121 @@ log_referral( Operation *op )
}
}
}
+
+/*
+ * Generate a octet string ber-encoded searchResultEntry for
+ * pre & post Read Entry Controls
+ */
+static struct berval *
+encode_read_entry (Slapi_PBlock *pb, Slapi_Entry *e, char **attrs, int alluserattrs, int attr_count)
+{
+ Slapi_Operation *op = pb->pb_op;
+ Connection*conn = pb->pb_conn;
+ LDAPControl **ctrlp = NULL;
+ struct berval *bv = NULL;
+ BerElement *ber = NULL;
+ int *dontsendattr = NULL;
+ int real_attrs_only = 0;
+ int rc = 0;
+
+ if ( (ber = der_alloc()) == NULL ) {
+ rc = -1;
+ goto cleanup;
+ }
+
+ /* Start the ber encoding with the DN */
+ rc = ber_printf( ber, "{s{", slapi_entry_get_dn_const(e) );
+ if ( rc == -1 ) {
+ rc = -1;
+ goto cleanup;
+ }
+
+ /* determine whether we are to return virtual attributes */
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+ if(slapi_control_present(ctrlp, LDAP_CONTROL_REAL_ATTRS_ONLY, NULL, NULL)){
+ real_attrs_only = SLAPI_SEND_VATTR_FLAG_REALONLY;
+ }
+ if(slapi_control_present(ctrlp, LDAP_CONTROL_VIRT_ATTRS_ONLY, NULL, NULL)){
+ if(real_attrs_only != SLAPI_SEND_VATTR_FLAG_REALONLY){
+ real_attrs_only = SLAPI_SEND_VATTR_FLAG_VIRTUALONLY;
+ } else {
+ /* we cannot service a request for virtual only and real only */
+ LDAPDebug( LDAP_DEBUG_ANY,"encode_read_entry: Error, both real and virtual attributes "
+ "only controls requested.\n", 0, 0, 0 );
+ rc = -1;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * We maintain a flag array so that we can remove requests
+ * for duplicate attributes. We also need to set o_searchattrs
+ * for the attribute processing, as modify op's don't have search attrs.
+ */
+ dontsendattr = (int*) slapi_ch_calloc( attr_count+1, sizeof(int) );
+ op->o_searchattrs = attrs;
+
+ /* Send all the attributes */
+ if ( alluserattrs ) {
+ rc = send_all_attrs(e, attrs, op, pb, ber, 0, conn->c_ldapversion,
+ dontsendattr, real_attrs_only, attr_count);
+ if(rc){
+ goto cleanup;
+ }
+ }
+
+ /* Send a specified list of attributes */
+ if( attrs != NULL) {
+ rc = send_specific_attrs(e, attrs, op, pb, ber, 0, conn->c_ldapversion,
+ dontsendattr, real_attrs_only);
+ if(rc){
+ goto cleanup;
+ }
+ }
+
+ /* wrap up the ber encoding */
+ rc = ber_printf( ber, "}}" );
+ if(rc != -1){
+ /* generate our string encoded value */
+ rc = ber_flatten(ber, &bv);
+ }
+
+cleanup:
+
+ ber_free( ber, 1 );
+ slapi_ch_free( (void **) &dontsendattr );
+ if(rc != 0){
+ return NULL;
+ } else {
+ return bv;
+ }
+}
+
+static char *
+op_to_string(int tag)
+{
+ char *op = NULL;
+
+ if(tag == LDAP_REQ_BIND){
+ op = "BIND";
+ } else if (tag == LDAP_REQ_UNBIND){
+ op = "UNBIND";
+ } else if (tag == LDAP_REQ_SEARCH){
+ op = "SEARCH";
+ } else if (tag == LDAP_REQ_ADD){
+ op = "ADD";
+ } else if (tag == LDAP_REQ_DELETE){
+ op = "DELETE";
+ } else if (tag == LDAP_REQ_RENAME){
+ op = "RENAME";
+ } else if (tag == LDAP_REQ_COMPARE){
+ op = "COMPARE";
+ } else if (tag == LDAP_REQ_ABANDON){
+ op = "ABANDON";
+ } else if (tag == LDAP_REQ_EXTENDED){
+ op = "EXTENDED";
+ }
+
+ return op;
+}
+
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 7000df6..ee209d2 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -350,6 +350,14 @@ NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...)
#define LDAP_CONTROL_AUTH_REQUEST "2.16.840.1.113730.3.4.16"
#endif
+/* Read Entry Controls - PRE & POST */
+#ifndef LDAP_CONTROL_PRE_READ_ENTRY
+#define LDAP_CONTROL_PRE_READ_ENTRY "1.3.6.1.1.13.1"
+#endif
+#ifndef LDAP_CONTROL_POST_READ_ENTRY
+#define LDAP_CONTROL_POST_READ_ENTRY "1.3.6.1.1.13.2"
+#endif
+
#ifndef LDAP_SORT_CONTROL_MISSING
#define LDAP_SORT_CONTROL_MISSING 0x3C /* 60 (server side sort extn) */
#endif
10 years, 4 months
ldap/servers
by thierry bordaz
ldap/servers/plugins/replication/repl5.h | 2
ldap/servers/plugins/replication/repl5_init.c | 3
ldap/servers/plugins/replication/repl5_plugins.c | 31 ++++++
ldap/servers/plugins/replication/repl5_replica.c | 23 ++++
ldap/servers/plugins/replication/repl5_replica_config.c | 76 ++++++++++++++++
ldap/servers/plugins/replication/repl5_ruv.c | 76 ++++++++++++++++
ldap/servers/plugins/replication/repl5_ruv.h | 2
7 files changed, 208 insertions(+), 5 deletions(-)
New commits:
commit 6c26f0ba8a33a7f1dff6a5b848e0dc39e1c9c41f
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Thu May 2 15:24:13 2013 +0200
Ticket 47350 - Allow search to look up 'in memory RUV'
Bug Description:
On a running instance and for a given replica the RUV is an in memory data structure.
This data structure is writen to disk at each update and there it is named database RUV.
With ticket https://fedorahosted.org/389/ticket/564, the update of the database RUV would be done
asynchronously. The consequence is that the database RUV would be late compare to the current
update status.
It is important for monitoring reason to look up the current update status and so to be able to
read the in memory RUV
Fix Description:
The fix consists to return the in memory RUV if attributes "nsds50ruv" and/or "nsruvReplicaLastModified" are
requested when reading the entry (replica_config_search):
cn=replica,cn=\"<suffix>\",cn=mapping tree,cn=config
In addition to provide backward compatibility, if the database ruv is lookup
(i.e. nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff,<suffix>), it actually returns the in memory ruv
(i.e. cn=replica,cn=\"<suffix>\",cn=mapping tree,cn=config). This is achieved with a registered MMR preop callback
(multimaster_preop_init), that is called when send the result entry (SLAPI_PLUGIN_PRE_ENTRY_FN).
https://fedorahosted.org/389/ticket/47350
Reviewed by: Rich Meggison, Noriko Hosoi
Platforms tested: F17
Flag Day: no
Doc impact: no
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index c7639e3..8da2d3b 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -212,6 +212,7 @@ int multimaster_preop_modify (Slapi_PBlock *pb);
int multimaster_preop_modrdn (Slapi_PBlock *pb);
int multimaster_preop_search (Slapi_PBlock *pb);
int multimaster_preop_compare (Slapi_PBlock *pb);
+int multimaster_ruv_search(Slapi_PBlock *pb);
int multimaster_bepreop_add (Slapi_PBlock *pb);
int multimaster_bepreop_delete (Slapi_PBlock *pb);
int multimaster_bepreop_modify (Slapi_PBlock *pb);
@@ -591,6 +592,7 @@ void replica_set_tombstone_reap_interval (Replica *r, long interval);
void replica_update_ruv_consumer (Replica *r, RUV *supplier_ruv);
void replica_set_ruv_dirty (Replica *r);
void replica_write_ruv (Replica *r);
+Slapi_Entry *get_in_memory_ruv(Slapi_DN *suffix_sdn);
char *replica_get_dn(Replica *r);
void replica_check_for_tasks(Replica*r, Slapi_Entry *e);
void replica_update_state (time_t when, void *arg);
diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c
index 8471f00..1533db9 100644
--- a/ldap/servers/plugins/replication/repl5_init.c
+++ b/ldap/servers/plugins/replication/repl5_init.c
@@ -259,7 +259,8 @@ multimaster_preop_init( Slapi_PBlock *pb )
slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void *) multimaster_preop_modify ) != 0 ||
slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODRDN_FN, (void *) multimaster_preop_modrdn ) != 0 ||
slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void *) multimaster_preop_search ) != 0 ||
- slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void *) multimaster_preop_compare ) != 0)
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void *) multimaster_preop_compare ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ENTRY_FN, (void *) multimaster_ruv_search ) != 0)
{
slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_preop_init failed\n" );
rc= -1;
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c
index 43c1596..cb5fe5c 100644
--- a/ldap/servers/plugins/replication/repl5_plugins.c
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
@@ -640,6 +640,37 @@ multimaster_preop_compare (Slapi_PBlock *pb)
return 0;
}
+int
+multimaster_ruv_search(Slapi_PBlock *pb)
+{
+ Slapi_Entry *e, *e_alt;
+ Slapi_DN *suffix_sdn;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_ENTRY_ORIG, &e);
+
+ if (e == NULL)
+ return 0;
+
+ if (is_ruv_tombstone_entry(e)) {
+ /* We are about to send back the database RUV, we need to return
+ * in memory RUV instead
+ */
+
+ /* Retrieve the suffix DN from the RUV entry */
+ suffix_sdn = slapi_sdn_new();
+ slapi_sdn_get_parent(slapi_entry_get_sdn(e), suffix_sdn);
+
+ /* Now set the in memory RUV into the pblock */
+ if ((e_alt = get_in_memory_ruv(suffix_sdn)) != NULL) {
+ slapi_pblock_set(pb, SLAPI_SEARCH_ENTRY_COPY, e_alt);
+ }
+
+ slapi_sdn_free(&suffix_sdn);
+ }
+
+ return 0;
+}
+
static void
purge_entry_state_information (Slapi_PBlock *pb)
{
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index 5a19833..6c73d05 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -104,7 +104,7 @@ typedef struct reap_callback_data
/* Forward declarations of helper functions*/
-static Slapi_Entry* _replica_get_config_entry (const Slapi_DN *root);
+static Slapi_Entry* _replica_get_config_entry (const Slapi_DN *root, char **attrs);
static int _replica_check_validity (const Replica *r);
static int _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext);
static int _replica_update_entry (Replica *r, Slapi_Entry *e, char *errortext);
@@ -139,7 +139,7 @@ replica_new(const Slapi_DN *root)
PR_ASSERT (root);
/* check if there is a replica associated with the tree */
- e = _replica_get_config_entry (root);
+ e = _replica_get_config_entry (root, NULL);
if (e)
{
errorbuf[0] = '\0';
@@ -1556,7 +1556,7 @@ int replica_check_for_data_reload (Replica *r, void *arg)
mapping tree node for the replica's backend */
static Slapi_Entry*
-_replica_get_config_entry (const Slapi_DN *root)
+_replica_get_config_entry (const Slapi_DN *root, char **attrs)
{
int rc = 0;
char *dn = NULL;
@@ -1573,7 +1573,7 @@ _replica_get_config_entry (const Slapi_DN *root)
}
pb = slapi_pblock_new ();
- slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL,
+ slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", attrs, 0, NULL,
NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
slapi_search_internal_pb (pb);
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
@@ -1590,6 +1590,21 @@ _replica_get_config_entry (const Slapi_DN *root)
return e;
}
+/* It does an internal search to read the in memory RUV
+ * of the provided suffix
+ */
+Slapi_Entry *
+get_in_memory_ruv(Slapi_DN *suffix_sdn)
+{
+ char *attrs[3];
+
+ /* these two attributes needs to be asked when reading the RUV */
+ attrs[0] = type_ruvElement;
+ attrs[1] = type_ruvElementUpdatetime;
+ attrs[2] = NULL;
+ return(_replica_get_config_entry(suffix_sdn, attrs));
+}
+
char *
replica_get_dn(Replica *r)
{
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 77f748f..9dc9169 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -704,6 +704,70 @@ replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter
return SLAPI_DSE_CALLBACK_OK;
}
+static void
+replica_config_search_last_modified(Slapi_PBlock *pb, Slapi_Entry* e, Replica *replica)
+{
+ Object *ruv_obj = NULL;
+ RUV *ruv = NULL;
+ Slapi_Value **values;
+
+ if (replica == NULL)
+ return;
+ ruv_obj = replica_get_ruv(replica);
+ ruv = object_get_data(ruv_obj);
+
+ if ((values = ruv_last_modified_to_valuearray(ruv)) != NULL) {
+ slapi_entry_add_values_sv(e, type_ruvElementUpdatetime, values);
+ valuearray_free(&values);
+ }
+
+ object_release(ruv_obj);
+
+}
+
+static void
+replica_config_search_ruv(Slapi_PBlock *pb, Slapi_Entry* e, Replica *replica)
+{
+ Object *ruv_obj = NULL;
+ RUV *ruv = NULL;
+ Slapi_Value **values;
+
+ if (replica == NULL)
+ return;
+ ruv_obj = replica_get_ruv(replica);
+ ruv = object_get_data(ruv_obj);
+
+ if ((values = ruv_to_valuearray(ruv)) != NULL) {
+ slapi_entry_add_values_sv(e, type_ruvElement, values);
+ valuearray_free(&values);
+ }
+
+ object_release(ruv_obj);
+
+}
+
+/* Returns PR_TRUE if 'attr' is present in the search requested attributes
+ * else it returns PR_FALSE
+ */
+static PRBool
+search_requested_attr(Slapi_PBlock *pb, char *attr)
+{
+ char **attrs = NULL;
+ int i;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRS, &attrs);
+ if ((attr == NULL) || (attrs == NULL))
+ return PR_FALSE;
+
+ for (i = 0; attrs[i] != NULL; i++) {
+ if (strcasecmp(attrs[i], attr) == 0) {
+ return PR_TRUE;
+ }
+ }
+
+ return PR_FALSE;
+}
+
static int
replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode,
char *returntext, void *arg)
@@ -730,6 +794,18 @@ replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter
if (replica) {
reapActive = replica_get_tombstone_reap_active(replica);
}
+
+ /* Check if the in memory ruv is requested */
+ if (search_requested_attr(pb, type_ruvElement)) {
+ replica_config_search_ruv(pb, e, replica);
+ }
+
+ /* Check if the last update time is requested */
+ if (search_requested_attr(pb, type_ruvElementUpdatetime)) {
+ replica_config_search_last_modified(pb, e, replica);
+ }
+
+
object_release (mtnode_ext->replica);
}
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
index 107c4f0..43f2c84 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.c
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -1178,6 +1178,82 @@ ruv_get_cleaned_rids(RUV *ruv, ReplicaId *rids)
}
}
+/*
+ * This routine dump the ruv (last modified time) into a value array
+ * the call must free the returned value array
+ */
+Slapi_Value **
+ruv_last_modified_to_valuearray(RUV *ruv)
+{
+ RUVElement *ruv_e;
+ int cookie;
+ Slapi_Value *value;
+ Slapi_Value **values = NULL;
+ char *buffer;
+
+
+ /* Acquire the ruv lock */
+ slapi_rwlock_rdlock(ruv->lock);
+
+ /* Now loop for each RUVElement and store its string value into the valueset*/
+ for (ruv_e = dl_get_first(ruv->elements, &cookie);
+ NULL != ruv_e;
+ ruv_e = dl_get_next(ruv->elements, &cookie)) {
+
+ buffer = slapi_ch_smprintf("%s%d%s%s} %08lx", prefix_ruvcsn, ruv_e->rid,
+ ruv_e->replica_purl == NULL ? "" : " ",
+ ruv_e->replica_purl == NULL ? "" : ruv_e->replica_purl,
+ ruv_e->last_modified);
+ value = slapi_value_new_string_passin(buffer);
+ valuearray_add_value(&values, value);
+ slapi_value_free(&value);
+ }
+
+ slapi_rwlock_unlock(ruv->lock);
+
+ return (values);
+}
+
+/*
+ * This routine dump the ruv (replicageneration and ruvElements) into a value array
+ * the call must free the returned value array
+ */
+Slapi_Value **
+ruv_to_valuearray(RUV *ruv)
+{
+ RUVElement *ruv_e;
+ int cookie;
+ Slapi_Value *value;
+ Slapi_Value **values = NULL;
+ struct berval bv;
+ char *buffer;
+
+ /* Acquire the ruv lock */
+ slapi_rwlock_rdlock(ruv->lock);
+
+ /* dump the replicageneration */
+ buffer = slapi_ch_smprintf("%s %s", prefix_replicageneration, ruv->replGen);
+ value = slapi_value_new_string_passin(buffer);
+ valuearray_add_value(&values, value);
+ slapi_value_free(&value);
+
+ /* Now loop for each RUVElement and store its string value into the valueset*/
+ for (ruv_e = dl_get_first(ruv->elements, &cookie);
+ NULL != ruv_e;
+ ruv_e = dl_get_next(ruv->elements, &cookie)) {
+
+ ruv_element_to_string(ruv_e, &bv, NULL, 0);
+ value = slapi_value_new_berval(&bv);
+ slapi_ber_bvdone(&bv);
+ valuearray_add_value(&values, value);
+ slapi_value_free(&value);
+ }
+
+ slapi_rwlock_unlock(ruv->lock);
+
+ return (values);
+}
+
int
ruv_to_smod(const RUV *ruv, Slapi_Mod *smod)
{
diff --git a/ldap/servers/plugins/replication/repl5_ruv.h b/ldap/servers/plugins/replication/repl5_ruv.h
index 036951f..c9b85ac 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.h
+++ b/ldap/servers/plugins/replication/repl5_ruv.h
@@ -125,6 +125,8 @@ int ruv_get_min_csn(const RUV *ruv, CSN **csn);
int ruv_get_max_csn(const RUV *ruv, CSN **csn);
int ruv_get_rid_max_csn(const RUV *ruv, CSN **csn, ReplicaId rid);
int ruv_enumerate_elements (const RUV *ruv, FNEnumRUV fn, void *arg);
+Slapi_Value **ruv_last_modified_to_valuearray(RUV *ruv);
+Slapi_Value **ruv_to_valuearray(RUV *ruv);
int ruv_to_smod(const RUV *ruv, Slapi_Mod *smod);
int ruv_last_modified_to_smod(const RUV *ruv, Slapi_Mod *smod);
int ruv_to_bervals(const RUV *ruv, struct berval ***bvals);
10 years, 4 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Richard Allen Megginson
ldap/servers/slapd/daemon.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
New commits:
commit d1754414bffca63ceec42812387e233c717fe14e
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Wed Apr 24 20:36:37 2013 -0600
Ticket #47349 - DS instance crashes under a high load
https://fedorahosted.org/389/ticket/47349
Reviewed by: nkinder (Thanks!)
Branch: 389-ds-base-1.2.11
Fix Description: handle_new_connection initializes the connection object,
then calls connection_table_move_connection_on_to_active_list to put it
on the list of active connections, then unlocks the c_mutex, then calls
connection_new_private to allocate c_private. If another thread
interrupts after the conn has been moved to the active list, but before
c_private has been allocated, the new conn will be available via
connection_table_iterate_active_connections where table_iterate_function
will attempt to dereference the NULL c_private.
The fix is to move connection_new_private inside the c_mutex lock, and to
move connection_table_move_connection_on_to_active_list to be the very last
thing before releasing the c_mutex lock. Once the conn is on the active
list it is live and we cannot do anything else to it.
Note: I have still not been able to reproduce the problem in a non-debug
optimized build.
Platforms tested: RHEL6 x86_64
Note: Before patch, server would crash within 5 minutes. After patch, server
has been running for several days in customer environment.
Flag Day: no
Doc impact: no
(cherry picked from commit 05d209432571dc64b242ae47113ae4cbb43607d2)
(cherry picked from commit 11c0f99aaa2deead80bde7e35dd9f9aabac5cc20)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index de7f18c..3f3061c 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -2694,16 +2694,6 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
/* Call the plugin extension constructors */
conn->c_extension = factory_create_extension(connection_type,conn,NULL /* Parent */);
-
- /* Add this connection slot to the doubly linked list of active connections. This
- * list is used to find the connections that should be used in the poll call. This
- * connection will be added directly after slot 0 which serves as the head of the list */
- if ( conn != NULL && conn->c_next == NULL && conn->c_prev == NULL )
- {
- /* Now give the new connection to the connection code */
- connection_table_move_connection_on_to_active_list(the_connection_table,conn);
- }
-
#if defined(ENABLE_LDAPI)
#if !defined( XP_WIN32 )
/* ldapi */
@@ -2716,10 +2706,21 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
#endif
#endif /* ENABLE_LDAPI */
- PR_Unlock( conn->c_mutex );
-
connection_new_private(conn);
+ /* Add this connection slot to the doubly linked list of active connections. This
+ * list is used to find the connections that should be used in the poll call. This
+ * connection will be added directly after slot 0 which serves as the head of the list.
+ * This must be done as the very last thing before we unlock the mutex, because once it
+ * is added to the active list, it is live. */
+ if ( conn != NULL && conn->c_next == NULL && conn->c_prev == NULL )
+ {
+ /* Now give the new connection to the connection code */
+ connection_table_move_connection_on_to_active_list(the_connection_table,conn);
+ }
+
+ PR_Unlock( conn->c_mutex );
+
g_increment_current_conn_count();
return 0;
10 years, 4 months
Branch '389-ds-base-1.3.0' - ldap/servers
by Richard Allen Megginson
ldap/servers/slapd/daemon.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
New commits:
commit 11c0f99aaa2deead80bde7e35dd9f9aabac5cc20
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Wed Apr 24 20:36:37 2013 -0600
Ticket #47349 - DS instance crashes under a high load
https://fedorahosted.org/389/ticket/47349
Reviewed by: nkinder (Thanks!)
Branch: 389-ds-base-1.3.0
Fix Description: handle_new_connection initializes the connection object,
then calls connection_table_move_connection_on_to_active_list to put it
on the list of active connections, then unlocks the c_mutex, then calls
connection_new_private to allocate c_private. If another thread
interrupts after the conn has been moved to the active list, but before
c_private has been allocated, the new conn will be available via
connection_table_iterate_active_connections where table_iterate_function
will attempt to dereference the NULL c_private.
The fix is to move connection_new_private inside the c_mutex lock, and to
move connection_table_move_connection_on_to_active_list to be the very last
thing before releasing the c_mutex lock. Once the conn is on the active
list it is live and we cannot do anything else to it.
Note: I have still not been able to reproduce the problem in a non-debug
optimized build.
Platforms tested: RHEL6 x86_64
Note: Before patch, server would crash within 5 minutes. After patch, server
has been running for several days in customer environment.
Flag Day: no
Doc impact: no
(cherry picked from commit 05d209432571dc64b242ae47113ae4cbb43607d2)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 1fd40f6..18ca091 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -2699,16 +2699,6 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
/* Call the plugin extension constructors */
conn->c_extension = factory_create_extension(connection_type,conn,NULL /* Parent */);
-
- /* Add this connection slot to the doubly linked list of active connections. This
- * list is used to find the connections that should be used in the poll call. This
- * connection will be added directly after slot 0 which serves as the head of the list */
- if ( conn != NULL && conn->c_next == NULL && conn->c_prev == NULL )
- {
- /* Now give the new connection to the connection code */
- connection_table_move_connection_on_to_active_list(the_connection_table,conn);
- }
-
#if defined(ENABLE_LDAPI)
#if !defined( XP_WIN32 )
/* ldapi */
@@ -2721,10 +2711,21 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
#endif
#endif /* ENABLE_LDAPI */
- PR_Unlock( conn->c_mutex );
-
connection_new_private(conn);
+ /* Add this connection slot to the doubly linked list of active connections. This
+ * list is used to find the connections that should be used in the poll call. This
+ * connection will be added directly after slot 0 which serves as the head of the list.
+ * This must be done as the very last thing before we unlock the mutex, because once it
+ * is added to the active list, it is live. */
+ if ( conn != NULL && conn->c_next == NULL && conn->c_prev == NULL )
+ {
+ /* Now give the new connection to the connection code */
+ connection_table_move_connection_on_to_active_list(the_connection_table,conn);
+ }
+
+ PR_Unlock( conn->c_mutex );
+
g_increment_current_conn_count();
return 0;
10 years, 4 months
Branch '389-ds-base-1.3.0' - ldap/servers
by Richard Allen Megginson
ldap/servers/slapd/daemon.c | 115 +++++++++++++++++++++++---------------------
1 file changed, 62 insertions(+), 53 deletions(-)
New commits:
commit e0328aba6ed9254cf537f85927c55cbbb82cae77
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Fri May 10 15:11:13 2013 -0600
Ticket #47359 - new ldap connections can block ldaps and ldapi connections
https://fedorahosted.org/389/ticket/47359
Reviewed by: lkrispen, nhosoi (Thanks!)
Branch: 389-ds-base-1.3.0
Fix Description: description
In the polling thread, first process all of the new connection requests from
the listening sockets, then process any new operation read requests
The listener_idxs keeps track of the index of the active listeners in the
poll fd array, and keeps a pointer to the listenfd object for that
listener. This allows us to very quickly scan through the poll fd array
and find the ready listeners. The work of scanning through the array
and handling the new connection requests has been moved to a new function
handle_listeners().
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 115ab1d9a3f026e8523b91bf62245a25454a3e8a)
(cherry picked from commit 24b751cc724468a7bce5f86848a82e4b03e24a3c)
(cherry picked from commit 5226ed9f2e585dc3d561f9286555efc7e3eea6b6)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index b59a195..1fd40f6 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -138,6 +138,15 @@ void disk_monitoring_stop();
#define FDS_SIGNAL_PIPE 0
+typedef struct listener_info {
+ int idx; /* index of this listener in the ct->fd array */
+ PRFileDesc *listenfd; /* the listener fd */
+ int secure;
+ int local;
+} listener_info;
+
+#define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
+
static int get_configured_connection_table_size();
#ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
static void get_loopback_by_addr( void );
@@ -151,7 +160,7 @@ static PRFileDesc **createprlistensockets(unsigned short port,
static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
size_t addrbuflen);
static void set_shutdown (int);
-static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read);
+static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
#ifdef HPUX10
static void* catch_signals();
@@ -917,6 +926,30 @@ disk_monitoring_thread(void *nothing)
}
}
+static void
+handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_listeners)
+{
+ int idx;
+ for (idx = 0; idx < n_listeners; ++idx) {
+ int fdidx = listener_idxs[idx].idx;
+ PRFileDesc *listenfd = listener_idxs[idx].listenfd;
+ int secure = listener_idxs[idx].secure;
+ int local = listener_idxs[idx].local;
+ if (fdidx && listenfd) {
+ if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
+ /* accept() the new connection, put it on the active list for handle_pr_read_ready */
+ int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local);
+ if (rc) {
+ LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
+ PR_FileDesc2NativeHandle(listenfd));
+ continue;
+ }
+ }
+ }
+ }
+ return;
+}
+
void slapd_daemon( daemon_ports_t *ports )
{
/* We are passed some ports---one for regular connections, one
@@ -933,7 +966,6 @@ void slapd_daemon( daemon_ports_t *ports )
int s_tcps_native = 0;
PRFileDesc *s_tcps = NULL;
#else
- PRFileDesc *tcps = 0;
PRFileDesc **n_tcps = NULL;
PRFileDesc **s_tcps = NULL;
PRFileDesc **i_unix = NULL;
@@ -944,6 +976,8 @@ void slapd_daemon( daemon_ports_t *ports )
PRThread *time_thread_p;
int threads;
int in_referral_mode = config_check_referral_mode();
+ int n_listeners = 0; /* number of listener sockets */
+ listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
int connection_table_size = get_configured_connection_table_size();
the_connection_table= connection_table_new(connection_table_size);
@@ -1058,6 +1092,7 @@ void slapd_daemon( daemon_ports_t *ports )
netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
ports->n_port, oserr, slapd_system_strerror( oserr ) );
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ n_listeners++;
}
#else
if ( n_tcps != NULL ) {
@@ -1075,6 +1110,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif
@@ -1094,6 +1130,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
@@ -1112,11 +1149,13 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif /* ENABLE_LDAPI */
#endif
+ listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
/* Now we write the pid file, indicating that the server is finally and listening for connections */
write_pid_file();
@@ -1129,9 +1168,6 @@ void slapd_daemon( daemon_ports_t *ports )
int oserr;
#endif
int select_return = 0;
- int secure = 0; /* is a new connection an SSL one ? */
- int local = 0; /* is new connection an ldapi one? */
- int i;
#ifndef _WIN32
PRErrorCode prerr;
@@ -1143,7 +1179,7 @@ void slapd_daemon( daemon_ports_t *ports )
/* This select needs to timeout to give the server a chance to test for shutdown */
select_return = select(connection_table_size, &readfds, NULL, 0, &wakeup_timer);
#else
- setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
+ setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
select_return = POLL_FN(the_connection_table->fd, num_poll, pr_timeout);
#endif
switch (select_return) {
@@ -1179,52 +1215,8 @@ void slapd_daemon( daemon_ports_t *ports )
handle_read_ready(the_connection_table,&readfds);
clear_signal(&readfds);
#else
- tcps = NULL;
- /* info for n_tcps is always in fd[n_tcps ~ n_tcpe] */
- if( NULL != n_tcps ) {
- for (i = the_connection_table->n_tcps;
- i < the_connection_table->n_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = n_tcps[i - the_connection_table->n_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- break;
- }
- }
- }
- /* info for s_tcps is always in fd[s_tcps ~ s_tcpe] */
- if ( NULL == tcps && NULL != s_tcps ) {
- for (i = the_connection_table->s_tcps;
- i < the_connection_table->s_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = s_tcps[i - the_connection_table->s_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- secure = 1;
- break;
- }
- }
- }
-#if defined(ENABLE_LDAPI)
- /* info for i_unix is always in fd[i_unixs ~ i_unixe] */
- if ( NULL == tcps && NULL != i_unix ) {
- for (i = the_connection_table->i_unixs;
- i < the_connection_table->i_unixe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = i_unix[i - the_connection_table->i_unixs]; */
- tcps = the_connection_table->fd[i].fd;
- local = 1;
- break;
- }
- }
- }
-#endif /* ENABLE_LDAPI */
-
- /* If so, then handle a new connection */
- if ( tcps != NULL ) {
- handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,tcps,secure,local);
- }
+ /* handle new connections from the listeners */
+ handle_listeners(the_connection_table, listener_idxs, n_listeners);
/* handle new data ready */
handle_pr_read_ready(the_connection_table, connection_table_size);
clear_signal(the_connection_table->fd);
@@ -1545,7 +1537,7 @@ static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, in
static int first_time_setup_pr_read_pds = 1;
static int listen_addr_count = 0;
static void
-setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read)
+setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners)
{
Connection *c= NULL;
Connection *next= NULL;
@@ -1555,6 +1547,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
PRIntn count = 0;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
int max_threads_per_conn = config_get_maxthreadsperconn();
+ int n_listeners = 0;
accept_new_connections = ((ct->size - g_get_current_conn_count())
> slapdFrontendConfig->reservedescriptors);
@@ -1606,6 +1599,9 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for connections on %d\n", socketdesc, 0, 0 );
}
@@ -1624,6 +1620,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].secure = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for SSL connections on %d\n", socketdesc, 0, 0 );
}
@@ -1645,6 +1645,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].local = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for LDAPI connections on %d\n", socketdesc, 0, 0 );
}
@@ -1658,6 +1662,11 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
first_time_setup_pr_read_pds = 0;
listen_addr_count = count;
+
+ if (n_listeners < max_listeners) {
+ listener_idxs[n_listeners].idx = 0;
+ listener_idxs[n_listeners].listenfd = NULL;
+ }
}
/* count is the number of entries we've place in the fds array.
10 years, 4 months
Branch '389-ds-base-1.3.1' - ldap/servers
by Richard Allen Megginson
ldap/servers/slapd/daemon.c | 115 +++++++++++++++++++++++---------------------
1 file changed, 62 insertions(+), 53 deletions(-)
New commits:
commit 5226ed9f2e585dc3d561f9286555efc7e3eea6b6
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Fri May 10 15:11:13 2013 -0600
Ticket #47359 - new ldap connections can block ldaps and ldapi connections
https://fedorahosted.org/389/ticket/47359
Reviewed by: lkrispen, nhosoi (Thanks!)
Branch: 389-ds-base-1.3.1
Fix Description: description
In the polling thread, first process all of the new connection requests from
the listening sockets, then process any new operation read requests
The listener_idxs keeps track of the index of the active listeners in the
poll fd array, and keeps a pointer to the listenfd object for that
listener. This allows us to very quickly scan through the poll fd array
and find the ready listeners. The work of scanning through the array
and handling the new connection requests has been moved to a new function
handle_listeners().
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 115ab1d9a3f026e8523b91bf62245a25454a3e8a)
(cherry picked from commit 24b751cc724468a7bce5f86848a82e4b03e24a3c)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 4dd051d..b0e0ed2 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -138,6 +138,15 @@ void disk_monitoring_stop();
#define FDS_SIGNAL_PIPE 0
+typedef struct listener_info {
+ int idx; /* index of this listener in the ct->fd array */
+ PRFileDesc *listenfd; /* the listener fd */
+ int secure;
+ int local;
+} listener_info;
+
+#define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
+
static int get_configured_connection_table_size();
#ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
static void get_loopback_by_addr( void );
@@ -151,7 +160,7 @@ static PRFileDesc **createprlistensockets(unsigned short port,
static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
size_t addrbuflen);
static void set_shutdown (int);
-static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read);
+static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
#ifdef HPUX10
static void* catch_signals();
@@ -917,6 +926,30 @@ disk_monitoring_thread(void *nothing)
}
}
+static void
+handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_listeners)
+{
+ int idx;
+ for (idx = 0; idx < n_listeners; ++idx) {
+ int fdidx = listener_idxs[idx].idx;
+ PRFileDesc *listenfd = listener_idxs[idx].listenfd;
+ int secure = listener_idxs[idx].secure;
+ int local = listener_idxs[idx].local;
+ if (fdidx && listenfd) {
+ if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
+ /* accept() the new connection, put it on the active list for handle_pr_read_ready */
+ int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local);
+ if (rc) {
+ LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
+ PR_FileDesc2NativeHandle(listenfd));
+ continue;
+ }
+ }
+ }
+ }
+ return;
+}
+
void slapd_daemon( daemon_ports_t *ports )
{
/* We are passed some ports---one for regular connections, one
@@ -933,7 +966,6 @@ void slapd_daemon( daemon_ports_t *ports )
int s_tcps_native = 0;
PRFileDesc *s_tcps = NULL;
#else
- PRFileDesc *tcps = 0;
PRFileDesc **n_tcps = NULL;
PRFileDesc **s_tcps = NULL;
PRFileDesc **i_unix = NULL;
@@ -944,6 +976,8 @@ void slapd_daemon( daemon_ports_t *ports )
PRThread *time_thread_p;
int threads;
int in_referral_mode = config_check_referral_mode();
+ int n_listeners = 0; /* number of listener sockets */
+ listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
int connection_table_size = get_configured_connection_table_size();
the_connection_table= connection_table_new(connection_table_size);
@@ -1058,6 +1092,7 @@ void slapd_daemon( daemon_ports_t *ports )
netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
ports->n_port, oserr, slapd_system_strerror( oserr ) );
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ n_listeners++;
}
#else
if ( n_tcps != NULL ) {
@@ -1075,6 +1110,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif
@@ -1094,6 +1130,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
@@ -1112,11 +1149,13 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif /* ENABLE_LDAPI */
#endif
+ listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
/* Now we write the pid file, indicating that the server is finally and listening for connections */
write_pid_file();
@@ -1129,9 +1168,6 @@ void slapd_daemon( daemon_ports_t *ports )
int oserr;
#endif
int select_return = 0;
- int secure = 0; /* is a new connection an SSL one ? */
- int local = 0; /* is new connection an ldapi one? */
- int i;
#ifndef _WIN32
PRErrorCode prerr;
@@ -1143,7 +1179,7 @@ void slapd_daemon( daemon_ports_t *ports )
/* This select needs to timeout to give the server a chance to test for shutdown */
select_return = select(connection_table_size, &readfds, NULL, 0, &wakeup_timer);
#else
- setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
+ setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
select_return = POLL_FN(the_connection_table->fd, num_poll, pr_timeout);
#endif
switch (select_return) {
@@ -1179,52 +1215,8 @@ void slapd_daemon( daemon_ports_t *ports )
handle_read_ready(the_connection_table,&readfds);
clear_signal(&readfds);
#else
- tcps = NULL;
- /* info for n_tcps is always in fd[n_tcps ~ n_tcpe] */
- if( NULL != n_tcps ) {
- for (i = the_connection_table->n_tcps;
- i < the_connection_table->n_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = n_tcps[i - the_connection_table->n_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- break;
- }
- }
- }
- /* info for s_tcps is always in fd[s_tcps ~ s_tcpe] */
- if ( NULL == tcps && NULL != s_tcps ) {
- for (i = the_connection_table->s_tcps;
- i < the_connection_table->s_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = s_tcps[i - the_connection_table->s_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- secure = 1;
- break;
- }
- }
- }
-#if defined(ENABLE_LDAPI)
- /* info for i_unix is always in fd[i_unixs ~ i_unixe] */
- if ( NULL == tcps && NULL != i_unix ) {
- for (i = the_connection_table->i_unixs;
- i < the_connection_table->i_unixe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = i_unix[i - the_connection_table->i_unixs]; */
- tcps = the_connection_table->fd[i].fd;
- local = 1;
- break;
- }
- }
- }
-#endif /* ENABLE_LDAPI */
-
- /* If so, then handle a new connection */
- if ( tcps != NULL ) {
- handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,tcps,secure,local);
- }
+ /* handle new connections from the listeners */
+ handle_listeners(the_connection_table, listener_idxs, n_listeners);
/* handle new data ready */
handle_pr_read_ready(the_connection_table, connection_table_size);
clear_signal(the_connection_table->fd);
@@ -1545,7 +1537,7 @@ static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, in
static int first_time_setup_pr_read_pds = 1;
static int listen_addr_count = 0;
static void
-setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read)
+setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners)
{
Connection *c= NULL;
Connection *next= NULL;
@@ -1555,6 +1547,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
PRIntn count = 0;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
int max_threads_per_conn = config_get_maxthreadsperconn();
+ int n_listeners = 0;
accept_new_connections = ((ct->size - g_get_current_conn_count())
> slapdFrontendConfig->reservedescriptors);
@@ -1606,6 +1599,9 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for connections on %d\n", socketdesc, 0, 0 );
}
@@ -1624,6 +1620,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].secure = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for SSL connections on %d\n", socketdesc, 0, 0 );
}
@@ -1645,6 +1645,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].local = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for LDAPI connections on %d\n", socketdesc, 0, 0 );
}
@@ -1658,6 +1662,11 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
first_time_setup_pr_read_pds = 0;
listen_addr_count = count;
+
+ if (n_listeners < max_listeners) {
+ listener_idxs[n_listeners].idx = 0;
+ listener_idxs[n_listeners].listenfd = NULL;
+ }
}
/* count is the number of entries we've place in the fds array.
10 years, 4 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Richard Allen Megginson
ldap/servers/slapd/daemon.c | 115 +++++++++++++++++++++++---------------------
1 file changed, 62 insertions(+), 53 deletions(-)
New commits:
commit 8a1fd0711e060aca3943ca346005bb43eddf82c4
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Fri May 10 15:11:13 2013 -0600
Ticket #47359 - new ldap connections can block ldaps and ldapi connections
https://fedorahosted.org/389/ticket/47359
Reviewed by: lkrispen, nhosoi (Thanks!)
Branch: 389-ds-base-1.2.11
Fix Description: description
In the polling thread, first process all of the new connection requests from
the listening sockets, then process any new operation read requests
The listener_idxs keeps track of the index of the active listeners in the
poll fd array, and keeps a pointer to the listenfd object for that
listener. This allows us to very quickly scan through the poll fd array
and find the ready listeners. The work of scanning through the array
and handling the new connection requests has been moved to a new function
handle_listeners().
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 115ab1d9a3f026e8523b91bf62245a25454a3e8a)
(cherry picked from commit 24b751cc724468a7bce5f86848a82e4b03e24a3c)
(cherry picked from commit 5226ed9f2e585dc3d561f9286555efc7e3eea6b6)
(cherry picked from commit e0328aba6ed9254cf537f85927c55cbbb82cae77)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 4a5fd4d..de7f18c 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -136,6 +136,15 @@ void disk_monitoring_stop();
#define FDS_SIGNAL_PIPE 0
+typedef struct listener_info {
+ int idx; /* index of this listener in the ct->fd array */
+ PRFileDesc *listenfd; /* the listener fd */
+ int secure;
+ int local;
+} listener_info;
+
+#define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
+
static int get_configured_connection_table_size();
#ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
static void get_loopback_by_addr( void );
@@ -149,7 +158,7 @@ static PRFileDesc **createprlistensockets(unsigned short port,
static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
size_t addrbuflen);
static void set_shutdown (int);
-static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read);
+static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
#ifdef HPUX10
static void* catch_signals();
@@ -915,6 +924,30 @@ disk_monitoring_thread(void *nothing)
}
}
+static void
+handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_listeners)
+{
+ int idx;
+ for (idx = 0; idx < n_listeners; ++idx) {
+ int fdidx = listener_idxs[idx].idx;
+ PRFileDesc *listenfd = listener_idxs[idx].listenfd;
+ int secure = listener_idxs[idx].secure;
+ int local = listener_idxs[idx].local;
+ if (fdidx && listenfd) {
+ if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
+ /* accept() the new connection, put it on the active list for handle_pr_read_ready */
+ int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local);
+ if (rc) {
+ LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
+ PR_FileDesc2NativeHandle(listenfd));
+ continue;
+ }
+ }
+ }
+ }
+ return;
+}
+
void slapd_daemon( daemon_ports_t *ports )
{
/* We are passed some ports---one for regular connections, one
@@ -931,7 +964,6 @@ void slapd_daemon( daemon_ports_t *ports )
int s_tcps_native = 0;
PRFileDesc *s_tcps = NULL;
#else
- PRFileDesc *tcps = 0;
PRFileDesc **n_tcps = NULL;
PRFileDesc **s_tcps = NULL;
PRFileDesc **i_unix = NULL;
@@ -942,6 +974,8 @@ void slapd_daemon( daemon_ports_t *ports )
PRThread *time_thread_p;
int threads;
int in_referral_mode = config_check_referral_mode();
+ int n_listeners = 0; /* number of listener sockets */
+ listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
int connection_table_size = get_configured_connection_table_size();
the_connection_table= connection_table_new(connection_table_size);
@@ -1056,6 +1090,7 @@ void slapd_daemon( daemon_ports_t *ports )
netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
ports->n_port, oserr, slapd_system_strerror( oserr ) );
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ n_listeners++;
}
#else
if ( n_tcps != NULL ) {
@@ -1073,6 +1108,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif
@@ -1092,6 +1128,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
@@ -1110,11 +1147,13 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif /* ENABLE_LDAPI */
#endif
+ listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
/* Now we write the pid file, indicating that the server is finally and listening for connections */
write_pid_file();
@@ -1127,9 +1166,6 @@ void slapd_daemon( daemon_ports_t *ports )
int oserr;
#endif
int select_return = 0;
- int secure = 0; /* is a new connection an SSL one ? */
- int local = 0; /* is new connection an ldapi one? */
- int i;
#ifndef _WIN32
PRErrorCode prerr;
@@ -1141,7 +1177,7 @@ void slapd_daemon( daemon_ports_t *ports )
/* This select needs to timeout to give the server a chance to test for shutdown */
select_return = select(connection_table_size, &readfds, NULL, 0, &wakeup_timer);
#else
- setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
+ setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
select_return = POLL_FN(the_connection_table->fd, num_poll, pr_timeout);
#endif
switch (select_return) {
@@ -1177,52 +1213,8 @@ void slapd_daemon( daemon_ports_t *ports )
handle_read_ready(the_connection_table,&readfds);
clear_signal(&readfds);
#else
- tcps = NULL;
- /* info for n_tcps is always in fd[n_tcps ~ n_tcpe] */
- if( NULL != n_tcps ) {
- for (i = the_connection_table->n_tcps;
- i < the_connection_table->n_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = n_tcps[i - the_connection_table->n_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- break;
- }
- }
- }
- /* info for s_tcps is always in fd[s_tcps ~ s_tcpe] */
- if ( NULL == tcps && NULL != s_tcps ) {
- for (i = the_connection_table->s_tcps;
- i < the_connection_table->s_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = s_tcps[i - the_connection_table->s_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- secure = 1;
- break;
- }
- }
- }
-#if defined(ENABLE_LDAPI)
- /* info for i_unix is always in fd[i_unixs ~ i_unixe] */
- if ( NULL == tcps && NULL != i_unix ) {
- for (i = the_connection_table->i_unixs;
- i < the_connection_table->i_unixe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = i_unix[i - the_connection_table->i_unixs]; */
- tcps = the_connection_table->fd[i].fd;
- local = 1;
- break;
- }
- }
- }
-#endif /* ENABLE_LDAPI */
-
- /* If so, then handle a new connection */
- if ( tcps != NULL ) {
- handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,tcps,secure,local);
- }
+ /* handle new connections from the listeners */
+ handle_listeners(the_connection_table, listener_idxs, n_listeners);
/* handle new data ready */
handle_pr_read_ready(the_connection_table, connection_table_size);
clear_signal(the_connection_table->fd);
@@ -1543,7 +1535,7 @@ static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, in
static int first_time_setup_pr_read_pds = 1;
static int listen_addr_count = 0;
static void
-setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read)
+setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners)
{
Connection *c= NULL;
Connection *next= NULL;
@@ -1553,6 +1545,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
PRIntn count = 0;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
int max_threads_per_conn = config_get_maxthreadsperconn();
+ int n_listeners = 0;
accept_new_connections = ((ct->size - g_get_current_conn_count())
> slapdFrontendConfig->reservedescriptors);
@@ -1604,6 +1597,9 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for connections on %d\n", socketdesc, 0, 0 );
}
@@ -1622,6 +1618,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].secure = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for SSL connections on %d\n", socketdesc, 0, 0 );
}
@@ -1643,6 +1643,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].local = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for LDAPI connections on %d\n", socketdesc, 0, 0 );
}
@@ -1656,6 +1660,11 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
first_time_setup_pr_read_pds = 0;
listen_addr_count = count;
+
+ if (n_listeners < max_listeners) {
+ listener_idxs[n_listeners].idx = 0;
+ listener_idxs[n_listeners].listenfd = NULL;
+ }
}
/* count is the number of entries we've place in the fds array.
10 years, 4 months