support-launchd-init-mode   [plain text]


Index: samba/source/configure.in
===================================================================
--- samba/source/configure.in.orig
+++ samba/source/configure.in
@@ -358,6 +358,35 @@ AC_ARG_ENABLE(swat,
     AC_SUBST(SWAT_INSTALL_TARGETS)
 ])
 
+AC_ARG_ENABLE(launchd,
+[  --enable-launchd        Support running under launchd (default=auto)])
+
+if test x"enable_launchd" != x"no" ; then
+    AC_CACHE_CHECK([whether to include launchd support],
+	samba_cv_launchd_support,
+	[
+	    AC_TRY_COMPILE(
+	    [
+#include <launch.h>
+	    ],
+	    [
+		launchd_msg(NULL);
+		launchd_data_get_fd(NULL);
+	    ],
+	    samba_cv_launchd_support=yes,
+	    samba_cv_launchd_support=no)
+	])
+
+    if test x"$samba_cv_launchd_support" = x"yes" ; then
+	AC_DEFINE(WITH_LAUNCHD_SUPPORT, 1,
+		    [Whether launchd support should be enabled])
+    else
+	if test x"$enable_launchd" = x"yes" ; then
+	    AC_ERROR(launchd support is not available)
+	fi
+    fi
+fi
+
 #################################################
 # set prefix for 'make test'
 selftest_prefix="./"
