From 4e51bba2176a3dc1bb88944f582afc6049f8ff69 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Wed, 15 May 2002 06:18:14 +0000 Subject: [PATCH] Patch: Implement surrogate parent for back-shell (ITS#1815) ================ Written by Hallvard B. Furuseth and placed into the public domain. This software is not subject to any license of the University of Oslo. ================ A surrogate parent is supposed to keep back-shell children from deadlocking due to resources locked by a threading parent. Implementation note: The surrogate parent closes all unused file descriptors, so it logs errors to stderr instead of via Debug() and uses relloc() instead of ch_realloc(). Also close a file descriptor leak if fork() fails in fork.c. Hallvard B. Furuseth , May 2002. --- configure | 29 +-- configure.in | 1 + include/portable.h.in | 3 + include/portable.nt | 3 + servers/slapd/back-shell/abandon.c | 2 +- servers/slapd/back-shell/add.c | 2 +- servers/slapd/back-shell/bind.c | 2 +- servers/slapd/back-shell/compare.c | 2 +- servers/slapd/back-shell/config.c | 40 +++- servers/slapd/back-shell/delete.c | 2 +- servers/slapd/back-shell/fork.c | 305 +++++++++++++++++++++++++++-- servers/slapd/back-shell/init.c | 34 +++- servers/slapd/back-shell/modify.c | 2 +- servers/slapd/back-shell/modrdn.c | 2 +- servers/slapd/back-shell/search.c | 3 +- servers/slapd/back-shell/shell.h | 45 ++++- servers/slapd/back-shell/unbind.c | 2 +- 17 files changed, 417 insertions(+), 62 deletions(-) diff --git a/configure b/configure index 60fddea76e..e7dd17ebd4 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # $OpenLDAP$ -# from OpenLDAP: pkg/ldap/configure.in,v 1.417 2002/05/13 16:48:37 kurt Exp +# from OpenLDAP: pkg/ldap/configure.in,v 1.418 2002/05/13 18:16:47 kurt Exp # Copyright 1998-2002 The OpenLDAP Foundation. All Rights Reserved. # @@ -19622,7 +19622,7 @@ else #if SASL_VERSION_MAJOR == 1 && SASL_VERSION_MINOR >= 5 char *__sasl_compat = "1.5.x okay"; #elif SASL_VERSION_MAJOR == 2 && SASL_VERSION_MINOR > 1 - __sasl_compat "2.2+ or better okay"; + __sasl_compat "2.2+ or better okay (we guess)"; #elif SASL_VERSION_MAJOR == 2 && SASL_VERSION_MINOR == 1 \ && SASL_VERSION_STEP >=3 __sasl_compat = "2.1.3+ or better okay"; @@ -21790,6 +21790,7 @@ for ac_func in \ read \ recv \ recvfrom \ + recvmsg \ setpwfile \ setgid \ setegid \ @@ -21818,12 +21819,12 @@ for ac_func in \ do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:21822: checking for $ac_func" >&5 +echo "configure:21823: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -21875,12 +21876,12 @@ done for ac_func in getopt do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:21879: checking for $ac_func" >&5 +echo "configure:21880: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21909: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -21937,13 +21938,13 @@ fi # Check Configuration echo $ac_n "checking declaration of sys_errlist""... $ac_c" 1>&6 -echo "configure:21941: checking declaration of sys_errlist" >&5 +echo "configure:21942: checking declaration of sys_errlist" >&5 if eval "test \"\${ol_cv_dcl_sys_errlist+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < @@ -21956,7 +21957,7 @@ int main() { char *c = (char *) *sys_errlist ; return 0; } EOF -if { (eval echo configure:21960: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:21961: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_dcl_sys_errlist=yes ol_cv_have_sys_errlist=yes @@ -21979,20 +21980,20 @@ EOF echo $ac_n "checking existence of sys_errlist""... $ac_c" 1>&6 -echo "configure:21983: checking existence of sys_errlist" >&5 +echo "configure:21984: checking existence of sys_errlist" >&5 if eval "test \"\${ol_cv_have_sys_errlist+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *c = (char *) *sys_errlist ; return 0; } EOF -if { (eval echo configure:21996: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21997: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_have_sys_errlist=yes else diff --git a/configure.in b/configure.in index c5c7003192..1b37a051c4 100644 --- a/configure.in +++ b/configure.in @@ -2426,6 +2426,7 @@ AC_CHECK_FUNCS( \ read \ recv \ recvfrom \ + recvmsg \ setpwfile \ setgid \ setegid \ diff --git a/include/portable.h.in b/include/portable.h.in index 2e2d7a9c7b..45964ed8ba 100644 --- a/include/portable.h.in +++ b/include/portable.h.in @@ -224,6 +224,9 @@ /* Define if you have the recvfrom function. */ #undef HAVE_RECVFROM +/* Define if you have the recvmsg function. */ +#undef HAVE_RECVMSG + /* Define if you have the sched_yield function. */ #undef HAVE_SCHED_YIELD diff --git a/include/portable.nt b/include/portable.nt index 921b3dd20e..8715d81a97 100644 --- a/include/portable.nt +++ b/include/portable.nt @@ -243,6 +243,9 @@ /* Define if you have the recvfrom function. */ /* #undef HAVE_RECVFROM */ +/* Define if you have the recvmsg function. */ +/* #undef HAVE_RECVMSG */ + /* Define if you have the sched_yield function. */ /* #undef HAVE_SCHED_YIELD */ diff --git a/servers/slapd/back-shell/abandon.c b/servers/slapd/back-shell/abandon.c index 1f5f3f092a..cae990af5b 100644 --- a/servers/slapd/back-shell/abandon.c +++ b/servers/slapd/back-shell/abandon.c @@ -29,7 +29,7 @@ shell_back_abandon( Operation *o; /* no abandon command defined - just kill the process handling it */ - if ( si->si_abandon == NULL ) { + if ( IS_NULLCMD( si->si_abandon ) ) { ldap_pvt_thread_mutex_lock( &conn->c_mutex ); pid = -1; LDAP_STAILQ_FOREACH( o, &conn->c_ops, o_next ) { diff --git a/servers/slapd/back-shell/add.c b/servers/slapd/back-shell/add.c index 528d3993e5..134416866b 100644 --- a/servers/slapd/back-shell/add.c +++ b/servers/slapd/back-shell/add.c @@ -27,7 +27,7 @@ shell_back_add( FILE *rfp, *wfp; int len; - if ( si->si_add == NULL ) { + if ( IS_NULLCMD( si->si_add ) ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, "add not implemented", NULL, NULL ); return( -1 ); diff --git a/servers/slapd/back-shell/bind.c b/servers/slapd/back-shell/bind.c index 024c41f663..fe36059215 100644 --- a/servers/slapd/back-shell/bind.c +++ b/servers/slapd/back-shell/bind.c @@ -31,7 +31,7 @@ shell_back_bind( FILE *rfp, *wfp; int rc; - if ( si->si_bind == NULL ) { + if ( IS_NULLCMD( si->si_bind ) ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, "bind not implemented", NULL, NULL ); return( -1 ); diff --git a/servers/slapd/back-shell/compare.c b/servers/slapd/back-shell/compare.c index 9ef16c5bc3..b5ef2d24eb 100644 --- a/servers/slapd/back-shell/compare.c +++ b/servers/slapd/back-shell/compare.c @@ -28,7 +28,7 @@ shell_back_compare( struct shellinfo *si = (struct shellinfo *) be->be_private; FILE *rfp, *wfp; - if ( si->si_compare == NULL ) { + if ( IS_NULLCMD( si->si_compare ) ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, "compare not implemented", NULL, NULL ); return( -1 ); diff --git a/servers/slapd/back-shell/config.c b/servers/slapd/back-shell/config.c index df730a9bd8..7c1e14e7ff 100644 --- a/servers/slapd/back-shell/config.c +++ b/servers/slapd/back-shell/config.c @@ -15,6 +15,28 @@ #include "slap.h" #include "shell.h" +#ifdef SHELL_SURROGATE_PARENT + +static struct berval make_cmd_info( + char **args +) +{ + struct berval ret = { 0, 0 }; + int i; + ber_len_t offset; + for( i = 0; args[i] != NULL; i++ ) + ret.bv_len += strlen( args[i] ) + 1; + ret.bv_val = ch_malloc( ret.bv_len ); + offset = 0; + for( i = 0; args[i] != NULL; i++ ) { + strcpy( ret.bv_val + offset, args[i] ); + offset += strlen( args[i] ) + 1; + } + return ret; +} + +#endif /* SHELL_SURROGATE_PARENT */ + int shell_back_db_config( BackendDB *be, @@ -40,7 +62,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_bind = charray_dup( &argv[1] ); + si->si_bind = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for unbinds */ } else if ( strcasecmp( argv[0], "unbind" ) == 0 ) { @@ -50,7 +72,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_unbind = charray_dup( &argv[1] ); + si->si_unbind = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for searches */ } else if ( strcasecmp( argv[0], "search" ) == 0 ) { @@ -60,7 +82,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_search = charray_dup( &argv[1] ); + si->si_search = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for compares */ } else if ( strcasecmp( argv[0], "compare" ) == 0 ) { @@ -70,7 +92,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_compare = charray_dup( &argv[1] ); + si->si_compare = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for modifies */ } else if ( strcasecmp( argv[0], "modify" ) == 0 ) { @@ -80,7 +102,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_modify = charray_dup( &argv[1] ); + si->si_modify = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for modrdn */ } else if ( strcasecmp( argv[0], "modrdn" ) == 0 ) { @@ -90,7 +112,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_modrdn = charray_dup( &argv[1] ); + si->si_modrdn = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for add */ } else if ( strcasecmp( argv[0], "add" ) == 0 ) { @@ -100,7 +122,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_add = charray_dup( &argv[1] ); + si->si_add = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for delete */ } else if ( strcasecmp( argv[0], "delete" ) == 0 ) { @@ -110,7 +132,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_delete = charray_dup( &argv[1] ); + si->si_delete = MAKE_CMD_INFO( &argv[1] ); /* command + args to exec for abandon */ } else if ( strcasecmp( argv[0], "abandon" ) == 0 ) { @@ -120,7 +142,7 @@ shell_back_db_config( fname, lineno ); return( 1 ); } - si->si_abandon = charray_dup( &argv[1] ); + si->si_abandon = MAKE_CMD_INFO( &argv[1] ); /* anything else */ } else { diff --git a/servers/slapd/back-shell/delete.c b/servers/slapd/back-shell/delete.c index 5902dbeb13..e675f8062e 100644 --- a/servers/slapd/back-shell/delete.c +++ b/servers/slapd/back-shell/delete.c @@ -27,7 +27,7 @@ shell_back_delete( struct shellinfo *si = (struct shellinfo *) be->be_private; FILE *rfp, *wfp; - if ( si->si_delete == NULL ) { + if ( IS_NULLCMD( si->si_delete ) ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, "delete not implemented", NULL, NULL ); return( -1 ); diff --git a/servers/slapd/back-shell/fork.c b/servers/slapd/back-shell/fork.c index 5a7bb396c7..fc1c0768c3 100644 --- a/servers/slapd/back-shell/fork.c +++ b/servers/slapd/back-shell/fork.c @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -16,18 +17,226 @@ #include "slap.h" #include "shell.h" +#ifdef SHELL_SURROGATE_PARENT + +#include + +/* Use several socketpairs to the surrogate parent, because * + * a single communication channel to it could be a bottleneck */ +ldap_pvt_thread_mutex_t shell_surrogate_fd_mutex[2]; +int shell_surrogate_fd[2] = { -1, -1 }; +/* Index to shell_surrogate_fd, and its mutex */ +ldap_pvt_thread_mutex_t shell_surrogate_index_mutex; +static int shell_surrogate_index = 1; + +pid_t shell_surrogate_pid = -1; + +#define nread( fd, buf, len ) n_rw( 0, fd, buf, len ) +#define nwrite( fd, buf, len ) n_rw( 1, fd, buf, len ) + +static int +n_rw( + int do_write, + int fd, + void *buf, + int len +) +{ + int ret = 0, i; + while( len ) { + for(;;) { + i = (do_write + ? write( fd, buf, len ) + : read( fd, buf, len )); + if( i < 0 ) { + if( errno == EINTR ) + continue; + if( ret == 0 ) + ret = -1; + } + break; + } + if( i <= 0 ) + break; + ret += i; + buf = (char *)buf + i; + len -= i; + } + return ret; +} + +void +make_surrogate_parent( void ) +{ + int pair[2][2], io[2], i, j, p, argc; + ber_len_t len, buflen, offset; + char *buf, **argv; + pid_t pid; + + if( socketpair( AF_LOCAL, SOCK_STREAM, 0, pair[0] ) < 0 || + socketpair( AF_LOCAL, SOCK_STREAM, 0, pair[1] ) < 0 ) { + Debug( LDAP_DEBUG_ANY, "socketpair failed\n", 0, 0, 0 ); + exit( EXIT_FAILURE ); + } + fflush( NULL ); + switch( fork() ) { + case -1: + Debug( LDAP_DEBUG_ANY, "fork failed\n", 0, 0, 0 ); + exit( EXIT_FAILURE ); + case 0: + break; + default: + shell_surrogate_fd[0] = pair[0][0]; + shell_surrogate_fd[1] = pair[1][0]; + close( pair[0][1] ); + close( pair[1][1] ); + return; + } + + /* Close unused file descriptors */ + for( i = 3, j = 32; j && i < 1024; i++ ) + if( i != pair[0][1] && i != pair[1][1] && close( i ) < 0 ) + --j; + else if( j < 32 ) + j = 32; + + /* Surrogate parent running */ + + buflen = 0; + buf = NULL; + argc = 0; + argv = NULL; + p = 0; + + for(;;) { + /* Read file descriptors io[] from socket */ + static char dummy; + static struct iovec iov = { &dummy, 1 }; + struct msghdr msg; +# ifdef CMSG_SPACE + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(io))]; + } control_un; + struct cmsghdr *cmptr; + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); +# else + msg.msg_accrights = (caddr_t) io; + msg.msg_accrightslen = sizeof(io); +# endif + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + switch( recvmsg( pair[p][1], &msg, MSG_WAITALL ) ) { + case -1: + if( errno == EINTR ) + continue; + _exit( EXIT_FAILURE ); + case 0: + _exit( EXIT_SUCCESS ); + } +# ifdef CMSG_SPACE + if( (cmptr = CMSG_FIRSTHDR(&msg)) == NULL || + cmptr->cmsg_len != CMSG_LEN(sizeof(io)) || + cmptr->cmsg_level != SOL_SOCKET || + cmptr->cmsg_type != SCM_RIGHTS ) { + fputs( "bad descriptor message received\n", stderr ); + exit( EXIT_FAILURE ); + } + memcpy( io, CMSG_DATA( cmptr ), sizeof(io) ); +# else + if( msg.msg_accrightslen != sizeof(io) ) { + fputs( "bad descriptor message received\n", stderr ); + exit( EXIT_FAILURE ); + } +# endif + + /* Read length of arguments and then arguments from socket */ + if( nread( pair[p][1], &len, sizeof(len) ) != sizeof(len) ) { + fputs( "bad descriptor message received\n", stderr ); + exit( EXIT_FAILURE ); + } + if( buflen < len ) { + buf = realloc( buf, buflen = len ); + if( buf == NULL ) { + fputs( "realloc failed\n", stderr ); + exit( EXIT_FAILURE ); + } + } + if( nread( pair[p][1], buf, len ) != len ) { + fputs( "bad descriptor message received\n", stderr ); + exit( EXIT_FAILURE ); + } + i = 0; + offset = 0; + while( offset < len ) { + if( i >= argc-1 ) { + argc += i + 10; + argv = realloc( argv, argc * sizeof(*argv) ); + if( argv == NULL ) { + fputs( "realloc failed\n", stderr ); + exit( EXIT_FAILURE ); + } + } + argv[i++] = buf + offset; + offset += strlen( buf + offset ) + 1; + } + argv[i] = NULL; + + /* Run program */ + pid = fork(); + switch( pid ) + { + case 0: /* child */ + if( dup2( io[0], 0 ) == -1 || dup2( io[1], 1 ) == -1 ) { + fputs( "dup2 failed\n", stderr ); + exit( EXIT_FAILURE ); + } + close( io[0] ); + close( io[1] ); + close( pair[0][1] ); + close( pair[1][1] ); + execv( argv[0], argv ); + + fputs( "execv failed\n", stderr ); + exit( EXIT_FAILURE ); + + case -1: /* trouble */ + fputs( "fork failed\n", stderr ); + break; + + default: /* parent */ + close( io[0] ); + close( io[1] ); + break; + } + if( nwrite( pair[p][1], &pid, + sizeof(pid_t) ) != sizeof(pid_t) ) { + fputs( "could not send pid\n", stderr ); + exit( EXIT_FAILURE ); + } + p ^= 1; + } +} +#endif /* SHELL_SURROGATE_PARENT */ + pid_t forkandexec( - char **args, + Cmd_info args, FILE **rfp, FILE **wfp ) { - int p2c[2], c2p[2]; + int p2c[2] = { -1, -1 }, c2p[2]; pid_t pid; if ( pipe( p2c ) != 0 || pipe( c2p ) != 0 ) { Debug( LDAP_DEBUG_ANY, "pipe failed\n", 0, 0, 0 ); + close( p2c[0] ); + close( p2c[1] ); return( -1 ); } @@ -37,27 +246,89 @@ forkandexec( * parent *rfp <- c2p[0] | c2p[1] <- stdout child */ -#ifdef HAVE_THR - switch ( (pid = fork1()) ) -#else - switch ( (pid = fork()) ) -#endif +#ifdef SHELL_SURROGATE_PARENT + { - case 0: /* child */ + int io[2] = { p2c[0], c2p[1] }, i, c; + static char dummy = '\0'; + static struct iovec iov = { &dummy, 1 }; + struct msghdr msg; +# ifdef CMSG_SPACE + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(io))]; + } control_un; + struct cmsghdr *cmptr; + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); + cmptr = CMSG_FIRSTHDR(&msg); + cmptr->cmsg_len = CMSG_LEN(sizeof(io)); + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + memcpy( CMSG_DATA(cmptr), io, sizeof(io) ); +# else + msg.msg_accrights = (caddr_t) io; + msg.msg_accrightslen = sizeof(io); +# endif + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + ldap_pvt_thread_mutex_lock( &shell_surrogate_index_mutex ); + i = shell_surrogate_index ^= 1; + ldap_pvt_thread_mutex_unlock( &shell_surrogate_index_mutex ); + ldap_pvt_thread_mutex_lock( &shell_surrogate_fd_mutex[i] ); + c = (sendmsg( shell_surrogate_fd[i], &msg, 0 ) == 1 && + nwrite( shell_surrogate_fd[i], &args.bv_len, + sizeof(args.bv_len) ) == sizeof(args.bv_len) && + nwrite( shell_surrogate_fd[i], args.bv_val, + args.bv_len ) == args.bv_len && + nread( shell_surrogate_fd[i], &pid, + sizeof(pid) ) == sizeof(pid)); + ldap_pvt_thread_mutex_unlock( &shell_surrogate_fd_mutex[i] ); + close( p2c[0] ); + close( c2p[1] ); + if ( !c ) { + Debug( LDAP_DEBUG_ANY, "process creation failed\n", 0, 0, 0 ); + close( p2c[1] ); + close( c2p[0] ); + close( shell_surrogate_fd[0] ); + close( shell_surrogate_fd[1] ); + shell_surrogate_fd[0] = + shell_surrogate_fd[1] = -1; + return( -1 ); + } + } + +#else /* !SHELL_SURROGATE_PARENT */ + + fflush( NULL ); +# ifdef HAVE_THR + pid = fork1(); +# else + pid = fork(); +# endif + if ( pid == 0 ) { /* child */ /* * child could deadlock here due to resources locked * by our parent * - * If so, configure --without-threads or implement forking - * via a surrogate parent. + * If so, configure --without-threads. */ - close( p2c[1] ); - close( c2p[0] ); if ( dup2( p2c[0], 0 ) == -1 || dup2( c2p[1], 1 ) == -1 ) { Debug( LDAP_DEBUG_ANY, "dup2 failed\n", 0, 0, 0 ); exit( EXIT_FAILURE ); } - + } + close( p2c[0] ); + close( c2p[1] ); + if ( pid <= 0 ) { + close( p2c[1] ); + close( c2p[0] ); + } + switch ( pid ) { + case 0: execv( args[0], args ); Debug( LDAP_DEBUG_ANY, "execv failed\n", 0, 0, 0 ); @@ -66,13 +337,11 @@ forkandexec( case -1: /* trouble */ Debug( LDAP_DEBUG_ANY, "fork failed\n", 0, 0, 0 ); return( -1 ); - - default: /* parent */ - close( p2c[0] ); - close( c2p[1] ); - break; } +#endif /* SHELL_SURROGATE_PARENT */ + + /* parent */ if ( (*rfp = fdopen( c2p[0], "r" )) == NULL || (*wfp = fdopen( p2c[1], "w" )) == NULL ) { Debug( LDAP_DEBUG_ANY, "fdopen failed\n", 0, 0, 0 ); diff --git a/servers/slapd/back-shell/init.c b/servers/slapd/back-shell/init.c index d7add624f5..03ab2d1801 100644 --- a/servers/slapd/back-shell/init.c +++ b/servers/slapd/back-shell/init.c @@ -10,6 +10,7 @@ #include #include +#include #include "slap.h" #include "shell.h" @@ -37,7 +38,7 @@ shell_back_initialize( bi->bi_open = 0; bi->bi_config = 0; bi->bi_close = 0; - bi->bi_destroy = 0; + bi->bi_destroy = shell_back_destroy; bi->bi_db_init = shell_back_db_init; bi->bi_db_config = shell_back_db_config; @@ -64,6 +65,32 @@ shell_back_initialize( bi->bi_connection_init = 0; bi->bi_connection_destroy = 0; +#ifdef SHELL_SURROGATE_PARENT + ldap_pvt_thread_mutex_init( &shell_surrogate_index_mutex ); + ldap_pvt_thread_mutex_init( &shell_surrogate_fd_mutex[0] ); + ldap_pvt_thread_mutex_init( &shell_surrogate_fd_mutex[1] ); +#endif + + return 0; +} + +int +shell_back_destroy( + BackendInfo *bi +) +{ +#ifdef SHELL_SURROGATE_PARENT + ldap_pvt_thread_mutex_destroy( &shell_surrogate_index_mutex ); + ldap_pvt_thread_mutex_destroy( &shell_surrogate_fd_mutex[0] ); + ldap_pvt_thread_mutex_destroy( &shell_surrogate_fd_mutex[1] ); + if ( shell_surrogate_fd[0] >= 0 ) { + close( shell_surrogate_fd[0] ); + close( shell_surrogate_fd[1] ); + } + if ( shell_surrogate_pid >= 0 ) + kill( shell_surrogate_pid, SIGTERM ); +#endif + return 0; } @@ -74,6 +101,11 @@ shell_back_db_init( { struct shellinfo *si; +#ifdef SHELL_SURROGATE_PARENT + if ( shell_surrogate_fd[0] < 0 ) + make_surrogate_parent(); +#endif + si = (struct shellinfo *) ch_calloc( 1, sizeof(struct shellinfo) ); be->be_private = si; diff --git a/servers/slapd/back-shell/modify.c b/servers/slapd/back-shell/modify.c index 91d7149eca..5acddbe994 100644 --- a/servers/slapd/back-shell/modify.c +++ b/servers/slapd/back-shell/modify.c @@ -30,7 +30,7 @@ shell_back_modify( FILE *rfp, *wfp; int i; - if ( si->si_modify == NULL ) { + if ( IS_NULLCMD( si->si_modify ) ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, "modify not implemented", NULL, NULL ); return( -1 ); diff --git a/servers/slapd/back-shell/modrdn.c b/servers/slapd/back-shell/modrdn.c index 00dd8a9d6c..e2c7d64d5f 100644 --- a/servers/slapd/back-shell/modrdn.c +++ b/servers/slapd/back-shell/modrdn.c @@ -45,7 +45,7 @@ shell_back_modrdn( struct shellinfo *si = (struct shellinfo *) be->be_private; FILE *rfp, *wfp; - if ( si->si_modrdn == NULL ) { + if ( IS_NULLCMD( si->si_modrdn ) ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, "modrdn not implemented", NULL, NULL ); return( -1 ); diff --git a/servers/slapd/back-shell/search.c b/servers/slapd/back-shell/search.c index 6d574524ad..a1579e20e2 100644 --- a/servers/slapd/back-shell/search.c +++ b/servers/slapd/back-shell/search.c @@ -33,11 +33,10 @@ shell_back_search( ) { struct shellinfo *si = (struct shellinfo *) be->be_private; - int i; FILE *rfp, *wfp; AttributeName *an; - if ( si->si_search == NULL ) { + if ( IS_NULLCMD( si->si_search ) ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, "search not implemented", NULL, NULL ); return( -1 ); diff --git a/servers/slapd/back-shell/shell.h b/servers/slapd/back-shell/shell.h index 866fd4b2aa..25b7aaf28d 100644 --- a/servers/slapd/back-shell/shell.h +++ b/servers/slapd/back-shell/shell.h @@ -12,16 +12,41 @@ LDAP_BEGIN_DECL +#if defined(HAVE_RECVMSG) && !defined(NO_THREADS) +# define SHELL_SURROGATE_PARENT +#endif + +#ifdef SHELL_SURROGATE_PARENT + +extern ldap_pvt_thread_mutex_t shell_surrogate_index_mutex; +extern ldap_pvt_thread_mutex_t shell_surrogate_fd_mutex[2]; +extern int shell_surrogate_fd[2]; +extern pid_t shell_surrogate_pid; + +typedef struct berval Cmd_info; +#define MAKE_CMD_INFO(args) make_cmd_info( args ) +#define IS_NULLCMD(cmd) ((cmd).bv_val == NULL) + +extern void make_surrogate_parent LDAP_P(( void )); + +#else /* !SHELL_SURROGATE_PARENT */ + +typedef char **Cmd_info; +#define MAKE_CMD_INFO(args) charray_dup( args ) +#define IS_NULLCMD(cmd) ((cmd) == NULL) + +#endif /* SHELL_SURROGATE_PARENT */ + struct shellinfo { - char **si_bind; /* cmd + args to exec for bind */ - char **si_unbind; /* cmd + args to exec for unbind */ - char **si_search; /* cmd + args to exec for search */ - char **si_compare; /* cmd + args to exec for compare */ - char **si_modify; /* cmd + args to exec for modify */ - char **si_modrdn; /* cmd + args to exec for modrdn */ - char **si_add; /* cmd + args to exec for add */ - char **si_delete; /* cmd + args to exec for delete */ - char **si_abandon; /* cmd + args to exec for abandon */ + Cmd_info si_bind; /* cmd + args to exec for bind */ + Cmd_info si_unbind; /* cmd + args to exec for unbind */ + Cmd_info si_search; /* cmd + args to exec for search */ + Cmd_info si_compare; /* cmd + args to exec for compare */ + Cmd_info si_modify; /* cmd + args to exec for modify */ + Cmd_info si_modrdn; /* cmd + args to exec for modrdn */ + Cmd_info si_add; /* cmd + args to exec for add */ + Cmd_info si_delete; /* cmd + args to exec for delete */ + Cmd_info si_abandon; /* cmd + args to exec for abandon */ }; struct slap_backend_db; @@ -29,7 +54,7 @@ struct slap_conn; struct slap_op; extern pid_t forkandexec LDAP_P(( - char **args, + Cmd_info args, FILE **rfp, FILE **wfp)); diff --git a/servers/slapd/back-shell/unbind.c b/servers/slapd/back-shell/unbind.c index b7c44c1577..a4327f99e2 100644 --- a/servers/slapd/back-shell/unbind.c +++ b/servers/slapd/back-shell/unbind.c @@ -25,7 +25,7 @@ shell_back_unbind( struct shellinfo *si = (struct shellinfo *) be->be_private; FILE *rfp, *wfp; - if ( si->si_unbind == NULL ) { + if ( IS_NULLCMD( si->si_unbind ) ) { return 0; } -- 2.39.5