mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-12 10:54:48 +08:00
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 <h.b.furuseth@usit.uio.no>, May 2002.
This commit is contained in:
parent
d8388e461d
commit
4e51bba217
29
configure
vendored
29
configure
vendored
@ -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 <<EOF
|
||||
#line 21827 "configure"
|
||||
#line 21828 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char $ac_func(); below. */
|
||||
@ -21847,7 +21848,7 @@ f = $ac_func;
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:21851: \"$ac_link\") 1>&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 <<EOF
|
||||
#line 21884 "configure"
|
||||
#line 21885 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char $ac_func(); below. */
|
||||
@ -21904,7 +21905,7 @@ f = $ac_func;
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:21908: \"$ac_link\") 1>&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 <<EOF
|
||||
#line 21947 "configure"
|
||||
#line 21948 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -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 <<EOF
|
||||
#line 21989 "configure"
|
||||
#line 21990 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <errno.h>
|
||||
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
|
||||
|
@ -2426,6 +2426,7 @@ AC_CHECK_FUNCS( \
|
||||
read \
|
||||
recv \
|
||||
recvfrom \
|
||||
recvmsg \
|
||||
setpwfile \
|
||||
setgid \
|
||||
setegid \
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 ) {
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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 {
|
||||
|
@ -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 );
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/errno.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/socket.h>
|
||||
#include <ac/unistd.h>
|
||||
@ -16,18 +17,226 @@
|
||||
#include "slap.h"
|
||||
#include "shell.h"
|
||||
|
||||
#ifdef SHELL_SURROGATE_PARENT
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
/* 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 );
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/socket.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#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;
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user