Index: samba/source/include/smb_launchd.h
===================================================================
--- /dev/null
+++ samba/source/include/smb_launchd.h
@@ -0,0 +1,44 @@
+/*
+   Unix SMB/CIFS implementation.
+   Launchd integration wrapper API
+
+   Copyright (C) 2007 Apple Inc. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct smb_launch_info
+{
+	int idle_timeout_secs;
+	int num_sockets;
+	int *socket_list;
+};
+
+/* Retrieve launchd configuration. Returns True if we are running under
+ * launchd, False otherwise. NOTE this does not guarantee to provide a list of
+ * sockets since this is a user configuration option.
+ */
+BOOL smb_launchd_checkin(struct smb_launch_info *linfo);
+
+/* Retrieve launchd configuration. The variadic arguments are a list of
+ * constant null-terminated strings. The strings are the names of the socket
+ * dictionaries to retrieve sockets from. The list of names is terminated by a
+ * NULL.
+ */
+BOOL smb_launchd_checkin_names(struct smb_launch_info *linfo, ...);
+
+
+/* Free any data or state associated with a successful launchd checkin. */
+void smb_launchd_checkout(struct smb_launch_info *linfo);
Index: samba/source/lib/launchd.c
===================================================================
--- /dev/null
+++ samba/source/lib/launchd.c
@@ -0,0 +1,238 @@
+/*
+   Unix SMB/CIFS implementation.
+   Launchd integration wrapper API
+
+   Copyright (C) 2007 Apple Inc. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "smb_launchd.h"
+
+#if defined(WITH_LAUNCHD_SUPPORT)
+
+#include <launch.h>
+#include <stdarg.h>
+
+typedef void (*launchd_iterator)(launch_data_t, const char*, void*);
+
+#define LAUNCHD_TRACE_LEVEL 10
+
+ void smb_launchd_checkout(struct smb_launch_info *linfo)
+{
+	talloc_free(linfo->socket_list);
+}
+
+static void pull_launch_sockets(launch_data_t key,
+				const char *name,
+				struct smb_launch_info *linfo)
+{
+	launch_data_type_t type;
+
+	type = launch_data_get_type(key);
+	DEBUG(LAUNCHD_TRACE_LEVEL,
+		("Searching item name='%s' type=%d for sockets\n",
+		 name ? name : "", (int)type));
+
+	switch (type) {
+	case LAUNCH_DATA_FD:
+		if (!linfo->socket_list) {
+			/* We are counting the number of sockets. */
+			linfo->num_sockets++;
+		} else {
+			/* We are collecting the socket fds. */
+			int fd = launch_data_get_fd(key);
+
+			linfo->socket_list[linfo->num_sockets] = fd;
+			linfo->num_sockets++;
+			DEBUG(LAUNCHD_TRACE_LEVEL,
+				("Added fd=%d to launchd set\n", fd));
+		}
+		return;
+	case LAUNCH_DATA_ARRAY:
+	{
+		int i;
+		launch_data_t item;
+
+		for (i = 0; i < launch_data_array_get_count(key); ++i) {
+			item = launch_data_array_get_index(key, i);
+			pull_launch_sockets(item, name, linfo);
+		}
+		return;
+	}
+	case LAUNCH_DATA_DICTIONARY:
+		launch_data_dict_iterate(key,
+			(launchd_iterator)pull_launch_sockets, linfo);
+		return;
+	default:
+		return;
+	}
+}
+
+ BOOL smb_launchd_checkin_names(struct smb_launch_info *linfo, ...)
+{
+	launch_data_t msg;
+	launch_data_t resp;
+	launch_data_t item;
+	BOOL is_launchd = False;
+
+	ZERO_STRUCTP(linfo);
+
+	msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+	resp = launch_msg(msg);
+	if (resp == NULL) {
+		/* IPC to launchd failed. */
+		launch_data_free(msg);
+		return is_launchd;
+	}
+
+	if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
+		errno = launch_data_get_errno(resp);
+		goto done;
+	}
+
+	/* At this point, we know we are running under launchd. */
+	linfo->idle_timeout_secs = 600;
+	is_launchd = True;
+
+	if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
+		linfo->idle_timeout_secs = launch_data_get_integer(item);
+	}
+
+	if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
+		int count = 0;
+		const char * sockname = NULL;
+		launch_data_t sockdata;
+		va_list args;
+
+		/* Figure out the maximum number of sockets. */
+		va_start(args, linfo);
+		while ((sockname = va_arg(args, const char *))) {
+		    ++count;
+		}
+		va_end(args);
+
+		DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
+					linfo->num_sockets));
+
+		if (launch_data_dict_get_count(item) < count) {
+			DEBUG(0, ("%d launchd sockets requested, "
+			    "but only %d are available\n",
+			    count, launch_data_dict_get_count(item)));
+		}
+
+		linfo->socket_list = talloc_array(NULL, int, count);
+		if (linfo->socket_list == NULL) {
+			goto done;
+		}
+
+		linfo->num_sockets = 0;
+		va_start(args, linfo);
+		while ((sockname = va_arg(args, const char *))) {
+		    sockdata = launch_data_dict_lookup(item, sockname);
+
+		    pull_launch_sockets(sockdata, sockname, linfo);
+		    DEBUG(LAUNCHD_TRACE_LEVEL,
+			    ("Added launchd socket \"%s\"\n", sockname));
+		}
+
+		SMB_ASSERT(count >= linfo->num_sockets);
+	}
+
+done:
+	launch_data_free(msg);
+	launch_data_free(resp);
+	return is_launchd;
+}
+
+ BOOL smb_launchd_checkin(struct smb_launch_info *linfo)
+{
+	launch_data_t msg;
+	launch_data_t resp;
+	launch_data_t item;
+	BOOL is_launchd = False;
+
+	ZERO_STRUCTP(linfo);
+
+	msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+	resp = launch_msg(msg);
+	if (resp == NULL) {
+		/* IPC to launchd failed. */
+		launch_data_free(msg);
+		return is_launchd;
+	}
+
+	if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
+		errno = launch_data_get_errno(resp);
+		goto done;
+	}
+
+	/* At this point, we know we are running under launchd. */
+	linfo->idle_timeout_secs = 600;
+	is_launchd = True;
+
+	if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
+		linfo->idle_timeout_secs = launch_data_get_integer(item);
+	}
+
+	if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
+		int count;
+
+		pull_launch_sockets(item, NULL, linfo);
+		DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
+					linfo->num_sockets));
+
+		count = linfo->num_sockets;
+		linfo->socket_list = talloc_array(NULL, int, count);
+		if (linfo->socket_list == NULL) {
+			goto done;
+		}
+
+		linfo->num_sockets = 0;
+		pull_launch_sockets(item, NULL, linfo);
+
+		DEBUG(LAUNCHD_TRACE_LEVEL, ("Added %d launchd sockets\n",
+					linfo->num_sockets));
+
+		SMB_ASSERT(count == linfo->num_sockets);
+	}
+
+done:
+	launch_data_free(msg);
+	launch_data_free(resp);
+	return is_launchd;
+}
+
+#else /* defined(WITH_LAUNCHD_SUPPORT) */
+
+ BOOL smb_launchd_checkin(struct smb_launch_info * UNUSED(linfo))
+{
+	ZERO_STRUCTP(linfo);
+	return False;
+}
+
+ BOOL smb_launchd_checkin_names(struct smb_launch_info * UNUSED(linfo), ...)
+{
+	ZERO_STRUCTP(linfo);
+	return False;
+}
+
+ void smb_launchd_checkout(struct smb_launch_info * UNUSED(linfo))
+{
+}
+
+#endif /* defined(WITH_LAUNCHD_SUPPORT) */
+
Index: samba/source/smbd/server.c
===================================================================
--- samba/source/smbd/server.c.orig
+++ samba/source/smbd/server.c
@@ -4,6 +4,7 @@
    Copyright (C) Andrew Tridgell		1992-1998
    Copyright (C) Martin Pool			2002
    Copyright (C) Jelmer Vernooij		2002-2003
