]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9112 cleaner error handling during connection setup
authorHoward Chu <hyc@openldap.org>
Mon, 28 Oct 2019 23:01:08 +0000 (23:01 +0000)
committerQuanah Gibson-Mount <quanah@openldap.org>
Fri, 22 Nov 2019 17:42:35 +0000 (17:42 +0000)
And additional debug code for tracking errant close()s

servers/slapd/connection.c
servers/slapd/daemon.c
servers/slapd/main.c

index 704067c55ffddbd346d3a5488b7e247bb558bfe8..479c1dfb73be41c2164a8a0ce9ed3077a121fc3d 100644 (file)
@@ -541,6 +541,23 @@ Connection * connection_init(
                Debug( LDAP_DEBUG_ANY,
                        "connection_init(%d, %s): set nonblocking failed\n",
                        s, c->c_peer_name.bv_val, 0 );
+
+               c->c_listener = NULL;
+               if(c->c_peer_domain.bv_val != NULL) {
+                       free(c->c_peer_domain.bv_val);
+               }
+               BER_BVZERO( &c->c_peer_domain );
+               if(c->c_peer_name.bv_val != NULL) {
+                       free(c->c_peer_name.bv_val);
+               }
+               BER_BVZERO( &c->c_peer_name );
+
+               ber_sockbuf_free( c->c_sb );
+               c->c_sb = NULL;
+               c->c_sd = AC_SOCKET_INVALID;
+               ldap_pvt_thread_mutex_unlock( &c->c_mutex );
+
+               return NULL;
        }
 
        ldap_pvt_thread_mutex_lock( &conn_nextid_mutex );
index bffde22e5e736372b9b969c4884820334cfd8014..deac8884b9d9248a3c04efbe41174439fa50c321 100644 (file)
@@ -840,6 +840,50 @@ slapd_sock2fd( ber_socket_t s )
 }
 #endif
 
+#ifdef DEBUG_CLOSE
+/* Was used to find a bug causing slapd's descriptors to be closed
+ * out from under it. Tracked it down to a long-standing (from 2009)
+ * bug in Heimdal https://github.com/heimdal/heimdal/issues/431 .
+ * Leaving this here for future use, if necessary.
+ */
+#include <dlfcn.h>
+#ifndef RTLD_NEXT
+#define RTLD_NEXT      (void *)-1L
+#endif
+static char *newconns;
+typedef int (closefunc)(int fd);
+static closefunc *close_ptr;
+int close( int s )
+{
+       if (newconns) {
+               Debug( LDAP_DEBUG_CONNS,
+                       "daemon: close(%ld)\n", s, 0, 0 );
+               if (s >= 0 && s < dtblsize && newconns[s])
+                       assert(newconns[s] == 2);
+       }
+       return close_ptr ? close_ptr(s) : -1;
+}
+
+void slapd_debug_close()
+{
+       if (dtblsize)
+               newconns = ch_calloc(1, dtblsize);
+       close_ptr = dlsym(RTLD_NEXT, "close");
+}
+
+void slapd_set_close(int fd)
+{
+       newconns[fd] = 3;
+}
+#define SETUP_CLOSE()  slapd_debug_close()
+#define SET_CLOSE(fd)  slapd_set_close(fd)
+#define CLR_CLOSE(fd)  if (newconns[fd]) newconns[fd]--
+#else
+#define SETUP_CLOSE(fd)
+#define SET_CLOSE(fd)
+#define CLR_CLOSE(fd)
+#endif
+
 /*
  * Add a descriptor to daemon control
  *
@@ -903,6 +947,7 @@ slapd_remove(
        if ( waswriter ) slap_daemon[id].sd_nwriters--;
 
        SLAP_SOCK_DEL(id, s);
+       CLR_CLOSE(s);
 
        if ( sb )
                ber_sockbuf_free(sb);
@@ -1035,6 +1080,7 @@ slapd_close( ber_socket_t s )
 {
        Debug( LDAP_DEBUG_CONNS, "daemon: closing %ld\n",
                (long) s, 0, 0 );
+       CLR_CLOSE( SLAP_FD2SOCK(s) );
        tcp_close( SLAP_FD2SOCK(s) );
 #ifdef HAVE_WINSOCK
        slapd_sockdel( s );
@@ -1636,6 +1682,8 @@ slapd_daemon_init( const char *urls )
        dtblsize = FD_SETSIZE;
 #endif /* ! HAVE_SYSCONF && ! HAVE_GETDTABLESIZE */
 
+       SETUP_CLOSE();
+
        /* open a pipe (or something equivalent connected to itself).
         * we write a byte on this fd whenever we catch a signal. The main
         * loop will be select'ing on this socket, and will wake up when
@@ -1844,6 +1892,11 @@ slap_listener(
 #  endif /* LDAP_PF_LOCAL */
 
        s = accept( SLAP_FD2SOCK( sl->sl_sd ), (struct sockaddr *) &from, &len );
+       if ( s != AC_SOCKET_INVALID ) {
+               SET_CLOSE(s);
+       }
+       Debug( LDAP_DEBUG_CONNS,
+               "daemon: accept() = %ld\n", s, 0, 0 );
 
        /* Resume the listener FD to allow concurrent-processing of
         * additional incoming connections.
@@ -1915,6 +1968,8 @@ slap_listener(
                        Debug( LDAP_DEBUG_ANY,
                                "slapd(%ld): setsockopt(SO_KEEPALIVE) failed "
                                "errno=%d (%s)\n", (long) sfd, err, sock_errstr(err) );
+                       slapd_close(sfd);
+                       return 0;
                }
 #endif /* SO_KEEPALIVE */
 #ifdef TCP_NODELAY
@@ -1927,6 +1982,8 @@ slap_listener(
                        Debug( LDAP_DEBUG_ANY,
                                "slapd(%ld): setsockopt(TCP_NODELAY) failed "
                                "errno=%d (%s)\n", (long) sfd, err, sock_errstr(err) );
+                       slapd_close(sfd);
+                       return 0;
                }
 #endif /* TCP_NODELAY */
        }
@@ -3046,6 +3103,9 @@ slap_sig_wake( int sig )
 void
 slapd_add_internal( ber_socket_t s, int isactive )
 {
+       if (!isactive) {
+               SET_CLOSE(s);
+       }
        slapd_add( s, isactive, NULL, -1 );
 }
 
index de086d73c14b18318547e6c6c768fe1fd424cc7f..84548313c469df44f940675155d35f18b46d0816 100644 (file)
@@ -400,11 +400,16 @@ int main( int argc, char **argv )
 
        slap_sl_mem_init();
 
+
        (void) ldap_pvt_thread_initialize();
 
        serverName = lutil_progname( "slapd", argc, argv );
 
        if ( strcmp( serverName, "slapd" ) ) {
+#ifdef DEBUG_CLOSE
+               extern void slapd_debug_close();
+               slapd_debug_close();
+#endif
                for (i=0; tools[i].name; i++) {
                        if ( !strcmp( serverName, tools[i].name ) ) {
                                rc = tools[i].func(argc, argv);
@@ -649,6 +654,10 @@ int main( int argc, char **argv )
                                        optarg );
                        }
 
+#ifdef DEBUG_CLOSE
+                       extern void slapd_debug_close();
+                       slapd_debug_close();
+#endif
                        /* try full option string first */
                        for ( i = 0; tools[i].name; i++ ) {
                                if ( strcmp( optarg, &tools[i].name[4] ) == 0 ) {