--- ldap/servers/slapd/daemon.c	Mon May 22 03:46:57 2000
+++ ldap6/servers/slapd/daemon.c	Tue Jun  6 10:33:54 2000
@@ -1,9 +1,22 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/daemon.c,v 1.135 2000/05/22 01:46:57 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/daemon.c,v 1.134 2000/05/13 00:47:57 kurt Exp $ */
 /*
  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 
+/*
+ * Portions
+ * Copyright 2000 Stig Venaas, UNINETT
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * without restriction or fee of any kind as long as this notice is
+ * preserved. The name of UNINETT may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission. This software is provided ``as is'' without express or
+ * implied warranty.
+ */
+
 #include "portable.h"
 
 #include <stdio.h>
@@ -35,13 +48,18 @@
 time_t starttime;
 ber_socket_t dtblsize;
 
-#ifdef LDAP_PF_LOCAL
+#if defined( LDAP_PF_LOCAL ) || defined( LDAP_INET6 )
 typedef union slap_sockaddr {
 	struct sockaddr sa_addr;
 	struct sockaddr_in sa_in_addr;
+#  ifdef LDAP_INET6
+	struct sockaddr_in6 sa_in6_addr;
+#  endif
+#  ifdef LDAP_PF_LOCAL
 	struct sockaddr_un sa_un_addr;
+#  endif
 } Sockaddr;
-#endif /* LDAP_PF_LOCAL */
+#endif /* LDAP_PF_LOCAL || LDAP_INET6 */
 
 typedef struct slap_listener {
 	char* sl_url;
@@ -53,7 +71,7 @@
 #ifdef LDAP_PF_LOCAL
 	Sockaddr sl_sa;
 #define sl_addr	sl_sa.sa_in_addr
-#else	
+#else
 	struct sockaddr_in	sl_addr;
 #endif /* LDAP_PF_LOCAL */
 } Listener;
@@ -194,7 +212,6 @@
 	tcp_close(s);
 }
 
-
 static Listener * open_listener( const char* url )
 {
 	int	tmp, rc;
@@ -203,6 +220,11 @@
 	LDAPURLDesc *lud;
 	char *s;
 	int port;
+#ifdef LDAP_INET6
+	char serv[7];
+	struct addrinfo hints, *res, *sai;
+	int err;
+#endif /* LDAP_INET6 */
 
 	rc = ldap_url_parse( url, &lud );
 
@@ -233,8 +255,53 @@
 		lud->lud_port = (lud->lud_properties & LDAP_URL_USE_SSL) ? LDAPS_PORT : LDAP_PORT;
 	}
 #endif
-
-#ifdef LDAP_PF_LOCAL
+#ifdef LDAP_INET6
+        bzero(&hints, sizeof hints);
+	hints.ai_flags = AI_PASSIVE;
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+#  ifdef LDAP_PF_LOCAL
+	if (lud->lud_protocol == LDAP_PROTO_LOCAL) {
+		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 {
+#  endif /* LDAP_PF_LOCAL */
+	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);
+	}
+#  ifdef LDAP_PF_LOCAL
+	}
+#  endif /* LDAP_PF_LOCAL */
+	if ( err ) {
+	        Debug( LDAP_DEBUG_ANY, "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
+#  ifdef LDAP_PF_LOCAL
 	if (lud->lud_protocol == LDAP_PROTO_LOCAL) {
 		port = 0;
 		(void) memset( (void *)&l.sl_sa.sa_un_addr, '\0', sizeof(l.sl_sa.sa_un_addr) );
@@ -254,27 +321,22 @@
 			strcpy( l.sl_sa.sa_un_addr.sun_path, lud->lud_host );
 		}
 		unlink( l.sl_sa.sa_un_addr.sun_path ); 
-#if 0
+#    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
+#    endif
 	} else {
-#endif /* LDAP_PF_LOCAL */
-
+#  endif /* LDAP_PF_LOCAL */
 	port = lud->lud_port;
-
 	(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 */
 		if( !inet_aton( lud->lud_host, &l.sl_addr.sin_addr ) ) {
@@ -285,23 +347,22 @@
 				ldap_free_urldesc( lud );
 				return NULL;
 			}
-
 			memcpy( &l.sl_addr.sin_addr, he->h_addr,
 			       sizeof( l.sl_addr.sin_addr ) );
 		}
 	}
-#ifdef LDAP_PF_LOCAL
+#  ifdef LDAP_PF_LOCAL
 	}
-#endif /* LDAP_PF_LOCAL */
+#  endif /* LDAP_PF_LOCAL */
 
 	ldap_free_urldesc( lud );
 