+   Copyright (C) 2007 Apple Inc. All rights reserved.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -330,14 +331,13 @@ static BOOL allowable_number_of_smbd_pro
 
 static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_ports)
 {
-	int num_interfaces = iface_count();
 	int num_sockets = 0;
 	int fd_listenset[FD_SETSIZE];
 	fd_set listen_set;
 	int s;
 	int maxfd = 0;
 	int i;
-	char *ports;
+	struct timeval idle_timeout = {0, 0};
 
 	if (server_mode == SERVER_MODE_INETD) {
 		return open_sockets_inetd();
@@ -355,116 +355,21 @@ static BOOL open_sockets_smbd(enum smb_s
 
 	/* Stop zombies */
 	CatchSignal(SIGCLD, sig_cld);
-				
-	FD_ZERO(&listen_set);
-
-	/* use a reasonable default set of ports - listing on 445 and 139 */
-	if (!smb_ports) {
-		ports = lp_smb_ports();
-		if (!ports || !*ports) {
-			ports = smb_xstrdup(SMB_PORTS);
-		} else {
-			ports = smb_xstrdup(ports);
-		}
-	} else {
-		ports = smb_xstrdup(smb_ports);
-	}
-
-	if (lp_interfaces() && lp_bind_interfaces_only()) {
-		/* We have been given an interfaces line, and been 
-		   told to only bind to those interfaces. Create a
-		   socket per interface and bind to only these.
-		*/
-		
-		/* Now open a listen socket for each of the
-		   interfaces. */
-		for(i = 0; i < num_interfaces; i++) {
-			struct in_addr *ifip = iface_n_ip(i);
-			fstring tok;
-			const char *ptr;
-
-			if(ifip == NULL) {
-				DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
-				continue;
-			}
-
-			for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
-				unsigned port = atoi(tok);
-				if (port == 0 || port > 0xffff) {
-					continue;
-				}
-				s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
-				if(s == -1)
-					return False;
-
-				/* ready to listen */
-				set_socket_options(s,"SO_KEEPALIVE"); 
-				set_socket_options(s,user_socket_options);
-     
-				/* Set server socket to non-blocking for the accept. */
-				set_blocking(s,False); 
- 
-				if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
-					DEBUG(0,("listen: %s\n",strerror(errno)));
-					close(s);
-					return False;
-				}
-				FD_SET(s,&listen_set);
-				maxfd = MAX( maxfd, s);
-
-				num_sockets++;
-				if (num_sockets >= FD_SETSIZE) {
-					DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
-					return False;
-				}
-			}
-		}
-	} else {
-		/* Just bind to 0.0.0.0 - accept connections
-		   from anywhere. */
 
-		fstring tok;
-		const char *ptr;
-
-		num_interfaces = 1;
-		
-		for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
-			unsigned port = atoi(tok);
-			if (port == 0 || port > 0xffff) continue;
-			/* open an incoming socket */
-			s = open_socket_in(SOCK_STREAM, port, 0,
-					   interpret_addr(lp_socket_address()),True);
-			if (s == -1)
-				return(False);
-		
-			/* ready to listen */
-			set_socket_options(s,"SO_KEEPALIVE"); 
-			set_socket_options(s,user_socket_options);
-			
-			/* Set server socket to non-blocking for the accept. */
-			set_blocking(s,False); 
- 
-			if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
-				DEBUG(0,("open_sockets_smbd: listen: %s\n",
-					 strerror(errno)));
-				close(s);
-				return False;
-			}
+	FD_ZERO(&listen_set);
 
-			fd_listenset[num_sockets] = s;
-			FD_SET(s,&listen_set);
-			maxfd = MAX( maxfd, s);
-
-			num_sockets++;
-
-			if (num_sockets >= FD_SETSIZE) {
-				DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
-				return False;
-			}
-		}
-	} 
+	/* At this point, it doesn't matter what daemon mode we are in, we
+	 * need some sockets to listen on.
+	 */
+	num_sockets = smbd_sockinit(smb_ports, fd_listenset, &idle_timeout);
+	if (num_sockets == 0) {
+		return False;
+  	}
 
