daemon.c 29.3 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
5
6
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
9
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
10
11
12
13
14
15
16
17
18

#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>

19
#include "ldap_pvt.h"
20
#include "lutil.h"
21
#include "slap.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
22
23

#ifdef HAVE_TCPD
24
25
26
27
#include <tcpd.h>

int allow_severity = LOG_INFO;
int deny_severity = LOG_NOTICE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
#endif /* TCP Wrappers */
29

30
#ifdef LDAP_PF_UNIX
31
#include <sys/stat.h>
32
#endif /* LDAP_PF_UNIX */
33

34
/* globals */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
35
time_t starttime;
36
ber_socket_t dtblsize;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37

38
39
40
typedef union slap_sockaddr {
	struct sockaddr sa_addr;
	struct sockaddr_in sa_in_addr;
41
#ifdef LDAP_PF_INET6
Kurt Zeilenga's avatar
Kurt Zeilenga committed
42
43
	struct sockaddr_in6 sa_in6_addr;
#endif
44
#ifdef LDAP_PF_UNIX
45
	struct sockaddr_un sa_un_addr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
46
#endif
47
48
} Sockaddr;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
49
50
typedef struct slap_listener {
	char* sl_url;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
51
	char* sl_name;
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
52
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
	int		sl_is_tls;
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
54
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
55
	ber_socket_t		sl_sd;
56
57
	Sockaddr sl_sa;
#define sl_addr	sl_sa.sa_in_addr
Kurt Zeilenga's avatar
Kurt Zeilenga committed
58
59
} Listener;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
60
Listener **slap_listeners = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
61

Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
static ber_socket_t wake_sds[2];
63

64
65
66
67
68
#ifdef NO_THREADS
static int waking;
#define WAKE_LISTENER(w) \
((w && !waking) ? tcp_write( wake_sds[1], "0", 1 ), waking=1 : 0)
#else
69
#define WAKE_LISTENER(w) \
Kurt Zeilenga's avatar
Kurt Zeilenga committed
70
do { if (w) tcp_write( wake_sds[1], "0", 1 ); } while(0)
71
#endif
72

73
#ifdef HAVE_NT_SERVICE_MANAGER
74
/* in nt_main.c */
75
extern ldap_pvt_thread_cond_t			started_event;
Howard Chu's avatar
Howard Chu committed
76
extern int	  is_NT_Service;
77
78
#endif

79
80
81
82
83
#ifndef HAVE_WINSOCK
static 
#endif
volatile sig_atomic_t slapd_shutdown = 0;

84
static ldap_pvt_thread_t	listener_tid;
85

Kurt Zeilenga's avatar
Kurt Zeilenga committed
86
static struct slap_daemon {
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
	ldap_pvt_thread_mutex_t	sd_mutex;

	int sd_nactives;

#ifndef HAVE_WINSOCK
	/* In winsock, accept() returns values higher than dtblsize
		so don't bother with this optimization */
	int sd_nfds;
#endif

	fd_set sd_actives;
	fd_set sd_readers;
	fd_set sd_writers;
} slap_daemon; 

/*
 * Add a descriptor to daemon control
 */
105
static void slapd_add(ber_socket_t s) {
106
107
108
109
110
111
	ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

	assert( !FD_ISSET( s, &slap_daemon.sd_actives ));
	assert( !FD_ISSET( s, &slap_daemon.sd_readers ));
	assert( !FD_ISSET( s, &slap_daemon.sd_writers ));

112
#ifndef HAVE_WINSOCK
113
114
115
	if (s >= slap_daemon.sd_nfds) {
		slap_daemon.sd_nfds = s + 1;
	}
116
#endif
117

118
119
	FD_SET( s, &slap_daemon.sd_actives );
	FD_SET( s, &slap_daemon.sd_readers );
120

121
122
	Debug( LDAP_DEBUG_CONNS, "daemon: added %ld%s%s\n",
		(long) s,
123
124
125
126
127
128
129
130
131
	    FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
		FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );

	ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
}

/*
 * Remove the descriptor from daemon control
 */
132
void slapd_remove(ber_socket_t s, int wake) {
133
134
	ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

135
136
	Debug( LDAP_DEBUG_CONNS, "daemon: removing %ld%s%s\n",
		(long) s,
137
138
139
	    FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
		FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );

140
141
142
	FD_CLR( s, &slap_daemon.sd_actives );
	FD_CLR( s, &slap_daemon.sd_readers );
	FD_CLR( s, &slap_daemon.sd_writers );
143
144

	ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
145
	WAKE_LISTENER(wake);
146
147
}