-#ifdef LDAP_PF_LOCAL
+#  ifdef LDAP_PF_LOCAL
 	l.sl_sd = socket( l.sl_sa.sa_addr.sa_family, SOCK_STREAM, 0 );
 	if ( l.sl_sd == AC_SOCKET_INVALID ) {
-#else
+#  else
 	if ( (l.sl_sd = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID ) {
-#endif /* LDAP_PF_LOCAL */
+#  endif /* LDAP_PF_LOCAL */
 		int err = sock_errno();
 		Debug( LDAP_DEBUG_ANY,
 			"daemon: socket() failed errno=%d (%s)\n", err,
@@ -309,7 +370,7 @@
 		return NULL;
 	}
 
-#ifndef HAVE_WINSOCK
+#  ifndef HAVE_WINSOCK
 	if ( l.sl_sd >= dtblsize ) {
 		Debug( LDAP_DEBUG_ANY,
 			"daemon: listener descriptor %ld is too great %ld\n",
@@ -317,12 +378,13 @@
 		tcp_close( l.sl_sd );
 		return NULL;
 	}
-#endif
+#  endif
 
-#ifdef LDAP_PF_LOCAL
+#  ifdef LDAP_PF_LOCAL
 	/* for IP sockets only */
 	if ( l.sl_sa.sa_addr.sa_family == AF_INET ) {
-#endif /* LDAP_PF_LOCAL */
+#  endif /* LDAP_PF_LOCAL */
+#endif /* LDAP_INET6 */
 
 #ifdef SO_REUSEADDR
 	/* enable address reuse */
@@ -361,7 +423,58 @@
 	}
 #endif
 
-#ifdef LDAP_PF_LOCAL
+#ifdef LDAP_INET6
+	        } /* 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 ) {
+#  ifdef LDAP_PF_LOCAL
+	        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;
+#  endif /* LDAP_PF_LOCAL */
+	        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;
+	        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;
+	        default:
+		        Debug( LDAP_DEBUG_ANY, "daemon: unsupported address family\n", 0, 0, 0 );
+			break;
+	}
+#else
+#  ifdef LDAP_PF_LOCAL
 	/* close conditional */
 	}
 
@@ -369,27 +482,27 @@
 		case AF_UNIX:
 			rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa,
 				sizeof(l.sl_sa.sa_un_addr) );
-			break;
+			break;	
 		case AF_INET:
 			rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa,
 				sizeof(l.sl_sa.sa_in_addr) );
 			break;
-		default:
+	default:
 			rc = AC_SOCKET_ERROR;
 			errno = EINVAL;
 			break;
 	}
-#else
+#  else
 	rc = bind( l.sl_sd, (struct sockaddr *) &l.sl_addr, sizeof(l.sl_addr) );
-#endif /* LDAP_PF_LOCAL */
+#  endif /* LDAP_PF_LOCAL */
 	if ( rc == AC_SOCKET_ERROR ) {
 		int err = sock_errno();
 		Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n",
-	    	(long) l.sl_sd, err, sock_errstr(err) );
+		       (long) l.sl_sd, err, sock_errstr(err) );
 		tcp_close( l.sl_sd );
 		return NULL;
 	}
-#ifdef LDAP_PF_LOCAL
+#  ifdef LDAP_PF_LOCAL
 	if ( l.sl_sa.sa_addr.sa_family == AF_UNIX ) {
 		if ( chmod( l.sl_sa.sa_un_addr.sun_path, S_IRWXU ) < 0 ) {
 			int err = sock_errno();
@@ -399,31 +512,27 @@
 			return NULL;
 		}
 	}
-#endif /* LDAP_PF_LOACL */
-	l.sl_url = ch_strdup( url );
-#ifdef LDAP_PF_LOCAL
 	switch ( l.sl_sa.sa_addr.sa_family ) {
 		case AF_UNIX:
 			l.sl_name = ch_malloc( strlen(l.sl_sa.sa_un_addr.sun_path) + sizeof("PATH=") );
 			sprintf( l.sl_name, "PATH=%s", l.sl_sa.sa_un_addr.sun_path );
 			break;
-		case AF_INET:
-			l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65336") );
+	        case AF_INET:
+#  endif /* LDAP_PF_LOCAL */
+		        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 );
+				 s != NULL ? s : "unknown" , port );
+#  ifdef LDAP_PF_LOCAL
 			break;
 		default:
 			l.sl_name = ch_strdup( "UNKNOWN" );
 			break;
 	}
-#else
-	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 );
-#endif /* LDAP_PF_LOCAL */
+#  endif /* LDAP_PF_LOCAL */
+#endif /* LDAP_INET6 */
 