-	SAFE_FREE(ports);
+	for (i = 0; i < num_sockets; ++i) {
+		FD_SET(fd_listenset[i], &listen_set);
+		maxfd = MAX(maxfd, fd_listenset[i]);
+	}
 
         /* Listen to messages */
 
@@ -504,8 +409,9 @@ static BOOL open_sockets_smbd(enum smb_s
 
 		memcpy((char *)&lfds, (char *)&listen_set, 
 		       sizeof(listen_set));
-		
-		num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL);
+
+		num = sys_select(maxfd+1,&lfds,NULL,NULL,
+			idle_timeout.tv_sec ? &idle_timeout : NULL);
 		
 		if (num == -1 && errno == EINTR) {
 			if (got_sig_term) {
@@ -522,7 +428,15 @@ static BOOL open_sockets_smbd(enum smb_s
 
 			continue;
 		}
-		
+
+		/* If the idle timeout fired and we don't have any connected
+		 * users, exit gracefully. We should be running under a process
+		 * controller that will restart us if necessry.
+		 */
+		if (num == 0 && count_all_current_connections() == 0) {
+			exit_server_cleanly("idle timeout");
+		}
+
 		/* check if we need to reload services */
 		check_reload(time(NULL));
 
Index: samba/source/Makefile.in
===================================================================
--- samba/source/Makefile.in.orig
+++ samba/source/Makefile.in
@@ -481,6 +481,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpass
 	       smbd/quotas.o smbd/ntquotas.o $(AFS_OBJ) smbd/msdfs.o \
 	       $(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
 	       smbd/dmapi.o lib/opendirectory.o \
+	       lib/launchd.o smbd/sockinit.o \
 	       $(MANGLE_OBJ) @VFS_STATIC@
 
 SMBD_OBJ_BASE = $(PARAM_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
@@ -771,6 +772,7 @@ IDMAP_NSS_OBJ = sam/idmap_nss.o
 
 WINBINDD_OBJ1 = \
 		nsswitch/winbindd.o       \
+		nsswitch/winbindd_sockinit.o \
 		nsswitch/winbindd_user.o  \
 		nsswitch/winbindd_group.o \
 		nsswitch/winbindd_util.o  \
@@ -797,7 +799,7 @@ WINBINDD_OBJ = \
 		$(PROFILE_OBJ) $(SLCACHE_OBJ) $(SMBLDAP_OBJ) \
 		$(SECRETS_OBJ) $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
 		$(DCUTIL_OBJ) $(IDMAP_OBJ) $(NSS_INFO_OBJ) \
-		$(AFS_OBJ) $(AFS_SETTOKEN_OBJ) \
+		$(AFS_OBJ) $(AFS_SETTOKEN_OBJ) lib/launchd.o \
 		$(LIBADS_SERVER_OBJ) $(SERVER_MUTEX_OBJ)
 
 WBINFO_OBJ = nsswitch/wbinfo.o $(LIBSAMBA_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
Index: samba/source/smbd/connection.c
===================================================================
--- samba/source/smbd/connection.c.orig
+++ samba/source/smbd/connection.c
@@ -114,8 +114,18 @@ static int count_fn( TDB_CONTEXT *the_td
 		return 0;
 	}
 
-	if (strequal(crec.servicename, cs->name))
+	if (cs->name) {
+		/* We are counting all the connections to a given share. */
+		if (strequal(crec.servicename, cs->name)) {
+			cs->curr_connections++;
+		}
+	} else {
+		/* We are counting all the connections. Static registrations
+		 * like the lpq backgroud process and the smbd daemon process
+		 * have a cnum of -1, so won't be counted here.
+		 */
 		cs->curr_connections++;
+	}
 
 	return 0;
 }
@@ -148,6 +158,15 @@ int count_current_connections( const cha
 }
 
 /****************************************************************************
+ Count the number of connections open across all shares.
+****************************************************************************/
+
+int count_all_current_connections(void)
+{
+	return count_current_connections(NULL, True /* clear stale entries */);
+}
+
+/****************************************************************************
  Claim an entry in the connections database.
 ****************************************************************************/
 
Index: samba/source/nsswitch/winbindd.c
===================================================================
--- samba/source/nsswitch/winbindd.c.orig
+++ samba/source/nsswitch/winbindd.c
@@ -7,6 +7,7 @@
    Copyright (C) Andrew Tridgell 2002
    Copyright (C) Jelmer Vernooij 2003
    Copyright (C) Volker Lendecke 2004
+   Copyright (C) 2007 Apple Inc. All rights reserved.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -118,13 +119,8 @@ static void flush_caches(void)
 
 static void terminate(void)
 {
-	pstring path;
-
-	/* Remove socket file */
-	pstr_sprintf(path, "%s/%s", 
-		 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
-	unlink(path);
 
+	winbindd_release_sockets();
 	idmap_close();
 	
 	trustdom_cache_shutdown();
@@ -722,23 +718,14 @@ static BOOL remove_idle_client(void)
    simultaneous connections while remaining impervious to many denial of
    service attacks. */
 
-static void process_loop(void)
+static int process_loop(int listen_sock, int listen_priv_sock)
 {
 	struct winbindd_cli_state *state;
 	struct fd_event *ev;
 	fd_set r_fds, w_fds;
-	int maxfd, listen_sock, listen_priv_sock, selret;
+	int maxfd, selret;
 	struct timeval timeout, ev_timeout;
 
-	/* Open Sockets here to get stuff going ASAP */
-	listen_sock = open_winbindd_socket();
-	listen_priv_sock = open_winbindd_priv_socket();
-
-	if (listen_sock == -1 || listen_priv_sock == -1) {
-		perror("open_winbind_socket");
-		exit(1);
-	}
-
 	/* We'll be doing this a lot */
 
 	/* Handle messages */
@@ -906,6 +893,55 @@ static void process_loop(void)
 			winbind_child_died(pid);
 		}
 	}
+
+
+	return winbindd_num_clients();
+}
+
+static void winbindd_process_loop(enum smb_server_mode server_mode)
+{
+	int idle_timeout_sec;
+	struct timeval starttime;
+	int listen_public, listen_priv;
+
+	errno = 0;
+	if (!winbindd_init_sockets(&listen_public, &listen_priv,
+				    &idle_timeout_sec)) {
+		terminate();
+	}
+
+	starttime = timeval_current();
+
+	if (listen_public == -1 || listen_priv == -1) {
+		DEBUG(0, ("failed to open winbindd pipes: %s\n",
+			    errno ? strerror(errno) : "unknown error"));
+		terminate();
+	}
+
+	for (;;) {
+		int clients = process_loop(listen_public, listen_priv);
+
+		/* Don't bother figuring out the idle time if we won't be
+		 * timing out anyway.
+		 */
+		if (idle_timeout_sec < 0) {
+			continue;
+		}
+
+		if (clients == 0 && server_mode == SERVER_MODE_FOREGROUND) {
+			struct timeval now;
+
+			now = timeval_current();
+			if (timeval_elapsed2(&starttime, &now) >
+				(double)idle_timeout_sec) {
+				DEBUG(0, ("idle for %d secs, exitting\n",
+					    idle_timeout_sec));
+				terminate();
+			}
+		} else {
+			starttime = timeval_current();
+		}
+	}
 }
 
 /* Main function */
@@ -1101,9 +1137,7 @@ int main(int argc, char **argv, char **e
 	smb_nscd_flush_group_cache();
 
 	/* Loop waiting for requests */
-
-	while (1)
-		process_loop();
+	winbindd_process_loop(server_mode);
 
 	return 0;
 }
Index: samba/source/nsswitch/winbindd_nss.h
===================================================================
--- samba/source/nsswitch/winbindd_nss.h.orig
+++ samba/source/nsswitch/winbindd_nss.h
@@ -28,7 +28,14 @@
 #define _WINBINDD_NTDOM_H
 
 #define WINBINDD_SOCKET_NAME "pipe"            /* Name of PF_UNIX socket */
+
+/* Let the build environment override the public winbindd socket location. This
+ * is needed for launchd support -- jpeach.
+ */
+#ifndef WINBINDD_SOCKET_DIR
 #define WINBINDD_SOCKET_DIR  "/tmp/.winbindd"  /* Name of PF_UNIX dir */
+#endif
+
 #define WINBINDD_PRIV_SOCKET_SUBDIR "winbindd_privileged" /* name of subdirectory of lp_lockdir() to hold the 'privileged' pipe */
 #define WINBINDD_DOMAIN_ENV  "WINBINDD_DOMAIN" /* Environment variables */
 #define WINBINDD_DONT_ENV    "_NO_WINBINDD"
Index: samba/source/nsswitch/winbindd_sockinit.c
===================================================================
--- /dev/null
+++ samba/source/nsswitch/winbindd_sockinit.c
@@ -0,0 +1,126 @@
+/*
+   Unix SMB/CIFS implementation.
+   Copyright (C) Tim Potter 2000-2001
+   Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+   Copyright (C) James Peach 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+#include "smb_launchd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+/* Open the winbindd socket */
+
+static int _winbindd_socket = -1;
+static int _winbindd_priv_socket = -1;
+static BOOL unlink_winbindd_socket = True;
+
+static int open_winbindd_socket(void)
+{
+	if (_winbindd_socket == -1) {
+		_winbindd_socket = create_pipe_sock(
+			WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
+		DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
+			   _winbindd_socket));
+	}
+
+	return _winbindd_socket;
+}
+
+static int open_winbindd_priv_socket(void)
+{
+	if (_winbindd_priv_socket == -1) {
+		_winbindd_priv_socket = create_pipe_sock(
+			get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
+		DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
+			   _winbindd_priv_socket));
+	}
+
+	return _winbindd_priv_socket;
+}
+
+/* Close the winbindd socket */
+
+static void close_winbindd_socket(void)
+{
+	if (_winbindd_socket != -1) {
+		DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
+			   _winbindd_socket));
+		close(_winbindd_socket);
+		_winbindd_socket = -1;
+	}
+	if (_winbindd_priv_socket != -1) {
+		DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
+			   _winbindd_priv_socket));
+		close(_winbindd_priv_socket);
+		_winbindd_priv_socket = -1;
+	}
+}
+
+BOOL winbindd_init_sockets(int *public_sock, int *priv_sock,
+				int *idle_timeout_sec)
+{
+	struct smb_launch_info linfo;
+
+	if (smb_launchd_checkin_names(&linfo, "WinbindPublicPipe",
+		    "WinbindPrivilegedPipe", NULL)) {
+		if (linfo.num_sockets != 2) {
+			DEBUG(0, ("invalid launchd configuration, "
+				"expected 2 sockets but got %d\n",
+				linfo.num_sockets));
+			return False;
+		}
+
+		*public_sock = _winbindd_socket = linfo.socket_list[0];
+		*priv_sock = _winbindd_priv_socket = linfo.socket_list[1];
+		*idle_timeout_sec = linfo.idle_timeout_secs;
+
+		unlink_winbindd_socket = False;
+
+		smb_launchd_checkout(&linfo);
+		return True;
+	} else {
+		*public_sock = open_winbindd_socket();
+		*priv_sock = open_winbindd_priv_socket();
+		*idle_timeout_sec = -1;
+
+		if (*public_sock == -1 || *priv_sock == -1) {
+			DEBUG(0, ("failed to open winbindd pipes: %s\n",
+			    errno ? strerror(errno) : "unknown error"));
+			return False;
+		}
+
+		return True;
+	}
+}
+
+void winbindd_release_sockets(void)
+{
+	pstring path;
+
+	close_winbindd_socket();
+
+	/* Remove socket file */
+	if (unlink_winbindd_socket) {
+		pstr_sprintf(path, "%s/%s",
+			 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
+		unlink(path);
+	}
+}
Index: samba/source/smbd/sockinit.c
===================================================================
--- /dev/null
+++ samba/source/smbd/sockinit.c
@@ -0,0 +1,201 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Tridgell		1992-1998
+   Copyright (C) James Peach			2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "smb_launchd.h"
+
+extern pstring user_socket_options;
+
+static int init_sockets_smbd(const char *smb_ports, int listenset[FD_SETSIZE])
+{
+	int num_interfaces = iface_count();
+	char * ports;
+	int num_sockets = 0;
+	int i, s;
+
+	/* use a reasonable default set of ports - listing on 445 and 139 */
+	if (!smb_ports) {
+		ports = lp_smb_ports();
+		if (!ports || !*ports) {
+			ports = smb_xstrdup(SMB_PORTS);
+		} else {
+			ports = smb_xstrdup(ports);
+		}
+	} else {
+		ports = smb_xstrdup(smb_ports);
+	}
+
+	if (lp_interfaces() && lp_bind_interfaces_only()) {
+		/* We have been given an interfaces line, and been
+		   told to only bind to those interfaces. Create a
+		   socket per interface and bind to only these.
+		*/
+
+		/* Now open a listen socket for each of the
+		   interfaces. */
+		for(i = 0; i < num_interfaces; i++) {
+			struct in_addr *ifip = iface_n_ip(i);
+			fstring tok;
+			const char *ptr;
+
+			if(ifip == NULL) {
+				DEBUG(0,("init_sockets_smbd: interface %d has NULL IP address !\n", i));
+				continue;
+			}
+
+			for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
+				unsigned port = atoi(tok);
+				if (port == 0) {
+					continue;
+				}
+				s = listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+				if(s == -1)
+					return 0;
+
+				/* ready to listen */
+				set_socket_options(s,"SO_KEEPALIVE");
+				set_socket_options(s,user_socket_options);
+
+				/* Set server socket to non-blocking for the accept. */
+				set_blocking(s,False);
+
+				if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+					DEBUG(0,("listen: %s\n",strerror(errno)));
+					close(s);
+					return 0;
+				}
+
+				num_sockets++;
+				if (num_sockets >= FD_SETSIZE) {
+					DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
+					return 0;
+				}
+			}
+		}
+	} else {
+		/* Just bind to 0.0.0.0 - accept connections
+		   from anywhere. */
+
+		fstring tok;
+		const char *ptr;
+
+		num_interfaces = 1;
+
+		for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
+			unsigned port = atoi(tok);
+			if (port == 0) continue;
+			/* open an incoming socket */
+			s = open_socket_in(SOCK_STREAM, port, 0,
+					   interpret_addr(lp_socket_address()),True);
+			if (s == -1)
+				return 0;
+
+			/* ready to listen */
+			set_socket_options(s,"SO_KEEPALIVE");
+			set_socket_options(s,user_socket_options);
+
+			/* Set server socket to non-blocking for the accept. */
+			set_blocking(s,False);
+
+			if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+				DEBUG(0,("init_sockets_smbd: listen: %s\n",
+					 strerror(errno)));
+				close(s);
+				return 0;
+			}
+
+			listenset[num_sockets] = s;
+			num_sockets++;
+
+			if (num_sockets >= FD_SETSIZE) {
+				DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
+				return 0;
+			}
+		}
+	}
+
+	SAFE_FREE(ports);
+	return num_sockets;
+}
+
+static int init_sockets_launchd(const struct smb_launch_info *linfo,
+				const char * smb_ports,
+				int listenset[FD_SETSIZE])
+{
+	int num_sockets;
+	int i;
+
+	/* The launchd service configuration does not have to provide sockets,
+	 * even though it's basically useless without it.
+	 */
+	if (!linfo->num_sockets) {
+		return init_sockets_smbd(smb_ports, listenset);
+	}
+
+	/* Make sure we don't get more sockets than we can handle. */
+	num_sockets = MIN(FD_SETSIZE, linfo->num_sockets);
+	memcpy(listenset, linfo->socket_list, num_sockets * sizeof(int));
+
+	/* Get the sockets ready. This could be hoisted into
+	 * open_sockets_smbd(), but the order of socket operations might
+	 * matter for some platforms, so this approach seems less risky.
+	 *	--jpeach
+	 */
+	for (i = 0; i < num_sockets; ++i) {
+		set_socket_options(listenset[i], "SO_KEEPALIVE");
+		set_socket_options(listenset[i], user_socket_options);
+
+		/* Set server socket to non-blocking for the accept. */
+		set_blocking(listenset[i], False);
+	}
+
+	return num_sockets;
+}
+
+/* This function is responsible for opening (or retrieving) all the sockets we
+ * smbd will be listening on. It should apply all the configured socket options
+ * and return the number of valid sockets in listenset.
+ */
+int smbd_sockinit(const char *cmdline_ports, int listenset[FD_SETSIZE],
+			struct timeval *idle)
+{
+	int num_sockets;
+	struct smb_launch_info linfo;
+
+	ZERO_STRUCTP(idle);
+
+	if (smb_launchd_checkin(&linfo)) {
+		/* We are running under launchd and launchd has
+		 * opened some sockets for us.
+		 */
+		num_sockets = init_sockets_launchd(&linfo,
+					    cmdline_ports,
+					    listenset);
+		idle->tv_sec = linfo.idle_timeout_secs;
+		smb_launchd_checkout(&linfo);
+	} else {
+		num_sockets = init_sockets_smbd(cmdline_ports,
+					    listenset);
+	}
+
+	return num_sockets;
+}
+
Index: samba/source/nsswitch/winbindd_util.c
===================================================================
--- samba/source/nsswitch/winbindd_util.c.orig
+++ samba/source/nsswitch/winbindd_util.c
@@ -913,53 +913,6 @@ char *get_winbind_priv_pipe_dir(void) 
 	return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
 }
 
-/* Open the winbindd socket */
-
-static int _winbindd_socket = -1;
-static int _winbindd_priv_socket = -1;
-
-int open_winbindd_socket(void)
-{
-	if (_winbindd_socket == -1) {
-		_winbindd_socket = create_pipe_sock(
-			WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
-		DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
-			   _winbindd_socket));
-	}
-
-	return _winbindd_socket;
-}
-
-int open_winbindd_priv_socket(void)
-{
-	if (_winbindd_priv_socket == -1) {
-		_winbindd_priv_socket = create_pipe_sock(
-			get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
-		DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
-			   _winbindd_priv_socket));
-	}
-
-	return _winbindd_priv_socket;
-}
-
-/* Close the winbindd socket */
-
-void close_winbindd_socket(void)
-{
-	if (_winbindd_socket != -1) {
-		DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
-			   _winbindd_socket));
-		close(_winbindd_socket);
-		_winbindd_socket = -1;
-	}
-	if (_winbindd_priv_socket != -1) {
-		DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
-			   _winbindd_priv_socket));
-		close(_winbindd_priv_socket);
-		_winbindd_priv_socket = -1;
-	}
-}
-
 /*
  * Client list accessor functions
  */