148
void slapd_clr_write(ber_socket_t s, int wake) {
149
150
	ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

151
152
	assert( FD_ISSET( s, &slap_daemon.sd_actives) );
	FD_CLR( s, &slap_daemon.sd_writers );
153
154

	ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
155
	WAKE_LISTENER(wake);
156
157
}

158
void slapd_set_write(ber_socket_t s, int wake) {
159
	ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
160

161
	assert( FD_ISSET( s, &slap_daemon.sd_actives) );
162
163
	if (!FD_ISSET(s, &slap_daemon.sd_writers))
	    FD_SET( (unsigned) s, &slap_daemon.sd_writers );
164
165

	ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
166
	WAKE_LISTENER(wake);
167
168
}

169
void slapd_clr_read(ber_socket_t s, int wake) {
170
171
172
	ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

	assert( FD_ISSET( s, &slap_daemon.sd_actives) );
173
	FD_CLR( s, &slap_daemon.sd_readers );
174
175

	ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
176
	WAKE_LISTENER(wake);
177
178
}

179
void slapd_set_read(ber_socket_t s, int wake) {
180
181
182
	ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

	assert( FD_ISSET( s, &slap_daemon.sd_actives) );
183
184
	if (!FD_ISSET(s, &slap_daemon.sd_readers))
	    FD_SET( s, &slap_daemon.sd_readers );
185
186

	ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
187
	WAKE_LISTENER(wake);
188
189
}

190
191
192
static void slapd_close(ber_socket_t s) {
	Debug( LDAP_DEBUG_CONNS, "daemon: closing %ld\n",
		(long) s, 0, 0 );
193
	tcp_close(s);
194
195
}

196

