/* $OpenLDAP$ */
/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
#include <ac/ctype.h>
#include <ac/errno.h>
-#include <ac/signal.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
#include "ldap_pvt.h"
+#include "ldap_pvt_thread.h"
#include "lutil.h"
#include "slap.h"
#ifdef LDAP_PF_LOCAL
#include <sys/stat.h>
+/* this should go in <ldap.h> as soon as it is accepted */
+#define LDAPI_MOD_URLEXT "x-mod"
#endif /* LDAP_PF_LOCAL */
/* globals */
time_t starttime;
ber_socket_t dtblsize;
-typedef struct slap_listener {
- char* sl_url;
- char* sl_name;
-#ifdef HAVE_TLS
- int sl_is_tls;
-#endif
-#ifdef LDAP_CONNECTIONLESS
- int sl_is_udp; /* UDP listener is also data port */
-#endif
- ber_socket_t sl_sd;
- Sockaddr sl_sa;
-#define sl_addr sl_sa.sa_in_addr
-} Listener;
-
Listener **slap_listeners = NULL;
#define SLAPD_LISTEN 10
do { if (w) tcp_write( wake_sds[1], "0", 1 ); } while(0)
#endif
-#ifdef HAVE_NT_SERVICE_MANAGER
-/* in nt_main.c */
-extern ldap_pvt_thread_cond_t started_event;
-extern int is_NT_Service;
-#endif
-
#ifndef HAVE_WINSOCK
static
#endif
-volatile sig_atomic_t slapd_shutdown = 0;
+volatile sig_atomic_t slapd_shutdown = 0, slapd_gentle_shutdown = 0;
static struct slap_daemon {
ldap_pvt_thread_mutex_t sd_mutex;
- int sd_nactives;
+ ber_socket_t sd_nactives;
#ifndef HAVE_WINSOCK
/* In winsock, accept() returns values higher than dtblsize
slapd_srvurls[i] = (char *) realloc( slapd_srvurls[i],
strlen( host ) +
sizeof( LDAP_SRVTYPE_PREFIX ) );
- strcpy( slapd_srvurls[i], LDAP_SRVTYPE_PREFIX );
- strcat( slapd_srvurls[i], host );
+ strcpy( slap_strcopy(slapd_srvurls[i],
+ LDAP_SRVTYPE_PREFIX ), host );
ch_free( host );
}
slapd_srvurls[i] = (char *) realloc( slapd_srvurls[i],
strlen( host ) +
sizeof( LDAPS_SRVTYPE_PREFIX ) );
- strcpy( slapd_srvurls[i], LDAPS_SRVTYPE_PREFIX );
- strcat( slapd_srvurls[i], host );
+ strcpy( slap_strcopy(slapd_srvurls[i],
+ LDAPS_SRVTYPE_PREFIX ), host );
ch_free( host );
}
}
#endif
+ slap_daemon.sd_nactives++;
+
FD_SET( s, &slap_daemon.sd_actives );
FD_SET( s, &slap_daemon.sd_readers );
void slapd_remove(ber_socket_t s, int wake) {
ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
+ slap_daemon.sd_nactives--;
+
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1,
"slapd_remove: removing %ld%s%s\n",
FD_CLR( s, &slap_daemon.sd_writers );
ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
- WAKE_LISTENER(wake);
+ WAKE_LISTENER(wake || slapd_gentle_shutdown == 2);
}
void slapd_clr_write(ber_socket_t s, int wake) {
ch_free(sal);
}
+#ifdef LDAP_PF_LOCAL
+static int get_url_perms(
+ char **exts,
+ mode_t *perms,
+ int *crit )
+{
+ int i;
+
+ assert( exts );
+ assert( perms );
+ assert( crit );
+
+ *crit = 0;
+ for ( i = 0; exts[ i ]; i++ ) {
+ char *type = exts[ i ];
+ int c = 0;
+
+ if ( type[ 0 ] == '!' ) {
+ c = 1;
+ type++;
+ }
+
+ if ( strncasecmp( type, LDAPI_MOD_URLEXT "=", sizeof(LDAPI_MOD_URLEXT "=") - 1 ) == 0 ) {
+ char *value = type + sizeof(LDAPI_MOD_URLEXT "=") - 1;
+ mode_t p = 0;
+ int j;
+
+ if ( strlen(value) != 3 ) {
+ return LDAP_OTHER;
+ }
+
+ for ( j = 0; j < 3; j++ ) {
+ static mode_t m[ 3 ]
+ = { S_IRWXU, S_IRWXG, S_IRWXO };
+
+ switch ( value[ j ] ) {
+ case 'w':
+ p |= m[ j ];
+ break;
+ case '-':
+ break;
+ default:
+ return LDAP_OTHER;
+ }
+ }
+
+ *crit = c;
+ *perms = p;
+
+ return LDAP_SUCCESS;
+ }
+ }
+
+ return LDAP_OTHER;
+}
+#endif /* LDAP_PF_LOCAL */
+
/* port = 0 indicates AF_LOCAL */
static int slap_get_listener_addresses(
const char *host,
for (n=2; (sai = sai->ai_next) != NULL; n++) {
/* EMPTY */ ;
}
- *sal = ch_malloc(n * sizeof(void *));
+ *sal = ch_calloc(n, sizeof(void *));
if (*sal == NULL) {
return -1;
}
freeaddrinfo(res);
#else
+ int i, n = 1;
struct in_addr in;
+ struct hostent *he = NULL;
if ( host == NULL ) {
in.s_addr = htonl(INADDR_ANY);
} else if ( !inet_aton( host, &in ) ) {
- struct hostent *he = gethostbyname( host );
+ he = gethostbyname( host );
if( he == NULL ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_INFO,
#endif
return -1;
}
- AC_MEMCPY( &in, he->h_addr, sizeof( in ) );
+ for (n = 0; he->h_addr_list[n]; n++) ;
}
- *sal = ch_malloc(2 * sizeof(void *));
+ *sal = ch_malloc((n+1) * sizeof(void *));
if (*sal == NULL) {
return -1;
}
sap = *sal;
- *sap = ch_malloc(sizeof(struct sockaddr_in));
- if (*sap == NULL) {
- goto errexit;
+ for ( i = 0; i<n; i++ ) {
+ sap[i] = ch_malloc(sizeof(struct sockaddr_in));
+ if (*sap == NULL) {
+ goto errexit;
+ }
+ (void)memset( (void *)sap[i], '\0', sizeof(struct sockaddr_in) );
+ sap[i]->sa_family = AF_INET;
+ ((struct sockaddr_in *)sap[i])->sin_port = htons(port);
+ if (he) {
+ AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr, he->h_addr_list[i], sizeof(struct in_addr) );
+ } else {
+ AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr, &in, sizeof(struct in_addr) );
+ }
}
- sap[1] = NULL;
-
- (void)memset( (void *)*sap, '\0', sizeof(struct sockaddr_in) );
- (*sap)->sa_family = AF_INET;
- ((struct sockaddr_in *)*sap)->sin_port = htons(port);
- ((struct sockaddr_in *)*sap)->sin_addr = in;
+ sap[i] = NULL;
#endif
}
return -1;
}
-static Listener * slap_open_listener(
- const char* url )
+static int slap_open_listener(
+ const char* url,
+ int *listeners,
+ int *cur
+ )
{
- int tmp, rc;
+ int num, tmp, rc;
Listener l;
Listener *li;
LDAPURLDesc *lud;
int err, addrlen = 0;
struct sockaddr **sal, **psal;
int socktype = SOCK_STREAM; /* default to COTS */
+#ifdef LDAP_PF_LOCAL
+ mode_t perms = S_IRWXU;
+ int crit = 1;
+#endif
rc = ldap_url_parse( url, &lud );
"daemon: listen URL \"%s\" parse error=%d\n",
url, rc, 0 );
#endif
- return NULL;
+ return rc;
}
#ifndef HAVE_TLS
url, 0, 0 );
#endif
ldap_free_urldesc( lud );
- return NULL;
+ return -1;
}
if(! lud->lud_port ) {
} else {
err = slap_get_listener_addresses(lud->lud_host, 0, &sal);
}
+
+ if ( lud->lud_exts ) {
+ err = get_url_perms( lud->lud_exts, &perms, &crit );
+ }
#else
#ifdef NEW_LOGGING
url, 0, 0);
#endif
ldap_free_urldesc( lud );
- return NULL;
+ return -1;
#endif
} else {
#ifdef LDAP_CONNECTIONLESS
ldap_free_urldesc( lud );
if ( err ) {
- return NULL;
+ return -1;
+ }
+
+ /* If we got more than one address returned, we need to make space
+ * for it in the slap_listeners array.
+ */
+ for ( num=0; sal[num]; num++ );
+ if ( num > 1 ) {
+ *listeners += num-1;
+ slap_listeners = ch_realloc( slap_listeners, (*listeners + 1) * sizeof(Listener *) );
}
psal = sal;
#endif
}
- if (!bind(l.sl_sd, *sal, addrlen))
- break;
- err = sock_errno();
+ if (bind(l.sl_sd, *sal, addrlen)) {
+ err = sock_errno();
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_INFO,
"slap_open_listener: bind(%ld) failed errno=%d (%s)\n",
Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n",
(long) l.sl_sd, err, sock_errstr(err) );
#endif
- tcp_close( l.sl_sd );
- sal++;
- } /* while ( *sal != NULL ) */
-
- if ( *sal == NULL ) {
-#ifdef NEW_LOGGING
- LDAP_LOG(( "connection", LDAP_LEVEL_INFO,
- "slap_open_listener: bind(%ld) failed.\n", (long)l.sl_sd ));
-#else
- Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed\n",
- (long) l.sl_sd, 0, 0 );
-#endif
- slap_free_listener_addresses(psal);
- return NULL;
- }
+ tcp_close( l.sl_sd );
+ sal++;
+ continue;
+ }
switch ( (*sal)->sa_family ) {
#ifdef LDAP_PF_LOCAL
case AF_LOCAL: {
char *addr = ((struct sockaddr_un *)*sal)->sun_path;
- if ( chmod( addr, S_IRWXU ) < 0 ) {
+ if ( chmod( addr, perms ) < 0 && crit ) {
int err = sock_errno();
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_INFO,
#endif
tcp_close( l.sl_sd );
slap_free_listener_addresses(psal);
- return NULL;
+ return -1;
}
l.sl_name = ch_malloc( strlen(addr) + sizeof("PATH=") );
sprintf( l.sl_name, "PATH=%s", addr );
inet_ntop( AF_INET, &((struct sockaddr_in *)*sal)->sin_addr,
addr, sizeof(addr) );
s = addr;
- port = ((struct sockaddr_in *)*sal) ->sin_port;
#else
- s = inet_ntoa( l.sl_addr.sin_addr );
- port = l.sl_addr.sin_port;
+ s = inet_ntoa( ((struct sockaddr_in *) *sal)->sin_addr );
#endif
+ port = ntohs( ((struct sockaddr_in *)*sal) ->sin_port );
l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65535") );
sprintf( l.sl_name, "IP=%s:%d",
s != NULL ? s : "unknown" , port );
char addr[INET6_ADDRSTRLEN];
inet_ntop( AF_INET6, &((struct sockaddr_in6 *)*sal)->sin6_addr,
addr, sizeof addr);
- port = ((struct sockaddr_in6 *)*sal)->sin6_port;
+ port = ntohs( ((struct sockaddr_in6 *)*sal)->sin6_port );
l.sl_name = ch_malloc( strlen(addr) + sizeof("IP= 65535") );
sprintf( l.sl_name, "IP=%s %d", addr, port );
} break;
break;
}
- slap_free_listener_addresses(psal);
-
+ AC_MEMCPY(&l.sl_sa, *sal, addrlen);
l.sl_url = ch_strdup( url );
li = ch_malloc( sizeof( Listener ) );
*li = l;
+ slap_listeners[*cur] = li;
+ (*cur)++;
+ sal++;
+
+ } /* while ( *sal != NULL ) */
+
+ slap_free_listener_addresses(psal);
+
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_RESULTS,
- "slap_open_listener: daemon initialzed %s\n", l.sl_url ));
+ "slap_open_listener: daemon initialized %s\n", l.sl_url ));
#else
Debug( LDAP_DEBUG_TRACE, "daemon: initialized %s\n",
l.sl_url, 0, 0 );
#endif
- return li;
+ return 0;
}
static int sockinit(void);
int slapd_daemon_init( const char *urls )
{
- int i, rc;
+ int i, j, n, rc;
char **u;
#ifdef NEW_LOGGING
#endif
slap_listeners = ch_malloc( (i+1)*sizeof(Listener *) );
- for(i = 0; u[i] != NULL; i++ ) {
- slap_listeners[i] = slap_open_listener( u[i] );
-
- if( slap_listeners[i] == NULL ) {
+ for(n = 0, j = 0; u[n]; n++ ) {
+ if ( slap_open_listener( u[n], &i, &j ) ) {
charray_free( u );
return -1;
}
}
- slap_listeners[i] = NULL;
+ slap_listeners[j] = NULL;
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1,
}
+static void
+close_listeners(
+ int remove
+)
+{
+ int l;
+
+ for ( l = 0; slap_listeners[l] != NULL; l++ ) {
+ if ( remove )
+ slapd_remove( slap_listeners[l]->sl_sd, 0 );
+ if ( slap_listeners[l]->sl_sd != AC_SOCKET_INVALID ) {
+#ifdef LDAP_PF_LOCAL
+ if ( slap_listeners[l]->sl_sa.sa_addr.sa_family == AF_LOCAL ) {
+ unlink( slap_listeners[l]->sl_sa.sa_un_addr.sun_path );
+ }
+#endif /* LDAP_PF_LOCAL */
+ slapd_close( slap_listeners[l]->sl_sd );
+ }
+ if ( slap_listeners[l]->sl_url )
+ free ( slap_listeners[l]->sl_url );
+ if ( slap_listeners[l]->sl_name )
+ free ( slap_listeners[l]->sl_name );
+ free ( slap_listeners[l] );
+ slap_listeners[l] = NULL;
+ }
+}
+
+
static void *
slapd_daemon_task(
void *ptr
}
}
+#ifdef SIGHUP
+ if( slapd_gentle_shutdown ) {
+ ber_socket_t active;
+
+ if( slapd_gentle_shutdown == 1 ) {
+ Debug( LDAP_DEBUG_ANY, "slapd gentle shutdown\n", 0, 0, 0 );
+ close_listeners( 1 );
+ global_restrictops |= SLAP_RESTRICT_OP_WRITES;
+ slapd_gentle_shutdown = 2;
+ }
+
+ ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
+ active = slap_daemon.sd_nactives;
+ ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
+ if( active == 0 ) {
+ slapd_shutdown = 2;
+ break;
+ }
+ }
+#endif
+
FD_ZERO( &writefds );
FD_ZERO( &readfds );
"daemon: select failed (%d): %s\n",
err, sock_errstr(err), 0 );
#endif
- slapd_shutdown = -1;
+ slapd_shutdown = 2;
}
}
continue;
case AF_LOCAL:
sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path );
ssf = LDAP_PVT_SASL_LOCAL_SSF;
+ dnsname = "local";
break;
#endif /* LDAP_PF_LOCAL */
#endif
) {
#ifdef SLAPD_RLOOKUPS
+ if ( use_reverse_lookup ) {
# ifdef LDAP_PF_INET6
- if ( from.sa_addr.sa_family == AF_INET6 )
- hp = gethostbyaddr(
- (char *)&(from.sa_in6_addr.sin6_addr),
- sizeof(from.sa_in6_addr.sin6_addr),
- AF_INET6 );
- else
+ if ( from.sa_addr.sa_family == AF_INET6 )
+ hp = gethostbyaddr(
+ (char *)&(from.sa_in6_addr.sin6_addr),
+ sizeof(from.sa_in6_addr.sin6_addr),
+ AF_INET6 );
+ else
# endif /* LDAP_PF_INET6 */
- hp = gethostbyaddr(
- (char *) &(from.sa_in_addr.sin_addr),
- sizeof(from.sa_in_addr.sin_addr),
- AF_INET );
- dnsname = hp ? ldap_pvt_str2lower( hp->h_name ) : NULL;
+ hp = gethostbyaddr(
+ (char *) &(from.sa_in_addr.sin_addr),
+ sizeof(from.sa_in_addr.sin_addr),
+ AF_INET );
+ dnsname = hp ? ldap_pvt_str2lower( hp->h_name ) : NULL;
+ }
#else
dnsname = NULL;
#endif /* SLAPD_RLOOKUPS */
ldap_pvt_thread_yield();
}
- if( slapd_shutdown > 0 ) {
+ if( slapd_shutdown == 1 ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_CRIT,
"slapd_daemon_task: shutdown requested and initiated.\n"));
0, 0, 0 );
#endif
- } else if ( slapd_shutdown < 0 ) {
+ } else if ( slapd_shutdown == 2 ) {
#ifdef HAVE_NT_SERVICE_MANAGER
- if (slapd_shutdown == -1)
- {
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_CRIT,
"slapd_daemon_task: shutdown initiated by Service Manager.\n"));
"daemon: shutdown initiated by Service Manager.\n",
0, 0, 0);
#endif
- }
- else
-#endif
- {
+#else /* !HAVE_NT_SERVICE_MANAGER */
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_CRIT,
"slapd_daemon_task: abnormal condition, shutdown initiated.\n" ));
"daemon: abnormal condition, shutdown initiated.\n",
0, 0, 0 );
#endif
- }
+#endif /* !HAVE_NT_SERVICE_MANAGER */
} else {
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_CRIT,
#endif
}
- for ( l = 0; slap_listeners[l] != NULL; l++ ) {
- if ( slap_listeners[l]->sl_sd != AC_SOCKET_INVALID ) {
-#ifdef LDAP_PF_LOCAL
- if ( slap_listeners[l]->sl_sa.sa_addr.sa_family == AF_LOCAL ) {
- unlink( slap_listeners[l]->sl_sa.sa_un_addr.sun_path );
- }
-#endif /* LDAP_PF_LOCAL */
- slapd_close( slap_listeners[l]->sl_sd );
- break;
- }
- }
+ if( slapd_gentle_shutdown != 2 )
+ close_listeners ( 0 );
+ free ( slap_listeners );
+ slap_listeners = NULL;
#ifdef NEW_LOGGING
LDAP_LOG(( "connection", LDAP_LEVEL_CRIT,
#endif
else
#endif
- slapd_shutdown = sig;
+#ifdef SIGHUP
+ if (sig == SIGHUP && global_gentlehup && slapd_gentle_shutdown == 0)
+ slapd_gentle_shutdown = 1;
+ else
+#endif
+ slapd_shutdown = 1;
WAKE_LISTENER(1);
void slapd_add_internal(ber_socket_t s) {
slapd_add(s);
}
+
+Listener ** slapd_get_listeners(void) {
+ return slap_listeners;
+}