]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/connection.c
zero out sml_managing any time a Modifications is built (use calloc?)
[openldap] / servers / slapd / connection.c
index d56b666d7576c52a6d55cfa9699dbe2a1d609c7a..217ba8da08812a91fb7035201cb69957c8e85522 100644 (file)
@@ -26,7 +26,9 @@
 #include "portable.h"
 
 #include <stdio.h>
+#ifdef HAVE_LIMITS_H
 #include <limits.h>
+#endif
 
 #include <ac/socket.h>
 #include <ac/errno.h>
@@ -48,6 +50,8 @@ static Connection *connections = NULL;
 static ldap_pvt_thread_mutex_t conn_nextid_mutex;
 static unsigned long conn_nextid = 0;
 
+static const char conn_lost_str[] = "connection lost";
+
 /* structure state (protected by connections_mutex) */
 #define SLAP_C_UNINITIALIZED   0x00    /* MUST BE ZERO (0) */
 #define SLAP_C_UNUSED                  0x01
@@ -189,7 +193,7 @@ int connections_shutdown(void)
                ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
 
                /* connections_mutex and c_mutex are locked */
-               connection_closing( &connections[i] );
+               connection_closing( &connections[i], "slapd shutdown" );
                connection_close( &connections[i] );
 
                ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
@@ -220,7 +224,7 @@ int connections_timeout_idle(time_t now)
 
                if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
                        /* close it */
-                       connection_closing( c );
+                       connection_closing( c, "idletimeout" );
                        connection_close( c );
                        i++;
                }
@@ -490,6 +494,7 @@ long connection_init(
        if ( flags == CONN_IS_CLIENT ) {
                c->c_conn_state = SLAP_C_CLIENT;
                c->c_struct_state = SLAP_C_USED;
+               c->c_close_reason = "?";                        /* should never be needed */
                ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s );
                ldap_pvt_thread_mutex_unlock( &c->c_mutex );
                ldap_pvt_thread_mutex_unlock( &connections_mutex );
@@ -561,6 +566,7 @@ long connection_init(
 
        c->c_conn_state = SLAP_C_INACTIVE;
        c->c_struct_state = SLAP_C_USED;
+       c->c_close_reason = "?";                        /* should never be needed */
 
        c->c_ssf = c->c_transport_ssf = ssf;
        c->c_tls_ssf = 0;
@@ -596,19 +602,23 @@ void connection2anonymous( Connection *c )
                ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
        }
 
-       if(c->c_authmech.bv_val != NULL ) {
-               free(c->c_authmech.bv_val);
+       if ( !BER_BVISNULL( &c->c_authmech ) ) {
+               ch_free(c->c_authmech.bv_val);
        }
        BER_BVZERO( &c->c_authmech );
 
-       if(c->c_dn.bv_val != NULL) {
-               free(c->c_dn.bv_val);
+       if ( !BER_BVISNULL( &c->c_dn ) ) {
+               ch_free(c->c_dn.bv_val);
        }
        BER_BVZERO( &c->c_dn );
-       if(c->c_ndn.bv_val != NULL) {
-               free(c->c_ndn.bv_val);
+       if ( !BER_BVISNULL( &c->c_ndn ) ) {
+               ch_free(c->c_ndn.bv_val);
        }
        BER_BVZERO( &c->c_ndn );
+       if ( !BER_BVISNULL( &c->c_sasl_authz_dn ) ) {
+               ber_memfree_x( c->c_sasl_authz_dn.bv_val, NULL );
+       }
+       BER_BVZERO( &c->c_sasl_authz_dn );
 
        c->c_authz_backend = NULL;
 }
@@ -619,6 +629,7 @@ connection_destroy( Connection *c )
        /* note: connections_mutex should be locked by caller */
        ber_socket_t    sd;
        unsigned long   connid;
+       const char              *close_reason;
 
        assert( connections != NULL );
        assert( c != NULL );
@@ -629,6 +640,7 @@ connection_destroy( Connection *c )
 
        /* only for stats (print -1 as "%lu" may give unexpected results ;) */
        connid = c->c_connid;
+       close_reason = c->c_close_reason;
 
        backend_connection_destroy(c);
 
@@ -666,9 +678,10 @@ connection_destroy( Connection *c )
        if ( sd != AC_SOCKET_INVALID ) {
                slapd_remove( sd, 1, 0 );
 
-               Statslog( LDAP_DEBUG_STATS,
-                       "conn=%lu fd=%ld closed\n",
-                       connid, (long) sd, 0, 0, 0 );
+               Statslog( LDAP_DEBUG_STATS, (close_reason
+                                                                        ? "conn=%lu fd=%ld closed (%s)\n"
+                                                                        : "conn=%lu fd=%ld closed\n"),
+                       connid, (long) sd, close_reason, 0, 0 );
        }
 
        ber_sockbuf_free( c->c_sb );
@@ -682,6 +695,7 @@ connection_destroy( Connection *c )
 
        c->c_conn_state = SLAP_C_INVALID;
        c->c_struct_state = SLAP_C_UNUSED;
+       c->c_close_reason = "?";                        /* should never be needed */
 
 #ifdef LDAP_SLAPI
        /* call destructors, then constructors; avoids unnecessary allocation */
@@ -734,7 +748,7 @@ static void connection_abandon( Connection *c )
        }
 }
 
-void connection_closing( Connection *c )
+void connection_closing( Connection *c, const char *why )
 {
        assert( connections != NULL );
        assert( c != NULL );
@@ -752,6 +766,7 @@ void connection_closing( Connection *c )
                        c->c_connid, sd, 0 );
                /* update state to closing */
                c->c_conn_state = SLAP_C_CLOSING;
+               c->c_close_reason = why;
 
                /* don't listen on this port anymore */
                slapd_clr_read( sd, 1 );
@@ -761,7 +776,15 @@ void connection_closing( Connection *c )
 
                /* wake write blocked operations */
                slapd_clr_write( sd, 1 );
-               ldap_pvt_thread_cond_signal( &c->c_write_cv );
+               if ( c->c_writewaiter ) {
+                       ldap_pvt_thread_cond_signal( &c->c_write_cv );
+                       ldap_pvt_thread_mutex_unlock( &c->c_mutex );
+                       ldap_pvt_thread_yield();
+                       ldap_pvt_thread_mutex_lock( &c->c_mutex );
+               }
+       } else if( why == NULL && c->c_close_reason == conn_lost_str ) {
+               /* Client closed connection after doing Unbind. */
+               c->c_close_reason = NULL;
        }
 }
 