197
static Listener * open_listener( const char* url )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
198
{
199
	int	tmp, rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
200
201
202
	Listener l;
	Listener *li;
	LDAPURLDesc *lud;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
203
	char *s;
204
	int port;
205
#ifdef HAVE_GETADDRINFO
Kurt Zeilenga's avatar
Kurt Zeilenga committed
206
207
208
209
	char serv[7];
	struct addrinfo hints, *res, *sai;
	int err;
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
210
211
212
213
214
215
216
217
218
219
220

	rc = ldap_url_parse( url, &lud );

	if( rc != LDAP_URL_SUCCESS ) {
		Debug( LDAP_DEBUG_ANY,
			"daemon: listen URL \"%s\" parse error=%d\n",
			url, rc, 0 );
		return NULL;
	}

#ifndef HAVE_TLS
221
	if( ldap_pvt_url_scheme2tls( lud->lud_scheme ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
222
223
224
225
226
227
228
229
		Debug( LDAP_DEBUG_ANY,
			"daemon: TLS not supported (%s)\n",
			url, 0, 0 );
		ldap_free_urldesc( lud );
		return NULL;
	}

	if(! lud->lud_port ) {
230
		lud->lud_port = LDAP_PORT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
231
232
233
	}

#else
234
	l.sl_is_tls = ldap_pvt_url_scheme2tls( lud->lud_scheme );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
235

Kurt Zeilenga's avatar
Kurt Zeilenga committed
236
	if(! lud->lud_port ) {
237
		lud->lud_port = l.sl_is_tls ? LDAPS_PORT : LDAP_PORT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
238
239
240
	}
#endif

241
#ifdef HAVE_GETADDRINFO
Kurt Zeilenga's avatar
Kurt Zeilenga committed
242
243
244
245
246
	memset( &hints, '\0', sizeof(hints) );
	hints.ai_flags = AI_PASSIVE;
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

247
#  ifdef LDAP_PF_UNIX
248
	if ( ldap_pvt_url_scheme2proto(lud->lud_scheme) == LDAP_PROTO_IPC ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
249
250
251
252
253
254
255
256
257
258
		if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
			err = getaddrinfo(NULL, "/tmp/.ldap-sock", &hints, &res);
			if (!err)
				unlink( "/tmp/.ldap-sock" );
		} else {
			err = getaddrinfo(NULL, lud->lud_host, &hints, &res);
			if (!err)
				unlink( lud->lud_host );
		}
	} else
259
#  endif /* LDAP_PF_UNIX */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
	{
		snprintf(serv, sizeof serv, "%d", lud->lud_port);
		if( lud->lud_host == NULL || lud->lud_host[0] == '\0'
			|| strcmp(lud->lud_host, "*") == 0 )
		{
			err = getaddrinfo(NULL, serv, &hints, &res);
		} else {
			err = getaddrinfo(lud->lud_host, serv, &hints, &res);
		}
	}

	if ( err ) {
		Debug( LDAP_DEBUG_ANY, "daemon: getaddrinfo failed\n", 0, 0, 0);
		ldap_free_urldesc( lud );
		return NULL;
	}

	ldap_free_urldesc( lud );
	sai = res;
	do {
		l.sl_sd = socket( sai->ai_family, sai->ai_socktype, sai->ai_protocol);
		if ( l.sl_sd == AC_SOCKET_INVALID ) {
			Debug( LDAP_DEBUG_ANY,
				"daemon: socket() failed errno=%d (%s)\n", err,
				sock_errstr(err), 0 );
			continue;
		}

		if ( sai->ai_family != AF_UNIX ) {
#else
290

291
	if ( ldap_pvt_url_scheme2proto(lud->lud_scheme) == LDAP_PROTO_IPC ) {
292
#ifdef LDAP_PF_UNIX
293
294
295
296
297
298
299
300
301
302
		port = 0;
		(void) memset( (void *)&l.sl_sa.sa_un_addr, '\0', sizeof(l.sl_sa.sa_un_addr) );

		l.sl_sa.sa_un_addr.sun_family = AF_UNIX;

		/* hack: overload the host to be the path */
		if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
			strcpy( l.sl_sa.sa_un_addr.sun_path, "/tmp/.ldap-sock" );
		} else {
			if ( strlen(lud->lud_host) > (sizeof(l.sl_sa.sa_un_addr.sun_path) - 1) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
304
				Debug( LDAP_DEBUG_ANY,
					"daemon: domain socket path (%s) too long in URL: %s",
305
306
307
308
309
310
311
312
313
314
315
316
317
					lud->lud_host, url, 0);
				ldap_free_urldesc( lud );
				return NULL;
			}
			strcpy( l.sl_sa.sa_un_addr.sun_path, lud->lud_host );
		}
		unlink( l.sl_sa.sa_un_addr.sun_path ); 
#if 0
		/* I don't think we need to set this. */
		l.sl_sa.sa_un_addr.sun_len = sizeof( l.sl_sa.sa_un_addr.sun_len ) +
			sizeof( l.sl_sa.sa_un_addr.sun_family ) +
			strlen( l.sl_sa.sa_un_addr.sun_path ) + 1;
#endif
318
319
320
321
322
323
324
#else
		Debug( LDAP_DEBUG_ANY, "daemon: URL scheme not supported: %s",
			url, 0, 0);
		ldap_free_urldesc( lud );
		return NULL;
#endif /* LDAP_PF_UNIX */
	} else {
325

Kurt Zeilenga's avatar
Kurt Zeilenga committed
326
327
	port = lud->lud_port;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
328
329
330
331
332
333
334
335
336
337
338
339
	(void) memset( (void*) &l.sl_addr, '\0', sizeof(l.sl_addr) );

	l.sl_addr.sin_family = AF_INET;
	l.sl_addr.sin_port = htons( (unsigned short) lud->lud_port );

	if( lud->lud_host == NULL || lud->lud_host[0] == '\0'
		|| strcmp(lud->lud_host, "*") == 0 )
	{
		l.sl_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	} else {
		/* host or address was specified */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
340
		if( !inet_aton( lud->lud_host, &l.sl_addr.sin_addr ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
341
342
			struct hostent *he = gethostbyname( lud->lud_host );
			if( he == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
343
344
				Debug( LDAP_DEBUG_ANY,
					"daemon: invalid host (%s) in URL: %s",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
345
346
347
348
349
					lud->lud_host, url, 0);
				ldap_free_urldesc( lud );
				return NULL;
			}

350
351
			memcpy( &l.sl_addr.sin_addr, he->h_addr,
			       sizeof( l.sl_addr.sin_addr ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
353
		}
	}
354
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
355
356
357

	ldap_free_urldesc( lud );

358
359
	l.sl_sd = socket( l.sl_sa.sa_addr.sa_family, SOCK_STREAM, 0 );
	if ( l.sl_sd == AC_SOCKET_INVALID ) {
360
		int err = sock_errno();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
361
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
			"daemon: socket() failed errno=%d (%s)\n", err,
363
			sock_errstr(err), 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
364
		return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
365
366
367
368
369
370
371
372
	}

#ifndef HAVE_WINSOCK
	if ( l.sl_sd >= dtblsize ) {
		Debug( LDAP_DEBUG_ANY,
			"daemon: listener descriptor %ld is too great %ld\n",
			(long) l.sl_sd, (long) dtblsize, 0 );
		tcp_close( l.sl_sd );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
373
		return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
374
375
376
	}
#endif

377
#ifdef LDAP_PF_UNIX
378
379
	/* for IP sockets only */
	if ( l.sl_sa.sa_addr.sa_family == AF_INET ) {
380
#endif /* LDAP_PF_UNIX */
381
#endif /* HAVE_GETADDRINFO */
382

Kurt Zeilenga's avatar
Kurt Zeilenga committed
383
#ifdef SO_REUSEADDR
384
	/* enable address reuse */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
385
	tmp = 1;
386
387
388
	rc = setsockopt( l.sl_sd, SOL_SOCKET, SO_REUSEADDR,
		(char *) &tmp, sizeof(tmp) );
	if ( rc == AC_SOCKET_ERROR ) {
389
		int err = sock_errno();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
390
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
391
	       "slapd(%ld): setsockopt(SO_REUSEADDR) failed errno=%d (%s)\n",
392
	    	(long) l.sl_sd, err, sock_errstr(err) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
394
395
	}
#endif
#ifdef SO_KEEPALIVE
396
	/* enable keep alives */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
397
	tmp = 1;
398
399
400
	rc = setsockopt( l.sl_sd, SOL_SOCKET, SO_KEEPALIVE,
		(char *) &tmp, sizeof(tmp) );
	if ( rc == AC_SOCKET_ERROR ) {
401
		int err = sock_errno();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
402
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
403
			"slapd(%ld): setsockopt(SO_KEEPALIVE) failed errno=%d (%s)\n",
404
	    	(long) l.sl_sd, err, sock_errstr(err) );
405
406
407
	}
#endif
#ifdef TCP_NODELAY
408
	/* enable no delay */
409
	tmp = 1;
410
411
412
	rc = setsockopt( l.sl_sd, IPPROTO_TCP, TCP_NODELAY,
		(char *)&tmp, sizeof(tmp) );
	if ( rc == AC_SOCKET_ERROR ) {
413
		int err = sock_errno();
414
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
415
			"slapd(%ld): setsockopt(TCP_NODELAY) failed errno=%d (%s)\n",
416
	    	(long) l.sl_sd, err, sock_errstr(err) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
417
418
419
	}
#endif

420
#ifdef HAVE_GETADDRINFO
Kurt Zeilenga's avatar
Kurt Zeilenga committed
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
		} /* sai->ai_family != AF_UNIX */
		if (!bind(l.sl_sd, sai->ai_addr, sai->ai_addrlen))
			break;
		err = sock_errno();
		Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n",
			(long) l.sl_sd, err, sock_errstr(err) );
		tcp_close( l.sl_sd );
	} while ((sai = sai->ai_next) != NULL);

	if (!sai) {
		Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed\n",
			(long) l.sl_sd, 0, 0 );
		return NULL;
	}

	switch ( sai->ai_family ) {
437
#  ifdef LDAP_PF_UNIX
Kurt Zeilenga's avatar
Kurt Zeilenga committed
438
439
440
441
442
443
444
445
446
447
448
	case AF_UNIX:
		if ( chmod( (char *)sai->ai_addr, S_IRWXU ) < 0 ) {
			err = sock_errno();
			Debug( LDAP_DEBUG_ANY, "daemon: fchmod(%ld) failed errno=%d (%s)",
				(long) l.sl_sd, err, sock_errstr(err) );
			tcp_close( l.sl_sd );
			return NULL;
		}
		l.sl_name = ch_malloc( strlen((char *)sai->ai_addr) + sizeof("PATH=") );
		sprintf( l.sl_name, "PATH=%s", sai->ai_addr );
		break;
449
#  endif /* LDAP_PF_UNIX */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
451
452
453
454
455
456
457
458
459

	case AF_INET: {
		char addr[INET_ADDRSTRLEN];
		inet_ntop( AF_INET,
			&((struct sockaddr_in *)sai->ai_addr)->sin_addr,
			addr, sizeof(addr) );
		l.sl_name = ch_malloc( strlen(addr) + strlen(serv) + sizeof("IP=:") );
		sprintf( l.sl_name, "IP=%s:%s", addr, serv );
	} break;

460
#  ifdef LDAP_PF_INET6
Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
462
463
464
465
466
467
468
	case AF_INET6: {
		char addr[INET6_ADDRSTRLEN];
		inet_ntop( AF_INET6,
			&((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr,
			addr, sizeof addr);
		l.sl_name = ch_malloc( strlen(addr) + strlen(serv) + sizeof("IP= ") );
		sprintf( l.sl_name, "IP=%s %s", addr, serv );
	} break;
469
#  endif /* LDAP_PF_INET6 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
470
471
472
473
474
475
476

	default:
		Debug( LDAP_DEBUG_ANY, "daemon: unsupported address family (%d)\n",
			(int) sai->ai_family, 0, 0 );
		break;
	}
#else
477
#ifdef LDAP_PF_UNIX
478
479
	/* close conditional */
	}
480
#endif /* LDAP_PF_UNIX */
481
482

	switch ( l.sl_sa.sa_addr.sa_family ) {
483
#ifdef LDAP_PF_UNIX
484
485
486
487
		case AF_UNIX:
			rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa,
				sizeof(l.sl_sa.sa_un_addr) );
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
489
#endif

490
491
492
493
		case AF_INET:
			rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa,
				sizeof(l.sl_sa.sa_in_addr) );
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
494

495
496
497
498
499
		default:
			rc = AC_SOCKET_ERROR;
			errno = EINVAL;
			break;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
500

501
	if ( rc == AC_SOCKET_ERROR ) {
502
		int err = sock_errno();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
503
		Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n",
504
	    	(long) l.sl_sd, err, sock_errstr(err) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
505
		tcp_close( l.sl_sd );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
506
		return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
507
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
508

509
	switch ( l.sl_sa.sa_addr.sa_family ) {
510
#ifdef LDAP_PF_UNIX
511
		case AF_UNIX:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
512
513
514
515
516
517
518
519
520
521
522
			if ( chmod( l.sl_sa.sa_un_addr.sun_path, S_IRWXU ) < 0 ) {
				int err = sock_errno();
				Debug( LDAP_DEBUG_ANY,
					"daemon: chmod(%ld) failed errno=%d (%s)",
					(long) l.sl_sd, err, sock_errstr(err) );
				tcp_close( l.sl_sd );
				return NULL;
			}

			l.sl_name = ch_malloc( strlen(l.sl_sa.sa_un_addr.sun_path)
				+ sizeof("PATH=") );
523
524
			sprintf( l.sl_name, "PATH=%s", l.sl_sa.sa_un_addr.sun_path );
			break;
525
#endif /* LDAP_PF_UNIX */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
526

527
528
529
530
531
532
		case AF_INET:
			l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65336") );
			s = inet_ntoa( l.sl_addr.sin_addr );
			sprintf( l.sl_name, "IP=%s:%d",
				s != NULL ? s : "unknown" , port );
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
533

534
535
536
537
		default:
			l.sl_name = ch_strdup( "UNKNOWN" );
			break;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
538

539
#endif /* HAVE_GETADDRINFO */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
540
541

	l.sl_url = ch_strdup( url );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
542
543
544
	li = ch_malloc( sizeof( Listener ) );
	*li = l;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
545
546
547
	Debug( LDAP_DEBUG_TRACE, "daemon: initialized %s\n",
		l.sl_url, 0, 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
548
549
550
551
552
553
	return li;
}

static int sockinit(void);
static int sockdestroy(void);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
554
int slapd_daemon_init( const char *urls )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
555
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
557
	int i, rc;
	char **u;
558

559
560
	Debug( LDAP_DEBUG_ARGS, "daemon_init: %s\n",
		urls ? urls : "<null>", 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
561

Hallvard Furuseth's avatar
Hallvard Furuseth committed
562
	if( (rc = sockinit()) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
563
564
		return rc;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
565

Kurt Zeilenga's avatar
Kurt Zeilenga committed
566
#ifdef HAVE_SYSCONF
Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
	dtblsize = sysconf( _SC_OPEN_MAX );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
568
#elif HAVE_GETDTABLESIZE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
569
	dtblsize = getdtablesize();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
570
#else
Gary Williams's avatar
NT port    
Gary Williams committed
571
	dtblsize = FD_SETSIZE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
572
573
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
574
#ifdef FD_SETSIZE
575
576
577
	if(dtblsize > FD_SETSIZE) {
		dtblsize = FD_SETSIZE;
	}
578
#endif	/* !FD_SETSIZE */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
579

580
581
582
583
	/* 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
	 * this byte arrives.
584
	 */
585
	if( (rc = lutil_pair( wake_sds )) < 0 ) {
586
		Debug( LDAP_DEBUG_ANY,
587
588
			"daemon: lutil_pair() failed rc=%d\n", rc, 0, 0 );
		return rc;
589
590
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
591
592
	FD_ZERO( &slap_daemon.sd_readers );
	FD_ZERO( &slap_daemon.sd_writers );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
593

Kurt Zeilenga's avatar
Kurt Zeilenga committed
594
	if( urls == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
595
		urls = "ldap:///";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
596
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
597

Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
	u = str2charray( urls, " " );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
599

Kurt Zeilenga's avatar
Kurt Zeilenga committed
600
601
602
603
	if( u == NULL || u[0] == NULL ) {
		Debug( LDAP_DEBUG_ANY, "daemon_init: no urls (%s) provided.\n",
			urls, 0, 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
604
605
		return -1;
	}
606

Kurt Zeilenga's avatar
Kurt Zeilenga committed
607
608
609
	for( i=0; u[i] != NULL; i++ ) {
		Debug( LDAP_DEBUG_TRACE, "daemon_init: listen on %s\n",
			u[i], 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
610
	}
611

Kurt Zeilenga's avatar
Kurt Zeilenga committed
612
613
614
	if( i == 0 ) {
		Debug( LDAP_DEBUG_ANY, "daemon_init: no listeners to open (%s)\n",
			urls, 0, 0 );
Hallvard Furuseth's avatar
Hallvard Furuseth committed
615
		charray_free( u );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
616
617
618
619
620
621
		return -1;
	}

	Debug( LDAP_DEBUG_TRACE, "daemon_init: %d listeners to open...\n",
		i, 0, 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
622
623
	slap_listeners = ch_malloc( (i+1)*sizeof(Listener *) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
624
	for(i = 0; u[i] != NULL; i++ ) {
625
		slap_listeners[i] = open_listener( u[i] );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
626
627

		if( slap_listeners[i] == NULL ) {
Hallvard Furuseth's avatar
Hallvard Furuseth committed
628
			charray_free( u );
629
			return -1;
630
		}
631
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
632
633
	slap_listeners[i] = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
634
	Debug( LDAP_DEBUG_TRACE, "daemon_init: %d listeners opened\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
635
		i, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
636
637
638

	charray_free( u );
	ldap_pvt_thread_mutex_init( &slap_daemon.sd_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
639
	return !i;
640
641
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
642

Hallvard Furuseth's avatar
Hallvard Furuseth committed
643
int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
644
645
646
slapd_daemon_destroy(void)
{
	connections_destroy();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
647
648
	tcp_close( wake_sds[1] );
	tcp_close( wake_sds[0] );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
649
650
651
652
653
	sockdestroy();
	return 0;
}


654
655
656
657
658
static void *
slapd_daemon_task(
	void *ptr
)
{
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
659
	int l;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
660
	time_t	last_idle_check = slap_get_time();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
661
	time( &starttime );
662

Kurt Zeilenga's avatar
Kurt Zeilenga committed
663
664
665
	for ( l = 0; slap_listeners[l] != NULL; l++ ) {
		if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
			continue;
666

Kurt Zeilenga's avatar
Kurt Zeilenga committed
667
		if ( listen( slap_listeners[l]->sl_sd, 5 ) == -1 ) {
668
			int err = sock_errno();
669
			Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
670
				"daemon: listen(%s, 5) failed errno=%d (%s)\n",
Hallvard Furuseth's avatar
Hallvard Furuseth committed
671
					slap_listeners[l]->sl_url, err,
672
					sock_errstr(err) );
673
			return( (void*)-1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
674
		}
675

Kurt Zeilenga's avatar
Kurt Zeilenga committed
676
		slapd_add( slap_listeners[l]->sl_sd );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
677
678
	}

679
#ifdef HAVE_NT_SERVICE_MANAGER
Kurt Zeilenga's avatar
Kurt Zeilenga committed
680
	if ( started_event != NULL ) {
681
		ldap_pvt_thread_cond_signal( &started_event );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
682
	}
683
#endif
684
	/* initialization complete. Here comes the loop. */
685

Kurt Zeilenga's avatar
Kurt Zeilenga committed
686
	while ( !slapd_shutdown ) {
687
688
		ber_socket_t i;
		int ns;
689
		int at;
690
		ber_socket_t nfds;
691
#define SLAPD_EBADF_LIMIT 10
692
693
694
		int ebadf = 0;

#define SLAPD_IDLE_CHECK_LIMIT 4
Kurt Zeilenga's avatar
Kurt Zeilenga committed
695
		time_t	now = slap_get_time();
696

697
698
699

		fd_set			readfds;
		fd_set			writefds;
700
		Sockaddr		from;
701

702
#if defined(SLAPD_RLOOKUPS)
703
704
        struct hostent		*hp;
#endif
705
		struct timeval		zero;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
706
707
		struct timeval		*tvp;

708
709
710
		if( global_idletimeout > 0 && difftime(
			last_idle_check+global_idletimeout/SLAPD_IDLE_CHECK_LIMIT,
			now ) < 0 )
711
712
713
714
		{
			connections_timeout_idle(now);
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
715
716
717
		FD_ZERO( &writefds );
		FD_ZERO( &readfds );

718
719
720
		zero.tv_sec = 0;
		zero.tv_usec = 0;

721
		ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
722

723
724
#ifdef FD_SET_MANUAL_COPY
		for( s = 0; s < nfds; s++ ) {
725
726
			if(FD_ISSET( &slap_sd_readers, s )) {
				FD_SET( s, &readfds );
727
728
			}
			if(FD_ISSET( &slap_sd_writers, s )) {
729
				FD_SET( s, &writefds );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
730
731
			}
		}
732
733
734
735
#else
		memcpy( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) );
		memcpy( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) );
#endif
736
		assert(!FD_ISSET(wake_sds[0], &readfds));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
737
		FD_SET( wake_sds[0], &readfds );
738

Kurt Zeilenga's avatar
Kurt Zeilenga committed
739
740
		for ( l = 0; slap_listeners[l] != NULL; l++ ) {
			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
741
				continue;
742
743
			if (!FD_ISSET(slap_listeners[l]->sl_sd, &readfds))
			    FD_SET( slap_listeners[l]->sl_sd, &readfds );
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
744
		}
745
746
747
748
749
750
751
752

#ifndef HAVE_WINSOCK
		nfds = slap_daemon.sd_nfds;
#else
		nfds = dtblsize;
#endif

		ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
753

754
		at = ldap_pvt_thread_pool_backload(connection_pool);
755

756
#if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS )
757
		tvp = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
758
#else
759
		tvp = at ? &zero : NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
760
#endif
761

Kurt Zeilenga's avatar
Kurt Zeilenga committed
762
763
		for ( l = 0; slap_listeners[l] != NULL; l++ ) {
			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
764
				continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
765

Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
766
			Debug( LDAP_DEBUG_CONNS,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
767
768
769
				"daemon: select: listen=%d active_threads=%d tvp=%s\n",
					slap_listeners[l]->sl_sd, at,
					tvp == NULL ? "NULL" : "zero" );
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
770
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
771

772
773
774
775
776
777
778
779
780
		switch(ns = select( nfds, &readfds,
#ifdef HAVE_WINSOCK
			/* don't pass empty fd_set */
			( writefds.fd_count > 0 ? &writefds : NULL ),
#else
			&writefds,
#endif
			NULL, tvp ))
		{
781
		case -1: {	/* failure - try again */
782
783
				int err = sock_errno();

784
785
786
787
788
789
790
				if( err == EBADF 
#ifdef HAVE_WINSOCK
					|| err == WSAENOTSOCK	/* you'd think this would be EBADF */
#endif
				) {
					if (++ebadf < SLAPD_EBADF_LIMIT)
						continue;
791
792
793
				}

				if( err != EINTR ) {
794
795
					Debug( LDAP_DEBUG_CONNS,
						"daemon: select failed (%d): %s\n",
796
						err, sock_errstr(err), 0 );
797

798
					slapd_shutdown = -1;
799
				}
800
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
801
802
803
			continue;

		case 0:		/* timeout - let threads run */
804
			ebadf = 0;
805
			Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
806
			    0, 0, 0 );
807
	     	ldap_pvt_thread_yield();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
808
809
810
			continue;

		default:	/* something happened - deal with it */
811
			ebadf = 0;
812
813
814
			Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n",
				ns, 0, 0 );
			/* FALL THRU */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
815
816
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
817
		if( FD_ISSET( wake_sds[0], &readfds ) ) {
818
819
			char c[BUFSIZ];
			tcp_read( wake_sds[0], c, sizeof(c) );
820
821
822
#ifdef NO_THREADS
			waking = 0;
#endif
823
824
			continue;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
825

Kurt Zeilenga's avatar
Kurt Zeilenga committed
826
		for ( l = 0; slap_listeners[l] != NULL; l++ ) {
827
			ber_int_t s;
828
			socklen_t len = sizeof(from);
829
830
			long id;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
831
832
			char	*dnsname;
			char	*peeraddr;
833
#ifdef LDAP_PF_UNIX
834
			char	peername[MAXPATHLEN + sizeof("PATH=")];
835
#elif defined(LDAP_PF_INET6)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
836
			char	peername[sizeof("IP=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535")];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
837
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
838
			char	peername[sizeof("IP=255.255.255.255:65336")];
839
#endif /* LDAP_PF_UNIX */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
840
841
842

			peername[0] = '\0';

Kurt Zeilenga's avatar
Kurt Zeilenga committed
843
			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
844
				continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
845
846

			if ( !FD_ISSET( slap_listeners[l]->sl_sd, &readfds ) )
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
847
848
				continue;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
849
			if ( (s = accept( slap_listeners[l]->sl_sd,
850
				(struct sockaddr *) &from, &len )) == AC_SOCKET_INVALID )
851
			{
852
				int err = sock_errno();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
853
				Debug( LDAP_DEBUG_ANY,
854
855
				    "daemon: accept(%ld) failed errno=%d (%s)\n",
				    (long) slap_listeners[l]->sl_sd, err,
856
				    sock_errstr(err) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
857
858
				continue;
			}
859

860
861
862
863
864
865
866
867
868
869
870
#ifdef LDAP_DEBUG
			ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

			/* newly accepted stream should not be in any of the FD SETS */

			assert( !FD_ISSET( s, &slap_daemon.sd_actives) );
			assert( !FD_ISSET( s, &slap_daemon.sd_readers) );
			assert( !FD_ISSET( s, &slap_daemon.sd_writers) );

			ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
#endif
871
872

#ifndef HAVE_WINSOCK
873
			/* make sure descriptor number isn't too great */
874
			if ( s >= dtblsize ) {
875
				Debug( LDAP_DEBUG_ANY,
876
877
					"daemon: %ld beyond descriptor table size %ld\n",
					(long) s, (long) dtblsize, 0 );
878
				slapd_close(s);
879
880
				continue;
			}
881
#endif
882
		   
883
884
			Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %ld\n",
				(long) s, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
885
886

			len = sizeof(from);
887

Kurt Zeilenga's avatar
Kurt Zeilenga committed
888
			if ( getpeername( s, (struct sockaddr *) &from, &len ) != 0 ) {
889
				int err = sock_errno();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
890
891
				Debug( LDAP_DEBUG_ANY,
					"daemon: getpeername( %ld ) failed: errno=%d (%s)\n",
892
					(long) s, err, sock_errstr(err) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
893
894
895
				slapd_close(s);
				continue;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
896

897
			switch ( from.sa_addr.sa_family ) {
898
#  ifdef LDAP_PF_UNIX
899
900
901
			case AF_UNIX:
				sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path );
				break;
902
#endif /* LDAP_PF_UNIX */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
903

904
#  ifdef LDAP_PF_INET6
Kurt Zeilenga's avatar
Kurt Zeilenga committed
905
906
907
908
909
910
911
912
			case AF_INET6: {
				char addr[INET6_ADDRSTRLEN];
				sprintf( peername, "IP=%s %d",
					inet_ntop( AF_INET6,
						&from.sa_in6_addr.sin6_addr,
					    addr, sizeof addr) ? addr : "unknown",
					(unsigned) ntohs( from.sa_in6_addr.sin6_port ) );
			} break;
913
#  endif /* LDAP_PF_INET6 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
914
915

			case AF_INET:
916
			peeraddr = inet_ntoa( from.sa_in_addr.sin_addr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
917
			sprintf( peername, "IP=%s:%d",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
918
				peeraddr != NULL ? peeraddr : "unknown",
919
				(unsigned) ntohs( from.sa_in_addr.sin_port ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
920
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
921

Kurt Zeilenga's avatar
Kurt Zeilenga committed
922
923
924
925
			default:
				slapd_close(s);
				continue;
			}