+	l.sl_url = ch_strdup( url );
 	li = ch_malloc( sizeof( Listener ) );
 	*li = l;
 
@@ -436,7 +545,7 @@
 static int sockinit(void);
 static int sockdestroy(void);
 
-int slapd_daemon_init( const char *urls )
+int slapd_daemon_init( char *urls )
 {
 	int i, rc;
 	char **u;
@@ -582,14 +691,14 @@
 
 		fd_set			readfds;
 		fd_set			writefds;
-#ifdef LDAP_PF_LOCAL
+#if defined( LDAP_PF_LOCAL ) || defined( LDAP_INET6 )
 		Sockaddr		from;
 /* minimize impact, undefine later. */
 #define	sin_addr sa_in_addr.sin_addr
 #define	sin_port sa_in_addr.sin_port
 #else
 		struct sockaddr_in	from;
-#endif /* LDAP_PF_LOCAL */
+#endif /* LDAP_PF_LOCAL || LDAP_INET6 */
 #if defined(SLAPD_RLOOKUPS)
         struct hostent		*hp;
 #endif
@@ -726,7 +835,11 @@
 #ifdef LDAP_PF_LOCAL
 			char	peername[MAXPATHLEN + sizeof("PATH=")];
 #else
+#  ifdef LDAP_INET6
+			char	peername[sizeof("IP=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535")];
+#  else
 			char	peername[sizeof("IP=255.255.255.255:65336")];
+#  endif
 #endif /* LDAP_PF_LOCAL */
 			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
 				continue;
@@ -782,32 +895,56 @@
 				continue;
 			}
 
-#ifdef LDAP_PF_LOCAL
+#if defined( LDAP_PF_LOCAL ) || defined( LDAP_INET6 )
 			switch ( from.sa_addr.sa_family ) {
-			case AF_UNIX:
-				sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path );
-				break;
-			case AF_INET:
-#endif /* LDAP_PF_LOCAL */
-			peeraddr = inet_ntoa( from.sin_addr );
-			sprintf( peername, "IP=%s:%d",
-				peeraddr != NULL ? peeraddr : "unknown",
-				(unsigned) ntohs( from.sin_port ) );
+#  ifdef LDAP_PF_LOCAL
+			        case AF_UNIX:
+				        sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path );
+					break;
+#  endif /* LDAP_PF_LOCAL */
+#  ifdef LDAP_INET6
+			        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;
+#  endif /* LDAP_INET6 */
+			        case AF_INET:
+#endif /* LDAP_PF_LOCAL || LDAP_INET6 */
+				        peeraddr = inet_ntoa( from.sin_addr );
+					sprintf( peername, "IP=%s:%d",
+						 peeraddr != NULL ? peeraddr : "unknown",
+						 (unsigned) ntohs( from.sin_port ) );
+#if defined( LDAP_PF_LOCAL ) || defined( LDAP_INET6 )
+					break;
+			        default:
+				        slapd_close(s);
+					continue;
+			}
+			if ( from.sa_addr.sa_family != AF_UNIX ) {
+#endif /* LDAP_PF_LOCAL || LDAP_INET6 */
+#ifdef SLAPD_RLOOKUPS
+#  ifdef LDAP_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
+#  endif LDAP_INET6
+			hp = gethostbyaddr( (char *) &(from.sin_addr),
+					    sizeof(from.sin_addr), AF_INET );
 
-#if defined(SLAPD_RLOOKUPS)
-			hp = gethostbyaddr( (char *)
-			    &(from.sin_addr),
-			    sizeof(from.sin_addr), AF_INET );
-
-			if(hp) {
-				dnsname = ldap_pvt_str2lower( hp->h_name );
-
-			} else {
-				dnsname = NULL;
-			}
+			dnsname = hp ? ldap_pvt_str2lower( hp->h_name ) : NULL;
 #else
 			dnsname = NULL;
-#endif
+#endif /* SLAPD_RLOOKUPS */
 
 #ifdef HAVE_TCPD
 			if( !hosts_ctl("slapd",
@@ -827,15 +964,11 @@
 				continue;
 			}
 #endif /* HAVE_TCPD */
-#ifdef LDAP_PF_LOCAL
-				break;
-			default:
-				slapd_close(s);
-				continue;
+#if defined( LDAP_PF_LOCAL ) || defined( LDAP_INET6 )
 			}
 #undef	sin_addr
 #undef	sin_port
-#endif /* LDAP_PF_LOCAL */
+#endif /* LDAP_PF_LOCAL || LDAP_INET6 */
 
 			if( (id = connection_init(s,
 				slap_listeners[l]->sl_url,