@@ -1074,7 +1097,8 @@ operations_error:
        case LBER_ERROR:
        case LDAP_REQ_UNBIND:
                /* c_mutex is locked */
-               connection_closing( conn );
+               connection_closing(
+                       conn, tag == LDAP_REQ_UNBIND ? NULL : "operations error" );
                break;
 
        case LDAP_REQ_BIND:
@@ -1133,6 +1157,7 @@ void connection_client_stop(
        c->c_listener = NULL;
        c->c_conn_state = SLAP_C_INVALID;
        c->c_struct_state = SLAP_C_UNUSED;
+       c->c_close_reason = "?";                        /* should never be needed */
        connection_return( c );
        slapd_remove( s, 0, 1 );
 }
@@ -1198,7 +1223,7 @@ int connection_read(ber_socket_t s)
                                s, rc, c->c_connid );
                        c->c_needs_tls_accept = 0;
                        /* connections_mutex and c_mutex are locked */
-                       connection_closing( c );
+                       connection_closing( c, "TLS negotiation failure" );
 
 #if 0
                        /* Drain input before close, to allow SSL error codes
@@ -1236,6 +1261,9 @@ int connection_read(ber_socket_t s)
                                        "unable to get TLS client DN, error=%d id=%lu\n",
                                        s, rc, c->c_connid );
                        }
+                       Statslog( LDAP_DEBUG_STATS,
+                               "conn=%lu TLS established tls_ssf=%u ssf=%u\n",
+                           c->c_connid, c->c_tls_ssf, c->c_ssf, 0, 0 );
                        slap_sasl_external( c, c->c_tls_ssf, &authid );
                        if ( authid.bv_val ) free( authid.bv_val );
                }
@@ -1270,7 +1298,7 @@ int connection_read(ber_socket_t s)
                                "error=%d id=%lu, closing\n",
                                s, rc, c->c_connid );
                        /* connections_mutex and c_mutex are locked */
-                       connection_closing( c );
+                       connection_closing( c, "SASL layer install failure" );
                        connection_close( c );
                        connection_return( c );
                        ldap_pvt_thread_mutex_unlock( &connections_mutex );
