From: Howard Chu Date: Mon, 28 Oct 2019 23:01:08 +0000 (+0000) Subject: ITS#9112 cleaner error handling during connection setup X-Git-Tag: OPENLDAP_REL_ENG_2_4_49~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=934055a11bf28a6f07347311bef2e03806e6a7d3;p=thirdparty%2Fopenldap.git ITS#9112 cleaner error handling during connection setup And additional debug code for tracking errant close()s --- diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 704067c55f..479c1dfb73 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -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 ); diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index bffde22e5e..deac8884b9 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -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 +#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 ); } diff --git a/servers/slapd/main.c b/servers/slapd/main.c index de086d73c1..84548313c4 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -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 ) {