@@ -1299,7 +1327,7 @@ int connection_read(ber_socket_t s)
                        "connection_read(%d): input error=%d id=%lu, closing.\n",
                        s, rc, c->c_connid );
                /* connections_mutex and c_mutex are locked */
-               connection_closing( c );
+               connection_closing( c, conn_lost_str );
                connection_close( c );
                connection_return( c );
                ldap_pvt_thread_mutex_unlock( &connections_mutex );
@@ -1463,16 +1491,32 @@ connection_input(
         * already pending ops, let them go first.  Abandon operations
         * get exceptions to some, but not all, cases.
         */
-       if (tag != LDAP_REQ_ABANDON && conn->c_conn_state == SLAP_C_CLOSING) {
-               defer = "closing";
-       } else if (tag != LDAP_REQ_ABANDON && conn->c_writewaiter) {
-               defer = "awaiting write";
-       } else if (conn->c_n_ops_executing >= connection_pool_max/2) {
-               defer = "too many executing";
-       } else if (conn->c_conn_state == SLAP_C_BINDING) {
-               defer = "binding";
-       } else if (tag != LDAP_REQ_ABANDON && conn->c_n_ops_pending) {
-               defer = "pending operations";
+       switch( tag ){
+       default:
+               /* Abandon and Unbind are exempt from these checks */
+               if (conn->c_conn_state == SLAP_C_CLOSING) {
+                       defer = "closing";
+                       break;
+               } else if (conn->c_writewaiter) {
+                       defer = "awaiting write";
+                       break;
+               } else if (conn->c_n_ops_pending) {
+                       defer = "pending operations";
+                       break;
+               }
+               /* FALLTHRU */
+       case LDAP_REQ_ABANDON:
+               /* Unbind is exempt from these checks */
+               if (conn->c_n_ops_executing >= connection_pool_max/2) {
+                       defer = "too many executing";
+                       break;
+               } else if (conn->c_conn_state == SLAP_C_BINDING) {
+                       defer = "binding";
+                       break;
+               }
+               /* FALLTHRU */
+       case LDAP_REQ_UNBIND:
+               break;
        }
 
        if( defer ) {
@@ -1598,8 +1642,13 @@ static int connection_op_activate( Operation *op )
 
        if (!op->o_dn.bv_len) {
                op->o_authz = op->o_conn->c_authz;
-               ber_dupbv( &op->o_dn, &op->o_conn->c_dn );
-               ber_dupbv( &op->o_ndn, &op->o_conn->c_ndn );
+               if ( BER_BVISNULL( &op->o_conn->c_sasl_authz_dn )) {
+                       ber_dupbv( &op->o_dn, &op->o_conn->c_dn );
+                       ber_dupbv( &op->o_ndn, &op->o_conn->c_ndn );
+               } else {
+                       ber_dupbv( &op->o_dn, &op->o_conn->c_sasl_authz_dn );
+                       ber_dupbv( &op->o_ndn, &op->o_conn->c_sasl_authz_dn );
+               }
        }
        op->o_authtype = op->o_conn->c_authtype;
        ber_dupbv( &op->o_authmech, &op->o_conn->c_authmech );
@@ -1635,6 +1684,7 @@ static int connection_op_activate( Operation *op )
 int connection_write(ber_socket_t s)
 {
        Connection *c;
+       Operation *op;
 
        assert( connections != NULL );
 
@@ -1666,6 +1716,26 @@ int connection_write(ber_socket_t s)
        if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) {
                slapd_set_write( s, 1 );
        }
+       /* If there are ops pending because of a writewaiter, start
+        * one up.
+        */
+       while ((op = LDAP_STAILQ_FIRST( &c->c_pending_ops )) != NULL) {
+               if ( !c->c_writewaiter ) break;
+               if ( c->c_n_ops_executing > connection_pool_max/2 ) {
+                       break;
+               }
+               LDAP_STAILQ_REMOVE_HEAD( &c->c_pending_ops, o_next );
+               LDAP_STAILQ_NEXT(op, o_next) = NULL;
+               /* pending operations should not be marked for abandonment */
+               assert(!op->o_abandon);
+
+               c->c_n_ops_pending--;
+               c->c_n_ops_executing++;
+
+               connection_op_activate( op );
+
+               break;
+       }
        connection_return( c );
        ldap_pvt_thread_mutex_unlock( &connections_mutex );
        return 0;